Skip to content

Commit

Permalink
Refactor onboarding steps
Browse files Browse the repository at this point in the history
(cherry picked from commit 2ca3ab077192a7e5e2e7a5fb00c303a5a633372e)
  • Loading branch information
ivaniskandar authored and arkon committed Dec 16, 2023
1 parent e36a2c6 commit 65e1e2c
Show file tree
Hide file tree
Showing 8 changed files with 140 additions and 111 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,34 +17,38 @@ import eu.kanade.presentation.theme.TachiyomiTheme
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.i18n.stringResource

@Composable
internal fun GuidesStep(
onRestoreBackup: () -> Unit,
) {
val handler = LocalUriHandler.current

Column(
modifier = Modifier.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
Text(stringResource(MR.strings.onboarding_guides_new_user, stringResource(MR.strings.app_name)))
Button(
modifier = Modifier.fillMaxWidth(),
onClick = { handler.openUri(GETTING_STARTED_URL) },
) {
Text(stringResource(MR.strings.getting_started_guide))
}
internal class GuidesStep(
private val onRestoreBackup: () -> Unit,
) : OnboardingStep {
override val isComplete: Boolean = true

HorizontalDivider(
color = MaterialTheme.colorScheme.onPrimaryContainer,
)
@Composable
override fun Content() {
val handler = LocalUriHandler.current

Text(stringResource(MR.strings.onboarding_guides_returning_user, stringResource(MR.strings.app_name)))
Button(
modifier = Modifier.fillMaxWidth(),
onClick = onRestoreBackup,
Column(
modifier = Modifier.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
Text(stringResource(MR.strings.pref_restore_backup))
Text(stringResource(MR.strings.onboarding_guides_new_user, stringResource(MR.strings.app_name)))
Button(
modifier = Modifier.fillMaxWidth(),
onClick = { handler.openUri(GETTING_STARTED_URL) },
) {
Text(stringResource(MR.strings.getting_started_guide))
}

HorizontalDivider(
color = MaterialTheme.colorScheme.onPrimaryContainer,
)

Text(stringResource(MR.strings.onboarding_guides_returning_user, stringResource(MR.strings.app_name)))
Button(
modifier = Modifier.fillMaxWidth(),
onClick = onRestoreBackup,
) {
Text(stringResource(MR.strings.pref_restore_backup))
}
}
}
}
Expand All @@ -57,6 +61,6 @@ private fun GuidesStepPreview() {
TachiyomiTheme {
GuidesStep(
onRestoreBackup = {},
)
).Content()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,40 +13,34 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
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.rememberSlideDistance
import tachiyomi.domain.storage.service.StoragePreferences
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.padding
import tachiyomi.presentation.core.i18n.stringResource
import tachiyomi.presentation.core.screens.InfoScreen

@Composable
fun OnboardingScreen(
storagePreferences: StoragePreferences,
uiPreferences: UiPreferences,
onComplete: () -> Unit,
onRestoreBackup: () -> Unit,
) {
val context = LocalContext.current
val slideDistance = rememberSlideDistance()

var currentStep by remember { mutableIntStateOf(0) }
val steps: List<@Composable () -> Unit> = remember {
var currentStep by rememberSaveable { mutableIntStateOf(0) }
val steps = remember {
listOf(
{ ThemeStep(uiPreferences = uiPreferences) },
{ StorageStep(storagePref = storagePreferences.baseStorageDirectory()) },
ThemeStep(),
StorageStep(),
// 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-- })

Expand All @@ -61,16 +55,12 @@ fun OnboardingScreen(
MR.strings.onboarding_action_next
},
),
canAccept = steps[currentStep].isComplete,
onAcceptClick = {
if (isLastStep) {
onComplete()
} else {
// TODO: this is kind of janky
if (currentStep == 1 && !storagePreferences.baseStorageDirectory().isSet()) {
context.toast(MR.strings.onboarding_storage_selection_required)
} else {
currentStep++
}
currentStep++
}
},
) {
Expand All @@ -91,7 +81,7 @@ fun OnboardingScreen(
},
label = "stepContent",
) {
steps[it]()
steps[it].Content()
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package eu.kanade.presentation.more.onboarding

import androidx.compose.runtime.Composable

internal interface OnboardingStep {

val isComplete: Boolean

@Composable
fun Content()
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,46 +7,66 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Text
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.platform.LocalContext
import androidx.compose.ui.unit.dp
import eu.kanade.presentation.more.settings.screen.SettingsDataScreen
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.presentation.core.components.material.Button
import tachiyomi.presentation.core.i18n.stringResource
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get

@Composable
internal fun StorageStep(
storagePref: Preference<String>,
) {
val context = LocalContext.current
val pickStorageLocation = SettingsDataScreen.storageLocationPicker(storagePref)

Column(
modifier = Modifier.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
Text(
stringResource(
MR.strings.onboarding_storage_info,
stringResource(MR.strings.app_name),
SettingsDataScreen.storageLocationText(storagePref),
),
)

Button(
modifier = Modifier.fillMaxWidth(),
onClick = {
try {
pickStorageLocation.launch(null)
} catch (e: ActivityNotFoundException) {
context.toast(MR.strings.file_picker_error)
}
},
internal class StorageStep : OnboardingStep {

private val storagePref = Injekt.get<StoragePreferences>().baseStorageDirectory()

private var _isComplete by mutableStateOf(false)

override val isComplete: Boolean
get() = _isComplete

@Composable
override fun Content() {
val context = LocalContext.current
val pickStorageLocation = SettingsDataScreen.storageLocationPicker(storagePref)

Column(
modifier = Modifier.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
Text(stringResource(MR.strings.onboarding_storage_action_select))
Text(
stringResource(
MR.strings.onboarding_storage_info,
stringResource(MR.strings.app_name),
SettingsDataScreen.storageLocationText(storagePref),
),
)

Button(
modifier = Modifier.fillMaxWidth(),
onClick = {
try {
pickStorageLocation.launch(null)
} catch (e: ActivityNotFoundException) {
context.toast(MR.strings.file_picker_error)
}
},
) {
Text(stringResource(MR.strings.onboarding_storage_action_select))
}
}

LaunchedEffect(Unit) {
storagePref.changes()
.collectLatest { _isComplete = storagePref.isSet() }
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,33 +8,40 @@ import eu.kanade.domain.ui.model.setAppCompatDelegateThemeMode
import eu.kanade.presentation.more.settings.widget.AppThemeModePreferenceWidget
import eu.kanade.presentation.more.settings.widget.AppThemePreferenceWidget
import tachiyomi.presentation.core.util.collectAsState
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get

@Composable
internal fun ThemeStep(
uiPreferences: UiPreferences,
) {
val themeModePref = uiPreferences.themeMode()
val themeMode by themeModePref.collectAsState()

val appThemePref = uiPreferences.appTheme()
val appTheme by appThemePref.collectAsState()

val amoledPref = uiPreferences.themeDarkAmoled()
val amoled by amoledPref.collectAsState()

Column {
AppThemeModePreferenceWidget(
value = themeMode,
onItemClick = {
themeModePref.set(it)
setAppCompatDelegateThemeMode(it)
},
)

AppThemePreferenceWidget(
value = appTheme,
amoled = amoled,
onItemClick = { appThemePref.set(it) },
)
internal class ThemeStep : OnboardingStep {

override val isComplete: Boolean = true

private val uiPreferences: UiPreferences = Injekt.get()

@Composable
override fun Content() {
val themeModePref = uiPreferences.themeMode()
val themeMode by themeModePref.collectAsState()

val appThemePref = uiPreferences.appTheme()
val appTheme by appThemePref.collectAsState()

val amoledPref = uiPreferences.themeDarkAmoled()
val amoled by amoledPref.collectAsState()

Column {
AppThemeModePreferenceWidget(
value = themeMode,
onItemClick = {
themeModePref.set(it)
setAppCompatDelegateThemeMode(it)
},
)

AppThemePreferenceWidget(
value = appTheme,
amoled = amoled,
onItemClick = { appThemePref.set(it) },
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ class MainActivity : BaseActivity() {
val navigator = LocalNavigator.currentOrThrow

LaunchedEffect(Unit) {
if (!preferences.shownOnboardingFlow().get()) {
if (!preferences.shownOnboardingFlow().get() && navigator.lastItem !is OnboardingScreen) {
navigator.push(OnboardingScreen())
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,9 @@ import androidx.compose.runtime.remember
import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.currentOrThrow
import eu.kanade.domain.base.BasePreferences
import eu.kanade.domain.ui.UiPreferences
import eu.kanade.presentation.more.onboarding.OnboardingScreen
import eu.kanade.presentation.util.Screen
import eu.kanade.tachiyomi.ui.setting.SettingsScreen
import tachiyomi.domain.storage.service.StoragePreferences
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get

Expand All @@ -20,17 +18,13 @@ class OnboardingScreen : Screen() {
val navigator = LocalNavigator.currentOrThrow

val basePreferences = remember { Injekt.get<BasePreferences>() }
val storagePreferences = remember { Injekt.get<StoragePreferences>() }
val uiPreferences = remember { Injekt.get<UiPreferences>() }

val finishOnboarding = {
basePreferences.shownOnboardingFlow().set(true)
navigator.pop()
}

OnboardingScreen(
storagePreferences = storagePreferences,
uiPreferences = uiPreferences,
onComplete = { finishOnboarding() },
onRestoreBackup = {
finishOnboarding()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Newspaper
import androidx.compose.material3.Button
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.NavigationBarDefaults
Expand All @@ -38,6 +39,7 @@ fun InfoScreen(
subtitleText: String,
acceptText: String,
onAcceptClick: () -> Unit,
canAccept: Boolean = true,
rejectText: String? = null,
onRejectClick: (() -> Unit)? = null,
content: @Composable ColumnScope.() -> Unit,
Expand All @@ -63,8 +65,9 @@ fun InfoScreen(
vertical = MaterialTheme.padding.small,
),
) {
androidx.compose.material3.Button(
Button(
modifier = Modifier.fillMaxWidth(),
enabled = canAccept,
onClick = onAcceptClick,
) {
Text(text = acceptText)
Expand Down

0 comments on commit 65e1e2c

Please sign in to comment.