Use a compose Adaptive Sheet for pre-migration sheet
This commit is contained in:
parent
c8c9e79a3e
commit
cd4c217a7f
@ -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<WindowManager>()?.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?)
|
||||
}
|
||||
|
@ -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<Long>) : 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<Long>) : Screen() {
|
||||
)
|
||||
},
|
||||
onClick = {
|
||||
if (!screenModel.dialog.isShowing) {
|
||||
screenModel.dialog.show()
|
||||
}
|
||||
screenModel.onMigrationSheet(true)
|
||||
},
|
||||
expanded = fabExpanded,
|
||||
)
|
||||
@ -182,6 +166,19 @@ class PreMigrationScreen(val mangaIds: List<Long>) : 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 {
|
||||
|
@ -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<MigrationSourceItem>())
|
||||
val state = _state.asStateFlow()
|
||||
|
||||
private val _migrationSheetOpen = MutableStateFlow(false)
|
||||
val migrationSheetOpen = _migrationSheetOpen.asStateFlow()
|
||||
|
||||
lateinit var controllerBinding: PreMigrationListBinding
|
||||
var adapter: MigrationSourceAdapter? = null
|
||||
|
||||
val startMigration = MutableSharedFlow<String?>()
|
||||
|
||||
val listener = object : StartMigrationListener {
|
||||
override fun startMigration(extraParam: String?) {
|
||||
val listOfSources = adapter?.currentItems
|
||||
?.filterIsInstance<MigrationSourceItem>()
|
||||
?.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<MigrationSourceItem>()
|
||||
?.filter {
|
||||
it.sourceEnabled
|
||||
}
|
||||
?.joinToString("/") { it.source.id.toString() }
|
||||
.orEmpty()
|
||||
|
||||
prefs.migrationSources().set(listOfSources)
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user