[#50] Preliminary design guide
Known issues - We cannot use downloadable fonts with Compose, so the fonts must be embedded with the app Questions - How does the transparent button show a disabled state? - Are the navigation buttons and secondary buttons supposed to be effectively the same style but one is smaller? TODO - Add gradients. Gradients are not implemented for background, progress bar, etc. Currently they simply use the start color for the gradient - Icons are using Material Icons, pending decision on how to leverage the vectors in the design - Add the border for hero images - Add shapes for the callout, which is currently square - Add padding - Add drop shadows - Double-check colors for correctness
This commit is contained in:
parent
4f513932a6
commit
575b3063bf
|
@ -18,3 +18,5 @@ local.properties
|
||||||
/.idea/deploymentTargetDropDown.xml
|
/.idea/deploymentTargetDropDown.xml
|
||||||
*.hprof
|
*.hprof
|
||||||
/.idea/artifacts
|
/.idea/artifacts
|
||||||
|
/.idea/assetWizardSettings.xml
|
||||||
|
/.idea/inspectionProfiles/Project_Default.xml
|
||||||
|
|
|
@ -34,4 +34,5 @@ If you plan to fork the project to create a new app of your own, please make the
|
||||||
1. During builds, a warning will be printed that says "Unable to detect AGP versions for included builds. All projects in the build should use the same AGP version." This can be safely ignored. The version under build-conventions is the same as the version used elsewhere in the application.
|
1. During builds, a warning will be printed that says "Unable to detect AGP versions for included builds. All projects in the build should use the same AGP version." This can be safely ignored. The version under build-conventions is the same as the version used elsewhere in the application.
|
||||||
1. When the code coverage Gradle property `IS_COVERAGE_ENABLED` is enabled, the debug app APK cannot be run. The coverage flag should therefore only be set when running automated tests.
|
1. When the code coverage Gradle property `IS_COVERAGE_ENABLED` is enabled, the debug app APK cannot be run. The coverage flag should therefore only be set when running automated tests.
|
||||||
1. Test coverage for Compose code will be low, due to [known limitations](https://github.com/jacoco/jacoco/issues/1208) in the interaction between Compose and Jacoco.
|
1. Test coverage for Compose code will be low, due to [known limitations](https://github.com/jacoco/jacoco/issues/1208) in the interaction between Compose and Jacoco.
|
||||||
1. Adding the `espresso-contrib` dependency will cause builds to fail, due to conflicting classes. This is a [known issue](https://github.com/zcash/zcash-android-wallet-sdk/issues/306) with the Zcash Android SDK.
|
1. Adding the `espresso-contrib` dependency will cause builds to fail, due to conflicting classes. This is a [known issue](https://github.com/zcash/zcash-android-wallet-sdk/issues/306) with the Zcash Android SDK.
|
||||||
|
1. Android Studio will warn about the Gradle checksum. This is a [known issue](https://github.com/gradle/gradle/issues/9361) and can be safely ignored.
|
|
@ -124,4 +124,4 @@ fun com.android.build.gradle.BaseExtension.configureBaseExtension() {
|
||||||
execution = "ANDROIDX_TEST_ORCHESTRATOR"
|
execution = "ANDROIDX_TEST_ORCHESTRATOR"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
# Third Party Licenses
|
||||||
|
|
||||||
|
The majority of the contents of this Git repository are covered under the [LICENSE](../LICENSE). However certain items, as described below, are under different license.
|
||||||
|
|
||||||
|
## Electric Coin Company copyrights trademarks
|
||||||
|
|
||||||
|
|
||||||
|
## Rubik Font
|
||||||
|
The fonts under the [font](../ui-lib/src/main/res/ui/common/font) directory are downloaded from [Google Fonts](https://fonts.google.com/specimen/Rubik) and are licensed under the [Open Font License](https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL).
|
|
@ -78,6 +78,7 @@ dependencyResolutionManagement {
|
||||||
alias("androidx-compose-foundation").to("androidx.compose.foundation:foundation:$androidxComposeVersion")
|
alias("androidx-compose-foundation").to("androidx.compose.foundation:foundation:$androidxComposeVersion")
|
||||||
alias("androidx-compose-material").to("androidx.compose.material:material:$androidxComposeVersion")
|
alias("androidx-compose-material").to("androidx.compose.material:material:$androidxComposeVersion")
|
||||||
alias("androidx-compose-material-icons-core").to("androidx.compose.material:material-icons-core:$androidxComposeVersion")
|
alias("androidx-compose-material-icons-core").to("androidx.compose.material:material-icons-core:$androidxComposeVersion")
|
||||||
|
alias("androidx-compose-material-icons-extended").to("androidx.compose.material:material-icons-extended:$androidxComposeVersion")
|
||||||
alias("androidx-compose-tooling").to("androidx.compose.ui:ui-tooling:$androidxComposeVersion")
|
alias("androidx-compose-tooling").to("androidx.compose.ui:ui-tooling:$androidxComposeVersion")
|
||||||
alias("androidx-compose-ui").to("androidx.compose.ui:ui:$androidxComposeVersion")
|
alias("androidx-compose-ui").to("androidx.compose.ui:ui:$androidxComposeVersion")
|
||||||
alias("androidx-compose-compiler").to("androidx.compose.compiler:compiler:$androidxComposeCompilerVersion")
|
alias("androidx-compose-compiler").to("androidx.compose.compiler:compiler:$androidxComposeCompilerVersion")
|
||||||
|
@ -113,6 +114,7 @@ dependencyResolutionManagement {
|
||||||
"androidx-compose-foundation",
|
"androidx-compose-foundation",
|
||||||
"androidx-compose-material",
|
"androidx-compose-material",
|
||||||
"androidx-compose-material-icons-core",
|
"androidx-compose-material-icons-core",
|
||||||
|
"androidx-compose-material-icons-extended",
|
||||||
"androidx-compose-tooling",
|
"androidx-compose-tooling",
|
||||||
"androidx-compose-ui",
|
"androidx-compose-ui",
|
||||||
"androidx-viewmodel-compose"
|
"androidx-viewmodel-compose"
|
||||||
|
|
|
@ -20,6 +20,18 @@ android {
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
jvmTarget = libs.versions.java.get()
|
jvmTarget = libs.versions.java.get()
|
||||||
allWarningsAsErrors = project.property("IS_TREAT_WARNINGS_AS_ERRORS").toString().toBoolean()
|
allWarningsAsErrors = project.property("IS_TREAT_WARNINGS_AS_ERRORS").toString().toBoolean()
|
||||||
|
freeCompilerArgs = freeCompilerArgs.plus("-Xopt-in=kotlin.RequiresOptIn")
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
getByName("main").apply {
|
||||||
|
res.setSrcDirs(
|
||||||
|
setOf(
|
||||||
|
"src/main/res/ui/common",
|
||||||
|
"src/main/res/ui/onboarding"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ import cash.z.ecc.ui.R
|
||||||
import cash.z.ecc.ui.screen.onboarding.model.OnboardingStage
|
import cash.z.ecc.ui.screen.onboarding.model.OnboardingStage
|
||||||
import cash.z.ecc.ui.screen.onboarding.state.OnboardingState
|
import cash.z.ecc.ui.screen.onboarding.state.OnboardingState
|
||||||
import cash.z.ecc.ui.screen.onboarding.test.getStringResource
|
import cash.z.ecc.ui.screen.onboarding.test.getStringResource
|
||||||
import cash.z.ecc.ui.theme.MyApplicationTheme
|
import cash.z.ecc.ui.theme.ZcashTheme
|
||||||
import org.junit.Assert.assertEquals
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
@ -263,7 +263,7 @@ class OnboardingViewTest {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
composeTestRule.setContent {
|
composeTestRule.setContent {
|
||||||
MyApplicationTheme {
|
ZcashTheme {
|
||||||
Onboarding(
|
Onboarding(
|
||||||
onboardingState,
|
onboardingState,
|
||||||
onCreateWallet = { onCreateWalletCallbackCount++ },
|
onCreateWallet = { onCreateWalletCallbackCount++ },
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
<activity
|
<activity
|
||||||
android:name="cash.z.ecc.ui.MainActivity"
|
android:name="cash.z.ecc.ui.MainActivity"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:theme="@style/Theme.MyApplication"
|
|
||||||
android:exported="false">
|
android:exported="false">
|
||||||
</activity>
|
</activity>
|
||||||
</application>
|
</application>
|
||||||
|
|
|
@ -6,7 +6,7 @@ import androidx.activity.compose.setContent
|
||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
import cash.z.ecc.ui.screen.onboarding.view.Onboarding
|
import cash.z.ecc.ui.screen.onboarding.view.Onboarding
|
||||||
import cash.z.ecc.ui.screen.onboarding.viewmodel.OnboardingViewModel
|
import cash.z.ecc.ui.screen.onboarding.viewmodel.OnboardingViewModel
|
||||||
import cash.z.ecc.ui.theme.MyApplicationTheme
|
import cash.z.ecc.ui.theme.ZcashTheme
|
||||||
|
|
||||||
class MainActivity : ComponentActivity() {
|
class MainActivity : ComponentActivity() {
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ class MainActivity : ComponentActivity() {
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContent {
|
setContent {
|
||||||
MyApplicationTheme {
|
ZcashTheme {
|
||||||
Onboarding(
|
Onboarding(
|
||||||
onboardingState = onboardingViewModel.onboardingState,
|
onboardingState = onboardingViewModel.onboardingState,
|
||||||
onImportWallet = { TODO("Implement wallet import") },
|
onImportWallet = { TODO("Implement wallet import") },
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
package cash.z.ecc.ui.screen.common
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material.Button
|
||||||
|
import androidx.compose.material.ButtonDefaults
|
||||||
|
import androidx.compose.material.ButtonDefaults.buttonColors
|
||||||
|
import androidx.compose.material.MaterialTheme
|
||||||
|
import androidx.compose.material.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import cash.z.ecc.ui.theme.ZcashTheme
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun PrimaryButton(
|
||||||
|
onClick: () -> Unit,
|
||||||
|
text: String,
|
||||||
|
modifier: Modifier = Modifier
|
||||||
|
) {
|
||||||
|
Button(
|
||||||
|
onClick = onClick,
|
||||||
|
modifier = modifier.then(
|
||||||
|
Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 16.dp, vertical = 8.dp)
|
||||||
|
),
|
||||||
|
colors = buttonColors(backgroundColor = MaterialTheme.colors.primary)
|
||||||
|
) {
|
||||||
|
Text(style = MaterialTheme.typography.button, text = text, color = MaterialTheme.colors.onPrimary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SecondaryButton(
|
||||||
|
onClick: () -> Unit,
|
||||||
|
text: String,
|
||||||
|
modifier: Modifier = Modifier
|
||||||
|
) {
|
||||||
|
Button(
|
||||||
|
onClick = onClick,
|
||||||
|
modifier = modifier.then(
|
||||||
|
Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 16.dp, vertical = 8.dp)
|
||||||
|
),
|
||||||
|
colors = buttonColors(backgroundColor = MaterialTheme.colors.secondary)
|
||||||
|
) {
|
||||||
|
Text(style = MaterialTheme.typography.button, text = text, color = MaterialTheme.colors.onSecondary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun NavigationButton(
|
||||||
|
onClick: () -> Unit,
|
||||||
|
text: String,
|
||||||
|
modifier: Modifier = Modifier
|
||||||
|
) {
|
||||||
|
Button(
|
||||||
|
onClick = onClick,
|
||||||
|
modifier = modifier.then(
|
||||||
|
Modifier
|
||||||
|
.padding(horizontal = 16.dp, vertical = 8.dp)
|
||||||
|
),
|
||||||
|
colors = buttonColors(backgroundColor = MaterialTheme.colors.secondary)
|
||||||
|
) {
|
||||||
|
Text(style = MaterialTheme.typography.button, text = text, color = MaterialTheme.colors.onSecondary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun TertiaryButton(
|
||||||
|
onClick: () -> Unit,
|
||||||
|
text: String,
|
||||||
|
modifier: Modifier = Modifier
|
||||||
|
) {
|
||||||
|
Button(
|
||||||
|
onClick = onClick,
|
||||||
|
modifier = modifier.then(
|
||||||
|
Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 16.dp, vertical = 8.dp)
|
||||||
|
),
|
||||||
|
elevation = ButtonDefaults.elevation(0.dp, 0.dp, 0.dp),
|
||||||
|
colors = buttonColors(backgroundColor = ZcashTheme.colors.tertiary)
|
||||||
|
) {
|
||||||
|
Text(style = MaterialTheme.typography.button, text = text, color = ZcashTheme.colors.onTertiary)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package cash.z.ecc.ui.screen.common
|
||||||
|
|
||||||
|
import androidx.compose.material.LinearProgressIndicator
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import cash.z.ecc.ui.screen.onboarding.model.Progress
|
||||||
|
import cash.z.ecc.ui.theme.ZcashTheme
|
||||||
|
|
||||||
|
// Eventually rename to GradientLinearProgressIndicator
|
||||||
|
@Composable
|
||||||
|
fun PinkProgress(progress: Progress, modifier: Modifier = Modifier) {
|
||||||
|
// Needs custom implementation to apply gradient
|
||||||
|
LinearProgressIndicator(
|
||||||
|
progress = progress.percent().decimal, modifier,
|
||||||
|
ZcashTheme.colors.progressStart, ZcashTheme.colors.progressBackground
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
package cash.z.ecc.ui.screen.common
|
||||||
|
|
||||||
|
import androidx.compose.material.MaterialTheme
|
||||||
|
import androidx.compose.material.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import cash.z.ecc.ui.theme.ZcashTheme
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Header(
|
||||||
|
text: String,
|
||||||
|
modifier: Modifier = Modifier
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = text,
|
||||||
|
style = MaterialTheme.typography.h1,
|
||||||
|
color = ZcashTheme.colors.onBackgroundHeader,
|
||||||
|
modifier = modifier
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Body(
|
||||||
|
text: String,
|
||||||
|
modifier: Modifier = Modifier
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = text,
|
||||||
|
style = MaterialTheme.typography.body1,
|
||||||
|
color = MaterialTheme.colors.onBackground,
|
||||||
|
modifier = modifier
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
package cash.z.ecc.ui.screen.debug.view
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.material.Surface
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.List
|
||||||
|
import androidx.compose.material.icons.filled.Person
|
||||||
|
import androidx.compose.material.icons.filled.Shield
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import cash.z.ecc.ui.screen.common.Body
|
||||||
|
import cash.z.ecc.ui.screen.common.Header
|
||||||
|
import cash.z.ecc.ui.screen.common.NavigationButton
|
||||||
|
import cash.z.ecc.ui.screen.common.PinkProgress
|
||||||
|
import cash.z.ecc.ui.screen.common.PrimaryButton
|
||||||
|
import cash.z.ecc.ui.screen.common.SecondaryButton
|
||||||
|
import cash.z.ecc.ui.screen.common.TertiaryButton
|
||||||
|
import cash.z.ecc.ui.screen.onboarding.model.Index
|
||||||
|
import cash.z.ecc.ui.screen.onboarding.model.Progress
|
||||||
|
import cash.z.ecc.ui.screen.onboarding.view.Callout
|
||||||
|
import cash.z.ecc.ui.theme.ZcashTheme
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun ComposablePreview() {
|
||||||
|
ZcashTheme(darkTheme = false) {
|
||||||
|
DesignGuide()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
// Allowing magic numbers since this is debug-only
|
||||||
|
@Suppress("MagicNumber")
|
||||||
|
fun DesignGuide() {
|
||||||
|
Surface {
|
||||||
|
Column {
|
||||||
|
Header(text = "H1")
|
||||||
|
Body(text = "body")
|
||||||
|
NavigationButton(onClick = { }, text = "Back")
|
||||||
|
NavigationButton(onClick = { }, text = "Next")
|
||||||
|
PrimaryButton(onClick = { }, text = "Primary button")
|
||||||
|
SecondaryButton(onClick = { }, text = "Secondary button")
|
||||||
|
TertiaryButton(onClick = { }, text = "Tertiary button")
|
||||||
|
Callout(Icons.Filled.Shield, contentDescription = "Shield")
|
||||||
|
Callout(Icons.Filled.Person, contentDescription = "Person")
|
||||||
|
Callout(Icons.Filled.List, contentDescription = "List")
|
||||||
|
PinkProgress(progress = Progress(Index(1), Index(4)), Modifier.fillMaxWidth())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,37 +1,49 @@
|
||||||
package cash.z.ecc.ui.screen.onboarding.view
|
package cash.z.ecc.ui.screen.onboarding.view
|
||||||
|
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
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.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.material.Button
|
import androidx.compose.material.Icon
|
||||||
import androidx.compose.material.LinearProgressIndicator
|
import androidx.compose.material.Surface
|
||||||
import androidx.compose.material.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.painter.ColorPainter
|
import androidx.compose.ui.graphics.painter.ColorPainter
|
||||||
import androidx.compose.ui.graphics.painter.Painter
|
import androidx.compose.ui.graphics.painter.Painter
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import cash.z.ecc.ui.R
|
import cash.z.ecc.ui.R
|
||||||
|
import cash.z.ecc.ui.screen.common.Body
|
||||||
|
import cash.z.ecc.ui.screen.common.Header
|
||||||
|
import cash.z.ecc.ui.screen.common.NavigationButton
|
||||||
|
import cash.z.ecc.ui.screen.common.PinkProgress
|
||||||
|
import cash.z.ecc.ui.screen.common.PrimaryButton
|
||||||
|
import cash.z.ecc.ui.screen.common.SecondaryButton
|
||||||
|
import cash.z.ecc.ui.screen.common.TertiaryButton
|
||||||
import cash.z.ecc.ui.screen.onboarding.model.OnboardingStage
|
import cash.z.ecc.ui.screen.onboarding.model.OnboardingStage
|
||||||
import cash.z.ecc.ui.screen.onboarding.model.Progress
|
import cash.z.ecc.ui.screen.onboarding.model.Progress
|
||||||
import cash.z.ecc.ui.screen.onboarding.state.OnboardingState
|
import cash.z.ecc.ui.screen.onboarding.state.OnboardingState
|
||||||
import cash.z.ecc.ui.theme.MINIMAL_WEIGHT
|
import cash.z.ecc.ui.theme.MINIMAL_WEIGHT
|
||||||
|
import cash.z.ecc.ui.theme.ZcashTheme
|
||||||
|
|
||||||
@Preview
|
@Preview
|
||||||
@Composable
|
@Composable
|
||||||
fun ComposablePreview() {
|
fun ComposablePreview() {
|
||||||
Onboarding(
|
ZcashTheme(darkTheme = true) {
|
||||||
OnboardingState(OnboardingStage.UnifiedAddresses),
|
Onboarding(
|
||||||
onImportWallet = {},
|
OnboardingState(OnboardingStage.UnifiedAddresses),
|
||||||
onCreateWallet = {}
|
onImportWallet = {},
|
||||||
)
|
onCreateWallet = {}
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -44,22 +56,24 @@ fun Onboarding(
|
||||||
onImportWallet: () -> Unit,
|
onImportWallet: () -> Unit,
|
||||||
onCreateWallet: () -> Unit
|
onCreateWallet: () -> Unit
|
||||||
) {
|
) {
|
||||||
Column {
|
Surface {
|
||||||
TopNavButtons(onboardingState)
|
Column {
|
||||||
|
TopNavButtons(onboardingState)
|
||||||
|
|
||||||
val onboardingStage = onboardingState.current.collectAsState().value
|
val onboardingStage = onboardingState.current.collectAsState().value
|
||||||
|
|
||||||
when (onboardingStage) {
|
when (onboardingStage) {
|
||||||
OnboardingStage.ShieldedByDefault -> ShieldedByDefault()
|
OnboardingStage.ShieldedByDefault -> ShieldedByDefault()
|
||||||
OnboardingStage.UnifiedAddresses -> UnifiedAddresses()
|
OnboardingStage.UnifiedAddresses -> UnifiedAddresses()
|
||||||
OnboardingStage.More -> More()
|
OnboardingStage.More -> More()
|
||||||
OnboardingStage.Wallet -> Wallet(
|
OnboardingStage.Wallet -> Wallet(
|
||||||
onCreateWallet = onCreateWallet,
|
onCreateWallet = onCreateWallet,
|
||||||
onImportWallet = onImportWallet
|
onImportWallet = onImportWallet
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
BottomNav(onboardingStage.getProgress(), onboardingState::goNext)
|
||||||
}
|
}
|
||||||
|
|
||||||
BottomNav(onboardingStage.getProgress(), onboardingState::goNext)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,17 +81,17 @@ fun Onboarding(
|
||||||
private fun TopNavButtons(onboardingState: OnboardingState) {
|
private fun TopNavButtons(onboardingState: OnboardingState) {
|
||||||
Row {
|
Row {
|
||||||
if (onboardingState.hasPrevious()) {
|
if (onboardingState.hasPrevious()) {
|
||||||
Button(onboardingState::goPrevious) {
|
NavigationButton(onboardingState::goPrevious, stringResource(R.string.onboarding_back))
|
||||||
Text(stringResource(R.string.onboarding_back))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer(Modifier.fillMaxWidth().weight(MINIMAL_WEIGHT, true))
|
Spacer(
|
||||||
|
Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.weight(MINIMAL_WEIGHT, true)
|
||||||
|
)
|
||||||
|
|
||||||
if (onboardingState.hasNext()) {
|
if (onboardingState.hasNext()) {
|
||||||
Button(onboardingState::goToEnd) {
|
NavigationButton(onboardingState::goToEnd, stringResource(R.string.onboarding_skip))
|
||||||
Text(stringResource(R.string.onboarding_skip))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,14 +100,12 @@ private fun TopNavButtons(onboardingState: OnboardingState) {
|
||||||
private fun BottomNav(progress: Progress, onNext: () -> Unit) {
|
private fun BottomNav(progress: Progress, onNext: () -> Unit) {
|
||||||
if (progress.current != progress.last) {
|
if (progress.current != progress.last) {
|
||||||
Column {
|
Column {
|
||||||
Button(onNext, Modifier.fillMaxWidth()) {
|
SecondaryButton(onNext, stringResource(R.string.onboarding_next), Modifier.fillMaxWidth())
|
||||||
Text(stringResource(R.string.onboarding_next))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Converts from index to human numbering
|
// Converts from index to human numbering
|
||||||
Text((progress.current.value + 1).toString())
|
Body((progress.current.value + 1).toString())
|
||||||
|
|
||||||
LinearProgressIndicator(progress = progress.percent().decimal, Modifier.fillMaxWidth())
|
PinkProgress(progress, Modifier.fillMaxWidth())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -137,12 +149,11 @@ private fun More() {
|
||||||
@Composable
|
@Composable
|
||||||
private fun Wallet(onCreateWallet: () -> Unit, onImportWallet: () -> Unit) {
|
private fun Wallet(onCreateWallet: () -> Unit, onImportWallet: () -> Unit) {
|
||||||
Column {
|
Column {
|
||||||
Button(onCreateWallet, Modifier.fillMaxWidth()) {
|
PrimaryButton(onCreateWallet, stringResource(R.string.onboarding_4_create_new_wallet), Modifier.fillMaxWidth())
|
||||||
Text(stringResource(R.string.onboarding_4_create_new_wallet))
|
TertiaryButton(
|
||||||
}
|
onImportWallet, stringResource(R.string.onboarding_4_import_existing_wallet),
|
||||||
Button(onImportWallet, Modifier.fillMaxWidth()) {
|
Modifier.fillMaxWidth()
|
||||||
Text(stringResource(R.string.onboarding_4_import_existing_wallet))
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,7 +170,14 @@ private fun Content(
|
||||||
@Suppress("MagicNumber")
|
@Suppress("MagicNumber")
|
||||||
Image(image, imageContentDescription, Modifier.fillMaxSize(0.50f))
|
Image(image, imageContentDescription, Modifier.fillMaxSize(0.50f))
|
||||||
}
|
}
|
||||||
Text(headline)
|
Header(headline)
|
||||||
Text(body)
|
Body(body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Callout(imageVector: ImageVector, contentDescription: String) {
|
||||||
|
Box(modifier = Modifier.background(ZcashTheme.colors.callout)) {
|
||||||
|
Icon(imageVector, contentDescription, tint = ZcashTheme.colors.onCallout)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,75 @@
|
||||||
|
@file:Suppress("MagicNumber")
|
||||||
|
|
||||||
package cash.z.ecc.ui.theme
|
package cash.z.ecc.ui.theme
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
|
||||||
@Suppress("MagicNumber")
|
object Dark {
|
||||||
val Purple200 = Color(0xFFBB86FC)
|
val backgroundStart = Color(0xff243155)
|
||||||
|
val backgroundEnd = Color(0xff29365A)
|
||||||
|
|
||||||
@Suppress("MagicNumber")
|
val textHeaderOnBackground = Color(0xffCBDCF2)
|
||||||
val Purple500 = Color(0xFF6200EE)
|
val textBodyOnBackground = Color(0xFF93A4BE)
|
||||||
|
val textPrimaryButton = Color(0xFF0F2341)
|
||||||
|
val textSecondaryButton = Color(0xFF0F2341)
|
||||||
|
val textTertiaryButton = Color.White
|
||||||
|
val textNavigationButton = Color.Black
|
||||||
|
val textCaption = Color(0xFF68728B)
|
||||||
|
|
||||||
@Suppress("MagicNumber")
|
val primaryButton = Color(0xFFFFB900)
|
||||||
val Purple700 = Color(0xFF3700B3)
|
val primaryButtonPressed = Color(0xFFFFD800)
|
||||||
|
val primaryButtonDisabled = Color(0x33F4B728)
|
||||||
|
|
||||||
@Suppress("MagicNumber")
|
val secondaryButton = Color(0xFFA7C0D9)
|
||||||
val Teal200 = Color(0xFF03DAC5)
|
val secondaryButtonPressed = Color(0xFFC8DCEF)
|
||||||
|
val secondaryButtonDisabled = Color(0x33C8DCEF)
|
||||||
|
|
||||||
|
val tertiaryButton = Color.Transparent
|
||||||
|
val tertiaryButtonPressed = Color(0xB0C3D2BA)
|
||||||
|
// TODO how does the invisible button show a disabled state?
|
||||||
|
|
||||||
|
val navigationButton = Color(0xFFA7C0D9)
|
||||||
|
val navigationButtonPressed = Color(0xFFC8DCEF)
|
||||||
|
|
||||||
|
val progressStart = Color(0xFFF364CE)
|
||||||
|
val progressEnd = Color(0xFFF8964F)
|
||||||
|
val progressBackground = Color(0xFF929bb3)
|
||||||
|
|
||||||
|
val callout = Color(0xFFa7bed8)
|
||||||
|
val onCallout = Color(0xFF3d698f)
|
||||||
|
}
|
||||||
|
|
||||||
|
object Light {
|
||||||
|
val backgroundStart = Color(0xFFE3EFF9)
|
||||||
|
val backgroundEnd = Color(0xFFD2E4F3)
|
||||||
|
|
||||||
|
val textHeaderOnBackground = Color(0xff2D3747)
|
||||||
|
val textBodyOnBackground = Color(0xFF7B8897)
|
||||||
|
val textNavigationButton = Color(0xFF7B8897)
|
||||||
|
val textPrimaryButton = Color(0xFFF2F7FC)
|
||||||
|
val textSecondaryButton = Color(0xFF2E476E)
|
||||||
|
val textTertiaryButton = Color(0xFF283559)
|
||||||
|
val textCaption = Color(0xFF2D3747)
|
||||||
|
|
||||||
|
// TODO The button colors are wrong for light
|
||||||
|
val primaryButton = Color(0xFF263357)
|
||||||
|
val primaryButtonPressed = Color(0xFFFFD800)
|
||||||
|
val primaryButtonDisabled = Color(0x33F4B728)
|
||||||
|
|
||||||
|
val secondaryButton = Color(0xFFE8F3FA)
|
||||||
|
val secondaryButtonPressed = Color(0xFFFAFBFD)
|
||||||
|
val secondaryButtonDisabled = Color(0xFFE6EFF8)
|
||||||
|
|
||||||
|
val tertiaryButton = Color.Transparent
|
||||||
|
val tertiaryButtonPressed = Color(0xFFFFFFFF)
|
||||||
|
|
||||||
|
val navigationButton = Color(0xFFE3EDF7)
|
||||||
|
val navigationButtonPressed = Color(0xFFE3EDF7)
|
||||||
|
|
||||||
|
val progressStart = Color(0xFFF364CE)
|
||||||
|
val progressEnd = Color(0xFFF8964F)
|
||||||
|
val progressBackground = Color(0xFFbeccdf)
|
||||||
|
|
||||||
|
val callout = Color(0xFFe6f0f9)
|
||||||
|
val onCallout = Color(0xFFa1b8d0)
|
||||||
|
}
|
||||||
|
|
|
@ -5,43 +5,110 @@ import androidx.compose.material.MaterialTheme
|
||||||
import androidx.compose.material.darkColors
|
import androidx.compose.material.darkColors
|
||||||
import androidx.compose.material.lightColors
|
import androidx.compose.material.lightColors
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
|
import androidx.compose.runtime.Immutable
|
||||||
|
import androidx.compose.runtime.staticCompositionLocalOf
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
|
||||||
private val DarkColorPalette = darkColors(
|
private val DarkColorPalette = darkColors(
|
||||||
primary = Purple200,
|
primary = Dark.primaryButton,
|
||||||
primaryVariant = Purple700,
|
secondary = Dark.secondaryButton,
|
||||||
secondary = Teal200
|
onPrimary = Dark.textPrimaryButton,
|
||||||
|
onSecondary = Dark.textSecondaryButton,
|
||||||
|
surface = Dark.backgroundStart,
|
||||||
|
onSurface = Dark.textBodyOnBackground,
|
||||||
|
background = Dark.backgroundStart,
|
||||||
|
onBackground = Dark.textBodyOnBackground
|
||||||
)
|
)
|
||||||
|
|
||||||
private val LightColorPalette = lightColors(
|
private val LightColorPalette = lightColors(
|
||||||
primary = Purple500,
|
primary = Light.primaryButton,
|
||||||
primaryVariant = Purple700,
|
secondary = Light.secondaryButton,
|
||||||
secondary = Teal200
|
onPrimary = Light.textPrimaryButton,
|
||||||
|
onSecondary = Light.textSecondaryButton,
|
||||||
/* Other default colors to override
|
surface = Light.backgroundStart,
|
||||||
background = Color.White,
|
onSurface = Light.textBodyOnBackground,
|
||||||
surface = Color.White,
|
background = Light.backgroundStart,
|
||||||
onPrimary = Color.White,
|
onBackground = Light.textBodyOnBackground
|
||||||
onSecondary = Color.Black,
|
|
||||||
onBackground = Color.Black,
|
|
||||||
onSurface = Color.Black,
|
|
||||||
*/
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
data class ExtendedColors(
|
||||||
|
val onBackgroundHeader: Color,
|
||||||
|
val tertiary: Color,
|
||||||
|
val onTertiary: Color,
|
||||||
|
val callout: Color,
|
||||||
|
val onCallout: Color,
|
||||||
|
val progressStart: Color,
|
||||||
|
val progressEnd: Color,
|
||||||
|
val progressBackground: Color
|
||||||
|
)
|
||||||
|
|
||||||
|
val DarkExtendedColorPalette = ExtendedColors(
|
||||||
|
onBackgroundHeader = Dark.textHeaderOnBackground,
|
||||||
|
tertiary = Dark.tertiaryButton,
|
||||||
|
onTertiary = Dark.textTertiaryButton,
|
||||||
|
callout = Dark.callout,
|
||||||
|
onCallout = Dark.onCallout,
|
||||||
|
progressStart = Dark.progressStart,
|
||||||
|
progressEnd = Dark.progressEnd,
|
||||||
|
progressBackground = Dark.progressBackground
|
||||||
|
)
|
||||||
|
|
||||||
|
val LightExtendedColorPalette = ExtendedColors(
|
||||||
|
onBackgroundHeader = Light.textHeaderOnBackground,
|
||||||
|
tertiary = Light.tertiaryButton,
|
||||||
|
onTertiary = Light.textTertiaryButton,
|
||||||
|
callout = Light.callout,
|
||||||
|
onCallout = Light.onCallout,
|
||||||
|
progressStart = Light.progressStart,
|
||||||
|
progressEnd = Light.progressEnd,
|
||||||
|
progressBackground = Light.progressBackground
|
||||||
|
)
|
||||||
|
|
||||||
|
val LocalExtendedColors = staticCompositionLocalOf {
|
||||||
|
ExtendedColors(
|
||||||
|
onBackgroundHeader = Color.Unspecified,
|
||||||
|
tertiary = Color.Unspecified,
|
||||||
|
onTertiary = Color.Unspecified,
|
||||||
|
callout = Color.Unspecified,
|
||||||
|
onCallout = Color.Unspecified,
|
||||||
|
progressStart = Color.Unspecified,
|
||||||
|
progressEnd = Color.Unspecified,
|
||||||
|
progressBackground = Color.Unspecified
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MyApplicationTheme(
|
fun ZcashTheme(
|
||||||
darkTheme: Boolean = isSystemInDarkTheme(),
|
darkTheme: Boolean = isSystemInDarkTheme(),
|
||||||
content: @Composable () -> Unit
|
content: @Composable () -> Unit
|
||||||
) {
|
) {
|
||||||
val colors = if (darkTheme) {
|
val baseColors = if (darkTheme) {
|
||||||
DarkColorPalette
|
DarkColorPalette
|
||||||
} else {
|
} else {
|
||||||
LightColorPalette
|
LightColorPalette
|
||||||
}
|
}
|
||||||
|
|
||||||
MaterialTheme(
|
val extendedColors = if (darkTheme) {
|
||||||
colors = colors,
|
DarkExtendedColorPalette
|
||||||
typography = Typography,
|
} else {
|
||||||
shapes = Shapes,
|
LightExtendedColorPalette
|
||||||
content = content
|
}
|
||||||
)
|
|
||||||
|
CompositionLocalProvider(LocalExtendedColors provides extendedColors) {
|
||||||
|
MaterialTheme(
|
||||||
|
colors = baseColors,
|
||||||
|
typography = Typography,
|
||||||
|
shapes = Shapes,
|
||||||
|
content = content
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use with eg. ZcashTheme.colors.tertiary
|
||||||
|
object ZcashTheme {
|
||||||
|
val colors: ExtendedColors
|
||||||
|
@Composable
|
||||||
|
get() = LocalExtendedColors.current
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
package cash.z.ecc.ui.theme
|
|
||||||
|
|
||||||
import androidx.compose.material.Typography
|
|
||||||
import androidx.compose.ui.text.TextStyle
|
|
||||||
import androidx.compose.ui.text.font.FontFamily
|
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
|
||||||
import androidx.compose.ui.unit.sp
|
|
||||||
|
|
||||||
// Set of Material typography styles to start with
|
|
||||||
val Typography = Typography(
|
|
||||||
body1 = TextStyle(
|
|
||||||
fontFamily = FontFamily.Default,
|
|
||||||
fontWeight = FontWeight.Normal,
|
|
||||||
fontSize = 16.sp
|
|
||||||
)
|
|
||||||
/* Other default text styles to override
|
|
||||||
button = TextStyle(
|
|
||||||
fontFamily = FontFamily.Default,
|
|
||||||
fontWeight = FontWeight.W500,
|
|
||||||
fontSize = 14.sp
|
|
||||||
),
|
|
||||||
caption = TextStyle(
|
|
||||||
fontFamily = FontFamily.Default,
|
|
||||||
fontWeight = FontWeight.Normal,
|
|
||||||
fontSize = 12.sp
|
|
||||||
)
|
|
||||||
*/
|
|
||||||
)
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
package cash.z.ecc.ui.theme
|
||||||
|
|
||||||
|
import androidx.compose.material.Typography
|
||||||
|
import androidx.compose.ui.text.TextStyle
|
||||||
|
import androidx.compose.ui.text.font.Font
|
||||||
|
import androidx.compose.ui.text.font.FontFamily
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.ExperimentalUnitApi
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import cash.z.ecc.ui.R
|
||||||
|
|
||||||
|
private val Rubik = FontFamily(
|
||||||
|
Font(R.font.rubik_regular, FontWeight.W400),
|
||||||
|
Font(R.font.rubik_medium, FontWeight.W500)
|
||||||
|
)
|
||||||
|
|
||||||
|
@OptIn(ExperimentalUnitApi::class)
|
||||||
|
val Typography = Typography(
|
||||||
|
h1 = TextStyle(
|
||||||
|
fontFamily = Rubik,
|
||||||
|
fontWeight = FontWeight.W600,
|
||||||
|
fontSize = 30.sp,
|
||||||
|
),
|
||||||
|
body1 = TextStyle(
|
||||||
|
fontFamily = Rubik,
|
||||||
|
fontWeight = FontWeight.Normal,
|
||||||
|
fontSize = 16.sp
|
||||||
|
),
|
||||||
|
caption = TextStyle(
|
||||||
|
fontFamily = Rubik,
|
||||||
|
fontWeight = FontWeight.Medium,
|
||||||
|
fontSize = 16.sp
|
||||||
|
),
|
||||||
|
button = TextStyle(
|
||||||
|
fontFamily = Rubik,
|
||||||
|
fontWeight = FontWeight.Normal,
|
||||||
|
fontSize = 16.sp
|
||||||
|
),
|
||||||
|
)
|
Binary file not shown.
Binary file not shown.
|
@ -1,11 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
<color name="purple_200">#FFBB86FC</color>
|
|
||||||
<color name="purple_500">#FF6200EE</color>
|
|
||||||
<color name="purple_700">#FF3700B3</color>
|
|
||||||
<color name="teal_200">#FF03DAC5</color>
|
|
||||||
<color name="teal_700">#FF018786</color>
|
|
||||||
<color name="black">#FF000000</color>
|
|
||||||
<color name="white">#FFFFFFFF</color>
|
|
||||||
|
|
||||||
</resources>
|
|
|
@ -1,25 +0,0 @@
|
||||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
|
||||||
<!-- Base application theme. -->
|
|
||||||
<style name="Theme.MyApplication" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
|
|
||||||
<!-- Primary brand color. -->
|
|
||||||
<item name="colorPrimary">@color/purple_500</item>
|
|
||||||
<item name="colorPrimaryVariant">@color/purple_700</item>
|
|
||||||
<item name="colorOnPrimary">@color/white</item>
|
|
||||||
<!-- Secondary brand color. -->
|
|
||||||
<item name="colorSecondary">@color/teal_200</item>
|
|
||||||
<item name="colorSecondaryVariant">@color/teal_700</item>
|
|
||||||
<item name="colorOnSecondary">@color/black</item>
|
|
||||||
<!-- Status bar color. -->
|
|
||||||
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
|
|
||||||
<!-- Customize your theme here. -->
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<style name="Theme.MyApplication.NoActionBar">
|
|
||||||
<item name="windowActionBar">false</item>
|
|
||||||
<item name="windowNoTitle">true</item>
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<style name="Theme.MyApplication.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
|
|
||||||
|
|
||||||
<style name="Theme.MyApplication.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
|
|
||||||
</resources>
|
|
Loading…
Reference in New Issue