Suggestion
This commit is contained in:
@@ -44,8 +44,10 @@ android {
|
|||||||
}
|
}
|
||||||
buildTypes {
|
buildTypes {
|
||||||
debug {
|
debug {
|
||||||
minifyEnabled true
|
minifyEnabled false
|
||||||
shrinkResources true
|
shrinkResources false
|
||||||
|
|
||||||
|
multiDexEnabled true
|
||||||
|
|
||||||
debuggable true
|
debuggable true
|
||||||
applicationIdSuffix ".debug"
|
applicationIdSuffix ".debug"
|
||||||
@@ -128,7 +130,7 @@ dependencies {
|
|||||||
|
|
||||||
implementation "xyz.quaver:libpupil:1.9.7"
|
implementation "xyz.quaver:libpupil:1.9.7"
|
||||||
implementation "xyz.quaver:documentfilex:0.4-alpha02"
|
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"
|
testImplementation "junit:junit:4.13.1"
|
||||||
androidTestImplementation "androidx.test.ext:junit:1.1.2"
|
androidTestImplementation "androidx.test.ext:junit:1.1.2"
|
||||||
|
|||||||
@@ -20,18 +20,18 @@ package xyz.quaver.pupil.adapters
|
|||||||
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.core.graphics.drawable.DrawableCompat
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion
|
||||||
import xyz.quaver.pupil.databinding.SourceSelectDialogItemBinding
|
import xyz.quaver.pupil.databinding.SourceSelectDialogItemBinding
|
||||||
import xyz.quaver.pupil.sources.Source
|
import xyz.quaver.pupil.sources.Source
|
||||||
import xyz.quaver.pupil.sources.sourceIcons
|
import xyz.quaver.pupil.sources.sourceIcons
|
||||||
|
|
||||||
class SourceAdapter(private val sources: List<Source<*>>) : RecyclerView.Adapter<SourceAdapter.ViewHolder>() {
|
class SourceAdapter(private val sources: List<Source<*, SearchSuggestion>>) : RecyclerView.Adapter<SourceAdapter.ViewHolder>() {
|
||||||
|
|
||||||
var onSourceSelectedListener: ((Source<*>) -> Unit)? = null
|
var onSourceSelectedListener: ((Source<*, SearchSuggestion>) -> Unit)? = null
|
||||||
|
|
||||||
inner class ViewHolder(private val binding: SourceSelectDialogItemBinding) : RecyclerView.ViewHolder(binding.root) {
|
inner class ViewHolder(private val binding: SourceSelectDialogItemBinding) : RecyclerView.ViewHolder(binding.root) {
|
||||||
lateinit var source: Source<*>
|
lateinit var source: Source<*, SearchSuggestion>
|
||||||
|
|
||||||
init {
|
init {
|
||||||
binding.go.setOnClickListener {
|
binding.go.setOnClickListener {
|
||||||
@@ -39,7 +39,7 @@ class SourceAdapter(private val sources: List<Source<*>>) : RecyclerView.Adapter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun bind(source: Source<*>) {
|
fun bind(source: Source<*, SearchSuggestion>) {
|
||||||
this.source = source
|
this.source = source
|
||||||
|
|
||||||
binding.icon.setImageDrawable(sourceIcons[source.name])
|
binding.icon.setImageDrawable(sourceIcons[source.name])
|
||||||
|
|||||||
@@ -22,9 +22,10 @@ import android.content.Context
|
|||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import kotlinx.coroutines.channels.Channel
|
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.R
|
||||||
import xyz.quaver.pupil.sources.hitomi.Hitomi
|
|
||||||
import xyz.quaver.pupil.sources.hitomi.Hiyobi
|
|
||||||
|
|
||||||
data class SearchResult(
|
data class SearchResult(
|
||||||
val id: String,
|
val id: String,
|
||||||
@@ -56,15 +57,24 @@ data class SearchResult(
|
|||||||
enum class DefaultSortMode {
|
enum class DefaultSortMode {
|
||||||
DEFAULT
|
DEFAULT
|
||||||
}
|
}
|
||||||
interface Source<Query_SortMode : Enum<Query_SortMode>> {
|
|
||||||
val name: String
|
|
||||||
val iconResID: Int
|
|
||||||
val availableSortMode: Array<Query_SortMode>
|
|
||||||
|
|
||||||
suspend fun query(query: String, range: IntRange, sortMode: Enum<*>) : Pair<Channel<SearchResult>, Int>
|
@Parcelize
|
||||||
|
class DefaultSearchSuggestion(override val body: String) : SearchSuggestion
|
||||||
|
|
||||||
|
abstract class Source<Query_SortMode: Enum<Query_SortMode>, Suggestion: SearchSuggestion> {
|
||||||
|
abstract val name: String
|
||||||
|
abstract val iconResID: Int
|
||||||
|
abstract val availableSortMode: Array<Query_SortMode>
|
||||||
|
|
||||||
|
abstract suspend fun search(query: String, range: IntRange, sortMode: Enum<*>) : Pair<Channel<SearchResult>, Int>
|
||||||
|
abstract suspend fun suggestion(query: String) : List<Suggestion>
|
||||||
|
|
||||||
|
open fun onSuggestionBind(binding: SearchSuggestionItemBinding, item: Suggestion) {
|
||||||
|
binding.leftIcon.setImageResource(R.drawable.tag)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val sources = mutableMapOf<String, Source<*>>()
|
val sources = mutableMapOf<String, Source<*, SearchSuggestion>>()
|
||||||
val sourceIcons = mutableMapOf<String, Drawable?>()
|
val sourceIcons = mutableMapOf<String, Drawable?>()
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
@@ -74,7 +84,7 @@ fun initSources(context: Context) {
|
|||||||
Hitomi(),
|
Hitomi(),
|
||||||
Hiyobi()
|
Hiyobi()
|
||||||
).forEach {
|
).forEach {
|
||||||
sources[it.name] = it
|
sources[it.name] = it as Source<*, SearchSuggestion>
|
||||||
sourceIcons[it.name] = ContextCompat.getDrawable(context, it.iconResID)
|
sourceIcons[it.name] = ContextCompat.getDrawable(context, it.iconResID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -16,26 +16,45 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
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.*
|
||||||
import kotlinx.coroutines.channels.Channel
|
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.hitomi.*
|
||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.R
|
||||||
import xyz.quaver.pupil.sources.SearchResult
|
|
||||||
import xyz.quaver.pupil.sources.SearchResult.ExtraType
|
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 xyz.quaver.pupil.util.wordCapitalize
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
class Hitomi : Source<Hitomi.SortMode> {
|
class Hitomi : Source<Hitomi.SortMode, Hitomi.TagSuggestion>() {
|
||||||
|
|
||||||
enum class SortMode {
|
enum class SortMode {
|
||||||
NEWEST,
|
NEWEST,
|
||||||
POPULAR
|
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 name: String = "hitomi.la"
|
||||||
override val iconResID: Int = R.drawable.hitomi
|
override val iconResID: Int = R.drawable.hitomi
|
||||||
override val availableSortMode: Array<SortMode> = SortMode.values()
|
override val availableSortMode: Array<SortMode> = SortMode.values()
|
||||||
@@ -44,7 +63,7 @@ class Hitomi : Source<Hitomi.SortMode> {
|
|||||||
var cachedSortMode: SortMode? = null
|
var cachedSortMode: SortMode? = null
|
||||||
val cache = mutableListOf<Int>()
|
val cache = mutableListOf<Int>()
|
||||||
|
|
||||||
override suspend fun query(query: String, range: IntRange, sortMode: Enum<*>): Pair<Channel<SearchResult>, Int> {
|
override suspend fun search(query: String, range: IntRange, sortMode: Enum<*>): Pair<Channel<SearchResult>, Int> {
|
||||||
if (cachedQuery != query || cachedSortMode != sortMode || cache.isEmpty()) {
|
if (cachedQuery != query || cachedSortMode != sortMode || cache.isEmpty()) {
|
||||||
cachedQuery = null
|
cachedQuery = null
|
||||||
cache.clear()
|
cache.clear()
|
||||||
@@ -79,6 +98,44 @@ class Hitomi : Source<Hitomi.SortMode> {
|
|||||||
return Pair(channel, cache.size)
|
return Pair(channel, cache.size)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun suggestion(query: String) : List<TagSuggestion> {
|
||||||
|
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<TextView>(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 {
|
companion object {
|
||||||
val languageMap = mapOf(
|
val languageMap = mapOf(
|
||||||
"indonesian" to "Bahasa Indonesia",
|
"indonesian" to "Bahasa Indonesia",
|
||||||
@@ -16,27 +16,30 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package xyz.quaver.pupil.sources.hitomi
|
package xyz.quaver.pupil.sources
|
||||||
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import androidx.core.content.ContextCompat
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.channels.Channel
|
import kotlinx.coroutines.channels.Channel
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.serialization.decodeFromString
|
||||||
import xyz.quaver.hitomi.galleryblockdir
|
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.hiyobi.*
|
||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.R
|
||||||
import xyz.quaver.pupil.sources.DefaultSortMode
|
import xyz.quaver.pupil.client
|
||||||
import xyz.quaver.pupil.sources.SearchResult
|
|
||||||
import xyz.quaver.pupil.sources.Source
|
|
||||||
import xyz.quaver.pupil.util.wordCapitalize
|
import xyz.quaver.pupil.util.wordCapitalize
|
||||||
|
import java.io.IOException
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
class Hiyobi : Source<DefaultSortMode> {
|
class Hiyobi : Source<DefaultSortMode, DefaultSearchSuggestion>() {
|
||||||
|
|
||||||
override val name: String = "hiyobi.me"
|
override val name: String = "hiyobi.me"
|
||||||
override val iconResID: Int = R.drawable.ic_hiyobi
|
override val iconResID: Int = R.drawable.ic_hiyobi
|
||||||
override val availableSortMode: Array<DefaultSortMode> = DefaultSortMode.values()
|
override val availableSortMode: Array<DefaultSortMode> = DefaultSortMode.values()
|
||||||
|
|
||||||
override suspend fun query(query: String, range: IntRange, sortMode: Enum<*>): Pair<Channel<SearchResult>, Int> {
|
override suspend fun search(query: String, range: IntRange, sortMode: Enum<*>): Pair<Channel<SearchResult>, Int> {
|
||||||
val channel = Channel<SearchResult>()
|
val channel = Channel<SearchResult>()
|
||||||
|
|
||||||
val (results, total) = if (query.isEmpty())
|
val (results, total) = if (query.isEmpty())
|
||||||
@@ -55,7 +58,58 @@ class Hiyobi : Source<DefaultSortMode> {
|
|||||||
return Pair(channel, total)
|
return Pair(channel, total)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun suggestion(query: String): List<DefaultSearchSuggestion> {
|
||||||
|
val result = mutableSetOf<String>()
|
||||||
|
|
||||||
|
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 {
|
companion object {
|
||||||
|
private fun downloadAllTags(): Deferred<List<String>> = 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<List<String>>? = null
|
||||||
|
|
||||||
|
val allTags: Deferred<List<String>>
|
||||||
|
get() = if (_allTags == null || (_allTags!!.isCompleted && runBlocking { _allTags!!.await() }.isEmpty())) downloadAllTags().also {
|
||||||
|
_allTags = it
|
||||||
|
} else _allTags!!
|
||||||
|
|
||||||
fun transform(galleryBlock: GalleryBlock): SearchResult =
|
fun transform(galleryBlock: GalleryBlock): SearchResult =
|
||||||
SearchResult(
|
SearchResult(
|
||||||
galleryBlock.id,
|
galleryBlock.id,
|
||||||
@@ -18,26 +18,11 @@
|
|||||||
|
|
||||||
package xyz.quaver.pupil.types
|
package xyz.quaver.pupil.types
|
||||||
|
|
||||||
import kotlinx.parcelize.IgnoredOnParcel
|
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion
|
import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion
|
||||||
import xyz.quaver.hitomi.Suggestion
|
|
||||||
import xyz.quaver.pupil.util.translations
|
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
data class TagSuggestion(val s: String, val t: Int, val u: String, val n: String) : SearchSuggestion {
|
class HistorySuggestion(override val body: 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
|
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
class NoResultSuggestion(override val body: String) : SearchSuggestion
|
class NoResultSuggestion(override val body: String) : SearchSuggestion
|
||||||
|
|||||||
@@ -47,7 +47,6 @@ import kotlinx.coroutines.channels.Channel
|
|||||||
import xyz.quaver.floatingsearchview.FloatingSearchView
|
import xyz.quaver.floatingsearchview.FloatingSearchView
|
||||||
import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion
|
import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion
|
||||||
import xyz.quaver.floatingsearchview.util.view.SearchInputView
|
import xyz.quaver.floatingsearchview.util.view.SearchInputView
|
||||||
import xyz.quaver.hitomi.getSuggestionsForQuery
|
|
||||||
import xyz.quaver.pupil.*
|
import xyz.quaver.pupil.*
|
||||||
import xyz.quaver.pupil.adapters.SearchResultsAdapter
|
import xyz.quaver.pupil.adapters.SearchResultsAdapter
|
||||||
import xyz.quaver.pupil.databinding.MainActivityBinding
|
import xyz.quaver.pupil.databinding.MainActivityBinding
|
||||||
@@ -77,14 +76,14 @@ class MainActivity :
|
|||||||
private var query = ""
|
private var query = ""
|
||||||
set(value) {
|
set(value) {
|
||||||
field = value
|
field = value
|
||||||
with(findViewById<SearchInputView>(R.id.search_bar_text)) {
|
with (findViewById<SearchInputView>(R.id.search_bar_text)) {
|
||||||
if (text.toString() != value)
|
if (text.toString() != value)
|
||||||
setText(query, TextView.BufferType.EDITABLE)
|
setText(query, TextView.BufferType.EDITABLE)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private var queryStack = mutableListOf<String>()
|
private var queryStack = mutableListOf<String>()
|
||||||
|
|
||||||
private lateinit var source: Source<*>
|
private lateinit var source: Source<*, SearchSuggestion>
|
||||||
private lateinit var sortMode: Enum<*>
|
private lateinit var sortMode: Enum<*>
|
||||||
|
|
||||||
private var searchJob: Deferred<Pair<Channel<SearchResult>, Int>>? = null
|
private var searchJob: Deferred<Pair<Channel<SearchResult>, Int>>? = null
|
||||||
@@ -168,7 +167,7 @@ class MainActivity :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setSource(source: Source<*>) {
|
private fun setSource(source: Source<*, SearchSuggestion>) {
|
||||||
this.source = source
|
this.source = source
|
||||||
sortMode = source.availableSortMode.first()
|
sortMode = source.availableSortMode.first()
|
||||||
|
|
||||||
@@ -219,14 +218,14 @@ class MainActivity :
|
|||||||
//NavigationView
|
//NavigationView
|
||||||
binding.navView.setNavigationItemSelectedListener(this)
|
binding.navView.setNavigationItemSelectedListener(this)
|
||||||
|
|
||||||
with(binding.contents.cancelFab) {
|
with (binding.contents.cancelFab) {
|
||||||
setImageResource(R.drawable.cancel)
|
setImageResource(R.drawable.cancel)
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
DownloadService.cancel(this@MainActivity)
|
DownloadService.cancel(this@MainActivity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
with(binding.contents.jumpFab) {
|
with (binding.contents.jumpFab) {
|
||||||
setImageResource(R.drawable.ic_jump)
|
setImageResource(R.drawable.ic_jump)
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
val perPage = Preferences["per_page", "25"].toInt()
|
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)
|
setImageResource(R.drawable.shuffle_variant)
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
setImageDrawable(CircularProgressDrawable(context))
|
setImageDrawable(CircularProgressDrawable(context))
|
||||||
@@ -259,7 +258,7 @@ class MainActivity :
|
|||||||
val random = Random.Default.nextInt(totalItems)
|
val random = Random.Default.nextInt(totalItems)
|
||||||
|
|
||||||
val randomResult =
|
val randomResult =
|
||||||
source.query(
|
source.search(
|
||||||
query + Preferences["default_query", ""],
|
query + Preferences["default_query", ""],
|
||||||
random .. random,
|
random .. random,
|
||||||
sortMode
|
sortMode
|
||||||
@@ -281,7 +280,7 @@ class MainActivity :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
with(binding.contents.idFab) {
|
with (binding.contents.idFab) {
|
||||||
setImageResource(R.drawable.numeric)
|
setImageResource(R.drawable.numeric)
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
val editText = EditText(context).apply {
|
val editText = EditText(context).apply {
|
||||||
@@ -309,7 +308,7 @@ class MainActivity :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
with(binding.contents.swipePageTurnView) {
|
with (binding.contents.swipePageTurnView) {
|
||||||
setOnPageTurnListener(object: SwipePageTurnView.OnPageTurnListener {
|
setOnPageTurnListener(object: SwipePageTurnView.OnPageTurnListener {
|
||||||
override fun onPrev(page: Int) {
|
override fun onPrev(page: Int) {
|
||||||
currentPage--
|
currentPage--
|
||||||
@@ -344,7 +343,7 @@ class MainActivity :
|
|||||||
|
|
||||||
@SuppressLint("ClickableViewAccessibility")
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
private fun setupRecyclerView() {
|
private fun setupRecyclerView() {
|
||||||
with(binding.contents.recyclerview) {
|
with (binding.contents.recyclerview) {
|
||||||
adapter = SearchResultsAdapter(searchResults).apply {
|
adapter = SearchResultsAdapter(searchResults).apply {
|
||||||
onChipClickedHandler = {
|
onChipClickedHandler = {
|
||||||
query = it.toQuery()
|
query = it.toQuery()
|
||||||
@@ -406,24 +405,9 @@ class MainActivity :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var isFavorite = false
|
|
||||||
private val defaultSuggestions: List<SearchSuggestion>
|
|
||||||
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 var suggestionJob : Job? = null
|
||||||
private fun setupSearchBar() {
|
private fun setupSearchBar() {
|
||||||
with(binding.contents.searchview) {
|
with (binding.contents.searchview) {
|
||||||
onMenuStatusChangeListener = object: FloatingSearchView.OnMenuStatusChangeListener {
|
onMenuStatusChangeListener = object: FloatingSearchView.OnMenuStatusChangeListener {
|
||||||
override fun onMenuOpened() {
|
override fun onMenuOpened() {
|
||||||
(this@MainActivity.binding.contents.recyclerview.adapter as SearchResultsAdapter).closeAllItems()
|
(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 = {
|
onMenuItemClickListener = {
|
||||||
onActionMenuItemSelected(it)
|
onActionMenuItemSelected(it)
|
||||||
}
|
}
|
||||||
@@ -452,12 +427,6 @@ class MainActivity :
|
|||||||
|
|
||||||
suggestionJob?.cancel()
|
suggestionJob?.cancel()
|
||||||
|
|
||||||
if (query.isEmpty() or query.endsWith(' ')) {
|
|
||||||
swapSuggestions(defaultSuggestions)
|
|
||||||
|
|
||||||
return@lambda
|
|
||||||
}
|
|
||||||
|
|
||||||
swapSuggestions(listOf(LoadingSuggestion(getText(R.string.reader_loading).toString())))
|
swapSuggestions(listOf(LoadingSuggestion(getText(R.string.reader_loading).toString())))
|
||||||
|
|
||||||
val currentQuery = query.split(" ").last()
|
val currentQuery = query.split(" ").last()
|
||||||
@@ -466,16 +435,8 @@ class MainActivity :
|
|||||||
|
|
||||||
suggestionJob = CoroutineScope(Dispatchers.IO).launch {
|
suggestionJob = CoroutineScope(Dispatchers.IO).launch {
|
||||||
val suggestions = kotlin.runCatching {
|
val suggestions = kotlin.runCatching {
|
||||||
getSuggestionsForQuery(currentQuery).map { TagSuggestion(it) }.toMutableList()
|
source.suggestion(currentQuery)
|
||||||
}.getOrElse { mutableListOf() }
|
}.getOrElse { emptyList() }
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
swapSuggestions(if (suggestions.isNotEmpty()) suggestions else listOf(NoResultSuggestion(getText(R.string.main_no_result).toString())))
|
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 {
|
onFocusChangeListener = object: FloatingSearchView.OnFocusChangeListener {
|
||||||
override fun onFocus() {
|
override fun onFocus() {
|
||||||
if (query.isEmpty() or query.endsWith(' '))
|
|
||||||
swapSuggestions(defaultSuggestions)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onFocusCleared() {
|
override fun onFocusCleared() {
|
||||||
@@ -577,7 +541,7 @@ class MainActivity :
|
|||||||
|
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
searchJob = async(Dispatchers.IO) {
|
searchJob = async(Dispatchers.IO) {
|
||||||
source.query(
|
source.search(
|
||||||
query + Preferences["default_query", ""],
|
query + Preferences["default_query", ""],
|
||||||
(currentPage - 1) * perPage until currentPage * perPage,
|
(currentPage - 1) * perPage until currentPage * perPage,
|
||||||
sortMode
|
sortMode
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ class ReaderActivity : BaseActivity() {
|
|||||||
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
|
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
|
||||||
menuInflater.inflate(R.menu.reader, menu)
|
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
|
this ?: return@with
|
||||||
|
|
||||||
if (favorites.contains(galleryID))
|
if (favorites.contains(galleryID))
|
||||||
@@ -149,7 +149,7 @@ class ReaderActivity : BaseActivity() {
|
|||||||
// TODO: Switch to DialogFragment
|
// TODO: Switch to DialogFragment
|
||||||
val binding = NumberpickerDialogBinding.inflate(layoutInflater, binding.root, false)
|
val binding = NumberpickerDialogBinding.inflate(layoutInflater, binding.root, false)
|
||||||
|
|
||||||
with(binding.numberPicker) {
|
with (binding.numberPicker) {
|
||||||
minValue = 1
|
minValue = 1
|
||||||
maxValue = cache.metadata.reader?.files?.size ?: 0
|
maxValue = cache.metadata.reader?.files?.size ?: 0
|
||||||
value = currentPage
|
value = currentPage
|
||||||
@@ -265,7 +265,7 @@ class ReaderActivity : BaseActivity() {
|
|||||||
val reader = cache.metadata.reader
|
val reader = cache.metadata.reader
|
||||||
|
|
||||||
if (reader != null) {
|
if (reader != null) {
|
||||||
with(binding.recyclerview.adapter as ReaderAdapter) {
|
with (binding.recyclerview.adapter as ReaderAdapter) {
|
||||||
this.reader = reader
|
this.reader = reader
|
||||||
notifyDataSetChanged()
|
notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
@@ -297,7 +297,7 @@ class ReaderActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun initView() {
|
private fun initView() {
|
||||||
with(binding.recyclerview) {
|
with (binding.recyclerview) {
|
||||||
adapter = ReaderAdapter(this@ReaderActivity, galleryID).apply {
|
adapter = ReaderAdapter(this@ReaderActivity, galleryID).apply {
|
||||||
onItemClickListener = {
|
onItemClickListener = {
|
||||||
if (isScroll) {
|
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
|
animateDownloadFAB(DownloadManager.getInstance(this@ReaderActivity).getDownloadFolder(galleryID) != null) //If download in progress, animate button
|
||||||
|
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
@@ -348,14 +348,14 @@ class ReaderActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
with(binding.retryFab) {
|
with (binding.retryFab) {
|
||||||
setImageResource(R.drawable.refresh)
|
setImageResource(R.drawable.refresh)
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
DownloadService.download(context, galleryID)
|
DownloadService.download(context, galleryID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
with(binding.fullscreenFab) {
|
with (binding.fullscreenFab) {
|
||||||
setImageResource(R.drawable.ic_fullscreen)
|
setImageResource(R.drawable.ic_fullscreen)
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
isFullscreen = true
|
isFullscreen = true
|
||||||
@@ -367,7 +367,7 @@ class ReaderActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun fullscreen(isFullscreen: Boolean) {
|
private fun fullscreen(isFullscreen: Boolean) {
|
||||||
with(window.attributes) {
|
with (window.attributes) {
|
||||||
if (isFullscreen) {
|
if (isFullscreen) {
|
||||||
flags = flags or WindowManager.LayoutParams.FLAG_FULLSCREEN
|
flags = flags or WindowManager.LayoutParams.FLAG_FULLSCREEN
|
||||||
supportActionBar?.hide()
|
supportActionBar?.hide()
|
||||||
@@ -413,7 +413,7 @@ class ReaderActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun animateDownloadFAB(animate: Boolean) {
|
private fun animateDownloadFAB(animate: Boolean) {
|
||||||
with(binding.downloadFab) {
|
with (binding.downloadFab) {
|
||||||
if (animate) {
|
if (animate) {
|
||||||
val icon = AnimatedVectorDrawableCompat.create(context, R.drawable.ic_downloading)
|
val icon = AnimatedVectorDrawableCompat.create(context, R.drawable.ic_downloading)
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import androidx.appcompat.app.AlertDialog
|
|||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.R
|
||||||
import xyz.quaver.pupil.databinding.DefaultQueryDialogBinding
|
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.types.Tags
|
||||||
import xyz.quaver.pupil.util.Preferences
|
import xyz.quaver.pupil.util.Preferences
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ class DefaultQueryDialogFragment() : DialogFragment() {
|
|||||||
setPositiveButton(android.R.string.ok) { _, _ ->
|
setPositiveButton(android.R.string.ok) { _, _ ->
|
||||||
val newTags = Tags.parse(binding.edittext.text.toString())
|
val newTags = Tags.parse(binding.edittext.text.toString())
|
||||||
|
|
||||||
with(binding.languageSelector) {
|
with (binding.languageSelector) {
|
||||||
if (selectedItemPosition != 0)
|
if (selectedItemPosition != 0)
|
||||||
newTags.add("language:${reverseLanguages[selectedItem]}")
|
newTags.add("language:${reverseLanguages[selectedItem]}")
|
||||||
}
|
}
|
||||||
@@ -89,7 +89,7 @@ class DefaultQueryDialogFragment() : DialogFragment() {
|
|||||||
Preferences["default_query"]
|
Preferences["default_query"]
|
||||||
)
|
)
|
||||||
|
|
||||||
with(binding.languageSelector) {
|
with (binding.languageSelector) {
|
||||||
adapter =
|
adapter =
|
||||||
ArrayAdapter(
|
ArrayAdapter(
|
||||||
context,
|
context,
|
||||||
@@ -112,13 +112,13 @@ class DefaultQueryDialogFragment() : DialogFragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
with(binding.BLCheckbox) {
|
with (binding.BLCheckbox) {
|
||||||
isChecked = tags.contains(excludeBL)
|
isChecked = tags.contains(excludeBL)
|
||||||
if (tags.contains(excludeBL))
|
if (tags.contains(excludeBL))
|
||||||
tags.remove(excludeBL)
|
tags.remove(excludeBL)
|
||||||
}
|
}
|
||||||
|
|
||||||
with(binding.guroCheckbox) {
|
with (binding.guroCheckbox) {
|
||||||
isChecked = excludeGuro.all { tags.contains(it) }
|
isChecked = excludeGuro.all { tags.contains(it) }
|
||||||
if (excludeGuro.all { tags.contains(it) })
|
if (excludeGuro.all { tags.contains(it) })
|
||||||
excludeGuro.forEach {
|
excludeGuro.forEach {
|
||||||
@@ -126,7 +126,7 @@ class DefaultQueryDialogFragment() : DialogFragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
with(binding.loliCheckbox) {
|
with (binding.loliCheckbox) {
|
||||||
isChecked = excludeLoli.all { tags.contains(it) }
|
isChecked = excludeLoli.all { tags.contains(it) }
|
||||||
if (excludeLoli.all { tags.contains(it) })
|
if (excludeLoli.all { tags.contains(it) })
|
||||||
excludeLoli.forEach {
|
excludeLoli.forEach {
|
||||||
@@ -134,7 +134,7 @@ class DefaultQueryDialogFragment() : DialogFragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
with(binding.edittext) {
|
with (binding.edittext) {
|
||||||
setText(tags.toString(), android.widget.TextView.BufferType.EDITABLE)
|
setText(tags.toString(), android.widget.TextView.BufferType.EDITABLE)
|
||||||
addTextChangedListener(object : TextWatcher {
|
addTextChangedListener(object : TextWatcher {
|
||||||
override fun beforeTextChanged(
|
override fun beforeTextChanged(
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ import xyz.quaver.pupil.adapters.SearchResultsAdapter
|
|||||||
import xyz.quaver.pupil.adapters.ThumbnailPageAdapter
|
import xyz.quaver.pupil.adapters.ThumbnailPageAdapter
|
||||||
import xyz.quaver.pupil.databinding.*
|
import xyz.quaver.pupil.databinding.*
|
||||||
import xyz.quaver.pupil.favoriteTags
|
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.sources.SearchResult
|
||||||
import xyz.quaver.pupil.types.Tag
|
import xyz.quaver.pupil.types.Tag
|
||||||
import xyz.quaver.pupil.ui.ReaderActivity
|
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)
|
window?.setLayout(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
|
||||||
|
|
||||||
with(binding.fab) {
|
with (binding.fab) {
|
||||||
setImageDrawable(ContextCompat.getDrawable(context, R.drawable.arrow_right))
|
setImageDrawable(ContextCompat.getDrawable(context, R.drawable.arrow_right))
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
context.startActivity(Intent(context, ReaderActivity::class.java).apply {
|
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.title.text = gallery.title
|
||||||
binding.artist.text = gallery.artists.joinToString(", ") { it.wordCapitalize() }
|
binding.artist.text = gallery.artists.joinToString(", ") { it.wordCapitalize() }
|
||||||
|
|
||||||
with(binding.type) {
|
with (binding.type) {
|
||||||
text = gallery.type.wordCapitalize()
|
text = gallery.type.wordCapitalize()
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
gallery.type.let {
|
gallery.type.let {
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ class ProxyDialog(context: Context) : AlertDialog(context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
with(binding.typeSelector) {
|
with (binding.typeSelector) {
|
||||||
adapter = ArrayAdapter(
|
adapter = ArrayAdapter(
|
||||||
context,
|
context,
|
||||||
android.R.layout.simple_spinner_dropdown_item,
|
android.R.layout.simple_spinner_dropdown_item,
|
||||||
|
|||||||
@@ -25,13 +25,14 @@ import android.view.Window
|
|||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion
|
||||||
import xyz.quaver.pupil.adapters.SourceAdapter
|
import xyz.quaver.pupil.adapters.SourceAdapter
|
||||||
import xyz.quaver.pupil.sources.Source
|
import xyz.quaver.pupil.sources.Source
|
||||||
import xyz.quaver.pupil.sources.sources
|
import xyz.quaver.pupil.sources.sources
|
||||||
|
|
||||||
class SourceSelectDialog : DialogFragment() {
|
class SourceSelectDialog : DialogFragment() {
|
||||||
|
|
||||||
var onSourceSelectedListener: ((Source<*>) -> Unit)? = null
|
var onSourceSelectedListener: ((Source<*, SearchSuggestion>) -> Unit)? = null
|
||||||
|
|
||||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
return Dialog(requireContext()).apply {
|
return Dialog(requireContext()).apply {
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ class LockSettingsFragment : PreferenceFragmentCompat() {
|
|||||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
setPreferencesFromResource(R.xml.lock_preferences, rootKey)
|
setPreferencesFromResource(R.xml.lock_preferences, rootKey)
|
||||||
|
|
||||||
with(findPreference<Preference>("lock_pattern")) {
|
with (findPreference<Preference>("lock_pattern")) {
|
||||||
this!!
|
this!!
|
||||||
|
|
||||||
if (LockManager(requireContext()).contains(Lock.Type.PATTERN))
|
if (LockManager(requireContext()).contains(Lock.Type.PATTERN))
|
||||||
@@ -93,7 +93,7 @@ class LockSettingsFragment : PreferenceFragmentCompat() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
with(findPreference<Preference>("lock_pin")) {
|
with (findPreference<Preference>("lock_pin")) {
|
||||||
this!!
|
this!!
|
||||||
|
|
||||||
if (LockManager(requireContext()).contains(Lock.Type.PIN))
|
if (LockManager(requireContext()).contains(Lock.Type.PIN))
|
||||||
@@ -126,7 +126,7 @@ class LockSettingsFragment : PreferenceFragmentCompat() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
with(findPreference<Preference>("lock_fingerprint")) {
|
with (findPreference<Preference>("lock_fingerprint")) {
|
||||||
this!!
|
this!!
|
||||||
|
|
||||||
setOnPreferenceChangeListener { _, newValue ->
|
setOnPreferenceChangeListener { _, newValue ->
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ class ManageStorageFragment : PreferenceFragmentCompat(), Preference.OnPreferenc
|
|||||||
override fun onPreferenceClick(preference: Preference?): Boolean {
|
override fun onPreferenceClick(preference: Preference?): Boolean {
|
||||||
val context = context ?: return false
|
val context = context ?: return false
|
||||||
|
|
||||||
with(preference) {
|
with (preference) {
|
||||||
this ?: return false
|
this ?: return false
|
||||||
|
|
||||||
when (key) {
|
when (key) {
|
||||||
@@ -141,7 +141,7 @@ class ManageStorageFragment : PreferenceFragmentCompat(), Preference.OnPreferenc
|
|||||||
private fun initPreferences() {
|
private fun initPreferences() {
|
||||||
val context = context ?: return
|
val context = context ?: return
|
||||||
|
|
||||||
with(findPreference<Preference>("delete_cache")) {
|
with (findPreference<Preference>("delete_cache")) {
|
||||||
this ?: return@with
|
this ?: return@with
|
||||||
|
|
||||||
val dir = File(context.cacheDir, "imageCache")
|
val dir = File(context.cacheDir, "imageCache")
|
||||||
@@ -162,7 +162,7 @@ class ManageStorageFragment : PreferenceFragmentCompat(), Preference.OnPreferenc
|
|||||||
onPreferenceClickListener = this@ManageStorageFragment
|
onPreferenceClickListener = this@ManageStorageFragment
|
||||||
}
|
}
|
||||||
|
|
||||||
with(findPreference<Preference>("delete_downloads")) {
|
with (findPreference<Preference>("delete_downloads")) {
|
||||||
this ?: return@with
|
this ?: return@with
|
||||||
|
|
||||||
val dir = DownloadManager.getInstance(context).downloadFolder
|
val dir = DownloadManager.getInstance(context).downloadFolder
|
||||||
@@ -184,7 +184,7 @@ class ManageStorageFragment : PreferenceFragmentCompat(), Preference.OnPreferenc
|
|||||||
onPreferenceClickListener = this@ManageStorageFragment
|
onPreferenceClickListener = this@ManageStorageFragment
|
||||||
}
|
}
|
||||||
|
|
||||||
with(findPreference<Preference>("clear_history")) {
|
with (findPreference<Preference>("clear_history")) {
|
||||||
this ?: return@with
|
this ?: return@with
|
||||||
|
|
||||||
summary = context.getString(R.string.settings_clear_history_summary, histories.size)
|
summary = context.getString(R.string.settings_clear_history_summary, histories.size)
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ class SettingsFragment :
|
|||||||
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
|
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
|
||||||
key ?: return
|
key ?: return
|
||||||
|
|
||||||
with(findPreference<Preference>(key)) {
|
with (findPreference<Preference>(key)) {
|
||||||
this ?: return
|
this ?: return
|
||||||
|
|
||||||
when (key) {
|
when (key) {
|
||||||
|
|||||||
@@ -28,18 +28,20 @@ import android.util.AttributeSet
|
|||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.inputmethod.EditorInfo
|
import android.view.inputmethod.EditorInfo
|
||||||
import android.widget.ImageView
|
|
||||||
import android.widget.LinearLayout
|
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.content.res.ResourcesCompat
|
import androidx.core.content.res.ResourcesCompat
|
||||||
import androidx.swiperefreshlayout.widget.CircularProgressDrawable
|
import androidx.swiperefreshlayout.widget.CircularProgressDrawable
|
||||||
import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat
|
import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat
|
||||||
import xyz.quaver.floatingsearchview.FloatingSearchView
|
import xyz.quaver.floatingsearchview.FloatingSearchView
|
||||||
|
import xyz.quaver.floatingsearchview.databinding.SearchSuggestionItemBinding
|
||||||
import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion
|
import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion
|
||||||
import xyz.quaver.floatingsearchview.util.view.SearchInputView
|
import xyz.quaver.floatingsearchview.util.view.SearchInputView
|
||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.R
|
||||||
|
import xyz.quaver.pupil.databinding.SuggestionCountBinding
|
||||||
import xyz.quaver.pupil.favoriteTags
|
import xyz.quaver.pupil.favoriteTags
|
||||||
|
import xyz.quaver.pupil.sources.DefaultSearchSuggestion
|
||||||
|
import xyz.quaver.pupil.sources.Hitomi
|
||||||
import xyz.quaver.pupil.types.*
|
import xyz.quaver.pupil.types.*
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@@ -53,13 +55,15 @@ class FloatingSearchView @JvmOverloads constructor(context: Context, attrs: Attr
|
|||||||
var onHistoryDeleteClickedListener: ((String) -> Unit)? = null
|
var onHistoryDeleteClickedListener: ((String) -> Unit)? = null
|
||||||
var onFavoriteHistorySwitchClickListener: (() -> Unit)? = null
|
var onFavoriteHistorySwitchClickListener: (() -> Unit)? = null
|
||||||
|
|
||||||
|
var onSuggestionBinding: ((SearchSuggestionItemBinding, SearchSuggestion) -> Unit)? = null
|
||||||
|
|
||||||
init {
|
init {
|
||||||
searchInputView.imeOptions = EditorInfo.IME_FLAG_NO_EXTRACT_UI or searchInputView.imeOptions
|
searchInputView.imeOptions = EditorInfo.IME_FLAG_NO_EXTRACT_UI or searchInputView.imeOptions
|
||||||
|
|
||||||
searchInputView.addTextChangedListener(this)
|
searchInputView.addTextChangedListener(this)
|
||||||
onSearchListener = this
|
onSearchListener = this
|
||||||
onBindSuggestionCallback = { a, b, c, d, e ->
|
onBindSuggestionCallback = { binding, item, _ ->
|
||||||
onBindSuggestion(a, b, c, d, e)
|
onBindSuggestion(binding, item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,17 +84,17 @@ class FloatingSearchView @JvmOverloads constructor(context: Context, attrs: Attr
|
|||||||
|
|
||||||
override fun onSuggestionClicked(searchSuggestion: SearchSuggestion?) {
|
override fun onSuggestionClicked(searchSuggestion: SearchSuggestion?) {
|
||||||
when (searchSuggestion) {
|
when (searchSuggestion) {
|
||||||
is TagSuggestion -> {
|
is Hitomi.TagSuggestion -> {
|
||||||
val tag = "${searchSuggestion.n}:${searchSuggestion.s.replace(Regex("\\s"), "_")}"
|
val tag = "${searchSuggestion.n}:${searchSuggestion.s.replace(Regex("\\s"), "_")}"
|
||||||
with(searchInputView.text!!) {
|
with (searchInputView.text!!) {
|
||||||
delete(if (lastIndexOf(' ') == -1) 0 else lastIndexOf(' ') + 1, length)
|
delete(if (lastIndexOf(' ') == -1) 0 else lastIndexOf(' ') + 1, length)
|
||||||
|
|
||||||
if (!this.contains(tag))
|
if (!this.contains(tag))
|
||||||
append("$tag ")
|
append("$tag ")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is Suggestion -> {
|
is HistorySuggestion -> {
|
||||||
with(searchInputView.text!!) {
|
with (searchInputView.text!!) {
|
||||||
clear()
|
clear()
|
||||||
append(searchSuggestion.body)
|
append(searchSuggestion.body)
|
||||||
}
|
}
|
||||||
@@ -101,114 +105,23 @@ class FloatingSearchView @JvmOverloads constructor(context: Context, attrs: Attr
|
|||||||
|
|
||||||
override fun onSearchAction(currentQuery: String?) {}
|
override fun onSearchAction(currentQuery: String?) {}
|
||||||
|
|
||||||
fun onBindSuggestion(
|
private fun onBindSuggestion(binding: SearchSuggestionItemBinding, item: SearchSuggestion) {
|
||||||
suggestionView: View?,
|
|
||||||
leftIcon: ImageView?,
|
|
||||||
textView: TextView?,
|
|
||||||
item: SearchSuggestion?,
|
|
||||||
itemPosition: Int
|
|
||||||
) {
|
|
||||||
when(item) {
|
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<ImageView>(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<TextView>(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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is FavoriteHistorySwitch -> {
|
is FavoriteHistorySwitch -> {
|
||||||
leftIcon?.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.swap_horizontal, context.theme))
|
binding.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<ImageView>(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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
is LoadingSuggestion -> {
|
is LoadingSuggestion -> {
|
||||||
leftIcon?.setImageDrawable(CircularProgressDrawable(context).also {
|
binding.leftIcon.setImageDrawable(CircularProgressDrawable(context).also {
|
||||||
it.setStyle(CircularProgressDrawable.DEFAULT)
|
it.setStyle(CircularProgressDrawable.DEFAULT)
|
||||||
it.colorFilter = PorterDuffColorFilter(ContextCompat.getColor(context, R.color.colorAccent), PorterDuff.Mode.SRC_IN)
|
it.colorFilter = PorterDuffColorFilter(ContextCompat.getColor(context, R.color.colorAccent), PorterDuff.Mode.SRC_IN)
|
||||||
it.start()
|
it.start()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
is NoResultSuggestion -> {
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import androidx.core.content.ContextCompat
|
|||||||
import com.google.android.material.chip.Chip
|
import com.google.android.material.chip.Chip
|
||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.R
|
||||||
import xyz.quaver.pupil.favoriteTags
|
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.types.Tag
|
||||||
import xyz.quaver.pupil.util.translations
|
import xyz.quaver.pupil.util.translations
|
||||||
import xyz.quaver.pupil.util.wordCapitalize
|
import xyz.quaver.pupil.util.wordCapitalize
|
||||||
|
|||||||
Reference in New Issue
Block a user