Manage library grid size
parent
5a565a16fe
commit
5edfda6c1a
@ -1,4 +1,4 @@
|
|||||||
package org.koitharu.kotatsu.library.ui.config
|
package org.koitharu.kotatsu.library.ui.config.categories
|
||||||
|
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter
|
import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package org.koitharu.kotatsu.library.ui.config
|
package org.koitharu.kotatsu.library.ui.config.categories
|
||||||
|
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@ -0,0 +1,63 @@
|
|||||||
|
package org.koitharu.kotatsu.library.ui.config.size
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.fragment.app.FragmentManager
|
||||||
|
import com.google.android.material.slider.LabelFormatter
|
||||||
|
import com.google.android.material.slider.Slider
|
||||||
|
import org.koin.android.ext.android.inject
|
||||||
|
import org.koitharu.kotatsu.R
|
||||||
|
import org.koitharu.kotatsu.base.ui.BaseBottomSheet
|
||||||
|
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||||
|
import org.koitharu.kotatsu.databinding.SheetLibrarySizeBinding
|
||||||
|
import org.koitharu.kotatsu.utils.ext.setValueRounded
|
||||||
|
import org.koitharu.kotatsu.utils.progress.IntPercentLabelFormatter
|
||||||
|
|
||||||
|
class LibrarySizeBottomSheet :
|
||||||
|
BaseBottomSheet<SheetLibrarySizeBinding>(),
|
||||||
|
Slider.OnChangeListener,
|
||||||
|
View.OnClickListener {
|
||||||
|
|
||||||
|
private val settings by inject<AppSettings>(mode = LazyThreadSafetyMode.NONE)
|
||||||
|
private var labelFormatter: LabelFormatter? = null
|
||||||
|
|
||||||
|
override fun onInflateView(inflater: LayoutInflater, container: ViewGroup?): SheetLibrarySizeBinding {
|
||||||
|
return SheetLibrarySizeBinding.inflate(inflater, container, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
labelFormatter = IntPercentLabelFormatter(view.context)
|
||||||
|
binding.sliderGrid.addOnChangeListener(this)
|
||||||
|
binding.buttonSmall.setOnClickListener(this)
|
||||||
|
binding.buttonLarge.setOnClickListener(this)
|
||||||
|
|
||||||
|
binding.sliderGrid.setValueRounded(settings.gridSize.toFloat())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
labelFormatter = null
|
||||||
|
super.onDestroyView()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onValueChange(slider: Slider, value: Float, fromUser: Boolean) {
|
||||||
|
settings.gridSize = value.toInt()
|
||||||
|
binding.textViewLabel.text = labelFormatter?.getFormattedValue(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onClick(v: View) {
|
||||||
|
when (v.id) {
|
||||||
|
R.id.button_small -> binding.sliderGrid.value -= binding.sliderGrid.stepSize
|
||||||
|
R.id.button_large -> binding.sliderGrid.value += binding.sliderGrid.stepSize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
private const val TAG = "LibrarySizeBottomSheet"
|
||||||
|
|
||||||
|
fun show(fm: FragmentManager) = LibrarySizeBottomSheet().show(fm, TAG)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,15 +1,85 @@
|
|||||||
package org.koitharu.kotatsu.list.ui
|
package org.koitharu.kotatsu.list.ui
|
||||||
|
|
||||||
|
import android.content.SharedPreferences
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.annotation.StyleRes
|
||||||
|
import androidx.core.view.updateLayoutParams
|
||||||
|
import androidx.lifecycle.DefaultLifecycleObserver
|
||||||
|
import androidx.lifecycle.LifecycleOwner
|
||||||
|
import kotlin.math.roundToInt
|
||||||
import org.koitharu.kotatsu.R
|
import org.koitharu.kotatsu.R
|
||||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||||
import kotlin.math.roundToInt
|
|
||||||
|
|
||||||
class ItemSizeResolver(resources: Resources, settings: AppSettings) {
|
class ItemSizeResolver(resources: Resources, private val settings: AppSettings) {
|
||||||
|
|
||||||
private val scaleFactor = settings.gridSize / 100f
|
|
||||||
private val gridWidth = resources.getDimension(R.dimen.preferred_grid_width)
|
private val gridWidth = resources.getDimension(R.dimen.preferred_grid_width)
|
||||||
|
private val scaleFactor: Float
|
||||||
|
get() = settings.gridSize / 100f
|
||||||
|
|
||||||
val cellWidth: Int
|
val cellWidth: Int
|
||||||
get() = (gridWidth * scaleFactor).roundToInt()
|
get() = (gridWidth * scaleFactor).roundToInt()
|
||||||
|
|
||||||
|
fun attachToView(lifecycleOwner: LifecycleOwner, view: View, textView: TextView?) {
|
||||||
|
val observer = SizeObserver(view, textView)
|
||||||
|
view.addOnAttachStateChangeListener(observer)
|
||||||
|
lifecycleOwner.lifecycle.addObserver(observer)
|
||||||
|
if (view.isAttachedToWindow) {
|
||||||
|
observer.update()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private inner class SizeObserver(
|
||||||
|
private val view: View,
|
||||||
|
private val textView: TextView?,
|
||||||
|
) : DefaultLifecycleObserver, SharedPreferences.OnSharedPreferenceChangeListener, View.OnAttachStateChangeListener {
|
||||||
|
|
||||||
|
private val widthThreshold = view.resources.getDimensionPixelSize(R.dimen.small_grid_width)
|
||||||
|
|
||||||
|
@StyleRes
|
||||||
|
private var prevTextAppearance = 0
|
||||||
|
|
||||||
|
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
|
||||||
|
if (key == AppSettings.KEY_GRID_SIZE) {
|
||||||
|
update()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewAttachedToWindow(v: View?) {
|
||||||
|
settings.subscribe(this)
|
||||||
|
update()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewDetachedFromWindow(v: View?) {
|
||||||
|
settings.unsubscribe(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy(owner: LifecycleOwner) {
|
||||||
|
super.onDestroy(owner)
|
||||||
|
settings.unsubscribe(this)
|
||||||
|
view.removeOnAttachStateChangeListener(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun update() {
|
||||||
|
val newWidth = cellWidth
|
||||||
|
textView?.adjustTextAppearance(newWidth)
|
||||||
|
view.updateLayoutParams {
|
||||||
|
width = newWidth
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun TextView.adjustTextAppearance(width: Int) {
|
||||||
|
val textAppearanceResId = if (width < widthThreshold) {
|
||||||
|
R.style.TextAppearance_Kotatsu_GridTitle_Small
|
||||||
|
} else {
|
||||||
|
R.style.TextAppearance_Kotatsu_GridTitle
|
||||||
|
}
|
||||||
|
if (textAppearanceResId != prevTextAppearance) {
|
||||||
|
prevTextAppearance = textAppearanceResId
|
||||||
|
setTextAppearance(textAppearanceResId)
|
||||||
|
requestLayout()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:tint="?attr/colorControlNormal"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="#000"
|
||||||
|
android:pathData="M21,15H23V17H21V15M21,11H23V13H21V11M23,19H21V21C22,21 23,20 23,19M13,3H15V5H13V3M21,7H23V9H21V7M21,3V5H23C23,4 22,3 21,3M1,7H3V9H1V7M17,3H19V5H17V3M17,19H19V21H17V19M3,3C2,3 1,4 1,5H3V3M9,3H11V5H9V3M5,3H7V5H5V3M1,11V19A2,2 0 0,0 3,21H15V11H1M3,19L5.5,15.79L7.29,17.94L9.79,14.72L13,19H3Z" />
|
||||||
|
</vector>
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:tint="?attr/colorControlNormal"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="#000"
|
||||||
|
android:pathData="M23,15H21V17H23V15M23,11H21V13H23V11M23,19H21V21C22,21 23,20 23,19M15,3H13V5H15V3M23,7H21V9H23V7M21,3V5H23C23,4 22,3 21,3M3,21H11V15H1V19A2,2 0 0,0 3,21M3,7H1V9H3V7M15,19H13V21H15V19M19,3H17V5H19V3M19,19H17V21H19V19M3,3C2,3 1,4 1,5H3V3M3,11H1V13H3V11M11,3H9V5H11V3M7,3H5V5H7V3Z" />
|
||||||
|
</vector>
|
||||||
@ -0,0 +1,83 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingHorizontal="@dimen/margin_small"
|
||||||
|
android:paddingBottom="@dimen/margin_normal">
|
||||||
|
|
||||||
|
<com.google.android.material.bottomsheet.BottomSheetDragHandleView
|
||||||
|
android:id="@+id/dragHandle"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentStart="true"
|
||||||
|
android:layout_alignParentTop="true"
|
||||||
|
android:layout_alignParentEnd="true" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/textView_title"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignWithParentIfMissing="true"
|
||||||
|
android:layout_below="@id/dragHandle"
|
||||||
|
android:layout_alignParentStart="true"
|
||||||
|
android:layout_toStartOf="@id/textView_label"
|
||||||
|
android:paddingHorizontal="@dimen/margin_small"
|
||||||
|
android:paddingBottom="@dimen/margin_small"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:text="@string/grid_size"
|
||||||
|
android:textAppearance="?textAppearanceTitleMedium" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/textView_label"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignBaseline="@id/textView_title"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:paddingHorizontal="@dimen/margin_small"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textAppearance="?textAppearanceLabelLarge"
|
||||||
|
tools:text="100%" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/button_small"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_alignTop="@id/slider_grid"
|
||||||
|
android:layout_alignBottom="@id/slider_grid"
|
||||||
|
android:layout_alignParentStart="true"
|
||||||
|
android:background="?selectableItemBackgroundBorderless"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:src="@drawable/ic_size_small"
|
||||||
|
android:theme="@style/ThemeOverlay.Kotatsu.MainToolbar" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/button_large"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_alignTop="@id/slider_grid"
|
||||||
|
android:layout_alignBottom="@id/slider_grid"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:background="?selectableItemBackgroundBorderless"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:src="@drawable/ic_size_large"
|
||||||
|
android:theme="@style/ThemeOverlay.Kotatsu.MainToolbar" />
|
||||||
|
|
||||||
|
<com.google.android.material.slider.Slider
|
||||||
|
android:id="@+id/slider_grid"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@id/textView_title"
|
||||||
|
android:layout_toStartOf="@id/button_large"
|
||||||
|
android:layout_toEndOf="@id/button_small"
|
||||||
|
android:stepSize="5"
|
||||||
|
android:valueFrom="50"
|
||||||
|
android:valueTo="150"
|
||||||
|
app:labelBehavior="gone"
|
||||||
|
app:tickVisible="false"
|
||||||
|
tools:value="100" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
Loading…
Reference in New Issue