Settings redesign (#1576)
* Settings redesign Closes #1146 * Tests hotfix * Changelogs update * Code cleanup * Add small padding above logo in Settings --------- Co-authored-by: Honza <rychnovsky.honza@gmail.com>
This commit is contained in:
parent
b75836f941
commit
fa9ea0c03a
|
@ -13,6 +13,7 @@ and this application adheres to [Semantic Versioning](https://semver.org/spec/v2
|
|||
|
||||
### Changed
|
||||
- Choose server screen has been redesigned
|
||||
- Settings and Advanced Settings screens have been redesigned
|
||||
|
||||
## [1.1.7 (718)] - 2024-09-06
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ directly impact users rather than highlighting other key architectural updates.*
|
|||
|
||||
### Changed
|
||||
- Choose server screen has been redesigned
|
||||
- Settings and Advanced Settings screens have been redesigned
|
||||
|
||||
## [1.1.7 (718)] - 2024-09-06
|
||||
|
||||
|
|
|
@ -33,9 +33,12 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.rememberVectorPainter
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
|
@ -351,7 +354,7 @@ private fun TopBarOneVisibleActionMenuExample(
|
|||
@Composable
|
||||
fun TopAppBarBackNavigation(
|
||||
backContentDescriptionText: String? = null,
|
||||
backIconVector: ImageVector = Icons.AutoMirrored.Filled.ArrowBack,
|
||||
painter: Painter = rememberVectorPainter(Icons.AutoMirrored.Filled.ArrowBack),
|
||||
backText: String? = null,
|
||||
onBack: () -> Unit
|
||||
) {
|
||||
|
@ -365,7 +368,7 @@ fun TopAppBarBackNavigation(
|
|||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Icon(
|
||||
imageVector = backIconVector,
|
||||
painter = painter,
|
||||
contentDescription = backContentDescriptionText,
|
||||
)
|
||||
|
||||
|
@ -440,6 +443,7 @@ fun SmallTopAppBar(
|
|||
subTitle: String? = null,
|
||||
showTitleLogo: Boolean = false,
|
||||
titleText: String? = null,
|
||||
titleStyle: TextStyle = SecondaryTypography.headlineSmall,
|
||||
) {
|
||||
CenterAlignedTopAppBar(
|
||||
title = {
|
||||
|
@ -451,7 +455,7 @@ fun SmallTopAppBar(
|
|||
if (titleText != null) {
|
||||
Text(
|
||||
text = titleText.uppercase(),
|
||||
style = SecondaryTypography.headlineSmall,
|
||||
style = titleStyle,
|
||||
color = colors.titleColor,
|
||||
)
|
||||
restoringSpacerHeight = ZcashTheme.dimens.spacingTiny
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
package co.electriccoin.zcash.ui.design.component
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.semantics.Role
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import co.electriccoin.zcash.ui.design.R
|
||||
import co.electriccoin.zcash.ui.design.newcomponent.PreviewScreens
|
||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||
import co.electriccoin.zcash.ui.design.util.orDark
|
||||
|
||||
@Composable
|
||||
fun ZashiSettingsListItem(
|
||||
text: String,
|
||||
@DrawableRes icon: Int,
|
||||
trailing: @Composable () -> Unit = {
|
||||
Image(
|
||||
painter = painterResource(R.drawable.ic_chevron_right orDark R.drawable.ic_chevron_right_dark),
|
||||
contentDescription = text,
|
||||
)
|
||||
},
|
||||
onClick: () -> Unit
|
||||
) {
|
||||
ZashiSettingsListItem(
|
||||
leading = {
|
||||
Image(
|
||||
modifier = Modifier.size(40.dp),
|
||||
painter = painterResource(icon),
|
||||
contentDescription = text
|
||||
)
|
||||
},
|
||||
content = {
|
||||
Text(
|
||||
text = text,
|
||||
style = ZcashTheme.typography.primary.titleSmall.copy(fontWeight = FontWeight.SemiBold),
|
||||
fontSize = 16.sp
|
||||
)
|
||||
},
|
||||
trailing = trailing,
|
||||
onClick = onClick
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ZashiSettingsListItem(
|
||||
leading: @Composable () -> Unit,
|
||||
content: @Composable () -> Unit,
|
||||
trailing: @Composable () -> Unit,
|
||||
onClick: () -> Unit
|
||||
) {
|
||||
Row(
|
||||
modifier =
|
||||
Modifier
|
||||
.clip(RoundedCornerShape(12.dp))
|
||||
.clickable(
|
||||
indication = rememberRipple(),
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
onClick = onClick,
|
||||
role = Role.Button,
|
||||
)
|
||||
.padding(vertical = 12.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Spacer(modifier = Modifier.width(20.dp))
|
||||
leading()
|
||||
Spacer(modifier = Modifier.width(16.dp))
|
||||
content()
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
trailing()
|
||||
Spacer(modifier = Modifier.width(20.dp))
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UnusedPrivateMember")
|
||||
@PreviewScreens
|
||||
@Composable
|
||||
private fun ZashiSettingsListItemPreview() =
|
||||
ZcashTheme {
|
||||
BlankSurface {
|
||||
ZashiSettingsListItem(
|
||||
text = "Test",
|
||||
icon = R.drawable.ic_radio_button_checked,
|
||||
onClick = {}
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package co.electriccoin.zcash.ui.design.component
|
||||
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||
import co.electriccoin.zcash.ui.design.theme.internal.SecondaryTypography
|
||||
import co.electriccoin.zcash.ui.design.theme.internal.TopAppBarColors
|
||||
|
||||
@Composable
|
||||
@Suppress("LongParameterList")
|
||||
fun ZashiSmallTopAppBar(
|
||||
title: String,
|
||||
subtitle: String?,
|
||||
modifier: Modifier = Modifier,
|
||||
showTitleLogo: Boolean = false,
|
||||
colors: TopAppBarColors = ZcashTheme.colors.topAppBarColors,
|
||||
navigationAction: @Composable () -> Unit = {},
|
||||
hamburgerMenuActions: (@Composable RowScope.() -> Unit)? = null,
|
||||
regularActions: (@Composable RowScope.() -> Unit)? = null,
|
||||
) {
|
||||
SmallTopAppBar(
|
||||
modifier = modifier,
|
||||
colors = colors,
|
||||
hamburgerMenuActions = hamburgerMenuActions,
|
||||
navigationAction = navigationAction,
|
||||
regularActions = regularActions,
|
||||
subTitle = subtitle,
|
||||
showTitleLogo = showTitleLogo,
|
||||
titleText = title,
|
||||
titleStyle = SecondaryTypography.headlineSmall.copy(fontWeight = FontWeight.SemiBold)
|
||||
)
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package co.electriccoin.zcash.ui.design.component
|
||||
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import co.electriccoin.zcash.ui.design.R
|
||||
import co.electriccoin.zcash.ui.design.util.orDark
|
||||
|
||||
@Composable
|
||||
fun ZashiTopAppBarBackNavigation(
|
||||
backContentDescriptionText: String = stringResource(R.string.back_navigation_content_description),
|
||||
painter: Painter =
|
||||
painterResource(
|
||||
R.drawable.ic_zashi_navigation_back orDark R.drawable.ic_zashi_navigation_back_dark
|
||||
),
|
||||
onBack: () -> Unit
|
||||
) {
|
||||
Row {
|
||||
Spacer(modifier = Modifier.width(16.dp))
|
||||
IconButton(onClick = onBack) {
|
||||
Icon(
|
||||
painter = painter,
|
||||
contentDescription = backContentDescriptionText,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,8 +2,12 @@ package co.electriccoin.zcash.ui.design.newcomponent
|
|||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import kotlin.annotation.AnnotationRetention.SOURCE
|
||||
|
||||
// TODO [#1580]: Suppress compilation warning on PreviewScreens
|
||||
// https://github.com/Electric-Coin-Company/zashi-android/issues/1580
|
||||
@Suppress("UnusedPrivateMember")
|
||||
@Preview(name = "1: Light preview", showBackground = true)
|
||||
@Preview(name = "2: Dark preview", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Retention(SOURCE)
|
||||
annotation class PreviewScreens
|
||||
|
|
|
@ -36,6 +36,9 @@ data class ZashiColors(
|
|||
val utilitySuccess700: Color,
|
||||
val utilitySuccess200: Color,
|
||||
val utilitySuccess50: Color,
|
||||
val btnDestroyFg: Color,
|
||||
val btnDestroyBg: Color,
|
||||
val btnDestroyBorder: Color,
|
||||
)
|
||||
|
||||
internal val LightZashiColorPalette =
|
||||
|
@ -63,6 +66,9 @@ internal val LightZashiColorPalette =
|
|||
utilitySuccess700 = Color(0xFF098605),
|
||||
utilitySuccess200 = Color(0xFFA3FF95),
|
||||
utilitySuccess50 = Color(0xFFEAFFE5),
|
||||
btnDestroyFg = Color(0xFFD92D20),
|
||||
btnDestroyBg = Color(0xFFFFFFFF),
|
||||
btnDestroyBorder = Color(0xFFFDA29B)
|
||||
)
|
||||
|
||||
internal val DarkZashiColorPalette =
|
||||
|
@ -90,6 +96,9 @@ internal val DarkZashiColorPalette =
|
|||
utilitySuccess700 = Color(0xFF098605),
|
||||
utilitySuccess200 = Color(0xFFA3FF95),
|
||||
utilitySuccess50 = Color(0xFFEAFFE5),
|
||||
btnDestroyFg = Color(0xFFFEE4E2),
|
||||
btnDestroyBg = Color(0xFF55160C),
|
||||
btnDestroyBorder = Color(0xFF912018)
|
||||
)
|
||||
|
||||
@Suppress("CompositionLocalAllowlist")
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
package co.electriccoin.zcash.ui.design.util
|
||||
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.ReadOnlyComposable
|
||||
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
infix fun <T> T.orDark(dark: T): T = if (isSystemInDarkTheme()) dark else this
|
|
@ -0,0 +1,13 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="20dp"
|
||||
android:height="20dp"
|
||||
android:viewportWidth="20"
|
||||
android:viewportHeight="20">
|
||||
<path
|
||||
android:pathData="M7.5,15L12.5,10L7.5,5"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="1.66667"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#87816F"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
|
@ -0,0 +1,13 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="20dp"
|
||||
android:height="20dp"
|
||||
android:viewportWidth="20"
|
||||
android:viewportHeight="20">
|
||||
<path
|
||||
android:pathData="M7.5,15L12.5,10L7.5,5"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="1.66667"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#A7A5A6"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
|
@ -0,0 +1,13 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="18dp"
|
||||
android:height="14dp"
|
||||
android:viewportWidth="18"
|
||||
android:viewportHeight="14">
|
||||
<path
|
||||
android:pathData="M17,7H1M1,7L7,13M1,7L7,1"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#231F20"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
|
@ -0,0 +1,13 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="18dp"
|
||||
android:height="14dp"
|
||||
android:viewportWidth="18"
|
||||
android:viewportHeight="14">
|
||||
<path
|
||||
android:pathData="M17,7H1M1,7L7,13M1,7L7,1"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#E8E8E8"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
|
@ -1,4 +1,5 @@
|
|||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="amount_with_fiat_currency_symbol" formatted="true"><xliff:g id="fiat_currency_symbol" example="$">%1$s</xliff:g><xliff:g id="amount" example="123">%2$s</xliff:g></string>
|
||||
<string name="hide_balance_placeholder">-----</string>
|
||||
<string name="back_navigation_content_description">Back</string>
|
||||
</resources>
|
||||
|
|
|
@ -3,13 +3,20 @@ package co.electriccoin.zcash.ui.screen.settings
|
|||
import androidx.compose.ui.test.junit4.ComposeContentTestRule
|
||||
import co.electriccoin.zcash.ui.common.model.TopAppBarSubTitleState
|
||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||
import co.electriccoin.zcash.ui.screen.settings.model.TroubleshootingParameters
|
||||
import co.electriccoin.zcash.ui.design.util.stringRes
|
||||
import co.electriccoin.zcash.ui.screen.settings.model.SettingsState
|
||||
import co.electriccoin.zcash.ui.screen.settings.model.SettingsTroubleshootingState
|
||||
import co.electriccoin.zcash.ui.screen.settings.model.TroubleshootingItemState
|
||||
import co.electriccoin.zcash.ui.screen.settings.view.Settings
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
class SettingsViewTestSetup(
|
||||
private val composeTestRule: ComposeContentTestRule,
|
||||
private val troubleshootingParameters: TroubleshootingParameters
|
||||
isTroubleshootingEnabled: Boolean = false,
|
||||
isBackgroundSyncEnabled: Boolean = false,
|
||||
isKeepScreenOnDuringSyncEnabled: Boolean = false,
|
||||
isAnalyticsEnabled: Boolean = false,
|
||||
isRescanEnabled: Boolean = false
|
||||
) {
|
||||
private val onBackCount = AtomicInteger(0)
|
||||
private val onFeedbackCount = AtomicInteger(0)
|
||||
|
@ -20,6 +27,30 @@ class SettingsViewTestSetup(
|
|||
private val onKeepScreenOnChangedCount = AtomicInteger(0)
|
||||
private val onAnalyticsChangedCount = AtomicInteger(0)
|
||||
|
||||
private val settingsTroubleshootingState =
|
||||
if (isTroubleshootingEnabled) {
|
||||
SettingsTroubleshootingState(
|
||||
rescan =
|
||||
TroubleshootingItemState(isRescanEnabled) {
|
||||
onRescanCount.incrementAndGet()
|
||||
},
|
||||
backgroundSync =
|
||||
TroubleshootingItemState(isBackgroundSyncEnabled) {
|
||||
onBackgroundSyncChangedCount.incrementAndGet()
|
||||
},
|
||||
keepScreenOnDuringSync =
|
||||
TroubleshootingItemState(isKeepScreenOnDuringSyncEnabled) {
|
||||
onKeepScreenOnChangedCount.incrementAndGet()
|
||||
},
|
||||
analytics =
|
||||
TroubleshootingItemState(isAnalyticsEnabled) {
|
||||
onAnalyticsChangedCount.incrementAndGet()
|
||||
}
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
fun getBackCount(): Int {
|
||||
composeTestRule.waitForIdle()
|
||||
return onBackCount.get()
|
||||
|
@ -64,31 +95,24 @@ class SettingsViewTestSetup(
|
|||
composeTestRule.setContent {
|
||||
ZcashTheme {
|
||||
Settings(
|
||||
troubleshootingParameters = troubleshootingParameters,
|
||||
onBack = {
|
||||
onBackCount.incrementAndGet()
|
||||
},
|
||||
onFeedback = {
|
||||
onFeedbackCount.incrementAndGet()
|
||||
},
|
||||
onAdvancedSettings = {
|
||||
onAdvancedSettingsCount.incrementAndGet()
|
||||
},
|
||||
onAbout = {
|
||||
onAboutCount.incrementAndGet()
|
||||
},
|
||||
onRescanWallet = {
|
||||
onRescanCount.incrementAndGet()
|
||||
},
|
||||
onBackgroundSyncSettingsChanged = {
|
||||
onBackgroundSyncChangedCount.incrementAndGet()
|
||||
},
|
||||
onKeepScreenOnDuringSyncSettingsChanged = {
|
||||
onKeepScreenOnChangedCount.incrementAndGet()
|
||||
},
|
||||
onAnalyticsSettingsChanged = {
|
||||
onAnalyticsChangedCount.incrementAndGet()
|
||||
},
|
||||
state =
|
||||
SettingsState(
|
||||
isLoading = false,
|
||||
version = stringRes("app_version"),
|
||||
settingsTroubleshootingState = settingsTroubleshootingState,
|
||||
onBack = {
|
||||
onBackCount.incrementAndGet()
|
||||
},
|
||||
onSendUsFeedbackClick = {
|
||||
onFeedbackCount.incrementAndGet()
|
||||
},
|
||||
onAdvancedSettingsClick = {
|
||||
onAdvancedSettingsCount.incrementAndGet()
|
||||
},
|
||||
onAboutUsClick = {
|
||||
onAboutCount.incrementAndGet()
|
||||
},
|
||||
),
|
||||
topAppBarSubTitleState = TopAppBarSubTitleState.None,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
package co.electriccoin.zcash.ui.screen.settings.fixture
|
||||
|
||||
import co.electriccoin.zcash.ui.screen.settings.model.TroubleshootingParameters
|
||||
|
||||
internal object TroubleshootingParametersFixture {
|
||||
internal const val ENABLED = false
|
||||
internal const val BACKGROUND_SYNC_ENABLED = false
|
||||
internal const val KEEP_SCREEN_ON_DURING_SYNC_ENABLED = false
|
||||
internal const val ANALYTICS_ENABLED = false
|
||||
internal const val RESCAN_ENABLED = false
|
||||
|
||||
fun new(
|
||||
isEnabled: Boolean = ENABLED,
|
||||
isBackgroundSyncEnabled: Boolean = BACKGROUND_SYNC_ENABLED,
|
||||
isKeepScreenOnDuringSyncEnabled: Boolean = KEEP_SCREEN_ON_DURING_SYNC_ENABLED,
|
||||
isAnalyticsEnabled: Boolean = ANALYTICS_ENABLED,
|
||||
isRescanEnabled: Boolean = RESCAN_ENABLED,
|
||||
) = TroubleshootingParameters(
|
||||
isEnabled,
|
||||
isBackgroundSyncEnabled,
|
||||
isKeepScreenOnDuringSyncEnabled,
|
||||
isAnalyticsEnabled,
|
||||
isRescanEnabled
|
||||
)
|
||||
}
|
|
@ -13,7 +13,6 @@ import co.electriccoin.zcash.test.UiTestPrerequisites
|
|||
import co.electriccoin.zcash.ui.R
|
||||
import co.electriccoin.zcash.ui.screen.settings.SettingsTag
|
||||
import co.electriccoin.zcash.ui.screen.settings.SettingsViewTestSetup
|
||||
import co.electriccoin.zcash.ui.screen.settings.fixture.TroubleshootingParametersFixture
|
||||
import co.electriccoin.zcash.ui.test.getStringResource
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Rule
|
||||
|
@ -26,7 +25,7 @@ class SettingsViewTest : UiTestPrerequisites() {
|
|||
@Test
|
||||
@MediumTest
|
||||
fun on_back_test() {
|
||||
val testSetup = SettingsViewTestSetup(composeTestRule, TroubleshootingParametersFixture.new())
|
||||
val testSetup = SettingsViewTestSetup(composeTestRule, isTroubleshootingEnabled = false)
|
||||
|
||||
assertEquals(0, testSetup.getBackCount())
|
||||
|
||||
|
@ -42,12 +41,12 @@ class SettingsViewTest : UiTestPrerequisites() {
|
|||
@Test
|
||||
@MediumTest
|
||||
fun on_feedback_test() {
|
||||
val testSetup = SettingsViewTestSetup(composeTestRule, TroubleshootingParametersFixture.new())
|
||||
val testSetup = SettingsViewTestSetup(composeTestRule, isTroubleshootingEnabled = false)
|
||||
|
||||
assertEquals(0, testSetup.getFeedbackCount())
|
||||
|
||||
composeTestRule.onNodeWithText(
|
||||
text = getStringResource(R.string.settings_send_us_feedback),
|
||||
text = getStringResource(R.string.settings_feedback),
|
||||
ignoreCase = true
|
||||
).also {
|
||||
it.performClick()
|
||||
|
@ -59,7 +58,7 @@ class SettingsViewTest : UiTestPrerequisites() {
|
|||
@Test
|
||||
@MediumTest
|
||||
fun on_advanced_settings_test() {
|
||||
val testSetup = SettingsViewTestSetup(composeTestRule, TroubleshootingParametersFixture.new())
|
||||
val testSetup = SettingsViewTestSetup(composeTestRule, isTroubleshootingEnabled = false)
|
||||
|
||||
assertEquals(0, testSetup.getAdvancedSettingsCount())
|
||||
|
||||
|
@ -76,12 +75,12 @@ class SettingsViewTest : UiTestPrerequisites() {
|
|||
@Test
|
||||
@MediumTest
|
||||
fun on_about_test() {
|
||||
val testSetup = SettingsViewTestSetup(composeTestRule, TroubleshootingParametersFixture.new())
|
||||
val testSetup = SettingsViewTestSetup(composeTestRule, isTroubleshootingEnabled = false)
|
||||
|
||||
assertEquals(0, testSetup.getAboutCount())
|
||||
|
||||
composeTestRule.onNodeWithText(
|
||||
text = getStringResource(R.string.settings_about),
|
||||
text = getStringResource(R.string.settings_about_us),
|
||||
ignoreCase = true
|
||||
).also {
|
||||
it.performScrollTo()
|
||||
|
@ -94,7 +93,7 @@ class SettingsViewTest : UiTestPrerequisites() {
|
|||
@Test
|
||||
@SmallTest
|
||||
fun troubleshooting_menu_visible_test() {
|
||||
SettingsViewTestSetup(composeTestRule, TroubleshootingParametersFixture.new(isEnabled = true))
|
||||
SettingsViewTestSetup(composeTestRule, isTroubleshootingEnabled = true)
|
||||
|
||||
composeTestRule.onNodeWithTag(SettingsTag.TROUBLESHOOTING_MENU).also {
|
||||
it.assertExists()
|
||||
|
@ -104,7 +103,7 @@ class SettingsViewTest : UiTestPrerequisites() {
|
|||
@Test
|
||||
@SmallTest
|
||||
fun troubleshooting_menu_not_visible_test() {
|
||||
SettingsViewTestSetup(composeTestRule, TroubleshootingParametersFixture.new(isEnabled = false))
|
||||
SettingsViewTestSetup(composeTestRule, isTroubleshootingEnabled = false)
|
||||
|
||||
composeTestRule.onNodeWithTag(SettingsTag.TROUBLESHOOTING_MENU).also {
|
||||
it.assertDoesNotExist()
|
||||
|
@ -116,11 +115,9 @@ class SettingsViewTest : UiTestPrerequisites() {
|
|||
fun troubleshooting_rescan_test() {
|
||||
val testSetup =
|
||||
SettingsViewTestSetup(
|
||||
composeTestRule,
|
||||
TroubleshootingParametersFixture.new(
|
||||
isEnabled = true,
|
||||
isRescanEnabled = true
|
||||
)
|
||||
composeTestRule = composeTestRule,
|
||||
isTroubleshootingEnabled = true,
|
||||
isRescanEnabled = true
|
||||
)
|
||||
|
||||
assertEquals(0, testSetup.getRescanCount())
|
||||
|
@ -140,10 +137,8 @@ class SettingsViewTest : UiTestPrerequisites() {
|
|||
val testSetup =
|
||||
SettingsViewTestSetup(
|
||||
composeTestRule,
|
||||
TroubleshootingParametersFixture.new(
|
||||
isEnabled = true,
|
||||
isBackgroundSyncEnabled = true
|
||||
)
|
||||
isTroubleshootingEnabled = true,
|
||||
isBackgroundSyncEnabled = true
|
||||
)
|
||||
|
||||
assertEquals(0, testSetup.getBackgroundSyncCount())
|
||||
|
@ -165,10 +160,8 @@ class SettingsViewTest : UiTestPrerequisites() {
|
|||
val testSetup =
|
||||
SettingsViewTestSetup(
|
||||
composeTestRule,
|
||||
TroubleshootingParametersFixture.new(
|
||||
isEnabled = true,
|
||||
isKeepScreenOnDuringSyncEnabled = true
|
||||
)
|
||||
isTroubleshootingEnabled = true,
|
||||
isKeepScreenOnDuringSyncEnabled = true
|
||||
)
|
||||
|
||||
assertEquals(0, testSetup.getKeepScreenOnSyncCount())
|
||||
|
@ -190,10 +183,8 @@ class SettingsViewTest : UiTestPrerequisites() {
|
|||
val testSetup =
|
||||
SettingsViewTestSetup(
|
||||
composeTestRule,
|
||||
TroubleshootingParametersFixture.new(
|
||||
isEnabled = true,
|
||||
isAnalyticsEnabled = true
|
||||
)
|
||||
isTroubleshootingEnabled = true,
|
||||
isAnalyticsEnabled = true
|
||||
)
|
||||
|
||||
assertEquals(0, testSetup.getAnalyticsCount())
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
package co.electriccoin.zcash.di
|
||||
|
||||
import co.electriccoin.zcash.ui.common.provider.GetDefaultServersProvider
|
||||
import co.electriccoin.zcash.ui.common.provider.GetVersionInfoProvider
|
||||
import org.koin.core.module.dsl.factoryOf
|
||||
import org.koin.dsl.module
|
||||
|
||||
val providerModule =
|
||||
module {
|
||||
factoryOf(::GetDefaultServersProvider)
|
||||
factoryOf(::GetVersionInfoProvider)
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package co.electriccoin.zcash.di
|
||||
|
||||
import co.electriccoin.zcash.ui.common.repository.ConfigurationRepository
|
||||
import co.electriccoin.zcash.ui.common.repository.ConfigurationRepositoryImpl
|
||||
import co.electriccoin.zcash.ui.common.repository.WalletRepository
|
||||
import co.electriccoin.zcash.ui.common.repository.WalletRepositoryImpl
|
||||
import org.koin.core.module.dsl.singleOf
|
||||
|
@ -9,4 +11,5 @@ import org.koin.dsl.module
|
|||
val repositoryModule =
|
||||
module {
|
||||
singleOf(::WalletRepositoryImpl) bind WalletRepository::class
|
||||
singleOf(::ConfigurationRepositoryImpl) bind ConfigurationRepository::class
|
||||
}
|
||||
|
|
|
@ -3,11 +3,13 @@ package co.electriccoin.zcash.di
|
|||
import co.electriccoin.zcash.ui.common.usecase.GetPersistableWalletUseCase
|
||||
import co.electriccoin.zcash.ui.common.usecase.GetSelectedEndpointUseCase
|
||||
import co.electriccoin.zcash.ui.common.usecase.GetSynchronizerUseCase
|
||||
import co.electriccoin.zcash.ui.common.usecase.ObserveConfigurationUseCase
|
||||
import co.electriccoin.zcash.ui.common.usecase.ObserveFastestServersUseCase
|
||||
import co.electriccoin.zcash.ui.common.usecase.ObserveSelectedEndpointUseCase
|
||||
import co.electriccoin.zcash.ui.common.usecase.ObserveSynchronizerUseCase
|
||||
import co.electriccoin.zcash.ui.common.usecase.PersistEndpointUseCase
|
||||
import co.electriccoin.zcash.ui.common.usecase.RefreshFastestServersUseCase
|
||||
import co.electriccoin.zcash.ui.common.usecase.RescanBlockchainUseCase
|
||||
import co.electriccoin.zcash.ui.common.usecase.ValidateEndpointUseCase
|
||||
import org.koin.core.module.dsl.singleOf
|
||||
import org.koin.dsl.module
|
||||
|
@ -23,4 +25,6 @@ val useCaseModule =
|
|||
singleOf(::ValidateEndpointUseCase)
|
||||
singleOf(::GetPersistableWalletUseCase)
|
||||
singleOf(::GetSelectedEndpointUseCase)
|
||||
singleOf(::ObserveConfigurationUseCase)
|
||||
singleOf(::RescanBlockchainUseCase)
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import co.electriccoin.zcash.ui.common.viewmodel.CheckUpdateViewModel
|
|||
import co.electriccoin.zcash.ui.common.viewmodel.HomeViewModel
|
||||
import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel
|
||||
import co.electriccoin.zcash.ui.screen.account.viewmodel.TransactionHistoryViewModel
|
||||
import co.electriccoin.zcash.ui.screen.advancedsettings.viewmodel.AdvancedSettingsViewModel
|
||||
import co.electriccoin.zcash.ui.screen.chooseserver.ChooseServerViewModel
|
||||
import co.electriccoin.zcash.ui.screen.onboarding.viewmodel.OnboardingViewModel
|
||||
import co.electriccoin.zcash.ui.screen.restore.viewmodel.RestoreViewModel
|
||||
|
@ -31,6 +32,7 @@ val viewModelModule =
|
|||
viewModelOf(::RestoreViewModel)
|
||||
viewModelOf(::ScreenBrightnessViewModel)
|
||||
viewModelOf(::SettingsViewModel)
|
||||
viewModelOf(::AdvancedSettingsViewModel)
|
||||
viewModelOf(::SupportViewModel)
|
||||
viewModelOf(::CreateTransactionsViewModel)
|
||||
viewModelOf(::RestoreSuccessViewModel)
|
||||
|
|
|
@ -115,26 +115,10 @@ internal fun MainActivity.Navigation() {
|
|||
NavigationHome(navController, backStack)
|
||||
}
|
||||
composable(SETTINGS) {
|
||||
WrapSettings(
|
||||
goAbout = {
|
||||
navController.navigateJustOnce(ABOUT)
|
||||
},
|
||||
goAdvancedSettings = {
|
||||
navController.navigateJustOnce(ADVANCED_SETTINGS)
|
||||
},
|
||||
goBack = {
|
||||
navController.popBackStackJustOnce(SETTINGS)
|
||||
},
|
||||
goFeedback = {
|
||||
navController.navigateJustOnce(SUPPORT)
|
||||
},
|
||||
)
|
||||
WrapSettings()
|
||||
}
|
||||
composable(ADVANCED_SETTINGS) {
|
||||
WrapAdvancedSettings(
|
||||
goBack = {
|
||||
navController.popBackStackJustOnce(ADVANCED_SETTINGS)
|
||||
},
|
||||
goExportPrivateData = {
|
||||
navController.checkProtectedDestination(
|
||||
scope = lifecycleScope,
|
||||
|
@ -151,9 +135,6 @@ internal fun MainActivity.Navigation() {
|
|||
unProtectedDestination = SEED_RECOVERY
|
||||
)
|
||||
},
|
||||
goChooseServer = {
|
||||
navController.navigateJustOnce(CHOOSE_SERVER)
|
||||
},
|
||||
goDeleteWallet = {
|
||||
navController.checkProtectedDestination(
|
||||
scope = lifecycleScope,
|
||||
|
@ -162,9 +143,6 @@ internal fun MainActivity.Navigation() {
|
|||
unProtectedDestination = DELETE_WALLET
|
||||
)
|
||||
},
|
||||
onCurrencyConversion = {
|
||||
navController.navigateJustOnce(SETTINGS_EXCHANGE_RATE_OPT_IN)
|
||||
}
|
||||
)
|
||||
|
||||
when {
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
package co.electriccoin.zcash.ui.common.provider
|
||||
|
||||
import android.app.Application
|
||||
import co.electriccoin.zcash.ui.common.model.VersionInfo
|
||||
|
||||
class GetVersionInfoProvider(private val application: Application) {
|
||||
operator fun invoke() = VersionInfo.new(application)
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package co.electriccoin.zcash.ui.common.repository
|
||||
|
||||
import cash.z.ecc.sdk.ANDROID_STATE_FLOW_TIMEOUT
|
||||
import co.electriccoin.zcash.configuration.api.ConfigurationProvider
|
||||
import co.electriccoin.zcash.configuration.model.map.Configuration
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
|
||||
interface ConfigurationRepository {
|
||||
val configurationFlow: StateFlow<Configuration?>
|
||||
}
|
||||
|
||||
class ConfigurationRepositoryImpl(androidConfigurationProvider: ConfigurationProvider) : ConfigurationRepository {
|
||||
private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
||||
|
||||
override val configurationFlow: StateFlow<Configuration?> =
|
||||
androidConfigurationProvider.getConfigurationFlow()
|
||||
.stateIn(
|
||||
scope,
|
||||
SharingStarted.WhileSubscribed(ANDROID_STATE_FLOW_TIMEOUT.inWholeMilliseconds),
|
||||
null
|
||||
)
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package co.electriccoin.zcash.ui.common.usecase
|
||||
|
||||
import co.electriccoin.zcash.ui.common.repository.ConfigurationRepository
|
||||
|
||||
class ObserveConfigurationUseCase(
|
||||
private val configurationRepository: ConfigurationRepository
|
||||
) {
|
||||
operator fun invoke() = configurationRepository.configurationFlow
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package co.electriccoin.zcash.ui.common.usecase
|
||||
|
||||
import cash.z.ecc.android.sdk.WalletCoordinator
|
||||
import co.electriccoin.zcash.preference.StandardPreferenceProvider
|
||||
import co.electriccoin.zcash.ui.common.model.WalletRestoringState
|
||||
import co.electriccoin.zcash.ui.preference.StandardPreferenceKeys
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.NonCancellable
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class RescanBlockchainUseCase(
|
||||
private val walletCoordinator: WalletCoordinator,
|
||||
private val standardPreferenceProvider: StandardPreferenceProvider
|
||||
) {
|
||||
suspend operator fun invoke() =
|
||||
withContext(Dispatchers.IO + NonCancellable) {
|
||||
walletCoordinator.rescanBlockchain()
|
||||
persistWalletRestoringState(WalletRestoringState.RESTORING)
|
||||
}
|
||||
|
||||
private suspend fun persistWalletRestoringState(walletRestoringState: WalletRestoringState) {
|
||||
StandardPreferenceKeys.WALLET_RESTORING_STATE.putValue(
|
||||
standardPreferenceProvider(),
|
||||
walletRestoringState.toNumber()
|
||||
)
|
||||
}
|
||||
}
|
|
@ -3,10 +3,10 @@ package co.electriccoin.zcash.ui.common.viewmodel
|
|||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import cash.z.ecc.sdk.ANDROID_STATE_FLOW_TIMEOUT
|
||||
import co.electriccoin.zcash.configuration.api.ConfigurationProvider
|
||||
import co.electriccoin.zcash.configuration.model.map.Configuration
|
||||
import co.electriccoin.zcash.preference.StandardPreferenceProvider
|
||||
import co.electriccoin.zcash.preference.model.entry.BooleanPreferenceDefault
|
||||
import co.electriccoin.zcash.ui.common.usecase.ObserveConfigurationUseCase
|
||||
import co.electriccoin.zcash.ui.preference.StandardPreferenceKeys
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
@ -19,7 +19,7 @@ import kotlinx.coroutines.flow.stateIn
|
|||
import kotlinx.coroutines.launch
|
||||
|
||||
class HomeViewModel(
|
||||
androidConfigurationProvider: ConfigurationProvider,
|
||||
private val observeConfiguration: ObserveConfigurationUseCase,
|
||||
private val standardPreferenceProvider: StandardPreferenceProvider,
|
||||
) : ViewModel() {
|
||||
/**
|
||||
|
@ -55,13 +55,7 @@ class HomeViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
val configurationFlow: StateFlow<Configuration?> =
|
||||
androidConfigurationProvider.getConfigurationFlow()
|
||||
.stateIn(
|
||||
viewModelScope,
|
||||
SharingStarted.WhileSubscribed(ANDROID_STATE_FLOW_TIMEOUT.inWholeMilliseconds),
|
||||
null
|
||||
)
|
||||
val configurationFlow: StateFlow<Configuration?> = observeConfiguration()
|
||||
|
||||
//
|
||||
// PRIVATE HELPERS
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
package co.electriccoin.zcash.ui.screen.advancedsettings
|
||||
|
||||
data class AdvancedSettingsState(
|
||||
val onBack: () -> Unit,
|
||||
val onRecoveryPhraseClick: () -> Unit,
|
||||
val onExportPrivateDataClick: () -> Unit,
|
||||
val onChooseServerClick: () -> Unit,
|
||||
val onCurrencyConversionClick: () -> Unit,
|
||||
val onDeleteZashiClick: () -> Unit,
|
||||
)
|
|
@ -4,60 +4,51 @@ package co.electriccoin.zcash.ui.screen.advancedsettings
|
|||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import co.electriccoin.zcash.di.koinActivityViewModel
|
||||
import co.electriccoin.zcash.ui.MainActivity
|
||||
import co.electriccoin.zcash.ui.common.model.TopAppBarSubTitleState
|
||||
import co.electriccoin.zcash.ui.common.compose.LocalNavController
|
||||
import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel
|
||||
import co.electriccoin.zcash.ui.screen.advancedsettings.view.AdvancedSettings
|
||||
import co.electriccoin.zcash.ui.screen.advancedsettings.viewmodel.AdvancedSettingsViewModel
|
||||
import org.koin.androidx.compose.koinViewModel
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
@Composable
|
||||
internal fun MainActivity.WrapAdvancedSettings(
|
||||
goBack: () -> Unit,
|
||||
internal fun WrapAdvancedSettings(
|
||||
goDeleteWallet: () -> Unit,
|
||||
goExportPrivateData: () -> Unit,
|
||||
goChooseServer: () -> Unit,
|
||||
goSeedRecovery: () -> Unit,
|
||||
onCurrencyConversion: () -> Unit
|
||||
) {
|
||||
val navController = LocalNavController.current
|
||||
val walletViewModel = koinActivityViewModel<WalletViewModel>()
|
||||
|
||||
val viewModel = koinViewModel<AdvancedSettingsViewModel>()
|
||||
val walletState = walletViewModel.walletStateInformation.collectAsStateWithLifecycle().value
|
||||
val state =
|
||||
viewModel.state.collectAsStateWithLifecycle().value.copy(
|
||||
onDeleteZashiClick = goDeleteWallet,
|
||||
onExportPrivateDataClick = goExportPrivateData,
|
||||
onRecoveryPhraseClick = goSeedRecovery
|
||||
)
|
||||
|
||||
WrapAdvancedSettings(
|
||||
goBack = goBack,
|
||||
goDeleteWallet = goDeleteWallet,
|
||||
goExportPrivateData = goExportPrivateData,
|
||||
goChooseServer = goChooseServer,
|
||||
goSeedRecovery = goSeedRecovery,
|
||||
topAppBarSubTitleState = walletState,
|
||||
onCurrencyConversion = onCurrencyConversion
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Suppress("LongParameterList")
|
||||
private fun WrapAdvancedSettings(
|
||||
goBack: () -> Unit,
|
||||
goExportPrivateData: () -> Unit,
|
||||
goChooseServer: () -> Unit,
|
||||
goSeedRecovery: () -> Unit,
|
||||
goDeleteWallet: () -> Unit,
|
||||
onCurrencyConversion: () -> Unit,
|
||||
topAppBarSubTitleState: TopAppBarSubTitleState,
|
||||
) {
|
||||
BackHandler {
|
||||
goBack()
|
||||
viewModel.onBack()
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
viewModel.navigationCommand.collect {
|
||||
navController.navigate(it)
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
viewModel.backNavigationCommand.collect {
|
||||
navController.popBackStack()
|
||||
}
|
||||
}
|
||||
|
||||
AdvancedSettings(
|
||||
onBack = goBack,
|
||||
onDeleteWallet = goDeleteWallet,
|
||||
onExportPrivateData = goExportPrivateData,
|
||||
onChooseServer = goChooseServer,
|
||||
onSeedRecovery = goSeedRecovery,
|
||||
topAppBarSubTitleState = topAppBarSubTitleState,
|
||||
onCurrencyConversion = onCurrencyConversion
|
||||
state = state,
|
||||
topAppBarSubTitleState = walletState,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,89 +1,128 @@
|
|||
package co.electriccoin.zcash.ui.screen.advancedsettings.view
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import co.electriccoin.zcash.ui.R
|
||||
import co.electriccoin.zcash.ui.common.model.TopAppBarSubTitleState
|
||||
import co.electriccoin.zcash.ui.design.MINIMAL_WEIGHT
|
||||
import co.electriccoin.zcash.ui.design.component.BlankBgScaffold
|
||||
import co.electriccoin.zcash.ui.design.component.PrimaryButton
|
||||
import co.electriccoin.zcash.ui.design.component.SmallTopAppBar
|
||||
import co.electriccoin.zcash.ui.design.component.TopAppBarBackNavigation
|
||||
import co.electriccoin.zcash.ui.design.component.ZashiSettingsListItem
|
||||
import co.electriccoin.zcash.ui.design.component.ZashiSmallTopAppBar
|
||||
import co.electriccoin.zcash.ui.design.component.ZashiTopAppBarBackNavigation
|
||||
import co.electriccoin.zcash.ui.design.newcomponent.PreviewScreens
|
||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme.dimens
|
||||
import co.electriccoin.zcash.ui.design.util.orDark
|
||||
import co.electriccoin.zcash.ui.screen.advancedsettings.AdvancedSettingsState
|
||||
import co.electriccoin.zcash.ui.screen.advancedsettings.AdvancedSettingsTag
|
||||
import co.electriccoin.zcash.ui.screen.exchangerate.ZashiButton
|
||||
import co.electriccoin.zcash.ui.screen.exchangerate.ZashiButtonDefaults
|
||||
|
||||
// TODO [#1271]: Add AdvancedSettingsView Tests
|
||||
// TODO [#1271]: https://github.com/Electric-Coin-Company/zashi-android/issues/1271
|
||||
|
||||
@Preview("Advanced Settings")
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
private fun PreviewAdvancedSettings() {
|
||||
ZcashTheme(forceDarkMode = false) {
|
||||
AdvancedSettings(
|
||||
onBack = {},
|
||||
onDeleteWallet = {},
|
||||
onExportPrivateData = {},
|
||||
onChooseServer = {},
|
||||
onSeedRecovery = {},
|
||||
topAppBarSubTitleState = TopAppBarSubTitleState.None,
|
||||
onCurrencyConversion = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Suppress("LongParameterList")
|
||||
fun AdvancedSettings(
|
||||
onBack: () -> Unit,
|
||||
onDeleteWallet: () -> Unit,
|
||||
onExportPrivateData: () -> Unit,
|
||||
onChooseServer: () -> Unit,
|
||||
onSeedRecovery: () -> Unit,
|
||||
onCurrencyConversion: () -> Unit,
|
||||
state: AdvancedSettingsState,
|
||||
topAppBarSubTitleState: TopAppBarSubTitleState,
|
||||
) {
|
||||
BlankBgScaffold(
|
||||
topBar = {
|
||||
AdvancedSettingsTopAppBar(
|
||||
onBack = onBack,
|
||||
onBack = state.onBack,
|
||||
subTitleState = topAppBarSubTitleState,
|
||||
)
|
||||
}
|
||||
) { paddingValues ->
|
||||
AdvancedSettingsMainContent(
|
||||
Column(
|
||||
modifier =
|
||||
Modifier
|
||||
.verticalScroll(
|
||||
rememberScrollState()
|
||||
)
|
||||
.fillMaxSize()
|
||||
.verticalScroll(rememberScrollState())
|
||||
.padding(
|
||||
top = paddingValues.calculateTopPadding() + dimens.spacingHuge,
|
||||
top = paddingValues.calculateTopPadding(),
|
||||
bottom = paddingValues.calculateBottomPadding(),
|
||||
start = dimens.screenHorizontalSpacingBig,
|
||||
end = dimens.screenHorizontalSpacingBig
|
||||
start = 4.dp,
|
||||
end = 4.dp
|
||||
),
|
||||
onDeleteWallet = onDeleteWallet,
|
||||
onExportPrivateData = onExportPrivateData,
|
||||
onSeedRecovery = onSeedRecovery,
|
||||
onChooseServer = onChooseServer,
|
||||
onCurrencyConversion = onCurrencyConversion
|
||||
)
|
||||
) {
|
||||
ZashiSettingsListItem(
|
||||
text = stringResource(id = R.string.advanced_settings_recovery),
|
||||
icon = R.drawable.ic_advanced_settings_recovery orDark R.drawable.ic_advanced_settings_recovery_dark,
|
||||
onClick = state.onRecoveryPhraseClick
|
||||
)
|
||||
HorizontalDivider(color = ZcashTheme.zashiColors.divider)
|
||||
ZashiSettingsListItem(
|
||||
text = stringResource(id = R.string.advanced_settings_export),
|
||||
icon = R.drawable.ic_advanced_settings_export orDark R.drawable.ic_advanced_settings_export_dark,
|
||||
onClick = state.onExportPrivateDataClick
|
||||
)
|
||||
HorizontalDivider(color = ZcashTheme.zashiColors.divider)
|
||||
ZashiSettingsListItem(
|
||||
text = stringResource(id = R.string.advanced_settings_choose_server),
|
||||
icon =
|
||||
R.drawable.ic_advanced_settings_choose_server orDark
|
||||
R.drawable.ic_advanced_settings_choose_server_dark,
|
||||
onClick = state.onChooseServerClick
|
||||
)
|
||||
HorizontalDivider(color = ZcashTheme.zashiColors.divider)
|
||||
ZashiSettingsListItem(
|
||||
text = stringResource(id = R.string.advanced_settings_currency_conversion),
|
||||
icon =
|
||||
R.drawable.ic_advanced_settings_currency_conversion orDark
|
||||
R.drawable.ic_advanced_settings_currency_conversion_dark,
|
||||
onClick = state.onCurrencyConversionClick
|
||||
)
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.Center
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.ic_advanced_settings_info),
|
||||
contentDescription = "",
|
||||
colorFilter = ColorFilter.tint(ZcashTheme.zashiColors.textTertiary)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(12.dp))
|
||||
Text(
|
||||
text = stringResource(id = R.string.advanced_settings_info),
|
||||
fontSize = 12.sp,
|
||||
color = ZcashTheme.zashiColors.textTertiary,
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
ZashiButton(
|
||||
modifier =
|
||||
Modifier
|
||||
.padding(horizontal = 20.dp)
|
||||
.fillMaxWidth(),
|
||||
text = stringResource(R.string.advanced_settings_delete_button),
|
||||
colors = ZashiButtonDefaults.destroyButtonColors(),
|
||||
onClick = state.onDeleteZashiClick
|
||||
)
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -92,8 +131,9 @@ private fun AdvancedSettingsTopAppBar(
|
|||
onBack: () -> Unit,
|
||||
subTitleState: TopAppBarSubTitleState
|
||||
) {
|
||||
SmallTopAppBar(
|
||||
subTitle =
|
||||
ZashiSmallTopAppBar(
|
||||
title = stringResource(id = R.string.advanced_settings_title),
|
||||
subtitle =
|
||||
when (subTitleState) {
|
||||
TopAppBarSubTitleState.Disconnected -> stringResource(id = R.string.disconnected_label)
|
||||
TopAppBarSubTitleState.Restoring -> stringResource(id = R.string.restoring_wallet_label)
|
||||
|
@ -102,88 +142,26 @@ private fun AdvancedSettingsTopAppBar(
|
|||
modifier = Modifier.testTag(AdvancedSettingsTag.ADVANCED_SETTINGS_TOP_APP_BAR),
|
||||
showTitleLogo = true,
|
||||
navigationAction = {
|
||||
TopAppBarBackNavigation(
|
||||
backText = stringResource(id = R.string.back_navigation).uppercase(),
|
||||
backContentDescriptionText = stringResource(R.string.back_navigation_content_description),
|
||||
onBack = onBack
|
||||
)
|
||||
}
|
||||
ZashiTopAppBarBackNavigation(onBack = onBack)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
@Suppress("UnusedPrivateMember")
|
||||
@PreviewScreens
|
||||
@Composable
|
||||
private fun AdvancedSettingsMainContent(
|
||||
onDeleteWallet: () -> Unit,
|
||||
onExportPrivateData: () -> Unit,
|
||||
onChooseServer: () -> Unit,
|
||||
onCurrencyConversion: () -> Unit,
|
||||
onSeedRecovery: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Column(
|
||||
Modifier
|
||||
.fillMaxSize()
|
||||
.then(modifier),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
PrimaryButton(
|
||||
onClick = onSeedRecovery,
|
||||
text = stringResource(R.string.advanced_settings_backup_wallet),
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(dimens.spacingDefault))
|
||||
|
||||
PrimaryButton(
|
||||
onClick = onExportPrivateData,
|
||||
text = stringResource(R.string.advanced_settings_export_private_data),
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(dimens.spacingDefault))
|
||||
|
||||
PrimaryButton(
|
||||
onClick = onChooseServer,
|
||||
text = stringResource(R.string.advanced_settings_choose_server),
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(dimens.spacingDefault))
|
||||
|
||||
PrimaryButton(
|
||||
onClick = onCurrencyConversion,
|
||||
text = stringResource(R.string.advanced_settings_currency_conversion),
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
|
||||
Spacer(
|
||||
modifier =
|
||||
Modifier
|
||||
.fillMaxHeight()
|
||||
.weight(MINIMAL_WEIGHT)
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(dimens.spacingDefault))
|
||||
|
||||
PrimaryButton(
|
||||
onClick = onDeleteWallet,
|
||||
text =
|
||||
stringResource(
|
||||
R.string.advanced_settings_delete_wallet,
|
||||
stringResource(id = R.string.app_name)
|
||||
private fun AdvancedSettingsPreview() =
|
||||
ZcashTheme {
|
||||
AdvancedSettings(
|
||||
state =
|
||||
AdvancedSettingsState(
|
||||
onBack = {},
|
||||
onRecoveryPhraseClick = {},
|
||||
onExportPrivateDataClick = {},
|
||||
onChooseServerClick = {},
|
||||
onCurrencyConversionClick = {},
|
||||
onDeleteZashiClick = {},
|
||||
),
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
topAppBarSubTitleState = TopAppBarSubTitleState.None,
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(dimens.spacingDefault))
|
||||
|
||||
Text(
|
||||
text = stringResource(id = R.string.advanced_settings_delete_wallet_footnote),
|
||||
style = ZcashTheme.extendedTypography.footnote,
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(dimens.spacingHuge))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
package co.electriccoin.zcash.ui.screen.advancedsettings.viewmodel
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import co.electriccoin.zcash.ui.NavigationTargets
|
||||
import co.electriccoin.zcash.ui.screen.advancedsettings.AdvancedSettingsState
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class AdvancedSettingsViewModel : ViewModel() {
|
||||
val state: StateFlow<AdvancedSettingsState> =
|
||||
MutableStateFlow(
|
||||
AdvancedSettingsState(
|
||||
onBack = ::onBack,
|
||||
onRecoveryPhraseClick = {},
|
||||
onExportPrivateDataClick = {},
|
||||
onChooseServerClick = ::onChooseServerClick,
|
||||
onCurrencyConversionClick = ::onCurrencyConversionClick,
|
||||
onDeleteZashiClick = {}
|
||||
)
|
||||
).asStateFlow()
|
||||
|
||||
val navigationCommand = MutableSharedFlow<String>()
|
||||
val backNavigationCommand = MutableSharedFlow<Unit>()
|
||||
|
||||
private fun onChooseServerClick() =
|
||||
viewModelScope.launch {
|
||||
navigationCommand.emit(NavigationTargets.CHOOSE_SERVER)
|
||||
}
|
||||
|
||||
private fun onCurrencyConversionClick() =
|
||||
viewModelScope.launch {
|
||||
navigationCommand.emit(NavigationTargets.SETTINGS_EXCHANGE_RATE_OPT_IN)
|
||||
}
|
||||
|
||||
fun onBack() =
|
||||
viewModelScope.launch {
|
||||
backNavigationCommand.emit(Unit)
|
||||
}
|
||||
}
|
|
@ -1,21 +1,25 @@
|
|||
package co.electriccoin.zcash.ui.screen.exchangerate
|
||||
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonColors
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.dp
|
||||
import co.electriccoin.zcash.ui.design.R
|
||||
import co.electriccoin.zcash.ui.design.component.BlankSurface
|
||||
import co.electriccoin.zcash.ui.design.component.ButtonState
|
||||
import co.electriccoin.zcash.ui.design.component.LottieProgress
|
||||
import co.electriccoin.zcash.ui.design.newcomponent.PreviewScreens
|
||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||
import co.electriccoin.zcash.ui.design.util.getValue
|
||||
|
||||
|
@ -23,7 +27,7 @@ import co.electriccoin.zcash.ui.design.util.getValue
|
|||
internal fun ZashiButton(
|
||||
state: ButtonState,
|
||||
modifier: Modifier = Modifier,
|
||||
colors: ButtonColors = ZashiButtonDefaults.primaryButtonColors(),
|
||||
colors: ZashiButtonColors = ZashiButtonDefaults.primaryButtonColors(),
|
||||
content: @Composable RowScope.(ZashiButtonScope) -> Unit = ZashiButtonDefaults.content
|
||||
) {
|
||||
ZashiButton(
|
||||
|
@ -45,7 +49,7 @@ internal fun ZashiButton(
|
|||
modifier: Modifier = Modifier,
|
||||
enabled: Boolean = true,
|
||||
isLoading: Boolean = false,
|
||||
colors: ButtonColors = ZashiButtonDefaults.primaryButtonColors(),
|
||||
colors: ZashiButtonColors = ZashiButtonDefaults.primaryButtonColors(),
|
||||
content: @Composable RowScope.(ZashiButtonScope) -> Unit = ZashiButtonDefaults.content
|
||||
) {
|
||||
val scope =
|
||||
|
@ -75,7 +79,8 @@ internal fun ZashiButton(
|
|||
modifier = modifier,
|
||||
shape = RoundedCornerShape(12.dp),
|
||||
enabled = enabled,
|
||||
colors = colors,
|
||||
colors = colors.toButtonColors(),
|
||||
border = colors.borderColor.takeIf { it != Color.Unspecified }?.let { BorderStroke(1.dp, it) },
|
||||
content = {
|
||||
content(scope)
|
||||
}
|
||||
|
@ -104,13 +109,13 @@ object ZashiButtonDefaults {
|
|||
contentColor: Color = ZcashTheme.zashiColors.btnPrimaryFg,
|
||||
disabledContainerColor: Color = ZcashTheme.zashiColors.btnPrimaryBgDisabled,
|
||||
disabledContentColor: Color = ZcashTheme.zashiColors.btnPrimaryFgDisabled,
|
||||
): ButtonColors =
|
||||
ButtonDefaults.buttonColors(
|
||||
containerColor = containerColor,
|
||||
contentColor = contentColor,
|
||||
disabledContainerColor = disabledContainerColor,
|
||||
disabledContentColor = disabledContentColor
|
||||
)
|
||||
) = ZashiButtonColors(
|
||||
containerColor = containerColor,
|
||||
contentColor = contentColor,
|
||||
disabledContainerColor = disabledContainerColor,
|
||||
disabledContentColor = disabledContentColor,
|
||||
borderColor = Color.Unspecified
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun tertiaryButtonColors(
|
||||
|
@ -118,11 +123,88 @@ object ZashiButtonDefaults {
|
|||
contentColor: Color = ZcashTheme.zashiColors.btnTertiaryFg,
|
||||
disabledContainerColor: Color = Color.Unspecified,
|
||||
disabledContentColor: Color = Color.Unspecified,
|
||||
): ButtonColors =
|
||||
ButtonDefaults.buttonColors(
|
||||
containerColor = containerColor,
|
||||
contentColor = contentColor,
|
||||
disabledContainerColor = disabledContainerColor,
|
||||
disabledContentColor = disabledContentColor
|
||||
)
|
||||
) = ZashiButtonColors(
|
||||
containerColor = containerColor,
|
||||
contentColor = contentColor,
|
||||
disabledContainerColor = disabledContainerColor,
|
||||
disabledContentColor = disabledContentColor,
|
||||
borderColor = Color.Unspecified
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun destroyButtonColors(
|
||||
containerColor: Color = ZcashTheme.zashiColors.btnDestroyBg,
|
||||
contentColor: Color = ZcashTheme.zashiColors.btnDestroyFg,
|
||||
borderColor: Color = ZcashTheme.zashiColors.btnDestroyBorder,
|
||||
disabledContainerColor: Color = Color.Unspecified,
|
||||
disabledContentColor: Color = Color.Unspecified,
|
||||
) = ZashiButtonColors(
|
||||
containerColor = containerColor,
|
||||
contentColor = contentColor,
|
||||
disabledContainerColor = disabledContainerColor,
|
||||
disabledContentColor = disabledContentColor,
|
||||
borderColor = borderColor
|
||||
)
|
||||
}
|
||||
|
||||
@Immutable
|
||||
data class ZashiButtonColors(
|
||||
val containerColor: Color,
|
||||
val contentColor: Color,
|
||||
val disabledContainerColor: Color,
|
||||
val disabledContentColor: Color,
|
||||
val borderColor: Color,
|
||||
)
|
||||
|
||||
@Composable
|
||||
private fun ZashiButtonColors.toButtonColors() =
|
||||
ButtonDefaults.buttonColors(
|
||||
containerColor = containerColor,
|
||||
contentColor = contentColor,
|
||||
disabledContainerColor = disabledContainerColor,
|
||||
disabledContentColor = disabledContentColor,
|
||||
)
|
||||
|
||||
@Suppress("UnusedPrivateMember")
|
||||
@PreviewScreens
|
||||
@Composable
|
||||
private fun PrimaryPreview() =
|
||||
ZcashTheme {
|
||||
BlankSurface {
|
||||
ZashiButton(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
text = "Primary",
|
||||
onClick = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UnusedPrivateMember")
|
||||
@PreviewScreens
|
||||
@Composable
|
||||
private fun TertiaryPreview() =
|
||||
ZcashTheme {
|
||||
BlankSurface {
|
||||
ZashiButton(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
text = "Primary",
|
||||
colors = ZashiButtonDefaults.tertiaryButtonColors(),
|
||||
onClick = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UnusedPrivateMember")
|
||||
@PreviewScreens
|
||||
@Composable
|
||||
private fun DestroyPreview() =
|
||||
ZcashTheme {
|
||||
BlankSurface {
|
||||
ZashiButton(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
text = "Primary",
|
||||
colors = ZashiButtonDefaults.destroyButtonColors(),
|
||||
onClick = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,77 +2,43 @@ package co.electriccoin.zcash.ui.screen.settings
|
|||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import co.electriccoin.zcash.di.koinActivityViewModel
|
||||
import co.electriccoin.zcash.ui.common.compose.LocalActivity
|
||||
import co.electriccoin.zcash.ui.common.model.VersionInfo
|
||||
import co.electriccoin.zcash.ui.common.compose.LocalNavController
|
||||
import co.electriccoin.zcash.ui.common.viewmodel.WalletViewModel
|
||||
import co.electriccoin.zcash.ui.configuration.ConfigurationEntries
|
||||
import co.electriccoin.zcash.ui.configuration.RemoteConfig
|
||||
import co.electriccoin.zcash.ui.design.component.CircularScreenProgressIndicator
|
||||
import co.electriccoin.zcash.ui.screen.settings.model.TroubleshootingParameters
|
||||
import co.electriccoin.zcash.ui.screen.settings.view.Settings
|
||||
import co.electriccoin.zcash.ui.screen.settings.viewmodel.SettingsViewModel
|
||||
import org.koin.androidx.compose.koinViewModel
|
||||
|
||||
@Composable
|
||||
internal fun WrapSettings(
|
||||
goAbout: () -> Unit,
|
||||
goAdvancedSettings: () -> Unit,
|
||||
goBack: () -> Unit,
|
||||
goFeedback: () -> Unit,
|
||||
) {
|
||||
val activity = LocalActivity.current
|
||||
|
||||
internal fun WrapSettings() {
|
||||
val navController = LocalNavController.current
|
||||
val walletViewModel = koinActivityViewModel<WalletViewModel>()
|
||||
|
||||
val settingsViewModel = koinActivityViewModel<SettingsViewModel>()
|
||||
|
||||
val settingsViewModel = koinViewModel<SettingsViewModel>()
|
||||
val state by settingsViewModel.state.collectAsStateWithLifecycle()
|
||||
val walletState = walletViewModel.walletStateInformation.collectAsStateWithLifecycle().value
|
||||
|
||||
val isBackgroundSyncEnabled = settingsViewModel.isBackgroundSync.collectAsStateWithLifecycle().value
|
||||
val isKeepScreenOnWhileSyncing = settingsViewModel.isKeepScreenOnWhileSyncing.collectAsStateWithLifecycle().value
|
||||
val isAnalyticsEnabled = settingsViewModel.isAnalyticsEnabled.collectAsStateWithLifecycle().value
|
||||
|
||||
val versionInfo = VersionInfo.new(activity.applicationContext)
|
||||
|
||||
BackHandler {
|
||||
goBack()
|
||||
LaunchedEffect(Unit) {
|
||||
settingsViewModel.navigationCommand.collect {
|
||||
navController.navigate(it)
|
||||
}
|
||||
}
|
||||
|
||||
if (null == isAnalyticsEnabled ||
|
||||
null == isBackgroundSyncEnabled ||
|
||||
null == isKeepScreenOnWhileSyncing
|
||||
) {
|
||||
// TODO [#1146]: Consider moving CircularScreenProgressIndicator from Android layer to View layer
|
||||
// TODO [#1146]: Improve this by allowing screen composition and updating it after the data is available
|
||||
// TODO [#1146]: https://github.com/Electric-Coin-Company/zashi-android/issues/1146
|
||||
CircularScreenProgressIndicator()
|
||||
} else {
|
||||
LaunchedEffect(Unit) {
|
||||
settingsViewModel.backNavigationCommand.collect {
|
||||
navController.popBackStack()
|
||||
}
|
||||
}
|
||||
|
||||
BackHandler {
|
||||
settingsViewModel.onBack()
|
||||
}
|
||||
|
||||
state?.let {
|
||||
Settings(
|
||||
onAbout = goAbout,
|
||||
onAdvancedSettings = goAdvancedSettings,
|
||||
onBack = goBack,
|
||||
onFeedback = goFeedback,
|
||||
troubleshootingParameters =
|
||||
TroubleshootingParameters(
|
||||
isEnabled = versionInfo.isDebuggable && !versionInfo.isRunningUnderTestService,
|
||||
isBackgroundSyncEnabled = isBackgroundSyncEnabled,
|
||||
isKeepScreenOnDuringSyncEnabled = isKeepScreenOnWhileSyncing,
|
||||
isAnalyticsEnabled = isAnalyticsEnabled,
|
||||
isRescanEnabled = ConfigurationEntries.IS_RESCAN_ENABLED.getValue(RemoteConfig.current),
|
||||
),
|
||||
onRescanWallet = {
|
||||
walletViewModel.rescanBlockchain()
|
||||
},
|
||||
onBackgroundSyncSettingsChanged = {
|
||||
settingsViewModel.setBackgroundSyncEnabled(it)
|
||||
},
|
||||
onKeepScreenOnDuringSyncSettingsChanged = {
|
||||
settingsViewModel.setKeepScreenOnWhileSyncing(it)
|
||||
},
|
||||
onAnalyticsSettingsChanged = {
|
||||
settingsViewModel.setAnalyticsEnabled(it)
|
||||
},
|
||||
state = it,
|
||||
topAppBarSubTitleState = walletState,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
package co.electriccoin.zcash.ui.screen.settings.model
|
||||
|
||||
import co.electriccoin.zcash.ui.design.util.StringResource
|
||||
|
||||
data class SettingsState(
|
||||
val isLoading: Boolean,
|
||||
val version: StringResource,
|
||||
val settingsTroubleshootingState: SettingsTroubleshootingState?,
|
||||
val onBack: () -> Unit,
|
||||
val onAdvancedSettingsClick: () -> Unit,
|
||||
val onAboutUsClick: () -> Unit,
|
||||
val onSendUsFeedbackClick: () -> Unit,
|
||||
)
|
|
@ -0,0 +1,17 @@
|
|||
package co.electriccoin.zcash.ui.screen.settings.model
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
|
||||
@Immutable
|
||||
data class SettingsTroubleshootingState(
|
||||
val backgroundSync: TroubleshootingItemState,
|
||||
val keepScreenOnDuringSync: TroubleshootingItemState,
|
||||
val analytics: TroubleshootingItemState,
|
||||
val rescan: TroubleshootingItemState,
|
||||
)
|
||||
|
||||
@Immutable
|
||||
data class TroubleshootingItemState(
|
||||
val isEnabled: Boolean,
|
||||
val onClick: () -> Unit,
|
||||
)
|
|
@ -1,9 +0,0 @@
|
|||
package co.electriccoin.zcash.ui.screen.settings.model
|
||||
|
||||
data class TroubleshootingParameters(
|
||||
val isEnabled: Boolean,
|
||||
val isBackgroundSyncEnabled: Boolean,
|
||||
val isKeepScreenOnDuringSyncEnabled: Boolean,
|
||||
val isAnalyticsEnabled: Boolean,
|
||||
val isRescanEnabled: Boolean,
|
||||
)
|
|
@ -1,9 +1,9 @@
|
|||
package co.electriccoin.zcash.ui.screen.settings.view
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
|
@ -14,6 +14,7 @@ import androidx.compose.material.icons.outlined.Cancel
|
|||
import androidx.compose.material.icons.outlined.CheckCircle
|
||||
import androidx.compose.material3.DropdownMenu
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.Text
|
||||
|
@ -22,106 +23,104 @@ 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.Alignment
|
||||
import androidx.compose.ui.Alignment.Companion.CenterHorizontally
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import co.electriccoin.zcash.ui.R
|
||||
import co.electriccoin.zcash.ui.common.model.TopAppBarSubTitleState
|
||||
import co.electriccoin.zcash.ui.design.MINIMAL_WEIGHT
|
||||
import co.electriccoin.zcash.ui.design.component.BlankBgScaffold
|
||||
import co.electriccoin.zcash.ui.design.component.PrimaryButton
|
||||
import co.electriccoin.zcash.ui.design.component.SmallTopAppBar
|
||||
import co.electriccoin.zcash.ui.design.component.TopAppBarBackNavigation
|
||||
import co.electriccoin.zcash.ui.design.component.CircularScreenProgressIndicator
|
||||
import co.electriccoin.zcash.ui.design.component.ZashiSettingsListItem
|
||||
import co.electriccoin.zcash.ui.design.component.ZashiSmallTopAppBar
|
||||
import co.electriccoin.zcash.ui.design.component.ZashiTopAppBarBackNavigation
|
||||
import co.electriccoin.zcash.ui.design.newcomponent.PreviewScreens
|
||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme.dimens
|
||||
import co.electriccoin.zcash.ui.design.util.getValue
|
||||
import co.electriccoin.zcash.ui.design.util.orDark
|
||||
import co.electriccoin.zcash.ui.design.util.stringRes
|
||||
import co.electriccoin.zcash.ui.screen.settings.SettingsTag
|
||||
import co.electriccoin.zcash.ui.screen.settings.model.TroubleshootingParameters
|
||||
import co.electriccoin.zcash.ui.screen.settings.model.SettingsState
|
||||
import co.electriccoin.zcash.ui.screen.settings.model.SettingsTroubleshootingState
|
||||
|
||||
@Preview("Settings")
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
private fun PreviewSettings() {
|
||||
ZcashTheme(forceDarkMode = false) {
|
||||
Settings(
|
||||
onAbout = {},
|
||||
onAdvancedSettings = {},
|
||||
onBack = {},
|
||||
onFeedback = {},
|
||||
onRescanWallet = {},
|
||||
onBackgroundSyncSettingsChanged = {},
|
||||
onKeepScreenOnDuringSyncSettingsChanged = {},
|
||||
onAnalyticsSettingsChanged = {},
|
||||
troubleshootingParameters =
|
||||
TroubleshootingParameters(
|
||||
isEnabled = false,
|
||||
isBackgroundSyncEnabled = false,
|
||||
isKeepScreenOnDuringSyncEnabled = false,
|
||||
isAnalyticsEnabled = false,
|
||||
isRescanEnabled = false
|
||||
),
|
||||
topAppBarSubTitleState = TopAppBarSubTitleState.None,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Suppress("LongParameterList")
|
||||
fun Settings(
|
||||
onAbout: () -> Unit,
|
||||
onAdvancedSettings: () -> Unit,
|
||||
onBack: () -> Unit,
|
||||
onFeedback: () -> Unit,
|
||||
onRescanWallet: () -> Unit,
|
||||
onBackgroundSyncSettingsChanged: (Boolean) -> Unit,
|
||||
onKeepScreenOnDuringSyncSettingsChanged: (Boolean) -> Unit,
|
||||
onAnalyticsSettingsChanged: (Boolean) -> Unit,
|
||||
troubleshootingParameters: TroubleshootingParameters,
|
||||
topAppBarSubTitleState: TopAppBarSubTitleState,
|
||||
state: SettingsState,
|
||||
topAppBarSubTitleState: TopAppBarSubTitleState
|
||||
) {
|
||||
BlankBgScaffold(topBar = {
|
||||
SettingsTopAppBar(
|
||||
troubleshootingParameters = troubleshootingParameters,
|
||||
onBackgroundSyncSettingsChanged = onBackgroundSyncSettingsChanged,
|
||||
onKeepScreenOnDuringSyncSettingsChanged = onKeepScreenOnDuringSyncSettingsChanged,
|
||||
onAnalyticsSettingsChanged = onAnalyticsSettingsChanged,
|
||||
onRescanWallet = onRescanWallet,
|
||||
onBack = onBack,
|
||||
subTitleState = topAppBarSubTitleState,
|
||||
)
|
||||
}) { paddingValues ->
|
||||
SettingsMainContent(
|
||||
modifier =
|
||||
Modifier
|
||||
.verticalScroll(
|
||||
rememberScrollState()
|
||||
)
|
||||
.padding(
|
||||
top = paddingValues.calculateTopPadding() + dimens.spacingHuge,
|
||||
bottom = paddingValues.calculateBottomPadding(),
|
||||
start = dimens.screenHorizontalSpacingBig,
|
||||
end = dimens.screenHorizontalSpacingBig
|
||||
),
|
||||
onAbout = onAbout,
|
||||
onAdvancedSettings = onAdvancedSettings,
|
||||
onFeedback = onFeedback,
|
||||
)
|
||||
BlankBgScaffold(
|
||||
topBar = {
|
||||
SettingsTopAppBar(
|
||||
onBack = state.onBack,
|
||||
subTitleState = topAppBarSubTitleState,
|
||||
state = state
|
||||
)
|
||||
}
|
||||
) { paddingValues ->
|
||||
if (state.isLoading) {
|
||||
CircularScreenProgressIndicator()
|
||||
} else {
|
||||
Column(
|
||||
modifier =
|
||||
Modifier
|
||||
.fillMaxSize()
|
||||
.verticalScroll(rememberScrollState())
|
||||
.padding(
|
||||
top = paddingValues.calculateTopPadding(),
|
||||
bottom = paddingValues.calculateBottomPadding(),
|
||||
start = 4.dp,
|
||||
end = 4.dp
|
||||
),
|
||||
) {
|
||||
ZashiSettingsListItem(
|
||||
text = stringResource(id = R.string.settings_advanced_settings),
|
||||
icon = R.drawable.ic_advanced_settings orDark R.drawable.ic_advanced_settings_dark,
|
||||
onClick = state.onAdvancedSettingsClick
|
||||
)
|
||||
HorizontalDivider(color = ZcashTheme.zashiColors.divider)
|
||||
ZashiSettingsListItem(
|
||||
text = stringResource(id = R.string.settings_about_us),
|
||||
icon = R.drawable.ic_settings_info orDark R.drawable.ic_settings_info_dark,
|
||||
onClick = state.onAboutUsClick
|
||||
)
|
||||
HorizontalDivider(color = ZcashTheme.zashiColors.divider)
|
||||
ZashiSettingsListItem(
|
||||
text = stringResource(id = R.string.settings_feedback),
|
||||
icon = R.drawable.ic_settings_feedback orDark R.drawable.ic_settings_feedback_dark,
|
||||
onClick = state.onSendUsFeedbackClick
|
||||
)
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingMin))
|
||||
Image(
|
||||
modifier = Modifier.align(CenterHorizontally),
|
||||
painter =
|
||||
painterResource(id = R.drawable.ic_settings_zashi orDark R.drawable.ic_settings_zashi_dark),
|
||||
contentDescription = ""
|
||||
)
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
Text(
|
||||
modifier = Modifier.align(CenterHorizontally),
|
||||
text = state.version.getValue(),
|
||||
color = ZcashTheme.zashiColors.textTertiary
|
||||
)
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Suppress("LongParameterList")
|
||||
private fun SettingsTopAppBar(
|
||||
onBackgroundSyncSettingsChanged: (Boolean) -> Unit,
|
||||
onKeepScreenOnDuringSyncSettingsChanged: (Boolean) -> Unit,
|
||||
onAnalyticsSettingsChanged: (Boolean) -> Unit,
|
||||
onRescanWallet: () -> Unit,
|
||||
onBack: () -> Unit,
|
||||
subTitleState: TopAppBarSubTitleState,
|
||||
troubleshootingParameters: TroubleshootingParameters,
|
||||
state: SettingsState
|
||||
) {
|
||||
SmallTopAppBar(
|
||||
subTitle =
|
||||
ZashiSmallTopAppBar(
|
||||
title = stringResource(id = R.string.settings_title),
|
||||
subtitle =
|
||||
when (subTitleState) {
|
||||
TopAppBarSubTitleState.Disconnected -> stringResource(id = R.string.disconnected_label)
|
||||
TopAppBarSubTitleState.Restoring -> stringResource(id = R.string.restoring_wallet_label)
|
||||
|
@ -130,26 +129,73 @@ private fun SettingsTopAppBar(
|
|||
modifier = Modifier.testTag(SettingsTag.SETTINGS_TOP_APP_BAR),
|
||||
showTitleLogo = true,
|
||||
navigationAction = {
|
||||
TopAppBarBackNavigation(
|
||||
backText = stringResource(id = R.string.back_navigation).uppercase(),
|
||||
backContentDescriptionText = stringResource(R.string.back_navigation_content_description),
|
||||
onBack = onBack
|
||||
)
|
||||
ZashiTopAppBarBackNavigation(onBack = onBack)
|
||||
},
|
||||
regularActions = {
|
||||
if (troubleshootingParameters.isEnabled) {
|
||||
TroubleshootingMenu(
|
||||
troubleshootingParameters,
|
||||
onBackgroundSyncSettingsChanged,
|
||||
onKeepScreenOnDuringSyncSettingsChanged,
|
||||
onAnalyticsSettingsChanged,
|
||||
onRescanWallet
|
||||
)
|
||||
if (state.settingsTroubleshootingState != null) {
|
||||
TroubleshootingMenu(state = state.settingsTroubleshootingState)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TroubleshootingMenu(state: SettingsTroubleshootingState) {
|
||||
Column(
|
||||
modifier = Modifier.testTag(SettingsTag.TROUBLESHOOTING_MENU)
|
||||
) {
|
||||
var expanded by rememberSaveable { mutableStateOf(false) }
|
||||
IconButton(onClick = { expanded = true }) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.MoreVert,
|
||||
contentDescription = stringResource(id = R.string.settings_troubleshooting_menu_content_description)
|
||||
)
|
||||
}
|
||||
|
||||
DropdownMenu(
|
||||
expanded = expanded,
|
||||
onDismissRequest = { expanded = false }
|
||||
) {
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(id = R.string.settings_troubleshooting_enable_background_sync)) },
|
||||
onClick = {
|
||||
state.backgroundSync.onClick()
|
||||
expanded = false
|
||||
},
|
||||
leadingIcon = { AddIcon(state.backgroundSync.isEnabled) }
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(id = R.string.settings_troubleshooting_enable_keep_screen_on)) },
|
||||
onClick = {
|
||||
state.keepScreenOnDuringSync.onClick()
|
||||
expanded = false
|
||||
},
|
||||
leadingIcon = { AddIcon(state.keepScreenOnDuringSync.isEnabled) }
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(id = R.string.settings_troubleshooting_enable_analytics)) },
|
||||
onClick = {
|
||||
state.analytics.onClick()
|
||||
expanded = false
|
||||
},
|
||||
leadingIcon = { AddIcon(state.analytics.isEnabled) }
|
||||
)
|
||||
// isRescanEnabled means if this feature should be visible, not whether it is enabled as in the case of
|
||||
// the previous booleans
|
||||
if (state.rescan.isEnabled) {
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(id = R.string.settings_troubleshooting_rescan)) },
|
||||
onClick = {
|
||||
state.rescan.onClick()
|
||||
expanded = false
|
||||
},
|
||||
leadingIcon = { AddIcon(true) }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add icon to Troubleshooting menu. No content description, as this is debug only menu.
|
||||
*/
|
||||
|
@ -168,112 +214,44 @@ private fun AddIcon(enabled: Boolean) {
|
|||
}
|
||||
}
|
||||
|
||||
@Suppress("UnusedPrivateMember")
|
||||
@PreviewScreens
|
||||
@Composable
|
||||
private fun TroubleshootingMenu(
|
||||
troubleshootParams: TroubleshootingParameters,
|
||||
onBackgroundSyncSettingsChanged: (Boolean) -> Unit,
|
||||
onKeepScreenOnDuringSyncSettingsChanged: (Boolean) -> Unit,
|
||||
onAnalyticsSettingsChanged: (Boolean) -> Unit,
|
||||
onRescanWallet: () -> Unit
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.testTag(SettingsTag.TROUBLESHOOTING_MENU)
|
||||
) {
|
||||
var expanded by rememberSaveable { mutableStateOf(false) }
|
||||
IconButton(onClick = { expanded = true }) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.MoreVert,
|
||||
contentDescription = stringResource(id = R.string.settings_troubleshooting_menu_content_description)
|
||||
)
|
||||
}
|
||||
|
||||
DropdownMenu(
|
||||
expanded = expanded,
|
||||
onDismissRequest = { expanded = false }
|
||||
) {
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(id = R.string.settings_troubleshooting_enable_background_sync)) },
|
||||
onClick = {
|
||||
onBackgroundSyncSettingsChanged(!troubleshootParams.isBackgroundSyncEnabled)
|
||||
expanded = false
|
||||
},
|
||||
leadingIcon = { AddIcon(troubleshootParams.isBackgroundSyncEnabled) }
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(id = R.string.settings_troubleshooting_enable_keep_screen_on)) },
|
||||
onClick = {
|
||||
onKeepScreenOnDuringSyncSettingsChanged(!troubleshootParams.isKeepScreenOnDuringSyncEnabled)
|
||||
expanded = false
|
||||
},
|
||||
leadingIcon = { AddIcon(troubleshootParams.isKeepScreenOnDuringSyncEnabled) }
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(id = R.string.settings_troubleshooting_enable_analytics)) },
|
||||
onClick = {
|
||||
onAnalyticsSettingsChanged(!troubleshootParams.isAnalyticsEnabled)
|
||||
expanded = false
|
||||
},
|
||||
leadingIcon = { AddIcon(troubleshootParams.isAnalyticsEnabled) }
|
||||
)
|
||||
// isRescanEnabled means if this feature should be visible, not whether it is enabled as in the case of
|
||||
// the previous booleans
|
||||
if (troubleshootParams.isRescanEnabled) {
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(id = R.string.settings_troubleshooting_rescan)) },
|
||||
onClick = {
|
||||
onRescanWallet()
|
||||
expanded = false
|
||||
},
|
||||
leadingIcon = { AddIcon(true) }
|
||||
)
|
||||
}
|
||||
}
|
||||
private fun PreviewSettings() {
|
||||
ZcashTheme {
|
||||
Settings(
|
||||
state =
|
||||
SettingsState(
|
||||
isLoading = false,
|
||||
version = stringRes("Version 1.2"),
|
||||
settingsTroubleshootingState = null,
|
||||
onBack = {},
|
||||
onAdvancedSettingsClick = {},
|
||||
onAboutUsClick = {},
|
||||
onSendUsFeedbackClick = {},
|
||||
),
|
||||
topAppBarSubTitleState = TopAppBarSubTitleState.None,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UnusedPrivateMember")
|
||||
@PreviewScreens
|
||||
@Composable
|
||||
private fun SettingsMainContent(
|
||||
onAbout: () -> Unit,
|
||||
onAdvancedSettings: () -> Unit,
|
||||
onFeedback: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Column(
|
||||
Modifier
|
||||
.fillMaxHeight()
|
||||
.fillMaxWidth()
|
||||
.then(modifier),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
PrimaryButton(
|
||||
onClick = onFeedback,
|
||||
text = stringResource(R.string.settings_send_us_feedback),
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
private fun PreviewSettingsLoading() {
|
||||
ZcashTheme {
|
||||
Settings(
|
||||
state =
|
||||
SettingsState(
|
||||
isLoading = true,
|
||||
version = stringRes("Version 1.2"),
|
||||
settingsTroubleshootingState = null,
|
||||
onBack = {},
|
||||
onAdvancedSettingsClick = {},
|
||||
onAboutUsClick = {},
|
||||
onSendUsFeedbackClick = {},
|
||||
),
|
||||
topAppBarSubTitleState = TopAppBarSubTitleState.None,
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(dimens.spacingDefault))
|
||||
|
||||
PrimaryButton(
|
||||
onClick = onAdvancedSettings,
|
||||
text = stringResource(R.string.settings_advanced_settings),
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
|
||||
Spacer(
|
||||
modifier =
|
||||
Modifier
|
||||
.fillMaxHeight()
|
||||
.weight(MINIMAL_WEIGHT)
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(dimens.spacingDefault))
|
||||
|
||||
PrimaryButton(
|
||||
onClick = onAbout,
|
||||
text = stringResource(R.string.settings_about),
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(dimens.spacingHuge))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,42 +5,124 @@ import androidx.lifecycle.viewModelScope
|
|||
import cash.z.ecc.sdk.ANDROID_STATE_FLOW_TIMEOUT
|
||||
import co.electriccoin.zcash.preference.StandardPreferenceProvider
|
||||
import co.electriccoin.zcash.preference.model.entry.BooleanPreferenceDefault
|
||||
import co.electriccoin.zcash.ui.NavigationTargets.ABOUT
|
||||
import co.electriccoin.zcash.ui.NavigationTargets.ADVANCED_SETTINGS
|
||||
import co.electriccoin.zcash.ui.NavigationTargets.SUPPORT
|
||||
import co.electriccoin.zcash.ui.R
|
||||
import co.electriccoin.zcash.ui.common.provider.GetVersionInfoProvider
|
||||
import co.electriccoin.zcash.ui.common.usecase.ObserveConfigurationUseCase
|
||||
import co.electriccoin.zcash.ui.common.usecase.RescanBlockchainUseCase
|
||||
import co.electriccoin.zcash.ui.configuration.ConfigurationEntries
|
||||
import co.electriccoin.zcash.ui.design.util.stringRes
|
||||
import co.electriccoin.zcash.ui.preference.StandardPreferenceKeys
|
||||
import co.electriccoin.zcash.ui.screen.settings.model.SettingsState
|
||||
import co.electriccoin.zcash.ui.screen.settings.model.SettingsTroubleshootingState
|
||||
import co.electriccoin.zcash.ui.screen.settings.model.TroubleshootingItemState
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.WhileSubscribed
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.emitAll
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class SettingsViewModel(
|
||||
observeConfiguration: ObserveConfigurationUseCase,
|
||||
private val standardPreferenceProvider: StandardPreferenceProvider,
|
||||
private val getVersionInfo: GetVersionInfoProvider,
|
||||
private val rescanBlockchain: RescanBlockchainUseCase
|
||||
) : ViewModel() {
|
||||
val isAnalyticsEnabled: StateFlow<Boolean?> = booleanStateFlow(StandardPreferenceKeys.IS_ANALYTICS_ENABLED)
|
||||
private val versionInfo by lazy { getVersionInfo() }
|
||||
|
||||
val isBackgroundSync: StateFlow<Boolean?> = booleanStateFlow(StandardPreferenceKeys.IS_BACKGROUND_SYNC_ENABLED)
|
||||
|
||||
val isKeepScreenOnWhileSyncing: StateFlow<Boolean?> =
|
||||
private val isAnalyticsEnabled = booleanStateFlow(StandardPreferenceKeys.IS_ANALYTICS_ENABLED)
|
||||
private val isBackgroundSyncEnabled = booleanStateFlow(StandardPreferenceKeys.IS_BACKGROUND_SYNC_ENABLED)
|
||||
private val isKeepScreenOnWhileSyncingEnabled =
|
||||
booleanStateFlow(StandardPreferenceKeys.IS_KEEP_SCREEN_ON_DURING_SYNC)
|
||||
|
||||
private fun booleanStateFlow(default: BooleanPreferenceDefault): StateFlow<Boolean?> =
|
||||
flow<Boolean?> {
|
||||
emitAll(default.observe(standardPreferenceProvider()))
|
||||
private val isLoading =
|
||||
combine(
|
||||
isAnalyticsEnabled,
|
||||
isBackgroundSyncEnabled,
|
||||
isKeepScreenOnWhileSyncingEnabled
|
||||
) { isAnalyticsEnabled, isBackgroundSync, isKeepScreenOnWhileSyncing ->
|
||||
isAnalyticsEnabled == null || isBackgroundSync == null || isKeepScreenOnWhileSyncing == null
|
||||
}.distinctUntilChanged()
|
||||
|
||||
@Suppress("ComplexCondition")
|
||||
private val troubleshootingState =
|
||||
combine(
|
||||
observeConfiguration(),
|
||||
isAnalyticsEnabled,
|
||||
isBackgroundSyncEnabled,
|
||||
isKeepScreenOnWhileSyncingEnabled
|
||||
) { configuration, isAnalyticsEnabled, isBackgroundSyncEnabled, isKeepScreenOnWhileSyncingEnabled ->
|
||||
if (configuration != null &&
|
||||
isAnalyticsEnabled != null &&
|
||||
isBackgroundSyncEnabled != null &&
|
||||
isKeepScreenOnWhileSyncingEnabled != null &&
|
||||
versionInfo.isDebuggable &&
|
||||
!versionInfo.isRunningUnderTestService
|
||||
) {
|
||||
SettingsTroubleshootingState(
|
||||
backgroundSync =
|
||||
TroubleshootingItemState(
|
||||
isBackgroundSyncEnabled
|
||||
) { setBackgroundSyncEnabled(isBackgroundSyncEnabled.not()) },
|
||||
keepScreenOnDuringSync =
|
||||
TroubleshootingItemState(
|
||||
isKeepScreenOnWhileSyncingEnabled
|
||||
) { setKeepScreenOnWhileSyncing(isKeepScreenOnWhileSyncingEnabled.not()) },
|
||||
analytics =
|
||||
TroubleshootingItemState(
|
||||
isAnalyticsEnabled
|
||||
) { setAnalyticsEnabled(isAnalyticsEnabled.not()) },
|
||||
rescan =
|
||||
TroubleshootingItemState(
|
||||
ConfigurationEntries.IS_RESCAN_ENABLED.getValue(configuration),
|
||||
::onRescanBlockchainClick
|
||||
)
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
val state: StateFlow<SettingsState?> =
|
||||
combine(isLoading, troubleshootingState) { isLoading, troubleshootingState ->
|
||||
SettingsState(
|
||||
isLoading = isLoading,
|
||||
version = stringRes(R.string.settings_version, getVersionInfo().versionName),
|
||||
settingsTroubleshootingState = troubleshootingState,
|
||||
onBack = ::onBack,
|
||||
onAdvancedSettingsClick = ::onAdvancedSettingsClick,
|
||||
onAboutUsClick = ::onAboutUsClick,
|
||||
onSendUsFeedbackClick = ::onSendUsFeedbackClick,
|
||||
)
|
||||
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(ANDROID_STATE_FLOW_TIMEOUT), null)
|
||||
|
||||
fun setAnalyticsEnabled(enabled: Boolean) {
|
||||
val navigationCommand = MutableSharedFlow<String>()
|
||||
val backNavigationCommand = MutableSharedFlow<Unit>()
|
||||
|
||||
private fun setAnalyticsEnabled(enabled: Boolean) {
|
||||
setBooleanPreference(StandardPreferenceKeys.IS_ANALYTICS_ENABLED, enabled)
|
||||
}
|
||||
|
||||
fun setBackgroundSyncEnabled(enabled: Boolean) {
|
||||
private fun setBackgroundSyncEnabled(enabled: Boolean) {
|
||||
setBooleanPreference(StandardPreferenceKeys.IS_BACKGROUND_SYNC_ENABLED, enabled)
|
||||
}
|
||||
|
||||
fun setKeepScreenOnWhileSyncing(enabled: Boolean) {
|
||||
private fun setKeepScreenOnWhileSyncing(enabled: Boolean) {
|
||||
setBooleanPreference(StandardPreferenceKeys.IS_KEEP_SCREEN_ON_DURING_SYNC, enabled)
|
||||
}
|
||||
|
||||
private fun onRescanBlockchainClick() =
|
||||
viewModelScope.launch {
|
||||
rescanBlockchain()
|
||||
}
|
||||
|
||||
private fun setBooleanPreference(
|
||||
default: BooleanPreferenceDefault,
|
||||
newState: Boolean
|
||||
|
@ -49,4 +131,29 @@ class SettingsViewModel(
|
|||
default.putValue(standardPreferenceProvider(), newState)
|
||||
}
|
||||
}
|
||||
|
||||
fun onBack() =
|
||||
viewModelScope.launch {
|
||||
backNavigationCommand.emit(Unit)
|
||||
}
|
||||
|
||||
private fun onAdvancedSettingsClick() =
|
||||
viewModelScope.launch {
|
||||
navigationCommand.emit(ADVANCED_SETTINGS)
|
||||
}
|
||||
|
||||
private fun onAboutUsClick() =
|
||||
viewModelScope.launch {
|
||||
navigationCommand.emit(ABOUT)
|
||||
}
|
||||
|
||||
private fun onSendUsFeedbackClick() =
|
||||
viewModelScope.launch {
|
||||
navigationCommand.emit(SUPPORT)
|
||||
}
|
||||
|
||||
private fun booleanStateFlow(default: BooleanPreferenceDefault): StateFlow<Boolean?> =
|
||||
flow<Boolean?> {
|
||||
emitAll(default.observe(standardPreferenceProvider()))
|
||||
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(ANDROID_STATE_FLOW_TIMEOUT), null)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="40dp"
|
||||
android:height="40dp"
|
||||
android:viewportWidth="40"
|
||||
android:viewportHeight="40">
|
||||
<path
|
||||
android:pathData="M0,20C0,8.954 8.954,0 20,0C31.046,0 40,8.954 40,20C40,31.046 31.046,40 20,40C8.954,40 0,31.046 0,20Z"
|
||||
android:fillColor="#EBEBE6"/>
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M10,10h20v20h-20z"/>
|
||||
<path
|
||||
android:pathData="M20,22.5C21.381,22.5 22.5,21.381 22.5,20C22.5,18.619 21.381,17.5 20,17.5C18.619,17.5 17.5,18.619 17.5,20C17.5,21.381 18.619,22.5 20,22.5Z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="1.66667"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#231F20"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M25.606,22.273C25.505,22.501 25.475,22.755 25.52,23C25.564,23.246 25.681,23.473 25.856,23.652L25.902,23.697C26.042,23.838 26.154,24.005 26.23,24.189C26.307,24.373 26.346,24.57 26.346,24.769C26.346,24.968 26.307,25.165 26.23,25.349C26.154,25.533 26.042,25.7 25.902,25.841C25.761,25.982 25.594,26.094 25.41,26.17C25.226,26.246 25.029,26.285 24.83,26.285C24.63,26.285 24.433,26.246 24.249,26.17C24.065,26.094 23.898,25.982 23.757,25.841L23.712,25.795C23.534,25.621 23.307,25.504 23.061,25.459C22.815,25.414 22.562,25.445 22.333,25.545C22.109,25.641 21.918,25.801 21.784,26.004C21.649,26.207 21.577,26.446 21.576,26.689V26.818C21.576,27.22 21.416,27.605 21.132,27.889C20.848,28.174 20.462,28.333 20.061,28.333C19.659,28.333 19.273,28.174 18.989,27.889C18.705,27.605 18.545,27.22 18.545,26.818V26.75C18.539,26.499 18.458,26.256 18.313,26.052C18.167,25.848 17.963,25.693 17.727,25.606C17.499,25.505 17.245,25.475 17,25.52C16.754,25.564 16.527,25.681 16.348,25.856L16.303,25.902C16.162,26.042 15.995,26.154 15.811,26.23C15.627,26.307 15.43,26.346 15.231,26.346C15.032,26.346 14.835,26.307 14.651,26.23C14.467,26.154 14.3,26.042 14.159,25.902C14.018,25.761 13.906,25.594 13.83,25.41C13.754,25.226 13.715,25.029 13.715,24.83C13.715,24.63 13.754,24.433 13.83,24.249C13.906,24.065 14.018,23.898 14.159,23.757L14.205,23.712C14.379,23.534 14.496,23.307 14.541,23.061C14.585,22.815 14.555,22.562 14.455,22.333C14.358,22.109 14.199,21.918 13.996,21.784C13.792,21.649 13.554,21.577 13.311,21.576H13.182C12.78,21.576 12.394,21.416 12.11,21.132C11.826,20.848 11.667,20.462 11.667,20.061C11.667,19.659 11.826,19.273 12.11,18.989C12.394,18.705 12.78,18.545 13.182,18.545H13.25C13.501,18.539 13.744,18.458 13.948,18.313C14.152,18.167 14.307,17.963 14.394,17.727C14.495,17.499 14.525,17.245 14.48,17C14.436,16.754 14.318,16.527 14.144,16.348L14.098,16.303C13.958,16.162 13.846,15.995 13.77,15.811C13.693,15.627 13.654,15.43 13.654,15.231C13.654,15.032 13.693,14.835 13.77,14.651C13.846,14.467 13.958,14.3 14.098,14.159C14.239,14.018 14.406,13.906 14.59,13.83C14.774,13.754 14.971,13.715 15.17,13.715C15.37,13.715 15.567,13.754 15.751,13.83C15.935,13.906 16.102,14.018 16.242,14.159L16.288,14.205C16.466,14.379 16.693,14.496 16.939,14.541C17.185,14.585 17.438,14.555 17.667,14.455H17.727C17.951,14.358 18.142,14.199 18.277,13.996C18.412,13.792 18.484,13.554 18.485,13.311V13.182C18.485,12.78 18.644,12.394 18.929,12.11C19.213,11.826 19.598,11.667 20,11.667C20.402,11.667 20.787,11.826 21.071,12.11C21.355,12.394 21.515,12.78 21.515,13.182V13.25C21.516,13.494 21.588,13.732 21.723,13.935C21.858,14.138 22.049,14.298 22.273,14.394C22.501,14.495 22.755,14.525 23,14.48C23.246,14.436 23.473,14.318 23.652,14.144L23.697,14.098C23.838,13.958 24.005,13.846 24.189,13.77C24.373,13.693 24.57,13.654 24.769,13.654C24.968,13.654 25.165,13.693 25.349,13.77C25.533,13.846 25.7,13.958 25.841,14.098C25.982,14.239 26.094,14.406 26.17,14.59C26.246,14.774 26.285,14.971 26.285,15.17C26.285,15.37 26.246,15.567 26.17,15.751C26.094,15.935 25.982,16.102 25.841,16.242L25.795,16.288C25.621,16.466 25.504,16.693 25.459,16.939C25.414,17.185 25.445,17.438 25.545,17.667V17.727C25.641,17.951 25.801,18.142 26.004,18.277C26.207,18.412 26.446,18.484 26.689,18.485H26.818C27.22,18.485 27.605,18.644 27.889,18.929C28.174,19.213 28.333,19.598 28.333,20C28.333,20.402 28.174,20.787 27.889,21.071C27.605,21.355 27.22,21.515 26.818,21.515H26.75C26.506,21.516 26.268,21.588 26.065,21.723C25.861,21.858 25.702,22.049 25.606,22.273Z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="1.66667"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#231F20"
|
||||
android:strokeLineCap="round"/>
|
||||
</group>
|
||||
</vector>
|
|
@ -0,0 +1,16 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="40dp"
|
||||
android:height="40dp"
|
||||
android:viewportWidth="40"
|
||||
android:viewportHeight="40">
|
||||
<path
|
||||
android:pathData="M0,20C0,8.954 8.954,0 20,0C31.046,0 40,8.954 40,20C40,31.046 31.046,40 20,40C8.954,40 0,31.046 0,20Z"
|
||||
android:fillColor="#EBEBE6"/>
|
||||
<path
|
||||
android:pathData="M15,16.667H15.008M15,23.333H15.008M15,20H25M15,20C13.159,20 11.667,18.508 11.667,16.667C11.667,14.826 13.159,13.333 15,13.333H25C26.841,13.333 28.333,14.826 28.333,16.667C28.333,18.508 26.841,20 25,20M15,20C13.159,20 11.667,21.492 11.667,23.333C11.667,25.174 13.159,26.667 15,26.667H25C26.841,26.667 28.333,25.174 28.333,23.333C28.333,21.492 26.841,20 25,20"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="1.66667"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#231F20"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
|
@ -0,0 +1,16 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="40dp"
|
||||
android:height="40dp"
|
||||
android:viewportWidth="40"
|
||||
android:viewportHeight="40">
|
||||
<path
|
||||
android:pathData="M0,20C0,8.954 8.954,0 20,0C31.046,0 40,8.954 40,20C40,31.046 31.046,40 20,40C8.954,40 0,31.046 0,20Z"
|
||||
android:fillColor="#454243"/>
|
||||
<path
|
||||
android:pathData="M15,16.667H15.008M15,23.333H15.008M15,20H25M15,20C13.159,20 11.667,18.508 11.667,16.667C11.667,14.826 13.159,13.333 15,13.333H25C26.841,13.333 28.333,14.826 28.333,16.667C28.333,18.508 26.841,20 25,20M15,20C13.159,20 11.667,21.492 11.667,23.333C11.667,25.174 13.159,26.667 15,26.667H25C26.841,26.667 28.333,25.174 28.333,23.333C28.333,21.492 26.841,20 25,20"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="1.66667"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#E8E8E8"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
|
@ -0,0 +1,16 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="40dp"
|
||||
android:height="40dp"
|
||||
android:viewportWidth="40"
|
||||
android:viewportHeight="40">
|
||||
<path
|
||||
android:pathData="M0,20C0,8.954 8.954,0 20,0C31.046,0 40,8.954 40,20C40,31.046 31.046,40 20,40C8.954,40 0,31.046 0,20Z"
|
||||
android:fillColor="#EBEBE6"/>
|
||||
<path
|
||||
android:pathData="M15,23.333C15,25.174 16.492,26.667 18.333,26.667H21.667C23.508,26.667 25,25.174 25,23.333C25,21.492 23.508,20 21.667,20H18.333C16.492,20 15,18.508 15,16.667C15,14.826 16.492,13.333 18.333,13.333H21.667C23.508,13.333 25,14.826 25,16.667M20,11.667V28.333"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="1.66667"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#231F20"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
|
@ -0,0 +1,16 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="40dp"
|
||||
android:height="40dp"
|
||||
android:viewportWidth="40"
|
||||
android:viewportHeight="40">
|
||||
<path
|
||||
android:pathData="M0,20C0,8.954 8.954,0 20,0C31.046,0 40,8.954 40,20C40,31.046 31.046,40 20,40C8.954,40 0,31.046 0,20Z"
|
||||
android:fillColor="#454243"/>
|
||||
<path
|
||||
android:pathData="M15,23.333C15,25.174 16.492,26.667 18.333,26.667H21.667C23.508,26.667 25,25.174 25,23.333C25,21.492 23.508,20 21.667,20H18.333C16.492,20 15,18.508 15,16.667C15,14.826 16.492,13.333 18.333,13.333H21.667C23.508,13.333 25,14.826 25,16.667M20,11.667V28.333"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="1.66667"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#E8E8E8"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
|
@ -0,0 +1,27 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="40dp"
|
||||
android:height="40dp"
|
||||
android:viewportWidth="40"
|
||||
android:viewportHeight="40">
|
||||
<path
|
||||
android:pathData="M0,20C0,8.954 8.954,0 20,0C31.046,0 40,8.954 40,20C40,31.046 31.046,40 20,40C8.954,40 0,31.046 0,20Z"
|
||||
android:fillColor="#454243"/>
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M10,10h20v20h-20z"/>
|
||||
<path
|
||||
android:pathData="M20,22.5C21.381,22.5 22.5,21.381 22.5,20C22.5,18.619 21.381,17.5 20,17.5C18.619,17.5 17.5,18.619 17.5,20C17.5,21.381 18.619,22.5 20,22.5Z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="1.66667"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#E8E8E8"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M25.606,22.273C25.505,22.501 25.475,22.755 25.52,23C25.564,23.246 25.681,23.473 25.856,23.652L25.902,23.697C26.042,23.838 26.154,24.005 26.23,24.189C26.307,24.373 26.346,24.57 26.346,24.769C26.346,24.968 26.307,25.165 26.23,25.349C26.154,25.533 26.042,25.7 25.902,25.841C25.761,25.982 25.594,26.094 25.41,26.17C25.226,26.246 25.029,26.285 24.83,26.285C24.63,26.285 24.433,26.246 24.249,26.17C24.065,26.094 23.898,25.982 23.758,25.841L23.712,25.795C23.534,25.621 23.307,25.504 23.061,25.459C22.815,25.414 22.562,25.445 22.333,25.545C22.109,25.641 21.918,25.801 21.784,26.004C21.649,26.207 21.577,26.446 21.576,26.689V26.818C21.576,27.22 21.416,27.605 21.132,27.889C20.848,28.174 20.462,28.333 20.061,28.333C19.659,28.333 19.273,28.174 18.989,27.889C18.705,27.605 18.545,27.22 18.545,26.818V26.75C18.54,26.499 18.458,26.256 18.313,26.052C18.167,25.848 17.963,25.693 17.727,25.606C17.499,25.505 17.245,25.475 17,25.52C16.754,25.564 16.527,25.681 16.348,25.856L16.303,25.902C16.162,26.042 15.995,26.154 15.811,26.23C15.627,26.307 15.43,26.346 15.231,26.346C15.032,26.346 14.835,26.307 14.651,26.23C14.467,26.154 14.3,26.042 14.159,25.902C14.018,25.761 13.906,25.594 13.83,25.41C13.754,25.226 13.715,25.029 13.715,24.83C13.715,24.63 13.754,24.433 13.83,24.249C13.906,24.065 14.018,23.898 14.159,23.757L14.205,23.712C14.379,23.534 14.496,23.307 14.541,23.061C14.585,22.815 14.555,22.562 14.455,22.333C14.358,22.109 14.199,21.918 13.996,21.784C13.793,21.649 13.554,21.577 13.311,21.576H13.182C12.78,21.576 12.395,21.416 12.11,21.132C11.826,20.848 11.667,20.462 11.667,20.061C11.667,19.659 11.826,19.273 12.11,18.989C12.395,18.705 12.78,18.545 13.182,18.545H13.25C13.501,18.539 13.744,18.458 13.948,18.313C14.152,18.167 14.307,17.963 14.394,17.727C14.495,17.499 14.525,17.245 14.48,17C14.436,16.754 14.319,16.527 14.144,16.348L14.099,16.303C13.958,16.162 13.846,15.995 13.77,15.811C13.693,15.627 13.654,15.43 13.654,15.231C13.654,15.032 13.693,14.835 13.77,14.651C13.846,14.467 13.958,14.3 14.099,14.159C14.239,14.018 14.406,13.906 14.59,13.83C14.774,13.754 14.971,13.715 15.17,13.715C15.37,13.715 15.567,13.754 15.751,13.83C15.935,13.906 16.102,14.018 16.242,14.159L16.288,14.205C16.466,14.379 16.693,14.496 16.939,14.541C17.185,14.585 17.438,14.555 17.667,14.455H17.727C17.951,14.358 18.142,14.199 18.277,13.996C18.412,13.792 18.484,13.554 18.485,13.311V13.182C18.485,12.78 18.645,12.394 18.929,12.11C19.213,11.826 19.598,11.667 20,11.667C20.402,11.667 20.787,11.826 21.071,12.11C21.355,12.394 21.515,12.78 21.515,13.182V13.25C21.516,13.494 21.588,13.732 21.723,13.935C21.858,14.138 22.049,14.298 22.273,14.394C22.501,14.495 22.755,14.525 23,14.48C23.246,14.436 23.473,14.318 23.652,14.144L23.697,14.098C23.838,13.958 24.005,13.846 24.189,13.77C24.373,13.693 24.57,13.654 24.769,13.654C24.968,13.654 25.165,13.693 25.349,13.77C25.533,13.846 25.7,13.958 25.841,14.098C25.982,14.239 26.094,14.406 26.17,14.59C26.246,14.774 26.285,14.971 26.285,15.17C26.285,15.37 26.246,15.567 26.17,15.751C26.094,15.935 25.982,16.102 25.841,16.242L25.795,16.288C25.621,16.466 25.504,16.693 25.459,16.939C25.414,17.185 25.445,17.438 25.545,17.667V17.727C25.642,17.951 25.801,18.142 26.004,18.277C26.207,18.412 26.446,18.484 26.689,18.485H26.818C27.22,18.485 27.605,18.644 27.89,18.929C28.174,19.213 28.333,19.598 28.333,20C28.333,20.402 28.174,20.787 27.89,21.071C27.605,21.355 27.22,21.515 26.818,21.515H26.75C26.506,21.516 26.268,21.588 26.065,21.723C25.862,21.858 25.702,22.049 25.606,22.273Z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="1.66667"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#E8E8E8"
|
||||
android:strokeLineCap="round"/>
|
||||
</group>
|
||||
</vector>
|
|
@ -0,0 +1,16 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="40dp"
|
||||
android:height="40dp"
|
||||
android:viewportWidth="40"
|
||||
android:viewportHeight="40">
|
||||
<path
|
||||
android:pathData="M0,20C0,8.954 8.954,0 20,0C31.046,0 40,8.954 40,20C40,31.046 31.046,40 20,40C8.954,40 0,31.046 0,20Z"
|
||||
android:fillColor="#EBEBE6"/>
|
||||
<path
|
||||
android:pathData="M13.333,23.535C12.328,22.862 11.667,21.717 11.667,20.417C11.667,18.464 13.16,16.859 15.066,16.683C15.457,14.31 17.517,12.5 20,12.5C22.483,12.5 24.544,14.31 24.934,16.683C26.84,16.859 28.333,18.464 28.333,20.417C28.333,21.717 27.672,22.862 26.667,23.535M16.667,24.167L20,27.5M20,27.5L23.333,24.167M20,27.5V20"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="1.66667"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#231F20"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
|
@ -0,0 +1,16 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="40dp"
|
||||
android:height="40dp"
|
||||
android:viewportWidth="40"
|
||||
android:viewportHeight="40">
|
||||
<path
|
||||
android:pathData="M0,20C0,8.954 8.954,0 20,0C31.046,0 40,8.954 40,20C40,31.046 31.046,40 20,40C8.954,40 0,31.046 0,20Z"
|
||||
android:fillColor="#454243"/>
|
||||
<path
|
||||
android:pathData="M13.333,23.535C12.328,22.862 11.667,21.717 11.667,20.417C11.667,18.464 13.16,16.859 15.066,16.683C15.457,14.31 17.517,12.5 20,12.5C22.483,12.5 24.544,14.31 24.934,16.683C26.84,16.859 28.333,18.464 28.333,20.417C28.333,21.717 27.672,22.862 26.667,23.535M16.667,24.167L20,27.5M20,27.5L23.333,24.167M20,27.5V20"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="1.66667"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#E8E8E8"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
|
@ -0,0 +1,17 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="20dp"
|
||||
android:height="20dp"
|
||||
android:viewportWidth="20"
|
||||
android:viewportHeight="20">
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M0,0h20v20h-20z"/>
|
||||
<path
|
||||
android:pathData="M10,13.333V10M10,6.667H10.008M18.333,10C18.333,14.602 14.602,18.333 10,18.333C5.398,18.333 1.667,14.602 1.667,10C1.667,5.398 5.398,1.667 10,1.667C14.602,1.667 18.333,5.398 18.333,10Z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="1.66667"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#716C5D"
|
||||
android:strokeLineCap="round"/>
|
||||
</group>
|
||||
</vector>
|
|
@ -0,0 +1,16 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="40dp"
|
||||
android:height="40dp"
|
||||
android:viewportWidth="40"
|
||||
android:viewportHeight="40">
|
||||
<path
|
||||
android:pathData="M0,20C0,8.954 8.954,0 20,0C31.046,0 40,8.954 40,20C40,31.046 31.046,40 20,40C8.954,40 0,31.046 0,20Z"
|
||||
android:fillColor="#EBEBE6"/>
|
||||
<path
|
||||
android:pathData="M24.167,17.5C24.167,17.073 24.004,16.647 23.678,16.322C23.353,15.996 22.927,15.833 22.5,15.833M22.5,22.5C25.261,22.5 27.5,20.261 27.5,17.5C27.5,14.739 25.261,12.5 22.5,12.5C19.739,12.5 17.5,14.739 17.5,17.5C17.5,17.728 17.515,17.953 17.545,18.173C17.594,18.534 17.618,18.715 17.601,18.83C17.584,18.949 17.563,19.013 17.504,19.118C17.448,19.219 17.348,19.319 17.149,19.517L12.891,23.776C12.746,23.92 12.674,23.992 12.623,24.076C12.577,24.151 12.543,24.232 12.523,24.317C12.5,24.413 12.5,24.515 12.5,24.719V26.167C12.5,26.633 12.5,26.867 12.591,27.045C12.671,27.202 12.798,27.329 12.955,27.409C13.133,27.5 13.367,27.5 13.833,27.5H15.833V25.833H17.5V24.167H19.167L20.483,22.851C20.681,22.652 20.781,22.552 20.882,22.496C20.987,22.437 21.051,22.416 21.17,22.399C21.285,22.382 21.466,22.406 21.827,22.455C22.047,22.485 22.272,22.5 22.5,22.5Z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="1.66667"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#231F20"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
|
@ -0,0 +1,16 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="40dp"
|
||||
android:height="40dp"
|
||||
android:viewportWidth="40"
|
||||
android:viewportHeight="40">
|
||||
<path
|
||||
android:pathData="M0,20C0,8.954 8.954,0 20,0C31.046,0 40,8.954 40,20C40,31.046 31.046,40 20,40C8.954,40 0,31.046 0,20Z"
|
||||
android:fillColor="#454243"/>
|
||||
<path
|
||||
android:pathData="M24.167,17.5C24.167,17.073 24.004,16.647 23.678,16.322C23.353,15.996 22.927,15.833 22.5,15.833M22.5,22.5C25.261,22.5 27.5,20.261 27.5,17.5C27.5,14.739 25.261,12.5 22.5,12.5C19.739,12.5 17.5,14.739 17.5,17.5C17.5,17.728 17.515,17.953 17.545,18.173C17.594,18.534 17.618,18.715 17.601,18.83C17.584,18.949 17.563,19.013 17.504,19.118C17.448,19.219 17.348,19.319 17.149,19.517L12.891,23.776C12.746,23.92 12.674,23.992 12.623,24.076C12.577,24.151 12.543,24.232 12.523,24.317C12.5,24.413 12.5,24.515 12.5,24.719V26.167C12.5,26.633 12.5,26.867 12.591,27.045C12.671,27.202 12.798,27.329 12.955,27.409C13.133,27.5 13.367,27.5 13.833,27.5H15.833V25.833H17.5V24.167H19.167L20.483,22.851C20.681,22.652 20.781,22.552 20.882,22.496C20.987,22.437 21.051,22.416 21.17,22.399C21.285,22.382 21.466,22.406 21.827,22.455C22.047,22.485 22.272,22.5 22.5,22.5Z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="1.66667"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#E8E8E8"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
|
@ -1,11 +1,10 @@
|
|||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="advanced_settings_backup_wallet">Recovery phrase</string>
|
||||
<string name="advanced_settings_export_private_data">Export private data</string>
|
||||
<string name="advanced_settings_choose_server">Choose a server</string>
|
||||
<string name="advanced_settings_title">Advanced Settings</string>
|
||||
<string name="advanced_settings_recovery">Recovery Phrase</string>
|
||||
<string name="advanced_settings_export">Export Private Data</string>
|
||||
<string name="advanced_settings_choose_server">Choose a Server</string>
|
||||
<string name="advanced_settings_currency_conversion">Currency Conversion</string>
|
||||
|
||||
<string name="advanced_settings_delete_wallet">
|
||||
Delete <xliff:g id="app_name" example="Zashi">%1$s</xliff:g>
|
||||
</string>
|
||||
<string name="advanced_settings_delete_wallet_footnote">(You will be asked to confirm on next screen)</string>
|
||||
<string name="advanced_settings_coinbase">Buy ZEC with Coinbase</string>
|
||||
<string name="advanced_settings_info">You will be asked to confirm on the next screen</string>
|
||||
<string name="advanced_settings_delete_button">Delete Zashi</string>
|
||||
</resources>
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="40dp"
|
||||
android:height="40dp"
|
||||
android:viewportWidth="40"
|
||||
android:viewportHeight="40">
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M0,0h40v40h-40z"/>
|
||||
<path
|
||||
android:pathData="M19.983,0.009C31.004,0.009 39.939,8.944 39.939,19.965C39.939,30.987 31.004,39.922 19.983,39.922C8.961,39.922 0.026,30.987 0.026,19.965C0.026,8.944 8.961,0.009 19.983,0.009Z"
|
||||
android:fillColor="#0052FF"/>
|
||||
<path
|
||||
android:pathData="M19.991,26.978C16.113,26.978 12.978,23.836 12.978,19.965C12.978,16.095 16.121,12.952 19.991,12.952C23.463,12.952 26.346,15.481 26.9,18.796H33.965C33.368,11.593 27.342,5.931 19.983,5.931C12.234,5.931 5.948,12.216 5.948,19.965C5.948,27.714 12.234,34 19.983,34C27.342,34 33.368,28.338 33.965,21.134H26.892C26.338,24.45 23.463,26.978 19.991,26.978Z"
|
||||
android:fillColor="#ffffff"/>
|
||||
</group>
|
||||
</vector>
|
|
@ -0,0 +1,16 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="40dp"
|
||||
android:height="40dp"
|
||||
android:viewportWidth="40"
|
||||
android:viewportHeight="40">
|
||||
<path
|
||||
android:pathData="M0,20C0,8.954 8.954,0 20,0C31.046,0 40,8.954 40,20C40,31.046 31.046,40 20,40C8.954,40 0,31.046 0,20Z"
|
||||
android:fillColor="#EBEBE6"/>
|
||||
<path
|
||||
android:pathData="M17.5,21.667C17.5,21.667 18.594,22.917 20.416,22.917C22.239,22.917 23.333,21.667 23.333,21.667M22.708,17.5H22.716M18.125,17.5H18.133M20.416,26.667C24.328,26.667 27.5,23.495 27.5,19.583C27.5,15.671 24.328,12.5 20.416,12.5C16.504,12.5 13.333,15.671 13.333,19.583C13.333,20.375 13.463,21.136 13.703,21.847C13.793,22.115 13.838,22.248 13.846,22.351C13.854,22.453 13.848,22.524 13.823,22.622C13.797,22.722 13.741,22.826 13.629,23.034L12.266,25.557C12.071,25.917 11.974,26.097 11.996,26.236C12.015,26.357 12.086,26.463 12.191,26.527C12.311,26.6 12.514,26.579 12.921,26.537L17.188,26.096C17.318,26.083 17.382,26.076 17.441,26.078C17.499,26.08 17.54,26.086 17.597,26.099C17.654,26.112 17.726,26.14 17.871,26.195C18.661,26.5 19.519,26.667 20.416,26.667ZM23.125,17.5C23.125,17.73 22.938,17.917 22.708,17.917C22.478,17.917 22.291,17.73 22.291,17.5C22.291,17.27 22.478,17.083 22.708,17.083C22.938,17.083 23.125,17.27 23.125,17.5ZM18.541,17.5C18.541,17.73 18.355,17.917 18.125,17.917C17.895,17.917 17.708,17.73 17.708,17.5C17.708,17.27 17.895,17.083 18.125,17.083C18.355,17.083 18.541,17.27 18.541,17.5Z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="1.66667"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#231F20"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
|
@ -0,0 +1,16 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="40dp"
|
||||
android:height="40dp"
|
||||
android:viewportWidth="40"
|
||||
android:viewportHeight="40">
|
||||
<path
|
||||
android:pathData="M0,20C0,8.954 8.954,0 20,0C31.046,0 40,8.954 40,20C40,31.046 31.046,40 20,40C8.954,40 0,31.046 0,20Z"
|
||||
android:fillColor="#454243"/>
|
||||
<path
|
||||
android:pathData="M17.5,21.667C17.5,21.667 18.593,22.917 20.416,22.917C22.239,22.917 23.333,21.667 23.333,21.667M22.708,17.5H22.716M18.125,17.5H18.133M20.416,26.667C24.328,26.667 27.5,23.495 27.5,19.583C27.5,15.671 24.328,12.5 20.416,12.5C16.504,12.5 13.333,15.671 13.333,19.583C13.333,20.375 13.463,21.136 13.703,21.847C13.793,22.115 13.838,22.248 13.846,22.351C13.854,22.453 13.848,22.524 13.823,22.622C13.797,22.722 13.741,22.826 13.629,23.034L12.266,25.557C12.071,25.917 11.974,26.097 11.996,26.236C12.015,26.357 12.086,26.463 12.191,26.527C12.311,26.6 12.514,26.579 12.921,26.537L17.188,26.096C17.318,26.083 17.382,26.076 17.441,26.078C17.499,26.08 17.54,26.086 17.597,26.099C17.654,26.112 17.726,26.14 17.871,26.195C18.661,26.5 19.519,26.667 20.416,26.667ZM23.125,17.5C23.125,17.73 22.938,17.917 22.708,17.917C22.478,17.917 22.291,17.73 22.291,17.5C22.291,17.27 22.478,17.083 22.708,17.083C22.938,17.083 23.125,17.27 23.125,17.5ZM18.541,17.5C18.541,17.73 18.355,17.917 18.125,17.917C17.895,17.917 17.708,17.73 17.708,17.5C17.708,17.27 17.895,17.083 18.125,17.083C18.355,17.083 18.541,17.27 18.541,17.5Z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="1.66667"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#E8E8E8"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
|
@ -0,0 +1,20 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="40dp"
|
||||
android:height="40dp"
|
||||
android:viewportWidth="40"
|
||||
android:viewportHeight="40">
|
||||
<path
|
||||
android:pathData="M0,20C0,8.954 8.954,0 20,0C31.046,0 40,8.954 40,20C40,31.046 31.046,40 20,40C8.954,40 0,31.046 0,20Z"
|
||||
android:fillColor="#EBEBE6"/>
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M10,10h20v20h-20z"/>
|
||||
<path
|
||||
android:pathData="M20,23.333V20M20,16.667H20.008M28.333,20C28.333,24.602 24.602,28.333 20,28.333C15.398,28.333 11.667,24.602 11.667,20C11.667,15.398 15.398,11.667 20,11.667C24.602,11.667 28.333,15.398 28.333,20Z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="1.66667"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#231F20"
|
||||
android:strokeLineCap="round"/>
|
||||
</group>
|
||||
</vector>
|
|
@ -0,0 +1,20 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="40dp"
|
||||
android:height="40dp"
|
||||
android:viewportWidth="40"
|
||||
android:viewportHeight="40">
|
||||
<path
|
||||
android:pathData="M0,20C0,8.954 8.954,0 20,0C31.046,0 40,8.954 40,20C40,31.046 31.046,40 20,40C8.954,40 0,31.046 0,20Z"
|
||||
android:fillColor="#454243"/>
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M10,10h20v20h-20z"/>
|
||||
<path
|
||||
android:pathData="M20,23.333V20M20,16.667H20.008M28.333,20C28.333,24.602 24.602,28.333 20,28.333C15.398,28.333 11.667,24.602 11.667,20C11.667,15.398 15.398,11.667 20,11.667C24.602,11.667 28.333,15.398 28.333,20Z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="1.66667"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#E8E8E8"
|
||||
android:strokeLineCap="round"/>
|
||||
</group>
|
||||
</vector>
|
|
@ -0,0 +1,21 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="75dp"
|
||||
android:height="20dp"
|
||||
android:viewportWidth="75"
|
||||
android:viewportHeight="20">
|
||||
<path
|
||||
android:pathData="M23.077,0.582L26.93,0.003L33.71,19.598L29.301,20M29.301,19.967L27.355,14.952L20.739,14.564L18.793,19.612L15.681,19.969L23.074,0.585M21.908,11.848L26.15,11.854L23.851,6.021L21.905,11.846L21.908,11.848Z"
|
||||
android:fillColor="#231F20"/>
|
||||
<path
|
||||
android:pathData="M41.265,19.969C38.305,19.969 35.584,19.104 34.024,17.021L37.775,13.857C38.885,15.281 39.904,16.209 41.623,16.893L45.043,16.86C45.36,16.253 45.493,15.674 45.493,15.12C45.493,13.328 44.541,12.773 41.001,12.086C36.959,11.321 34.474,9.872 34.474,6.6C34.474,5.414 35.082,3.99 36.031,2.962L42.267,0C44.882,0 47.817,0.903 49.375,2.987L45.621,6.151C44.51,4.727 43.403,3.832 41.684,3.145H38.461C38.169,3.646 38.011,4.201 38.011,4.755C38.011,6.442 39.199,6.969 43.03,7.656C47.364,8.368 49.055,9.95 49.055,13.089C49.055,14.275 48.528,15.672 47.656,16.965L41.262,19.966L41.265,19.969Z"
|
||||
android:fillColor="#231F20"/>
|
||||
<path
|
||||
android:pathData="M62.645,0.003L67.221,0.582V19.612L62.645,19.967V11.192L55.546,11.067V19.609L50.876,19.967V0.538L55.546,0.003V8.349L62.645,8.291V0.003Z"
|
||||
android:fillColor="#231F20"/>
|
||||
<path
|
||||
android:pathData="M69.559,0.529L74.228,0.005V19.969L69.559,19.614V0.529Z"
|
||||
android:fillColor="#231F20"/>
|
||||
<path
|
||||
android:pathData="M6.607,15.22H15.558L13.987,19.509H0.771V18.326L10.111,4.344H1.549L2.715,0.46H15.944"
|
||||
android:fillColor="#231F20"/>
|
||||
</vector>
|
|
@ -0,0 +1,21 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="75dp"
|
||||
android:height="20dp"
|
||||
android:viewportWidth="75"
|
||||
android:viewportHeight="20">
|
||||
<path
|
||||
android:pathData="M23.077,0.582L26.93,0.003L33.71,19.598L29.301,20M29.301,19.967L27.355,14.952L20.739,14.564L18.793,19.612L15.681,19.969L23.074,0.585M21.908,11.848L26.15,11.854L23.851,6.021L21.905,11.846L21.908,11.848Z"
|
||||
android:fillColor="#E8E8E8"/>
|
||||
<path
|
||||
android:pathData="M41.265,19.969C38.305,19.969 35.584,19.104 34.024,17.021L37.775,13.857C38.886,15.281 39.904,16.209 41.623,16.893L45.043,16.86C45.36,16.253 45.493,15.674 45.493,15.12C45.493,13.328 44.541,12.773 41.001,12.086C36.959,11.321 34.474,9.872 34.474,6.6C34.474,5.414 35.082,3.99 36.031,2.962L42.267,0C44.882,0 47.817,0.903 49.375,2.987L45.621,6.151C44.51,4.727 43.403,3.832 41.684,3.145H38.461C38.169,3.646 38.011,4.201 38.011,4.755C38.011,6.442 39.199,6.969 43.031,7.656C47.364,8.368 49.055,9.95 49.055,13.089C49.055,14.275 48.528,15.672 47.656,16.965L41.262,19.966L41.265,19.969Z"
|
||||
android:fillColor="#E8E8E8"/>
|
||||
<path
|
||||
android:pathData="M62.645,0.003L67.221,0.582V19.612L62.645,19.967V11.192L55.546,11.067V19.609L50.876,19.967V0.538L55.546,0.003V8.349L62.645,8.291V0.003Z"
|
||||
android:fillColor="#E8E8E8"/>
|
||||
<path
|
||||
android:pathData="M69.559,0.529L74.228,0.005V19.969L69.559,19.614V0.529Z"
|
||||
android:fillColor="#E8E8E8"/>
|
||||
<path
|
||||
android:pathData="M6.607,15.22H15.559L13.987,19.509H0.772V18.326L10.111,4.344H1.549L2.715,0.46H15.944"
|
||||
android:fillColor="#E8E8E8"/>
|
||||
</vector>
|
|
@ -1,11 +1,14 @@
|
|||
<resources>
|
||||
<string name="settings_title">Settings</string>
|
||||
<string name="settings_advanced_settings">Advanced Settings</string>
|
||||
<string name="settings_about_us">About Us</string>
|
||||
<string name="settings_feedback">Send Us Feedback</string>
|
||||
<string name="settings_version">Version %s</string>
|
||||
|
||||
<string name="settings_troubleshooting_menu_content_description">Additional settings</string>
|
||||
<string name="settings_troubleshooting_rescan">Rescan blockchain</string>
|
||||
<string name="settings_troubleshooting_enable_background_sync">Background sync</string>
|
||||
<string name="settings_troubleshooting_enable_keep_screen_on">Keep screen on during sync</string>
|
||||
<string name="settings_troubleshooting_enable_analytics">Report crashes</string>
|
||||
|
||||
<string name="settings_send_us_feedback">Send us feedback</string>
|
||||
<string name="settings_advanced_settings">Advanced</string>
|
||||
<string name="settings_about">About</string>
|
||||
</resources>
|
||||
|
|
|
@ -425,7 +425,7 @@ private fun settingsScreenshots(
|
|||
composeTestRule: ComposeTestRule
|
||||
) {
|
||||
composeTestRule.onNode(
|
||||
hasText(resContext.getString(R.string.settings_send_us_feedback), ignoreCase = true)
|
||||
hasText(resContext.getString(R.string.settings_feedback), ignoreCase = true)
|
||||
).also {
|
||||
it.assertExists()
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue