- Closes #1262 - Closes #1083 - Closes #1241
This commit is contained in:
parent
45ab8ce8c9
commit
5bf7a635ff
|
@ -14,6 +14,7 @@ directly impact users rather than highlighting other key architectural updates.*
|
||||||
Choose server
|
Choose server
|
||||||
- A new Server switching screen was added. Its purpose is to enable switching between predefined and custom
|
- A new Server switching screen was added. Its purpose is to enable switching between predefined and custom
|
||||||
lightwalletd servers in runtime.
|
lightwalletd servers in runtime.
|
||||||
|
- The About screen now contains a link to the new Zashi Privacy Policy website
|
||||||
|
|
||||||
## [0.2.0 (560)] - 2024-02-27
|
## [0.2.0 (560)] - 2024-02-27
|
||||||
|
|
||||||
|
|
|
@ -165,6 +165,7 @@ data class ExtendedTypography(
|
||||||
val buttonTextSmall: TextStyle,
|
val buttonTextSmall: TextStyle,
|
||||||
val checkboxText: TextStyle,
|
val checkboxText: TextStyle,
|
||||||
val securityWarningText: TextStyle,
|
val securityWarningText: TextStyle,
|
||||||
|
val securityWarningFootnote: TextStyle,
|
||||||
val textFieldHint: TextStyle,
|
val textFieldHint: TextStyle,
|
||||||
val textFieldValue: TextStyle,
|
val textFieldValue: TextStyle,
|
||||||
val textFieldBirthday: TextStyle,
|
val textFieldBirthday: TextStyle,
|
||||||
|
@ -250,7 +251,13 @@ val LocalExtendedTypography =
|
||||||
),
|
),
|
||||||
securityWarningText =
|
securityWarningText =
|
||||||
PrimaryTypography.bodySmall.copy(
|
PrimaryTypography.bodySmall.copy(
|
||||||
lineHeight = 22.32.sp
|
fontSize = 16.sp,
|
||||||
|
fontWeight = FontWeight.Medium
|
||||||
|
),
|
||||||
|
securityWarningFootnote =
|
||||||
|
PrimaryTypography.bodySmall.copy(
|
||||||
|
fontSize = 11.sp,
|
||||||
|
fontWeight = FontWeight.Medium
|
||||||
),
|
),
|
||||||
textFieldHint =
|
textFieldHint =
|
||||||
PrimaryTypography.bodySmall.copy(
|
PrimaryTypography.bodySmall.copy(
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package co.electriccoin.zcash.ui.screen.securitywarning.util
|
package co.electriccoin.zcash.ui.screen.about.util
|
||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import androidx.test.filters.SmallTest
|
import androidx.test.filters.SmallTest
|
|
@ -1,5 +1,6 @@
|
||||||
package co.electriccoin.zcash.ui.screen.about.view
|
package co.electriccoin.zcash.ui.screen.about.view
|
||||||
|
|
||||||
|
import androidx.compose.material3.SnackbarHostState
|
||||||
import androidx.compose.ui.test.junit4.ComposeContentTestRule
|
import androidx.compose.ui.test.junit4.ComposeContentTestRule
|
||||||
import co.electriccoin.zcash.ui.common.model.VersionInfo
|
import co.electriccoin.zcash.ui.common.model.VersionInfo
|
||||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||||
|
@ -24,7 +25,9 @@ class AboutViewTestSetup(
|
||||||
About(
|
About(
|
||||||
onBack = { onBackCount.incrementAndGet() },
|
onBack = { onBackCount.incrementAndGet() },
|
||||||
versionInfo = versionInfo,
|
versionInfo = versionInfo,
|
||||||
configInfo = configInfo
|
configInfo = configInfo,
|
||||||
|
onPrivacyPolicy = {},
|
||||||
|
snackbarHostState = SnackbarHostState()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,11 +44,6 @@ class SecurityWarningViewTest : UiTestPrerequisites() {
|
||||||
it.assertHasClickAction()
|
it.assertHasClickAction()
|
||||||
it.assertIsNotEnabled()
|
it.assertIsNotEnabled()
|
||||||
}
|
}
|
||||||
|
|
||||||
composeTestRule.onNodeWithTag(SecurityScreenTag.WARNING_TEXT_TAG).also {
|
|
||||||
it.assertExists()
|
|
||||||
it.assertIsDisplayed()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package co.electriccoin.zcash.ui.screen.securitywarning.view
|
package co.electriccoin.zcash.ui.screen.securitywarning.view
|
||||||
|
|
||||||
import androidx.compose.material3.SnackbarHostState
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.test.junit4.ComposeContentTestRule
|
import androidx.compose.ui.test.junit4.ComposeContentTestRule
|
||||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||||
|
@ -34,13 +33,9 @@ class SecurityWarningViewTestSetup(private val composeTestRule: ComposeContentTe
|
||||||
@Suppress("TestFunctionName")
|
@Suppress("TestFunctionName")
|
||||||
fun DefaultContent() {
|
fun DefaultContent() {
|
||||||
SecurityWarning(
|
SecurityWarning(
|
||||||
SnackbarHostState(),
|
|
||||||
onBack = {
|
onBack = {
|
||||||
onBackCount.incrementAndGet()
|
onBackCount.incrementAndGet()
|
||||||
},
|
},
|
||||||
onPrivacyPolicy = {
|
|
||||||
// Not tested yet. UI testing of clicking on an AnnotatedString Text part is complicated.
|
|
||||||
},
|
|
||||||
onAcknowledged = {
|
onAcknowledged = {
|
||||||
onAcknowledged.getAndSet(it)
|
onAcknowledged.getAndSet(it)
|
||||||
},
|
},
|
||||||
|
|
|
@ -2,14 +2,22 @@
|
||||||
|
|
||||||
package co.electriccoin.zcash.ui.screen.about
|
package co.electriccoin.zcash.ui.screen.about
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
|
import androidx.compose.material3.SnackbarHostState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import co.electriccoin.zcash.configuration.AndroidConfigurationFactory
|
import co.electriccoin.zcash.configuration.AndroidConfigurationFactory
|
||||||
import co.electriccoin.zcash.ui.MainActivity
|
import co.electriccoin.zcash.ui.MainActivity
|
||||||
|
import co.electriccoin.zcash.ui.R
|
||||||
import co.electriccoin.zcash.ui.common.model.VersionInfo
|
import co.electriccoin.zcash.ui.common.model.VersionInfo
|
||||||
|
import co.electriccoin.zcash.ui.screen.about.util.WebBrowserUtil
|
||||||
import co.electriccoin.zcash.ui.screen.about.view.About
|
import co.electriccoin.zcash.ui.screen.about.view.About
|
||||||
import co.electriccoin.zcash.ui.screen.support.model.ConfigInfo
|
import co.electriccoin.zcash.ui.screen.support.model.ConfigInfo
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun MainActivity.WrapAbout(goBack: () -> Unit) {
|
internal fun MainActivity.WrapAbout(goBack: () -> Unit) {
|
||||||
|
@ -29,9 +37,37 @@ internal fun WrapAbout(
|
||||||
AndroidConfigurationFactory.getInstance(activity.applicationContext).hintToRefresh()
|
AndroidConfigurationFactory.getInstance(activity.applicationContext).hintToRefresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val snackbarHostState = remember { SnackbarHostState() }
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
About(
|
About(
|
||||||
onBack = goBack,
|
onBack = goBack,
|
||||||
versionInfo = versionInfo,
|
versionInfo = versionInfo,
|
||||||
configInfo = configInfo
|
configInfo = configInfo,
|
||||||
|
onPrivacyPolicy = {
|
||||||
|
openPrivacyPolicyInWebBrowser(
|
||||||
|
activity.applicationContext,
|
||||||
|
snackbarHostState,
|
||||||
|
scope
|
||||||
|
)
|
||||||
|
},
|
||||||
|
snackbarHostState = snackbarHostState,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun openPrivacyPolicyInWebBrowser(
|
||||||
|
context: Context,
|
||||||
|
snackbarHostState: SnackbarHostState,
|
||||||
|
scope: CoroutineScope
|
||||||
|
) {
|
||||||
|
val storeIntent = WebBrowserUtil.newActivityIntent(WebBrowserUtil.ZCASH_PRIVACY_POLICY_URI)
|
||||||
|
runCatching {
|
||||||
|
context.startActivity(storeIntent)
|
||||||
|
}.onFailure {
|
||||||
|
scope.launch {
|
||||||
|
snackbarHostState.showSnackbar(
|
||||||
|
message = context.getString(R.string.about_unable_to_web_browser)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package co.electriccoin.zcash.ui.screen.securitywarning.util
|
package co.electriccoin.zcash.ui.screen.about.util
|
||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
@ -9,7 +9,7 @@ object WebBrowserUtil {
|
||||||
Intent.FLAG_ACTIVITY_NEW_TASK or
|
Intent.FLAG_ACTIVITY_NEW_TASK or
|
||||||
Intent.FLAG_ACTIVITY_MULTIPLE_TASK
|
Intent.FLAG_ACTIVITY_MULTIPLE_TASK
|
||||||
|
|
||||||
const val ZCASH_PRIVACY_POLICY_URI = "https://z.cash/privacy-policy/" // NON-NLS
|
const val ZCASH_PRIVACY_POLICY_URI = "https://electriccoin.co/zashi-privacy-policy/" // NON-NLS
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns new action view app intent. We assume the a web browser app is installed.
|
* Returns new action view app intent. We assume the a web browser app is installed.
|
|
@ -5,4 +5,5 @@ package co.electriccoin.zcash.ui.screen.about.view
|
||||||
*/
|
*/
|
||||||
object AboutTag {
|
object AboutTag {
|
||||||
const val DEBUG_MENU_TAG = "debug_menu"
|
const val DEBUG_MENU_TAG = "debug_menu"
|
||||||
|
const val PP_TEXT_TAG = "pp_text"
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,10 +5,12 @@ import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxHeight
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.text.ClickableText
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.MoreVert
|
import androidx.compose.material.icons.filled.MoreVert
|
||||||
|
@ -17,6 +19,8 @@ import androidx.compose.material3.DropdownMenuItem
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
|
import androidx.compose.material3.SnackbarHost
|
||||||
|
import androidx.compose.material3.SnackbarHostState
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
@ -30,6 +34,10 @@ import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.semantics.contentDescription
|
import androidx.compose.ui.semantics.contentDescription
|
||||||
import androidx.compose.ui.semantics.semantics
|
import androidx.compose.ui.semantics.semantics
|
||||||
|
import androidx.compose.ui.text.SpanStyle
|
||||||
|
import androidx.compose.ui.text.buildAnnotatedString
|
||||||
|
import androidx.compose.ui.text.style.TextDecoration
|
||||||
|
import androidx.compose.ui.text.withStyle
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import co.electriccoin.zcash.ui.R
|
import co.electriccoin.zcash.ui.R
|
||||||
import co.electriccoin.zcash.ui.common.model.VersionInfo
|
import co.electriccoin.zcash.ui.common.model.VersionInfo
|
||||||
|
@ -48,7 +56,9 @@ private fun AboutPreview() {
|
||||||
About(
|
About(
|
||||||
onBack = {},
|
onBack = {},
|
||||||
versionInfo = VersionInfoFixture.new(),
|
versionInfo = VersionInfoFixture.new(),
|
||||||
configInfo = ConfigInfoFixture.new()
|
configInfo = ConfigInfoFixture.new(),
|
||||||
|
snackbarHostState = SnackbarHostState(),
|
||||||
|
onPrivacyPolicy = {},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,18 +67,24 @@ private fun AboutPreview() {
|
||||||
@Composable
|
@Composable
|
||||||
fun About(
|
fun About(
|
||||||
onBack: () -> Unit,
|
onBack: () -> Unit,
|
||||||
|
configInfo: ConfigInfo,
|
||||||
|
onPrivacyPolicy: () -> Unit,
|
||||||
|
snackbarHostState: SnackbarHostState,
|
||||||
versionInfo: VersionInfo,
|
versionInfo: VersionInfo,
|
||||||
configInfo: ConfigInfo
|
|
||||||
) {
|
) {
|
||||||
Scaffold(topBar = {
|
Scaffold(
|
||||||
AboutTopAppBar(
|
topBar = {
|
||||||
onBack = onBack,
|
AboutTopAppBar(
|
||||||
versionInfo = versionInfo,
|
onBack = onBack,
|
||||||
configInfo = configInfo
|
versionInfo = versionInfo,
|
||||||
)
|
configInfo = configInfo
|
||||||
}) { paddingValues ->
|
)
|
||||||
|
},
|
||||||
|
snackbarHost = { SnackbarHost(snackbarHostState) },
|
||||||
|
) { paddingValues ->
|
||||||
AboutMainContent(
|
AboutMainContent(
|
||||||
versionInfo = versionInfo,
|
versionInfo = versionInfo,
|
||||||
|
onPrivacyPolicy = onPrivacyPolicy,
|
||||||
modifier =
|
modifier =
|
||||||
Modifier
|
Modifier
|
||||||
.fillMaxHeight()
|
.fillMaxHeight()
|
||||||
|
@ -143,6 +159,7 @@ private fun DebugMenu(
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun AboutMainContent(
|
fun AboutMainContent(
|
||||||
|
onPrivacyPolicy: () -> Unit,
|
||||||
versionInfo: VersionInfo,
|
versionInfo: VersionInfo,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
|
@ -188,5 +205,49 @@ fun AboutMainContent(
|
||||||
color = ZcashTheme.colors.aboutTextColor,
|
color = ZcashTheme.colors.aboutTextColor,
|
||||||
style = ZcashTheme.extendedTypography.aboutText
|
style = ZcashTheme.extendedTypography.aboutText
|
||||||
)
|
)
|
||||||
|
|
||||||
|
PrivacyPolicyLink(onPrivacyPolicy)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun PrivacyPolicyLink(onPrivacyPolicy: () -> Unit) {
|
||||||
|
Column {
|
||||||
|
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingLarge))
|
||||||
|
|
||||||
|
val textPart1 = stringResource(R.string.about_pp_part_1)
|
||||||
|
val textPart2 = stringResource(R.string.about_pp_part_2)
|
||||||
|
val textPart3 = stringResource(R.string.about_pp_part_3)
|
||||||
|
|
||||||
|
ClickableText(
|
||||||
|
text =
|
||||||
|
buildAnnotatedString {
|
||||||
|
withStyle(SpanStyle(color = ZcashTheme.colors.aboutTextColor)) {
|
||||||
|
append(textPart1)
|
||||||
|
}
|
||||||
|
withStyle(
|
||||||
|
SpanStyle(
|
||||||
|
textDecoration = TextDecoration.Underline,
|
||||||
|
color = ZcashTheme.colors.aboutTextColor,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
append(textPart2)
|
||||||
|
}
|
||||||
|
withStyle(SpanStyle(color = ZcashTheme.colors.aboutTextColor)) {
|
||||||
|
append(textPart3)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
style = ZcashTheme.extendedTypography.aboutText,
|
||||||
|
modifier =
|
||||||
|
Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.testTag(AboutTag.PP_TEXT_TAG),
|
||||||
|
onClick = { letterOffset ->
|
||||||
|
// Call the callback only if user clicked the underlined part
|
||||||
|
if (letterOffset >= textPart1.length && letterOffset <= (textPart1.length + textPart2.length)) {
|
||||||
|
onPrivacyPolicy()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,12 @@
|
||||||
package co.electriccoin.zcash.ui.screen.securitywarning
|
package co.electriccoin.zcash.ui.screen.securitywarning
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.compose.material3.SnackbarHostState
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
|
||||||
import co.electriccoin.zcash.configuration.AndroidConfigurationFactory
|
import co.electriccoin.zcash.configuration.AndroidConfigurationFactory
|
||||||
import co.electriccoin.zcash.ui.MainActivity
|
import co.electriccoin.zcash.ui.MainActivity
|
||||||
import co.electriccoin.zcash.ui.R
|
|
||||||
import co.electriccoin.zcash.ui.common.model.VersionInfo
|
import co.electriccoin.zcash.ui.common.model.VersionInfo
|
||||||
import co.electriccoin.zcash.ui.screen.securitywarning.util.WebBrowserUtil
|
|
||||||
import co.electriccoin.zcash.ui.screen.securitywarning.view.SecurityWarning
|
import co.electriccoin.zcash.ui.screen.securitywarning.view.SecurityWarning
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun MainActivity.WrapSecurityWarning(
|
internal fun MainActivity.WrapSecurityWarning(
|
||||||
|
@ -34,23 +26,12 @@ internal fun WrapSecurityWarning(
|
||||||
onBack: () -> Unit,
|
onBack: () -> Unit,
|
||||||
onConfirm: () -> Unit
|
onConfirm: () -> Unit
|
||||||
) {
|
) {
|
||||||
val snackbarHostState = remember { SnackbarHostState() }
|
|
||||||
val scope = rememberCoroutineScope()
|
|
||||||
|
|
||||||
SecurityWarning(
|
SecurityWarning(
|
||||||
snackbarHostState = snackbarHostState,
|
|
||||||
versionInfo = VersionInfo.new(activity.applicationContext),
|
versionInfo = VersionInfo.new(activity.applicationContext),
|
||||||
onBack = onBack,
|
onBack = onBack,
|
||||||
onAcknowledged = {
|
onAcknowledged = {
|
||||||
// Needed for UI testing only
|
// Needed for UI testing only
|
||||||
},
|
},
|
||||||
onPrivacyPolicy = {
|
|
||||||
openPrivacyPolicyInWebBrowser(
|
|
||||||
activity.applicationContext,
|
|
||||||
snackbarHostState,
|
|
||||||
scope
|
|
||||||
)
|
|
||||||
},
|
|
||||||
onConfirm = onConfirm
|
onConfirm = onConfirm
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -58,20 +39,3 @@ internal fun WrapSecurityWarning(
|
||||||
AndroidConfigurationFactory.getInstance(activity.applicationContext).hintToRefresh()
|
AndroidConfigurationFactory.getInstance(activity.applicationContext).hintToRefresh()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun openPrivacyPolicyInWebBrowser(
|
|
||||||
context: Context,
|
|
||||||
snackbarHostState: SnackbarHostState,
|
|
||||||
scope: CoroutineScope
|
|
||||||
) {
|
|
||||||
val storeIntent = WebBrowserUtil.newActivityIntent(WebBrowserUtil.ZCASH_PRIVACY_POLICY_URI)
|
|
||||||
runCatching {
|
|
||||||
context.startActivity(storeIntent)
|
|
||||||
}.onFailure {
|
|
||||||
scope.launch {
|
|
||||||
snackbarHostState.showSnackbar(
|
|
||||||
message = context.getString(R.string.security_warning_unable_to_web_browser)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -5,5 +5,4 @@ package co.electriccoin.zcash.ui.screen.securitywarning.view
|
||||||
*/
|
*/
|
||||||
object SecurityScreenTag {
|
object SecurityScreenTag {
|
||||||
const val ACKNOWLEDGE_CHECKBOX_TAG = "acknowledge_checkbox"
|
const val ACKNOWLEDGE_CHECKBOX_TAG = "acknowledge_checkbox"
|
||||||
const val WARNING_TEXT_TAG = "warning_text"
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,22 +8,18 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.text.ClickableText
|
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.SnackbarHost
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.SnackbarHostState
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.testTag
|
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.SpanStyle
|
import androidx.compose.ui.text.SpanStyle
|
||||||
import androidx.compose.ui.text.buildAnnotatedString
|
import androidx.compose.ui.text.buildAnnotatedString
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextDecoration
|
|
||||||
import androidx.compose.ui.text.withStyle
|
import androidx.compose.ui.text.withStyle
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import co.electriccoin.zcash.ui.R
|
import co.electriccoin.zcash.ui.R
|
||||||
|
@ -43,11 +39,9 @@ private fun SecurityWarningPreview() {
|
||||||
ZcashTheme(forceDarkMode = false) {
|
ZcashTheme(forceDarkMode = false) {
|
||||||
GradientSurface {
|
GradientSurface {
|
||||||
SecurityWarning(
|
SecurityWarning(
|
||||||
snackbarHostState = SnackbarHostState(),
|
|
||||||
versionInfo = VersionInfoFixture.new(),
|
versionInfo = VersionInfoFixture.new(),
|
||||||
onBack = {},
|
onBack = {},
|
||||||
onAcknowledged = {},
|
onAcknowledged = {},
|
||||||
onPrivacyPolicy = {},
|
|
||||||
onConfirm = {},
|
onConfirm = {},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -60,20 +54,16 @@ private fun SecurityWarningPreview() {
|
||||||
@Composable
|
@Composable
|
||||||
@Suppress("LongParameterList")
|
@Suppress("LongParameterList")
|
||||||
fun SecurityWarning(
|
fun SecurityWarning(
|
||||||
snackbarHostState: SnackbarHostState,
|
|
||||||
versionInfo: VersionInfo,
|
versionInfo: VersionInfo,
|
||||||
onBack: () -> Unit,
|
onBack: () -> Unit,
|
||||||
onAcknowledged: (Boolean) -> Unit,
|
onAcknowledged: (Boolean) -> Unit,
|
||||||
onPrivacyPolicy: () -> Unit,
|
|
||||||
onConfirm: () -> Unit,
|
onConfirm: () -> Unit,
|
||||||
) {
|
) {
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = { SecurityWarningTopAppBar(onBack = onBack) },
|
topBar = { SecurityWarningTopAppBar(onBack = onBack) },
|
||||||
snackbarHost = { SnackbarHost(snackbarHostState) },
|
|
||||||
) { paddingValues ->
|
) { paddingValues ->
|
||||||
SecurityWarningContent(
|
SecurityWarningContent(
|
||||||
versionInfo = versionInfo,
|
versionInfo = versionInfo,
|
||||||
onPrivacyPolicy = onPrivacyPolicy,
|
|
||||||
onAcknowledged = onAcknowledged,
|
onAcknowledged = onAcknowledged,
|
||||||
onConfirm = onConfirm,
|
onConfirm = onConfirm,
|
||||||
modifier =
|
modifier =
|
||||||
|
@ -102,7 +92,6 @@ private fun SecurityWarningTopAppBar(onBack: () -> Unit) {
|
||||||
@Composable
|
@Composable
|
||||||
private fun SecurityWarningContent(
|
private fun SecurityWarningContent(
|
||||||
versionInfo: VersionInfo,
|
versionInfo: VersionInfo,
|
||||||
onPrivacyPolicy: () -> Unit,
|
|
||||||
onAcknowledged: (Boolean) -> Unit,
|
onAcknowledged: (Boolean) -> Unit,
|
||||||
onConfirm: () -> Unit,
|
onConfirm: () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
@ -119,11 +108,10 @@ private fun SecurityWarningContent(
|
||||||
Spacer(Modifier.height(ZcashTheme.dimens.spacingLarge))
|
Spacer(Modifier.height(ZcashTheme.dimens.spacingLarge))
|
||||||
|
|
||||||
SecurityWarningContentText(
|
SecurityWarningContentText(
|
||||||
versionInfo = versionInfo,
|
versionInfo = versionInfo
|
||||||
onPrivacyPolicy = onPrivacyPolicy
|
|
||||||
)
|
)
|
||||||
|
|
||||||
Spacer(Modifier.height(ZcashTheme.dimens.spacingDefault))
|
Spacer(Modifier.height(ZcashTheme.dimens.spacingLarge))
|
||||||
|
|
||||||
val checkedState = rememberSaveable { mutableStateOf(false) }
|
val checkedState = rememberSaveable { mutableStateOf(false) }
|
||||||
CheckBox(
|
CheckBox(
|
||||||
|
@ -158,35 +146,28 @@ private fun SecurityWarningContent(
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SecurityWarningContentText(
|
fun SecurityWarningContentText(versionInfo: VersionInfo) {
|
||||||
versionInfo: VersionInfo,
|
Column {
|
||||||
onPrivacyPolicy: () -> Unit,
|
Text(
|
||||||
) {
|
text = stringResource(id = R.string.security_warning_text, versionInfo.versionName),
|
||||||
val textPart1 = stringResource(R.string.security_warning_text_part_1, versionInfo.versionName)
|
style = ZcashTheme.extendedTypography.securityWarningText
|
||||||
val textPart2 = stringResource(R.string.security_warning_text_part_2)
|
)
|
||||||
ClickableText(
|
|
||||||
text =
|
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingLarge))
|
||||||
buildAnnotatedString {
|
|
||||||
append(textPart1)
|
val textPart1 = stringResource(R.string.security_warning_text_footnote_part_1)
|
||||||
withStyle(SpanStyle(textDecoration = TextDecoration.Underline)) {
|
val textPart2 = stringResource(R.string.security_warning_text_footnote_part_2)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text =
|
||||||
|
buildAnnotatedString {
|
||||||
|
withStyle(SpanStyle(fontWeight = FontWeight.Bold)) {
|
||||||
|
append(textPart1)
|
||||||
|
}
|
||||||
append(textPart2)
|
append(textPart2)
|
||||||
}
|
},
|
||||||
append(stringResource(R.string.security_warning_text_part_3))
|
style = ZcashTheme.extendedTypography.securityWarningFootnote,
|
||||||
withStyle(SpanStyle(fontWeight = FontWeight.Bold)) {
|
modifier = Modifier.fillMaxWidth()
|
||||||
append(stringResource(R.string.security_warning_text_part_4))
|
)
|
||||||
}
|
}
|
||||||
append(stringResource(R.string.security_warning_text_part_5))
|
|
||||||
},
|
|
||||||
style = ZcashTheme.extendedTypography.securityWarningText,
|
|
||||||
modifier =
|
|
||||||
Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.testTag(SecurityScreenTag.WARNING_TEXT_TAG),
|
|
||||||
onClick = { letterOffset ->
|
|
||||||
// Call the callback only if user clicked the underlined part
|
|
||||||
if (letterOffset >= textPart1.length && letterOffset <= (textPart1.length + textPart2.length)) {
|
|
||||||
onPrivacyPolicy()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,4 +12,9 @@
|
||||||
shielded wallet that keeps your transaction history and wallet balance private. Built by Zcashers, for
|
shielded wallet that keeps your transaction history and wallet balance private. Built by Zcashers, for
|
||||||
Zcashers. Developed and maintained by Electric Coin Co., the inventor of Zcash, Zashi features a built-in
|
Zcashers. Developed and maintained by Electric Coin Co., the inventor of Zcash, Zashi features a built-in
|
||||||
user-feedback mechanism to enable more features, more quickly.</string>
|
user-feedback mechanism to enable more features, more quickly.</string>
|
||||||
|
|
||||||
|
<string name="about_pp_part_1">See our Privacy Policy\u0020</string>
|
||||||
|
<string name="about_pp_part_2">here</string>
|
||||||
|
<string name="about_pp_part_3">.</string>
|
||||||
|
<string name="about_unable_to_web_browser">Unable to find a web browser app.</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -1,18 +1,17 @@
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
<string name="security_warning_text_part_1" formatted="true">Zashi <xliff:g example="0.2.0" id="version_name">%1$s
|
|
||||||
</xliff:g>is a Zcash-only shielded wallet, built by Zcashers for Zcashers. The purpose of this release is
|
|
||||||
primarily to test functionality and collect feedback. While Zashi has been engineered for your privacy and
|
|
||||||
safety (read the privacy policy\u0020</string>
|
|
||||||
<string name="security_warning_text_part_2">here</string>
|
|
||||||
<string name="security_warning_text_part_3">), this release has not yet been security audited.</string>
|
|
||||||
<string name="security_warning_text_part_4">\u0020Users are cautioned to deposit, send, and receive only small
|
|
||||||
amounts
|
|
||||||
of ZEC.</string>
|
|
||||||
<string name="security_warning_text_part_5">\u0020Please click below to proceed.</string>
|
|
||||||
<string name="security_warning_confirm">confirm</string>
|
|
||||||
<string name="security_warning_acknowledge">I acknowledge</string>
|
|
||||||
<string name="security_warning_back_content_description">Back</string>
|
|
||||||
<string name="security_warning_header">Security warning:</string>
|
<string name="security_warning_header">Security warning:</string>
|
||||||
<string name="security_warning_back">Back</string>
|
<string name="security_warning_back">Back</string>
|
||||||
<string name="security_warning_unable_to_web_browser">Unable to find a web browser app.</string>
|
<string name="security_warning_back_content_description">Back</string>
|
||||||
|
|
||||||
|
<string name="security_warning_text" formatted="true">Zashi <xliff:g example="0.2.0" id="version_name">%1$s
|
||||||
|
</xliff:g>is a Zcash-only, shielded wallet — built by Zcashers for Zcashers. Zashi has been engineered for your
|
||||||
|
privacy and safety. By installing and using Zashi, you consent to share crash reports with Electric Coin Co.
|
||||||
|
(the wallet developer), which will help us improve the Zashi user experience.*\n\nPlease acknowledge and
|
||||||
|
confirm below to proceed.</string>
|
||||||
|
<string name="security_warning_text_footnote_part_1">*Note:</string>
|
||||||
|
<string name="security_warning_text_footnote_part_2">\u0020Crash reports might reveal the timing of the crash and
|
||||||
|
what events occurred, but it would not reveal spending or viewing keys.</string>
|
||||||
|
|
||||||
|
<string name="security_warning_confirm">Confirm</string>
|
||||||
|
<string name="security_warning_acknowledge">I acknowledge</string>
|
||||||
</resources>
|
</resources>
|
Loading…
Reference in New Issue