Improve explore fragment
parent
b7442fe445
commit
49634a2f52
@ -1,71 +1,40 @@
|
||||
package org.koitharu.kotatsu.explore.ui
|
||||
|
||||
import androidx.core.os.LocaleListCompat
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onStart
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.ui.BaseViewModel
|
||||
import org.koitharu.kotatsu.core.model.getLocaleTitle
|
||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
import org.koitharu.kotatsu.explore.ui.model.ExploreItem
|
||||
import org.koitharu.kotatsu.utils.ext.map
|
||||
import java.util.*
|
||||
|
||||
private const val KEY_ENABLED = "!"
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import org.koitharu.kotatsu.utils.ext.asLiveDataDistinct
|
||||
|
||||
class ExploreViewModel(
|
||||
private val settings: AppSettings,
|
||||
) : BaseViewModel() {
|
||||
|
||||
val items = MutableLiveData<List<ExploreItem>>(emptyList())
|
||||
|
||||
init {
|
||||
buildList()
|
||||
}
|
||||
val content: LiveData<List<ExploreItem>> = settings.observe()
|
||||
.filter { it == AppSettings.KEY_SOURCES_HIDDEN || it == AppSettings.KEY_SOURCES_ORDER }
|
||||
.onStart { emit("") }
|
||||
.map { settings.getMangaSources(includeHidden = false) }
|
||||
.distinctUntilChanged()
|
||||
.map { buildList(it) }
|
||||
.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default, emptyList())
|
||||
|
||||
private fun buildList() {
|
||||
val sources = settings.getMangaSources(includeHidden = true)
|
||||
val hiddenSources = settings.hiddenSources
|
||||
val map = sources.groupByTo(TreeMap(LocaleKeyComparator())) {
|
||||
if (it.name !in hiddenSources) {
|
||||
KEY_ENABLED
|
||||
} else {
|
||||
it.locale
|
||||
}
|
||||
}
|
||||
val result = ArrayList<ExploreItem>(sources.size + map.size + 1)
|
||||
private fun buildList(sources: List<MangaSource>): List<ExploreItem> {
|
||||
val result = ArrayList<ExploreItem>(sources.size + 2)
|
||||
result += ExploreItem.Buttons
|
||||
val enabledSources = map.remove(KEY_ENABLED)
|
||||
if (!enabledSources.isNullOrEmpty()) {
|
||||
if (sources.isNotEmpty()) {
|
||||
result += ExploreItem.Header(R.string.enabled_sources)
|
||||
enabledSources.mapTo(result) {
|
||||
ExploreItem.Source(
|
||||
source = it,
|
||||
summary = it.getLocaleTitle(),
|
||||
)
|
||||
}
|
||||
}
|
||||
items.value = result
|
||||
}
|
||||
|
||||
private class LocaleKeyComparator : Comparator<String?> {
|
||||
|
||||
private val deviceLocales = LocaleListCompat.getAdjustedDefault()
|
||||
.map { it.language }
|
||||
|
||||
override fun compare(a: String?, b: String?): Int {
|
||||
when {
|
||||
a == b -> return 0
|
||||
a == null -> return 1
|
||||
b == null -> return -1
|
||||
}
|
||||
val ai = deviceLocales.indexOf(a!!)
|
||||
val bi = deviceLocales.indexOf(b!!)
|
||||
return when {
|
||||
ai < 0 && bi < 0 -> a.compareTo(b)
|
||||
ai < 0 -> 1
|
||||
bi < 0 -> -1
|
||||
else -> ai.compareTo(bi)
|
||||
}
|
||||
sources.mapTo(result) { ExploreItem.Source(it) }
|
||||
} else {
|
||||
// TODO
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,66 @@
|
||||
package org.koitharu.kotatsu.utils.image
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.*
|
||||
import android.graphics.drawable.Drawable
|
||||
import androidx.core.graphics.ColorUtils
|
||||
import kotlin.math.absoluteValue
|
||||
|
||||
class FaviconFallbackDrawable(
|
||||
context: Context,
|
||||
name: String,
|
||||
) : Drawable() {
|
||||
|
||||
private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
|
||||
private val letter = name.take(1).uppercase()
|
||||
private val color = colorOfString(name)
|
||||
private val textBounds = Rect()
|
||||
private val tempRect = Rect()
|
||||
|
||||
init {
|
||||
paint.style = Paint.Style.FILL
|
||||
paint.textAlign = Paint.Align.CENTER
|
||||
paint.isFakeBoldText = true
|
||||
}
|
||||
|
||||
override fun draw(canvas: Canvas) {
|
||||
val cx = bounds.exactCenterX()
|
||||
paint.color = color
|
||||
canvas.drawPaint(paint)
|
||||
paint.color = Color.WHITE
|
||||
val ty = bounds.height() / 2f + textBounds.height() / 2f - textBounds.bottom
|
||||
canvas.drawText(letter, cx, ty, paint)
|
||||
}
|
||||
|
||||
override fun onBoundsChange(bounds: Rect) {
|
||||
super.onBoundsChange(bounds)
|
||||
val innerWidth = bounds.width() - (paint.strokeWidth * 2f)
|
||||
paint.textSize = getTextSizeForWidth(innerWidth, "100%")
|
||||
paint.getTextBounds(letter, 0, letter.length, textBounds)
|
||||
invalidateSelf()
|
||||
}
|
||||
|
||||
override fun setAlpha(alpha: Int) {
|
||||
paint.alpha = alpha
|
||||
}
|
||||
|
||||
override fun setColorFilter(colorFilter: ColorFilter?) {
|
||||
paint.colorFilter = colorFilter
|
||||
}
|
||||
|
||||
@Suppress("DeprecatedCallableAddReplaceWith")
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun getOpacity() = PixelFormat.TRANSPARENT
|
||||
|
||||
private fun getTextSizeForWidth(width: Float, text: String): Float {
|
||||
val testTextSize = 48f
|
||||
paint.textSize = testTextSize
|
||||
paint.getTextBounds(text, 0, text.length, tempRect)
|
||||
return testTextSize * width / tempRect.width()
|
||||
}
|
||||
|
||||
private fun colorOfString(str: String): Int {
|
||||
val hue = (str.hashCode() % 360).absoluteValue.toFloat()
|
||||
return ColorUtils.HSLToColor(floatArrayOf(hue, 0.5f, 0.5f))
|
||||
}
|
||||
}
|
||||
@ -1,62 +1,63 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<GridLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:columnCount="2"
|
||||
android:orientation="vertical"
|
||||
android:paddingHorizontal="8dp"
|
||||
android:paddingVertical="4dp">
|
||||
android:rowCount="2">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/favourites"
|
||||
android:id="@+id/button_history"
|
||||
style="@style/Widget.Kotatsu.ExploreButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_columnWeight="0.5"
|
||||
android:layout_gravity="fill_horizontal"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:text="@string/history"
|
||||
app:icon="@drawable/ic_history"
|
||||
app:layout_constraintEnd_toStartOf="@+id/local_storage"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
app:icon="@drawable/ic_history" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/local_storage"
|
||||
android:id="@+id/button_suggestions"
|
||||
style="@style/Widget.Kotatsu.ExploreButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/local_storage"
|
||||
app:icon="@drawable/ic_storage"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toEndOf="@+id/favourites"
|
||||
app:layout_constraintTop_toTopOf="@+id/favourites" />
|
||||
android:layout_columnWeight="0.5"
|
||||
android:layout_gravity="fill_horizontal"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:text="@string/suggestions"
|
||||
app:icon="@drawable/ic_suggestion" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/suggestions"
|
||||
android:id="@+id/button_local"
|
||||
style="@style/Widget.Kotatsu.ExploreButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:text="@string/suggestions"
|
||||
app:icon="@drawable/ic_suggestion"
|
||||
app:layout_constraintEnd_toStartOf="@+id/downloads"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="@+id/favourites"
|
||||
app:layout_constraintTop_toBottomOf="@+id/favourites" />
|
||||
android:layout_columnWeight="0.5"
|
||||
android:layout_gravity="fill_horizontal"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:text="@string/local_storage"
|
||||
app:icon="@drawable/ic_storage" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/downloads"
|
||||
android:id="@+id/button_bookmarks"
|
||||
style="@style/Widget.Kotatsu.ExploreButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_columnWeight="0.5"
|
||||
android:layout_gravity="fill_horizontal"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:text="@string/bookmarks"
|
||||
app:icon="@drawable/ic_bookmark"
|
||||
app:layout_constraintEnd_toEndOf="@+id/local_storage"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toEndOf="@+id/suggestions"
|
||||
app:layout_constraintTop_toBottomOf="@+id/local_storage" />
|
||||
app:icon="@drawable/ic_bookmark" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</GridLayout>
|
||||
Loading…
Reference in New Issue