643 lines
25 KiB
Kotlin
643 lines
25 KiB
Kotlin
package co.electriccoin.zcash.ui
|
|
|
|
import androidx.compose.runtime.Composable
|
|
import androidx.compose.runtime.LaunchedEffect
|
|
import androidx.compose.runtime.getValue
|
|
import androidx.compose.runtime.mutableStateOf
|
|
import androidx.compose.runtime.remember
|
|
import androidx.compose.runtime.saveable.rememberSaveable
|
|
import androidx.compose.ui.window.DialogProperties
|
|
import androidx.lifecycle.LifecycleCoroutineScope
|
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
|
import androidx.lifecycle.lifecycleScope
|
|
import androidx.navigation.NavHostController
|
|
import androidx.navigation.NavOptionsBuilder
|
|
import androidx.navigation.NavType
|
|
import androidx.navigation.compose.NavHost
|
|
import androidx.navigation.compose.composable
|
|
import androidx.navigation.compose.dialog
|
|
import androidx.navigation.navArgument
|
|
import androidx.navigation.toRoute
|
|
import cash.z.ecc.android.sdk.Synchronizer
|
|
import co.electriccoin.zcash.spackle.Twig
|
|
import co.electriccoin.zcash.spackle.getSerializableCompat
|
|
import co.electriccoin.zcash.ui.NavigationArgs.ADDRESS_TYPE
|
|
import co.electriccoin.zcash.ui.NavigationTargets.ABOUT
|
|
import co.electriccoin.zcash.ui.NavigationTargets.ADVANCED_SETTINGS
|
|
import co.electriccoin.zcash.ui.NavigationTargets.CHOOSE_SERVER
|
|
import co.electriccoin.zcash.ui.NavigationTargets.DELETE_WALLET
|
|
import co.electriccoin.zcash.ui.NavigationTargets.EXPORT_PRIVATE_DATA
|
|
import co.electriccoin.zcash.ui.NavigationTargets.NOT_ENOUGH_SPACE
|
|
import co.electriccoin.zcash.ui.NavigationTargets.QR_CODE
|
|
import co.electriccoin.zcash.ui.NavigationTargets.REQUEST
|
|
import co.electriccoin.zcash.ui.NavigationTargets.SETTINGS
|
|
import co.electriccoin.zcash.ui.NavigationTargets.SUPPORT
|
|
import co.electriccoin.zcash.ui.NavigationTargets.WHATS_NEW
|
|
import co.electriccoin.zcash.ui.common.compose.LocalNavController
|
|
import co.electriccoin.zcash.ui.common.datasource.MessageAvailabilityDataSource
|
|
import co.electriccoin.zcash.ui.common.provider.ApplicationStateProvider
|
|
import co.electriccoin.zcash.ui.common.provider.isInForeground
|
|
import co.electriccoin.zcash.ui.design.LocalKeyboardManager
|
|
import co.electriccoin.zcash.ui.design.LocalSheetStateManager
|
|
import co.electriccoin.zcash.ui.design.animation.ScreenAnimation.enterTransition
|
|
import co.electriccoin.zcash.ui.design.animation.ScreenAnimation.exitTransition
|
|
import co.electriccoin.zcash.ui.design.animation.ScreenAnimation.popEnterTransition
|
|
import co.electriccoin.zcash.ui.design.animation.ScreenAnimation.popExitTransition
|
|
import co.electriccoin.zcash.ui.screen.about.WrapAbout
|
|
import co.electriccoin.zcash.ui.screen.accountlist.AccountList
|
|
import co.electriccoin.zcash.ui.screen.accountlist.AndroidAccountList
|
|
import co.electriccoin.zcash.ui.screen.addressbook.AddressBookArgs
|
|
import co.electriccoin.zcash.ui.screen.addressbook.WrapAddressBook
|
|
import co.electriccoin.zcash.ui.screen.advancedsettings.WrapAdvancedSettings
|
|
import co.electriccoin.zcash.ui.screen.authentication.AuthenticationUseCase
|
|
import co.electriccoin.zcash.ui.screen.authentication.WrapAuthentication
|
|
import co.electriccoin.zcash.ui.screen.balances.action.AndroidBalanceAction
|
|
import co.electriccoin.zcash.ui.screen.balances.action.BalanceAction
|
|
import co.electriccoin.zcash.ui.screen.chooseserver.WrapChooseServer
|
|
import co.electriccoin.zcash.ui.screen.connectkeystone.AndroidConnectKeystone
|
|
import co.electriccoin.zcash.ui.screen.connectkeystone.ConnectKeystone
|
|
import co.electriccoin.zcash.ui.screen.contact.AddContactArgs
|
|
import co.electriccoin.zcash.ui.screen.contact.UpdateContactArgs
|
|
import co.electriccoin.zcash.ui.screen.contact.WrapAddContact
|
|
import co.electriccoin.zcash.ui.screen.contact.WrapUpdateContact
|
|
import co.electriccoin.zcash.ui.screen.deletewallet.WrapDeleteWallet
|
|
import co.electriccoin.zcash.ui.screen.disconnected.WrapDisconnected
|
|
import co.electriccoin.zcash.ui.screen.error.AndroidErrorBottomSheet
|
|
import co.electriccoin.zcash.ui.screen.error.AndroidErrorDialog
|
|
import co.electriccoin.zcash.ui.screen.error.ErrorBottomSheet
|
|
import co.electriccoin.zcash.ui.screen.error.ErrorDialog
|
|
import co.electriccoin.zcash.ui.screen.exchangerate.optin.AndroidExchangeRateOptIn
|
|
import co.electriccoin.zcash.ui.screen.exchangerate.optin.ExchangeRateOptIn
|
|
import co.electriccoin.zcash.ui.screen.exchangerate.settings.AndroidExchangeRateSettings
|
|
import co.electriccoin.zcash.ui.screen.exchangerate.settings.ExchangeRateSettings
|
|
import co.electriccoin.zcash.ui.screen.exportdata.WrapExportPrivateData
|
|
import co.electriccoin.zcash.ui.screen.feedback.WrapFeedback
|
|
import co.electriccoin.zcash.ui.screen.flexa.FlexaViewModel
|
|
import co.electriccoin.zcash.ui.screen.home.AndroidHome
|
|
import co.electriccoin.zcash.ui.screen.home.backup.AndroidWalletBackupInfo
|
|
import co.electriccoin.zcash.ui.screen.home.disconnected.AndroidWalletDisconnectedInfo
|
|
import co.electriccoin.zcash.ui.screen.home.restoring.AndroidWalletRestoringInfo
|
|
import co.electriccoin.zcash.ui.screen.home.syncing.AndroidWalletSyncingInfo
|
|
import co.electriccoin.zcash.ui.screen.home.updating.AndroidWalletUpdatingInfo
|
|
import co.electriccoin.zcash.ui.screen.home.Home
|
|
import co.electriccoin.zcash.ui.screen.home.backup.SeedBackupInfo
|
|
import co.electriccoin.zcash.ui.screen.home.disconnected.WalletDisconnectedInfo
|
|
import co.electriccoin.zcash.ui.screen.home.restoring.WalletRestoringInfo
|
|
import co.electriccoin.zcash.ui.screen.home.syncing.WalletSyncingInfo
|
|
import co.electriccoin.zcash.ui.screen.home.updating.WalletUpdatingInfo
|
|
import co.electriccoin.zcash.ui.screen.home.shieldfunds.AndroidShieldFundsInfo
|
|
import co.electriccoin.zcash.ui.screen.home.shieldfunds.ShieldFundsInfo
|
|
import co.electriccoin.zcash.ui.screen.integrations.AndroidDialogIntegrations
|
|
import co.electriccoin.zcash.ui.screen.integrations.AndroidIntegrations
|
|
import co.electriccoin.zcash.ui.screen.integrations.DialogIntegrations
|
|
import co.electriccoin.zcash.ui.screen.integrations.Integrations
|
|
import co.electriccoin.zcash.ui.screen.qrcode.WrapQrCode
|
|
import co.electriccoin.zcash.ui.screen.receive.AndroidReceive
|
|
import co.electriccoin.zcash.ui.screen.receive.Receive
|
|
import co.electriccoin.zcash.ui.screen.receive.model.ReceiveAddressType
|
|
import co.electriccoin.zcash.ui.screen.request.WrapRequest
|
|
import co.electriccoin.zcash.ui.screen.restore.info.AndroidSeedInfo
|
|
import co.electriccoin.zcash.ui.screen.restore.info.SeedInfo
|
|
import co.electriccoin.zcash.ui.screen.reviewtransaction.AndroidReviewTransaction
|
|
import co.electriccoin.zcash.ui.screen.reviewtransaction.ReviewTransaction
|
|
import co.electriccoin.zcash.ui.screen.scan.Scan
|
|
import co.electriccoin.zcash.ui.screen.scan.WrapScanValidator
|
|
import co.electriccoin.zcash.ui.screen.scankeystone.ScanKeystonePCZTRequest
|
|
import co.electriccoin.zcash.ui.screen.scankeystone.ScanKeystoneSignInRequest
|
|
import co.electriccoin.zcash.ui.screen.scankeystone.WrapScanKeystonePCZTRequest
|
|
import co.electriccoin.zcash.ui.screen.scankeystone.WrapScanKeystoneSignInRequest
|
|
import co.electriccoin.zcash.ui.screen.walletbackup.AndroidWalletBackup
|
|
import co.electriccoin.zcash.ui.screen.walletbackup.WalletBackup
|
|
import co.electriccoin.zcash.ui.screen.home.backup.AndroidWalletBackupDetail
|
|
import co.electriccoin.zcash.ui.screen.home.backup.WalletBackupDetail
|
|
import co.electriccoin.zcash.ui.screen.selectkeystoneaccount.AndroidSelectKeystoneAccount
|
|
import co.electriccoin.zcash.ui.screen.selectkeystoneaccount.SelectKeystoneAccount
|
|
import co.electriccoin.zcash.ui.screen.send.Send
|
|
import co.electriccoin.zcash.ui.screen.send.WrapSend
|
|
import co.electriccoin.zcash.ui.screen.settings.WrapSettings
|
|
import co.electriccoin.zcash.ui.screen.signkeystonetransaction.AndroidSignKeystoneTransaction
|
|
import co.electriccoin.zcash.ui.screen.signkeystonetransaction.SignKeystoneTransaction
|
|
import co.electriccoin.zcash.ui.screen.taxexport.AndroidTaxExport
|
|
import co.electriccoin.zcash.ui.screen.taxexport.TaxExport
|
|
import co.electriccoin.zcash.ui.screen.transactiondetail.AndroidTransactionDetail
|
|
import co.electriccoin.zcash.ui.screen.transactiondetail.TransactionDetail
|
|
import co.electriccoin.zcash.ui.screen.transactionfilters.AndroidTransactionFiltersList
|
|
import co.electriccoin.zcash.ui.screen.transactionfilters.TransactionFilters
|
|
import co.electriccoin.zcash.ui.screen.transactionhistory.AndroidTransactionHistory
|
|
import co.electriccoin.zcash.ui.screen.transactionhistory.TransactionHistory
|
|
import co.electriccoin.zcash.ui.screen.transactionnote.AndroidTransactionNote
|
|
import co.electriccoin.zcash.ui.screen.transactionnote.TransactionNote
|
|
import co.electriccoin.zcash.ui.screen.transactionprogress.AndroidTransactionProgress
|
|
import co.electriccoin.zcash.ui.screen.transactionprogress.TransactionProgress
|
|
import co.electriccoin.zcash.ui.screen.warning.WrapNotEnoughSpace
|
|
import co.electriccoin.zcash.ui.screen.whatsnew.WrapWhatsNew
|
|
import kotlinx.coroutines.flow.StateFlow
|
|
import kotlinx.coroutines.flow.filterNotNull
|
|
import kotlinx.coroutines.launch
|
|
import org.koin.android.ext.android.inject
|
|
import org.koin.androidx.compose.koinViewModel
|
|
import org.koin.compose.koinInject
|
|
|
|
// TODO [#1297]: Consider: Navigation passing complex data arguments different way
|
|
// TODO [#1297]: https://github.com/Electric-Coin-Company/zashi-android/issues/1297
|
|
@Composable
|
|
@Suppress("LongMethod", "CyclomaticComplexMethod")
|
|
internal fun MainActivity.Navigation() {
|
|
val navController = LocalNavController.current
|
|
val keyboardManager = LocalKeyboardManager.current
|
|
val flexaViewModel = koinViewModel<FlexaViewModel>()
|
|
val navigationRouter = koinInject<NavigationRouter>()
|
|
val sheetStateManager = LocalSheetStateManager.current
|
|
val messageAvailabilityDataSource = koinInject<MessageAvailabilityDataSource>()
|
|
|
|
// Helper properties for triggering the system security UI from callbacks
|
|
val (exportPrivateDataAuthentication, setExportPrivateDataAuthentication) =
|
|
rememberSaveable { mutableStateOf(false) }
|
|
val (deleteWalletAuthentication, setDeleteWalletAuthentication) =
|
|
rememberSaveable { mutableStateOf(false) }
|
|
|
|
val navigator: Navigator =
|
|
remember(
|
|
navController,
|
|
flexaViewModel,
|
|
keyboardManager,
|
|
sheetStateManager,
|
|
messageAvailabilityDataSource
|
|
) {
|
|
NavigatorImpl(
|
|
activity = this@Navigation,
|
|
navController = navController,
|
|
flexaViewModel = flexaViewModel,
|
|
keyboardManager = keyboardManager,
|
|
sheetStateManager = sheetStateManager,
|
|
messageAvailabilityDataSource = messageAvailabilityDataSource
|
|
)
|
|
}
|
|
|
|
LaunchedEffect(Unit) {
|
|
navigationRouter.observePipeline().collect {
|
|
navigator.executeCommand(it)
|
|
}
|
|
}
|
|
|
|
NavHost(
|
|
navController = navController,
|
|
startDestination = Home,
|
|
enterTransition = { enterTransition() },
|
|
exitTransition = { exitTransition() },
|
|
popEnterTransition = { popEnterTransition() },
|
|
popExitTransition = { popExitTransition() }
|
|
) {
|
|
composable<Home> {
|
|
NavigationHome(navController)
|
|
}
|
|
composable(SETTINGS) {
|
|
WrapSettings()
|
|
}
|
|
composable(ADVANCED_SETTINGS) {
|
|
WrapAdvancedSettings(
|
|
goExportPrivateData = {
|
|
navController.checkProtectedDestination(
|
|
scope = lifecycleScope,
|
|
propertyToCheck = authenticationViewModel.isExportPrivateDataAuthenticationRequired,
|
|
setCheckedProperty = setExportPrivateDataAuthentication,
|
|
unProtectedDestination = EXPORT_PRIVATE_DATA
|
|
)
|
|
},
|
|
goDeleteWallet = {
|
|
navController.checkProtectedDestination(
|
|
scope = lifecycleScope,
|
|
propertyToCheck = authenticationViewModel.isDeleteWalletAuthenticationRequired,
|
|
setCheckedProperty = setDeleteWalletAuthentication,
|
|
unProtectedDestination = DELETE_WALLET
|
|
)
|
|
},
|
|
)
|
|
|
|
when {
|
|
deleteWalletAuthentication -> {
|
|
ShowSystemAuthentication(
|
|
navHostController = navController,
|
|
protectedDestination = DELETE_WALLET,
|
|
protectedUseCase = AuthenticationUseCase.DeleteWallet,
|
|
setCheckedProperty = setDeleteWalletAuthentication
|
|
)
|
|
}
|
|
|
|
exportPrivateDataAuthentication -> {
|
|
ShowSystemAuthentication(
|
|
navHostController = navController,
|
|
protectedDestination = EXPORT_PRIVATE_DATA,
|
|
protectedUseCase = AuthenticationUseCase.ExportPrivateData,
|
|
setCheckedProperty = setExportPrivateDataAuthentication
|
|
)
|
|
}
|
|
}
|
|
}
|
|
composable(CHOOSE_SERVER) {
|
|
WrapChooseServer()
|
|
}
|
|
composable<WalletBackup> {
|
|
AndroidWalletBackup(it.toRoute())
|
|
}
|
|
composable(SUPPORT) {
|
|
// Pop back stack won't be right if we deep link into support
|
|
WrapFeedback()
|
|
}
|
|
composable(DELETE_WALLET) {
|
|
WrapDeleteWallet(
|
|
goBack = {
|
|
setDeleteWalletAuthentication(false)
|
|
navController.popBackStackJustOnce(DELETE_WALLET)
|
|
},
|
|
onConfirm = {
|
|
setDeleteWalletAuthentication(false)
|
|
navController.popBackStackJustOnce(DELETE_WALLET)
|
|
}
|
|
)
|
|
}
|
|
composable(ABOUT) {
|
|
WrapAbout(
|
|
goBack = { navController.popBackStackJustOnce(ABOUT) },
|
|
)
|
|
}
|
|
composable(WHATS_NEW) {
|
|
WrapWhatsNew()
|
|
}
|
|
composable<Integrations> {
|
|
AndroidIntegrations()
|
|
}
|
|
dialog<DialogIntegrations> {
|
|
AndroidDialogIntegrations()
|
|
}
|
|
composable<ExchangeRateOptIn> {
|
|
AndroidExchangeRateOptIn()
|
|
}
|
|
composable<ExchangeRateSettings> {
|
|
AndroidExchangeRateSettings()
|
|
}
|
|
composable<ScanKeystoneSignInRequest> {
|
|
WrapScanKeystoneSignInRequest()
|
|
}
|
|
composable<ScanKeystonePCZTRequest> {
|
|
WrapScanKeystonePCZTRequest()
|
|
}
|
|
composable<SignKeystoneTransaction> {
|
|
AndroidSignKeystoneTransaction()
|
|
}
|
|
dialog<AccountList>(
|
|
dialogProperties =
|
|
DialogProperties(
|
|
dismissOnBackPress = false,
|
|
dismissOnClickOutside = false,
|
|
)
|
|
) {
|
|
AndroidAccountList()
|
|
}
|
|
composable<Scan> {
|
|
WrapScanValidator(it.toRoute())
|
|
}
|
|
composable(EXPORT_PRIVATE_DATA) {
|
|
WrapExportPrivateData(
|
|
goBack = {
|
|
setExportPrivateDataAuthentication(false)
|
|
navController.popBackStackJustOnce(EXPORT_PRIVATE_DATA)
|
|
},
|
|
onConfirm = {
|
|
setExportPrivateDataAuthentication(false)
|
|
navController.popBackStackJustOnce(EXPORT_PRIVATE_DATA)
|
|
}
|
|
)
|
|
}
|
|
composable(NOT_ENOUGH_SPACE) {
|
|
WrapNotEnoughSpace(
|
|
goPrevious = { navController.popBackStackJustOnce(NOT_ENOUGH_SPACE) },
|
|
goSettings = { navController.navigateJustOnce(SETTINGS) }
|
|
)
|
|
}
|
|
composable(
|
|
route = AddressBookArgs.ROUTE,
|
|
arguments =
|
|
listOf(
|
|
navArgument(AddressBookArgs.MODE) {
|
|
defaultValue = AddressBookArgs.DEFAULT
|
|
type = NavType.EnumType(AddressBookArgs::class.java)
|
|
}
|
|
)
|
|
) { backStackEntry ->
|
|
val args =
|
|
backStackEntry.arguments
|
|
?.getSerializableCompat<AddressBookArgs>(AddressBookArgs.MODE) ?: AddressBookArgs.DEFAULT
|
|
|
|
WrapAddressBook(args)
|
|
}
|
|
composable(
|
|
route = AddContactArgs.ROUTE,
|
|
arguments =
|
|
listOf(
|
|
navArgument(AddContactArgs.ADDRESS) {
|
|
nullable = true
|
|
defaultValue = null
|
|
type = NavType.StringType
|
|
}
|
|
)
|
|
) { backStackEntry ->
|
|
val address = backStackEntry.arguments?.getString(AddContactArgs.ADDRESS)
|
|
WrapAddContact(address)
|
|
}
|
|
composable(
|
|
route = UpdateContactArgs.ROUTE,
|
|
arguments = listOf(navArgument(UpdateContactArgs.CONTACT_ADDRESS) { type = NavType.StringType })
|
|
) { backStackEntry ->
|
|
val contactAddress = backStackEntry.arguments?.getString(UpdateContactArgs.CONTACT_ADDRESS).orEmpty()
|
|
WrapUpdateContact(contactAddress)
|
|
}
|
|
composable(
|
|
route = "$QR_CODE/{$ADDRESS_TYPE}",
|
|
arguments = listOf(navArgument(ADDRESS_TYPE) { type = NavType.IntType })
|
|
) { backStackEntry ->
|
|
val addressType = backStackEntry.arguments?.getInt(ADDRESS_TYPE) ?: ReceiveAddressType.Unified.ordinal
|
|
WrapQrCode(addressType)
|
|
}
|
|
composable(
|
|
route = "$REQUEST/{$ADDRESS_TYPE}",
|
|
arguments = listOf(navArgument(ADDRESS_TYPE) { type = NavType.IntType })
|
|
) { backStackEntry ->
|
|
val addressType = backStackEntry.arguments?.getInt(ADDRESS_TYPE) ?: ReceiveAddressType.Unified.ordinal
|
|
WrapRequest(addressType)
|
|
}
|
|
composable<ConnectKeystone> {
|
|
AndroidConnectKeystone()
|
|
}
|
|
composable<SelectKeystoneAccount> {
|
|
AndroidSelectKeystoneAccount(it.toRoute())
|
|
}
|
|
composable<ReviewTransaction> {
|
|
AndroidReviewTransaction()
|
|
}
|
|
composable<TransactionProgress> {
|
|
AndroidTransactionProgress(it.toRoute())
|
|
}
|
|
composable<TransactionHistory> {
|
|
AndroidTransactionHistory()
|
|
}
|
|
dialog<TransactionFilters>(
|
|
dialogProperties =
|
|
DialogProperties(
|
|
dismissOnBackPress = false,
|
|
dismissOnClickOutside = false
|
|
)
|
|
) {
|
|
AndroidTransactionFiltersList()
|
|
}
|
|
composable<TransactionDetail> {
|
|
AndroidTransactionDetail(it.toRoute())
|
|
}
|
|
dialog<TransactionNote>(
|
|
dialogProperties =
|
|
DialogProperties(
|
|
dismissOnBackPress = false,
|
|
dismissOnClickOutside = false,
|
|
)
|
|
) {
|
|
AndroidTransactionNote(it.toRoute())
|
|
}
|
|
composable<TaxExport> {
|
|
AndroidTaxExport()
|
|
}
|
|
composable<Receive> {
|
|
AndroidReceive()
|
|
}
|
|
composable<Send> {
|
|
WrapSend(it.toRoute())
|
|
}
|
|
dialog<SeedInfo>(
|
|
dialogProperties =
|
|
DialogProperties(
|
|
dismissOnBackPress = false,
|
|
dismissOnClickOutside = false,
|
|
)
|
|
) {
|
|
AndroidSeedInfo()
|
|
}
|
|
composable<WalletBackupDetail> {
|
|
AndroidWalletBackupDetail(it.toRoute())
|
|
}
|
|
dialog<SeedBackupInfo>(
|
|
dialogProperties =
|
|
DialogProperties(
|
|
dismissOnBackPress = false,
|
|
dismissOnClickOutside = false
|
|
)
|
|
) {
|
|
AndroidWalletBackupInfo()
|
|
}
|
|
dialog<ShieldFundsInfo>(
|
|
dialogProperties =
|
|
DialogProperties(
|
|
dismissOnBackPress = false,
|
|
dismissOnClickOutside = false
|
|
)
|
|
) {
|
|
AndroidShieldFundsInfo()
|
|
}
|
|
dialog<WalletDisconnectedInfo>(
|
|
dialogProperties =
|
|
DialogProperties(
|
|
dismissOnBackPress = false,
|
|
dismissOnClickOutside = false
|
|
)
|
|
) {
|
|
AndroidWalletDisconnectedInfo()
|
|
}
|
|
dialog<WalletRestoringInfo>(
|
|
dialogProperties =
|
|
DialogProperties(
|
|
dismissOnBackPress = false,
|
|
dismissOnClickOutside = false
|
|
)
|
|
) {
|
|
AndroidWalletRestoringInfo()
|
|
}
|
|
dialog<WalletSyncingInfo>(
|
|
dialogProperties =
|
|
DialogProperties(
|
|
dismissOnBackPress = false,
|
|
dismissOnClickOutside = false
|
|
)
|
|
) {
|
|
AndroidWalletSyncingInfo()
|
|
}
|
|
dialog<WalletUpdatingInfo>(
|
|
dialogProperties =
|
|
DialogProperties(
|
|
dismissOnBackPress = false,
|
|
dismissOnClickOutside = false
|
|
)
|
|
) {
|
|
AndroidWalletUpdatingInfo()
|
|
}
|
|
dialog<ErrorDialog>(
|
|
dialogProperties =
|
|
DialogProperties(
|
|
dismissOnBackPress = false,
|
|
dismissOnClickOutside = false
|
|
)
|
|
) {
|
|
AndroidErrorDialog()
|
|
}
|
|
dialog<ErrorBottomSheet>(
|
|
dialogProperties =
|
|
DialogProperties(
|
|
dismissOnBackPress = false,
|
|
dismissOnClickOutside = false
|
|
)
|
|
) {
|
|
AndroidErrorBottomSheet()
|
|
}
|
|
dialog<BalanceAction>(
|
|
dialogProperties =
|
|
DialogProperties(
|
|
dismissOnBackPress = false,
|
|
dismissOnClickOutside = false
|
|
)
|
|
) {
|
|
AndroidBalanceAction()
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This is the Home screens sub-navigation. We could consider creating a separate sub-navigation graph.
|
|
*/
|
|
@Composable
|
|
private fun MainActivity.NavigationHome(navController: NavHostController) {
|
|
val applicationStateProvider: ApplicationStateProvider by inject()
|
|
|
|
AndroidHome()
|
|
|
|
val isEnoughSpace by storageCheckViewModel.isEnoughSpace.collectAsStateWithLifecycle()
|
|
|
|
val sdkStatus =
|
|
walletViewModel.currentWalletSnapshot
|
|
.collectAsStateWithLifecycle()
|
|
.value
|
|
?.status
|
|
|
|
val currentAppState = applicationStateProvider.state.collectAsStateWithLifecycle().value
|
|
|
|
if (isEnoughSpace == false) {
|
|
Twig.info { "Not enough free space" }
|
|
navController.navigateJustOnce(NOT_ENOUGH_SPACE)
|
|
} else if (Synchronizer.Status.DISCONNECTED == sdkStatus) {
|
|
Twig.info { "Disconnected state received from Synchronizer" }
|
|
|
|
if (!currentAppState.isInForeground()) {
|
|
Twig.info { "Disconnected state received but omitted as the app is not in foreground" }
|
|
return
|
|
}
|
|
|
|
WrapDisconnected(
|
|
goChooseServer = {
|
|
navController.navigateJustOnce(CHOOSE_SERVER)
|
|
},
|
|
onIgnore = {
|
|
// Keep the current navigation location
|
|
}
|
|
)
|
|
}
|
|
}
|
|
|
|
@Composable
|
|
private fun MainActivity.ShowSystemAuthentication(
|
|
navHostController: NavHostController,
|
|
protectedDestination: String,
|
|
protectedUseCase: AuthenticationUseCase,
|
|
setCheckedProperty: (Boolean) -> Unit,
|
|
) {
|
|
WrapAuthentication(
|
|
goSupport = {
|
|
setCheckedProperty(false)
|
|
navHostController.navigateJustOnce(SUPPORT)
|
|
},
|
|
onSuccess = {
|
|
navHostController.navigateJustOnce(protectedDestination)
|
|
},
|
|
onCancel = {
|
|
setCheckedProperty(false)
|
|
},
|
|
onFail = {
|
|
// No action needed
|
|
},
|
|
useCase = protectedUseCase
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Check and trigger authentication if required, navigate to the destination otherwise
|
|
*/
|
|
private fun NavHostController.checkProtectedDestination(
|
|
scope: LifecycleCoroutineScope,
|
|
propertyToCheck: StateFlow<Boolean?>,
|
|
setCheckedProperty: (Boolean) -> Unit,
|
|
unProtectedDestination: String
|
|
) {
|
|
scope.launch {
|
|
propertyToCheck
|
|
.filterNotNull()
|
|
.collect { isProtected ->
|
|
if (isProtected) {
|
|
setCheckedProperty(true)
|
|
} else {
|
|
navigateJustOnce(unProtectedDestination)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fun NavHostController.navigateJustOnce(
|
|
route: String,
|
|
navOptionsBuilder: (NavOptionsBuilder.() -> Unit)? = null
|
|
) {
|
|
if (currentDestination?.route == route) {
|
|
return
|
|
}
|
|
|
|
if (navOptionsBuilder != null) {
|
|
navigate(route, navOptionsBuilder)
|
|
} else {
|
|
navigate(route)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Pops up the current screen from the back stack. Parameter currentRouteToBePopped is meant to be
|
|
* set only to the current screen so we can easily debounce multiple screen popping from the back stack.
|
|
*
|
|
* @param currentRouteToBePopped current screen which should be popped up.
|
|
*/
|
|
fun NavHostController.popBackStackJustOnce(currentRouteToBePopped: String) {
|
|
if (currentDestination?.route != currentRouteToBePopped) {
|
|
return
|
|
}
|
|
popBackStack()
|
|
}
|
|
|
|
object NavigationTargets {
|
|
const val ABOUT = "about"
|
|
const val ADVANCED_SETTINGS = "advanced_settings"
|
|
const val DELETE_WALLET = "delete_wallet"
|
|
const val EXPORT_PRIVATE_DATA = "export_private_data"
|
|
const val CHOOSE_SERVER = "choose_server"
|
|
const val NOT_ENOUGH_SPACE = "not_enough_space"
|
|
const val QR_CODE = "qr_code"
|
|
const val REQUEST = "request"
|
|
const val SETTINGS = "settings"
|
|
const val SUPPORT = "support"
|
|
const val WHATS_NEW = "whats_new"
|
|
}
|
|
|
|
object NavigationArgs {
|
|
const val ADDRESS_TYPE = "addressType"
|
|
}
|