[#1338] Redesign Update-Available screen

- Closes  #1338
- Changelog update
This commit is contained in:
Honza Rychnovský 2024-05-07 16:57:45 +02:00 committed by GitHub
parent b235e0cc82
commit a97b71d922
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 218 additions and 76 deletions

View File

@ -16,6 +16,7 @@ directly impact users rather than highlighting other key architectural updates.*
### Changed ### Changed
- We've improved the visibility logic of the little loader that is part of the Balances widget - We've improved the visibility logic of the little loader that is part of the Balances widget
- The App-Update screen UI has been reworked to align with the latest design guidelines
### Removed ### Removed
- Concatenation of the messages on a multi-messages transaction has been removed and will be addressed using a new - Concatenation of the messages on a multi-messages transaction has been removed and will be addressed using a new

View File

@ -245,6 +245,8 @@ abstract class PublishToGooglePlay @Inject constructor(
track, track,
Track().setReleases( Track().setReleases(
listOf(TrackRelease() listOf(TrackRelease()
// TODO [#1440]: Provide a way to inject in-app-update information
// TODO [#1440]: https://github.com/Electric-Coin-Company/zashi-android/issues/1440
.setName(versionName) .setName(versionName)
.setVersionCodes(bundleVersionCodes) .setVersionCodes(bundleVersionCodes)
.setStatus(status) .setStatus(status)

View File

@ -161,7 +161,7 @@ ANDROIDX_CAMERA_VERSION=1.3.2
ANDROIDX_COMPOSE_COMPILER_VERSION=1.5.11 ANDROIDX_COMPOSE_COMPILER_VERSION=1.5.11
ANDROIDX_COMPOSE_MATERIAL3_VERSION=1.2.1 ANDROIDX_COMPOSE_MATERIAL3_VERSION=1.2.1
ANDROIDX_COMPOSE_MATERIAL_ICONS_VERSION=1.6.5 ANDROIDX_COMPOSE_MATERIAL_ICONS_VERSION=1.6.5
ANDROIDX_COMPOSE_VERSION=1.6.5 ANDROIDX_COMPOSE_VERSION=1.6.6
ANDROIDX_CONSTRAINTLAYOUT_VERSION=1.0.1 ANDROIDX_CONSTRAINTLAYOUT_VERSION=1.0.1
ANDROIDX_CORE_VERSION=1.12.0 ANDROIDX_CORE_VERSION=1.12.0
ANDROIDX_ESPRESSO_VERSION=3.5.1 ANDROIDX_ESPRESSO_VERSION=3.5.1

View File

@ -278,6 +278,7 @@ fun Reference(
fontWeight: FontWeight = FontWeight.SemiBold, fontWeight: FontWeight = FontWeight.SemiBold,
textAlign: TextAlign = TextAlign.Center, textAlign: TextAlign = TextAlign.Center,
textStyle: TextStyle = ZcashTheme.typography.primary.bodyLarge, textStyle: TextStyle = ZcashTheme.typography.primary.bodyLarge,
color: Color = ZcashTheme.colors.reference,
imageVector: ImageVector? = null, imageVector: ImageVector? = null,
imageContentDescription: String? = null imageContentDescription: String? = null
) { ) {
@ -303,7 +304,7 @@ fun Reference(
style = style =
textStyle.merge( textStyle.merge(
TextStyle( TextStyle(
color = ZcashTheme.colors.reference, color = color,
textAlign = textAlign, textAlign = textAlign,
textDecoration = TextDecoration.Underline, textDecoration = TextDecoration.Underline,
fontWeight = fontWeight fontWeight = fontWeight

View File

@ -29,6 +29,7 @@ data class ExtendedColors(
val textFieldWarning: Color, val textFieldWarning: Color,
val textFieldFrame: Color, val textFieldFrame: Color,
val textDescription: Color, val textDescription: Color,
val textDescriptionDark: Color,
val textPending: Color, val textPending: Color,
val layoutStroke: Color, val layoutStroke: Color,
val overlay: Color, val overlay: Color,

View File

@ -32,6 +32,7 @@ internal object Dark {
val textFieldWarning = Color(0xFFF40202) val textFieldWarning = Color(0xFFF40202)
val textFieldHint = Color(0xFFB7B7B7) val textFieldHint = Color(0xFFB7B7B7)
val textDescription = Color(0xFF777777) val textDescription = Color(0xFF777777)
val textDescriptionDark = Color(0xFF4D4D4D)
val textProgress = Color(0xFF8B8A8A) val textProgress = Color(0xFF8B8A8A)
val aboutTextColor = Color(0xFF4E4E4E) val aboutTextColor = Color(0xFF4E4E4E)
@ -98,6 +99,7 @@ internal object Light {
val textFieldHint = Color(0xFFB7B7B7) val textFieldHint = Color(0xFFB7B7B7)
val textChipIndex = Color(0xFFEE8592) val textChipIndex = Color(0xFFEE8592)
val textDescription = Color(0xFF777777) val textDescription = Color(0xFF777777)
val textDescriptionDark = Color(0xFF4D4D4D)
val textProgress = Color(0xFF8B8A8A) val textProgress = Color(0xFF8B8A8A)
val screenTitleColor = Color(0xFF040404) val screenTitleColor = Color(0xFF040404)
@ -191,6 +193,7 @@ internal val DarkExtendedColorPalette =
textFieldWarning = Dark.textFieldWarning, textFieldWarning = Dark.textFieldWarning,
textFieldHint = Dark.textFieldHint, textFieldHint = Dark.textFieldHint,
textDescription = Dark.textDescription, textDescription = Dark.textDescription,
textDescriptionDark = Dark.textDescriptionDark,
textPending = Dark.textProgress, textPending = Dark.textProgress,
layoutStroke = Dark.layoutStroke, layoutStroke = Dark.layoutStroke,
overlay = Dark.overlay, overlay = Dark.overlay,
@ -240,6 +243,7 @@ internal val LightExtendedColorPalette =
textFieldWarning = Light.textFieldWarning, textFieldWarning = Light.textFieldWarning,
textFieldHint = Light.textFieldHint, textFieldHint = Light.textFieldHint,
textDescription = Light.textDescription, textDescription = Light.textDescription,
textDescriptionDark = Light.textDescriptionDark,
textPending = Light.textProgress, textPending = Light.textProgress,
layoutStroke = Light.layoutStroke, layoutStroke = Light.layoutStroke,
overlay = Light.overlay, overlay = Light.overlay,
@ -291,6 +295,7 @@ internal val LocalExtendedColors =
textFieldWarning = Color.Unspecified, textFieldWarning = Color.Unspecified,
textFieldFrame = Color.Unspecified, textFieldFrame = Color.Unspecified,
textDescription = Color.Unspecified, textDescription = Color.Unspecified,
textDescriptionDark = Color.Unspecified,
textPending = Color.Unspecified, textPending = Color.Unspecified,
layoutStroke = Color.Unspecified, layoutStroke = Color.Unspecified,
overlay = Color.Unspecified, overlay = Color.Unspecified,

View File

@ -194,6 +194,7 @@ data class ExtendedTypography(
val transactionItemStyles: TransactionItemTextStyles, val transactionItemStyles: TransactionItemTextStyles,
val restoringTopAppBarStyle: TextStyle, val restoringTopAppBarStyle: TextStyle,
val deleteWalletWarnStyle: TextStyle, val deleteWalletWarnStyle: TextStyle,
val updateTitleStyle: TextStyle,
) )
@Suppress("CompositionLocalAllowlist") @Suppress("CompositionLocalAllowlist")
@ -377,6 +378,10 @@ val LocalExtendedTypography =
deleteWalletWarnStyle = deleteWalletWarnStyle =
PrimaryTypography.bodyLarge.copy( PrimaryTypography.bodyLarge.copy(
fontWeight = FontWeight.Bold fontWeight = FontWeight.Bold
),
updateTitleStyle =
PrimaryTypography.titleLarge.copy(
fontWeight = FontWeight.Bold
) )
) )
} }

View File

@ -7,6 +7,7 @@ import co.electriccoin.zcash.test.UiTestPrerequisites
import co.electriccoin.zcash.ui.fixture.UpdateInfoFixture import co.electriccoin.zcash.ui.fixture.UpdateInfoFixture
import co.electriccoin.zcash.ui.integration.test.common.IntegrationTestingActivity import co.electriccoin.zcash.ui.integration.test.common.IntegrationTestingActivity
import co.electriccoin.zcash.ui.screen.update.AppUpdateChecker import co.electriccoin.zcash.ui.screen.update.AppUpdateChecker
import co.electriccoin.zcash.ui.screen.update.AppUpdateCheckerMock
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.screen.update.viewmodel.UpdateViewModel import co.electriccoin.zcash.ui.screen.update.viewmodel.UpdateViewModel

View File

@ -6,6 +6,7 @@ import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.onRoot import androidx.compose.ui.test.onRoot
import androidx.compose.ui.test.performClick import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.performScrollTo
import androidx.test.filters.MediumTest import androidx.test.filters.MediumTest
import co.electriccoin.zcash.test.UiTestPrerequisites import co.electriccoin.zcash.test.UiTestPrerequisites
import co.electriccoin.zcash.ui.R import co.electriccoin.zcash.ui.R
@ -147,6 +148,7 @@ class UpdateViewTest : UiTestPrerequisites() {
composeTestRule.onNodeWithText(getStringResource(R.string.update_link_text)).also { composeTestRule.onNodeWithText(getStringResource(R.string.update_link_text)).also {
it.assertExists() it.assertExists()
it.performScrollTo()
it.performClick() it.performClick()
} }

View File

@ -1,4 +1,4 @@
package co.electriccoin.zcash.ui.integration.test.screen.update.viewmodel package co.electriccoin.zcash.ui.screen.update
import android.app.Activity import android.app.Activity
import android.content.Context import android.content.Context
@ -6,7 +6,6 @@ import androidx.activity.ComponentActivity
import co.electriccoin.zcash.spackle.getPackageInfoCompat import co.electriccoin.zcash.spackle.getPackageInfoCompat
import co.electriccoin.zcash.spackle.versionCodeCompat import co.electriccoin.zcash.spackle.versionCodeCompat
import co.electriccoin.zcash.ui.fixture.UpdateInfoFixture import co.electriccoin.zcash.ui.fixture.UpdateInfoFixture
import co.electriccoin.zcash.ui.screen.update.AppUpdateChecker
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 com.google.android.play.core.appupdate.AppUpdateInfo import com.google.android.play.core.appupdate.AppUpdateInfo
@ -26,13 +25,13 @@ class AppUpdateCheckerMock private constructor() : AppUpdateChecker {
fun new() = AppUpdateCheckerMock() fun new() = AppUpdateCheckerMock()
// used mostly for tests // Used mostly for tests
val resultUpdateInfo = val resultUpdateInfo =
UpdateInfoFixture.new( UpdateInfoFixture.new(
appUpdateInfo = null, appUpdateInfo = null,
state = UpdateState.Prepared, state = UpdateState.Prepared,
priority = AppUpdateChecker.Priority.HIGH, priority = AppUpdateChecker.Priority.LOW,
force = true force = false
) )
} }
@ -52,7 +51,7 @@ class AppUpdateCheckerMock private constructor() : AppUpdateChecker {
val appUpdateInfoTask = fakeAppUpdateManager.appUpdateInfo val appUpdateInfoTask = fakeAppUpdateManager.appUpdateInfo
// to simulate a real-world situation // To simulate a real-world situation
delay(100.milliseconds) delay(100.milliseconds)
appUpdateInfoTask.addOnCompleteListener { infoTask -> appUpdateInfoTask.addOnCompleteListener { infoTask ->
@ -83,8 +82,8 @@ class AppUpdateCheckerMock private constructor() : AppUpdateChecker {
appUpdateInfo: AppUpdateInfo appUpdateInfo: AppUpdateInfo
): Flow<Int> = ): Flow<Int> =
flow { flow {
// to simulate a real-world situation // To simulate a real-world situation
delay(100.milliseconds) delay(2000.milliseconds)
emit(Activity.RESULT_OK) emit(Activity.RESULT_OK)
} }
} }

View File

@ -7,22 +7,27 @@ 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.Spacer
import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxHeight
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.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.rememberScrollState
import androidx.compose.material.icons.Icons import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.filled.Update
import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.DividerDefaults
import androidx.compose.material3.HorizontalDivider
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.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
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.testTag import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import co.electriccoin.zcash.ui.R import co.electriccoin.zcash.ui.R
import co.electriccoin.zcash.ui.design.component.Body import co.electriccoin.zcash.ui.design.component.Body
@ -30,7 +35,6 @@ 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.SmallTopAppBar
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
import co.electriccoin.zcash.ui.screen.update.UpdateTag import co.electriccoin.zcash.ui.screen.update.UpdateTag
@ -73,28 +77,21 @@ fun Update(
updateInfo, updateInfo,
onDownload, onDownload,
onLater, onLater,
modifier = modifier = Modifier.fillMaxWidth()
Modifier
.fillMaxWidth()
.padding(
top = ZcashTheme.dimens.spacingDefault,
bottom = ZcashTheme.dimens.spacingHuge,
start = ZcashTheme.dimens.screenHorizontalSpacingBig,
end = ZcashTheme.dimens.screenHorizontalSpacingBig
)
) )
} }
) { paddingValues -> ) { paddingValues ->
UpdateContentNormal( UpdateContentContent(
onReference, onReference = onReference,
updateInfo = updateInfo,
modifier = modifier =
Modifier Modifier
.fillMaxWidth() .fillMaxWidth()
.padding( .padding(
top = paddingValues.calculateTopPadding(), top = paddingValues.calculateTopPadding(),
bottom = paddingValues.calculateBottomPadding(), bottom = paddingValues.calculateBottomPadding(),
start = ZcashTheme.dimens.spacingDefault, start = ZcashTheme.dimens.screenHorizontalSpacingRegular,
end = ZcashTheme.dimens.spacingDefault end = ZcashTheme.dimens.screenHorizontalSpacingRegular
) )
) )
} }
@ -136,6 +133,7 @@ private fun UpdateTopAppBar(updateInfo: UpdateInfo) {
} }
@Composable @Composable
@Suppress("LongMethod")
private fun UpdateBottomAppBar( private fun UpdateBottomAppBar(
updateInfo: UpdateInfo, updateInfo: UpdateInfo,
onDownload: (state: UpdateState) -> Unit, onDownload: (state: UpdateState) -> Unit,
@ -146,73 +144,143 @@ private fun UpdateBottomAppBar(
modifier = modifier, modifier = modifier,
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.CenterHorizontally
) { ) {
PrimaryButton( HorizontalDivider(
onClick = { onDownload(UpdateState.Running) }, thickness = DividerDefaults.Thickness,
text = stringResource(R.string.update_download_button), color = ZcashTheme.colors.dividerColor
)
Column(
modifier = modifier =
Modifier Modifier
.testTag(UpdateTag.BTN_DOWNLOAD) .padding(
.fillMaxWidth(), top = ZcashTheme.dimens.spacingDefault,
enabled = updateInfo.state != UpdateState.Running, bottom = ZcashTheme.dimens.spacingBig,
outerPaddingValues = PaddingValues(all = ZcashTheme.dimens.spacingNone), start = ZcashTheme.dimens.screenHorizontalSpacingBig,
) end = ZcashTheme.dimens.screenHorizontalSpacingBig
),
horizontalAlignment = Alignment.CenterHorizontally
) {
PrimaryButton(
onClick = { onDownload(UpdateState.Running) },
text = stringResource(R.string.update_download_button),
modifier =
Modifier
.testTag(UpdateTag.BTN_DOWNLOAD)
.fillMaxWidth(),
enabled = updateInfo.state != UpdateState.Running,
outerPaddingValues = PaddingValues(all = ZcashTheme.dimens.spacingNone),
)
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingDefault)) Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingDefault))
TertiaryButton( if (updateInfo.isForce) {
onClick = onLater, Text(
text = text = stringResource(R.string.update_later_disabled_button),
stringResource( textAlign = TextAlign.Center,
updateInfo.isForce.let { force -> style = ZcashTheme.typography.primary.bodyLarge,
if (force) { fontWeight = FontWeight.SemiBold,
R.string.update_later_disabled_button modifier =
Modifier
.padding(all = ZcashTheme.dimens.spacingDefault)
.testTag(UpdateTag.BTN_LATER)
)
} else {
Reference(
text = stringResource(R.string.update_later_enabled_button),
onClick = {
if (updateInfo.state != UpdateState.Running) {
onLater()
} else { } else {
R.string.update_later_enabled_button // Keep current state
} }
} },
), textAlign = TextAlign.Center,
modifier = Modifier.testTag(UpdateTag.BTN_LATER), modifier =
enabled = !updateInfo.isForce && updateInfo.state != UpdateState.Running, Modifier
outerPaddingValues = PaddingValues(top = ZcashTheme.dimens.spacingSmall) .padding(all = ZcashTheme.dimens.spacingDefault)
) .testTag(UpdateTag.BTN_LATER)
)
}
}
} }
} }
@Composable @Composable
private fun UpdateContentNormal( @Suppress("LongMethod")
private fun UpdateContentContent(
onReference: () -> Unit, onReference: () -> Unit,
modifier: Modifier = Modifier updateInfo: UpdateInfo,
modifier: Modifier = Modifier,
) { ) {
val appName = stringResource(id = R.string.app_name)
Column( Column(
modifier = modifier, modifier =
modifier.then(
Modifier
.fillMaxHeight()
.verticalScroll(
rememberScrollState()
)
),
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.CenterHorizontally
) { ) {
// Replace this placeholder graphic once this screen is being redesigned Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingBig))
@Suppress("MagicNumber")
Image( Image(
imageVector = Icons.Filled.Update, imageVector =
contentDescription = stringResource(id = R.string.update_image_content_description), if (updateInfo.isForce) {
modifier = Modifier.fillMaxSize(0.45f) ImageVector.vectorResource(R.drawable.ic_zashi_logo_update_required)
} else {
ImageVector.vectorResource(R.drawable.ic_zashi_logo_update_available)
},
contentDescription = stringResource(id = R.string.update_image_content_description)
) )
Body( Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingBig))
text = stringResource(id = R.string.update_description),
modifier = Text(
Modifier text =
.wrapContentHeight() if (updateInfo.isForce) {
.align(Alignment.CenterHorizontally) stringResource(id = R.string.update_title_required)
} else {
stringResource(id = R.string.update_title_available, appName)
},
style = ZcashTheme.extendedTypography.updateTitleStyle,
textAlign = TextAlign.Center
) )
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingLarge))
Body(
text =
if (updateInfo.isForce) {
stringResource(id = R.string.update_description_required, appName)
} else {
stringResource(id = R.string.update_description_available, appName)
},
textAlign = TextAlign.Center,
color = ZcashTheme.colors.textDescriptionDark
)
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingDefault))
Reference( Reference(
text = stringResource(id = R.string.update_link_text), text = stringResource(id = R.string.update_link_text),
onClick = { onClick = {
onReference() if (updateInfo.state != UpdateState.Running) {
onReference()
} else {
// Keep current state
}
}, },
modifier = fontWeight = FontWeight.Normal,
Modifier textStyle = ZcashTheme.typography.primary.bodyMedium,
.wrapContentHeight() textAlign = TextAlign.Center,
.align(Alignment.CenterHorizontally) color = ZcashTheme.colors.textDescriptionDark,
.padding(all = ZcashTheme.dimens.spacingDefault), modifier = Modifier.padding(all = ZcashTheme.dimens.spacingDefault)
) )
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingDefault))
} }
} }

View File

@ -0,0 +1,34 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="92dp"
android:height="118dp"
android:viewportWidth="92"
android:viewportHeight="118">
<path
android:pathData="M50.11,86.3L64.11,114.47L27.61,98.12L89.79,65.69L84.77,47.89L6.21,5.29L58.15,71.12L84.77,47.89L27.61,98.12"
android:strokeWidth="3"
android:fillColor="#00000000"
android:strokeColor="#000000"/>
<group>
<clip-path
android:pathData="M70.58,84h14.1v18h-14.1z"/>
<path
android:strokeWidth="1"
android:pathData="M80.41,93.27H83.74L77.63,101.24L71.52,93.27H74.85V90.49H80.41V93.27Z"
android:fillColor="#000000"
android:strokeColor="#000000"/>
<path
android:pathData="M79.87,84.93H75.4"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#000000"
android:strokeLineCap="square"/>
<path
android:pathData="M79.87,87.71H75.4"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#000000"
android:strokeLineCap="square"/>
</group>
</vector>

View File

@ -0,0 +1,14 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="92dp"
android:height="118dp"
android:viewportWidth="92"
android:viewportHeight="118">
<path
android:pathData="M50.11,86.02L64.11,114.18L27.61,97.84L89.79,65.4L84.77,47.61L6.21,5L58.15,70.83L84.77,47.61L27.61,97.84"
android:strokeWidth="3"
android:fillColor="#00000000"
android:strokeColor="#000000"/>
<path
android:pathData="M77.86,102.59C72.34,102.59 67.86,98.11 67.86,92.59C67.86,87.06 72.34,82.59 77.86,82.59C83.38,82.59 87.86,87.06 87.86,92.59C87.86,98.11 83.38,102.59 77.86,102.59ZM77.86,87.59C77.59,87.59 77.34,87.69 77.15,87.88C76.96,88.07 76.86,88.32 76.86,88.59V93.59C76.86,93.85 76.96,94.11 77.15,94.29C77.34,94.48 77.59,94.59 77.86,94.59C78.12,94.59 78.38,94.48 78.57,94.29C78.75,94.11 78.86,93.85 78.86,93.59V88.59C78.86,88.32 78.75,88.07 78.57,87.88C78.38,87.69 78.12,87.59 77.86,87.59ZM77.86,97.59C78.12,97.59 78.38,97.48 78.57,97.29C78.75,97.11 78.86,96.85 78.86,96.59C78.86,96.32 78.75,96.07 78.57,95.88C78.38,95.69 78.12,95.59 77.86,95.59C77.59,95.59 77.34,95.69 77.15,95.88C76.96,96.07 76.86,96.32 76.86,96.59C76.86,96.85 76.96,97.11 77.15,97.29C77.34,97.48 77.59,97.59 77.86,97.59Z"
android:fillColor="#000000"/>
</vector>

View File

@ -1,12 +1,21 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<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">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_title_available"><xliff:g id="app_name" example="Zcash">%1$s</xliff:g> here.</string>
<string name="update_title_required">It\'s not you, it\'s me.</string>
<string name="update_description_required">
There is a required update for <xliff:g id="app_name" example="Zcash">%1$s</xliff:g> that makes major
improvements to performance and/or security.
</string>
<string name="update_description_available">
There is a new version of <xliff:g id="app_name" example="Zcash">%1$s</xliff:g> that makes minor updates to
improve performance and/or security.\n\nPlease take a moment to update to the latest version.
</string>
<string name="update_link_text">Learn more about this update here.</string> <string name="update_link_text">Learn more about this update here.</string>
<string name="update_download_button">Download Update</string> <string name="update_download_button">Update</string>
<string name="update_later_enabled_button">Remind me later</string> <string name="update_later_enabled_button">Remind me later</string>
<string name="update_later_disabled_button">This can not be skipped.</string> <string name="update_later_disabled_button">(required)</string>
<string name="update_unable_to_open_play_store">Unable to launch Google Play store app.</string> <string name="update_unable_to_open_play_store">Unable to launch Google Play store app.</string>
</resources> </resources>