From 730a3baedce5292cd64e194b3be60dbc086564e3 Mon Sep 17 00:00:00 2001 From: tom5079 Date: Wed, 2 Dec 2020 09:57:16 +0900 Subject: [PATCH] Suggestion --- app/build.gradle | 8 +- .../quaver/pupil/adapters/SourceAdapter.kt | 10 +- .../java/xyz/quaver/pupil/sources/Common.kt | 30 +++-- .../pupil/sources/{hitomi => }/Hitomi.kt | 67 ++++++++- .../pupil/sources/{hitomi => }/Hiyobi.kt | 74 ++++++++-- .../xyz/quaver/pupil/types/Suggestions.kt | 17 +-- .../java/xyz/quaver/pupil/ui/MainActivity.kt | 74 +++------- .../xyz/quaver/pupil/ui/ReaderActivity.kt | 18 +-- .../ui/dialog/DefaultQueryDialogFragment.kt | 14 +- .../quaver/pupil/ui/dialog/GalleryDialog.kt | 6 +- .../xyz/quaver/pupil/ui/dialog/ProxyDialog.kt | 2 +- .../pupil/ui/dialog/SourceSelectDialog.kt | 3 +- .../pupil/ui/fragment/LockSettingsFragment.kt | 6 +- .../ui/fragment/ManageStorageFragment.kt | 8 +- .../pupil/ui/fragment/SettingsFragment.kt | 2 +- .../pupil/ui/view/FloatingSearchView.kt | 127 +++--------------- .../java/xyz/quaver/pupil/ui/view/TagChip.kt | 2 +- 17 files changed, 227 insertions(+), 241 deletions(-) rename app/src/main/java/xyz/quaver/pupil/sources/{hitomi => }/Hitomi.kt (66%) rename app/src/main/java/xyz/quaver/pupil/sources/{hitomi => }/Hiyobi.kt (50%) diff --git a/app/build.gradle b/app/build.gradle index 5f865475..5861dfda 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -44,8 +44,10 @@ android { } buildTypes { debug { - minifyEnabled true - shrinkResources true + minifyEnabled false + shrinkResources false + + multiDexEnabled true debuggable true applicationIdSuffix ".debug" @@ -128,7 +130,7 @@ dependencies { implementation "xyz.quaver:libpupil:1.9.7" implementation "xyz.quaver:documentfilex:0.4-alpha02" - implementation "xyz.quaver:floatingsearchview:1.0.9" + implementation "xyz.quaver:floatingsearchview:1.1.1" testImplementation "junit:junit:4.13.1" androidTestImplementation "androidx.test.ext:junit:1.1.2" diff --git a/app/src/main/java/xyz/quaver/pupil/adapters/SourceAdapter.kt b/app/src/main/java/xyz/quaver/pupil/adapters/SourceAdapter.kt index 3010eb4d..56c8cfa2 100644 --- a/app/src/main/java/xyz/quaver/pupil/adapters/SourceAdapter.kt +++ b/app/src/main/java/xyz/quaver/pupil/adapters/SourceAdapter.kt @@ -20,18 +20,18 @@ package xyz.quaver.pupil.adapters import android.view.LayoutInflater import android.view.ViewGroup -import androidx.core.graphics.drawable.DrawableCompat import androidx.recyclerview.widget.RecyclerView +import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion import xyz.quaver.pupil.databinding.SourceSelectDialogItemBinding import xyz.quaver.pupil.sources.Source import xyz.quaver.pupil.sources.sourceIcons -class SourceAdapter(private val sources: List>) : RecyclerView.Adapter() { +class SourceAdapter(private val sources: List>) : RecyclerView.Adapter() { - var onSourceSelectedListener: ((Source<*>) -> Unit)? = null + var onSourceSelectedListener: ((Source<*, SearchSuggestion>) -> Unit)? = null inner class ViewHolder(private val binding: SourceSelectDialogItemBinding) : RecyclerView.ViewHolder(binding.root) { - lateinit var source: Source<*> + lateinit var source: Source<*, SearchSuggestion> init { binding.go.setOnClickListener { @@ -39,7 +39,7 @@ class SourceAdapter(private val sources: List>) : RecyclerView.Adapter } } - fun bind(source: Source<*>) { + fun bind(source: Source<*, SearchSuggestion>) { this.source = source binding.icon.setImageDrawable(sourceIcons[source.name]) diff --git a/app/src/main/java/xyz/quaver/pupil/sources/Common.kt b/app/src/main/java/xyz/quaver/pupil/sources/Common.kt index cbe3c8ab..b486ad7c 100644 --- a/app/src/main/java/xyz/quaver/pupil/sources/Common.kt +++ b/app/src/main/java/xyz/quaver/pupil/sources/Common.kt @@ -22,9 +22,10 @@ import android.content.Context import android.graphics.drawable.Drawable import androidx.core.content.ContextCompat import kotlinx.coroutines.channels.Channel +import kotlinx.parcelize.Parcelize +import xyz.quaver.floatingsearchview.databinding.SearchSuggestionItemBinding +import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion import xyz.quaver.pupil.R -import xyz.quaver.pupil.sources.hitomi.Hitomi -import xyz.quaver.pupil.sources.hitomi.Hiyobi data class SearchResult( val id: String, @@ -56,15 +57,24 @@ data class SearchResult( enum class DefaultSortMode { DEFAULT } -interface Source> { - val name: String - val iconResID: Int - val availableSortMode: Array - suspend fun query(query: String, range: IntRange, sortMode: Enum<*>) : Pair, Int> +@Parcelize +class DefaultSearchSuggestion(override val body: String) : SearchSuggestion + +abstract class Source, Suggestion: SearchSuggestion> { + abstract val name: String + abstract val iconResID: Int + abstract val availableSortMode: Array + + abstract suspend fun search(query: String, range: IntRange, sortMode: Enum<*>) : Pair, Int> + abstract suspend fun suggestion(query: String) : List + + open fun onSuggestionBind(binding: SearchSuggestionItemBinding, item: Suggestion) { + binding.leftIcon.setImageResource(R.drawable.tag) + } } -val sources = mutableMapOf>() +val sources = mutableMapOf>() val sourceIcons = mutableMapOf() @Suppress("UNCHECKED_CAST") @@ -73,8 +83,8 @@ fun initSources(context: Context) { listOf( Hitomi(), Hiyobi() - ).forEach { - sources[it.name] = it + ).forEach { + sources[it.name] = it as Source<*, SearchSuggestion> sourceIcons[it.name] = ContextCompat.getDrawable(context, it.iconResID) } } \ No newline at end of file diff --git a/app/src/main/java/xyz/quaver/pupil/sources/hitomi/Hitomi.kt b/app/src/main/java/xyz/quaver/pupil/sources/Hitomi.kt similarity index 66% rename from app/src/main/java/xyz/quaver/pupil/sources/hitomi/Hitomi.kt rename to app/src/main/java/xyz/quaver/pupil/sources/Hitomi.kt index d73fbb8e..49750046 100644 --- a/app/src/main/java/xyz/quaver/pupil/sources/hitomi/Hitomi.kt +++ b/app/src/main/java/xyz/quaver/pupil/sources/Hitomi.kt @@ -16,26 +16,45 @@ * along with this program. If not, see . */ -package xyz.quaver.pupil.sources.hitomi +package xyz.quaver.pupil.sources +import android.view.LayoutInflater +import android.widget.TextView +import androidx.core.content.ContextCompat import kotlinx.coroutines.* import kotlinx.coroutines.channels.Channel +import kotlinx.parcelize.IgnoredOnParcel +import kotlinx.parcelize.Parcelize +import xyz.quaver.floatingsearchview.databinding.SearchSuggestionItemBinding +import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion import xyz.quaver.hitomi.* import xyz.quaver.pupil.R -import xyz.quaver.pupil.sources.SearchResult import xyz.quaver.pupil.sources.SearchResult.ExtraType -import xyz.quaver.pupil.sources.Source +import xyz.quaver.pupil.util.translations import xyz.quaver.pupil.util.wordCapitalize import kotlin.math.max import kotlin.math.min -class Hitomi : Source { +class Hitomi : Source() { enum class SortMode { NEWEST, POPULAR } + @Parcelize + data class TagSuggestion(val s: String, val t: Int, val u: String, val n: String) : + SearchSuggestion { + constructor(s: Suggestion) : this(s.s, s.t, s.u, s.n) + + @IgnoredOnParcel + override val body = + if (translations[s] != null) + "${translations[s]} ($s)" + else + s + } + override val name: String = "hitomi.la" override val iconResID: Int = R.drawable.hitomi override val availableSortMode: Array = SortMode.values() @@ -44,7 +63,7 @@ class Hitomi : Source { var cachedSortMode: SortMode? = null val cache = mutableListOf() - override suspend fun query(query: String, range: IntRange, sortMode: Enum<*>): Pair, Int> { + override suspend fun search(query: String, range: IntRange, sortMode: Enum<*>): Pair, Int> { if (cachedQuery != query || cachedSortMode != sortMode || cache.isEmpty()) { cachedQuery = null cache.clear() @@ -79,6 +98,44 @@ class Hitomi : Source { return Pair(channel, cache.size) } + override suspend fun suggestion(query: String) : List { + return getSuggestionsForQuery(query.takeLastWhile { !it.isWhitespace() }).map { + TagSuggestion(it) + } + } + + override fun onSuggestionBind(binding: SearchSuggestionItemBinding, item: TagSuggestion) { + binding.leftIcon.setImageResource( + when(item.n) { + "female" -> R.drawable.gender_female + "male" -> R.drawable.gender_male + "language" -> R.drawable.translate + "group" -> R.drawable.account_group + "character" -> R.drawable.account_star + "series" -> R.drawable.book_open + "artist" -> R.drawable.brush + else -> R.drawable.tag + } + ) + + if (item.t > 0) { + with (binding.root) { + val count = findViewById(R.id.count) + if (count == null) + addView( + LayoutInflater.from(context).inflate(R.layout.suggestion_count, binding.root, false) + .apply { + this as TextView + + text = item.t.toString() + }, 2 + ) + else + count.text = item.t.toString() + } + } + } + companion object { val languageMap = mapOf( "indonesian" to "Bahasa Indonesia", diff --git a/app/src/main/java/xyz/quaver/pupil/sources/hitomi/Hiyobi.kt b/app/src/main/java/xyz/quaver/pupil/sources/Hiyobi.kt similarity index 50% rename from app/src/main/java/xyz/quaver/pupil/sources/hitomi/Hiyobi.kt rename to app/src/main/java/xyz/quaver/pupil/sources/Hiyobi.kt index edaad665..43eada73 100644 --- a/app/src/main/java/xyz/quaver/pupil/sources/hitomi/Hiyobi.kt +++ b/app/src/main/java/xyz/quaver/pupil/sources/Hiyobi.kt @@ -16,27 +16,30 @@ * along with this program. If not, see . */ -package xyz.quaver.pupil.sources.hitomi +package xyz.quaver.pupil.sources -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers +import androidx.core.content.ContextCompat +import kotlinx.coroutines.* import kotlinx.coroutines.channels.Channel -import kotlinx.coroutines.launch -import xyz.quaver.hitomi.galleryblockdir +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.json.Json +import okhttp3.Request +import xyz.quaver.floatingsearchview.databinding.SearchSuggestionItemBinding +import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion import xyz.quaver.hiyobi.* import xyz.quaver.pupil.R -import xyz.quaver.pupil.sources.DefaultSortMode -import xyz.quaver.pupil.sources.SearchResult -import xyz.quaver.pupil.sources.Source +import xyz.quaver.pupil.client import xyz.quaver.pupil.util.wordCapitalize +import java.io.IOException +import java.util.* -class Hiyobi : Source { +class Hiyobi : Source() { override val name: String = "hiyobi.me" override val iconResID: Int = R.drawable.ic_hiyobi override val availableSortMode: Array = DefaultSortMode.values() - override suspend fun query(query: String, range: IntRange, sortMode: Enum<*>): Pair, Int> { + override suspend fun search(query: String, range: IntRange, sortMode: Enum<*>): Pair, Int> { val channel = Channel() val (results, total) = if (query.isEmpty()) @@ -55,7 +58,58 @@ class Hiyobi : Source { return Pair(channel, total) } + override suspend fun suggestion(query: String): List { + val result = mutableSetOf() + + for (tag in allTags.await()) { + if (result.size >= 10) + break + + val lowQuery = query.toLowerCase(Locale.ROOT) + + if (tag.contains(lowQuery, true)) + result.add(tag) + } + + return result.map { DefaultSearchSuggestion(it) } + } + + override fun onSuggestionBind(binding: SearchSuggestionItemBinding, item: DefaultSearchSuggestion) { + val split = item.body.split(':', limit = 2) + + if (split.size != 2) + return + + binding.leftIcon.setImageResource( + when(split.first()) { + "female" -> R.drawable.gender_female + "male" -> R.drawable.gender_male + "language" -> R.drawable.translate + "group" -> R.drawable.account_group + "character" -> R.drawable.account_star + "series" -> R.drawable.book_open + "artist" -> R.drawable.brush + else -> R.drawable.tag + } + ) + + binding.body.text = split.last() + } + companion object { + private fun downloadAllTags(): Deferred> = CoroutineScope(Dispatchers.IO).async { + Json.decodeFromString(kotlin.runCatching { + client.newCall(Request.Builder().url("https://api.hiyobi.me/auto.json").build()).execute().also { if (it.code() != 200) throw IOException() }.body()?.use { it.string() } + }.getOrNull() ?: "[]") + } + + private var _allTags: Deferred>? = null + + val allTags: Deferred> + get() = if (_allTags == null || (_allTags!!.isCompleted && runBlocking { _allTags!!.await() }.isEmpty())) downloadAllTags().also { + _allTags = it + } else _allTags!! + fun transform(galleryBlock: GalleryBlock): SearchResult = SearchResult( galleryBlock.id, diff --git a/app/src/main/java/xyz/quaver/pupil/types/Suggestions.kt b/app/src/main/java/xyz/quaver/pupil/types/Suggestions.kt index d3c02196..4b902410 100644 --- a/app/src/main/java/xyz/quaver/pupil/types/Suggestions.kt +++ b/app/src/main/java/xyz/quaver/pupil/types/Suggestions.kt @@ -18,26 +18,11 @@ package xyz.quaver.pupil.types -import kotlinx.parcelize.IgnoredOnParcel import kotlinx.parcelize.Parcelize import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion -import xyz.quaver.hitomi.Suggestion -import xyz.quaver.pupil.util.translations @Parcelize -data class TagSuggestion(val s: String, val t: Int, val u: String, val n: String) : SearchSuggestion { - constructor(s: Suggestion) : this(s.s, s.t, s.u, s.n) - - @IgnoredOnParcel - override val body = - if (translations[s] != null) - "${translations[s]} ($s)" - else - s -} - -@Parcelize -class Suggestion(override val body: String) : SearchSuggestion +class HistorySuggestion(override val body: String) : SearchSuggestion @Parcelize class NoResultSuggestion(override val body: String) : SearchSuggestion diff --git a/app/src/main/java/xyz/quaver/pupil/ui/MainActivity.kt b/app/src/main/java/xyz/quaver/pupil/ui/MainActivity.kt index d35e7ebb..3d2bfa74 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/MainActivity.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/MainActivity.kt @@ -47,7 +47,6 @@ import kotlinx.coroutines.channels.Channel import xyz.quaver.floatingsearchview.FloatingSearchView import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion import xyz.quaver.floatingsearchview.util.view.SearchInputView -import xyz.quaver.hitomi.getSuggestionsForQuery import xyz.quaver.pupil.* import xyz.quaver.pupil.adapters.SearchResultsAdapter import xyz.quaver.pupil.databinding.MainActivityBinding @@ -77,14 +76,14 @@ class MainActivity : private var query = "" set(value) { field = value - with(findViewById(R.id.search_bar_text)) { + with (findViewById(R.id.search_bar_text)) { if (text.toString() != value) setText(query, TextView.BufferType.EDITABLE) } } private var queryStack = mutableListOf() - private lateinit var source: Source<*> + private lateinit var source: Source<*, SearchSuggestion> private lateinit var sortMode: Enum<*> private var searchJob: Deferred, Int>>? = null @@ -168,7 +167,7 @@ class MainActivity : } } - private fun setSource(source: Source<*>) { + private fun setSource(source: Source<*, SearchSuggestion>) { this.source = source sortMode = source.availableSortMode.first() @@ -219,14 +218,14 @@ class MainActivity : //NavigationView binding.navView.setNavigationItemSelectedListener(this) - with(binding.contents.cancelFab) { + with (binding.contents.cancelFab) { setImageResource(R.drawable.cancel) setOnClickListener { DownloadService.cancel(this@MainActivity) } } - with(binding.contents.jumpFab) { + with (binding.contents.jumpFab) { setImageResource(R.drawable.ic_jump) setOnClickListener { val perPage = Preferences["per_page", "25"].toInt() @@ -250,7 +249,7 @@ class MainActivity : } } - with(binding.contents.randomFab) { + with (binding.contents.randomFab) { setImageResource(R.drawable.shuffle_variant) setOnClickListener { setImageDrawable(CircularProgressDrawable(context)) @@ -259,7 +258,7 @@ class MainActivity : val random = Random.Default.nextInt(totalItems) val randomResult = - source.query( + source.search( query + Preferences["default_query", ""], random .. random, sortMode @@ -281,7 +280,7 @@ class MainActivity : } } - with(binding.contents.idFab) { + with (binding.contents.idFab) { setImageResource(R.drawable.numeric) setOnClickListener { val editText = EditText(context).apply { @@ -309,7 +308,7 @@ class MainActivity : } } - with(binding.contents.swipePageTurnView) { + with (binding.contents.swipePageTurnView) { setOnPageTurnListener(object: SwipePageTurnView.OnPageTurnListener { override fun onPrev(page: Int) { currentPage-- @@ -344,7 +343,7 @@ class MainActivity : @SuppressLint("ClickableViewAccessibility") private fun setupRecyclerView() { - with(binding.contents.recyclerview) { + with (binding.contents.recyclerview) { adapter = SearchResultsAdapter(searchResults).apply { onChipClickedHandler = { query = it.toQuery() @@ -406,24 +405,9 @@ class MainActivity : } } - private var isFavorite = false - private val defaultSuggestions: List - get() = when { - isFavorite -> { - favoriteTags.map { - TagSuggestion(it.tag, -1, "", it.area ?: "tag") - } + FavoriteHistorySwitch(getString(R.string.search_show_histories)) - } - else -> { - searchHistory.map { - Suggestion(it) - }.takeLast(10) + FavoriteHistorySwitch(getString(R.string.search_show_tags)) - } - }.reversed() - private var suggestionJob : Job? = null private fun setupSearchBar() { - with(binding.contents.searchview) { + with (binding.contents.searchview) { onMenuStatusChangeListener = object: FloatingSearchView.OnMenuStatusChangeListener { override fun onMenuOpened() { (this@MainActivity.binding.contents.recyclerview.adapter as SearchResultsAdapter).closeAllItems() @@ -434,15 +418,6 @@ class MainActivity : } } - onHistoryDeleteClickedListener = { - searchHistory.remove(it) - swapSuggestions(defaultSuggestions) - } - onFavoriteHistorySwitchClickListener = { - isFavorite = !isFavorite - swapSuggestions(defaultSuggestions) - } - onMenuItemClickListener = { onActionMenuItemSelected(it) } @@ -452,12 +427,6 @@ class MainActivity : suggestionJob?.cancel() - if (query.isEmpty() or query.endsWith(' ')) { - swapSuggestions(defaultSuggestions) - - return@lambda - } - swapSuggestions(listOf(LoadingSuggestion(getText(R.string.reader_loading).toString()))) val currentQuery = query.split(" ").last() @@ -466,16 +435,8 @@ class MainActivity : suggestionJob = CoroutineScope(Dispatchers.IO).launch { val suggestions = kotlin.runCatching { - getSuggestionsForQuery(currentQuery).map { TagSuggestion(it) }.toMutableList() - }.getOrElse { mutableListOf() } - - suggestions.filter { - val tag = "${it.n}:${it.s.replace(Regex("\\s"), "_")}" - favoriteTags.contains(Tag.parse(tag)) - }.reversed().forEach { - suggestions.remove(it) - suggestions.add(0, it) - } + source.suggestion(currentQuery) + }.getOrElse { emptyList() } withContext(Dispatchers.Main) { swapSuggestions(if (suggestions.isNotEmpty()) suggestions else listOf(NoResultSuggestion(getText(R.string.main_no_result).toString()))) @@ -483,10 +444,13 @@ class MainActivity : } } + onSuggestionBinding = { binding, item -> + source.onSuggestionBind(binding, item) + } + onFocusChangeListener = object: FloatingSearchView.OnFocusChangeListener { override fun onFocus() { - if (query.isEmpty() or query.endsWith(' ')) - swapSuggestions(defaultSuggestions) + } override fun onFocusCleared() { @@ -577,7 +541,7 @@ class MainActivity : CoroutineScope(Dispatchers.Main).launch { searchJob = async(Dispatchers.IO) { - source.query( + source.search( query + Preferences["default_query", ""], (currentPage - 1) * perPage until currentPage * perPage, sortMode diff --git a/app/src/main/java/xyz/quaver/pupil/ui/ReaderActivity.kt b/app/src/main/java/xyz/quaver/pupil/ui/ReaderActivity.kt index 7c1bc4cf..3bff09f3 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/ReaderActivity.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/ReaderActivity.kt @@ -132,7 +132,7 @@ class ReaderActivity : BaseActivity() { override fun onCreateOptionsMenu(menu: Menu?): Boolean { menuInflater.inflate(R.menu.reader, menu) - with(menu?.findItem(R.id.reader_menu_favorite)) { + with (menu?.findItem(R.id.reader_menu_favorite)) { this ?: return@with if (favorites.contains(galleryID)) @@ -149,7 +149,7 @@ class ReaderActivity : BaseActivity() { // TODO: Switch to DialogFragment val binding = NumberpickerDialogBinding.inflate(layoutInflater, binding.root, false) - with(binding.numberPicker) { + with (binding.numberPicker) { minValue = 1 maxValue = cache.metadata.reader?.files?.size ?: 0 value = currentPage @@ -265,7 +265,7 @@ class ReaderActivity : BaseActivity() { val reader = cache.metadata.reader if (reader != null) { - with(binding.recyclerview.adapter as ReaderAdapter) { + with (binding.recyclerview.adapter as ReaderAdapter) { this.reader = reader notifyDataSetChanged() } @@ -297,7 +297,7 @@ class ReaderActivity : BaseActivity() { } private fun initView() { - with(binding.recyclerview) { + with (binding.recyclerview) { adapter = ReaderAdapter(this@ReaderActivity, galleryID).apply { onItemClickListener = { if (isScroll) { @@ -331,7 +331,7 @@ class ReaderActivity : BaseActivity() { }) } - with(binding.downloadFab) { + with (binding.downloadFab) { animateDownloadFAB(DownloadManager.getInstance(this@ReaderActivity).getDownloadFolder(galleryID) != null) //If download in progress, animate button setOnClickListener { @@ -348,14 +348,14 @@ class ReaderActivity : BaseActivity() { } } - with(binding.retryFab) { + with (binding.retryFab) { setImageResource(R.drawable.refresh) setOnClickListener { DownloadService.download(context, galleryID) } } - with(binding.fullscreenFab) { + with (binding.fullscreenFab) { setImageResource(R.drawable.ic_fullscreen) setOnClickListener { isFullscreen = true @@ -367,7 +367,7 @@ class ReaderActivity : BaseActivity() { } private fun fullscreen(isFullscreen: Boolean) { - with(window.attributes) { + with (window.attributes) { if (isFullscreen) { flags = flags or WindowManager.LayoutParams.FLAG_FULLSCREEN supportActionBar?.hide() @@ -413,7 +413,7 @@ class ReaderActivity : BaseActivity() { } private fun animateDownloadFAB(animate: Boolean) { - with(binding.downloadFab) { + with (binding.downloadFab) { if (animate) { val icon = AnimatedVectorDrawableCompat.create(context, R.drawable.ic_downloading) diff --git a/app/src/main/java/xyz/quaver/pupil/ui/dialog/DefaultQueryDialogFragment.kt b/app/src/main/java/xyz/quaver/pupil/ui/dialog/DefaultQueryDialogFragment.kt index eeb76ecc..1e49682c 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/dialog/DefaultQueryDialogFragment.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/dialog/DefaultQueryDialogFragment.kt @@ -27,7 +27,7 @@ import androidx.appcompat.app.AlertDialog import androidx.fragment.app.DialogFragment import xyz.quaver.pupil.R import xyz.quaver.pupil.databinding.DefaultQueryDialogBinding -import xyz.quaver.pupil.sources.hitomi.Hitomi +import xyz.quaver.pupil.sources.Hitomi import xyz.quaver.pupil.types.Tags import xyz.quaver.pupil.util.Preferences @@ -56,7 +56,7 @@ class DefaultQueryDialogFragment() : DialogFragment() { setPositiveButton(android.R.string.ok) { _, _ -> val newTags = Tags.parse(binding.edittext.text.toString()) - with(binding.languageSelector) { + with (binding.languageSelector) { if (selectedItemPosition != 0) newTags.add("language:${reverseLanguages[selectedItem]}") } @@ -89,7 +89,7 @@ class DefaultQueryDialogFragment() : DialogFragment() { Preferences["default_query"] ) - with(binding.languageSelector) { + with (binding.languageSelector) { adapter = ArrayAdapter( context, @@ -112,13 +112,13 @@ class DefaultQueryDialogFragment() : DialogFragment() { } } - with(binding.BLCheckbox) { + with (binding.BLCheckbox) { isChecked = tags.contains(excludeBL) if (tags.contains(excludeBL)) tags.remove(excludeBL) } - with(binding.guroCheckbox) { + with (binding.guroCheckbox) { isChecked = excludeGuro.all { tags.contains(it) } if (excludeGuro.all { tags.contains(it) }) excludeGuro.forEach { @@ -126,7 +126,7 @@ class DefaultQueryDialogFragment() : DialogFragment() { } } - with(binding.loliCheckbox) { + with (binding.loliCheckbox) { isChecked = excludeLoli.all { tags.contains(it) } if (excludeLoli.all { tags.contains(it) }) excludeLoli.forEach { @@ -134,7 +134,7 @@ class DefaultQueryDialogFragment() : DialogFragment() { } } - with(binding.edittext) { + with (binding.edittext) { setText(tags.toString(), android.widget.TextView.BufferType.EDITABLE) addTextChangedListener(object : TextWatcher { override fun beforeTextChanged( diff --git a/app/src/main/java/xyz/quaver/pupil/ui/dialog/GalleryDialog.kt b/app/src/main/java/xyz/quaver/pupil/ui/dialog/GalleryDialog.kt index f30dff14..3ea994ad 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/dialog/GalleryDialog.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/dialog/GalleryDialog.kt @@ -42,7 +42,7 @@ import xyz.quaver.pupil.adapters.SearchResultsAdapter import xyz.quaver.pupil.adapters.ThumbnailPageAdapter import xyz.quaver.pupil.databinding.* import xyz.quaver.pupil.favoriteTags -import xyz.quaver.pupil.sources.hitomi.Hitomi +import xyz.quaver.pupil.sources.Hitomi import xyz.quaver.pupil.sources.SearchResult import xyz.quaver.pupil.types.Tag import xyz.quaver.pupil.ui.ReaderActivity @@ -66,7 +66,7 @@ class GalleryDialog(context: Context, private val galleryID: String) : AlertDial window?.setLayout(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT) - with(binding.fab) { + with (binding.fab) { setImageDrawable(ContextCompat.getDrawable(context, R.drawable.arrow_right)) setOnClickListener { context.startActivity(Intent(context, ReaderActivity::class.java).apply { @@ -84,7 +84,7 @@ class GalleryDialog(context: Context, private val galleryID: String) : AlertDial binding.title.text = gallery.title binding.artist.text = gallery.artists.joinToString(", ") { it.wordCapitalize() } - with(binding.type) { + with (binding.type) { text = gallery.type.wordCapitalize() setOnClickListener { gallery.type.let { diff --git a/app/src/main/java/xyz/quaver/pupil/ui/dialog/ProxyDialog.kt b/app/src/main/java/xyz/quaver/pupil/ui/dialog/ProxyDialog.kt index c0d4a093..a623766f 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/dialog/ProxyDialog.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/dialog/ProxyDialog.kt @@ -67,7 +67,7 @@ class ProxyDialog(context: Context) : AlertDialog(context) { } } - with(binding.typeSelector) { + with (binding.typeSelector) { adapter = ArrayAdapter( context, android.R.layout.simple_spinner_dropdown_item, diff --git a/app/src/main/java/xyz/quaver/pupil/ui/dialog/SourceSelectDialog.kt b/app/src/main/java/xyz/quaver/pupil/ui/dialog/SourceSelectDialog.kt index 1ca45b79..631eab36 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/dialog/SourceSelectDialog.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/dialog/SourceSelectDialog.kt @@ -25,13 +25,14 @@ import android.view.Window import androidx.fragment.app.DialogFragment import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView +import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion import xyz.quaver.pupil.adapters.SourceAdapter import xyz.quaver.pupil.sources.Source import xyz.quaver.pupil.sources.sources class SourceSelectDialog : DialogFragment() { - var onSourceSelectedListener: ((Source<*>) -> Unit)? = null + var onSourceSelectedListener: ((Source<*, SearchSuggestion>) -> Unit)? = null override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { return Dialog(requireContext()).apply { diff --git a/app/src/main/java/xyz/quaver/pupil/ui/fragment/LockSettingsFragment.kt b/app/src/main/java/xyz/quaver/pupil/ui/fragment/LockSettingsFragment.kt index 8dce8389..06a319cb 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/fragment/LockSettingsFragment.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/fragment/LockSettingsFragment.kt @@ -60,7 +60,7 @@ class LockSettingsFragment : PreferenceFragmentCompat() { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { setPreferencesFromResource(R.xml.lock_preferences, rootKey) - with(findPreference("lock_pattern")) { + with (findPreference("lock_pattern")) { this!! if (LockManager(requireContext()).contains(Lock.Type.PATTERN)) @@ -93,7 +93,7 @@ class LockSettingsFragment : PreferenceFragmentCompat() { } } - with(findPreference("lock_pin")) { + with (findPreference("lock_pin")) { this!! if (LockManager(requireContext()).contains(Lock.Type.PIN)) @@ -126,7 +126,7 @@ class LockSettingsFragment : PreferenceFragmentCompat() { } } - with(findPreference("lock_fingerprint")) { + with (findPreference("lock_fingerprint")) { this!! setOnPreferenceChangeListener { _, newValue -> diff --git a/app/src/main/java/xyz/quaver/pupil/ui/fragment/ManageStorageFragment.kt b/app/src/main/java/xyz/quaver/pupil/ui/fragment/ManageStorageFragment.kt index fbaca241..4efa9357 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/fragment/ManageStorageFragment.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/fragment/ManageStorageFragment.kt @@ -48,7 +48,7 @@ class ManageStorageFragment : PreferenceFragmentCompat(), Preference.OnPreferenc override fun onPreferenceClick(preference: Preference?): Boolean { val context = context ?: return false - with(preference) { + with (preference) { this ?: return false when (key) { @@ -141,7 +141,7 @@ class ManageStorageFragment : PreferenceFragmentCompat(), Preference.OnPreferenc private fun initPreferences() { val context = context ?: return - with(findPreference("delete_cache")) { + with (findPreference("delete_cache")) { this ?: return@with val dir = File(context.cacheDir, "imageCache") @@ -162,7 +162,7 @@ class ManageStorageFragment : PreferenceFragmentCompat(), Preference.OnPreferenc onPreferenceClickListener = this@ManageStorageFragment } - with(findPreference("delete_downloads")) { + with (findPreference("delete_downloads")) { this ?: return@with val dir = DownloadManager.getInstance(context).downloadFolder @@ -184,7 +184,7 @@ class ManageStorageFragment : PreferenceFragmentCompat(), Preference.OnPreferenc onPreferenceClickListener = this@ManageStorageFragment } - with(findPreference("clear_history")) { + with (findPreference("clear_history")) { this ?: return@with summary = context.getString(R.string.settings_clear_history_summary, histories.size) diff --git a/app/src/main/java/xyz/quaver/pupil/ui/fragment/SettingsFragment.kt b/app/src/main/java/xyz/quaver/pupil/ui/fragment/SettingsFragment.kt index d852a06c..530a8af1 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/fragment/SettingsFragment.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/fragment/SettingsFragment.kt @@ -155,7 +155,7 @@ class SettingsFragment : override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { key ?: return - with(findPreference(key)) { + with (findPreference(key)) { this ?: return when (key) { diff --git a/app/src/main/java/xyz/quaver/pupil/ui/view/FloatingSearchView.kt b/app/src/main/java/xyz/quaver/pupil/ui/view/FloatingSearchView.kt index 064f3d0c..d3d5f026 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/view/FloatingSearchView.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/view/FloatingSearchView.kt @@ -28,18 +28,20 @@ import android.util.AttributeSet import android.view.LayoutInflater import android.view.View import android.view.inputmethod.EditorInfo -import android.widget.ImageView -import android.widget.LinearLayout import android.widget.TextView import androidx.core.content.ContextCompat import androidx.core.content.res.ResourcesCompat import androidx.swiperefreshlayout.widget.CircularProgressDrawable import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat import xyz.quaver.floatingsearchview.FloatingSearchView +import xyz.quaver.floatingsearchview.databinding.SearchSuggestionItemBinding import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion import xyz.quaver.floatingsearchview.util.view.SearchInputView import xyz.quaver.pupil.R +import xyz.quaver.pupil.databinding.SuggestionCountBinding import xyz.quaver.pupil.favoriteTags +import xyz.quaver.pupil.sources.DefaultSearchSuggestion +import xyz.quaver.pupil.sources.Hitomi import xyz.quaver.pupil.types.* import java.util.* @@ -53,13 +55,15 @@ class FloatingSearchView @JvmOverloads constructor(context: Context, attrs: Attr var onHistoryDeleteClickedListener: ((String) -> Unit)? = null var onFavoriteHistorySwitchClickListener: (() -> Unit)? = null + var onSuggestionBinding: ((SearchSuggestionItemBinding, SearchSuggestion) -> Unit)? = null + init { searchInputView.imeOptions = EditorInfo.IME_FLAG_NO_EXTRACT_UI or searchInputView.imeOptions searchInputView.addTextChangedListener(this) onSearchListener = this - onBindSuggestionCallback = { a, b, c, d, e -> - onBindSuggestion(a, b, c, d, e) + onBindSuggestionCallback = { binding, item, _ -> + onBindSuggestion(binding, item) } } @@ -80,17 +84,17 @@ class FloatingSearchView @JvmOverloads constructor(context: Context, attrs: Attr override fun onSuggestionClicked(searchSuggestion: SearchSuggestion?) { when (searchSuggestion) { - is TagSuggestion -> { + is Hitomi.TagSuggestion -> { val tag = "${searchSuggestion.n}:${searchSuggestion.s.replace(Regex("\\s"), "_")}" - with(searchInputView.text!!) { + with (searchInputView.text!!) { delete(if (lastIndexOf(' ') == -1) 0 else lastIndexOf(' ') + 1, length) if (!this.contains(tag)) append("$tag ") } } - is Suggestion -> { - with(searchInputView.text!!) { + is HistorySuggestion -> { + with (searchInputView.text!!) { clear() append(searchSuggestion.body) } @@ -101,114 +105,23 @@ class FloatingSearchView @JvmOverloads constructor(context: Context, attrs: Attr override fun onSearchAction(currentQuery: String?) {} - fun onBindSuggestion( - suggestionView: View?, - leftIcon: ImageView?, - textView: TextView?, - item: SearchSuggestion?, - itemPosition: Int - ) { - when(item) { - is TagSuggestion -> { - val tag = "${item.n}:${item.s.replace(Regex("\\s"), "_")}" - - leftIcon?.setImageDrawable( - ResourcesCompat.getDrawable( - resources, - when(item.n) { - "female" -> R.drawable.gender_female - "male" -> R.drawable.gender_male - "language" -> R.drawable.translate - "group" -> R.drawable.account_group - "character" -> R.drawable.account_star - "series" -> R.drawable.book_open - "artist" -> R.drawable.brush - else -> R.drawable.tag - }, - context.theme) - ) - - with(suggestionView?.findViewById(R.id.right_icon)) { - this ?: return@with - - if (favoriteTags.contains(Tag.parse(tag))) - setImageResource(R.drawable.ic_star_filled) - else - setImageResource(R.drawable.ic_star_empty) - - visibility = View.VISIBLE - rotation = 0f - - isEnabled = true - isClickable = true - - setOnClickListener { - val tag = Tag.parse(tag) - - if (favoriteTags.contains(tag)) { - setImageResource(R.drawable.ic_star_empty) - favoriteTags.remove(tag) - } - else { - setImageDrawable( - AnimatedVectorDrawableCompat.create(context, - R.drawable.avd_star - )) - (drawable as Animatable).start() - - favoriteTags.add(tag) - } - } - } - - if (item.t > 0) { - (suggestionView as? LinearLayout)?.let { - val count = it.findViewById(R.id.count) - if (count == null) - it.addView( - LayoutInflater.from(context).inflate(R.layout.suggestion_count, suggestionView, false) - .apply { - this as TextView - - text = item.t.toString() - }, 2 - ) - else - count.text = item.t.toString() - } - } - } + private fun onBindSuggestion(binding: SearchSuggestionItemBinding, item: SearchSuggestion) { + when(item) { is FavoriteHistorySwitch -> { - leftIcon?.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.swap_horizontal, context.theme)) - } - is Suggestion -> { - leftIcon?.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.history, context.theme)) - - with(suggestionView?.findViewById(R.id.right_icon)) { - this ?: return@with - - setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.delete, context.theme)) - - visibility = View.VISIBLE - rotation = 0f - - isEnabled = true - isClickable = true - - setOnClickListener { - onHistoryDeleteClickedListener?.invoke(item.body) - } - } + binding.leftIcon.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.swap_horizontal, context.theme)) } is LoadingSuggestion -> { - leftIcon?.setImageDrawable(CircularProgressDrawable(context).also { + binding.leftIcon.setImageDrawable(CircularProgressDrawable(context).also { it.setStyle(CircularProgressDrawable.DEFAULT) it.colorFilter = PorterDuffColorFilter(ContextCompat.getColor(context, R.color.colorAccent), PorterDuff.Mode.SRC_IN) it.start() }) } is NoResultSuggestion -> { - leftIcon?.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.close, context.theme)) + binding.leftIcon.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.close, context.theme)) + } + else -> { + onSuggestionBinding?.invoke(binding, item) } } } diff --git a/app/src/main/java/xyz/quaver/pupil/ui/view/TagChip.kt b/app/src/main/java/xyz/quaver/pupil/ui/view/TagChip.kt index 6de28c78..93421314 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/view/TagChip.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/view/TagChip.kt @@ -24,7 +24,7 @@ import androidx.core.content.ContextCompat import com.google.android.material.chip.Chip import xyz.quaver.pupil.R import xyz.quaver.pupil.favoriteTags -import xyz.quaver.pupil.sources.hitomi.Hitomi +import xyz.quaver.pupil.sources.Hitomi import xyz.quaver.pupil.types.Tag import xyz.quaver.pupil.util.translations import xyz.quaver.pupil.util.wordCapitalize