diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index ca9a68bd..46402a65 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -9,8 +9,7 @@
-
-
+
@@ -126,6 +125,7 @@
+
diff --git a/ui-design-lib/src/main/java/co/electriccoin/zcash/ui/design/component/Button.kt b/ui-design-lib/src/main/java/co/electriccoin/zcash/ui/design/component/Button.kt
index 015ec4cc..b569ff6f 100644
--- a/ui-design-lib/src/main/java/co/electriccoin/zcash/ui/design/component/Button.kt
+++ b/ui-design-lib/src/main/java/co/electriccoin/zcash/ui/design/component/Button.kt
@@ -21,6 +21,7 @@ import androidx.compose.ui.graphics.PaintingStyle
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
import androidx.compose.ui.graphics.toArgb
+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.dp
@@ -79,7 +80,12 @@ fun PrimaryButton(
),
onClick = onClick,
) {
- Text(text = text, color = textColor, style = MaterialTheme.typography.labelLarge)
+ Text(
+ style = ZcashTheme.extendedTypography.buttonText,
+ textAlign = TextAlign.Center,
+ text = text.uppercase(),
+ color = textColor
+ )
}
}
@@ -107,7 +113,8 @@ fun SecondaryButton(
) {
Text(
style = MaterialTheme.typography.labelLarge,
- text = text,
+ textAlign = TextAlign.Center,
+ text = text.uppercase(),
color = MaterialTheme.colorScheme.onSecondary
)
}
@@ -132,7 +139,12 @@ fun NavigationButton(
),
colors = buttonColors(containerColor = MaterialTheme.colorScheme.secondary)
) {
- Text(style = MaterialTheme.typography.labelLarge, text = text, color = MaterialTheme.colorScheme.onSecondary)
+ Text(
+ style = MaterialTheme.typography.labelLarge,
+ textAlign = TextAlign.Center,
+ text = text,
+ color = MaterialTheme.colorScheme.onSecondary
+ )
}
}
@@ -161,6 +173,7 @@ fun TertiaryButton(
) {
Text(
style = MaterialTheme.typography.labelLarge,
+ textAlign = TextAlign.Center,
text = text,
color = ZcashTheme.colors.onTertiary
)
@@ -189,6 +202,7 @@ fun DangerousButton(
) {
Text(
style = MaterialTheme.typography.labelLarge,
+ textAlign = TextAlign.Center,
text = text,
color = ZcashTheme.colors.onDangerous
)
diff --git a/ui-design-lib/src/main/java/co/electriccoin/zcash/ui/design/theme/ExtendedColors.kt b/ui-design-lib/src/main/java/co/electriccoin/zcash/ui/design/theme/ExtendedColors.kt
index 2357b485..a05806dc 100644
--- a/ui-design-lib/src/main/java/co/electriccoin/zcash/ui/design/theme/ExtendedColors.kt
+++ b/ui-design-lib/src/main/java/co/electriccoin/zcash/ui/design/theme/ExtendedColors.kt
@@ -30,6 +30,7 @@ data class ExtendedColors(
val disabledButtonColor: Color,
val disabledButtonTextColor: Color,
val buttonShadowColor: Color,
+ val screenTitleColor: Color,
) {
@Composable
fun surfaceGradient() = Brush.verticalGradient(
diff --git a/ui-design-lib/src/main/java/co/electriccoin/zcash/ui/design/theme/internal/Color.kt b/ui-design-lib/src/main/java/co/electriccoin/zcash/ui/design/theme/internal/Color.kt
index bcde5ebe..33b6a9d8 100644
--- a/ui-design-lib/src/main/java/co/electriccoin/zcash/ui/design/theme/internal/Color.kt
+++ b/ui-design-lib/src/main/java/co/electriccoin/zcash/ui/design/theme/internal/Color.kt
@@ -59,6 +59,9 @@ internal object Dark {
val disabledButtonTextColor = Color(0xFFDDDDDD)
val buttonShadowColor = Color(0xFFFFFFFF)
+
+ // to be added later for dark theme
+ val screenTitleColor = Color.Unspecified
}
internal object Light {
@@ -115,6 +118,8 @@ internal object Light {
val disabledButtonColor = Color(0xFFB7B7B7)
val disabledButtonTextColor = Color(0xFFDDDDDD)
val buttonShadowColor = Color(0xFF000000)
+
+ val screenTitleColor = Color(0xFF040404)
}
internal val DarkColorPalette = darkColorScheme(
@@ -162,7 +167,7 @@ internal val DarkExtendedColorPalette = ExtendedColors(
disabledButtonColor = Dark.disabledButtonColor,
reference = Dark.reference,
buttonShadowColor = Dark.buttonShadowColor,
-
+ screenTitleColor = Dark.screenTitleColor
)
internal val LightExtendedColorPalette = ExtendedColors(
@@ -187,7 +192,8 @@ internal val LightExtendedColorPalette = ExtendedColors(
disabledButtonTextColor = Light.disabledButtonTextColor,
disabledButtonColor = Light.disabledButtonColor,
reference = Light.reference,
- buttonShadowColor = Light.buttonShadowColor
+ buttonShadowColor = Light.buttonShadowColor,
+ screenTitleColor = Light.screenTitleColor,
)
@Suppress("CompositionLocalAllowlist")
@@ -215,5 +221,6 @@ internal val LocalExtendedColors = staticCompositionLocalOf {
disabledButtonColor = Color.Unspecified,
reference = Color.Unspecified,
buttonShadowColor = Color.Unspecified,
+ screenTitleColor = Color.Unspecified,
)
}
diff --git a/ui-design-lib/src/main/java/co/electriccoin/zcash/ui/design/theme/internal/Typography.kt b/ui-design-lib/src/main/java/co/electriccoin/zcash/ui/design/theme/internal/Typography.kt
index efb135f6..4ba9e058 100644
--- a/ui-design-lib/src/main/java/co/electriccoin/zcash/ui/design/theme/internal/Typography.kt
+++ b/ui-design-lib/src/main/java/co/electriccoin/zcash/ui/design/theme/internal/Typography.kt
@@ -49,6 +49,11 @@ internal val PrimaryTypography = Typography(
fontWeight = FontWeight.SemiBold,
fontSize = 30.sp
),
+ titleSmall = TextStyle(
+ fontFamily = InterFontFamily,
+ fontWeight = FontWeight.Bold,
+ fontSize = 14.sp
+ ),
bodyLarge = TextStyle(
fontFamily = InterFontFamily,
fontWeight = FontWeight.Normal,
@@ -99,7 +104,8 @@ data class Typography(
data class ExtendedTypography(
val chipIndex: TextStyle,
val listItem: TextStyle,
- val zecBalance: TextStyle
+ val zecBalance: TextStyle,
+ val buttonText: TextStyle,
)
@Suppress("CompositionLocalAllowlist")
@@ -125,6 +131,9 @@ val LocalExtendedTypography = staticCompositionLocalOf {
fontFamily = Zboto,
fontWeight = FontWeight.Normal,
fontSize = 30.sp
- )
+ ),
+ buttonText = PrimaryTypography.bodySmall.copy(
+ fontSize = 14.sp
+ ),
)
}
diff --git a/ui-lib/src/androidTest/java/co/electriccoin/zcash/ui/screen/settings/SettingsViewTestSetup.kt b/ui-lib/src/androidTest/java/co/electriccoin/zcash/ui/screen/settings/SettingsViewTestSetup.kt
new file mode 100644
index 00000000..39d57abd
--- /dev/null
+++ b/ui-lib/src/androidTest/java/co/electriccoin/zcash/ui/screen/settings/SettingsViewTestSetup.kt
@@ -0,0 +1,113 @@
+package co.electriccoin.zcash.ui.screen.settings
+
+import androidx.compose.ui.test.junit4.ComposeContentTestRule
+import co.electriccoin.zcash.ui.design.theme.ZcashTheme
+import co.electriccoin.zcash.ui.screen.settings.model.TroubleshootingParameters
+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
+) {
+ private val onBackCount = AtomicInteger(0)
+ private val onBackupCount = AtomicInteger(0)
+ private val onDocumentationCount = AtomicInteger(0)
+ private val onPrivacyPolicyCount = AtomicInteger(0)
+ private val onFeedbackCount = AtomicInteger(0)
+ private val onAboutCount = AtomicInteger(0)
+ private val onRescanCount = AtomicInteger(0)
+ private val onBackgroundSyncChangedCount = AtomicInteger(0)
+ private val onKeepScreenOnChangedCount = AtomicInteger(0)
+ private val onAnalyticsChangedCount = AtomicInteger(0)
+
+ fun getBackCount(): Int {
+ composeTestRule.waitForIdle()
+ return onBackCount.get()
+ }
+
+ fun getBackupCount(): Int {
+ composeTestRule.waitForIdle()
+ return onBackupCount.get()
+ }
+
+ fun getDocumentationCount(): Int {
+ composeTestRule.waitForIdle()
+ return onDocumentationCount.get()
+ }
+
+ fun getPrivacyPolicyCount(): Int {
+ composeTestRule.waitForIdle()
+ return onPrivacyPolicyCount.get()
+ }
+
+ fun getFeedbackCount(): Int {
+ composeTestRule.waitForIdle()
+ return onFeedbackCount.get()
+ }
+
+ fun getAboutCount(): Int {
+ composeTestRule.waitForIdle()
+ return onAboutCount.get()
+ }
+
+ fun getRescanCount(): Int {
+ composeTestRule.waitForIdle()
+ return onRescanCount.get()
+ }
+
+ fun getBackgroundSyncCount(): Int {
+ composeTestRule.waitForIdle()
+ return onBackgroundSyncChangedCount.get()
+ }
+
+ fun getKeepScreenOnSyncCount(): Int {
+ composeTestRule.waitForIdle()
+ return onKeepScreenOnChangedCount.get()
+ }
+
+ fun getAnalyticsCount(): Int {
+ composeTestRule.waitForIdle()
+ return onAnalyticsChangedCount.get()
+ }
+
+ init {
+ composeTestRule.setContent {
+ ZcashTheme {
+ Settings(
+ troubleshootingParameters = troubleshootingParameters,
+ onBack = {
+ onBackCount.incrementAndGet()
+ },
+ onBackup = {
+ onBackupCount.incrementAndGet()
+ },
+ onDocumentation = {
+ onDocumentationCount.incrementAndGet()
+ },
+ onPrivacyPolicy = {
+ onPrivacyPolicyCount.incrementAndGet()
+ },
+ onFeedback = {
+ onFeedbackCount.incrementAndGet()
+ },
+ onAbout = {
+ onAboutCount.incrementAndGet()
+ },
+ onRescanWallet = {
+ onRescanCount.incrementAndGet()
+ },
+ onBackgroundSyncSettingsChanged = {
+ onBackgroundSyncChangedCount.incrementAndGet()
+ },
+ onKeepScreenOnDuringSyncSettingsChanged = {
+ onKeepScreenOnChangedCount.incrementAndGet()
+ },
+ onAnalyticsSettingsChanged = {
+ onAnalyticsChangedCount.incrementAndGet()
+ }
+ )
+ }
+ }
+ }
+}
diff --git a/ui-lib/src/androidTest/java/co/electriccoin/zcash/ui/screen/settings/fixture/TroubleshootingParametersFixture.kt b/ui-lib/src/androidTest/java/co/electriccoin/zcash/ui/screen/settings/fixture/TroubleshootingParametersFixture.kt
new file mode 100644
index 00000000..210fabe0
--- /dev/null
+++ b/ui-lib/src/androidTest/java/co/electriccoin/zcash/ui/screen/settings/fixture/TroubleshootingParametersFixture.kt
@@ -0,0 +1,25 @@
+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
+ )
+}
diff --git a/ui-lib/src/androidTest/java/co/electriccoin/zcash/ui/screen/settings/view/SettingsViewTest.kt b/ui-lib/src/androidTest/java/co/electriccoin/zcash/ui/screen/settings/view/SettingsViewTest.kt
index cf6ca120..9cde1e17 100644
--- a/ui-lib/src/androidTest/java/co/electriccoin/zcash/ui/screen/settings/view/SettingsViewTest.kt
+++ b/ui-lib/src/androidTest/java/co/electriccoin/zcash/ui/screen/settings/view/SettingsViewTest.kt
@@ -3,34 +3,31 @@ package co.electriccoin.zcash.ui.screen.settings.view
import androidx.compose.ui.test.junit4.ComposeContentTestRule
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithContentDescription
+import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.test.filters.MediumTest
-import co.electriccoin.zcash.configuration.model.map.StringConfiguration
+import androidx.test.filters.SmallTest
import co.electriccoin.zcash.test.UiTestPrerequisites
import co.electriccoin.zcash.ui.R
-import co.electriccoin.zcash.ui.configuration.ConfigurationEntries
-import co.electriccoin.zcash.ui.design.theme.ZcashTheme
+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 kotlinx.collections.immutable.toPersistentMap
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals
import org.junit.Rule
import org.junit.Test
-import java.util.concurrent.atomic.AtomicInteger
-@OptIn(ExperimentalCoroutinesApi::class)
class SettingsViewTest : UiTestPrerequisites() {
@get:Rule
val composeTestRule = createComposeRule()
@Test
@MediumTest
- fun back() = runTest {
- val testSetup = TestSetup(composeTestRule)
+ fun on_back_test() {
+ val testSetup = SettingsViewTestSetup(composeTestRule, TroubleshootingParametersFixture.new())
- assertEquals(0, testSetup.getOnBackCount())
+ assertEquals(0, testSetup.getBackCount())
composeTestRule.onNodeWithContentDescription(
getStringResource(R.string.settings_back_content_description)
@@ -38,141 +35,208 @@ class SettingsViewTest : UiTestPrerequisites() {
it.performClick()
}
- assertEquals(1, testSetup.getOnBackCount())
+ assertEquals(1, testSetup.getBackCount())
}
@Test
@MediumTest
- fun rescan() = runTest {
- val testSetup = TestSetup(composeTestRule)
+ fun on_feedback_test() {
+ val testSetup = SettingsViewTestSetup(composeTestRule, TroubleshootingParametersFixture.new())
- if (ConfigurationEntries.IS_RESCAN_ENABLED.getValue(
- StringConfiguration(emptyMap().toPersistentMap(), null)
+ assertEquals(0, testSetup.getFeedbackCount())
+
+ composeTestRule.onNodeWithText(
+ getStringResource(R.string.settings_send_us_feedback)
+ ).also {
+ it.performClick()
+ }
+
+ assertEquals(1, testSetup.getFeedbackCount())
+ }
+
+ @Test
+ @MediumTest
+ fun on_backup_test() {
+ val testSetup = SettingsViewTestSetup(composeTestRule, TroubleshootingParametersFixture.new())
+
+ assertEquals(0, testSetup.getBackupCount())
+
+ composeTestRule.onNodeWithText(
+ getStringResource(R.string.settings_backup_wallet)
+ ).also {
+ it.performClick()
+ }
+
+ assertEquals(1, testSetup.getBackupCount())
+ }
+
+ @Test
+ @MediumTest
+ fun on_documentation_test() {
+ val testSetup = SettingsViewTestSetup(composeTestRule, TroubleshootingParametersFixture.new())
+
+ assertEquals(0, testSetup.getDocumentationCount())
+
+ composeTestRule.onNodeWithText(
+ getStringResource(R.string.settings_documentation)
+ ).also {
+ it.performClick()
+ }
+
+ assertEquals(1, testSetup.getDocumentationCount())
+ }
+
+ @Test
+ @MediumTest
+ fun on_privacy_policy_test() {
+ val testSetup = SettingsViewTestSetup(composeTestRule, TroubleshootingParametersFixture.new())
+
+ assertEquals(0, testSetup.getPrivacyPolicyCount())
+
+ composeTestRule.onNodeWithText(
+ getStringResource(R.string.settings_privacy_policy)
+ ).also {
+ it.performClick()
+ }
+
+ assertEquals(1, testSetup.getPrivacyPolicyCount())
+ }
+
+ @Test
+ @MediumTest
+ fun on_about_test() {
+ val testSetup = SettingsViewTestSetup(composeTestRule, TroubleshootingParametersFixture.new())
+
+ assertEquals(0, testSetup.getAboutCount())
+
+ composeTestRule.onNodeWithText(
+ getStringResource(R.string.settings_about)
+ ).also {
+ it.performClick()
+ }
+
+ assertEquals(1, testSetup.getAboutCount())
+ }
+
+ @Test
+ @SmallTest
+ fun troubleshooting_menu_visible_test() {
+ SettingsViewTestSetup(composeTestRule, TroubleshootingParametersFixture.new(isEnabled = true))
+
+ composeTestRule.onNodeWithTag(SettingsTag.TROUBLESHOOTING_MENU).also {
+ it.assertExists()
+ }
+ }
+
+ @Test
+ @SmallTest
+ fun troubleshooting_menu_not_visible_test() {
+ SettingsViewTestSetup(composeTestRule, TroubleshootingParametersFixture.new(isEnabled = false))
+
+ composeTestRule.onNodeWithTag(SettingsTag.TROUBLESHOOTING_MENU).also {
+ it.assertDoesNotExist()
+ }
+ }
+
+ @Test
+ @MediumTest
+ fun troubleshooting_rescan_test() {
+ val testSetup = SettingsViewTestSetup(
+ composeTestRule,
+ TroubleshootingParametersFixture.new(
+ isEnabled = true,
+ isRescanEnabled = true
)
- ) {
- assertEquals(0, testSetup.getRescanCount())
+ )
- composeTestRule.onNodeWithContentDescription(
- getStringResource(R.string.settings_overflow_content_description)
- ).also {
- it.performClick()
- }
+ assertEquals(0, testSetup.getRescanCount())
- composeTestRule.onNodeWithText(getStringResource(R.string.settings_rescan)).also {
- it.performClick()
- }
+ composeTestRule.openTroubleshootingMenu()
- assertEquals(1, testSetup.getRescanCount())
+ composeTestRule.onNodeWithText(getStringResource(R.string.settings_troubleshooting_rescan)).also {
+ it.performClick()
}
+
+ assertEquals(1, testSetup.getRescanCount())
}
@Test
@MediumTest
- fun toggle_background_sync() = runTest {
- val testSetup = TestSetup(composeTestRule)
+ fun troubleshooting_background_sync_test() {
+ val testSetup = SettingsViewTestSetup(
+ composeTestRule,
+ TroubleshootingParametersFixture.new(
+ isEnabled = true,
+ isBackgroundSyncEnabled = true
+ )
+ )
- assertEquals(0, testSetup.getBackgroundSyncToggleCount())
+ assertEquals(0, testSetup.getBackgroundSyncCount())
- composeTestRule.onNodeWithText(getStringResource(R.string.settings_enable_background_sync)).also {
+ composeTestRule.openTroubleshootingMenu()
+
+ composeTestRule.onNodeWithText(
+ getStringResource(R.string.settings_troubleshooting_enable_background_sync)
+ ).also {
it.performClick()
}
- assertEquals(1, testSetup.getBackgroundSyncToggleCount())
+ assertEquals(1, testSetup.getBackgroundSyncCount())
}
@Test
@MediumTest
- fun toggle_keep_screen_on() = runTest {
- val testSetup = TestSetup(composeTestRule)
+ fun troubleshooting_keep_screen_on_during_sync_test() {
+ val testSetup = SettingsViewTestSetup(
+ composeTestRule,
+ TroubleshootingParametersFixture.new(
+ isEnabled = true,
+ isKeepScreenOnDuringSyncEnabled = true
+ )
+ )
- assertEquals(0, testSetup.getKeepScreenOnSyncToggleCount())
+ assertEquals(0, testSetup.getKeepScreenOnSyncCount())
- composeTestRule.onNodeWithText(getStringResource(R.string.settings_enable_keep_screen_on)).also {
+ composeTestRule.openTroubleshootingMenu()
+
+ composeTestRule.onNodeWithText(
+ getStringResource(R.string.settings_troubleshooting_enable_keep_screen_on)
+ ).also {
it.performClick()
}
- assertEquals(1, testSetup.getKeepScreenOnSyncToggleCount())
+ assertEquals(1, testSetup.getKeepScreenOnSyncCount())
}
@Test
@MediumTest
- fun toggle_analytics() = runTest {
- val testSetup = TestSetup(composeTestRule)
+ fun troubleshooting_analytics_test() {
+ val testSetup = SettingsViewTestSetup(
+ composeTestRule,
+ TroubleshootingParametersFixture.new(
+ isEnabled = true,
+ isAnalyticsEnabled = true
+ )
+ )
- assertEquals(0, testSetup.getAnalyticsToggleCount())
+ assertEquals(0, testSetup.getAnalyticsCount())
- composeTestRule.onNodeWithText(getStringResource(R.string.settings_enable_analytics)).also {
+ composeTestRule.openTroubleshootingMenu()
+
+ composeTestRule.onNodeWithText(
+ getStringResource(R.string.settings_troubleshooting_enable_analytics)
+ ).also {
it.performClick()
}
- assertEquals(1, testSetup.getAnalyticsToggleCount())
- }
-
- private class TestSetup(private val composeTestRule: ComposeContentTestRule) {
-
- private val onBackCount = AtomicInteger(0)
- private val onBackupCount = AtomicInteger(0)
- private val onRescanCount = AtomicInteger(0)
- private val onBackgroundSyncChangedCount = AtomicInteger(0)
- private val onKeepScreenOnChangedCount = AtomicInteger(0)
- private val onAnalyticsChangedCount = AtomicInteger(0)
-
- fun getOnBackCount(): Int {
- composeTestRule.waitForIdle()
- return onBackCount.get()
- }
-
- fun getBackupCount(): Int {
- composeTestRule.waitForIdle()
- return onBackupCount.get()
- }
-
- fun getRescanCount(): Int {
- composeTestRule.waitForIdle()
- return onRescanCount.get()
- }
-
- fun getBackgroundSyncToggleCount(): Int {
- composeTestRule.waitForIdle()
- return onBackgroundSyncChangedCount.get()
- }
-
- fun getKeepScreenOnSyncToggleCount(): Int {
- composeTestRule.waitForIdle()
- return onKeepScreenOnChangedCount.get()
- }
-
- fun getAnalyticsToggleCount(): Int {
- composeTestRule.waitForIdle()
- return onAnalyticsChangedCount.get()
- }
-
- init {
- composeTestRule.setContent {
- ZcashTheme {
- Settings(
- isBackgroundSyncEnabled = true,
- isKeepScreenOnDuringSyncEnabled = true,
- isAnalyticsEnabled = true,
- isRescanEnabled = true,
- onBack = {
- onBackCount.incrementAndGet()
- },
- onRescanWallet = {
- onRescanCount.incrementAndGet()
- },
- onBackgroundSyncSettingsChanged = {
- onBackgroundSyncChangedCount.incrementAndGet()
- },
- onIsKeepScreenOnDuringSyncSettingsChanged = {
- onKeepScreenOnChangedCount.incrementAndGet()
- },
- onAnalyticsSettingsChanged = {
- onAnalyticsChangedCount.incrementAndGet()
- }
- )
- }
- }
- }
+ assertEquals(1, testSetup.getAnalyticsCount())
+ }
+}
+
+fun ComposeContentTestRule.openTroubleshootingMenu() {
+ onNodeWithContentDescription(
+ getStringResource(R.string.settings_troubleshooting_menu_content_description)
+ ).also {
+ it.performClick()
}
}
diff --git a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/settings/AndroidSettings.kt b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/settings/AndroidSettings.kt
index 24b7f719..25d5cd8b 100644
--- a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/settings/AndroidSettings.kt
+++ b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/settings/AndroidSettings.kt
@@ -6,10 +6,12 @@ import androidx.activity.ComponentActivity
import androidx.activity.viewModels
import androidx.compose.runtime.Composable
import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import co.electriccoin.zcash.ui.BuildConfig
import co.electriccoin.zcash.ui.MainActivity
import co.electriccoin.zcash.ui.configuration.ConfigurationEntries
import co.electriccoin.zcash.ui.configuration.RemoteConfig
import co.electriccoin.zcash.ui.screen.home.viewmodel.WalletViewModel
+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
@@ -45,18 +47,26 @@ private fun WrapSettings(
// Display loading indicator
} else {
Settings(
- isBackgroundSyncEnabled = isBackgroundSyncEnabled,
- isKeepScreenOnDuringSyncEnabled = isKeepScreenOnWhileSyncing,
- isAnalyticsEnabled = isAnalyticsEnabled,
- isRescanEnabled = ConfigurationEntries.IS_RESCAN_ENABLED.getValue(RemoteConfig.current),
+ TroubleshootingParameters(
+ isEnabled = BuildConfig.DEBUG,
+ isBackgroundSyncEnabled = isBackgroundSyncEnabled,
+ isKeepScreenOnDuringSyncEnabled = isKeepScreenOnWhileSyncing,
+ isAnalyticsEnabled = isAnalyticsEnabled,
+ isRescanEnabled = ConfigurationEntries.IS_RESCAN_ENABLED.getValue(RemoteConfig.current),
+ ),
onBack = goBack,
+ onBackup = {},
+ onDocumentation = {},
+ onPrivacyPolicy = {},
+ onFeedback = {},
+ onAbout = {},
onRescanWallet = {
walletViewModel.rescanBlockchain()
},
onBackgroundSyncSettingsChanged = {
settingsViewModel.setBackgroundSyncEnabled(it)
},
- onIsKeepScreenOnDuringSyncSettingsChanged = {
+ onKeepScreenOnDuringSyncSettingsChanged = {
settingsViewModel.setKeepScreenOnWhileSyncing(it)
},
onAnalyticsSettingsChanged = {
diff --git a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/settings/SettingsTag.kt b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/settings/SettingsTag.kt
new file mode 100644
index 00000000..6510700d
--- /dev/null
+++ b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/settings/SettingsTag.kt
@@ -0,0 +1,8 @@
+package co.electriccoin.zcash.ui.screen.settings
+
+/**
+ * These are only used for automated testing.
+ */
+object SettingsTag {
+ const val TROUBLESHOOTING_MENU = "troubleshooting_menu"
+}
diff --git a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/settings/model/TroubleshootingParameters.kt b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/settings/model/TroubleshootingParameters.kt
new file mode 100644
index 00000000..f104ef2f
--- /dev/null
+++ b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/settings/model/TroubleshootingParameters.kt
@@ -0,0 +1,9 @@
+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,
+)
diff --git a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/settings/view/SettingsView.kt b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/settings/view/SettingsView.kt
index ab6814ac..ad906ed2 100644
--- a/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/settings/view/SettingsView.kt
+++ b/ui-lib/src/main/java/co/electriccoin/zcash/ui/screen/settings/view/SettingsView.kt
@@ -1,7 +1,12 @@
package co.electriccoin.zcash.ui.screen.settings.view
+import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
@@ -9,6 +14,9 @@ import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.MoreVert
+import androidx.compose.material.icons.outlined.Cancel
+import androidx.compose.material.icons.outlined.CheckCircle
+import androidx.compose.material3.CenterAlignedTopAppBar
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
@@ -16,35 +24,47 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
-import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import co.electriccoin.zcash.ui.R
+import co.electriccoin.zcash.ui.design.MINIMAL_WEIGHT
import co.electriccoin.zcash.ui.design.component.GradientSurface
-import co.electriccoin.zcash.ui.design.component.SwitchWithLabel
+import co.electriccoin.zcash.ui.design.component.PrimaryButton
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
import co.electriccoin.zcash.ui.design.theme.ZcashTheme.dimens
+import co.electriccoin.zcash.ui.screen.settings.SettingsTag
+import co.electriccoin.zcash.ui.screen.settings.model.TroubleshootingParameters
@Preview("Settings")
@Composable
private fun PreviewSettings() {
- ZcashTheme(darkTheme = true) {
+ ZcashTheme(darkTheme = false) {
GradientSurface {
Settings(
- isBackgroundSyncEnabled = true,
- isKeepScreenOnDuringSyncEnabled = true,
- isAnalyticsEnabled = true,
- isRescanEnabled = true,
+ TroubleshootingParameters(
+ isEnabled = false,
+ isBackgroundSyncEnabled = false,
+ isKeepScreenOnDuringSyncEnabled = false,
+ isAnalyticsEnabled = false,
+ isRescanEnabled = false
+ ),
onBack = {},
+ onBackup = {},
+ onDocumentation = {},
+ onPrivacyPolicy = {},
+ onFeedback = {},
+ onAbout = {},
onRescanWallet = {},
onBackgroundSyncSettingsChanged = {},
- onIsKeepScreenOnDuringSyncSettingsChanged = {},
+ onKeepScreenOnDuringSyncSettingsChanged = {},
onAnalyticsSettingsChanged = {}
)
}
@@ -54,81 +74,134 @@ private fun PreviewSettings() {
@Composable
@Suppress("LongParameterList")
fun Settings(
- isBackgroundSyncEnabled: Boolean,
- isKeepScreenOnDuringSyncEnabled: Boolean,
- isAnalyticsEnabled: Boolean,
- isRescanEnabled: Boolean,
+ troubleshootingParameters: TroubleshootingParameters,
onBack: () -> Unit,
+ onBackup: () -> Unit,
+ onDocumentation: () -> Unit,
+ onPrivacyPolicy: () -> Unit,
+ onFeedback: () -> Unit,
+ onAbout: () -> Unit,
onRescanWallet: () -> Unit,
onBackgroundSyncSettingsChanged: (Boolean) -> Unit,
- onIsKeepScreenOnDuringSyncSettingsChanged: (Boolean) -> Unit,
+ onKeepScreenOnDuringSyncSettingsChanged: (Boolean) -> Unit,
onAnalyticsSettingsChanged: (Boolean) -> Unit
) {
Scaffold(topBar = {
SettingsTopAppBar(
- isRescanEnabled = isRescanEnabled,
+ troubleshootingParameters = troubleshootingParameters,
+ onBackgroundSyncSettingsChanged = onBackgroundSyncSettingsChanged,
+ onKeepScreenOnDuringSyncSettingsChanged = onKeepScreenOnDuringSyncSettingsChanged,
+ onAnalyticsSettingsChanged = onAnalyticsSettingsChanged,
+ onRescanWallet = onRescanWallet,
onBack = onBack,
- onRescanWallet = onRescanWallet
)
}) { paddingValues ->
SettingsMainContent(
- isBackgroundSyncEnabled = isBackgroundSyncEnabled,
- isKeepScreenOnDuringSyncEnabled = isKeepScreenOnDuringSyncEnabled,
- isAnalyticsEnabled = isAnalyticsEnabled,
- onBackgroundSyncSettingsChanged = onBackgroundSyncSettingsChanged,
- onIsKeepScreenOnDuringSyncSettingsChanged = onIsKeepScreenOnDuringSyncSettingsChanged,
- onAnalyticsSettingsChanged = onAnalyticsSettingsChanged,
modifier = Modifier
.verticalScroll(
rememberScrollState()
)
.padding(
- top = paddingValues.calculateTopPadding() + dimens.spacingDefault,
- bottom = paddingValues.calculateTopPadding() + dimens.spacingDefault,
- start = dimens.spacingDefault,
- end = dimens.spacingDefault
- )
+ top = paddingValues.calculateTopPadding() + dimens.spacingHuge,
+ bottom = paddingValues.calculateBottomPadding() + dimens.spacingHuge,
+ start = dimens.spacingHuge,
+ end = dimens.spacingHuge
+ ),
+ onBackup = onBackup,
+ onDocumentation = onDocumentation,
+ onPrivacyPolicy = onPrivacyPolicy,
+ onFeedback = onFeedback,
+ onAbout = onAbout,
)
}
}
@Composable
@OptIn(ExperimentalMaterial3Api::class)
+@Suppress("LongParameterList")
private fun SettingsTopAppBar(
- isRescanEnabled: Boolean,
+ troubleshootingParameters: TroubleshootingParameters,
+ onBackgroundSyncSettingsChanged: (Boolean) -> Unit,
+ onKeepScreenOnDuringSyncSettingsChanged: (Boolean) -> Unit,
+ onAnalyticsSettingsChanged: (Boolean) -> Unit,
+ onRescanWallet: () -> Unit,
onBack: () -> Unit,
- onRescanWallet: () -> Unit
) {
- TopAppBar(
- title = { Text(text = stringResource(id = R.string.settings_header)) },
+ CenterAlignedTopAppBar(
+ title = {
+ Text(
+ text = stringResource(id = R.string.settings_header).uppercase(),
+ style = ZcashTheme.typography.primary.titleSmall,
+ color = ZcashTheme.colors.screenTitleColor
+ )
+ },
navigationIcon = {
- IconButton(
- onClick = onBack
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.SpaceBetween
) {
- Icon(
- imageVector = Icons.Filled.ArrowBack,
- contentDescription = stringResource(R.string.settings_back_content_description)
+ IconButton(
+ onClick = onBack
+ ) {
+ Icon(
+ imageVector = Icons.Filled.ArrowBack,
+ contentDescription = stringResource(R.string.settings_back_content_description)
+ )
+ }
+ Text(
+ text = stringResource(id = R.string.settings_back).uppercase(),
+ style = ZcashTheme.typography.primary.bodyMedium
)
}
},
actions = {
- if (isRescanEnabled) {
- TroubleshootingMenu(onRescanWallet)
+ if (troubleshootingParameters.isEnabled) {
+ TroubleshootingMenu(
+ troubleshootingParameters,
+ onBackgroundSyncSettingsChanged,
+ onKeepScreenOnDuringSyncSettingsChanged,
+ onAnalyticsSettingsChanged,
+ onRescanWallet
+ )
}
}
)
}
+/**
+ * Add icon to Troubleshooting menu. No content description, as this is debug only menu.
+ */
+@Composable
+private fun AddIcon(enabled: Boolean) {
+ if (enabled) {
+ Icon(
+ imageVector = Icons.Outlined.CheckCircle,
+ contentDescription = null
+ )
+ } else {
+ Icon(
+ imageVector = Icons.Outlined.Cancel,
+ contentDescription = null
+ )
+ }
+}
+
@Composable
private fun TroubleshootingMenu(
+ troubleshootParams: TroubleshootingParameters,
+ onBackgroundSyncSettingsChanged: (Boolean) -> Unit,
+ onKeepScreenOnDuringSyncSettingsChanged: (Boolean) -> Unit,
+ onAnalyticsSettingsChanged: (Boolean) -> Unit,
onRescanWallet: () -> Unit
) {
- Column {
+ 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_overflow_content_description)
+ contentDescription = stringResource(id = R.string.settings_troubleshooting_menu_content_description)
)
}
@@ -137,12 +210,41 @@ private fun TroubleshootingMenu(
onDismissRequest = { expanded = false }
) {
DropdownMenuItem(
- text = { Text(stringResource(id = R.string.settings_rescan)) },
+ text = { Text(stringResource(id = R.string.settings_troubleshooting_enable_background_sync)) },
onClick = {
- onRescanWallet()
+ 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) }
+ )
+ }
}
}
}
@@ -150,35 +252,77 @@ private fun TroubleshootingMenu(
@Composable
@Suppress("LongParameterList")
private fun SettingsMainContent(
- isBackgroundSyncEnabled: Boolean,
- isKeepScreenOnDuringSyncEnabled: Boolean,
- isAnalyticsEnabled: Boolean,
- onBackgroundSyncSettingsChanged: (Boolean) -> Unit,
- onIsKeepScreenOnDuringSyncSettingsChanged: (Boolean) -> Unit,
- onAnalyticsSettingsChanged: (Boolean) -> Unit,
+ onBackup: () -> Unit,
+ onDocumentation: () -> Unit,
+ onPrivacyPolicy: () -> Unit,
+ onFeedback: () -> Unit,
+ onAbout: () -> Unit,
modifier: Modifier = Modifier
) {
- Column(modifier = modifier) {
- SwitchWithLabel(
- label = stringResource(id = R.string.settings_enable_background_sync),
- state = isBackgroundSyncEnabled,
- onStateChange = { onBackgroundSyncSettingsChanged(!isBackgroundSyncEnabled) }
+ Column(
+ Modifier
+ .fillMaxHeight()
+ .fillMaxWidth()
+ .then(modifier),
+ horizontalAlignment = Alignment.CenterHorizontally
+ ) {
+ PrimaryButton(
+ onClick = onBackup,
+ text = stringResource(R.string.settings_backup_wallet),
+ outerPaddingValues = PaddingValues(
+ horizontal = dimens.spacingNone,
+ vertical = dimens.spacingSmall
+ ),
)
- Spacer(modifier = Modifier.height(dimens.spacingXlarge))
+ Spacer(modifier = Modifier.height(dimens.spacingDefault))
- SwitchWithLabel(
- label = stringResource(id = R.string.settings_enable_keep_screen_on),
- state = isKeepScreenOnDuringSyncEnabled,
- onStateChange = { onIsKeepScreenOnDuringSyncSettingsChanged(!isKeepScreenOnDuringSyncEnabled) }
+ PrimaryButton(
+ onClick = onFeedback,
+ text = stringResource(R.string.settings_send_us_feedback),
+ outerPaddingValues = PaddingValues(
+ horizontal = dimens.spacingNone,
+ vertical = dimens.spacingSmall
+ ),
)
- Spacer(modifier = Modifier.height(dimens.spacingXlarge))
+ Spacer(modifier = Modifier.height(dimens.spacingDefault))
- SwitchWithLabel(
- label = stringResource(id = R.string.settings_enable_analytics),
- state = isAnalyticsEnabled,
- onStateChange = { onAnalyticsSettingsChanged(!isAnalyticsEnabled) }
+ PrimaryButton(
+ onClick = onPrivacyPolicy,
+ text = stringResource(R.string.settings_privacy_policy),
+ outerPaddingValues = PaddingValues(
+ horizontal = dimens.spacingNone,
+ vertical = dimens.spacingSmall
+ ),
+ )
+
+ Spacer(modifier = Modifier.height(dimens.spacingDefault))
+
+ PrimaryButton(
+ onClick = onDocumentation,
+ text = stringResource(R.string.settings_documentation),
+ outerPaddingValues = PaddingValues(
+ horizontal = dimens.spacingNone,
+ vertical = dimens.spacingSmall
+ ),
+ )
+
+ Spacer(modifier = Modifier.height(dimens.spacingDefault))
+
+ Spacer(
+ modifier = Modifier
+ .fillMaxHeight()
+ .weight(MINIMAL_WEIGHT)
+ )
+
+ PrimaryButton(
+ onClick = onAbout,
+ text = stringResource(R.string.settings_about),
+ outerPaddingValues = PaddingValues(
+ horizontal = dimens.spacingNone,
+ vertical = dimens.spacingSmall
+ ),
)
}
}
diff --git a/ui-lib/src/main/res/ui/settings/values/strings.xml b/ui-lib/src/main/res/ui/settings/values/strings.xml
index 8d6f16ff..1f0f2a19 100644
--- a/ui-lib/src/main/res/ui/settings/values/strings.xml
+++ b/ui-lib/src/main/res/ui/settings/values/strings.xml
@@ -1,11 +1,18 @@
Settings
+ Back
Back
- Additional settings
- Rescan blockchain
- Background sync
- Keep screen on during sync
- Report crashes
+ Additional settings
+ Rescan blockchain
+ Background sync
+ Keep screen on during sync
+ Report crashes
+
+ Backup wallet
+ Documentation
+ Privacy policy
+ Send us feedback
+ About