Using a seekbar to select grid size

This is mostly the same amount of options for phones, but opens more for tablets

There's also actual math now for setting the grid size and a float used (rounded to the nearest .25)

I could just add back portrait/landscape per row....I could but

This seeker also has a bubble tooltip to show the current value, might use elsewhere later
This commit is contained in:
Jays2Kings 2021-04-16 22:59:55 -04:00
parent 4cbf1cc785
commit 0cf56ca335
13 changed files with 281 additions and 98 deletions

View File

@ -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
}

View File

@ -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"

View File

@ -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)

View File

@ -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 {

View File

@ -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<LibraryDisplayLayoutBinding>(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
}
}
}

View File

@ -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

View File

@ -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 {

View File

@ -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

View File

@ -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
}
}

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF000000"
android:pathData="M12,3.6c-3.9,0 -7,3.1 -7,7c0,5.2 7,9.8 7,9.8s7,-4.5 7,-9.8C19,6.7 15.9,3.6 12,3.6z"/>
</vector>

View File

@ -1,93 +1,111 @@
<?xml version="1.0" encoding="utf-8"?>
<eu.kanade.tachiyomi.ui.library.display.LibraryDisplayView
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
<eu.kanade.tachiyomi.ui.library.display.LibraryDisplayView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical">
<LinearLayout
android:id="@+id/linear_layout"
android:orientation="vertical"
<FrameLayout
android:id="@+id/display_frame_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="wrap_content">
<RadioGroup
android:id="@+id/display_group"
android:layout_width="match_parent"
android:layout_height="wrap_content"
<LinearLayout
android:id="@+id/linear_layout"
android:orientation="vertical"
android:paddingStart="12dp"
android:paddingEnd="12dp">
<com.google.android.material.radiobutton.MaterialRadioButton
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/list" />
<com.google.android.material.radiobutton.MaterialRadioButton
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/compact_grid" />
<com.google.android.material.radiobutton.MaterialRadioButton
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/comfortable_grid" />
</RadioGroup>
<com.google.android.material.textview.MaterialTextView
style="@style/TextAppearance.MaterialComponents.Headline6"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:paddingStart="16dp"
android:paddingEnd="12dp"
android:text="@string/grid_options" />
android:layout_height="match_parent">
<RadioGroup
android:id="@+id/grid_size_toggle_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
android:orientation="horizontal">
<com.google.android.material.radiobutton.MaterialRadioButton
android:layout_width="wrap_content"
<RadioGroup
android:id="@+id/display_group"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/x_small" />
android:orientation="vertical"
android:paddingStart="12dp"
android:paddingEnd="12dp">
<com.google.android.material.radiobutton.MaterialRadioButton
android:layout_width="wrap_content"
<com.google.android.material.radiobutton.MaterialRadioButton
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/list" />
<com.google.android.material.radiobutton.MaterialRadioButton
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/compact_grid" />
<com.google.android.material.radiobutton.MaterialRadioButton
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/comfortable_grid" />
</RadioGroup>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/grid_size_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:gravity="center"
android:orientation="horizontal">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/grid_size_text"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/grid_seekbar"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintHorizontal_bias="0.0"
android:textAppearance="@style/TextAppearance.Regular.Body1"
android:textSize="15sp"
android:text="@string/grid_size"
android:layout_weight="0"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<SeekBar
android:id="@+id/grid_seekbar"
android:layout_marginStart="12dp"
android:paddingTop="6dp"
android:paddingBottom="6dp"
android:max="7"
android:layout_width="0dp"
app:layout_constraintStart_toEndOf="@id/grid_size_text"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/reset_grid_size"
app:layout_constraintWidth_max="350dp"
android:layout_height="wrap_content"/>
<com.google.android.material.button.MaterialButton
android:id="@+id/reset_grid_size"
android:layout_marginStart="8dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toEndOf="@id/grid_seekbar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
style="@style/Theme.Widget.Button.TextButton"
android:text="@string/reset" />
</androidx.constraintlayout.widget.ConstraintLayout>
<com.google.android.material.checkbox.MaterialCheckBox
android:id="@+id/uniform_grid"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
android:text="@string/uniform_grid_covers" />
</LinearLayout>
android:text="@string/small" />
<com.google.android.material.radiobutton.MaterialRadioButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:text="@string/medium" />
<com.google.android.material.radiobutton.MaterialRadioButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:text="@string/large" />
<com.google.android.material.radiobutton.MaterialRadioButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:text="@string/x_large" />
</RadioGroup>
<com.google.android.material.checkbox.MaterialCheckBox
android:id="@+id/uniform_grid"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
android:text="@string/uniform_covers" />
</LinearLayout>
<include
android:id="@+id/seek_bar_text_view"
android:visibility="gone"
android:alpha="0"
tools:alpha="1"
tools:visibility="visible"
layout="@layout/tooltip_text_view"/>
</FrameLayout>
</eu.kanade.tachiyomi.ui.library.display.LibraryDisplayView>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="45sp"
android:layout_height="45sp"
xmlns:tools="http://schemas.android.com/tools"
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
tools:text="1"
android:elevation="6dp"
android:textAlignment="center"
android:paddingTop="8dp"
android:textColor="?colorOnAccent"
android:backgroundTint="?colorAccent"
android:background="@drawable/ic_rounded_tooltip_24dp" />

View File

@ -154,12 +154,14 @@
<string name="hide_start_reading_button">Hide start reading button</string>
<string name="badges">Badges</string>
<string name="uniform_covers">Uniform covers</string>
<string name="uniform_grid_covers">Uniform grid covers</string>
<string name="grid_size">Grid size</string>
<string name="x_small">XS</string>
<string name="small">S</string>
<string name="medium">M</string>
<string name="large">L</string>
<string name="x_large">XL</string>
<string name="grid_options">Grid options</string>
<string name="_per_row">%d per row</string>
<string name="hide_unread_badges">Hide unread badges</string>
<string name="show_unread_badges">Show unread badges</string>
<string name="show_unread_count">Show unread count</string>