[#1178] Slightly improve Update screen UI

This commit is contained in:
Honza Rychnovský 2024-01-10 16:12:27 +01:00 committed by GitHub
parent 0ad1477e1b
commit b58d3069c2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 44 additions and 38 deletions

View File

@ -12,6 +12,8 @@ directly impact users rather than highlighting other key architectural updates.*
### Changed ### Changed
- The Not Enough Space screen used for notifying about insufficient free device disk space now provides the light - The Not Enough Space screen used for notifying about insufficient free device disk space now provides the light
theme by default theme by default
- The App Update screen's user interface was improved to align with the other implemented screens. Its final design
is still in progress.
## [0.2.0 (523)] - 2024-01-09 ## [0.2.0 (523)] - 2024-01-09

View File

@ -42,10 +42,11 @@ import co.electriccoin.zcash.ui.design.theme.ZcashTheme
private fun ButtonComposablePreview() { private fun ButtonComposablePreview() {
ZcashTheme(forceDarkMode = false) { ZcashTheme(forceDarkMode = false) {
GradientSurface { GradientSurface {
Column { Column(Modifier.padding(ZcashTheme.dimens.spacingDefault)) {
PrimaryButton(onClick = { }, text = "Primary") PrimaryButton(onClick = { }, text = "Primary")
SecondaryButton(onClick = { }, text = "Secondary") SecondaryButton(onClick = { }, text = "Secondary")
TertiaryButton(onClick = { }, text = "Tertiary") TertiaryButton(onClick = { }, text = "Tertiary")
TertiaryButton(onClick = { }, text = "Tertiary", enabled = false)
NavigationButton(onClick = { }, text = "Navigation") NavigationButton(onClick = { }, text = "Navigation")
DangerousButton(onClick = { }, text = "Dangerous") DangerousButton(onClick = { }, text = "Dangerous")
} }
@ -165,7 +166,7 @@ fun NavigationButton(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
outerPaddingValues: PaddingValues = outerPaddingValues: PaddingValues =
PaddingValues( PaddingValues(
horizontal = ZcashTheme.dimens.spacingDefault, horizontal = ZcashTheme.dimens.spacingNone,
vertical = ZcashTheme.dimens.spacingSmall vertical = ZcashTheme.dimens.spacingSmall
), ),
) { ) {
@ -195,7 +196,7 @@ fun TertiaryButton(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
outerPaddingValues: PaddingValues = outerPaddingValues: PaddingValues =
PaddingValues( PaddingValues(
horizontal = ZcashTheme.dimens.spacingDefault, horizontal = ZcashTheme.dimens.spacingNone,
vertical = ZcashTheme.dimens.spacingSmall vertical = ZcashTheme.dimens.spacingSmall
), ),
enabled: Boolean = true enabled: Boolean = true
@ -208,6 +209,7 @@ fun TertiaryButton(
Modifier Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(outerPaddingValues) .padding(outerPaddingValues)
.defaultMinSize(ZcashTheme.dimens.buttonWidth, ZcashTheme.dimens.buttonHeight)
), ),
enabled = enabled, enabled = enabled,
elevation = ButtonDefaults.buttonElevation(0.dp, 0.dp, 0.dp), elevation = ButtonDefaults.buttonElevation(0.dp, 0.dp, 0.dp),
@ -229,7 +231,7 @@ fun DangerousButton(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
outerPaddingValues: PaddingValues = outerPaddingValues: PaddingValues =
PaddingValues( PaddingValues(
horizontal = ZcashTheme.dimens.spacingDefault, horizontal = ZcashTheme.dimens.spacingNone,
vertical = ZcashTheme.dimens.spacingSmall vertical = ZcashTheme.dimens.spacingSmall
), ),
) { ) {
@ -241,6 +243,7 @@ fun DangerousButton(
Modifier Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(outerPaddingValues) .padding(outerPaddingValues)
.defaultMinSize(ZcashTheme.dimens.buttonWidth, ZcashTheme.dimens.buttonHeight)
), ),
colors = buttonColors(containerColor = ZcashTheme.colors.dangerous) colors = buttonColors(containerColor = ZcashTheme.colors.dangerous)
) { ) {

View File

@ -11,7 +11,6 @@ import co.electriccoin.zcash.ui.screen.update.model.UpdateInfo
import co.electriccoin.zcash.ui.screen.update.model.UpdateState import co.electriccoin.zcash.ui.screen.update.model.UpdateState
import co.electriccoin.zcash.ui.test.getAppContext import co.electriccoin.zcash.ui.test.getAppContext
import com.google.android.play.core.install.model.ActivityResult import com.google.android.play.core.install.model.ActivityResult
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Rule import org.junit.Rule
@ -30,7 +29,6 @@ class AppUpdateCheckerImpTest {
} }
private fun getAppUpdateInfoFlow(): Flow<UpdateInfo> { private fun getAppUpdateInfoFlow(): Flow<UpdateInfo> {
@Suppress("MagicNumber")
return updateChecker.newCheckForUpdateAvailabilityFlow( return updateChecker.newCheckForUpdateAvailabilityFlow(
context context
) )
@ -38,7 +36,6 @@ class AppUpdateCheckerImpTest {
@Test @Test
@MediumTest @MediumTest
@OptIn(ExperimentalCoroutinesApi::class)
fun check_for_update_availability_test() = fun check_for_update_availability_test() =
runTest { runTest {
assertNotNull(updateChecker) assertNotNull(updateChecker)
@ -56,7 +53,6 @@ class AppUpdateCheckerImpTest {
@Test @Test
@MediumTest @MediumTest
@OptIn(ExperimentalCoroutinesApi::class)
fun start_update_availability_test() = fun start_update_availability_test() =
runTest { runTest {
getAppUpdateInfoFlow().onFirst { updateInfo -> getAppUpdateInfoFlow().onFirst { updateInfo ->

View File

@ -41,13 +41,13 @@ class UpdateViewAndroidTest : UiTestPrerequisites() {
) )
newTestSetup(updateInfo) newTestSetup(updateInfo)
composeTestRule.onNodeWithText(getStringResource(R.string.update_header)).also { composeTestRule.onNodeWithText(getStringResource(R.string.update_header), ignoreCase = true).also {
it.assertExists() it.assertExists()
} }
Espresso.pressBack() Espresso.pressBack()
composeTestRule.onNodeWithText(getStringResource(R.string.update_header)).also { composeTestRule.onNodeWithText(getStringResource(R.string.update_header), ignoreCase = true).also {
it.assertDoesNotExist() it.assertDoesNotExist()
} }
} }
@ -64,13 +64,13 @@ class UpdateViewAndroidTest : UiTestPrerequisites() {
) )
newTestSetup(updateInfo) newTestSetup(updateInfo)
composeTestRule.onNodeWithText(getStringResource(R.string.update_critical_header)).also { composeTestRule.onNodeWithText(getStringResource(R.string.update_critical_header), ignoreCase = true).also {
it.assertExists() it.assertExists()
} }
Espresso.pressBack() Espresso.pressBack()
composeTestRule.onNodeWithText(getStringResource(R.string.update_critical_header)).also { composeTestRule.onNodeWithText(getStringResource(R.string.update_critical_header), ignoreCase = true).also {
it.assertExists() it.assertExists()
} }
} }

View File

@ -15,7 +15,6 @@ import co.electriccoin.zcash.ui.screen.update.UpdateTag
import co.electriccoin.zcash.ui.screen.update.model.UpdateInfo import co.electriccoin.zcash.ui.screen.update.model.UpdateInfo
import co.electriccoin.zcash.ui.screen.update.model.UpdateState import co.electriccoin.zcash.ui.screen.update.model.UpdateState
import co.electriccoin.zcash.ui.test.getStringResource import co.electriccoin.zcash.ui.test.getStringResource
import co.electriccoin.zcash.ui.test.getStringResourceWithArgs
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
@ -38,13 +37,15 @@ class UpdateViewTest : UiTestPrerequisites() {
newTestSetup(updateInfo) newTestSetup(updateInfo)
composeTestRule.onNodeWithText( composeTestRule.onNodeWithText(
getStringResourceWithArgs(R.string.update_critical_header) text = getStringResource(R.string.update_critical_header),
ignoreCase = true
).also { ).also {
it.assertExists() it.assertExists()
} }
composeTestRule.onNodeWithText( composeTestRule.onNodeWithText(
getStringResourceWithArgs(R.string.update_later_disabled_button) text = getStringResource(R.string.update_later_disabled_button),
ignoreCase = true
).also { ).also {
it.assertExists() it.assertExists()
} }
@ -82,12 +83,16 @@ class UpdateViewTest : UiTestPrerequisites() {
newTestSetup(updateInfo) newTestSetup(updateInfo)
composeTestRule.onNodeWithText(getStringResourceWithArgs(R.string.update_header)).also { composeTestRule.onNodeWithText(
text = getStringResource(R.string.update_header),
ignoreCase = true
).also {
it.assertExists() it.assertExists()
} }
composeTestRule.onNodeWithText( composeTestRule.onNodeWithText(
getStringResourceWithArgs(R.string.update_later_enabled_button) text = getStringResource(R.string.update_later_enabled_button),
ignoreCase = true
).also { ).also {
it.assertExists() it.assertExists()
} }

View File

@ -49,7 +49,7 @@ class AppUpdateCheckerImp private constructor() : AppUpdateChecker {
if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE && if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE &&
appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE) appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)
) { ) {
// we force user to update immediately in case of high priority // We force user to update immediately in case of high priority
// or in case of staleness days passed // or in case of staleness days passed
if (isHighPriority(appUpdateInfo.updatePriority()) || if (isHighPriority(appUpdateInfo.updatePriority()) ||
(appUpdateInfo.clientVersionStalenessDays() ?: -1) >= stalenessDays (appUpdateInfo.clientVersionStalenessDays() ?: -1) >= stalenessDays
@ -58,6 +58,9 @@ class AppUpdateCheckerImp private constructor() : AppUpdateChecker {
} else { } else {
emitSuccess(this, infoTask.result, UpdateState.Done) emitSuccess(this, infoTask.result, UpdateState.Done)
} }
} else {
// Return Done in case of no update available
emitSuccess(this, infoTask.result, UpdateState.Done)
} }
} }
awaitClose { awaitClose {

View File

@ -5,20 +5,19 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxHeight
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.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Update import androidx.compose.material.icons.filled.Update
import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@ -30,6 +29,7 @@ import co.electriccoin.zcash.ui.design.component.Body
import co.electriccoin.zcash.ui.design.component.GradientSurface import co.electriccoin.zcash.ui.design.component.GradientSurface
import co.electriccoin.zcash.ui.design.component.PrimaryButton import co.electriccoin.zcash.ui.design.component.PrimaryButton
import co.electriccoin.zcash.ui.design.component.Reference import co.electriccoin.zcash.ui.design.component.Reference
import co.electriccoin.zcash.ui.design.component.SmallTopAppBar
import co.electriccoin.zcash.ui.design.component.TertiaryButton import co.electriccoin.zcash.ui.design.component.TertiaryButton
import co.electriccoin.zcash.ui.design.theme.ZcashTheme import co.electriccoin.zcash.ui.design.theme.ZcashTheme
import co.electriccoin.zcash.ui.fixture.UpdateInfoFixture import co.electriccoin.zcash.ui.fixture.UpdateInfoFixture
@ -63,7 +63,7 @@ fun Update(
) { ) {
Scaffold( Scaffold(
topBar = { topBar = {
UpdateTopAppBar(updateInfo) UpdateTopAppBar(updateInfo = updateInfo)
}, },
snackbarHost = { snackbarHost = {
SnackbarHost(snackbarHostState) SnackbarHost(snackbarHostState)
@ -120,23 +120,18 @@ fun UpdateOverlayRunning(updateInfo: UpdateInfo) {
} }
@Composable @Composable
@OptIn(ExperimentalMaterial3Api::class)
private fun UpdateTopAppBar(updateInfo: UpdateInfo) { private fun UpdateTopAppBar(updateInfo: UpdateInfo) {
TopAppBar( SmallTopAppBar(
title = { titleText =
Text( stringResource(
text = updateInfo.isForce.let { force ->
stringResource( if (force) {
updateInfo.isForce.let { force -> R.string.update_critical_header
if (force) { } else {
R.string.update_critical_header R.string.update_header
} else { }
R.string.update_header }
}
}
)
) )
}
) )
} }
@ -159,6 +154,8 @@ private fun UpdateBottomAppBar(
outerPaddingValues = PaddingValues(all = ZcashTheme.dimens.spacingNone) outerPaddingValues = PaddingValues(all = ZcashTheme.dimens.spacingNone)
) )
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingDefault))
TertiaryButton( TertiaryButton(
onClick = onLater, onClick = onLater,
text = text =

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="update_header">Update available!</string> <string name="update_header">Update available</string>
<string name="update_critical_header">Critical update required!</string> <string name="update_critical_header">Critical update required!</string>
<string name="update_image_content_description"></string> <string name="update_image_content_description"></string>
<string name="update_description">There is a new version of the app available.</string> <string name="update_description">There is a new version of the app available.</string>