From acc65529a00c94ec902401fadcba0b82fd352c98 Mon Sep 17 00:00:00 2001 From: Ivan Iskandar <12537387+ivaniskandar@users.noreply.github.com> Date: Sat, 12 Nov 2022 03:02:45 +0700 Subject: [PATCH] Replace numberpicker with wheelpicker (#8501) * Replace numberpicker with wheelpicker * cleanups --- app/build.gradle.kts | 2 +- .../settings/screen/SettingsLibraryScreen.kt | 140 ++++++++++++------ .../tachiyomi/widget/MinMaxNumberPicker.kt | 40 ----- app/src/main/res/values/attrs.xml | 5 - gradle/compose.versions.toml | 3 + gradle/libs.versions.toml | 1 - 6 files changed, 101 insertions(+), 90 deletions(-) delete mode 100644 app/src/main/java/eu/kanade/tachiyomi/widget/MinMaxNumberPicker.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 7d93f298b3..6f2b355c61 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -173,6 +173,7 @@ dependencies { implementation(compose.foundation) implementation(compose.material3.core) implementation(compose.material3.adapter) + implementation(compose.material.core) implementation(compose.material.icons) implementation(compose.animation) implementation(compose.animation.graphics) @@ -269,7 +270,6 @@ dependencies { implementation(libs.markwon) implementation(libs.aboutLibraries.compose) implementation(libs.cascade) - implementation(libs.numberpicker) implementation(libs.bundles.voyager) implementation(libs.wheelpicker) diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsLibraryScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsLibraryScreen.kt index d4b5e34644..14091b3a18 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsLibraryScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsLibraryScreen.kt @@ -1,13 +1,15 @@ package eu.kanade.presentation.more.settings.screen -import android.content.Context import androidx.annotation.StringRes +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.layout.BoxWithConstraints import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.size import androidx.compose.material3.AlertDialog -import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable @@ -21,15 +23,18 @@ import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clipToBounds +import androidx.compose.ui.draw.alpha import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.pluralStringResource import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.DpSize +import androidx.compose.ui.unit.dp import androidx.compose.ui.util.fastMap import androidx.core.content.ContextCompat import cafe.adriel.voyager.navigator.currentOrThrow import com.bluelinelabs.conductor.Router -import com.chargemap.compose.numberpicker.NumberPicker +import com.commandiron.wheel_picker_compose.WheelPicker import eu.kanade.domain.category.interactor.GetCategories import eu.kanade.domain.category.interactor.ResetCategoryFlags import eu.kanade.domain.category.model.Category @@ -78,7 +83,6 @@ class SettingsLibraryScreen : SearchableSettings { @Composable private fun getDisplayGroup(libraryPreferences: LibraryPreferences): Preference.PreferenceGroup { - val context = LocalContext.current val scope = rememberCoroutineScope() val portraitColumns by libraryPreferences.portraitColumns().stateIn(scope).collectAsState() val landscapeColumns by libraryPreferences.landscapeColumns().stateIn(scope).collectAsState() @@ -102,8 +106,8 @@ class SettingsLibraryScreen : SearchableSettings { preferenceItems = listOf( Preference.PreferenceItem.TextPreference( title = stringResource(R.string.pref_library_columns), - subtitle = "${stringResource(R.string.portrait)}: ${getColumnValue(context, portraitColumns)}, " + - "${stringResource(R.string.landscape)}: ${getColumnValue(context, landscapeColumns)}", + subtitle = "${stringResource(R.string.portrait)}: ${getColumnValue(portraitColumns)}, " + + "${stringResource(R.string.landscape)}: ${getColumnValue(landscapeColumns)}", onClick = { showDialog = true }, ), ), @@ -273,7 +277,6 @@ class SettingsLibraryScreen : SearchableSettings { onDismissRequest: () -> Unit, onValueChanged: (portrait: Int, landscape: Int) -> Unit, ) { - val context = LocalContext.current var portraitValue by rememberSaveable { mutableStateOf(initialPortrait) } var landscapeValue by rememberSaveable { mutableStateOf(initialLandscape) } @@ -281,48 +284,30 @@ class SettingsLibraryScreen : SearchableSettings { onDismissRequest = onDismissRequest, title = { Text(text = stringResource(R.string.pref_library_columns)) }, text = { - Row { - Column( - modifier = Modifier.weight(1f), - horizontalAlignment = Alignment.CenterHorizontally, - ) { + Column { + Row { Text( + modifier = Modifier.weight(1f), text = stringResource(R.string.portrait), + textAlign = TextAlign.Center, + maxLines = 1, style = MaterialTheme.typography.labelMedium, ) - NumberPicker( - modifier = Modifier - .fillMaxWidth() - .clipToBounds(), - value = portraitValue, - onValueChange = { portraitValue = it }, - range = 0..10, - label = { getColumnValue(context, it) }, - dividersColor = MaterialTheme.colorScheme.primary, - textStyle = LocalTextStyle.current.copy(color = MaterialTheme.colorScheme.onSurface), - ) - } - - Column( - modifier = Modifier.weight(1f), - horizontalAlignment = Alignment.CenterHorizontally, - ) { Text( + modifier = Modifier.weight(1f), text = stringResource(R.string.landscape), + textAlign = TextAlign.Center, + maxLines = 1, style = MaterialTheme.typography.labelMedium, ) - NumberPicker( - modifier = Modifier - .fillMaxWidth() - .clipToBounds(), - value = landscapeValue, - onValueChange = { landscapeValue = it }, - range = 0..10, - label = { getColumnValue(context, it) }, - dividersColor = MaterialTheme.colorScheme.primary, - textStyle = LocalTextStyle.current.copy(color = MaterialTheme.colorScheme.onSurface), - ) } + LibraryColumnsPicker( + modifier = Modifier.fillMaxWidth(), + portraitValue = portraitValue, + onPortraitChange = { portraitValue = it }, + landscapeValue = landscapeValue, + onLandscapeChange = { landscapeValue = it }, + ) } }, dismissButton = { @@ -338,9 +323,78 @@ class SettingsLibraryScreen : SearchableSettings { ) } - private fun getColumnValue(context: Context, value: Int): String { + @Composable + private fun LibraryColumnsPicker( + modifier: Modifier = Modifier, + portraitValue: Int, + onPortraitChange: (Int) -> Unit, + landscapeValue: Int, + onLandscapeChange: (Int) -> Unit, + ) { + BoxWithConstraints( + modifier = modifier, + contentAlignment = Alignment.Center, + ) { + Surface( + modifier = Modifier.size(maxWidth, maxHeight / 3), + shape = MaterialTheme.shapes.large, + color = MaterialTheme.colorScheme.primary.copy(alpha = 0.2f), + border = BorderStroke(1.dp, MaterialTheme.colorScheme.primary), + ) {} + + val size = DpSize(width = maxWidth / 2, height = 128.dp) + Row { + WheelPicker( + size = size, + count = 10, + startIndex = portraitValue, + onScrollFinished = { + onPortraitChange(it) + null + }, + ) { index, snappedIndex -> + ColumnPickerLabel(index = index, snappedIndex = snappedIndex) + } + WheelPicker( + size = size, + count = 10, + startIndex = landscapeValue, + onScrollFinished = { + onLandscapeChange(it) + null + }, + ) { index, snappedIndex -> + ColumnPickerLabel(index = index, snappedIndex = snappedIndex) + } + } + } + } + + @Composable + private fun ColumnPickerLabel( + index: Int, + snappedIndex: Int, + ) { + Text( + modifier = Modifier.alpha( + when (snappedIndex) { + index + 1 -> 0.2f + index -> 1f + index - 1 -> 0.2f + else -> 0.2f + }, + ), + text = getColumnValue(index), + style = MaterialTheme.typography.titleMedium, + maxLines = 1, + ) + } + + @Composable + @ReadOnlyComposable + private fun getColumnValue(value: Int): String { return if (value == 0) { - context.getString(R.string.label_default) + stringResource(R.string.label_default) } else { value.toString() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/MinMaxNumberPicker.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/MinMaxNumberPicker.kt deleted file mode 100644 index 5da40a9039..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/MinMaxNumberPicker.kt +++ /dev/null @@ -1,40 +0,0 @@ -package eu.kanade.tachiyomi.widget - -import android.content.Context -import android.text.InputType -import android.util.AttributeSet -import android.widget.EditText -import android.widget.NumberPicker -import androidx.core.view.doOnLayout -import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.util.view.findDescendant - -class MinMaxNumberPicker @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : - NumberPicker(context, attrs) { - - override fun setDisplayedValues(displayedValues: Array?) { - super.setDisplayedValues(displayedValues) - - // Disable keyboard input when a value that can't be auto-filled with number exists - val notNumberValue = displayedValues?.find { it.getOrNull(0)?.digitToIntOrNull() == null } - if (notNumberValue != null) { - descendantFocusability = FOCUS_BLOCK_DESCENDANTS - } - } - - init { - if (attrs != null) { - val ta = context.obtainStyledAttributes(attrs, R.styleable.MinMaxNumberPicker, 0, 0) - try { - minValue = ta.getInt(R.styleable.MinMaxNumberPicker_min, 0) - maxValue = ta.getInt(R.styleable.MinMaxNumberPicker_max, 0) - } finally { - ta.recycle() - } - } - - doOnLayout { - findDescendant()?.setRawInputType(InputType.TYPE_CLASS_NUMBER) - } - } -} diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index a91f4f615f..d644cdf854 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -1,11 +1,6 @@ - - - - - diff --git a/gradle/compose.versions.toml b/gradle/compose.versions.toml index c5be552bd0..81f36ec6a7 100644 --- a/gradle/compose.versions.toml +++ b/gradle/compose.versions.toml @@ -16,6 +16,9 @@ material3-core = { module = "androidx.compose.material3:material3" } material3-adapter = "com.google.android.material:compose-theme-adapter-3:1.0.21" material-icons = { module = "androidx.compose.material:material-icons-extended" } +# Here until M3's swipeable became public https://issuetracker.google.com/issues/234640556 +material-core = { module = "androidx.compose.material:material" } + accompanist-webview = { module = "com.google.accompanist:accompanist-webview", version.ref = "accompanist" } accompanist-swiperefresh = { module = "com.google.accompanist:accompanist-swiperefresh", version.ref = "accompanist" } accompanist-flowlayout = { module = "com.google.accompanist:accompanist-flowlayout", version.ref = "accompanist" } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9fbf4d2d75..0ce9f35c7d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -63,7 +63,6 @@ photoview = "com.github.chrisbanes:PhotoView:2.3.0" directionalviewpager = "com.github.tachiyomiorg:DirectionalViewPager:1.0.0" insetter = "dev.chrisbanes.insetter:insetter:0.6.1" cascade = "me.saket.cascade:cascade-compose:2.0.0-beta1" -numberpicker = "com.chargemap.compose:numberpicker:1.0.3" wheelpicker = "com.github.commandiron:WheelPickerCompose:1.0.11" conductor-core = { module = "com.bluelinelabs:conductor", version.ref = "conductor_version" }