[#1178] Slightly improve Update screen UI
This commit is contained in:
parent
0ad1477e1b
commit
b58d3069c2
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -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 ->
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 =
|
||||||
|
|
|
@ -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>
|
||||||
|
|
Loading…
Reference in New Issue