diff --git a/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt b/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt index b4a97664e6..2ee8803f47 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt @@ -110,6 +110,25 @@ object Migrations { remove("enable_doh") } } + + val oldGridSize = prefs.getInt("grid_size", -1) + // Migrate to float for grid size + if (oldGridSize != -1) { + prefs.edit { + putFloat( + PreferenceKeys.gridSize, + when (oldGridSize) { + 4 -> 3f + 3 -> 1.5f + 2 -> 1f + 1 -> 0f + 0 -> -.5f + else -> .5f + } + ) + remove("grid_size") + } + } } return true } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt index 58d97903c0..b91ce7e426 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt @@ -150,7 +150,7 @@ object PreferenceKeys { const val libraryLayout = "pref_display_library_layout" - const val gridSize = "grid_size" + const val gridSize = "grid_size_float" const val uniformGrid = "uniform_grid" diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt index ff18bb112f..8105ea5fdf 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt @@ -242,7 +242,7 @@ class PreferencesHelper(val context: Context) { fun libraryLayout() = flowPrefs.getInt(Keys.libraryLayout, 2) - fun gridSize() = flowPrefs.getInt(Keys.gridSize, 2) + fun gridSize() = flowPrefs.getFloat(Keys.gridSize, 1f) fun uniformGrid() = flowPrefs.getBoolean(Keys.uniformGrid, true) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt index bb4e374b39..14271ed850 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt @@ -794,13 +794,7 @@ class LibraryController( end = 0 ) } else { - binding.libraryGridRecycler.recycler.columnWidth = when (preferences.gridSize().get()) { - 1 -> 1f - 2 -> 1.25f - 3 -> 1.66f - 4 -> 3f - else -> .75f - } + binding.libraryGridRecycler.recycler.setGridSize(preferences) binding.libraryGridRecycler.recycler.updatePaddingRelative( start = 5.dpToPx, end = 5.dpToPx @@ -809,7 +803,12 @@ class LibraryController( } private fun setPreferenceFlows() { - listOf(preferences.libraryLayout(), preferences.uniformGrid(), preferences.gridSize(), preferences.unreadBadgeType()).forEach { + listOf( + preferences.libraryLayout(), + preferences.uniformGrid(), + preferences.gridSize(), + preferences.unreadBadgeType() + ).forEach { it.asFlow() .drop(1) .onEach { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/display/LibraryDisplayView.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/display/LibraryDisplayView.kt index 6dea5d8242..97b0b444f5 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/display/LibraryDisplayView.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/display/LibraryDisplayView.kt @@ -1,10 +1,24 @@ package eu.kanade.tachiyomi.ui.library.display +import android.animation.ValueAnimator import android.content.Context +import android.text.Spannable +import android.text.SpannableStringBuilder +import android.text.style.ForegroundColorSpan import android.util.AttributeSet +import android.view.ViewTreeObserver +import android.widget.SeekBar +import androidx.core.animation.addListener +import androidx.core.view.isVisible +import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.databinding.LibraryDisplayLayoutBinding import eu.kanade.tachiyomi.util.bindToPreference +import eu.kanade.tachiyomi.util.system.dpToPx +import eu.kanade.tachiyomi.util.system.getResourceColor +import eu.kanade.tachiyomi.util.view.rowsForValue import eu.kanade.tachiyomi.widget.BaseLibraryDisplayView +import eu.kanade.tachiyomi.widget.EndAnimatorListener +import kotlin.math.roundToInt class LibraryDisplayView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : BaseLibraryDisplayView(context, attrs) { @@ -13,6 +27,93 @@ class LibraryDisplayView @JvmOverloads constructor(context: Context, attrs: Attr override fun initGeneralPreferences() { binding.displayGroup.bindToPreference(preferences.libraryLayout()) binding.uniformGrid.bindToPreference(preferences.uniformGrid()) - binding.gridSizeToggleGroup.bindToPreference(preferences.gridSize()) + binding.gridSeekbar.progress = ((preferences.gridSize().get() + .5f) * 2f).roundToInt() + binding.resetGridSize.setOnClickListener { + binding.gridSeekbar.progress = 3 + } + binding.root.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener { + override fun onGlobalLayout() { + if (binding.root.width > 0) { + setGridText(binding.gridSeekbar.progress) + binding.root.viewTreeObserver.removeOnGlobalLayoutListener(this) + } + } + }) + binding.gridSeekbar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { + override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { + if (seekBar != null && fromUser) { + alpha = 1f + isVisible = true + adjustSeekBarTip(seekBar, progress) + } + if (!fromUser) { + preferences.gridSize().set((progress / 2f) - .5f) + } + setGridText(progress) + } + + override fun onStartTrackingTouch(seekBar: SeekBar?) { + with(binding.seekBarTextView.root) { + alpha = 0f + isVisible = true + animate().alpha(1f).setDuration(250L).start() + seekBar?.post { + adjustSeekBarTip(seekBar, seekBar.progress) + } + } + } + + override fun onStopTrackingTouch(seekBar: SeekBar?) { + preferences.gridSize().set(((seekBar?.progress ?: 2) / 2f) - .5f) + with(binding.seekBarTextView.root) { + isVisible = true + alpha = 1f + post { + val anim = + ValueAnimator.ofFloat( + 1f, + 0f + ) // animate().alpha(0f).setDuration(250L) + anim.duration = 250 + anim.startDelay = 500 + anim.addUpdateListener { + alpha = it.animatedValue as Float + } + anim.addListener { + EndAnimatorListener { + isVisible = false + } + } + anim.start() + } + } + } + }) + } + + private fun setGridText(progress: Int) { + with(binding.gridSizeText) { + val rows = this@LibraryDisplayView.rowsForValue(progress) + val titleText = context.getString(R.string.grid_size) + val subtitleText = context.getString(R.string._per_row, rows) + val spannable = SpannableStringBuilder(titleText + "\n" + subtitleText) + spannable.setSpan( + ForegroundColorSpan(context.getResourceColor(android.R.attr.textColorSecondary)), + titleText.length + 1, + spannable.length, + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE + ) + text = spannable + } + } + + private fun adjustSeekBarTip(seekBar: SeekBar, progress: Int) { + with(binding.seekBarTextView.root) { + val value = + (progress * (seekBar.width - 12.dpToPx - 2 * seekBar.thumbOffset)) / seekBar.max + text = this@LibraryDisplayView.rowsForValue(progress).toString() + x = seekBar.x + value + seekBar.thumbOffset / 2 + 5.dpToPx + y = seekBar.y + binding.gridSizeLayout.y - 6.dpToPx - height + } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/display/TabbedLibraryDisplaySheet.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/display/TabbedLibraryDisplaySheet.kt index e40426b101..1b7d6fd881 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/display/TabbedLibraryDisplaySheet.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/display/TabbedLibraryDisplaySheet.kt @@ -11,7 +11,6 @@ import eu.kanade.tachiyomi.data.preference.getOrDefault import eu.kanade.tachiyomi.ui.library.LibraryController import eu.kanade.tachiyomi.ui.setting.SettingsLibraryController import eu.kanade.tachiyomi.util.view.compatToolTipText -import eu.kanade.tachiyomi.util.view.visible import eu.kanade.tachiyomi.util.view.withFadeTransaction import eu.kanade.tachiyomi.widget.TabbedBottomSheetDialog import uy.kohesive.injekt.Injekt diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/source/browse/BrowseSourceController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/source/browse/BrowseSourceController.kt index 8d0ba18453..5d43242746 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/source/browse/BrowseSourceController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/source/browse/BrowseSourceController.kt @@ -167,13 +167,7 @@ open class BrowseSourceController(bundle: Bundle) : } } else { (binding.catalogueView.inflate(R.layout.manga_recycler_autofit) as AutofitRecyclerView).apply { - columnWidth = when (preferences.gridSize().get()) { - 1 -> 1f - 2 -> 1.25f - 3 -> 1.66f - 4 -> 3f - else -> .75f - } + setGridSize(preferences) (layoutManager as androidx.recyclerview.widget.GridLayoutManager).spanSizeLookup = object : androidx.recyclerview.widget.GridLayoutManager.SpanSizeLookup() { override fun getSpanSize(position: Int): Int { diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/view/ViewExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/view/ViewExtensions.kt index 1d92e421b2..69d53c3875 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/view/ViewExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/view/ViewExtensions.kt @@ -37,8 +37,13 @@ import eu.kanade.tachiyomi.util.system.ThemeUtil import eu.kanade.tachiyomi.util.system.contextCompatColor import eu.kanade.tachiyomi.util.system.getPrefTheme import eu.kanade.tachiyomi.util.system.getResourceColor +import eu.kanade.tachiyomi.util.system.pxToDp +import eu.kanade.tachiyomi.widget.AutofitRecyclerView import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get +import kotlin.math.max +import kotlin.math.pow +import kotlin.math.roundToInt /** * Returns coordinates of view. @@ -338,6 +343,17 @@ fun RecyclerView.smoothScrollToTop() { } } +fun View.rowsForValue(value: Int): Int { + return rowsForValue((value / 2f) - .5f) +} + +fun View.rowsForValue(value: Float): Int { + val size = 1.5f.pow(value) + val trueSize = AutofitRecyclerView.MULTIPLE * ((size * 100 / AutofitRecyclerView.MULTIPLE).roundToInt()) / 100f + val dpWidth = (measuredWidth.pxToDp / 100f).roundToInt() + return max(1, (dpWidth / trueSize).roundToInt()) +} + var View.compatToolTipText: CharSequence? get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { tooltipText diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/AutofitRecyclerView.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/AutofitRecyclerView.kt index 11f054dbe1..516cc0757d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/AutofitRecyclerView.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/widget/AutofitRecyclerView.kt @@ -3,8 +3,10 @@ package eu.kanade.tachiyomi.widget import android.content.Context import android.util.AttributeSet import androidx.recyclerview.widget.GridLayoutManager +import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.util.system.pxToDp import kotlin.math.max +import kotlin.math.pow import kotlin.math.roundToInt class AutofitRecyclerView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : @@ -51,6 +53,12 @@ class AutofitRecyclerView @JvmOverloads constructor(context: Context, attrs: Att setSpan() } + fun setGridSize(preferences: PreferencesHelper) { + val size = 1.5f.pow(preferences.gridSize().get()) + val trueSize = MULTIPLE * ((size * 100 / MULTIPLE).roundToInt()) / 100f + columnWidth = trueSize + } + private fun setSpan(force: Boolean = false) { if ((spanCount == 0 || force) && columnWidth > 0) { val dpWidth = (measuredWidth.pxToDp / 100f).roundToInt() @@ -58,4 +66,9 @@ class AutofitRecyclerView @JvmOverloads constructor(context: Context, attrs: Att spanCount = count } } + + companion object { + private const val MULTIPLE_PERCENT = 0.25f + const val MULTIPLE = MULTIPLE_PERCENT * 100 + } } diff --git a/app/src/main/res/drawable/ic_rounded_tooltip_24dp.xml b/app/src/main/res/drawable/ic_rounded_tooltip_24dp.xml new file mode 100644 index 0000000000..36d0b4d437 --- /dev/null +++ b/app/src/main/res/drawable/ic_rounded_tooltip_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/library_display_layout.xml b/app/src/main/res/layout/library_display_layout.xml index 6ac64debad..25fe0c60ff 100644 --- a/app/src/main/res/layout/library_display_layout.xml +++ b/app/src/main/res/layout/library_display_layout.xml @@ -1,93 +1,111 @@ - - + android:layout_height="wrap_content"> - - - - - - - - - - + android:layout_height="match_parent"> - - - + android:orientation="vertical" + android:paddingStart="12dp" + android:paddingEnd="12dp"> - + + + + + + + + + + + + + + + + + - android:text="@string/small" /> - - - - - - - - - - + + \ No newline at end of file diff --git a/app/src/main/res/layout/tooltip_text_view.xml b/app/src/main/res/layout/tooltip_text_view.xml new file mode 100644 index 0000000000..bb65071b6b --- /dev/null +++ b/app/src/main/res/layout/tooltip_text_view.xml @@ -0,0 +1,13 @@ + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 49b8eefb29..ee2c302747 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -154,12 +154,14 @@ Hide start reading button Badges Uniform covers + Uniform grid covers + Grid size XS S M L XL - Grid options + %d per row Hide unread badges Show unread badges Show unread count