Full Compose settings (#8201)

* Uses Voyager for navigation.
* Replaces every screen inside settings except category editor screen since it's
called from several places.
This commit is contained in:
Ivan Iskandar
2022-10-15 22:38:01 +07:00
committed by GitHub
parent 3fdcd636d7
commit 890f1a3c7b
42 changed files with 4904 additions and 80 deletions

View File

@@ -56,6 +56,17 @@ abstract class BasicFullComposeController(bundle: Bundle? = null) :
}
}
}
// Let Compose view handle this
override fun handleBack(): Boolean {
val dispatcher = (activity as? OnBackPressedDispatcherOwner)?.onBackPressedDispatcher ?: return false
return if (dispatcher.hasEnabledCallbacks()) {
dispatcher.onBackPressed()
true
} else {
false
}
}
}
interface ComposeContentController {

View File

@@ -7,7 +7,6 @@ import eu.kanade.tachiyomi.ui.base.controller.RootController
import eu.kanade.tachiyomi.ui.base.controller.pushController
import eu.kanade.tachiyomi.ui.category.CategoryController
import eu.kanade.tachiyomi.ui.download.DownloadController
import eu.kanade.tachiyomi.ui.setting.SettingsBackupController
import eu.kanade.tachiyomi.ui.setting.SettingsMainController
class MoreController :
@@ -22,7 +21,7 @@ class MoreController :
presenter = presenter,
onClickDownloadQueue = { router.pushController(DownloadController()) },
onClickCategories = { router.pushController(CategoryController()) },
onClickBackupAndRestore = { router.pushController(SettingsBackupController()) },
onClickBackupAndRestore = { router.pushController(SettingsMainController(toBackupScreen = true)) },
onClickSettings = { router.pushController(SettingsMainController()) },
onClickAbout = { router.pushController(AboutController()) },
)

View File

@@ -1,85 +1,49 @@
package eu.kanade.tachiyomi.ui.setting
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.ChromeReaderMode
import androidx.compose.material.icons.outlined.Code
import androidx.compose.material.icons.outlined.GetApp
import androidx.compose.material.icons.outlined.Palette
import androidx.compose.material.icons.outlined.Security
import androidx.compose.material.icons.outlined.SettingsBackupRestore
import androidx.compose.material.icons.outlined.Sync
import androidx.compose.material.icons.outlined.Tune
import android.os.Bundle
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.vector.rememberVectorPainter
import androidx.compose.ui.res.painterResource
import eu.kanade.presentation.more.settings.SettingsMainScreen
import eu.kanade.presentation.more.settings.SettingsSection
import eu.kanade.tachiyomi.R
import androidx.compose.runtime.CompositionLocalProvider
import androidx.core.os.bundleOf
import cafe.adriel.voyager.core.stack.StackEvent
import cafe.adriel.voyager.navigator.Navigator
import cafe.adriel.voyager.transitions.ScreenTransition
import eu.kanade.presentation.more.settings.screen.SettingsBackupScreen
import eu.kanade.presentation.more.settings.screen.SettingsMainScreen
import eu.kanade.presentation.util.LocalBackPress
import eu.kanade.presentation.util.LocalRouter
import eu.kanade.tachiyomi.ui.base.controller.BasicFullComposeController
import eu.kanade.tachiyomi.ui.base.controller.pushController
import eu.kanade.tachiyomi.ui.setting.search.SettingsSearchController
import soup.compose.material.motion.animation.materialSharedAxisZ
class SettingsMainController : BasicFullComposeController() {
class SettingsMainController : BasicFullComposeController {
@Suppress("unused")
constructor(bundle: Bundle) : this(bundle.getBoolean(TO_BACKUP_SCREEN))
constructor(toBackupScreen: Boolean = false) : super(bundleOf(TO_BACKUP_SCREEN to toBackupScreen))
private val toBackupScreen = args.getBoolean(TO_BACKUP_SCREEN)
@Composable
override fun ComposeContent() {
val settingsSections = listOf(
SettingsSection(
titleRes = R.string.pref_category_general,
painter = rememberVectorPainter(Icons.Outlined.Tune),
onClick = { router.pushController(SettingsGeneralController()) },
),
SettingsSection(
titleRes = R.string.pref_category_appearance,
painter = rememberVectorPainter(Icons.Outlined.Palette),
onClick = { router.pushController(SettingsAppearanceController()) },
),
SettingsSection(
titleRes = R.string.pref_category_library,
painter = painterResource(R.drawable.ic_library_outline_24dp),
onClick = { router.pushController(SettingsLibraryController()) },
),
SettingsSection(
titleRes = R.string.pref_category_reader,
painter = rememberVectorPainter(Icons.Outlined.ChromeReaderMode),
onClick = { router.pushController(SettingsReaderController()) },
),
SettingsSection(
titleRes = R.string.pref_category_downloads,
painter = rememberVectorPainter(Icons.Outlined.GetApp),
onClick = { router.pushController(SettingsDownloadController()) },
),
SettingsSection(
titleRes = R.string.pref_category_tracking,
painter = rememberVectorPainter(Icons.Outlined.Sync),
onClick = { router.pushController(SettingsTrackingController()) },
),
SettingsSection(
titleRes = R.string.browse,
painter = painterResource(R.drawable.ic_browse_outline_24dp),
onClick = { router.pushController(SettingsBrowseController()) },
),
SettingsSection(
titleRes = R.string.label_backup,
painter = rememberVectorPainter(Icons.Outlined.SettingsBackupRestore),
onClick = { router.pushController(SettingsBackupController()) },
),
SettingsSection(
titleRes = R.string.pref_category_security,
painter = rememberVectorPainter(Icons.Outlined.Security),
onClick = { router.pushController(SettingsSecurityController()) },
),
SettingsSection(
titleRes = R.string.pref_category_advanced,
painter = rememberVectorPainter(Icons.Outlined.Code),
onClick = { router.pushController(SettingsAdvancedController()) },
),
)
SettingsMainScreen(
navigateUp = router::popCurrentController,
sections = settingsSections,
onClickSearch = { router.pushController(SettingsSearchController()) },
Navigator(
screen = if (toBackupScreen) SettingsBackupScreen() else SettingsMainScreen,
content = {
CompositionLocalProvider(
LocalRouter provides router,
LocalBackPress provides this::back,
) {
ScreenTransition(
navigator = it,
transition = { materialSharedAxisZ(forward = it.lastEvent != StackEvent.Pop) },
)
}
},
)
}
private fun back() {
activity?.onBackPressed()
}
}
private const val TO_BACKUP_SCREEN = "to_backup_screen"

View File

@@ -10,6 +10,9 @@ import androidx.biometric.auth.AuthPromptCallback
import androidx.biometric.auth.startClass2BiometricOrCredentialAuthentication
import androidx.core.content.ContextCompat
import androidx.fragment.app.FragmentActivity
import eu.kanade.tachiyomi.R
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlin.coroutines.resume
object AuthenticatorUtil {
@@ -43,6 +46,45 @@ object AuthenticatorUtil {
)
}
suspend fun FragmentActivity.authenticate(
title: String,
subtitle: String? = getString(R.string.confirm_lock_change),
): Boolean = suspendCancellableCoroutine { cont ->
if (!isAuthenticationSupported()) {
cont.resume(true)
return@suspendCancellableCoroutine
}
startAuthentication(
title,
subtitle,
callback = object : AuthenticationCallback() {
override fun onAuthenticationSucceeded(
activity: FragmentActivity?,
result: BiometricPrompt.AuthenticationResult,
) {
super.onAuthenticationSucceeded(activity, result)
cont.resume(true)
}
override fun onAuthenticationError(
activity: FragmentActivity?,
errorCode: Int,
errString: CharSequence,
) {
super.onAuthenticationError(activity, errorCode, errString)
activity?.toast(errString.toString())
cont.resume(false)
}
override fun onAuthenticationFailed(activity: FragmentActivity?) {
super.onAuthenticationFailed(activity)
cont.resume(false)
}
},
)
}
/**
* Returns true if Class 2 biometric or credential lock is set and available to use
*/