Adds an option to enable/disable background sync, as well as an option to keep the screen on during sync --------- Co-authored-by: Honza <rychnovsky.honza@gmail.com>
This commit is contained in:
parent
e0d3bea3de
commit
edaeda56da
|
@ -0,0 +1,26 @@
|
|||
# Configure keep screen on setting - Because sync can take a long time, the app has a feature to keep the screen on until sync completes. The functionality to keep the screen on will apply to any screen while the app is open and syncing is actively in progress
|
||||
1. Change the systemwide screen timeout in the Android Settings to something short, e.g. 15 seconds
|
||||
1. Install the app
|
||||
1. Launch the app
|
||||
1. Get to the app's settings
|
||||
1. Enable the "keep screen on while syncing" option
|
||||
1. Assuming that sync will take a long time, leave the app open and do not touch the screen for more than the systemwide screen timeout duration
|
||||
1. Verify that the screen does not turn off
|
||||
1. Go to the settings and disable the "Keep screen on while syncing" option
|
||||
1. Keeping the app on the screen, leave the device alone for more than the systemwide screen timeout
|
||||
1. Verify that the screen does turn off
|
||||
1. Wake the device
|
||||
1. Turn the "Keep screen on while syncing" option back on
|
||||
1. Return to the home screen
|
||||
1. Leave the device alone until sync completes (this may take hours)
|
||||
1. Verify when you return that the screen is off (the screen should turn off within the systemwide screen timeout after syncing completes)
|
||||
|
||||
# Disable background syncing
|
||||
1. Install a debug build of the app and connect the device to a system with the Android developer tools installed
|
||||
1. Perform a fresh install of the app
|
||||
1. Go through the onboarding to get to the home screen
|
||||
1. In the developer tools (App Inspection -> Background Task Inspector), verify that a periodic WorkManager job is scheduled or running
|
||||
1. Go into the app's settings and disable the background sync option
|
||||
1. In the developer tools, verify that no periodic WorkManager job is scheduled or running (e.g. it may be cancelled)
|
||||
1. Go into the app's settings and re-enable the background sync option
|
||||
1. In the developer tools, verify that a periodic WorkManager job is scheduled
|
|
@ -45,6 +45,7 @@ class HomeTestSetup(
|
|||
fun getDefaultContent() {
|
||||
Home(
|
||||
walletSnapshot,
|
||||
isKeepScreenOnDuringSync = false,
|
||||
emptyList(),
|
||||
goScan = {
|
||||
onScanCount.incrementAndGet()
|
||||
|
|
|
@ -55,7 +55,7 @@ class SettingsViewTest : UiTestPrerequisites() {
|
|||
fun rescan() = runTest {
|
||||
val testSetup = TestSetup(composeTestRule)
|
||||
|
||||
assertEquals(0, testSetup.getBackupCount())
|
||||
assertEquals(0, testSetup.getRescanCount())
|
||||
|
||||
composeTestRule.onNodeWithText(getStringResource(R.string.settings_rescan)).also {
|
||||
it.performClick()
|
||||
|
@ -64,12 +64,40 @@ class SettingsViewTest : UiTestPrerequisites() {
|
|||
assertEquals(1, testSetup.getRescanCount())
|
||||
}
|
||||
|
||||
@Test
|
||||
@MediumTest
|
||||
fun toggle_background_sync() = runTest {
|
||||
val testSetup = TestSetup(composeTestRule)
|
||||
|
||||
assertEquals(0, testSetup.getBackgroundSyncToggleCount())
|
||||
|
||||
composeTestRule.onNodeWithText(getStringResource(R.string.settings_enable_background_sync)).also {
|
||||
it.performClick()
|
||||
}
|
||||
|
||||
assertEquals(1, testSetup.getBackgroundSyncToggleCount())
|
||||
}
|
||||
|
||||
@Test
|
||||
@MediumTest
|
||||
fun toggle_keep_screen_on() = runTest {
|
||||
val testSetup = TestSetup(composeTestRule)
|
||||
|
||||
assertEquals(0, testSetup.getKeepScreenOnSyncToggleCount())
|
||||
|
||||
composeTestRule.onNodeWithText(getStringResource(R.string.settings_enable_keep_screen_on)).also {
|
||||
it.performClick()
|
||||
}
|
||||
|
||||
assertEquals(1, testSetup.getKeepScreenOnSyncToggleCount())
|
||||
}
|
||||
|
||||
@Test
|
||||
@MediumTest
|
||||
fun toggle_analytics() = runTest {
|
||||
val testSetup = TestSetup(composeTestRule)
|
||||
|
||||
assertEquals(0, testSetup.getBackupCount())
|
||||
assertEquals(0, testSetup.getAnalyticsToggleCount())
|
||||
|
||||
composeTestRule.onNodeWithText(getStringResource(R.string.settings_enable_analytics)).also {
|
||||
it.performClick()
|
||||
|
@ -83,6 +111,8 @@ class SettingsViewTest : UiTestPrerequisites() {
|
|||
private val onBackCount = AtomicInteger(0)
|
||||
private val onBackupCount = AtomicInteger(0)
|
||||
private val onRescanCount = AtomicInteger(0)
|
||||
private val onBackgroundSyncChangedCount = AtomicInteger(0)
|
||||
private val onKeepScreenOnChangedCount = AtomicInteger(0)
|
||||
private val onAnalyticsChangedCount = AtomicInteger(0)
|
||||
|
||||
fun getOnBackCount(): Int {
|
||||
|
@ -100,6 +130,16 @@ class SettingsViewTest : UiTestPrerequisites() {
|
|||
return onRescanCount.get()
|
||||
}
|
||||
|
||||
fun getBackgroundSyncToggleCount(): Int {
|
||||
composeTestRule.waitForIdle()
|
||||
return onBackgroundSyncChangedCount.get()
|
||||
}
|
||||
|
||||
fun getKeepScreenOnSyncToggleCount(): Int {
|
||||
composeTestRule.waitForIdle()
|
||||
return onKeepScreenOnChangedCount.get()
|
||||
}
|
||||
|
||||
fun getAnalyticsToggleCount(): Int {
|
||||
composeTestRule.waitForIdle()
|
||||
return onAnalyticsChangedCount.get()
|
||||
|
@ -109,6 +149,8 @@ class SettingsViewTest : UiTestPrerequisites() {
|
|||
composeTestRule.setContent {
|
||||
ZcashTheme {
|
||||
Settings(
|
||||
isBackgroundSyncEnabled = true,
|
||||
isKeepScreenOnDuringSyncEnabled = true,
|
||||
isAnalyticsEnabled = true,
|
||||
onBack = {
|
||||
onBackCount.incrementAndGet()
|
||||
|
@ -119,6 +161,12 @@ class SettingsViewTest : UiTestPrerequisites() {
|
|||
onRescanWallet = {
|
||||
onRescanCount.incrementAndGet()
|
||||
},
|
||||
onBackgroundSyncSettingsChanged = {
|
||||
onBackgroundSyncChangedCount.incrementAndGet()
|
||||
},
|
||||
onIsKeepScreenOnDuringSyncSettingsChanged = {
|
||||
onKeepScreenOnChangedCount.incrementAndGet()
|
||||
},
|
||||
onAnalyticsSettingsChanged = {
|
||||
onAnalyticsChangedCount.incrementAndGet()
|
||||
}
|
||||
|
|
|
@ -12,7 +12,10 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.navigation.NavHostController
|
||||
import co.electriccoin.zcash.ui.common.BindCompLocalProvider
|
||||
import co.electriccoin.zcash.ui.design.component.ConfigurationOverride
|
||||
|
@ -20,12 +23,18 @@ import co.electriccoin.zcash.ui.design.component.GradientSurface
|
|||
import co.electriccoin.zcash.ui.design.component.Override
|
||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||
import co.electriccoin.zcash.ui.screen.backup.WrapBackup
|
||||
import co.electriccoin.zcash.ui.screen.home.viewmodel.HomeViewModel
|
||||
import co.electriccoin.zcash.ui.screen.home.viewmodel.SecretState
|
||||
import co.electriccoin.zcash.ui.screen.home.viewmodel.WalletViewModel
|
||||
import co.electriccoin.zcash.ui.screen.onboarding.WrapOnboarding
|
||||
import co.electriccoin.zcash.ui.screen.warning.WrapNotEnoughSpace
|
||||
import co.electriccoin.zcash.ui.screen.warning.viewmodel.StorageCheckViewModel
|
||||
import co.electriccoin.zcash.work.WorkIds
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.filterNotNull
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlin.time.Duration
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
@ -47,6 +56,8 @@ class MainActivity : ComponentActivity() {
|
|||
setupSplashScreen()
|
||||
|
||||
setupUiContent()
|
||||
|
||||
monitorForBackgroundSync()
|
||||
}
|
||||
|
||||
private fun setupSplashScreen() {
|
||||
|
@ -116,6 +127,30 @@ class MainActivity : ComponentActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun monitorForBackgroundSync() {
|
||||
val isEnableBackgroundSyncFlow = run {
|
||||
val homeViewModel by viewModels<HomeViewModel>()
|
||||
val isSecretReadyFlow = walletViewModel.secretState.map { it is SecretState.Ready }
|
||||
val isBackgroundSyncEnabledFlow = homeViewModel.isBackgroundSyncEnabled.filterNotNull()
|
||||
|
||||
isSecretReadyFlow.combine(isBackgroundSyncEnabledFlow) { isSecretReady, isBackgroundSyncEnabled ->
|
||||
isSecretReady && isBackgroundSyncEnabled
|
||||
}
|
||||
}
|
||||
|
||||
lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||
isEnableBackgroundSyncFlow.collect { isEnableBackgroundSync ->
|
||||
if (isEnableBackgroundSync) {
|
||||
WorkIds.enableBackgroundSynchronization(application)
|
||||
} else {
|
||||
WorkIds.disableBackgroundSynchronization(application)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@VisibleForTesting
|
||||
internal val SPLASH_SCREEN_DELAY = 0.seconds
|
||||
|
|
|
@ -13,6 +13,10 @@ object StandardPreferenceKeys {
|
|||
// Default to true until https://github.com/zcash/secant-android-wallet/issues/304
|
||||
val IS_ANALYTICS_ENABLED = BooleanPreferenceDefault(Key("is_analytics_enabled"), true)
|
||||
|
||||
val IS_BACKGROUND_SYNC_ENABLED = BooleanPreferenceDefault(Key("is_background_sync_enabled"), true)
|
||||
|
||||
val IS_KEEP_SCREEN_ON_DURING_SYNC = BooleanPreferenceDefault(Key("is_keep_screen_on_during_sync"), true)
|
||||
|
||||
/**
|
||||
* The fiat currency that the user prefers.
|
||||
*/
|
||||
|
|
|
@ -14,6 +14,7 @@ import co.electriccoin.zcash.ui.MainActivity
|
|||
import co.electriccoin.zcash.ui.screen.home.view.Home
|
||||
import co.electriccoin.zcash.ui.screen.home.viewmodel.CheckUpdateViewModel
|
||||
import co.electriccoin.zcash.ui.screen.home.viewmodel.WalletViewModel
|
||||
import co.electriccoin.zcash.ui.screen.settings.viewmodel.SettingsViewModel
|
||||
import co.electriccoin.zcash.ui.screen.update.AppUpdateCheckerImp
|
||||
import co.electriccoin.zcash.ui.screen.update.model.UpdateState
|
||||
|
||||
|
@ -53,9 +54,12 @@ internal fun WrapHome(
|
|||
}
|
||||
|
||||
val walletViewModel by activity.viewModels<WalletViewModel>()
|
||||
|
||||
val walletSnapshot = walletViewModel.walletSnapshot.collectAsStateWithLifecycle().value
|
||||
|
||||
val settingsViewModel by activity.viewModels<SettingsViewModel>()
|
||||
|
||||
val isKeepScreenOnWhileSyncing = settingsViewModel.isKeepScreenOnWhileSyncing.collectAsStateWithLifecycle().value
|
||||
|
||||
if (null == walletSnapshot) {
|
||||
// Display loading indicator
|
||||
} else {
|
||||
|
@ -71,6 +75,7 @@ internal fun WrapHome(
|
|||
|
||||
Home(
|
||||
walletSnapshot,
|
||||
isKeepScreenOnDuringSync = isKeepScreenOnWhileSyncing,
|
||||
transactionSnapshot,
|
||||
goScan = goScan,
|
||||
goRequest = goRequest,
|
||||
|
|
|
@ -42,10 +42,12 @@ 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 cash.z.ecc.android.sdk.Synchronizer
|
||||
import cash.z.ecc.android.sdk.model.FiatCurrencyConversionRateState
|
||||
import cash.z.ecc.android.sdk.model.PercentDecimal
|
||||
import co.electriccoin.zcash.crash.android.GlobalCrashReporter
|
||||
import co.electriccoin.zcash.ui.R
|
||||
import co.electriccoin.zcash.ui.common.DisableScreenTimeout
|
||||
import co.electriccoin.zcash.ui.design.MINIMAL_WEIGHT
|
||||
import co.electriccoin.zcash.ui.design.component.Body
|
||||
import co.electriccoin.zcash.ui.design.component.BodyWithFiatCurrencySymbol
|
||||
|
@ -67,6 +69,7 @@ fun ComposablePreview() {
|
|||
GradientSurface {
|
||||
Home(
|
||||
WalletSnapshotFixture.new(),
|
||||
isKeepScreenOnDuringSync = false,
|
||||
emptyList(),
|
||||
goScan = {},
|
||||
goProfile = {},
|
||||
|
@ -85,6 +88,7 @@ fun ComposablePreview() {
|
|||
@Composable
|
||||
fun Home(
|
||||
walletSnapshot: WalletSnapshot,
|
||||
isKeepScreenOnDuringSync: Boolean?,
|
||||
transactionHistory: List<CommonTransaction>,
|
||||
goScan: () -> Unit,
|
||||
goProfile: () -> Unit,
|
||||
|
@ -100,6 +104,7 @@ fun Home(
|
|||
HomeMainContent(
|
||||
paddingValues,
|
||||
walletSnapshot,
|
||||
isKeepScreenOnDuringSync = isKeepScreenOnDuringSync,
|
||||
transactionHistory,
|
||||
goScan = goScan,
|
||||
goProfile = goProfile,
|
||||
|
@ -171,6 +176,7 @@ private fun DebugMenu(
|
|||
private fun HomeMainContent(
|
||||
paddingValues: PaddingValues,
|
||||
walletSnapshot: WalletSnapshot,
|
||||
isKeepScreenOnDuringSync: Boolean?,
|
||||
transactionHistory: List<CommonTransaction>,
|
||||
goScan: () -> Unit,
|
||||
goProfile: () -> Unit,
|
||||
|
@ -212,7 +218,18 @@ private fun HomeMainContent(
|
|||
TertiaryButton(onClick = goRequest, text = stringResource(R.string.home_button_request))
|
||||
|
||||
History(transactionHistory)
|
||||
|
||||
if (isKeepScreenOnDuringSync == true && isSyncing(walletSnapshot.status)) {
|
||||
DisableScreenTimeout()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun isSyncing(status: Synchronizer.Status): Boolean {
|
||||
return status == Synchronizer.Status.DOWNLOADING ||
|
||||
status == Synchronizer.Status.VALIDATING ||
|
||||
status == Synchronizer.Status.SCANNING ||
|
||||
status == Synchronizer.Status.ENHANCING
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
package co.electriccoin.zcash.ui.screen.home.viewmodel
|
||||
|
||||
import android.app.Application
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import co.electriccoin.zcash.ui.common.ANDROID_STATE_FLOW_TIMEOUT
|
||||
import co.electriccoin.zcash.ui.preference.StandardPreferenceKeys
|
||||
import co.electriccoin.zcash.ui.preference.StandardPreferenceSingleton
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.emitAll
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
|
||||
class HomeViewModel(application: Application) : AndroidViewModel(application) {
|
||||
|
||||
/**
|
||||
* A flow of whether background sync is enabled
|
||||
*/
|
||||
val isBackgroundSyncEnabled: StateFlow<Boolean?> = flow {
|
||||
val preferenceProvider = StandardPreferenceSingleton.getInstance(application)
|
||||
emitAll(StandardPreferenceKeys.IS_BACKGROUND_SYNC_ENABLED.observe(preferenceProvider))
|
||||
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(ANDROID_STATE_FLOW_TIMEOUT.inWholeMilliseconds), null)
|
||||
}
|
|
@ -32,7 +32,6 @@ import co.electriccoin.zcash.ui.preference.StandardPreferenceKeys
|
|||
import co.electriccoin.zcash.ui.preference.StandardPreferenceSingleton
|
||||
import co.electriccoin.zcash.ui.screen.home.model.CommonTransaction
|
||||
import co.electriccoin.zcash.ui.screen.home.model.WalletSnapshot
|
||||
import co.electriccoin.zcash.work.WorkIds
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.channels.awaitClose
|
||||
|
@ -151,7 +150,7 @@ class WalletViewModel(application: Application) : AndroidViewModel(application)
|
|||
)
|
||||
|
||||
// This is not the right API, because the transaction list could be very long and might need UI filtering
|
||||
@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
val transactionSnapshot: StateFlow<List<CommonTransaction>> = synchronizer
|
||||
.flatMapLatest {
|
||||
if (null == it) {
|
||||
|
@ -205,8 +204,6 @@ class WalletViewModel(application: Application) : AndroidViewModel(application)
|
|||
persistWalletMutex.withLock {
|
||||
EncryptedPreferenceKeys.PERSISTABLE_WALLET.putValue(preferenceProvider, persistableWallet)
|
||||
}
|
||||
|
||||
WorkIds.enableBackgroundSynchronization(application)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -33,18 +33,29 @@ private fun WrapSettings(
|
|||
val settingsViewModel by activity.viewModels<SettingsViewModel>()
|
||||
|
||||
val synchronizer = walletViewModel.synchronizer.collectAsStateWithLifecycle().value
|
||||
val isBackgroundSyncEnabled = settingsViewModel.isBackgroundSync.collectAsStateWithLifecycle().value
|
||||
val isKeepScreenOnWhileSyncing = settingsViewModel.isKeepScreenOnWhileSyncing.collectAsStateWithLifecycle().value
|
||||
val isAnalyticsEnabled = settingsViewModel.isAnalyticsEnabled.collectAsStateWithLifecycle().value
|
||||
|
||||
if (null == synchronizer || null == isAnalyticsEnabled) {
|
||||
@Suppress("ComplexCondition")
|
||||
if (null == synchronizer || null == isAnalyticsEnabled || null == isBackgroundSyncEnabled || null == isKeepScreenOnWhileSyncing) {
|
||||
// Display loading indicator
|
||||
} else {
|
||||
Settings(
|
||||
isAnalyticsEnabled,
|
||||
isBackgroundSyncEnabled = isBackgroundSyncEnabled,
|
||||
isKeepScreenOnDuringSyncEnabled = isKeepScreenOnWhileSyncing,
|
||||
isAnalyticsEnabled = isAnalyticsEnabled,
|
||||
onBack = goBack,
|
||||
onBackupWallet = goWalletBackup,
|
||||
onRescanWallet = {
|
||||
walletViewModel.rescanBlockchain()
|
||||
},
|
||||
onBackgroundSyncSettingsChanged = {
|
||||
settingsViewModel.setBackgroundSyncEnabled(it)
|
||||
},
|
||||
onIsKeepScreenOnDuringSyncSettingsChanged = {
|
||||
settingsViewModel.setKeepScreenOnWhileSyncing(it)
|
||||
},
|
||||
onAnalyticsSettingsChanged = {
|
||||
settingsViewModel.setAnalyticsEnabled(it)
|
||||
}
|
||||
|
|
|
@ -39,10 +39,14 @@ fun PreviewSettings() {
|
|||
ZcashTheme(darkTheme = true) {
|
||||
GradientSurface {
|
||||
Settings(
|
||||
isBackgroundSyncEnabled = true,
|
||||
isKeepScreenOnDuringSyncEnabled = true,
|
||||
isAnalyticsEnabled = true,
|
||||
onBack = {},
|
||||
onBackupWallet = {},
|
||||
onRescanWallet = {},
|
||||
onBackgroundSyncSettingsChanged = {},
|
||||
onIsKeepScreenOnDuringSyncSettingsChanged = {},
|
||||
onAnalyticsSettingsChanged = {}
|
||||
)
|
||||
}
|
||||
|
@ -53,10 +57,14 @@ fun PreviewSettings() {
|
|||
@Composable
|
||||
@Suppress("LongParameterList")
|
||||
fun Settings(
|
||||
isBackgroundSyncEnabled: Boolean,
|
||||
isKeepScreenOnDuringSyncEnabled: Boolean,
|
||||
isAnalyticsEnabled: Boolean,
|
||||
onBack: () -> Unit,
|
||||
onBackupWallet: () -> Unit,
|
||||
onRescanWallet: () -> Unit,
|
||||
onBackgroundSyncSettingsChanged: (Boolean) -> Unit,
|
||||
onIsKeepScreenOnDuringSyncSettingsChanged: (Boolean) -> Unit,
|
||||
onAnalyticsSettingsChanged: (Boolean) -> Unit
|
||||
) {
|
||||
Scaffold(topBar = {
|
||||
|
@ -64,9 +72,13 @@ fun Settings(
|
|||
}) { paddingValues ->
|
||||
SettingsMainContent(
|
||||
paddingValues,
|
||||
isAnalyticsEnabled,
|
||||
isBackgroundSyncEnabled = isBackgroundSyncEnabled,
|
||||
isKeepScreenOnDuringSyncEnabled = isKeepScreenOnDuringSyncEnabled,
|
||||
isAnalyticsEnabled = isAnalyticsEnabled,
|
||||
onBackupWallet = onBackupWallet,
|
||||
onRescanWallet = onRescanWallet,
|
||||
onBackgroundSyncSettingsChanged = onBackgroundSyncSettingsChanged,
|
||||
onIsKeepScreenOnDuringSyncSettingsChanged = onIsKeepScreenOnDuringSyncSettingsChanged,
|
||||
onAnalyticsSettingsChanged = onAnalyticsSettingsChanged
|
||||
)
|
||||
}
|
||||
|
@ -94,9 +106,13 @@ private fun SettingsTopAppBar(onBack: () -> Unit) {
|
|||
@Suppress("LongParameterList")
|
||||
private fun SettingsMainContent(
|
||||
paddingValues: PaddingValues,
|
||||
isBackgroundSyncEnabled: Boolean,
|
||||
isKeepScreenOnDuringSyncEnabled: Boolean,
|
||||
isAnalyticsEnabled: Boolean,
|
||||
onBackupWallet: () -> Unit,
|
||||
onRescanWallet: () -> Unit,
|
||||
onBackgroundSyncSettingsChanged: (Boolean) -> Unit,
|
||||
onIsKeepScreenOnDuringSyncSettingsChanged: (Boolean) -> Unit,
|
||||
onAnalyticsSettingsChanged: (Boolean) -> Unit
|
||||
) {
|
||||
Column(
|
||||
|
@ -104,9 +120,17 @@ private fun SettingsMainContent(
|
|||
.padding(top = paddingValues.calculateTopPadding())
|
||||
) {
|
||||
PrimaryButton(onClick = onBackupWallet, text = stringResource(id = R.string.settings_backup))
|
||||
// We have decided to not include this in settings; see overflow debug menu instead
|
||||
// DangerousButton(onClick = onWipeWallet, text = stringResource(id = R.string.settings_wipe))
|
||||
TertiaryButton(onClick = onRescanWallet, text = stringResource(id = R.string.settings_rescan))
|
||||
SwitchWithLabel(
|
||||
label = stringResource(id = R.string.settings_enable_background_sync),
|
||||
state = isBackgroundSyncEnabled,
|
||||
onStateChange = { onBackgroundSyncSettingsChanged(!isBackgroundSyncEnabled) }
|
||||
)
|
||||
SwitchWithLabel(
|
||||
label = stringResource(id = R.string.settings_enable_keep_screen_on),
|
||||
state = isKeepScreenOnDuringSyncEnabled,
|
||||
onStateChange = { onIsKeepScreenOnDuringSyncSettingsChanged(!isKeepScreenOnDuringSyncEnabled) }
|
||||
)
|
||||
SwitchWithLabel(
|
||||
label = stringResource(id = R.string.settings_enable_analytics),
|
||||
state = isAnalyticsEnabled,
|
||||
|
|
|
@ -3,6 +3,7 @@ package co.electriccoin.zcash.ui.screen.settings.viewmodel
|
|||
import android.app.Application
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import co.electriccoin.zcash.preference.model.entry.BooleanPreferenceDefault
|
||||
import co.electriccoin.zcash.ui.common.ANDROID_STATE_FLOW_TIMEOUT
|
||||
import co.electriccoin.zcash.ui.preference.StandardPreferenceKeys
|
||||
import co.electriccoin.zcash.ui.preference.StandardPreferenceSingleton
|
||||
|
@ -19,17 +20,34 @@ import kotlinx.coroutines.sync.withLock
|
|||
class SettingsViewModel(application: Application) : AndroidViewModel(application) {
|
||||
private val mutex = Mutex()
|
||||
|
||||
val isAnalyticsEnabled: StateFlow<Boolean?> = flow<Boolean?> {
|
||||
val preferenceProvider = StandardPreferenceSingleton.getInstance(application)
|
||||
emitAll(StandardPreferenceKeys.IS_ANALYTICS_ENABLED.observe(preferenceProvider))
|
||||
val isAnalyticsEnabled: StateFlow<Boolean?> = booleanStateFlow(StandardPreferenceKeys.IS_ANALYTICS_ENABLED)
|
||||
|
||||
val isBackgroundSync: StateFlow<Boolean?> = booleanStateFlow(StandardPreferenceKeys.IS_BACKGROUND_SYNC_ENABLED)
|
||||
|
||||
val isKeepScreenOnWhileSyncing: StateFlow<Boolean?> = booleanStateFlow(StandardPreferenceKeys.IS_KEEP_SCREEN_ON_DURING_SYNC)
|
||||
|
||||
private fun booleanStateFlow(default: BooleanPreferenceDefault): StateFlow<Boolean?> = flow<Boolean?> {
|
||||
val preferenceProvider = StandardPreferenceSingleton.getInstance(getApplication())
|
||||
emitAll(default.observe(preferenceProvider))
|
||||
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(ANDROID_STATE_FLOW_TIMEOUT), null)
|
||||
|
||||
fun setAnalyticsEnabled(enabled: Boolean) {
|
||||
setBooleanPreference(StandardPreferenceKeys.IS_ANALYTICS_ENABLED, enabled)
|
||||
}
|
||||
|
||||
fun setBackgroundSyncEnabled(enabled: Boolean) {
|
||||
setBooleanPreference(StandardPreferenceKeys.IS_BACKGROUND_SYNC_ENABLED, enabled)
|
||||
}
|
||||
|
||||
fun setKeepScreenOnWhileSyncing(enabled: Boolean) {
|
||||
setBooleanPreference(StandardPreferenceKeys.IS_KEEP_SCREEN_ON_DURING_SYNC, enabled)
|
||||
}
|
||||
|
||||
private fun setBooleanPreference(default: BooleanPreferenceDefault, newState: Boolean) {
|
||||
viewModelScope.launch {
|
||||
val prefs = StandardPreferenceSingleton.getInstance(getApplication())
|
||||
mutex.withLock {
|
||||
// Note that the Application object observes this and performs the actual side effects
|
||||
StandardPreferenceKeys.IS_ANALYTICS_ENABLED.putValue(prefs, enabled)
|
||||
default.putValue(prefs, newState)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,13 +7,6 @@ import androidx.work.WorkManager
|
|||
object WorkIds {
|
||||
const val WORK_ID_BACKGROUND_SYNC = "co.electriccoin.zcash.background_sync"
|
||||
|
||||
/*
|
||||
* For now, sync is always enabled. In the future, we can consider whether a preference
|
||||
* is a good idea.
|
||||
*
|
||||
* Also note that if we ever change the sync interval period, this code won't re-run on
|
||||
* existing installations unless we make changes to call this during app startup.
|
||||
*/
|
||||
fun enableBackgroundSynchronization(context: Context) {
|
||||
val workManager = WorkManager.getInstance(context)
|
||||
|
||||
|
@ -23,4 +16,10 @@ object WorkIds {
|
|||
SyncWorker.newWorkRequest()
|
||||
)
|
||||
}
|
||||
|
||||
fun disableBackgroundSynchronization(context: Context) {
|
||||
val workManager = WorkManager.getInstance(context)
|
||||
|
||||
workManager.cancelUniqueWork(WORK_ID_BACKGROUND_SYNC)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
<string name="settings_wipe">Wipe Wallet Data</string>
|
||||
|
||||
<string name="settings_rescan">Rescan Blockchain</string>
|
||||
<string name="settings_enable_background_sync">Background sync</string>
|
||||
<string name="settings_enable_keep_screen_on">Keep screen on during sync</string>
|
||||
<string name="settings_enable_analytics">Report crashes</string>
|
||||
|
||||
</resources>
|
||||
|
|
Loading…
Reference in New Issue