More onboarding screen additions
This commit is contained in:
parent
8b57169e92
commit
e3404cd3d3
8 changed files with 114 additions and 19 deletions
|
@ -2,7 +2,7 @@ package eu.kanade.presentation.crash
|
|||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.BugReport
|
||||
|
@ -47,7 +47,7 @@ fun CrashScreen(
|
|||
modifier = Modifier
|
||||
.padding(vertical = MaterialTheme.padding.small)
|
||||
.clip(MaterialTheme.shapes.small)
|
||||
.fillMaxWidth()
|
||||
.fillMaxSize()
|
||||
.background(MaterialTheme.colorScheme.surfaceVariant),
|
||||
) {
|
||||
Text(
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
package eu.kanade.presentation.more.onboarding
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalUriHandler
|
||||
import androidx.compose.ui.unit.dp
|
||||
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))
|
||||
}
|
||||
|
||||
HorizontalDivider()
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const val GETTING_STARTED_URL = "https://tachiyomi.org/docs/guides/getting-started"
|
|
@ -1,18 +1,27 @@
|
|||
package eu.kanade.presentation.more.onboarding
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.RocketLaunch
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import eu.kanade.domain.ui.UiPreferences
|
||||
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
|
||||
|
||||
|
@ -21,16 +30,20 @@ fun OnboardingScreen(
|
|||
storagePreferences: StoragePreferences,
|
||||
uiPreferences: UiPreferences,
|
||||
onComplete: () -> Unit,
|
||||
onRestoreBackup: () -> Unit,
|
||||
) {
|
||||
var currentStep by remember { mutableIntStateOf(0) }
|
||||
val steps: List<@Composable () -> Unit> = listOf(
|
||||
{ ThemeStep(uiPreferences = uiPreferences) },
|
||||
{ StorageStep(storagePref = storagePreferences.baseStorageDirectory()) },
|
||||
// TODO: prompt for notification permissions when bumping target to Android 13
|
||||
{ GuidesStep(onRestoreBackup = onRestoreBackup) },
|
||||
)
|
||||
val isLastStep = currentStep == steps.size - 1
|
||||
val slideDistance = rememberSlideDistance()
|
||||
|
||||
BackHandler(enabled = currentStep != 0, onBack = { currentStep-- })
|
||||
|
||||
InfoScreen(
|
||||
icon = Icons.Outlined.RocketLaunch,
|
||||
headingText = stringResource(MR.strings.onboarding_heading),
|
||||
|
@ -52,17 +65,25 @@ fun OnboardingScreen(
|
|||
rejectText = stringResource(MR.strings.onboarding_action_skip),
|
||||
onRejectClick = onComplete,
|
||||
) {
|
||||
AnimatedContent(
|
||||
targetState = currentStep,
|
||||
transitionSpec = {
|
||||
materialSharedAxisX(
|
||||
forward = true,
|
||||
slideDistance = slideDistance,
|
||||
)
|
||||
},
|
||||
label = "stepContent",
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(vertical = MaterialTheme.padding.small)
|
||||
.clip(MaterialTheme.shapes.small)
|
||||
.fillMaxSize()
|
||||
.background(MaterialTheme.colorScheme.surfaceVariant),
|
||||
) {
|
||||
steps[it]()
|
||||
AnimatedContent(
|
||||
targetState = currentStep,
|
||||
transitionSpec = {
|
||||
materialSharedAxisX(
|
||||
forward = true,
|
||||
slideDistance = slideDistance,
|
||||
)
|
||||
},
|
||||
label = "stepContent",
|
||||
) {
|
||||
steps[it]()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,8 +3,11 @@ package eu.kanade.presentation.more.onboarding
|
|||
import android.content.ActivityNotFoundException
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
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.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.unit.dp
|
||||
import eu.kanade.presentation.more.settings.screen.SettingsDataScreen
|
||||
|
@ -22,11 +25,19 @@ internal fun StorageStep(
|
|||
val pickStorageLocation = SettingsDataScreen.storageLocationPicker(storagePref)
|
||||
|
||||
Column(
|
||||
modifier = Modifier.padding(16.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||
) {
|
||||
Text(stringResource(MR.strings.onboarding_storage_info))
|
||||
Text(
|
||||
stringResource(
|
||||
MR.strings.onboarding_storage_info,
|
||||
stringResource(MR.strings.app_name),
|
||||
SettingsDataScreen.storageLocationText(storagePref),
|
||||
),
|
||||
)
|
||||
|
||||
Button(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
onClick = {
|
||||
try {
|
||||
pickStorageLocation.launch(null)
|
||||
|
@ -35,7 +46,7 @@ internal fun StorageStep(
|
|||
}
|
||||
},
|
||||
) {
|
||||
Text(SettingsDataScreen.storageLocationText(storagePref))
|
||||
Text(stringResource(MR.strings.onboarding_storage_action_select))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -110,6 +110,10 @@ object SettingsDataScreen : SearchableSettings {
|
|||
val context = LocalContext.current
|
||||
val storageDir by storageDirPref.collectAsState()
|
||||
|
||||
if (storageDir == storageDirPref.defaultValue()) {
|
||||
return stringResource(MR.strings.no_location_set)
|
||||
}
|
||||
|
||||
return remember(storageDir) {
|
||||
val file = UniFile.fromUri(context, storageDir.toUri())
|
||||
file?.filePath ?: file?.uri?.toString()
|
||||
|
|
|
@ -33,6 +33,7 @@ import eu.kanade.presentation.library.LibrarySettingsDialog
|
|||
import eu.kanade.presentation.library.components.LibraryContent
|
||||
import eu.kanade.presentation.library.components.LibraryToolbar
|
||||
import eu.kanade.presentation.manga.components.LibraryBottomActionMenu
|
||||
import eu.kanade.presentation.more.onboarding.GETTING_STARTED_URL
|
||||
import eu.kanade.presentation.util.Tab
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
|
||||
|
@ -163,7 +164,7 @@ object LibraryTab : Tab {
|
|||
EmptyScreenAction(
|
||||
stringRes = MR.strings.getting_started_guide,
|
||||
icon = Icons.AutoMirrored.Outlined.HelpOutline,
|
||||
onClick = { handler.openUri("https://tachiyomi.org/docs/guides/getting-started") },
|
||||
onClick = { handler.openUri(GETTING_STARTED_URL) },
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
|
@ -8,6 +8,7 @@ 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
|
||||
|
@ -22,12 +23,18 @@ class OnboardingScreen : Screen() {
|
|||
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 = {
|
||||
basePreferences.shownOnboardingFlow().set(true)
|
||||
navigator.pop()
|
||||
onComplete = { finishOnboarding() },
|
||||
onRestoreBackup = {
|
||||
finishOnboarding()
|
||||
navigator.push(SettingsScreen.toDataAndStorageScreen())
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
@ -180,7 +180,10 @@
|
|||
<string name="onboarding_action_next">Next</string>
|
||||
<string name="onboarding_action_finish">Get started</string>
|
||||
<string name="onboarding_action_skip">Skip</string>
|
||||
<string name="onboarding_storage_info">Select a storage location where chapter downloads, backups, and local source content will be stored.</string>
|
||||
<string name="onboarding_storage_info">Select a folder where %1$s will store chapter downloads, backups, and more.\n\nA dedicated folder is recommended.\n\nSelected folder: %2$s</string>
|
||||
<string name="onboarding_storage_action_select">Select a folder</string>
|
||||
<string name="onboarding_guides_new_user">New to %s? We recommend checking out the getting started guide.</string>
|
||||
<string name="onboarding_guides_returning_user">Already used %s before?</string>
|
||||
|
||||
<!-- Preferences -->
|
||||
<!-- Subsections -->
|
||||
|
@ -439,6 +442,7 @@
|
|||
<string name="pref_remove_after_read">After reading automatically delete</string>
|
||||
<string name="pref_remove_bookmarked_chapters">Allow deleting bookmarked chapters</string>
|
||||
<string name="pref_remove_exclude_categories">Excluded categories</string>
|
||||
<string name="no_location_set">No storage location set</string>
|
||||
<string name="invalid_location">Invalid location: %s</string>
|
||||
<string name="disabled">Disabled</string>
|
||||
<string name="last_read_chapter">Last read chapter</string>
|
||||
|
|
Reference in a new issue