[#296] About screen scaffold
This provides a basic scaffold for the About screen. There are several followup issues: - #392 update the in-app legal text - #398 Add open source attributions
This commit is contained in:
parent
5e1d25b34a
commit
08fad9e763
|
@ -192,6 +192,25 @@ class ScreenshotTest {
|
|||
it.performClick()
|
||||
}
|
||||
|
||||
composeTestRule.onNode(hasText(getStringResource(R.string.profile_title))).also {
|
||||
it.assertExists()
|
||||
it.performClick()
|
||||
}
|
||||
|
||||
// About is a subscreen of profile
|
||||
composeTestRule.onNode(hasText(getStringResource(R.string.profile_about))).also {
|
||||
it.performScrollTo()
|
||||
it.assertExists()
|
||||
it.performClick()
|
||||
}
|
||||
aboutScreenshots(composeTestRule)
|
||||
|
||||
// Back to profile
|
||||
composeTestRule.onNode(hasContentDescription(getStringResource(R.string.about_back_content_description))).also {
|
||||
it.assertExists()
|
||||
it.performClick()
|
||||
}
|
||||
|
||||
// Back to home
|
||||
composeTestRule.onNode(hasContentDescription(getStringResource(R.string.settings_back_content_description))).also {
|
||||
it.assertExists()
|
||||
|
@ -431,3 +450,11 @@ private fun supportScreenshots(composeTestRule: ComposeTestRule) {
|
|||
|
||||
ScreenshotTest.takeScreenshot("Support 1")
|
||||
}
|
||||
|
||||
private fun aboutScreenshots(composeTestRule: ComposeTestRule) {
|
||||
composeTestRule.onNode(hasText(getStringResource(R.string.about_title))).also {
|
||||
it.assertExists()
|
||||
}
|
||||
|
||||
ScreenshotTest.takeScreenshot("About 1")
|
||||
}
|
||||
|
|
|
@ -1,17 +1,16 @@
|
|||
# Build Integrity
|
||||
Multiple tools can be put in place to enhance build integrity and reduce the risk of supply chain issues. These tools include:
|
||||
* Policy — We try to minimize third party dependencies, especially when they are not provided by Google and JetBrains. We also try to minimize the number of Gradle plugins.
|
||||
* Policy — We minimize third party dependencies, especially when they are not provided by Google and JetBrains. We also try to minimize the number of Gradle plugins.
|
||||
* Checklists — Our [pull request checklist](../.github/pull_request_template.md) specifies only running code from contributors after reviewing the changes first. Our [dependency update checklist](../.github/ISSUE_TEMPLATE/dependency.md) specifies verifying lock file changes during dependency updates.
|
||||
* Fixed dependency versions — For our dependency declarations, we use exact dependency versions in gradle.properties instead of version ranges.
|
||||
* GitHub Actions versions use SHA instead of tags
|
||||
* Dependency locking
|
||||
* Gradle buildscript (e.g. plugins) dependencies are locked
|
||||
* Kotlin Multiplatform modules have dependency locking enabled
|
||||
* Android modules do not have dependency locking for transitive dependencies enabled. [Issue #55](https://github.com/zcash/secant-android-wallet/issues/55) tracks this feature request.
|
||||
* Dependency hash or signature verification
|
||||
* Gradle — The SHA256 for Gradle is stored in [gradle/wrapper/gradle-wrapper.properties](../gradle/wrapper/gradle-wrapper.properties) which is verified when Gradle is downloaded for the first time
|
||||
* Gradle Wrapper — The SHA256 for the Gradle Wrapper is verified on the continuous integration server
|
||||
* Dependencies — Verification is not currently enabled for buildscript or compile dependencies
|
||||
* Dependencies — Verification is NOT currently enabled for buildscript or compile dependencies
|
||||
|
||||
# Dependency locking
|
||||
## Buildscript
|
||||
|
|
|
@ -30,6 +30,7 @@ android {
|
|||
getByName("main").apply {
|
||||
res.setSrcDirs(
|
||||
setOf(
|
||||
"src/main/res/ui/about",
|
||||
"src/main/res/ui/backup",
|
||||
"src/main/res/ui/common",
|
||||
"src/main/res/ui/home",
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
package co.electriccoin.zcash.ui.screen.about
|
||||
|
||||
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.onNodeWithText
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.test.filters.MediumTest
|
||||
import co.electriccoin.zcash.build.gitSha
|
||||
import co.electriccoin.zcash.ui.R
|
||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||
import co.electriccoin.zcash.ui.fixture.VersionInfoFixture
|
||||
import co.electriccoin.zcash.ui.screen.about.model.VersionInfo
|
||||
import co.electriccoin.zcash.ui.screen.about.view.About
|
||||
import co.electriccoin.zcash.ui.test.getStringResource
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
class AboutViewTest {
|
||||
@get:Rule
|
||||
val composeTestRule = createComposeRule()
|
||||
|
||||
@Test
|
||||
@MediumTest
|
||||
fun setup() {
|
||||
newTestSetup()
|
||||
|
||||
composeTestRule.onNodeWithText(VersionInfoFixture.VERSION_NAME, substring = true).also {
|
||||
it.assertExists()
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithText(gitSha, substring = true).also {
|
||||
it.assertExists()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@MediumTest
|
||||
fun back() {
|
||||
val testSetup = newTestSetup()
|
||||
|
||||
assertEquals(0, testSetup.getOnBackCount())
|
||||
|
||||
composeTestRule.onNodeWithContentDescription(getStringResource(R.string.about_back_content_description)).also {
|
||||
it.performClick()
|
||||
}
|
||||
|
||||
assertEquals(1, testSetup.getOnBackCount())
|
||||
}
|
||||
|
||||
private fun newTestSetup() = TestSetup(composeTestRule, VersionInfoFixture.new())
|
||||
|
||||
private class TestSetup(private val composeTestRule: ComposeContentTestRule, versionInfo: VersionInfo) {
|
||||
|
||||
private val onBackCount = AtomicInteger(0)
|
||||
|
||||
fun getOnBackCount(): Int {
|
||||
composeTestRule.waitForIdle()
|
||||
return onBackCount.get()
|
||||
}
|
||||
|
||||
init {
|
||||
composeTestRule.setContent {
|
||||
ZcashTheme {
|
||||
About(versionInfo = versionInfo) {
|
||||
onBackCount.incrementAndGet()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,11 +11,11 @@ import cash.z.ecc.sdk.fixture.WalletAddressFixture
|
|||
import cash.z.ecc.sdk.model.WalletAddress
|
||||
import co.electriccoin.zcash.ui.R
|
||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||
import co.electriccoin.zcash.ui.screen.profile.util.ProfileConfiguration
|
||||
import co.electriccoin.zcash.ui.test.getStringResource
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Ignore
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
@ -72,17 +72,18 @@ class ProfileViewTest {
|
|||
|
||||
@Test
|
||||
@MediumTest
|
||||
@Ignore("https://github.com/zcash/secant-android-wallet/issues/247")
|
||||
fun address_book() = runTest {
|
||||
val testSetup = newTestSetup(WalletAddressFixture.unified())
|
||||
if (ProfileConfiguration.IS_ADDRESS_BOOK_ENABLED) {
|
||||
val testSetup = newTestSetup(WalletAddressFixture.unified())
|
||||
|
||||
assertEquals(0, testSetup.getOnAddressBookCount())
|
||||
assertEquals(0, testSetup.getOnAddressBookCount())
|
||||
|
||||
composeTestRule.onNodeWithText(getStringResource(R.string.profile_address_book)).also {
|
||||
it.performClick()
|
||||
composeTestRule.onNodeWithText(getStringResource(R.string.profile_address_book)).also {
|
||||
it.performClick()
|
||||
}
|
||||
|
||||
assertEquals(1, testSetup.getOnAddressBookCount())
|
||||
}
|
||||
|
||||
assertEquals(1, testSetup.getOnAddressBookCount())
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -103,16 +104,18 @@ class ProfileViewTest {
|
|||
@Test
|
||||
@MediumTest
|
||||
fun coinholder_vote() = runTest {
|
||||
val testSetup = newTestSetup(WalletAddressFixture.unified())
|
||||
if (ProfileConfiguration.IS_COINHOLDER_VOTE_ENABLED) {
|
||||
val testSetup = newTestSetup(WalletAddressFixture.unified())
|
||||
|
||||
assertEquals(0, testSetup.getOnCoinholderVoteCount())
|
||||
assertEquals(0, testSetup.getOnCoinholderVoteCount())
|
||||
|
||||
composeTestRule.onNodeWithText(getStringResource(R.string.profile_coinholder_vote)).also {
|
||||
it.performScrollTo()
|
||||
it.performClick()
|
||||
composeTestRule.onNodeWithText(getStringResource(R.string.profile_coinholder_vote)).also {
|
||||
it.performScrollTo()
|
||||
it.performClick()
|
||||
}
|
||||
|
||||
assertEquals(1, testSetup.getOnCoinholderVoteCount())
|
||||
}
|
||||
|
||||
assertEquals(1, testSetup.getOnCoinholderVoteCount())
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -131,6 +134,22 @@ class ProfileViewTest {
|
|||
assertEquals(1, testSetup.getOnSupportCount())
|
||||
}
|
||||
|
||||
@Test
|
||||
@MediumTest
|
||||
fun about() = runTest {
|
||||
val testSetup = newTestSetup(WalletAddressFixture.unified())
|
||||
|
||||
assertEquals(0, testSetup.getOnAboutCount())
|
||||
|
||||
composeTestRule.onNodeWithText(getStringResource(R.string.profile_about)).also {
|
||||
it.performScrollTo()
|
||||
it.assertExists()
|
||||
it.performClick()
|
||||
}
|
||||
|
||||
assertEquals(1, testSetup.getOnAboutCount())
|
||||
}
|
||||
|
||||
private fun newTestSetup(walletAddress: WalletAddress) = TestSetup(composeTestRule, walletAddress)
|
||||
|
||||
private class TestSetup(private val composeTestRule: ComposeContentTestRule, walletAddress: WalletAddress) {
|
||||
|
@ -141,6 +160,7 @@ class ProfileViewTest {
|
|||
private val onSettingsCount = AtomicInteger(0)
|
||||
private val onCoinholderVoteCount = AtomicInteger(0)
|
||||
private val onSupportCount = AtomicInteger(0)
|
||||
private val onAboutCount = AtomicInteger(0)
|
||||
|
||||
fun getOnBackCount(): Int {
|
||||
composeTestRule.waitForIdle()
|
||||
|
@ -172,6 +192,11 @@ class ProfileViewTest {
|
|||
return onSupportCount.get()
|
||||
}
|
||||
|
||||
fun getOnAboutCount(): Int {
|
||||
composeTestRule.waitForIdle()
|
||||
return onAboutCount.get()
|
||||
}
|
||||
|
||||
init {
|
||||
composeTestRule.setContent {
|
||||
ZcashTheme {
|
||||
|
@ -194,6 +219,9 @@ class ProfileViewTest {
|
|||
},
|
||||
onSupport = {
|
||||
onSupportCount.getAndIncrement()
|
||||
},
|
||||
onAbout = {
|
||||
onAboutCount.getAndIncrement()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ import cash.z.ecc.sdk.type.fromResources
|
|||
import co.electriccoin.zcash.ui.design.compat.FontCompat
|
||||
import co.electriccoin.zcash.ui.design.component.GradientSurface
|
||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||
import co.electriccoin.zcash.ui.screen.about.WrapAbout
|
||||
import co.electriccoin.zcash.ui.screen.backup.WrapBackup
|
||||
import co.electriccoin.zcash.ui.screen.backup.copyToClipboard
|
||||
import co.electriccoin.zcash.ui.screen.home.model.spendableBalance
|
||||
|
@ -38,7 +39,7 @@ import co.electriccoin.zcash.ui.screen.home.viewmodel.SecretState
|
|||
import co.electriccoin.zcash.ui.screen.home.viewmodel.WalletViewModel
|
||||
import co.electriccoin.zcash.ui.screen.onboarding.view.Onboarding
|
||||
import co.electriccoin.zcash.ui.screen.onboarding.viewmodel.OnboardingViewModel
|
||||
import co.electriccoin.zcash.ui.screen.profile.view.Profile
|
||||
import co.electriccoin.zcash.ui.screen.profile.WrapProfile
|
||||
import co.electriccoin.zcash.ui.screen.request.view.Request
|
||||
import co.electriccoin.zcash.ui.screen.restore.view.RestoreWallet
|
||||
import co.electriccoin.zcash.ui.screen.restore.viewmodel.CompleteWordSetState
|
||||
|
@ -195,6 +196,7 @@ class MainActivity : ComponentActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
private fun Navigation() {
|
||||
val navController = rememberNavController().also {
|
||||
|
@ -217,7 +219,8 @@ class MainActivity : ComponentActivity() {
|
|||
onAddressBook = { },
|
||||
onSettings = { navController.navigate(NAV_SETTINGS) },
|
||||
onCoinholderVote = { },
|
||||
onSupport = { navController.navigate(NAV_SUPPORT) }
|
||||
onSupport = { navController.navigate(NAV_SUPPORT) },
|
||||
onAbout = { navController.navigate(NAV_ABOUT) }
|
||||
)
|
||||
}
|
||||
composable(NAV_WALLET_ADDRESS_DETAILS) {
|
||||
|
@ -254,6 +257,9 @@ class MainActivity : ComponentActivity() {
|
|||
// Pop back stack won't be right if we deep link into support
|
||||
WrapSupport(goBack = { navController.popBackStack() })
|
||||
}
|
||||
composable(NAV_ABOUT) {
|
||||
WrapAbout(goBack = { navController.popBackStack() })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -281,32 +287,6 @@ class MainActivity : ComponentActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Suppress("LongParameterList")
|
||||
private fun WrapProfile(
|
||||
onBack: () -> Unit,
|
||||
onAddressDetails: () -> Unit,
|
||||
onAddressBook: () -> Unit,
|
||||
onSettings: () -> Unit,
|
||||
onCoinholderVote: () -> Unit,
|
||||
onSupport: () -> Unit
|
||||
) {
|
||||
val walletAddresses = walletViewModel.addresses.collectAsState().value
|
||||
if (null == walletAddresses) {
|
||||
// Display loading indicator
|
||||
} else {
|
||||
Profile(
|
||||
walletAddresses.unified,
|
||||
onBack = onBack,
|
||||
onAddressDetails = onAddressDetails,
|
||||
onAddressBook = onAddressBook,
|
||||
onSettings = onSettings,
|
||||
onCoinholderVote = onCoinholderVote,
|
||||
onSupport = onSupport
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun WrapWalletAddresses(
|
||||
goBack: () -> Unit,
|
||||
|
@ -446,6 +426,9 @@ class MainActivity : ComponentActivity() {
|
|||
|
||||
@VisibleForTesting
|
||||
const val NAV_SUPPORT = "support"
|
||||
|
||||
@VisibleForTesting
|
||||
const val NAV_ABOUT = "about"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
package co.electriccoin.zcash.ui.fixture
|
||||
|
||||
import co.electriccoin.zcash.ui.screen.about.model.VersionInfo
|
||||
|
||||
// Magic Number doesn't matter here for hard-coded fixture values
|
||||
@Suppress("MagicNumber")
|
||||
object VersionInfoFixture {
|
||||
const val VERSION_NAME = "1.0.3"
|
||||
const val VERSION_CODE = 3L
|
||||
|
||||
fun new(
|
||||
versionName: String = VERSION_NAME,
|
||||
versionCode: Long = VERSION_CODE
|
||||
) = VersionInfo(versionName, versionCode)
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package co.electriccoin.zcash.ui.screen.about
|
||||
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.compose.runtime.Composable
|
||||
import co.electriccoin.zcash.ui.MainActivity
|
||||
import co.electriccoin.zcash.ui.screen.about.model.VersionInfo
|
||||
import co.electriccoin.zcash.ui.screen.about.view.About
|
||||
|
||||
@Composable
|
||||
internal fun MainActivity.WrapAbout(
|
||||
goBack: () -> Unit
|
||||
) {
|
||||
WrapAbout(this, goBack)
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun WrapAbout(
|
||||
activity: ComponentActivity,
|
||||
goBack: () -> Unit
|
||||
) {
|
||||
val packageInfo = activity.packageManager.getPackageInfo(activity.packageName, 0)
|
||||
|
||||
About(VersionInfo.new(packageInfo), goBack)
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package co.electriccoin.zcash.ui.screen.about.model
|
||||
|
||||
import android.content.pm.PackageInfo
|
||||
import co.electriccoin.zcash.util.VersionCodeCompat
|
||||
|
||||
data class VersionInfo(val versionName: String, val versionCode: Long) {
|
||||
companion object {
|
||||
fun new(packageInfo: PackageInfo) = VersionInfo(
|
||||
packageInfo.versionName ?: "null", // Should only be null during tests
|
||||
VersionCodeCompat.getVersionCode(packageInfo)
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
package co.electriccoin.zcash.ui.screen.about.view
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowBack
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.SmallTopAppBar
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
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.build.gitSha
|
||||
import co.electriccoin.zcash.ui.R
|
||||
import co.electriccoin.zcash.ui.design.component.Body
|
||||
import co.electriccoin.zcash.ui.design.component.GradientSurface
|
||||
import co.electriccoin.zcash.ui.design.component.Header
|
||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||
import co.electriccoin.zcash.ui.fixture.VersionInfoFixture
|
||||
import co.electriccoin.zcash.ui.screen.about.model.VersionInfo
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun AboutPreview() {
|
||||
ZcashTheme(darkTheme = true) {
|
||||
GradientSurface {
|
||||
About(versionInfo = VersionInfoFixture.new(), goBack = {})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun About(
|
||||
versionInfo: VersionInfo,
|
||||
goBack: () -> Unit,
|
||||
) {
|
||||
Scaffold(topBar = {
|
||||
AboutTopAppBar(onBack = goBack)
|
||||
}) {
|
||||
AboutMainContent(versionInfo)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AboutTopAppBar(onBack: () -> Unit) {
|
||||
SmallTopAppBar(
|
||||
title = { Text(text = stringResource(id = R.string.about_title)) },
|
||||
navigationIcon = {
|
||||
IconButton(
|
||||
onClick = onBack
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.ArrowBack,
|
||||
contentDescription = stringResource(R.string.about_back_content_description)
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AboutMainContent(versionInfo: VersionInfo) {
|
||||
Column(Modifier.verticalScroll(rememberScrollState())) {
|
||||
Icon(painterResource(id = R.drawable.ic_launcher_adaptive_foreground), contentDescription = null)
|
||||
Text(stringResource(id = R.string.app_name))
|
||||
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
|
||||
Header(stringResource(id = R.string.about_version_header))
|
||||
Body(stringResource(R.string.about_version_format, versionInfo.versionName, versionInfo.versionCode))
|
||||
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
|
||||
Header(stringResource(id = R.string.about_build_header))
|
||||
Body(gitSha)
|
||||
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
|
||||
Header(stringResource(id = R.string.about_legal_header))
|
||||
Body(stringResource(id = R.string.about_legal_info))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
package co.electriccoin.zcash.ui.screen.profile
|
||||
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.viewModels
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import cash.z.ecc.sdk.model.WalletAddresses
|
||||
import co.electriccoin.zcash.ui.MainActivity
|
||||
import co.electriccoin.zcash.ui.screen.home.viewmodel.WalletViewModel
|
||||
import co.electriccoin.zcash.ui.screen.profile.view.Profile
|
||||
|
||||
@Composable
|
||||
@Suppress("LongParameterList")
|
||||
internal fun MainActivity.WrapProfile(
|
||||
onBack: () -> Unit,
|
||||
onAddressDetails: () -> Unit,
|
||||
onAddressBook: () -> Unit,
|
||||
onSettings: () -> Unit,
|
||||
onCoinholderVote: () -> Unit,
|
||||
onSupport: () -> Unit,
|
||||
onAbout: () -> Unit
|
||||
) {
|
||||
WrapProfile(
|
||||
this,
|
||||
onBack = onBack,
|
||||
onAddressDetails = onAddressDetails,
|
||||
onAddressBook = onAddressBook,
|
||||
onSettings = onSettings,
|
||||
onCoinholderVote = onCoinholderVote,
|
||||
onSupport = onSupport,
|
||||
onAbout = onAbout
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Suppress("LongParameterList")
|
||||
internal fun WrapProfile(
|
||||
activity: ComponentActivity,
|
||||
onBack: () -> Unit,
|
||||
onAddressDetails: () -> Unit,
|
||||
onAddressBook: () -> Unit,
|
||||
onSettings: () -> Unit,
|
||||
onCoinholderVote: () -> Unit,
|
||||
onSupport: () -> Unit,
|
||||
onAbout: () -> Unit
|
||||
) {
|
||||
val viewModel by activity.viewModels<WalletViewModel>()
|
||||
val walletAddresses = viewModel.addresses.collectAsState().value
|
||||
|
||||
WrapProfile(
|
||||
walletAddresses,
|
||||
onBack = onBack,
|
||||
onAddressDetails = onAddressDetails,
|
||||
onAddressBook = onAddressBook,
|
||||
onSettings = onSettings,
|
||||
onCoinholderVote = onCoinholderVote,
|
||||
onSupport = onSupport,
|
||||
onAbout = onAbout
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Suppress("LongParameterList")
|
||||
internal fun WrapProfile(
|
||||
walletAddresses: WalletAddresses?,
|
||||
onBack: () -> Unit,
|
||||
onAddressDetails: () -> Unit,
|
||||
onAddressBook: () -> Unit,
|
||||
onSettings: () -> Unit,
|
||||
onCoinholderVote: () -> Unit,
|
||||
onSupport: () -> Unit,
|
||||
onAbout: () -> Unit
|
||||
) {
|
||||
if (null == walletAddresses) {
|
||||
// Display loading indicator
|
||||
} else {
|
||||
Profile(
|
||||
walletAddresses.unified,
|
||||
onBack = onBack,
|
||||
onAddressDetails = onAddressDetails,
|
||||
onAddressBook = onAddressBook,
|
||||
onSettings = onSettings,
|
||||
onCoinholderVote = onCoinholderVote,
|
||||
onSupport = onSupport,
|
||||
onAbout = onAbout
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package co.electriccoin.zcash.ui.screen.profile.util
|
||||
|
||||
object ProfileConfiguration {
|
||||
const val IS_ADDRESS_BOOK_ENABLED = false
|
||||
const val IS_COINHOLDER_VOTE_ENABLED = false
|
||||
}
|
|
@ -31,6 +31,7 @@ import co.electriccoin.zcash.ui.design.component.TertiaryButton
|
|||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||
import co.electriccoin.zcash.ui.screen.profile.util.AndroidQrCodeImageGenerator
|
||||
import co.electriccoin.zcash.ui.screen.profile.util.JvmQrCodeGenerator
|
||||
import co.electriccoin.zcash.ui.screen.profile.util.ProfileConfiguration
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
|
@ -46,7 +47,8 @@ fun ComposablePreview() {
|
|||
onAddressBook = {},
|
||||
onSettings = {},
|
||||
onCoinholderVote = {},
|
||||
onSupport = {}
|
||||
onSupport = {},
|
||||
onAbout = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -61,7 +63,8 @@ fun Profile(
|
|||
onAddressBook: () -> Unit,
|
||||
onSettings: () -> Unit,
|
||||
onCoinholderVote: () -> Unit,
|
||||
onSupport: () -> Unit
|
||||
onSupport: () -> Unit,
|
||||
onAbout: () -> Unit
|
||||
) {
|
||||
Column {
|
||||
ProfileTopAppBar(onBack = onBack)
|
||||
|
@ -71,7 +74,10 @@ fun Profile(
|
|||
onAddressBook = onAddressBook,
|
||||
onSettings = onSettings,
|
||||
onCoinholderVote = onCoinholderVote,
|
||||
onSupport = onSupport
|
||||
onSupport = onSupport,
|
||||
onAbout = onAbout,
|
||||
isAddressBookEnabled = ProfileConfiguration.IS_ADDRESS_BOOK_ENABLED,
|
||||
isCoinholderVoteEnabled = ProfileConfiguration.IS_COINHOLDER_VOTE_ENABLED
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -104,7 +110,9 @@ private fun ProfileContents(
|
|||
onSettings: () -> Unit,
|
||||
onCoinholderVote: () -> Unit,
|
||||
onSupport: () -> Unit,
|
||||
isAddressBookEnabled: Boolean = false
|
||||
onAbout: () -> Unit,
|
||||
isAddressBookEnabled: Boolean,
|
||||
isCoinholderVoteEnabled: Boolean
|
||||
) {
|
||||
Column(Modifier.verticalScroll(rememberScrollState())) {
|
||||
QrCode(data = walletAddress.address, DEFAULT_QR_CODE_SIZE, Modifier.align(Alignment.CenterHorizontally))
|
||||
|
@ -123,8 +131,11 @@ private fun ProfileContents(
|
|||
}
|
||||
TertiaryButton(onClick = onSettings, text = stringResource(id = R.string.profile_settings))
|
||||
Divider()
|
||||
TertiaryButton(onClick = onCoinholderVote, text = stringResource(id = R.string.profile_coinholder_vote))
|
||||
if (isCoinholderVoteEnabled) {
|
||||
TertiaryButton(onClick = onCoinholderVote, text = stringResource(id = R.string.profile_coinholder_vote))
|
||||
}
|
||||
TertiaryButton(onClick = onSupport, text = stringResource(id = R.string.profile_support))
|
||||
TertiaryButton(onClick = onAbout, text = stringResource(id = R.string.profile_about))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="about_title">About</string>
|
||||
<string name="about_back_content_description">Back</string>
|
||||
<string name="about_icon_content_description">Zcash icon</string>
|
||||
<string name="about_version_header">Version</string>
|
||||
<string name="about_version_format" formatted="true"><xliff:g id="version_name" example="1.0">%1$s</xliff:g> (<xliff:g id="version_code" example="1.0">%2$d</xliff:g>)</string>
|
||||
<string name="about_build_header">Build</string>
|
||||
<string name="about_legal_header">Legal</string>
|
||||
<!-- TODO [#392] Update with real legal info. -->
|
||||
<string name="about_legal_info">GitHub Issue #392</string>
|
||||
</resources>
|
|
@ -9,5 +9,6 @@
|
|||
<string name="profile_settings">Settings</string>
|
||||
<string name="profile_coinholder_vote">Coinholder Vote</string>
|
||||
<string name="profile_support">Support</string>
|
||||
<string name="profile_about">About</string>
|
||||
|
||||
</resources>
|
||||
|
|
Loading…
Reference in New Issue