feat(ui): Improve migration bottom sheet layout with scrollable content (#983)

* feat(ui): Improve migration bottom sheet layout with scrollable content

* Using with(binding) and remove redundant Box

* Simplify checkbox listener setup in MigrationBottomSheetDialog

* Fix reference ID should not create new ID
This commit is contained in:
Cuong-Tran 2025-06-05 12:03:22 +07:00 committed by GitHub
parent 4b4e4c6204
commit a843918e7f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 305 additions and 293 deletions

View file

@ -5,7 +5,10 @@ import android.widget.CompoundButton
import android.widget.RadioButton import android.widget.RadioButton
import android.widget.RadioGroup import android.widget.RadioGroup
import android.widget.Toast import android.widget.Toast
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.State import androidx.compose.runtime.State
@ -50,45 +53,55 @@ fun MigrationBottomSheetDialog(
// KMK <-- // KMK <--
AdaptiveSheet(onDismissRequest = onDismissRequest) { AdaptiveSheet(onDismissRequest = onDismissRequest) {
// Wrap AndroidView in a scrollable Column using verticalScroll
Column(
modifier = Modifier
.verticalScroll(rememberScrollState())
.fillMaxWidth(),
) {
AndroidView( AndroidView(
factory = { factoryContext -> factory = { factoryContext ->
val binding = MigrationBottomSheetBinding.inflate(LayoutInflater.from(factoryContext)) val binding = MigrationBottomSheetBinding.inflate(LayoutInflater.from(factoryContext))
state.initPreferences(binding) state.initPreferences(binding)
// KMK --> // KMK -->
binding.migrateBtn.setBackgroundColor(colorScheme.primary) with(binding) {
binding.dataLabel.setTextColor(colorScheme.primary) migrateBtn.setBackgroundColor(colorScheme.primary)
binding.optionsLabel.setTextColor(colorScheme.primary) dataLabel.setTextColor(colorScheme.primary)
optionsLabel.setTextColor(colorScheme.primary)
binding.migChapters.buttonTintList = colorScheme.checkboxTintList listOf(
binding.migCategories.buttonTintList = colorScheme.checkboxTintList migChapters,
binding.migTracking.buttonTintList = colorScheme.checkboxTintList migCategories,
binding.migCustomCover.buttonTintList = colorScheme.checkboxTintList migTracking,
binding.migExtra.buttonTintList = colorScheme.checkboxTintList migCustomCover,
binding.migDeleteDownloaded.buttonTintList = colorScheme.checkboxTintList migExtra,
migDeleteDownloaded,
radioButton,
radioButton2,
).forEach {
it.buttonTintList = colorScheme.checkboxTintList
}
binding.radioButton.buttonTintList = colorScheme.checkboxTintList listOf(
binding.radioButton2.buttonTintList = colorScheme.checkboxTintList useSmartSearch,
extraSearchParam,
skipStep,
hideNotFoundManga,
onlyShowUpdates,
).forEach {
it.trackTintList = colorScheme.trackTintList
it.thumbTintList = colorScheme.thumbTintList
}
binding.useSmartSearch.trackTintList = colorScheme.trackTintList colorScheme.setTextInputLayoutColor(extraSearchParamInputLayout)
binding.extraSearchParam.trackTintList = colorScheme.trackTintList colorScheme.setEditTextColor(extraSearchParamText)
binding.skipStep.trackTintList = colorScheme.trackTintList }
binding.HideNotFoundManga.trackTintList = colorScheme.trackTintList
binding.OnlyShowUpdates.trackTintList = colorScheme.trackTintList
binding.useSmartSearch.thumbTintList = colorScheme.thumbTintList
binding.extraSearchParam.thumbTintList = colorScheme.thumbTintList
binding.skipStep.thumbTintList = colorScheme.thumbTintList
binding.HideNotFoundManga.thumbTintList = colorScheme.thumbTintList
binding.OnlyShowUpdates.thumbTintList = colorScheme.thumbTintList
colorScheme.setTextInputLayoutColor(binding.extraSearchParamInputLayout)
colorScheme.setEditTextColor(binding.extraSearchParamText)
// KMK <-- // KMK <--
binding.root binding.root
}, },
modifier = Modifier.fillMaxWidth(),
) )
} }
}
} }
class MigrationBottomSheetDialogState( class MigrationBottomSheetDialogState(
@ -105,46 +118,51 @@ class MigrationBottomSheetDialogState(
fun initPreferences(binding: MigrationBottomSheetBinding) { fun initPreferences(binding: MigrationBottomSheetBinding) {
val flags = preferences.migrateFlags().get() val flags = preferences.migrateFlags().get()
binding.migChapters.isChecked = MigrationFlags.hasChapters(flags) with(binding) {
binding.migCategories.isChecked = MigrationFlags.hasCategories(flags) migChapters.isChecked = MigrationFlags.hasChapters(flags)
binding.migTracking.isChecked = MigrationFlags.hasTracks(flags) migCategories.isChecked = MigrationFlags.hasCategories(flags)
binding.migCustomCover.isChecked = MigrationFlags.hasCustomCover(flags) migTracking.isChecked = MigrationFlags.hasTracks(flags)
binding.migExtra.isChecked = MigrationFlags.hasExtra(flags) migCustomCover.isChecked = MigrationFlags.hasCustomCover(flags)
binding.migDeleteDownloaded.isChecked = MigrationFlags.hasDeleteDownloaded(flags) migExtra.isChecked = MigrationFlags.hasExtra(flags)
migDeleteDownloaded.isChecked = MigrationFlags.hasDeleteDownloaded(flags)
binding.migChapters.setOnCheckedChangeListener { _, _ -> setFlags(binding) } listOf(
binding.migCategories.setOnCheckedChangeListener { _, _ -> setFlags(binding) } migChapters,
binding.migTracking.setOnCheckedChangeListener { _, _ -> setFlags(binding) } migCategories,
binding.migCustomCover.setOnCheckedChangeListener { _, _ -> setFlags(binding) } migTracking,
binding.migExtra.setOnCheckedChangeListener { _, _ -> setFlags(binding) } migCustomCover,
binding.migDeleteDownloaded.setOnCheckedChangeListener { _, _ -> setFlags(binding) } migExtra,
migDeleteDownloaded,
binding.useSmartSearch.bindToPreference(preferences.smartMigration()) ).forEach { checkBox ->
binding.extraSearchParamInputLayout.isVisible = false checkBox.setOnCheckedChangeListener { _, _ -> setFlags(binding) }
binding.extraSearchParam.setOnCheckedChangeListener { _, isChecked ->
binding.extraSearchParamInputLayout.isVisible = isChecked
} }
binding.sourceGroup.bindToPreference(preferences.useSourceWithMost())
binding.skipStep.isChecked = preferences.skipPreMigration().get() useSmartSearch.bindToPreference(preferences.smartMigration())
binding.HideNotFoundManga.isChecked = preferences.hideNotFoundMigration().get() extraSearchParamInputLayout.isVisible = false
binding.OnlyShowUpdates.isChecked = preferences.showOnlyUpdatesMigration().get() extraSearchParam.setOnCheckedChangeListener { _, isChecked ->
binding.skipStep.setOnCheckedChangeListener { _, isChecked -> extraSearchParamInputLayout.isVisible = isChecked
}
sourceGroup.bindToPreference(preferences.useSourceWithMost())
skipStep.isChecked = preferences.skipPreMigration().get()
hideNotFoundManga.isChecked = preferences.hideNotFoundMigration().get()
onlyShowUpdates.isChecked = preferences.showOnlyUpdatesMigration().get()
skipStep.setOnCheckedChangeListener { _, isChecked ->
if (isChecked) { if (isChecked) {
binding.root.context.toast( root.context.toast(
SYMR.strings.pre_migration_skip_toast, SYMR.strings.pre_migration_skip_toast,
Toast.LENGTH_LONG, Toast.LENGTH_LONG,
) )
} }
} }
binding.migrateBtn.setOnClickListener { migrateBtn.setOnClickListener {
preferences.skipPreMigration().set(binding.skipStep.isChecked) preferences.skipPreMigration().set(skipStep.isChecked)
preferences.hideNotFoundMigration().set(binding.HideNotFoundManga.isChecked) preferences.hideNotFoundMigration().set(hideNotFoundManga.isChecked)
preferences.showOnlyUpdatesMigration().set(binding.OnlyShowUpdates.isChecked) preferences.showOnlyUpdatesMigration().set(onlyShowUpdates.isChecked)
onStartMigration.value( onStartMigration.value(
if (binding.useSmartSearch.isChecked && !binding.extraSearchParamText.text.isNullOrBlank()) { if (useSmartSearch.isChecked && !extraSearchParamText.text.isNullOrBlank()) {
binding.extraSearchParamText.text.toString() extraSearchParamText.text.toString()
} else { } else {
null null
}, },
@ -153,24 +171,28 @@ class MigrationBottomSheetDialogState(
// KMK --> // KMK -->
if (!fullSettings) { if (!fullSettings) {
binding.useSmartSearch.isVisible = false useSmartSearch.isVisible = false
binding.extraSearchParam.isVisible = false extraSearchParam.isVisible = false
binding.extraSearchParamInputLayout.isVisible = false extraSearchParamInputLayout.isVisible = false
binding.sourceGroup.isVisible = false sourceGroup.isVisible = false
binding.skipStep.isVisible = false skipStep.isVisible = false
binding.migrateBtn.text = binding.root.context.stringResource(MR.strings.action_save) migrateBtn.text = root.context.stringResource(MR.strings.action_save)
} }
// KMK <-- // KMK <--
} }
}
private fun setFlags(binding: MigrationBottomSheetBinding) { private fun setFlags(binding: MigrationBottomSheetBinding) {
var flags = 0 var flags = 0
if (binding.migChapters.isChecked) flags = flags or MigrationFlags.CHAPTERS with(binding) {
if (binding.migCategories.isChecked) flags = flags or MigrationFlags.CATEGORIES @Suppress("KotlinConstantConditions")
if (binding.migTracking.isChecked) flags = flags or MigrationFlags.TRACK if (migChapters.isChecked) flags = flags or MigrationFlags.CHAPTERS
if (binding.migCustomCover.isChecked) flags = flags or MigrationFlags.CUSTOM_COVER if (migCategories.isChecked) flags = flags or MigrationFlags.CATEGORIES
if (binding.migExtra.isChecked) flags = flags or MigrationFlags.EXTRA if (migTracking.isChecked) flags = flags or MigrationFlags.TRACK
if (binding.migDeleteDownloaded.isChecked) flags = flags or MigrationFlags.DELETE_DOWNLOADED if (migCustomCover.isChecked) flags = flags or MigrationFlags.CUSTOM_COVER
if (migExtra.isChecked) flags = flags or MigrationFlags.EXTRA
if (migDeleteDownloaded.isChecked) flags = flags or MigrationFlags.DELETE_DOWNLOADED
}
preferences.migrateFlags().set(flags) preferences.migrateFlags().set(flags)
} }

View file

@ -3,28 +3,17 @@
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/constraintLayout" android:id="@+id/constraintLayout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="wrap_content"
android:clipToPadding="false" android:clipToPadding="false"
android:paddingVertical="8dp" android:paddingVertical="8dp"
android:orientation="vertical"> android:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/constraintLayout2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0">
<TextView <TextView
android:id="@+id/data_label" android:id="@+id/data_label"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingTop="8dp" android:paddingTop="8dp"
android:layout_marginStart="8dp" android:layout_marginStart="16dp"
android:text="@string/data_to_include_in_migration" android:text="@string/data_to_include_in_migration"
android:textAppearance="?attr/textAppearanceTitleMedium" android:textAppearance="?attr/textAppearanceTitleMedium"
android:textColor="?attr/colorPrimary" android:textColor="?attr/colorPrimary"
@ -35,9 +24,10 @@
android:id="@+id/migration_data_group" android:id="@+id/migration_data_group"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingHorizontal="16dp"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/data_label"> app:layout_constraintTop_toBottomOf="@id/data_label">
<androidx.constraintlayout.helper.widget.Flow <androidx.constraintlayout.helper.widget.Flow
android:layout_width="0dp" android:layout_width="0dp"
@ -111,12 +101,12 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="16dp" android:layout_marginTop="16dp"
android:layout_marginStart="8dp" android:layout_marginStart="16dp"
android:text="@string/action_settings" android:text="@string/action_settings"
android:textAppearance="?attr/textAppearanceTitleMedium" android:textAppearance="?attr/textAppearanceTitleMedium"
android:textColor="?attr/colorPrimary" android:textColor="?attr/colorPrimary"
app:layout_constraintStart_toStartOf="@+id/migration_data_group" app:layout_constraintStart_toStartOf="@id/migration_data_group"
app:layout_constraintTop_toBottomOf="@+id/migration_data_divider" /> app:layout_constraintTop_toBottomOf="@id/migration_data_divider" />
<RadioGroup <RadioGroup
android:id="@+id/sourceGroup" android:id="@+id/sourceGroup"
@ -125,8 +115,8 @@
android:layout_marginEnd="8dp" android:layout_marginEnd="8dp"
android:orientation="vertical" android:orientation="vertical"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/options_label" app:layout_constraintStart_toStartOf="@id/options_label"
app:layout_constraintTop_toBottomOf="@+id/options_label"> app:layout_constraintTop_toBottomOf="@id/options_label">
<RadioButton <RadioButton
android:id="@+id/radioButton" android:id="@+id/radioButton"
@ -155,6 +145,7 @@
app:layout_constraintTop_toBottomOf="@id/sourceGroup"/> app:layout_constraintTop_toBottomOf="@id/sourceGroup"/>
<LinearLayout <LinearLayout
android:id="@+id/switches"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical" android:orientation="vertical"
@ -162,14 +153,14 @@
android:paddingEnd="16dp" android:paddingEnd="16dp"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/sourceGroup_divider"> app:layout_constraintTop_toBottomOf="@id/sourceGroup_divider">
<com.google.android.material.materialswitch.MaterialSwitch <com.google.android.material.materialswitch.MaterialSwitch
android:id="@+id/use_smart_search" android:id="@+id/use_smart_search"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="16dp" android:layout_marginTop="16dp"
android:paddingHorizontal="16.dp" android:paddingHorizontal="16dp"
android:paddingVertical="16dp" android:paddingVertical="16dp"
android:text="@string/use_intelligent_search" /> android:text="@string/use_intelligent_search" />
@ -178,7 +169,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:paddingHorizontal="16.dp" android:paddingHorizontal="16dp"
android:paddingVertical="16dp" android:paddingVertical="16dp"
android:text="@string/include_extra_search_parameter" /> android:text="@string/include_extra_search_parameter" />
@ -203,32 +194,30 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:paddingHorizontal="16.dp" android:paddingHorizontal="16dp"
android:paddingVertical="16dp" android:paddingVertical="16dp"
android:text="@string/skip_this_step_next_time" /> android:text="@string/skip_this_step_next_time" />
<com.google.android.material.materialswitch.MaterialSwitch <com.google.android.material.materialswitch.MaterialSwitch
android:id="@+id/Hide_not_found_manga" android:id="@+id/hide_not_found_manga"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:paddingHorizontal="16.dp" android:paddingHorizontal="16dp"
android:paddingVertical="16dp" android:paddingVertical="16dp"
android:text="@string/hide_not_found_entries" /> android:text="@string/hide_not_found_entries" />
<com.google.android.material.materialswitch.MaterialSwitch <com.google.android.material.materialswitch.MaterialSwitch
android:id="@+id/Only_show_updates" android:id="@+id/only_show_updates"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:layout_marginBottom="82dp" android:layout_marginBottom="8dp"
android:paddingHorizontal="16.dp" android:paddingHorizontal="16dp"
android:paddingVertical="16dp" android:paddingVertical="16dp"
android:text="@string/only_show_updated_entries" /> android:text="@string/only_show_updated_entries" />
</LinearLayout> </LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
<View <View
android:id="@+id/migrate_btn_divider" android:id="@+id/migrate_btn_divider"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -237,7 +226,7 @@
android:background="?android:attr/divider" android:background="?android:attr/divider"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toTopOf="@id/migrate_btn" /> app:layout_constraintTop_toBottomOf="@id/switches" />
<Button <Button
android:id="@+id/migrate_btn" android:id="@+id/migrate_btn"
@ -245,10 +234,11 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="16dp" android:layout_marginEnd="16dp"
android:layout_marginStart="16dp" android:layout_marginStart="16dp"
android:layout_marginTop="12dp"
android:layout_marginBottom="12dp" android:layout_marginBottom="12dp"
android:text="@string/action_migrate" android:text="@string/action_migrate"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="@id/constraintLayout2" /> app:layout_constraintTop_toBottomOf="@id/migrate_btn_divider"/>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>