mirror of
https://github.com/mihonapp/mihon.git
synced 2024-11-21 20:47:03 -05:00
Refactor onboarding steps
(cherry picked from commit 2ca3ab077192a7e5e2e7a5fb00c303a5a633372e)
This commit is contained in:
parent
e36a2c68f1
commit
65e1e2cf4f
8 changed files with 133 additions and 104 deletions
|
@ -17,10 +17,13 @@ import eu.kanade.presentation.theme.TachiyomiTheme
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import tachiyomi.presentation.core.i18n.stringResource
|
import tachiyomi.presentation.core.i18n.stringResource
|
||||||
|
|
||||||
|
internal class GuidesStep(
|
||||||
|
private val onRestoreBackup: () -> Unit,
|
||||||
|
) : OnboardingStep {
|
||||||
|
override val isComplete: Boolean = true
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun GuidesStep(
|
override fun Content() {
|
||||||
onRestoreBackup: () -> Unit,
|
|
||||||
) {
|
|
||||||
val handler = LocalUriHandler.current
|
val handler = LocalUriHandler.current
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
|
@ -48,6 +51,7 @@ internal fun GuidesStep(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const val GETTING_STARTED_URL = "https://tachiyomi.org/docs/guides/getting-started"
|
const val GETTING_STARTED_URL = "https://tachiyomi.org/docs/guides/getting-started"
|
||||||
|
|
||||||
|
@ -57,6 +61,6 @@ private fun GuidesStepPreview() {
|
||||||
TachiyomiTheme {
|
TachiyomiTheme {
|
||||||
GuidesStep(
|
GuidesStep(
|
||||||
onRestoreBackup = {},
|
onRestoreBackup = {},
|
||||||
)
|
).Content()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,15 +13,12 @@ import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableIntStateOf
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.platform.LocalContext
|
|
||||||
import eu.kanade.domain.ui.UiPreferences
|
|
||||||
import eu.kanade.tachiyomi.util.system.toast
|
|
||||||
import soup.compose.material.motion.animation.materialSharedAxisX
|
import soup.compose.material.motion.animation.materialSharedAxisX
|
||||||
import soup.compose.material.motion.animation.rememberSlideDistance
|
import soup.compose.material.motion.animation.rememberSlideDistance
|
||||||
import tachiyomi.domain.storage.service.StoragePreferences
|
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import tachiyomi.presentation.core.components.material.padding
|
import tachiyomi.presentation.core.components.material.padding
|
||||||
import tachiyomi.presentation.core.i18n.stringResource
|
import tachiyomi.presentation.core.i18n.stringResource
|
||||||
|
@ -29,24 +26,21 @@ import tachiyomi.presentation.core.screens.InfoScreen
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun OnboardingScreen(
|
fun OnboardingScreen(
|
||||||
storagePreferences: StoragePreferences,
|
|
||||||
uiPreferences: UiPreferences,
|
|
||||||
onComplete: () -> Unit,
|
onComplete: () -> Unit,
|
||||||
onRestoreBackup: () -> Unit,
|
onRestoreBackup: () -> Unit,
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
|
||||||
val slideDistance = rememberSlideDistance()
|
val slideDistance = rememberSlideDistance()
|
||||||
|
|
||||||
var currentStep by remember { mutableIntStateOf(0) }
|
var currentStep by rememberSaveable { mutableIntStateOf(0) }
|
||||||
val steps: List<@Composable () -> Unit> = remember {
|
val steps = remember {
|
||||||
listOf(
|
listOf(
|
||||||
{ ThemeStep(uiPreferences = uiPreferences) },
|
ThemeStep(),
|
||||||
{ StorageStep(storagePref = storagePreferences.baseStorageDirectory()) },
|
StorageStep(),
|
||||||
// TODO: prompt for notification permissions when bumping target to Android 13
|
// TODO: prompt for notification permissions when bumping target to Android 13
|
||||||
{ GuidesStep(onRestoreBackup = onRestoreBackup) },
|
GuidesStep(onRestoreBackup = onRestoreBackup),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
val isLastStep = currentStep == steps.size - 1
|
val isLastStep = currentStep == steps.lastIndex
|
||||||
|
|
||||||
BackHandler(enabled = currentStep != 0, onBack = { currentStep-- })
|
BackHandler(enabled = currentStep != 0, onBack = { currentStep-- })
|
||||||
|
|
||||||
|
@ -61,17 +55,13 @@ fun OnboardingScreen(
|
||||||
MR.strings.onboarding_action_next
|
MR.strings.onboarding_action_next
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
canAccept = steps[currentStep].isComplete,
|
||||||
onAcceptClick = {
|
onAcceptClick = {
|
||||||
if (isLastStep) {
|
if (isLastStep) {
|
||||||
onComplete()
|
onComplete()
|
||||||
} else {
|
|
||||||
// TODO: this is kind of janky
|
|
||||||
if (currentStep == 1 && !storagePreferences.baseStorageDirectory().isSet()) {
|
|
||||||
context.toast(MR.strings.onboarding_storage_selection_required)
|
|
||||||
} else {
|
} else {
|
||||||
currentStep++
|
currentStep++
|
||||||
}
|
}
|
||||||
}
|
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
Box(
|
Box(
|
||||||
|
@ -91,7 +81,7 @@ fun OnboardingScreen(
|
||||||
},
|
},
|
||||||
label = "stepContent",
|
label = "stepContent",
|
||||||
) {
|
) {
|
||||||
steps[it]()
|
steps[it].Content()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
package eu.kanade.presentation.more.onboarding
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
|
||||||
|
internal interface OnboardingStep {
|
||||||
|
|
||||||
|
val isComplete: Boolean
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Content()
|
||||||
|
}
|
|
@ -7,20 +7,34 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import eu.kanade.presentation.more.settings.screen.SettingsDataScreen
|
import eu.kanade.presentation.more.settings.screen.SettingsDataScreen
|
||||||
import eu.kanade.tachiyomi.util.system.toast
|
import eu.kanade.tachiyomi.util.system.toast
|
||||||
import tachiyomi.core.preference.Preference
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
|
import tachiyomi.domain.storage.service.StoragePreferences
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import tachiyomi.presentation.core.components.material.Button
|
import tachiyomi.presentation.core.components.material.Button
|
||||||
import tachiyomi.presentation.core.i18n.stringResource
|
import tachiyomi.presentation.core.i18n.stringResource
|
||||||
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
|
internal class StorageStep : OnboardingStep {
|
||||||
|
|
||||||
|
private val storagePref = Injekt.get<StoragePreferences>().baseStorageDirectory()
|
||||||
|
|
||||||
|
private var _isComplete by mutableStateOf(false)
|
||||||
|
|
||||||
|
override val isComplete: Boolean
|
||||||
|
get() = _isComplete
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun StorageStep(
|
override fun Content() {
|
||||||
storagePref: Preference<String>,
|
|
||||||
) {
|
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val pickStorageLocation = SettingsDataScreen.storageLocationPicker(storagePref)
|
val pickStorageLocation = SettingsDataScreen.storageLocationPicker(storagePref)
|
||||||
|
|
||||||
|
@ -49,4 +63,10 @@ internal fun StorageStep(
|
||||||
Text(stringResource(MR.strings.onboarding_storage_action_select))
|
Text(stringResource(MR.strings.onboarding_storage_action_select))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
storagePref.changes()
|
||||||
|
.collectLatest { _isComplete = storagePref.isSet() }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,11 +8,17 @@ import eu.kanade.domain.ui.model.setAppCompatDelegateThemeMode
|
||||||
import eu.kanade.presentation.more.settings.widget.AppThemeModePreferenceWidget
|
import eu.kanade.presentation.more.settings.widget.AppThemeModePreferenceWidget
|
||||||
import eu.kanade.presentation.more.settings.widget.AppThemePreferenceWidget
|
import eu.kanade.presentation.more.settings.widget.AppThemePreferenceWidget
|
||||||
import tachiyomi.presentation.core.util.collectAsState
|
import tachiyomi.presentation.core.util.collectAsState
|
||||||
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
|
internal class ThemeStep : OnboardingStep {
|
||||||
|
|
||||||
|
override val isComplete: Boolean = true
|
||||||
|
|
||||||
|
private val uiPreferences: UiPreferences = Injekt.get()
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun ThemeStep(
|
override fun Content() {
|
||||||
uiPreferences: UiPreferences,
|
|
||||||
) {
|
|
||||||
val themeModePref = uiPreferences.themeMode()
|
val themeModePref = uiPreferences.themeMode()
|
||||||
val themeMode by themeModePref.collectAsState()
|
val themeMode by themeModePref.collectAsState()
|
||||||
|
|
||||||
|
@ -38,3 +44,4 @@ internal fun ThemeStep(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -349,7 +349,7 @@ class MainActivity : BaseActivity() {
|
||||||
val navigator = LocalNavigator.currentOrThrow
|
val navigator = LocalNavigator.currentOrThrow
|
||||||
|
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
if (!preferences.shownOnboardingFlow().get()) {
|
if (!preferences.shownOnboardingFlow().get() && navigator.lastItem !is OnboardingScreen) {
|
||||||
navigator.push(OnboardingScreen())
|
navigator.push(OnboardingScreen())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,11 +5,9 @@ import androidx.compose.runtime.remember
|
||||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||||
import eu.kanade.domain.base.BasePreferences
|
import eu.kanade.domain.base.BasePreferences
|
||||||
import eu.kanade.domain.ui.UiPreferences
|
|
||||||
import eu.kanade.presentation.more.onboarding.OnboardingScreen
|
import eu.kanade.presentation.more.onboarding.OnboardingScreen
|
||||||
import eu.kanade.presentation.util.Screen
|
import eu.kanade.presentation.util.Screen
|
||||||
import eu.kanade.tachiyomi.ui.setting.SettingsScreen
|
import eu.kanade.tachiyomi.ui.setting.SettingsScreen
|
||||||
import tachiyomi.domain.storage.service.StoragePreferences
|
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
|
@ -20,8 +18,6 @@ class OnboardingScreen : Screen() {
|
||||||
val navigator = LocalNavigator.currentOrThrow
|
val navigator = LocalNavigator.currentOrThrow
|
||||||
|
|
||||||
val basePreferences = remember { Injekt.get<BasePreferences>() }
|
val basePreferences = remember { Injekt.get<BasePreferences>() }
|
||||||
val storagePreferences = remember { Injekt.get<StoragePreferences>() }
|
|
||||||
val uiPreferences = remember { Injekt.get<UiPreferences>() }
|
|
||||||
|
|
||||||
val finishOnboarding = {
|
val finishOnboarding = {
|
||||||
basePreferences.shownOnboardingFlow().set(true)
|
basePreferences.shownOnboardingFlow().set(true)
|
||||||
|
@ -29,8 +25,6 @@ class OnboardingScreen : Screen() {
|
||||||
}
|
}
|
||||||
|
|
||||||
OnboardingScreen(
|
OnboardingScreen(
|
||||||
storagePreferences = storagePreferences,
|
|
||||||
uiPreferences = uiPreferences,
|
|
||||||
onComplete = { finishOnboarding() },
|
onComplete = { finishOnboarding() },
|
||||||
onRestoreBackup = {
|
onRestoreBackup = {
|
||||||
finishOnboarding()
|
finishOnboarding()
|
||||||
|
|
|
@ -13,6 +13,7 @@ import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.outlined.Newspaper
|
import androidx.compose.material.icons.outlined.Newspaper
|
||||||
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.NavigationBarDefaults
|
import androidx.compose.material3.NavigationBarDefaults
|
||||||
|
@ -38,6 +39,7 @@ fun InfoScreen(
|
||||||
subtitleText: String,
|
subtitleText: String,
|
||||||
acceptText: String,
|
acceptText: String,
|
||||||
onAcceptClick: () -> Unit,
|
onAcceptClick: () -> Unit,
|
||||||
|
canAccept: Boolean = true,
|
||||||
rejectText: String? = null,
|
rejectText: String? = null,
|
||||||
onRejectClick: (() -> Unit)? = null,
|
onRejectClick: (() -> Unit)? = null,
|
||||||
content: @Composable ColumnScope.() -> Unit,
|
content: @Composable ColumnScope.() -> Unit,
|
||||||
|
@ -63,8 +65,9 @@ fun InfoScreen(
|
||||||
vertical = MaterialTheme.padding.small,
|
vertical = MaterialTheme.padding.small,
|
||||||
),
|
),
|
||||||
) {
|
) {
|
||||||
androidx.compose.material3.Button(
|
Button(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
enabled = canAccept,
|
||||||
onClick = onAcceptClick,
|
onClick = onAcceptClick,
|
||||||
) {
|
) {
|
||||||
Text(text = acceptText)
|
Text(text = acceptText)
|
||||||
|
|
Loading…
Reference in a new issue