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
|
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.LayoutInflater
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.view.WindowManager
|
|
||||||
import android.widget.CompoundButton
|
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.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 androidx.core.view.isVisible
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
import eu.kanade.presentation.components.AdaptiveSheet
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
|
||||||
import com.google.android.material.bottomsheet.getElevation
|
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.databinding.MigrationBottomSheetBinding
|
import eu.kanade.tachiyomi.databinding.MigrationBottomSheetBinding
|
||||||
import eu.kanade.tachiyomi.ui.browse.migration.MigrationFlags
|
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.system.toast
|
||||||
import eu.kanade.tachiyomi.util.view.setNavigationBarTransparentCompat
|
|
||||||
import tachiyomi.core.preference.Preference
|
import tachiyomi.core.preference.Preference
|
||||||
import tachiyomi.core.util.lang.toLong
|
import tachiyomi.core.util.lang.toLong
|
||||||
import tachiyomi.domain.UnsortedPreferences
|
import tachiyomi.domain.UnsortedPreferences
|
||||||
import uy.kohesive.injekt.injectLazy
|
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()
|
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.
|
* Init general reader preferences.
|
||||||
*/
|
*/
|
||||||
private fun initPreferences() {
|
fun initPreferences(binding: MigrationBottomSheetBinding) {
|
||||||
val flags = preferences.migrateFlags().get()
|
val flags = preferences.migrateFlags().get()
|
||||||
|
|
||||||
binding.migChapters.isChecked = MigrationFlags.hasChapters(flags)
|
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.migCustomCover.isChecked = MigrationFlags.hasCustomCover(flags)
|
||||||
binding.migExtra.isChecked = MigrationFlags.hasExtra(flags)
|
binding.migExtra.isChecked = MigrationFlags.hasExtra(flags)
|
||||||
|
|
||||||
binding.migChapters.setOnCheckedChangeListener { _, _ -> setFlags() }
|
binding.migChapters.setOnCheckedChangeListener { _, _ -> setFlags(binding) }
|
||||||
binding.migCategories.setOnCheckedChangeListener { _, _ -> setFlags() }
|
binding.migCategories.setOnCheckedChangeListener { _, _ -> setFlags(binding) }
|
||||||
binding.migTracking.setOnCheckedChangeListener { _, _ -> setFlags() }
|
binding.migTracking.setOnCheckedChangeListener { _, _ -> setFlags(binding) }
|
||||||
binding.migCustomCover.setOnCheckedChangeListener { _, _ -> setFlags() }
|
binding.migCustomCover.setOnCheckedChangeListener { _, _ -> setFlags(binding) }
|
||||||
binding.migExtra.setOnCheckedChangeListener { _, _ -> setFlags() }
|
binding.migExtra.setOnCheckedChangeListener { _, _ -> setFlags(binding) }
|
||||||
|
|
||||||
binding.useSmartSearch.bindToPreference(preferences.smartMigration())
|
binding.useSmartSearch.bindToPreference(preferences.smartMigration())
|
||||||
binding.extraSearchParamText.isVisible = false
|
binding.extraSearchParamText.isVisible = false
|
||||||
@ -129,15 +76,27 @@ class MigrationBottomSheetDialog(private val baseContext: Context, private val l
|
|||||||
binding.HideNotFoundManga.isChecked = preferences.hideNotFoundMigration().get()
|
binding.HideNotFoundManga.isChecked = preferences.hideNotFoundMigration().get()
|
||||||
binding.skipStep.setOnCheckedChangeListener { _, isChecked ->
|
binding.skipStep.setOnCheckedChangeListener { _, isChecked ->
|
||||||
if (isChecked) {
|
if (isChecked) {
|
||||||
context.toast(
|
binding.root.context.toast(
|
||||||
R.string.pre_migration_skip_toast,
|
R.string.pre_migration_skip_toast,
|
||||||
Toast.LENGTH_LONG,
|
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
|
var flags = 0
|
||||||
if (binding.migChapters.isChecked) flags = flags or MigrationFlags.CHAPTERS
|
if (binding.migChapters.isChecked) flags = flags or MigrationFlags.CHAPTERS
|
||||||
if (binding.migCategories.isChecked) flags = flags or MigrationFlags.CATEGORIES
|
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.TopAppBarDefaults
|
||||||
import androidx.compose.material3.rememberTopAppBarState
|
import androidx.compose.material3.rememberTopAppBarState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.DisposableEffect
|
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
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.NestedScrollConnection
|
||||||
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
|
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
|
||||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
import androidx.compose.ui.platform.LocalContext
|
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
@ -57,17 +54,6 @@ class PreMigrationScreen(val mangaIds: List<Long>) : Screen() {
|
|||||||
val navigator = LocalNavigator.currentOrThrow
|
val navigator = LocalNavigator.currentOrThrow
|
||||||
var fabExpanded by remember { mutableStateOf(true) }
|
var fabExpanded by remember { mutableStateOf(true) }
|
||||||
val items by screenModel.state.collectAsState()
|
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 {
|
val nestedScrollConnection = remember {
|
||||||
// All this lines just for fab state :/
|
// All this lines just for fab state :/
|
||||||
@ -132,9 +118,7 @@ class PreMigrationScreen(val mangaIds: List<Long>) : Screen() {
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
onClick = {
|
onClick = {
|
||||||
if (!screenModel.dialog.isShowing) {
|
screenModel.onMigrationSheet(true)
|
||||||
screenModel.dialog.show()
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
expanded = fabExpanded,
|
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 {
|
companion object {
|
||||||
|
@ -6,11 +6,9 @@ import eu.davidea.flexibleadapter.FlexibleAdapter
|
|||||||
import eu.kanade.domain.source.service.SourcePreferences
|
import eu.kanade.domain.source.service.SourcePreferences
|
||||||
import eu.kanade.tachiyomi.databinding.PreMigrationListBinding
|
import eu.kanade.tachiyomi.databinding.PreMigrationListBinding
|
||||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import tachiyomi.core.util.lang.launchIO
|
import tachiyomi.core.util.lang.launchIO
|
||||||
import tachiyomi.domain.UnsortedPreferences
|
import tachiyomi.domain.UnsortedPreferences
|
||||||
import tachiyomi.domain.source.service.SourceManager
|
import tachiyomi.domain.source.service.SourceManager
|
||||||
@ -26,28 +24,12 @@ class PreMigrationScreenModel(
|
|||||||
private val _state = MutableStateFlow(emptyList<MigrationSourceItem>())
|
private val _state = MutableStateFlow(emptyList<MigrationSourceItem>())
|
||||||
val state = _state.asStateFlow()
|
val state = _state.asStateFlow()
|
||||||
|
|
||||||
|
private val _migrationSheetOpen = MutableStateFlow(false)
|
||||||
|
val migrationSheetOpen = _migrationSheetOpen.asStateFlow()
|
||||||
|
|
||||||
lateinit var controllerBinding: PreMigrationListBinding
|
lateinit var controllerBinding: PreMigrationListBinding
|
||||||
var adapter: MigrationSourceAdapter? = null
|
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 clickListener = FlexibleAdapter.OnItemClickListener { _, position ->
|
||||||
val adapter = adapter ?: return@OnItemClickListener false
|
val adapter = adapter ?: return@OnItemClickListener false
|
||||||
adapter.getItem(position)?.let {
|
adapter.getItem(position)?.let {
|
||||||
@ -57,8 +39,6 @@ class PreMigrationScreenModel(
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
lateinit var dialog: MigrationBottomSheetDialog
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
coroutineScope.launchIO {
|
coroutineScope.launchIO {
|
||||||
val enabledSources = getEnabledSources()
|
val enabledSources = getEnabledSources()
|
||||||
@ -140,4 +120,20 @@ class PreMigrationScreenModel(
|
|||||||
val sortedItems = items.sortedBy { it.source.name }.sortedBy { !it.sourceEnabled }
|
val sortedItems = items.sortedBy { it.source.name }.sortedBy { !it.sourceEnabled }
|
||||||
adapter.updateDataSet(sortedItems)
|
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