Repo created

This commit is contained in:
Fr4nz D13trich 2025-11-22 13:56:56 +01:00
parent 75dc487a7a
commit 39c29d175b
6317 changed files with 388324 additions and 2 deletions

View file

@ -0,0 +1,19 @@
plugins {
id(ThunderbirdPlugins.Library.androidCompose)
}
android {
namespace = "app.k9mail.feature.onboarding.main"
resourcePrefix = "onboarding_main_"
}
dependencies {
implementation(projects.core.common)
implementation(projects.core.ui.compose.designsystem)
implementation(projects.core.ui.compose.navigation)
implementation(projects.feature.onboarding.welcome)
implementation(projects.feature.account.setup)
implementation(projects.feature.settings.import)
implementation(projects.feature.onboarding.permissions)
implementation(projects.feature.onboarding.migration.api)
}

View file

@ -0,0 +1,15 @@
package app.k9mail.feature.onboarding.main
import app.k9mail.feature.onboarding.main.navigation.DefaultOnboardingNavigation
import app.k9mail.feature.onboarding.main.navigation.OnboardingNavigation
import app.k9mail.feature.onboarding.permissions.featureOnboardingPermissionsModule
import org.koin.core.module.Module
import org.koin.dsl.module
val featureOnboardingModule: Module = module {
single<OnboardingNavigation> { DefaultOnboardingNavigation() }
includes(
featureOnboardingPermissionsModule,
)
}

View file

@ -0,0 +1,21 @@
package app.k9mail.feature.onboarding.main.navigation
import androidx.navigation.NavGraphBuilder
import app.k9mail.core.ui.compose.navigation.deepLinkComposable
import app.k9mail.feature.onboarding.main.navigation.OnboardingRoute.Onboarding
class DefaultOnboardingNavigation : OnboardingNavigation {
override fun registerRoutes(
navGraphBuilder: NavGraphBuilder,
onBack: () -> Unit,
onFinish: (OnboardingRoute) -> Unit,
) {
with(navGraphBuilder) {
deepLinkComposable<Onboarding>(Onboarding.BASE_PATH) {
OnboardingNavHost(
onFinish = onFinish,
)
}
}
}
}

View file

@ -0,0 +1,139 @@
package app.k9mail.feature.onboarding.main.navigation
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.navigation.NavController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import app.k9mail.feature.account.setup.navigation.AccountSetupNavHost
import app.k9mail.feature.account.setup.navigation.AccountSetupRoute
import app.k9mail.feature.onboarding.migration.api.OnboardingMigrationManager
import app.k9mail.feature.onboarding.permissions.domain.PermissionsDomainContract.UseCase.HasRuntimePermissions
import app.k9mail.feature.onboarding.permissions.ui.PermissionsScreen
import app.k9mail.feature.onboarding.welcome.ui.WelcomeScreen
import app.k9mail.feature.settings.import.ui.SettingsImportAction
import app.k9mail.feature.settings.import.ui.SettingsImportScreen
import org.koin.compose.koinInject
private const val NESTED_NAVIGATION_ROUTE_WELCOME = "welcome"
private const val NESTED_NAVIGATION_ROUTE_MIGRATION = "migration"
private const val NESTED_NAVIGATION_ROUTE_ACCOUNT_SETUP = "account_setup"
private const val NESTED_NAVIGATION_ROUTE_SETTINGS_IMPORT = "settings_import"
private const val NESTED_NAVIGATION_ROUTE_SETTINGS_IMPORT_QR_CODE = "settings_import_qr_code"
private const val NESTED_NAVIGATION_ROUTE_PERMISSIONS = "permissions"
private fun NavController.navigateToMigration() {
navigate(NESTED_NAVIGATION_ROUTE_MIGRATION)
}
private fun NavController.navigateToAccountSetup() {
navigate(NESTED_NAVIGATION_ROUTE_ACCOUNT_SETUP)
}
private fun NavController.navigateToSettingsImport() {
navigate(NESTED_NAVIGATION_ROUTE_SETTINGS_IMPORT)
}
private fun NavController.navigateToSettingsImportQrCode() {
navigate(NESTED_NAVIGATION_ROUTE_SETTINGS_IMPORT_QR_CODE)
}
private fun NavController.navigateToPermissions() {
navigate(NESTED_NAVIGATION_ROUTE_PERMISSIONS) {
popUpTo(NESTED_NAVIGATION_ROUTE_WELCOME) {
inclusive = true
}
}
}
@Suppress("LongMethod")
@Composable
fun OnboardingNavHost(
onFinish: (OnboardingRoute) -> Unit,
hasRuntimePermissions: HasRuntimePermissions = koinInject(),
onboardingMigrationManager: OnboardingMigrationManager = koinInject(),
) {
val navController = rememberNavController()
var accountUuid by rememberSaveable { mutableStateOf<String?>(null) }
fun onImportSuccess() {
if (hasRuntimePermissions()) {
navController.navigateToPermissions()
} else {
onFinish(OnboardingRoute.Onboarding(null))
}
}
NavHost(
navController = navController,
startDestination = NESTED_NAVIGATION_ROUTE_WELCOME,
) {
composable(route = NESTED_NAVIGATION_ROUTE_WELCOME) {
WelcomeScreen(
onStartClick = {
if (onboardingMigrationManager.isFeatureIncluded()) {
navController.navigateToMigration()
} else {
navController.navigateToAccountSetup()
}
},
onImportClick = { navController.navigateToSettingsImport() },
appNameProvider = koinInject(),
onboardingMigrationManager = koinInject(),
)
}
composable(route = NESTED_NAVIGATION_ROUTE_MIGRATION) {
onboardingMigrationManager.OnboardingMigrationScreen(
onQrCodeScan = { navController.navigateToSettingsImportQrCode() },
onAddAccount = { navController.navigateToAccountSetup() },
onImport = { navController.navigateToSettingsImport() },
)
}
composable(route = NESTED_NAVIGATION_ROUTE_ACCOUNT_SETUP) {
AccountSetupNavHost(
onBack = { navController.popBackStack() },
onFinish = { route: AccountSetupRoute ->
when (route) {
is AccountSetupRoute.AccountSetup -> {
val createdAccountUuid = route.accountId
accountUuid = createdAccountUuid
if (hasRuntimePermissions()) {
navController.navigateToPermissions()
} else {
onFinish(OnboardingRoute.Onboarding(createdAccountUuid))
}
}
}
},
)
}
composable(route = NESTED_NAVIGATION_ROUTE_SETTINGS_IMPORT) {
SettingsImportScreen(
action = SettingsImportAction.Overview,
onImportSuccess = ::onImportSuccess,
onBack = { navController.popBackStack() },
)
}
composable(route = NESTED_NAVIGATION_ROUTE_SETTINGS_IMPORT_QR_CODE) {
SettingsImportScreen(
action = SettingsImportAction.ScanQrCode,
onImportSuccess = ::onImportSuccess,
onBack = { navController.popBackStack() },
)
}
composable(route = NESTED_NAVIGATION_ROUTE_PERMISSIONS) {
PermissionsScreen(
onNext = { onFinish(OnboardingRoute.Onboarding(accountUuid)) },
)
}
}
}

View file

@ -0,0 +1,5 @@
package app.k9mail.feature.onboarding.main.navigation
import app.k9mail.core.ui.compose.navigation.Navigation
interface OnboardingNavigation : Navigation<OnboardingRoute>

View file

@ -0,0 +1,24 @@
package app.k9mail.feature.onboarding.main.navigation
import app.k9mail.core.ui.compose.navigation.Route
import kotlinx.serialization.Serializable
interface OnboardingRoute : Route {
@Serializable
data class Onboarding(
val accountId: String? = null,
) : OnboardingRoute {
override val basePath: String = BASE_PATH
override fun route(): String = basePath
companion object {
const val BASE_PATH = ONBOARDING_BASE_PATH
}
}
companion object {
const val ONBOARDING_BASE_PATH = "app://onboarding"
}
}