From cd4c217a7fcb0fd2d772023f536dac3fb6f226c4 Mon Sep 17 00:00:00 2001 From: Jobobby04 Date: Sat, 15 Jul 2023 19:53:14 -0400 Subject: [PATCH] Use a compose Adaptive Sheet for pre-migration sheet --- .../design/MigrationBottomSheetDialog.kt | 145 ++++++------------ .../advanced/design/PreMigrationScreen.kt | 31 ++-- .../design/PreMigrationScreenModel.kt | 42 +++-- 3 files changed, 83 insertions(+), 135 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/design/MigrationBottomSheetDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/design/MigrationBottomSheetDialog.kt index 93531bea1..eff92f531 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/design/MigrationBottomSheetDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/design/MigrationBottomSheetDialog.kt @@ -1,109 +1,56 @@ package eu.kanade.tachiyomi.ui.browse.migration.advanced.design -import android.content.Context -import android.content.res.Resources -import android.os.Build -import android.os.Bundle -import android.util.DisplayMetrics import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.view.WindowManager import android.widget.CompoundButton import android.widget.RadioButton import android.widget.RadioGroup import android.widget.Toast -import androidx.core.content.getSystemService +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.runtime.Composable +import androidx.compose.runtime.State +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberUpdatedState +import androidx.compose.ui.Modifier +import androidx.compose.ui.viewinterop.AndroidView import androidx.core.view.isVisible -import com.google.android.material.bottomsheet.BottomSheetBehavior -import com.google.android.material.bottomsheet.BottomSheetDialog -import com.google.android.material.bottomsheet.getElevation +import eu.kanade.presentation.components.AdaptiveSheet import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.databinding.MigrationBottomSheetBinding import eu.kanade.tachiyomi.ui.browse.migration.MigrationFlags -import eu.kanade.tachiyomi.util.system.dpToPx -import eu.kanade.tachiyomi.util.system.isNightMode -import eu.kanade.tachiyomi.util.system.isTabletUi import eu.kanade.tachiyomi.util.system.toast -import eu.kanade.tachiyomi.util.view.setNavigationBarTransparentCompat import tachiyomi.core.preference.Preference import tachiyomi.core.util.lang.toLong import tachiyomi.domain.UnsortedPreferences import uy.kohesive.injekt.injectLazy -class MigrationBottomSheetDialog(private val baseContext: Context, private val listener: StartMigrationListener) : BottomSheetDialog(baseContext) { +@Composable +fun MigrationBottomSheetDialog( + onDismissRequest: () -> Unit, + onStartMigration: (extraParam: String?) -> Unit, +) { + val startMigration = rememberUpdatedState(onStartMigration) + val state = remember { + MigrationBottomSheetDialogState(startMigration) + } + AdaptiveSheet(onDismissRequest = onDismissRequest) { + AndroidView( + factory = { factoryContext -> + val binding = MigrationBottomSheetBinding.inflate(LayoutInflater.from(factoryContext)) + state.initPreferences(binding) + binding.root + }, + modifier = Modifier.fillMaxWidth(), + ) + } +} + +class MigrationBottomSheetDialogState(private val onStartMigration: State<(extraParam: String?) -> Unit>) { private val preferences: UnsortedPreferences by injectLazy() - lateinit var binding: MigrationBottomSheetBinding - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - val rootView = createView() - setContentView(rootView) - - // Enforce max width for tablets - if (context.isTabletUi()) { - behavior.maxWidth = 480.dpToPx - } else { - behavior.maxWidth = 0.dpToPx - } - - // Set peek height to 50% display height - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { - context.display - } else { - @Suppress("DEPRECATION") - context.getSystemService()?.defaultDisplay - }?.let { - val metrics = DisplayMetrics() - @Suppress("DEPRECATION") - it.getRealMetrics(metrics) - behavior.peekHeight = metrics.heightPixels / 2 - } - - // Set navbar color to transparent for edge-to-edge bottom sheet if we can use light navigation bar - // TODO Replace deprecated systemUiVisibility when material-components uses new API to modify status bar icons - @Suppress("DEPRECATION") - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - window?.setNavigationBarTransparentCompat(context, behavior.getElevation()) - val bottomSheet = rootView.parent as ViewGroup - var flags = bottomSheet.systemUiVisibility - flags = if (context.isNightMode()) { - flags and View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR.inv() - } else { - flags or View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR - } - bottomSheet.systemUiVisibility = flags - } - - initPreferences() - - binding.migrateBtn.setOnClickListener { - preferences.skipPreMigration().set(binding.skipStep.isChecked) - preferences.hideNotFoundMigration().set(binding.HideNotFoundManga.isChecked) - listener.startMigration( - if (binding.useSmartSearch.isChecked && binding.extraSearchParamText.text.isNotBlank()) { - binding.extraSearchParamText.toString() - } else { - null - }, - ) - dismiss() - } - - behavior.peekHeight = Resources.getSystem().displayMetrics.heightPixels - behavior.state = BottomSheetBehavior.STATE_COLLAPSED - } - - fun createView(): View { - binding = MigrationBottomSheetBinding.inflate(LayoutInflater.from(baseContext)) - return binding.root - } - /** * Init general reader preferences. */ - private fun initPreferences() { + fun initPreferences(binding: MigrationBottomSheetBinding) { val flags = preferences.migrateFlags().get() binding.migChapters.isChecked = MigrationFlags.hasChapters(flags) @@ -112,11 +59,11 @@ class MigrationBottomSheetDialog(private val baseContext: Context, private val l binding.migCustomCover.isChecked = MigrationFlags.hasCustomCover(flags) binding.migExtra.isChecked = MigrationFlags.hasExtra(flags) - binding.migChapters.setOnCheckedChangeListener { _, _ -> setFlags() } - binding.migCategories.setOnCheckedChangeListener { _, _ -> setFlags() } - binding.migTracking.setOnCheckedChangeListener { _, _ -> setFlags() } - binding.migCustomCover.setOnCheckedChangeListener { _, _ -> setFlags() } - binding.migExtra.setOnCheckedChangeListener { _, _ -> setFlags() } + binding.migChapters.setOnCheckedChangeListener { _, _ -> setFlags(binding) } + binding.migCategories.setOnCheckedChangeListener { _, _ -> setFlags(binding) } + binding.migTracking.setOnCheckedChangeListener { _, _ -> setFlags(binding) } + binding.migCustomCover.setOnCheckedChangeListener { _, _ -> setFlags(binding) } + binding.migExtra.setOnCheckedChangeListener { _, _ -> setFlags(binding) } binding.useSmartSearch.bindToPreference(preferences.smartMigration()) binding.extraSearchParamText.isVisible = false @@ -129,15 +76,27 @@ class MigrationBottomSheetDialog(private val baseContext: Context, private val l binding.HideNotFoundManga.isChecked = preferences.hideNotFoundMigration().get() binding.skipStep.setOnCheckedChangeListener { _, isChecked -> if (isChecked) { - context.toast( + binding.root.context.toast( R.string.pre_migration_skip_toast, Toast.LENGTH_LONG, ) } } + + binding.migrateBtn.setOnClickListener { + preferences.skipPreMigration().set(binding.skipStep.isChecked) + preferences.hideNotFoundMigration().set(binding.HideNotFoundManga.isChecked) + onStartMigration.value( + if (binding.useSmartSearch.isChecked && binding.extraSearchParamText.text.isNotBlank()) { + binding.extraSearchParamText.toString() + } else { + null + }, + ) + } } - private fun setFlags() { + private fun setFlags(binding: MigrationBottomSheetBinding) { var flags = 0 if (binding.migChapters.isChecked) flags = flags or MigrationFlags.CHAPTERS if (binding.migCategories.isChecked) flags = flags or MigrationFlags.CATEGORIES @@ -167,7 +126,3 @@ class MigrationBottomSheetDialog(private val baseContext: Context, private val l } } } - -interface StartMigrationListener { - fun startMigration(extraParam: String?) -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/design/PreMigrationScreen.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/design/PreMigrationScreen.kt index ef9236df6..614a37bde 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/design/PreMigrationScreen.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/design/PreMigrationScreen.kt @@ -12,8 +12,6 @@ import androidx.compose.material3.Text import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.rememberTopAppBarState import androidx.compose.runtime.Composable -import androidx.compose.runtime.DisposableEffect -import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -24,7 +22,6 @@ import androidx.compose.ui.geometry.Offset import androidx.compose.ui.input.nestedscroll.NestedScrollConnection import androidx.compose.ui.input.nestedscroll.NestedScrollSource import androidx.compose.ui.input.nestedscroll.nestedScroll -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.res.stringResource @@ -57,17 +54,6 @@ class PreMigrationScreen(val mangaIds: List) : Screen() { val navigator = LocalNavigator.currentOrThrow var fabExpanded by remember { mutableStateOf(true) } val items by screenModel.state.collectAsState() - val context = LocalContext.current - DisposableEffect(screenModel) { - screenModel.dialog = MigrationBottomSheetDialog(context, screenModel.listener) - onDispose {} - } - - LaunchedEffect(screenModel) { - screenModel.startMigration.collect { extraParam -> - navigator replace MigrationListScreen(MigrationProcedureConfig(mangaIds, extraParam)) - } - } val nestedScrollConnection = remember { // All this lines just for fab state :/ @@ -132,9 +118,7 @@ class PreMigrationScreen(val mangaIds: List) : Screen() { ) }, onClick = { - if (!screenModel.dialog.isShowing) { - screenModel.dialog.show() - } + screenModel.onMigrationSheet(true) }, expanded = fabExpanded, ) @@ -182,6 +166,19 @@ class PreMigrationScreen(val mangaIds: List) : Screen() { ) } } + + val migrationSheetOpen by screenModel.migrationSheetOpen.collectAsState() + if (migrationSheetOpen) { + MigrationBottomSheetDialog( + onDismissRequest = { screenModel.onMigrationSheet(false) }, + onStartMigration = { extraParam -> + screenModel.onMigrationSheet(false) + screenModel.saveEnabledSources() + + navigator replace MigrationListScreen(MigrationProcedureConfig(mangaIds, extraParam)) + }, + ) + } } companion object { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/design/PreMigrationScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/design/PreMigrationScreenModel.kt index 45cd0d40a..d12682439 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/design/PreMigrationScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/design/PreMigrationScreenModel.kt @@ -6,11 +6,9 @@ import eu.davidea.flexibleadapter.FlexibleAdapter import eu.kanade.domain.source.service.SourcePreferences import eu.kanade.tachiyomi.databinding.PreMigrationListBinding import eu.kanade.tachiyomi.source.online.HttpSource -import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update -import kotlinx.coroutines.launch import tachiyomi.core.util.lang.launchIO import tachiyomi.domain.UnsortedPreferences import tachiyomi.domain.source.service.SourceManager @@ -26,28 +24,12 @@ class PreMigrationScreenModel( private val _state = MutableStateFlow(emptyList()) val state = _state.asStateFlow() + private val _migrationSheetOpen = MutableStateFlow(false) + val migrationSheetOpen = _migrationSheetOpen.asStateFlow() + lateinit var controllerBinding: PreMigrationListBinding var adapter: MigrationSourceAdapter? = null - val startMigration = MutableSharedFlow() - - val listener = object : StartMigrationListener { - override fun startMigration(extraParam: String?) { - val listOfSources = adapter?.currentItems - ?.filterIsInstance() - ?.filter { - it.sourceEnabled - } - ?.joinToString("/") { it.source.id.toString() } - .orEmpty() - - prefs.migrationSources().set(listOfSources) - - coroutineScope.launch { - startMigration.emit(extraParam) - } - } - } val clickListener = FlexibleAdapter.OnItemClickListener { _, position -> val adapter = adapter ?: return@OnItemClickListener false adapter.getItem(position)?.let { @@ -57,8 +39,6 @@ class PreMigrationScreenModel( false } - lateinit var dialog: MigrationBottomSheetDialog - init { coroutineScope.launchIO { val enabledSources = getEnabledSources() @@ -140,4 +120,20 @@ class PreMigrationScreenModel( val sortedItems = items.sortedBy { it.source.name }.sortedBy { !it.sourceEnabled } adapter.updateDataSet(sortedItems) } + + fun onMigrationSheet(isOpen: Boolean) { + _migrationSheetOpen.value = isOpen + } + + fun saveEnabledSources() { + val listOfSources = adapter?.currentItems + ?.filterIsInstance() + ?.filter { + it.sourceEnabled + } + ?.joinToString("/") { it.source.id.toString() } + .orEmpty() + + prefs.migrationSources().set(listOfSources) + } }