Show initial restoring dialog (#1335)

This commit is contained in:
Honza Rychnovský 2024-04-12 15:02:44 +02:00 committed by GitHub
parent cad8e48bf8
commit 47937ffabc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 100 additions and 9 deletions

View File

@ -17,6 +17,7 @@ import kotlinx.coroutines.flow.WhileSubscribed
import kotlinx.coroutines.flow.emitAll
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
class HomeViewModel(application: Application) : AndroidViewModel(application) {
/**
@ -42,6 +43,16 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) {
val isDetailedSyncStatus: StateFlow<Boolean?> =
booleanStateFlow(StandardPreferenceKeys.IS_DETAILED_SYNC_STATUS)
/**
* A flow of whether the app presented the user with an initial restoring dialog
*/
val isRestoringInitialWarningSeen: StateFlow<Boolean?> =
booleanStateFlow(StandardPreferenceKeys.IS_RESTORING_INITIAL_WARNING_SEEN)
fun setRestoringInitialWarningSeen() {
setBooleanPreference(StandardPreferenceKeys.IS_RESTORING_INITIAL_WARNING_SEEN, true)
}
private fun booleanStateFlow(default: BooleanPreferenceDefault): StateFlow<Boolean?> =
flow<Boolean?> {
val preferenceProvider = StandardPreferenceSingleton.getInstance(getApplication())
@ -59,4 +70,14 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) {
SharingStarted.WhileSubscribed(ANDROID_STATE_FLOW_TIMEOUT.inWholeMilliseconds),
null
)
private fun setBooleanPreference(
default: BooleanPreferenceDefault,
newState: Boolean
) {
viewModelScope.launch {
val prefs = StandardPreferenceSingleton.getInstance(getApplication())
default.putValue(prefs, newState)
}
}
}

View File

@ -34,6 +34,9 @@ object StandardPreferenceKeys {
val IS_DETAILED_SYNC_STATUS = BooleanPreferenceDefault(PreferenceKey("is_detailed_sync_status"), false)
val IS_RESTORING_INITIAL_WARNING_SEEN =
BooleanPreferenceDefault(PreferenceKey("IS_RESTORING_INITIAL_WARNING_SEEN"), false)
/**
* The fiat currency that the user prefers.
*/

View File

@ -6,7 +6,12 @@ import androidx.activity.ComponentActivity
import androidx.activity.compose.BackHandler
import androidx.activity.viewModels
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.res.stringResource
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import cash.z.ecc.android.sdk.model.ZecSend
@ -28,6 +33,7 @@ import co.electriccoin.zcash.ui.screen.send.WrapSend
import co.electriccoin.zcash.ui.screen.send.model.SendArguments
import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableSharedFlow
@Composable
@ -48,6 +54,8 @@ internal fun MainActivity.WrapHome(
val isKeepScreenOnWhileSyncing = homeViewModel.isKeepScreenOnWhileSyncing.collectAsStateWithLifecycle().value
val isRestoringInitialWarningSeen = homeViewModel.isRestoringInitialWarningSeen.collectAsStateWithLifecycle().value
// Detailed sync status info is used if set in configuration or if the app is built as debuggable
// (i.e. mainly in development)
val isDetailedSyncStatus =
@ -64,6 +72,24 @@ internal fun MainActivity.WrapHome(
walletViewModel.persistWalletRestoringState(WalletRestoringState.SYNCING)
}
var isShowingRestoreInitDialog by rememberSaveable { mutableStateOf(false) }
val setShowingRestoreInitDialog = {
homeViewModel.setRestoringInitialWarningSeen()
isShowingRestoreInitDialog = false
}
// Show initial restoring warn dialog
isRestoringInitialWarningSeen?.let { restoringWarningSeen ->
if (!restoringWarningSeen && walletRestoringState == WalletRestoringState.RESTORING) {
LaunchedEffect(key1 = isShowingRestoreInitDialog) {
// Adding an extra little delay before displaying the dialog for a better UX
@Suppress("MagicNumber")
delay(1500)
isShowingRestoreInitDialog = true
}
}
}
WrapHome(
this,
goBack = goBack,
@ -74,10 +100,12 @@ internal fun MainActivity.WrapHome(
homeScreenIndex = homeScreenIndex,
isDetailedSyncStatus = isDetailedSyncStatus,
isKeepScreenOnWhileSyncing = isKeepScreenOnWhileSyncing,
isShowingRestoreInitDialog = isShowingRestoreInitDialog,
onPageChange = {
homeViewModel.screenIndex.value = it
},
sendArguments = sendArguments,
setShowingRestoreInitDialog = setShowingRestoreInitDialog,
walletSnapshot = walletSnapshot
)
}
@ -94,8 +122,10 @@ internal fun WrapHome(
homeScreenIndex: HomeScreenIndex,
isDetailedSyncStatus: Boolean,
isKeepScreenOnWhileSyncing: Boolean?,
isShowingRestoreInitDialog: Boolean,
onPageChange: (HomeScreenIndex) -> Unit,
sendArguments: SendArguments,
setShowingRestoreInitDialog: () -> Unit,
walletSnapshot: WalletSnapshot?,
) {
// Flow for propagating the new page index to the pager in the view layer
@ -185,7 +215,9 @@ internal fun WrapHome(
subScreens = tabs,
forcePage = forceIndex,
isKeepScreenOnWhileSyncing = isKeepScreenOnWhileSyncing,
isShowingRestoreInitDialog = isShowingRestoreInitDialog,
onPageChange = onPageChange,
setShowingRestoreInitDialog = setShowingRestoreInitDialog,
walletSnapshot = walletSnapshot
)
}

View File

@ -8,6 +8,7 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.PageSize
import androidx.compose.foundation.pager.PagerDefaults
import androidx.compose.foundation.pager.PagerState
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.material3.Divider
import androidx.compose.material3.DividerDefaults
@ -20,14 +21,17 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.constraintlayout.compose.ConstraintLayout
import androidx.constraintlayout.compose.Dimension
import cash.z.ecc.android.sdk.Synchronizer
import co.electriccoin.zcash.spackle.Twig
import co.electriccoin.zcash.ui.R
import co.electriccoin.zcash.ui.common.compose.DisableScreenTimeout
import co.electriccoin.zcash.ui.common.model.WalletSnapshot
import co.electriccoin.zcash.ui.design.component.AppAlertDialog
import co.electriccoin.zcash.ui.design.component.GradientSurface
import co.electriccoin.zcash.ui.design.component.NavigationTabText
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
@ -46,9 +50,11 @@ private fun ComposablePreview() {
ZcashTheme(forceDarkMode = false) {
GradientSurface {
Home(
isKeepScreenOnWhileSyncing = false,
forcePage = null,
isKeepScreenOnWhileSyncing = false,
isShowingRestoreInitDialog = false,
onPageChange = {},
setShowingRestoreInitDialog = {},
subScreens = persistentListOf(),
walletSnapshot = WalletSnapshotFixture.new(),
)
@ -57,12 +63,14 @@ private fun ComposablePreview() {
}
@OptIn(ExperimentalFoundationApi::class)
@Suppress("LongMethod")
@Suppress("LongParameterList")
@Composable
fun Home(
isKeepScreenOnWhileSyncing: Boolean?,
forcePage: ForcePage?,
isKeepScreenOnWhileSyncing: Boolean?,
isShowingRestoreInitDialog: Boolean,
onPageChange: (HomeScreenIndex) -> Unit,
setShowingRestoreInitDialog: () -> Unit,
subScreens: ImmutableList<TabItem>,
walletSnapshot: WalletSnapshot?,
) {
@ -91,6 +99,29 @@ fun Home(
}
}
HomeContent(
pagerState = pagerState,
subScreens = subScreens,
)
if (isShowingRestoreInitDialog) {
HomeRestoringInitialDialog(setShowingRestoreInitDialog)
}
if (isKeepScreenOnWhileSyncing == true &&
walletSnapshot?.status == Synchronizer.Status.SYNCING
) {
DisableScreenTimeout()
}
}
@Composable
@Suppress("LongMethod")
@OptIn(ExperimentalFoundationApi::class)
fun HomeContent(
pagerState: PagerState,
subScreens: ImmutableList<TabItem>
) {
val coroutineScope = rememberCoroutineScope()
ConstraintLayout {
@ -177,10 +208,14 @@ fun Home(
}
}
}
if (isKeepScreenOnWhileSyncing == true &&
walletSnapshot?.status == Synchronizer.Status.SYNCING
) {
DisableScreenTimeout()
}
}
@Composable
fun HomeRestoringInitialDialog(setShowingRestoreInitDialog: () -> Unit) {
AppAlertDialog(
title = stringResource(id = R.string.restoring_initial_dialog_title),
text = stringResource(id = R.string.restoring_initial_dialog_description),
confirmButtonText = stringResource(id = R.string.restoring_initial_dialog_positive_button),
onConfirmButtonClick = setShowingRestoreInitDialog
)
}