Improve backup onboarding for numberless accounts.

This commit is contained in:
Greyson Parrelli
2026-09-09 16:37:44 -04:00
committed by Cody Henthorne
parent 16cc68e80a
commit bd3c4af8e4
86 changed files with 945 additions and 425 deletions
@@ -136,7 +136,7 @@ class MessageBackupsCheckoutActivityTest {
// Backup education screen
composeTestRule.onNodeWithText(context.getString(R.string.RemoteBackupsSettingsFragment__signal_backups)).assertIsDisplayed()
composeTestRule.onNodeWithText(context.getString(R.string.MessageBackupsEducationScreen__enable_backups)).performClick()
composeTestRule.onNodeWithText(context.getString(R.string.MessageBackupsEducationScreen__continue)).performClick()
// Key education screen
composeTestRule.onNodeWithText(context.getString(R.string.MessageBackupsKeyEducationScreen__your_backup_key)).assertIsDisplayed()
@@ -0,0 +1,217 @@
/*
* Copyright 2026 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.thoughtcrime.securesms.backup.v2.ui.subscription
import android.content.Context
import android.widget.Toast
import androidx.annotation.UiContext
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.launch
import org.signal.core.models.AccountEntropyPool
import org.signal.core.models.ServiceId
import org.signal.core.ui.compose.Buttons
import org.signal.core.ui.compose.DayNightPreviews
import org.signal.core.ui.compose.Dialogs
import org.signal.core.ui.compose.Previews
import org.signal.core.ui.compose.Scaffolds
import org.signal.core.ui.compose.SignalIcons
import org.signal.core.ui.compose.theme.SignalTheme
import org.signal.passwordmanager.SignalCredentialManager
import org.signal.signallogin.card.SignalLoginCard
import org.thoughtcrime.securesms.R
import java.util.UUID
import org.signal.core.ui.R as CoreUiR
import org.signal.signallogin.R as SignalLoginR
object MessageBackupsConfirmRecoveryKeyTestTags {
const val CONFIRM_BUTTON = "confirm-recovery-key-screen-confirm-button"
const val ENTER_MANUALLY_BUTTON = "confirm-recovery-key-screen-enter-manually-button"
}
/**
* Asks a user who already has a Signal Login to confirm the recovery key that came with it, by pulling the credential
* back out of their password manager. Shown in place of the record-and-verify screens, since the key already exists and
* was already presented to them during registration.
*/
@Composable
fun MessageBackupsConfirmRecoveryKeyScreen(
aci: ServiceId.ACI,
aep: AccountEntropyPool,
onNavigationClick: () -> Unit = {},
onViewDetailsClick: () -> Unit = {},
onConfirmed: () -> Unit = {},
onEnterManuallyClick: () -> Unit = {}
) {
val context = LocalContext.current
val coroutineScope = rememberCoroutineScope()
val successMessage = stringResource(R.string.MessageBackupsConfirmRecoveryKeyScreen__recovery_key_confirmed)
var displayConfirmationFailure by remember { mutableStateOf(false) }
if (displayConfirmationFailure) {
ConfirmationFailureDialog(
onEnterManuallyClick = onEnterManuallyClick,
onDismiss = { displayConfirmationFailure = false }
)
}
Scaffolds.Settings(
title = "",
navigationIcon = SignalIcons.ArrowStart.imageVector,
onNavigationClick = onNavigationClick
) { paddingValues ->
Column(
modifier = Modifier
.fillMaxSize()
.padding(paddingValues)
.padding(horizontal = dimensionResource(CoreUiR.dimen.gutter))
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.fillMaxWidth()
.weight(1f)
.verticalScroll(rememberScrollState())
) {
Image(
painter = painterResource(SignalLoginR.drawable.image_signal_login_keys),
contentDescription = null,
modifier = Modifier
.padding(top = 12.dp)
.size(96.dp)
)
Text(
text = stringResource(R.string.MessageBackupsConfirmRecoveryKeyScreen__confirm_your_recovery_key),
style = MaterialTheme.typography.headlineMedium,
textAlign = TextAlign.Center,
modifier = Modifier.padding(top = 24.dp)
)
Text(
text = stringResource(R.string.MessageBackupsConfirmRecoveryKeyScreen__your_recovery_key_is_a_64_character_code),
style = MaterialTheme.typography.bodyLarge,
color = MaterialTheme.colorScheme.onSurfaceVariant,
textAlign = TextAlign.Center,
modifier = Modifier.padding(top = 12.dp)
)
SignalLoginCard(
aci = aci,
aep = aep,
onViewDetailsClicked = onViewDetailsClick,
modifier = Modifier.padding(top = 32.dp)
)
Spacer(modifier = Modifier.height(24.dp))
}
Text(
text = stringResource(R.string.MessageBackupsConfirmRecoveryKeyScreen__you_will_be_prompted_with_your_saved_password),
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant,
textAlign = TextAlign.Center,
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 16.dp)
)
Buttons.LargeTonal(
onClick = {
coroutineScope.launch {
if (getKeyFromCredentialManager(context, aci) == aep.displayValue) {
Toast.makeText(context, successMessage, Toast.LENGTH_SHORT).show()
onConfirmed()
} else {
displayConfirmationFailure = true
}
}
},
modifier = Modifier
.fillMaxWidth()
.testTag(MessageBackupsConfirmRecoveryKeyTestTags.CONFIRM_BUTTON)
) {
Text(text = stringResource(R.string.MessageBackupsConfirmRecoveryKeyScreen__confirm_recovery_key))
}
Buttons.LargeTonal(
onClick = onEnterManuallyClick,
colors = ButtonDefaults.filledTonalButtonColors(
containerColor = SignalTheme.colors.colorSurface2,
contentColor = MaterialTheme.colorScheme.onPrimaryContainer
),
modifier = Modifier
.fillMaxWidth()
.padding(top = 16.dp, bottom = 16.dp)
.testTag(MessageBackupsConfirmRecoveryKeyTestTags.ENTER_MANUALLY_BUTTON)
) {
Text(text = stringResource(R.string.MessageBackupsConfirmRecoveryKeyScreen__enter_manually))
}
}
}
}
@Composable
private fun ConfirmationFailureDialog(
onEnterManuallyClick: () -> Unit,
onDismiss: () -> Unit
) {
Dialogs.SimpleAlertDialog(
title = stringResource(R.string.MessageBackupsConfirmRecoveryKeyScreen__error_confirming_recovery_key),
body = stringResource(R.string.MessageBackupsConfirmRecoveryKeyScreen__your_recovery_key_could_not_be_confirmed),
confirm = stringResource(R.string.MessageBackupsConfirmRecoveryKeyScreen__enter_manually),
dismiss = stringResource(android.R.string.cancel),
onConfirm = onEnterManuallyClick,
onDismiss = onDismiss
)
}
/**
* The password manager stores the Signal Login under the account key, so that is the credential id we ask for.
*/
private suspend fun getKeyFromCredentialManager(
@UiContext activityContext: Context,
aci: ServiceId.ACI
): String? {
return SignalCredentialManager.getCredential(activityContext, aci.toString().uppercase())?.password
}
@DayNightPreviews
@Composable
private fun MessageBackupsConfirmRecoveryKeyScreenPreview() {
Previews.Preview {
MessageBackupsConfirmRecoveryKeyScreen(
aci = ServiceId.ACI.from(UUID.fromString("a6b28482-2e32-83d0-7f23-91360a4c2b91")),
aep = AccountEntropyPool("uy38jh2778hjjhj8lk19ga61s672jsj089r023s6a57809bap92j2yh5t326vv7t")
)
}
}
@@ -14,10 +14,10 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@@ -32,18 +32,19 @@ import org.signal.core.ui.compose.DayNightPreviews
import org.signal.core.ui.compose.Previews
import org.signal.core.ui.compose.Scaffolds
import org.signal.core.ui.compose.SignalIcons
import org.signal.core.ui.compose.theme.SignalTheme
import org.thoughtcrime.securesms.R
import org.signal.core.ui.R as CoreUiR
/**
* Educational content which allows user to proceed to set up automatic backups
* or navigate to a support page to learn more.
* or leave the flow without enabling them.
*/
@Composable
fun MessageBackupsEducationScreen(
onNavigationClick: () -> Unit,
onEnableBackups: () -> Unit,
onLearnMore: () -> Unit
onNotNow: () -> Unit
) {
Scaffolds.Settings(
onNavigationClick = onNavigationClick,
@@ -65,7 +66,7 @@ fun MessageBackupsEducationScreen(
) {
item {
Image(
painter = painterResource(id = R.drawable.image_signal_backups),
painter = painterResource(id = R.drawable.image_signal_backups_clock),
contentDescription = null,
modifier = Modifier
.padding(top = 24.dp)
@@ -119,18 +120,22 @@ fun MessageBackupsEducationScreen(
modifier = Modifier.fillMaxWidth()
) {
Text(
text = stringResource(id = R.string.MessageBackupsEducationScreen__enable_backups)
text = stringResource(id = R.string.MessageBackupsEducationScreen__continue)
)
}
TextButton(
onClick = onLearnMore,
Buttons.LargeTonal(
onClick = onNotNow,
colors = ButtonDefaults.filledTonalButtonColors(
containerColor = SignalTheme.colors.colorSurface2,
contentColor = MaterialTheme.colorScheme.onPrimaryContainer
),
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 16.dp)
.padding(top = 16.dp, bottom = 16.dp)
) {
Text(
text = stringResource(id = R.string.MessageBackupsEducationScreen__learn_more)
text = stringResource(id = R.string.MessageBackupsEducationScreen__not_now)
)
}
}
@@ -144,7 +149,7 @@ private fun MessageBackupsEducationSheetPreview() {
MessageBackupsEducationScreen(
onNavigationClick = {},
onEnableBackups = {},
onLearnMore = {}
onNotNow = {}
)
}
}
@@ -6,10 +6,12 @@
package org.thoughtcrime.securesms.backup.v2.ui.subscription
import android.app.Activity
import android.net.Uri
import android.os.Bundle
import android.view.View
import android.widget.Toast
import androidx.activity.OnBackPressedCallback
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.VisibleForTesting
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
@@ -18,6 +20,7 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.core.os.bundleOf
import androidx.fragment.app.viewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.compose.LocalLifecycleOwner
import androidx.lifecycle.compose.collectAsStateWithLifecycle
@@ -29,15 +32,21 @@ import com.google.android.gms.common.GoogleApiAvailability
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import kotlinx.coroutines.rx3.asFlowable
import org.signal.core.ui.compose.CollectActions
import org.signal.core.ui.compose.ComposeFragment
import org.signal.core.ui.compose.Dialogs
import org.signal.core.util.Result
import org.signal.core.util.Util
import org.signal.core.util.concurrent.SignalDispatchers
import org.signal.core.util.getSerializableCompat
import org.signal.passwordmanager.SignalCredentialManager
import org.signal.signallogin.pdf.SignalLoginPdfRenderer
import org.signal.signallogin.viewdetails.SignalLoginViewDetailsScreen
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.backup.DeletionState
import org.thoughtcrime.securesms.backup.v2.MessageBackupTier
import org.thoughtcrime.securesms.components.settings.app.account.signallogin.SignalLoginViewDetailsAction
import org.thoughtcrime.securesms.components.settings.app.account.signallogin.SignalLoginViewDetailsViewModel
import org.thoughtcrime.securesms.components.settings.app.subscription.donate.InAppPaymentCheckoutDelegate
import org.thoughtcrime.securesms.compose.Nav
import org.thoughtcrime.securesms.database.InAppPaymentTable
@@ -58,6 +67,8 @@ class MessageBackupsFlowFragment : ComposeFragment(), InAppPaymentCheckoutDelega
const val TIER = "tier"
const val CLIPBOARD_TIMEOUT_SECONDS = 60
private const val PDF_MIME_TYPE = "application/pdf"
fun create(messageBackupTier: MessageBackupTier?): MessageBackupsFlowFragment {
return MessageBackupsFlowFragment().apply {
arguments = bundleOf(TIER to messageBackupTier)
@@ -69,10 +80,25 @@ class MessageBackupsFlowFragment : ComposeFragment(), InAppPaymentCheckoutDelega
MessageBackupsFlowViewModel(
initialTierSelection = requireArguments().getSerializableCompat(TIER, MessageBackupTier::class.java),
googlePlayApiAvailability = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(requireContext()),
isCredentialManagerSupported = SignalCredentialManager.isSupported(requireContext())
isCredentialManagerSupported = SignalCredentialManager.isSupported(requireContext()),
isPhoneNumberless = SignalStore.account.isPhoneNumberless
)
}
private val signalLoginViewDetailsViewModel: SignalLoginViewDetailsViewModel by viewModels()
private val savePdfLauncher = registerForActivityResult(ActivityResultContracts.CreateDocument(PDF_MIME_TYPE)) { uri: Uri? ->
if (uri != null) {
val context = requireContext().applicationContext
lifecycleScope.launch {
val result = SignalLoginPdfRenderer.renderTo(context, uri, signalLoginViewDetailsViewModel.state.value)
if (result is Result.Failure) {
Toast.makeText(context, result.failure.userMessageRes, Toast.LENGTH_LONG).show()
}
}
}
}
private val errorHandler = InAppPaymentCheckoutDelegate.ErrorHandler()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@@ -134,9 +160,7 @@ class MessageBackupsFlowFragment : ComposeFragment(), InAppPaymentCheckoutDelega
MessageBackupsEducationScreen(
onNavigationClick = viewModel::goToPreviousStage,
onEnableBackups = viewModel::goToNextStage,
onLearnMore = {
CommunicationActions.openBrowserLink(requireContext(), getString(R.string.remote_backup_support_url))
}
onNotNow = viewModel::goToPreviousStage
)
}
@@ -201,7 +225,34 @@ class MessageBackupsFlowFragment : ComposeFragment(), InAppPaymentCheckoutDelega
MessageBackupsKeyVerifyScreen(
backupKey = state.accountEntropyPool.displayValue,
onNavigationClick = viewModel::goToPreviousStage,
onNextClick = viewModel::goToNextStage
onNextClick = viewModel::goToNextStage,
mode = if (state.isPhoneNumberless) {
MessageBackupsKeyVerifyScreenMode.SIGNAL_LOGIN
} else {
MessageBackupsKeyVerifyScreenMode.DEFAULT
}
)
}
composable(route = MessageBackupsStage.Route.CONFIRM_RECOVERY_KEY.name) {
MessageBackupsConfirmRecoveryKeyScreen(
aci = state.aci,
aep = state.accountEntropyPool,
onNavigationClick = viewModel::goToPreviousStage,
onViewDetailsClick = viewModel::goToSignalLoginViewDetails,
onConfirmed = viewModel::onRecoveryKeyConfirmed,
onEnterManuallyClick = viewModel::goToEnterRecoveryKeyManually
)
}
composable(route = MessageBackupsStage.Route.SIGNAL_LOGIN_VIEW_DETAILS.name) {
val signalLoginState by signalLoginViewDetailsViewModel.state.collectAsStateWithLifecycle()
CollectActions(signalLoginViewDetailsViewModel.actions) { action -> handleSignalLoginViewDetailsAction(action) }
SignalLoginViewDetailsScreen(
state = signalLoginState,
onEvent = signalLoginViewDetailsViewModel::onEvent
)
}
@@ -273,6 +324,23 @@ class MessageBackupsFlowFragment : ComposeFragment(), InAppPaymentCheckoutDelega
}
}
private fun handleSignalLoginViewDetailsAction(action: SignalLoginViewDetailsAction) {
when (action) {
SignalLoginViewDetailsAction.NavigateBack -> viewModel.goToPreviousStage()
SignalLoginViewDetailsAction.LaunchSaveToPasswordManager -> {
lifecycleScope.launch {
SignalCredentialManager.saveCredential(
activityContext = requireActivity(),
username = signalLoginViewDetailsViewModel.state.value.accountKey,
password = signalLoginViewDetailsViewModel.state.value.recoveryKey
)
}
}
SignalLoginViewDetailsAction.LaunchSaveAsPdf -> savePdfLauncher.launch(SignalLoginPdfRenderer.suggestedFileName(requireContext()))
is SignalLoginViewDetailsAction.CopyTextToClipboard -> Util.copyToClipboard(requireContext(), action.text, CLIPBOARD_TIMEOUT_SECONDS)
}
}
override fun onUserLaunchedAnExternalApplication() = error("Not supported by this fragment.")
override fun navigateToDonationPending(inAppPayment: InAppPaymentTable.InAppPayment) = error("Not supported by this fragment.")
@@ -7,6 +7,7 @@ package org.thoughtcrime.securesms.backup.v2.ui.subscription
import androidx.compose.runtime.Immutable
import org.signal.core.models.AccountEntropyPool
import org.signal.core.models.ServiceId
import org.signal.core.util.billing.BillingResponseCode
import org.thoughtcrime.securesms.backup.v2.MessageBackupTier
import org.thoughtcrime.securesms.components.settings.app.backups.remote.BackupKeySaveState
@@ -24,6 +25,8 @@ data class MessageBackupsFlowState(
val startScreen: MessageBackupsStage,
val stage: MessageBackupsStage = startScreen,
val accountEntropyPool: AccountEntropyPool = SignalStore.account.accountEntropyPool,
val aci: ServiceId.ACI = SignalStore.account.requireAci(),
val isPhoneNumberless: Boolean = false,
val failure: Throwable? = null,
val paymentReadyState: PaymentReadyState = PaymentReadyState.NOT_READY,
val backupKeySaveState: BackupKeySaveState? = null
@@ -54,6 +54,7 @@ class MessageBackupsFlowViewModel(
private val initialTierSelection: MessageBackupTier?,
googlePlayApiAvailability: Int,
private val isCredentialManagerSupported: Boolean,
private val isPhoneNumberless: Boolean,
startScreen: MessageBackupsStage = if (SignalStore.backup.backupTier == null) MessageBackupsStage.EDUCATION else MessageBackupsStage.TYPE_SELECTION
) : ViewModel(), BackupKeyCredentialManagerHandler {
@@ -68,7 +69,8 @@ class MessageBackupsFlowViewModel(
googlePlayApiAvailability = GooglePlayServicesAvailability.fromCode(googlePlayApiAvailability),
currentMessageBackupTier = SignalStore.backup.backupTier,
selectedMessageBackupTier = resolveSelectedTier(initialTierSelection, SignalStore.backup.backupTier),
startScreen = startScreen
startScreen = startScreen,
isPhoneNumberless = isPhoneNumberless
)
)
@@ -237,11 +239,13 @@ class MessageBackupsFlowViewModel(
internalStateFlow.update {
when (it.stage) {
MessageBackupsStage.CANCEL -> error("Unsupported state transition from terminal state CANCEL")
MessageBackupsStage.EDUCATION -> it.copy(stage = MessageBackupsStage.BACKUP_KEY_EDUCATION)
MessageBackupsStage.EDUCATION -> it.copy(stage = if (isPhoneNumberless) MessageBackupsStage.CONFIRM_RECOVERY_KEY else MessageBackupsStage.BACKUP_KEY_EDUCATION)
MessageBackupsStage.BACKUP_KEY_EDUCATION -> it.copy(stage = if (isCredentialManagerSupported) MessageBackupsStage.BACKUP_KEY_RECORD else MessageBackupsStage.BACKUP_KEY_RECORD_MANUALLY)
MessageBackupsStage.BACKUP_KEY_RECORD -> it.copy(stage = MessageBackupsStage.TYPE_SELECTION)
MessageBackupsStage.BACKUP_KEY_RECORD_MANUALLY -> it.copy(stage = MessageBackupsStage.BACKUP_KEY_VERIFY)
MessageBackupsStage.BACKUP_KEY_VERIFY -> it.copy(stage = MessageBackupsStage.TYPE_SELECTION)
MessageBackupsStage.CONFIRM_RECOVERY_KEY -> it.copy(stage = MessageBackupsStage.TYPE_SELECTION)
MessageBackupsStage.SIGNAL_LOGIN_VIEW_DETAILS -> error("Unsupported state transition from SIGNAL_LOGIN_VIEW_DETAILS")
MessageBackupsStage.TYPE_SELECTION -> validateTypeAndUpdateState(it)
MessageBackupsStage.CHECKOUT_SHEET -> it.copy(stage = MessageBackupsStage.PROCESS_PAYMENT)
MessageBackupsStage.CREATING_IN_APP_PAYMENT -> error("This is driven by an async coroutine.")
@@ -264,8 +268,10 @@ class MessageBackupsFlowViewModel(
MessageBackupsStage.BACKUP_KEY_EDUCATION -> MessageBackupsStage.EDUCATION
MessageBackupsStage.BACKUP_KEY_RECORD -> MessageBackupsStage.BACKUP_KEY_EDUCATION
MessageBackupsStage.BACKUP_KEY_RECORD_MANUALLY -> if (isCredentialManagerSupported) MessageBackupsStage.BACKUP_KEY_RECORD else MessageBackupsStage.BACKUP_KEY_EDUCATION
MessageBackupsStage.BACKUP_KEY_VERIFY -> MessageBackupsStage.BACKUP_KEY_RECORD_MANUALLY
MessageBackupsStage.TYPE_SELECTION -> MessageBackupsStage.BACKUP_KEY_RECORD
MessageBackupsStage.BACKUP_KEY_VERIFY -> if (isPhoneNumberless) MessageBackupsStage.CONFIRM_RECOVERY_KEY else MessageBackupsStage.BACKUP_KEY_RECORD_MANUALLY
MessageBackupsStage.CONFIRM_RECOVERY_KEY -> MessageBackupsStage.EDUCATION
MessageBackupsStage.SIGNAL_LOGIN_VIEW_DETAILS -> MessageBackupsStage.CONFIRM_RECOVERY_KEY
MessageBackupsStage.TYPE_SELECTION -> if (isPhoneNumberless) MessageBackupsStage.CONFIRM_RECOVERY_KEY else MessageBackupsStage.BACKUP_KEY_RECORD
MessageBackupsStage.CHECKOUT_SHEET -> MessageBackupsStage.TYPE_SELECTION
MessageBackupsStage.CREATING_IN_APP_PAYMENT -> MessageBackupsStage.CREATING_IN_APP_PAYMENT
MessageBackupsStage.PROCESS_PAYMENT -> MessageBackupsStage.PROCESS_PAYMENT
@@ -290,6 +296,26 @@ class MessageBackupsFlowViewModel(
}
}
/** The user asked to see the full keys that make up their Signal Login. */
fun goToSignalLoginViewDetails() {
internalStateFlow.update {
it.copy(stage = MessageBackupsStage.SIGNAL_LOGIN_VIEW_DETAILS)
}
}
/** The user chose to type their recovery key in by hand instead of pulling it from their password manager. */
fun goToEnterRecoveryKeyManually() {
internalStateFlow.update {
it.copy(stage = MessageBackupsStage.BACKUP_KEY_VERIFY)
}
}
/** The recovery key stored in the user's password manager matched the one on this device. */
fun onRecoveryKeyConfirmed() {
SignalStore.backup.lastVerifyKeyTime = System.currentTimeMillis()
goToNextStage()
}
fun onMessageBackupTierUpdated(messageBackupTier: MessageBackupTier) {
internalStateFlow.update {
it.copy(
@@ -43,6 +43,18 @@ import kotlin.random.Random
import kotlin.random.nextInt
import org.signal.core.ui.R as CoreUiR
enum class MessageBackupsKeyVerifyScreenMode {
/**
* Displayed when the user recorded their recovery key earlier in this same flow.
*/
DEFAULT,
/**
* Displayed when the user's recovery key came with their Signal Login rather than being recorded in this flow.
*/
SIGNAL_LOGIN
}
/**
* Prompt user to re-enter backup key (AEP) to confirm they have it still.
*/
@@ -51,7 +63,8 @@ import org.signal.core.ui.R as CoreUiR
fun MessageBackupsKeyVerifyScreen(
backupKey: String,
onNavigationClick: () -> Unit = {},
onNextClick: () -> Unit = {}
onNextClick: () -> Unit = {},
mode: MessageBackupsKeyVerifyScreenMode = MessageBackupsKeyVerifyScreenMode.DEFAULT
) {
val coroutineScope = rememberCoroutineScope()
val sheetState = rememberModalBottomSheetState(
@@ -72,7 +85,10 @@ fun MessageBackupsKeyVerifyScreen(
},
captionContent = {
Text(
text = stringResource(R.string.MessageBackupsKeyVerifyScreen__enter_the_backup_key_that_you_just_recorded),
text = when (mode) {
MessageBackupsKeyVerifyScreenMode.DEFAULT -> stringResource(R.string.MessageBackupsKeyVerifyScreen__enter_the_backup_key_that_you_just_recorded)
MessageBackupsKeyVerifyScreenMode.SIGNAL_LOGIN -> stringResource(R.string.MessageBackupsKeyVerifyScreen__enter_the_recovery_key_from_your_signal_login)
},
style = MaterialTheme.typography.bodyLarge.copy(color = MaterialTheme.colorScheme.onSurfaceVariant)
)
},
@@ -17,6 +17,8 @@ enum class MessageBackupsStage(
BACKUP_KEY_RECORD(route = Route.BACKUP_KEY_RECORD),
BACKUP_KEY_RECORD_MANUALLY(route = Route.BACKUP_KEY_RECORD_MANUALLY),
BACKUP_KEY_VERIFY(route = Route.BACKUP_KEY_VERIFY),
CONFIRM_RECOVERY_KEY(route = Route.CONFIRM_RECOVERY_KEY),
SIGNAL_LOGIN_VIEW_DETAILS(route = Route.SIGNAL_LOGIN_VIEW_DETAILS),
TYPE_SELECTION(route = Route.TYPE_SELECTION),
CREATING_IN_APP_PAYMENT(route = Route.TYPE_SELECTION),
CHECKOUT_SHEET(route = Route.TYPE_SELECTION),
@@ -32,6 +34,8 @@ enum class MessageBackupsStage(
CANCEL,
EDUCATION,
BACKUP_KEY_EDUCATION,
CONFIRM_RECOVERY_KEY,
SIGNAL_LOGIN_VIEW_DETAILS,
BACKUP_KEY_RECORD,
BACKUP_KEY_RECORD_MANUALLY,
BACKUP_KEY_VERIFY,
@@ -35,6 +35,7 @@ import org.thoughtcrime.securesms.backup.v2.ui.subscription.MessageBackupsType
import org.thoughtcrime.securesms.components.settings.app.subscription.donate.InAppPaymentCheckoutDelegate
import org.thoughtcrime.securesms.database.InAppPaymentTable
import org.thoughtcrime.securesms.dependencies.AppDependencies
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.util.viewModel
/**
@@ -63,6 +64,7 @@ abstract class UpgradeToPaidTierBottomSheet : ComposeBottomSheetDialogFragment()
initialTierSelection = MessageBackupTier.PAID,
googlePlayApiAvailability = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(requireContext()),
isCredentialManagerSupported = SignalCredentialManager.isSupported(requireContext()),
isPhoneNumberless = SignalStore.account.isPhoneNumberless,
startScreen = MessageBackupsStage.TYPE_SELECTION
)
}
@@ -0,0 +1,61 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="81dp"
android:height="81dp"
android:viewportWidth="81"
android:viewportHeight="81">
<path
android:fillColor="#FFABAFF8"
android:fillType="evenOdd"
android:pathData="M40.5 70.5C34.98 70.5 29.82 68.96 25.4 66.28V61.3C25.4 58.09 22.85 55.49 19.69 55.49 18.22 55.49 16.87 56.06 15.86 57 12.79 52.26 11 46.59 11 40.5 11 23.93 24.21 10.5 40.5 10.5 56.79 10.5 70 23.93 70 40.5 70 57.07 56.79 70.5 40.5 70.5Z"/>
<group>
<clip-path
android:pathData="M40.5 69.5C34.98 69.5 29.82 67.99 25.4 65.35V60.45C25.4 57.3 22.85 54.74 19.69 54.74 18.22 54.74 16.87 55.3 15.86 56.22 12.79 51.57 11 45.99 11 40 11 23.71 24.21 10.5 40.5 10.5 56.79 10.5 70 23.71 70 40 70 56.29 56.79 69.5 40.5 69.5Z"/>
<path
android:fillColor="#FFDEE0FC"
android:pathData="M-1 18.5a24.5 24 0 1 0 49 0a24.5 24 0 1 0 -49 0Z"/>
<path
android:fillColor="#FFC1C4FA"
android:pathData="M6 35a28.5 28.5 0 1 0 57 0a28.5 28.5 0 1 0 -57 0Z"/>
<path
android:fillColor="#FFDEE0FC"
android:pathData="M-1 18.5a24.5 24 0 1 0 49 0a24.5 24 0 1 0 -49 0Z"/>
</group>
<path
android:strokeColor="#FF8C90CB"
android:strokeWidth="1"
android:strokeLineCap="square"
android:pathData="M40.5 11C56.51 11 69.5 24.2 69.5 40.5 69.5 56.8 56.51 70 40.5 70 35.18 70 30.19 68.54 25.9 65.99V61.3C25.9 57.82 23.13 54.99 19.69 54.99 18.3 54.99 17.01 55.46 15.97 56.25 13.14 51.69 11.5 46.29 11.5 40.5 11.5 24.2 24.49 11 40.5 11Z"/>
<path
android:fillColor="#FF686FE5"
android:strokeColor="#FF8C90CB"
android:strokeWidth="1"
android:strokeLineCap="square"
android:fillType="evenOdd"
android:pathData="M66.85 10.83C72.8 15.92 77.28 22.82 79.32 30.94 81.37 39.07 80.68 47.24 77.83 54.5 77.34 55.75 75.94 56.36 74.7 55.89L74.65 55.87C73.42 55.39 72.8 53.99 73.29 52.75 75.78 46.39 76.39 39.24 74.6 32.11 72.8 24.98 68.88 18.94 63.67 14.48 62.65 13.61 62.55 12.07 63.43 11.06 64.3 10.06 65.82 9.94 66.82 10.8L66.85 10.83Z"/>
<path
android:fillColor="#FF686FE5"
android:strokeColor="#FF8C90CB"
android:strokeWidth="1"
android:strokeLineCap="square"
android:pathData="M18.55 58.73C19.63 58.73 20.5 59.62 20.5 60.73V69.91C20.5 71.02 19.63 71.91 18.55 71.91H8.72C7.64 71.91 6.77 71.02 6.77 69.91 6.77 68.8 7.64 67.91 8.72 67.91L11.67 67.88C6.96 62.91 3.43 56.63 1.68 49.41-0.37 40.97 0.32 32.49 3.17 24.95 3.66 23.67 5.07 23.03 6.33 23.53 7.58 24.03 8.21 25.48 7.72 26.77 5.22 33.37 4.62 40.8 6.41 48.2 8.2 55.6 11.38 61.76 16.6 66.39V60.73C16.6 59.62 17.47 58.73 18.55 58.73Z"/>
<path
android:fillColor="#FFC1C4FA"
android:strokeColor="#FF8C90CB"
android:strokeWidth="1"
android:strokeLineCap="square"
android:fillType="evenOdd"
android:pathData="M55.96 6.37C55.49 7.61 54.1 8.23 52.86 7.74 46.53 5.24 39.4 4.63 32.3 6.43 25.19 8.23 19.18 12.16 14.73 17.4 13.87 18.42 12.33 18.52 11.33 17.64 10.34 16.77 10.22 15.24 11.07 14.23L11.1 14.2C16.17 8.23 23.04 3.73 31.13 1.68 39.23-0.37 47.37 0.32 54.6 3.18 55.84 3.67 56.46 5.07 55.98 6.32L55.96 6.37Z"/>
<path
android:fillColor="#FFC1C4FA"
android:strokeColor="#FF8C90CB"
android:strokeWidth="1"
android:strokeLineCap="square"
android:fillType="evenOdd"
android:pathData="M69.98 63.36C70.97 64.24 71.1 65.76 70.24 66.77L70.21 66.8C65.14 72.77 58.27 77.27 50.18 79.32 42.08 81.37 33.94 80.68 26.71 77.82 25.47 77.33 24.85 75.93 25.33 74.68L25.35 74.63C25.82 73.39 27.21 72.77 28.45 73.26 34.78 75.76 41.91 76.37 49.01 74.57 56.12 72.77 62.13 68.84 66.58 63.6 67.44 62.58 68.98 62.48 69.98 63.36Z"/>
<path
android:fillColor="#FF686FE5"
android:strokeColor="#FF8C90CB"
android:strokeWidth="1"
android:strokeLineCap="square"
android:pathData="M36.5 41.52V25.73C36.5 24.5 37.45 23.5 38.63 23.5 39.8 23.5 40.76 24.5 40.76 25.73V41.52C40.76 42.35 41.02 43.15 41.51 43.81L49.05 53.9C49.77 54.87 49.61 56.27 48.68 57.03 47.82 57.74 46.59 57.63 45.84 56.82L45.7 56.64 38.16 46.55C37.08 45.12 36.5 43.34 36.5 41.52Z"/>
</vector>
@@ -1,73 +1,63 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="80dp"
android:height="80dp"
android:viewportWidth="80"
android:viewportHeight="80">
android:width="86.5623dp"
android:height="81.6602dp"
android:viewportWidth="86.5623"
android:viewportHeight="81.6602">
<path
android:pathData="M20 22.67c0-5.14 0-7.7 1-9.66 0.88-1.73 2.28-3.13 4-4.01 1.97-1 4.53-1 9.67-1h10.66c5.14 0 7.7 0 9.66 1 1.73 0.88 3.13 2.28 4.01 4 1 1.97 1 4.53 1 9.67v34.66c0 5.14 0 7.7-1 9.66-0.88 1.73-2.28 3.13-4 4.01-1.97 1-4.53 1-9.67 1H34.67c-5.14 0-7.7 0-9.66-1-1.73-0.88-3.13-2.28-4.01-4-1-1.97-1-4.53-1-9.67V22.67Z">
<aapt:attr name="android:fillColor">
<gradient
android:type="linear"
android:startX="40"
android:startY="8"
android:endX="40"
android:endY="72">
<item
android:color="#FFD2D8FE"
android:offset="0"/>
<item
android:color="#FFC1C7FE"
android:offset="1"/>
</gradient>
</aapt:attr>
</path>
android:fillColor="#FFC1C4FA"
android:pathData="M17.39 18.71C17.39 12.16 17.39 8.89 18.66 6.39 19.78 4.19 21.57 2.4 23.77 1.27 26.27 0 29.55 0 36.1 0H49.71C56.26 0 59.53 0 62.04 1.27 64.24 2.4 66.03 4.19 67.15 6.39 68.42 8.89 68.42 12.16 68.42 18.71V62.95C68.42 69.5 68.42 72.77 67.15 75.27 66.03 77.47 64.24 79.26 62.04 80.39 59.53 81.66 56.26 81.66 49.71 81.66H36.1C29.55 81.66 26.27 81.66 23.77 80.39 21.57 79.26 19.78 77.47 18.66 75.27 17.39 72.77 17.39 69.5 17.39 62.95V18.71Z"/>
<group>
<clip-path
android:pathData="M17.39 18.71C17.39 12.16 17.39 8.89 18.66 6.39 19.78 4.19 21.57 2.4 23.77 1.27 26.27 0 29.55 0 36.1 0H49.71C56.26 0 59.53 0 62.04 1.27 64.24 2.4 66.03 4.19 67.15 6.39 68.42 8.89 68.42 12.16 68.42 18.71V62.95C68.42 69.5 68.42 72.77 67.15 75.27 66.03 77.47 64.24 79.26 62.04 80.39 59.53 81.66 56.26 81.66 49.71 81.66H36.1C29.55 81.66 26.27 81.66 23.77 80.39 21.57 79.26 19.78 77.47 18.66 75.27 17.39 72.77 17.39 69.5 17.39 62.95V18.71Z"/>
<path
android:fillColor="#FFA9ADF8"
android:pathData="M88.17 71.07C88.17 75.49 84.59 79.07 80.17 79.07H77.32C72.9 79.07 69.32 82.65 69.32 87.07V153.62C69.32 158.03 65.74 161.62 61.32 161.62H29.43C25.01 161.62 21.43 158.03 21.43 153.62V82.63C21.43 78.21 25.01 74.63 29.43 74.63H52.99C57.41 74.63 60.99 71.04 60.99 66.63V-10.5C60.99-14.92 64.57-18.5 68.99-18.5H80.17C84.59-18.5 88.17-14.92 88.17-10.5V71.07Z"/>
<path
android:fillColor="#FFCED1FB"
android:pathData="M0.7175 10.2079a22.3289 22.3289 0 1 0 44.6578 0a22.3289 22.3289 0 1 0 -44.6578 0Z"/>
</group>
<path
android:fillColor="#FF666EE5"
android:fillType="evenOdd"
android:pathData="M34.6 6.5h10.8c2.51 0 4.49 0 6.08 0.13 1.62 0.13 2.97 0.4 4.2 1.03 2 1.03 3.63 2.66 4.66 4.66 0.62 1.23 0.9 2.58 1.03 4.2 0.13 1.6 0.13 3.57 0.13 6.08v34.8c0 2.51 0 4.49-0.13 6.08-0.13 1.62-0.4 2.97-1.03 4.2-1.03 2-2.66 3.63-4.66 4.66-1.23 0.62-2.58 0.9-4.2 1.03-1.6 0.13-3.57 0.13-6.08 0.13H34.6c-2.51 0-4.49 0-6.08-0.13-1.62-0.13-2.97-0.4-4.2-1.03-2-1.03-3.63-2.66-4.66-4.66-0.62-1.23-0.9-2.58-1.03-4.2-0.13-1.6-0.13-3.57-0.13-6.08V22.6c0-2.51 0-4.49 0.13-6.08 0.13-1.62 0.4-2.97 1.03-4.2 1.03-2 2.66-3.63 4.66-4.66 1.23-0.62 2.58-0.9 4.2-1.03C30.12 6.5 32.1 6.5 34.6 6.5Zm-5.83 3.12c-1.44 0.12-2.35 0.34-3.08 0.72-1.45 0.73-2.62 1.9-3.35 3.35-0.38 0.73-0.6 1.64-0.72 3.08-0.12 1.45-0.12 3.3-0.12 5.9v34.66c0 2.6 0 4.45 0.12 5.9 0.12 1.44 0.34 2.35 0.72 3.08 0.73 1.45 1.9 2.62 3.35 3.35 0.73 0.38 1.64 0.6 3.08 0.72 1.45 0.12 3.3 0.12 5.9 0.12h10.66c2.6 0 4.45 0 5.9-0.12 1.44-0.12 2.35-0.34 3.08-0.72 1.45-0.73 2.62-1.9 3.35-3.35 0.38-0.73 0.6-1.64 0.72-3.08 0.12-1.45 0.12-3.3 0.12-5.9V22.67c0-2.6 0-4.45-0.12-5.9-0.12-1.44-0.34-2.35-0.72-3.08-0.73-1.45-1.9-2.62-3.35-3.35-0.73-0.38-1.64-0.6-3.08-0.72-1.45-0.12-3.3-0.12-5.9-0.12H34.67c-2.6 0-4.45 0-5.9 0.12Z"/>
android:strokeColor="#FF8C90CB"
android:strokeWidth="2"
android:pathData="M36.1 1H49.71C53 1 55.41 1 57.31 1.16 59.2 1.31 60.5 1.61 61.58 2.17 63.6 3.19 65.23 4.83 66.26 6.84 66.81 7.93 67.11 9.22 67.27 11.11 67.42 13.01 67.42 15.42 67.42 18.71V62.95C67.42 66.24 67.42 68.65 67.27 70.55 67.11 72.44 66.81 73.73 66.26 74.82 65.23 76.83 63.6 78.47 61.58 79.49 60.5 80.05 59.2 80.35 57.31 80.5 55.41 80.66 53 80.66 49.71 80.66H36.1C32.81 80.66 30.4 80.66 28.5 80.5 26.61 80.35 25.31 80.05 24.23 79.49 22.21 78.47 20.58 76.83 19.55 74.82 19 73.73 18.7 72.44 18.54 70.55 18.39 68.65 18.39 66.24 18.39 62.95V18.71C18.39 15.42 18.39 13.01 18.54 11.11 18.7 9.22 19 7.93 19.55 6.84 20.58 4.83 22.21 3.19 24.23 2.17 25.31 1.61 26.61 1.31 28.5 1.16 30.4 1 32.81 1 36.1 1Z"/>
<path
android:fillColor="#FFE3E8FE"
android:pathData="M19.37 40.66l-4.11 0.91-4.57 1.37-1.83 3.2-2.29 3.66-0.46 5.49 1.83 4.11-1.37 5.94 6.4-0.91L18 65.34l5.94-0.45c1.37-1.22 4.12-3.75 4.12-4.12 0-0.36 2.13-2.9 3.2-4.11l-0.46-5.49-0.91-4.57-5.95-4.57-4.57-1.37Z"/>
android:fillColor="#FFC0CBE2"
android:strokeColor="#FF929AAC"
android:strokeWidth="1.5"
android:pathData="M17.3 35.84C26.05 35.84 33.14 42.93 33.14 51.67 33.14 60.42 26.05 67.51 17.3 67.51 14.77 67.51 12.37 66.92 10.25 65.86L9.83 65.64 9.75 65.6C9.7 65.58 9.65 65.57 9.6 65.56L9.52 65.55 9.43 65.54C9.42 65.55 9.41 65.55 9.4 65.55 9.4 65.55 9.4 65.55 9.39 65.55H9.38L9.38 65.55H9.38L9.29 65.56 9.2 65.59 2.03 68.17C1.27 68.44 0.54 67.71 0.81 66.95L3.39 59.78 3.42 59.69 3.43 59.6V59.59C3.43 59.58 3.43 59.58 3.43 59.58 3.43 59.57 3.44 59.56 3.44 59.55L3.43 59.46 3.42 59.38C3.41 59.3 3.38 59.23 3.34 59.15 2.15 56.93 1.47 54.38 1.47 51.67 1.47 42.93 8.56 35.84 17.3 35.84Z"/>
<group>
<clip-path
android:pathData="M17.3 35.09C8.14 35.09 0.72 42.51 0.72 51.68 0.72 54.51 1.43 57.17 2.68 59.51 2.68 59.51 2.69 59.52 2.69 59.53 2.69 59.53 2.69 59.53 2.69 59.53L0.1 66.7C-0.38 68.05 0.93 69.36 2.28 68.88L9.45 66.29C9.45 66.29 9.45 66.29 9.45 66.29 9.46 66.29 9.46 66.3 9.47 66.3 11.81 67.55 14.47 68.26 17.3 68.26 26.47 68.26 33.89 60.84 33.89 51.68 33.89 42.51 26.47 35.09 17.3 35.09Z"/>
<path
android:fillColor="#FFD9E0EE"
android:pathData="M15.08 32.54C6.8 32.54 0.09 39.25 0.09 47.52 0.09 50.08 0.73 52.49 1.86 54.6 1.87 54.61 1.87 54.61 1.87 54.62 1.87 54.62 1.87 54.62 1.87 54.62L-0.46 61.1C-0.91 62.32 0.28 63.51 1.5 63.06L7.98 60.73C7.98 60.73 7.98 60.73 7.98 60.73 7.99 60.73 7.99 60.73 8 60.74 10.11 61.87 12.52 62.51 15.08 62.51 23.35 62.51 30.06 55.8 30.06 47.52 30.06 39.25 23.35 32.54 15.08 32.54Z"/>
<path
android:fillColor="#FFEAEEF6"
android:pathData="M-10.766 37.64a16.5872 16.5872 0 1 0 33.1744 0a16.5872 16.5872 0 1 0 -33.1744 0Z"/>
</group>
<path
android:fillColor="#FF666EE5"
android:fillType="evenOdd"
android:pathData="M4.17 53c0-7.64 6.19-13.83 13.83-13.83S31.83 45.36 31.83 53 25.64 66.83 18 66.83c-2.4 0-4.65-0.6-6.61-1.68l-5 1.8c-1.45 0.53-2.87-0.89-2.34-2.34l1.8-5C4.78 57.65 4.17 55.4 4.17 53ZM18 41.5c-6.35 0-11.5 5.15-11.5 11.5 0 2.06 0.54 3.98 1.48 5.65 0.26 0.46 0.33 1.02 0.14 1.54L6.6 64.4l4.2-1.5c0.53-0.2 1.1-0.13 1.55 0.13 1.67 0.94 3.6 1.48 5.65 1.48 6.35 0 11.5-5.15 11.5-11.5S24.35 41.5 18 41.5Z"/>
android:strokeColor="#FF929AAC"
android:strokeWidth="2"
android:pathData="M17.3 36.09C25.91 36.09 32.89 43.07 32.89 51.67 32.89 60.28 25.91 67.26 17.3 67.26 14.64 67.26 12.14 66.59 9.95 65.42L9.85 65.37C9.78 65.35 9.71 65.33 9.64 65.31L9.54 65.3 9.43 65.29C9.41 65.3 9.4 65.3 9.39 65.3 9.38 65.3 9.38 65.3 9.37 65.3H9.36L9.36 65.3H9.36L9.45 66.29 9.36 65.3 9.23 65.31 9.11 65.35 1.94 67.93C1.38 68.14 0.84 67.6 1.04 67.04L3.63 59.87 3.67 59.75 3.68 59.62V59.62H3.68V59.61C3.68 59.61 3.68 59.61 3.68 59.61 3.68 59.6 3.68 59.6 3.68 59.59 3.68 59.58 3.68 59.57 3.68 59.55 3.69 59.53 3.69 59.49 3.68 59.44 3.67 59.3 3.63 59.16 3.56 59.03 2.38 56.84 1.72 54.34 1.72 51.67 1.72 43.07 8.7 36.09 17.3 36.09Z"/>
<path
android:strokeColor="#FF666EE5"
android:strokeWidth="1"
android:pathData="M19.37 40.66l-4.11 0.91-4.57 1.37-1.83 3.2-2.29 3.66-0.46 5.49 1.83 4.11-1.37 5.94 6.4-0.91L18 65.34l5.94-0.45c1.37-1.22 4.12-3.75 4.12-4.12 0-0.36 2.13-2.9 3.2-4.11l-0.46-5.49-0.91-4.57-5.95-4.57-4.57-1.37Z"/>
android:fillColor="#FFD9E0EE"
android:strokeColor="#FF929AAC"
android:strokeWidth="1.5"
android:pathData="M60.56 21.41H79.56C83.01 21.41 85.81 24.21 85.81 27.66V40.66C85.81 44.11 83.01 46.91 79.56 46.91H60.56C57.11 46.91 54.31 44.11 54.31 40.66V27.66C54.31 24.21 57.11 21.41 60.56 21.41Z"/>
<group>
<clip-path
android:pathData="M60.56 21.41H79.56C83.01 21.41 85.81 24.21 85.81 27.66V40.66C85.81 44.11 83.01 46.91 79.56 46.91H60.56C57.11 46.91 54.31 44.11 54.31 40.66V27.66C54.31 24.21 57.11 21.41 60.56 21.41Z"/>
<path
android:fillColor="#FFAFBDDB"
android:strokeColor="#FF929AAC"
android:strokeWidth="1.5"
android:pathData="M60.58 36.4L54.26 42.76C53.82 43.2 53.61 43.82 53.69 44.44L53.83 45.43C53.96 46.42 54.81 47.16 55.81 47.16H86.56C87.67 47.16 88.56 46.26 88.56 45.16V43.65C88.56 43.12 88.35 42.61 87.98 42.24L77.89 32.09C77.11 31.3 75.84 31.3 75.05 32.09L68.81 38.36C68.1 39.08 66.96 39.15 66.16 38.53L63.23 36.23C62.44 35.61 61.3 35.68 60.58 36.4Z"/>
</group>
<path
android:strokeColor="#FF666EE5"
android:strokeWidth="1"
android:pathData="M4.17 53c0-7.64 6.19-13.83 13.83-13.83S31.83 45.36 31.83 53 25.64 66.83 18 66.83c-2.4 0-4.65-0.6-6.61-1.68l-5 1.8c-1.45 0.53-2.87-0.89-2.34-2.34l1.8-5C4.78 57.65 4.17 55.4 4.17 53ZM18 41.5c-6.35 0-11.5 5.15-11.5 11.5 0 2.06 0.54 3.98 1.48 5.65 0.26 0.46 0.33 1.02 0.14 1.54L6.6 64.4l4.2-1.5c0.53-0.2 1.1-0.13 1.55 0.13 1.67 0.94 3.6 1.48 5.65 1.48 6.35 0 11.5-5.15 11.5-11.5S24.35 41.5 18 41.5Z"/>
android:strokeColor="#FF929AAC"
android:strokeWidth="2"
android:pathData="M60.56 21.66H79.56C82.88 21.66 85.56 24.35 85.56 27.66V40.66C85.56 43.97 82.88 46.66 79.56 46.66H60.56C57.25 46.66 54.56 43.97 54.56 40.66V27.66C54.56 24.35 57.25 21.66 60.56 21.66Z"/>
<path
android:fillColor="#FFE3E8FE"
android:pathData="M48.82 17.77c-0.14 4.61-0.43 14.08-0.43 15.12l1.3 2.16 6.04-5.18 4.32 2.59 8.2-6.48 7.35 5.61 0.43-12.09-3.45-3.45L52.7 15.6l-3.89 2.16Z"/>
<path
android:fillColor="#FFE3E8FE"
android:pathData="M55.41 30.2l-6.58 6.14v0.44l2.2 3.07 7.46 0.44 13.6-0.44 3.52-3.07 0.88-4.39-8.34-6.15-7.47 6.15-5.27-2.2Z"/>
<path
android:fillColor="#FF666EE5"
android:pathData="M53.38 23.13c0-1.45 1.17-2.63 2.62-2.63 1.45 0 2.63 1.18 2.63 2.63 0 1.44-1.18 2.62-2.63 2.62s-2.63-1.18-2.63-2.63Z"/>
<path
android:fillColor="#FF666EE5"
android:fillType="evenOdd"
android:pathData="M77.56 24.34v7.32c0 1.42 0 2.57-0.07 3.5-0.08 0.95-0.25 1.8-0.64 2.57-0.63 1.23-1.64 2.24-2.87 2.87-0.78 0.4-1.62 0.56-2.57 0.64-0.93 0.07-2.08 0.07-3.5 0.07H56.09c-1.42 0-2.57 0-3.5-0.07-0.95-0.08-1.8-0.25-2.57-0.64-1.23-0.63-2.24-1.64-2.87-2.87-0.4-0.78-0.56-1.62-0.64-2.57-0.07-0.93-0.07-2.08-0.07-3.5v-7.32c0-1.42 0-2.57 0.07-3.5 0.08-0.95 0.25-1.8 0.64-2.57 0.63-1.23 1.64-2.24 2.87-2.87 0.78-0.4 1.62-0.56 2.57-0.64 0.93-0.07 2.08-0.07 3.5-0.07h11.82c1.42 0 2.57 0 3.5 0.07 0.95 0.08 1.8 0.25 2.57 0.64 1.23 0.63 2.24 1.64 2.87 2.87 0.4 0.78 0.56 1.62 0.64 2.57 0.07 0.93 0.07 2.08 0.07 3.5Zm-2.69-3.28c-0.06-0.8-0.19-1.25-0.36-1.6-0.38-0.74-0.98-1.34-1.72-1.72-0.35-0.17-0.8-0.3-1.6-0.36-0.8-0.07-1.85-0.07-3.34-0.07h-11.7c-1.5 0-2.53 0-3.34 0.07-0.8 0.06-1.25 0.19-1.6 0.36-0.74 0.38-1.34 0.98-1.72 1.72-0.17 0.35-0.3 0.8-0.36 1.6-0.07 0.8-0.07 1.85-0.07 3.34v7.2c0 0.88 0 1.6 0.02 2.22l3.87-3.88c1.68-1.68 4.42-1.68 6.1 0l1.08 1.08 4.82-4.83c1.68-1.68 4.42-1.68 6.1 0l3.89 3.9V24.4c0-1.5 0-2.53-0.07-3.34Zm-23.66 17.2c-0.61-0.31-1.13-0.78-1.5-1.36l5.1-5.1c0.66-0.66 1.72-0.66 2.38 0l2 2c0.52 0.52 1.35 0.52 1.86 0l5.76-5.75c0.66-0.66 1.72-0.66 2.38 0l5.73 5.73c0 0.44-0.02 0.82-0.05 1.16-0.06 0.8-0.19 1.25-0.36 1.6-0.38 0.74-0.98 1.34-1.72 1.72-0.35 0.17-0.8 0.3-1.6 0.36-0.8 0.07-1.85 0.07-3.34 0.07h-11.7c-1.5 0-2.53 0-3.34-0.07-0.8-0.06-1.25-0.19-1.6-0.36Z"/>
<path
android:strokeColor="#FF666EE5"
android:strokeWidth="0.5"
android:pathData="M48.82 17.77c-0.14 4.61-0.43 14.08-0.43 15.12l1.3 2.16 6.04-5.18 4.32 2.59 8.2-6.48 7.35 5.61 0.43-12.09-3.45-3.45L52.7 15.6l-3.89 2.16Z"/>
<path
android:strokeColor="#FF666EE5"
android:strokeWidth="0.5"
android:pathData="M55.41 30.2l-6.58 6.14v0.44l2.2 3.07 7.46 0.44 13.6-0.44 3.52-3.07 0.88-4.39-8.34-6.15-7.47 6.15-5.27-2.2Z"/>
<path
android:strokeColor="#FF666EE5"
android:strokeWidth="0.5"
android:pathData="M53.38 23.13c0-1.45 1.17-2.63 2.62-2.63 1.45 0 2.63 1.18 2.63 2.63 0 1.44-1.18 2.62-2.63 2.62s-2.63-1.18-2.63-2.63Z"/>
<path
android:strokeColor="#FF666EE5"
android:strokeWidth="0.5"
android:pathData="M77.56 24.34v7.32c0 1.42 0 2.57-0.07 3.5-0.08 0.95-0.25 1.8-0.64 2.57-0.63 1.23-1.64 2.24-2.87 2.87-0.78 0.4-1.62 0.56-2.57 0.64-0.93 0.07-2.08 0.07-3.5 0.07H56.09c-1.42 0-2.57 0-3.5-0.07-0.95-0.08-1.8-0.25-2.57-0.64-1.23-0.63-2.24-1.64-2.87-2.87-0.4-0.78-0.56-1.62-0.64-2.57-0.07-0.93-0.07-2.08-0.07-3.5v-7.32c0-1.42 0-2.57 0.07-3.5 0.08-0.95 0.25-1.8 0.64-2.57 0.63-1.23 1.64-2.24 2.87-2.87 0.78-0.4 1.62-0.56 2.57-0.64 0.93-0.07 2.08-0.07 3.5-0.07h11.82c1.42 0 2.57 0 3.5 0.07 0.95 0.08 1.8 0.25 2.57 0.64 1.23 0.63 2.24 1.64 2.87 2.87 0.4 0.78 0.56 1.62 0.64 2.57 0.07 0.93 0.07 2.08 0.07 3.5Zm-2.69-3.28c-0.06-0.8-0.19-1.25-0.36-1.6-0.38-0.74-0.98-1.34-1.72-1.72-0.35-0.17-0.8-0.3-1.6-0.36-0.8-0.07-1.85-0.07-3.34-0.07h-11.7c-1.5 0-2.53 0-3.34 0.07-0.8 0.06-1.25 0.19-1.6 0.36-0.74 0.38-1.34 0.98-1.72 1.72-0.17 0.35-0.3 0.8-0.36 1.6-0.07 0.8-0.07 1.85-0.07 3.34v7.2c0 0.88 0 1.6 0.02 2.22l3.87-3.88c1.68-1.68 4.42-1.68 6.1 0l1.08 1.08 4.82-4.83c1.68-1.68 4.42-1.68 6.1 0l3.89 3.9V24.4c0-1.5 0-2.53-0.07-3.34Zm-23.66 17.2c-0.61-0.31-1.13-0.78-1.5-1.36l5.1-5.1c0.66-0.66 1.72-0.66 2.38 0l2 2c0.52 0.52 1.35 0.52 1.86 0l5.76-5.75c0.66-0.66 1.72-0.66 2.38 0l5.73 5.73c0 0.44-0.02 0.82-0.05 1.16-0.06 0.8-0.19 1.25-0.36 1.6-0.38 0.74-0.98 1.34-1.72 1.72-0.35 0.17-0.8 0.3-1.6 0.36-0.8 0.07-1.85 0.07-3.34 0.07h-11.7c-1.5 0-2.53 0-3.34-0.07-0.8-0.06-1.25-0.19-1.6-0.36Z"/>
android:fillColor="#FF929AAC"
android:pathData="M59.86 28.79C59.86 27.06 61.27 25.66 63 25.66 64.74 25.66 66.14 27.06 66.14 28.79 66.14 30.52 64.74 31.93 63 31.93 61.27 31.93 59.86 30.52 59.86 28.79Z"/>
</vector>
@@ -0,0 +1,61 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="81dp"
android:height="81dp"
android:viewportWidth="81"
android:viewportHeight="81">
<path
android:fillColor="#FFABAFF8"
android:fillType="evenOdd"
android:pathData="M40.5 70.5C34.98 70.5 29.82 68.96 25.4 66.28V61.3C25.4 58.09 22.85 55.49 19.69 55.49 18.22 55.49 16.87 56.06 15.86 57 12.79 52.26 11 46.59 11 40.5 11 23.93 24.21 10.5 40.5 10.5 56.79 10.5 70 23.93 70 40.5 70 57.07 56.79 70.5 40.5 70.5Z"/>
<group>
<clip-path
android:pathData="M40.5 69.5C34.98 69.5 29.82 67.99 25.4 65.35V60.45C25.4 57.3 22.85 54.74 19.69 54.74 18.22 54.74 16.87 55.3 15.86 56.22 12.79 51.57 11 45.99 11 40 11 23.71 24.21 10.5 40.5 10.5 56.79 10.5 70 23.71 70 40 70 56.29 56.79 69.5 40.5 69.5Z"/>
<path
android:fillColor="#FFDEE0FC"
android:pathData="M-1 18.5a24.5 24 0 1 0 49 0a24.5 24 0 1 0 -49 0Z"/>
<path
android:fillColor="#FFC1C4FA"
android:pathData="M6 35a28.5 28.5 0 1 0 57 0a28.5 28.5 0 1 0 -57 0Z"/>
<path
android:fillColor="#FFDEE0FC"
android:pathData="M-1 18.5a24.5 24 0 1 0 49 0a24.5 24 0 1 0 -49 0Z"/>
</group>
<path
android:strokeColor="#FF4046A9"
android:strokeWidth="1"
android:strokeLineCap="square"
android:pathData="M40.5 11C56.51 11 69.5 24.2 69.5 40.5 69.5 56.8 56.51 70 40.5 70 35.18 70 30.19 68.54 25.9 65.99V61.3C25.9 57.82 23.13 54.99 19.69 54.99 18.3 54.99 17.01 55.46 15.97 56.25 13.14 51.69 11.5 46.29 11.5 40.5 11.5 24.2 24.49 11 40.5 11Z"/>
<path
android:fillColor="#FF686FE5"
android:strokeColor="#FF4046A9"
android:strokeWidth="1"
android:strokeLineCap="square"
android:fillType="evenOdd"
android:pathData="M66.85 10.83C72.8 15.92 77.28 22.82 79.32 30.94 81.37 39.07 80.68 47.24 77.83 54.5 77.34 55.75 75.94 56.36 74.7 55.89L74.65 55.87C73.42 55.39 72.8 53.99 73.29 52.75 75.78 46.39 76.39 39.24 74.6 32.11 72.8 24.98 68.88 18.94 63.67 14.48 62.65 13.61 62.55 12.07 63.43 11.06 64.3 10.06 65.82 9.94 66.82 10.8L66.85 10.83Z"/>
<path
android:fillColor="#FF686FE5"
android:strokeColor="#FF4046A9"
android:strokeWidth="1"
android:strokeLineCap="square"
android:pathData="M18.55 58.73C19.63 58.73 20.5 59.62 20.5 60.73V69.91C20.5 71.02 19.63 71.91 18.55 71.91H8.72C7.64 71.91 6.77 71.02 6.77 69.91 6.77 68.8 7.64 67.91 8.72 67.91L11.67 67.88C6.96 62.91 3.43 56.63 1.68 49.41-0.37 40.97 0.32 32.49 3.17 24.95 3.66 23.67 5.07 23.03 6.33 23.53 7.58 24.03 8.21 25.48 7.72 26.77 5.22 33.37 4.62 40.8 6.41 48.2 8.2 55.6 11.38 61.76 16.6 66.39V60.73C16.6 59.62 17.47 58.73 18.55 58.73Z"/>
<path
android:fillColor="#FFC1C4FA"
android:strokeColor="#FF4046A9"
android:strokeWidth="1"
android:strokeLineCap="square"
android:fillType="evenOdd"
android:pathData="M55.96 6.37C55.49 7.61 54.1 8.23 52.86 7.74 46.53 5.24 39.4 4.63 32.3 6.43 25.19 8.23 19.18 12.16 14.73 17.4 13.87 18.42 12.33 18.52 11.33 17.64 10.34 16.77 10.22 15.24 11.07 14.23L11.1 14.2C16.17 8.23 23.04 3.73 31.13 1.68 39.23-0.37 47.37 0.32 54.6 3.18 55.84 3.67 56.46 5.07 55.98 6.32L55.96 6.37Z"/>
<path
android:fillColor="#FFC1C4FA"
android:strokeColor="#FF4046A9"
android:strokeWidth="1"
android:strokeLineCap="square"
android:fillType="evenOdd"
android:pathData="M69.98 63.36C70.97 64.24 71.1 65.76 70.24 66.77L70.21 66.8C65.14 72.77 58.27 77.27 50.18 79.32 42.08 81.37 33.94 80.68 26.71 77.82 25.47 77.33 24.85 75.93 25.33 74.68L25.35 74.63C25.82 73.39 27.21 72.77 28.45 73.26 34.78 75.76 41.91 76.37 49.01 74.57 56.12 72.77 62.13 68.84 66.58 63.6 67.44 62.58 68.98 62.48 69.98 63.36Z"/>
<path
android:fillColor="#FF686FE5"
android:strokeColor="#FF4046A9"
android:strokeWidth="1"
android:strokeLineCap="square"
android:pathData="M36.5 41.52V25.73C36.5 24.5 37.45 23.5 38.63 23.5 39.8 23.5 40.76 24.5 40.76 25.73V41.52C40.76 42.35 41.02 43.15 41.51 43.81L49.05 53.9C49.77 54.87 49.61 56.27 48.68 57.03 47.82 57.74 46.59 57.63 45.84 56.82L45.7 56.64 38.16 46.55C37.08 45.12 36.5 43.34 36.5 41.52Z"/>
</vector>
@@ -1,73 +1,63 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="80dp"
android:height="80dp"
android:viewportWidth="80"
android:viewportHeight="80">
android:width="86.5623dp"
android:height="81.6602dp"
android:viewportWidth="86.5623"
android:viewportHeight="81.6602">
<path
android:pathData="M20 22.67c0-5.14 0-7.7 1-9.66 0.88-1.73 2.28-3.13 4-4.01 1.97-1 4.53-1 9.67-1h10.66c5.14 0 7.7 0 9.66 1 1.73 0.88 3.13 2.28 4.01 4 1 1.97 1 4.53 1 9.67v34.66c0 5.14 0 7.7-1 9.66-0.88 1.73-2.28 3.13-4 4.01-1.97 1-4.53 1-9.67 1H34.67c-5.14 0-7.7 0-9.66-1-1.73-0.88-3.13-2.28-4.01-4-1-1.97-1-4.53-1-9.67V22.67Z">
<aapt:attr name="android:fillColor">
<gradient
android:type="linear"
android:startX="42"
android:startY="6"
android:endX="44.87"
android:endY="71.88">
<item
android:color="#FFD2D8FE"
android:offset="0"/>
<item
android:color="#FFB0BCFC"
android:offset="1"/>
</gradient>
</aapt:attr>
</path>
android:fillColor="#FFC1C4FA"
android:pathData="M17.39 18.71C17.39 12.16 17.39 8.89 18.66 6.39 19.78 4.19 21.57 2.4 23.77 1.27 26.27 0 29.55 0 36.1 0H49.71C56.26 0 59.53 0 62.04 1.27 64.24 2.4 66.03 4.19 67.15 6.39 68.42 8.89 68.42 12.16 68.42 18.71V62.95C68.42 69.5 68.42 72.77 67.15 75.27 66.03 77.47 64.24 79.26 62.04 80.39 59.53 81.66 56.26 81.66 49.71 81.66H36.1C29.55 81.66 26.27 81.66 23.77 80.39 21.57 79.26 19.78 77.47 18.66 75.27 17.39 72.77 17.39 69.5 17.39 62.95V18.71Z"/>
<group>
<clip-path
android:pathData="M17.39 18.71C17.39 12.16 17.39 8.89 18.66 6.39 19.78 4.19 21.57 2.4 23.77 1.27 26.27 0 29.55 0 36.1 0H49.71C56.26 0 59.53 0 62.04 1.27 64.24 2.4 66.03 4.19 67.15 6.39 68.42 8.89 68.42 12.16 68.42 18.71V62.95C68.42 69.5 68.42 72.77 67.15 75.27 66.03 77.47 64.24 79.26 62.04 80.39 59.53 81.66 56.26 81.66 49.71 81.66H36.1C29.55 81.66 26.27 81.66 23.77 80.39 21.57 79.26 19.78 77.47 18.66 75.27 17.39 72.77 17.39 69.5 17.39 62.95V18.71Z"/>
<path
android:fillColor="#FFA9ADF8"
android:pathData="M88.17 71.07C88.17 75.49 84.59 79.07 80.17 79.07H77.32C72.9 79.07 69.32 82.65 69.32 87.07V153.62C69.32 158.03 65.74 161.62 61.32 161.62H29.43C25.01 161.62 21.43 158.03 21.43 153.62V82.63C21.43 78.21 25.01 74.63 29.43 74.63H52.99C57.41 74.63 60.99 71.04 60.99 66.63V-10.5C60.99-14.92 64.57-18.5 68.99-18.5H80.17C84.59-18.5 88.17-14.92 88.17-10.5V71.07Z"/>
<path
android:fillColor="#FFCED1FB"
android:pathData="M0.7175 10.2079a22.3289 22.3289 0 1 0 44.6578 0a22.3289 22.3289 0 1 0 -44.6578 0Z"/>
</group>
<path
android:fillColor="#FF3B45FD"
android:fillType="evenOdd"
android:pathData="M34.6 6.5h10.8c2.51 0 4.49 0 6.08 0.13 1.62 0.13 2.97 0.4 4.2 1.03 2 1.03 3.63 2.66 4.66 4.66 0.62 1.23 0.9 2.58 1.03 4.2 0.13 1.6 0.13 3.57 0.13 6.08v34.8c0 2.51 0 4.49-0.13 6.08-0.13 1.62-0.4 2.97-1.03 4.2-1.03 2-2.66 3.63-4.66 4.66-1.23 0.62-2.58 0.9-4.2 1.03-1.6 0.13-3.57 0.13-6.08 0.13H34.6c-2.51 0-4.49 0-6.08-0.13-1.62-0.13-2.97-0.4-4.2-1.03-2-1.03-3.63-2.66-4.66-4.66-0.62-1.23-0.9-2.58-1.03-4.2-0.13-1.6-0.13-3.57-0.13-6.08V22.6c0-2.51 0-4.49 0.13-6.08 0.13-1.62 0.4-2.97 1.03-4.2 1.03-2 2.66-3.63 4.66-4.66 1.23-0.62 2.58-0.9 4.2-1.03C30.12 6.5 32.1 6.5 34.6 6.5Zm-5.83 3.12c-1.44 0.12-2.35 0.34-3.08 0.72-1.45 0.73-2.62 1.9-3.35 3.35-0.38 0.73-0.6 1.64-0.72 3.08-0.12 1.45-0.12 3.3-0.12 5.9v34.66c0 2.6 0 4.45 0.12 5.9 0.12 1.44 0.34 2.35 0.72 3.08 0.73 1.45 1.9 2.62 3.35 3.35 0.73 0.38 1.64 0.6 3.08 0.72 1.45 0.12 3.3 0.12 5.9 0.12h10.66c2.6 0 4.45 0 5.9-0.12 1.44-0.12 2.35-0.34 3.08-0.72 1.45-0.73 2.62-1.9 3.35-3.35 0.38-0.73 0.6-1.64 0.72-3.08 0.12-1.45 0.12-3.3 0.12-5.9V22.67c0-2.6 0-4.45-0.12-5.9-0.12-1.44-0.34-2.35-0.72-3.08-0.73-1.45-1.9-2.62-3.35-3.35-0.73-0.38-1.64-0.6-3.08-0.72-1.45-0.12-3.3-0.12-5.9-0.12H34.67c-2.6 0-4.45 0-5.9 0.12Z"/>
android:strokeColor="#FF4046A9"
android:strokeWidth="2"
android:pathData="M36.1 1H49.71C53 1 55.41 1 57.31 1.16 59.2 1.31 60.5 1.61 61.58 2.17 63.6 3.19 65.23 4.83 66.26 6.84 66.81 7.93 67.11 9.22 67.27 11.11 67.42 13.01 67.42 15.42 67.42 18.71V62.95C67.42 66.24 67.42 68.65 67.27 70.55 67.11 72.44 66.81 73.73 66.26 74.82 65.23 76.83 63.6 78.47 61.58 79.49 60.5 80.05 59.2 80.35 57.31 80.5 55.41 80.66 53 80.66 49.71 80.66H36.1C32.81 80.66 30.4 80.66 28.5 80.5 26.61 80.35 25.31 80.05 24.23 79.49 22.21 78.47 20.58 76.83 19.55 74.82 19 73.73 18.7 72.44 18.54 70.55 18.39 68.65 18.39 66.24 18.39 62.95V18.71C18.39 15.42 18.39 13.01 18.54 11.11 18.7 9.22 19 7.93 19.55 6.84 20.58 4.83 22.21 3.19 24.23 2.17 25.31 1.61 26.61 1.31 28.5 1.16 30.4 1 32.81 1 36.1 1Z"/>
<path
android:fillColor="#FFE0E5FF"
android:pathData="M19.37 40.66l-4.11 0.91-4.57 1.37-1.83 3.2-2.29 3.66-0.46 5.49 1.83 4.11-1.37 5.94 6.4-0.91L18 65.34l5.94-0.45c1.37-1.22 4.12-3.75 4.12-4.12 0-0.36 2.13-2.9 3.2-4.11l-0.46-5.49-0.91-4.57-5.95-4.57-4.57-1.37Z"/>
android:fillColor="#FFC0CBE2"
android:strokeColor="#FF4A5775"
android:strokeWidth="1.5"
android:pathData="M17.3 35.84C26.05 35.84 33.14 42.93 33.14 51.67 33.14 60.42 26.05 67.51 17.3 67.51 14.77 67.51 12.37 66.92 10.25 65.86L9.83 65.64 9.75 65.6C9.7 65.58 9.65 65.57 9.6 65.56L9.52 65.55 9.43 65.54C9.42 65.55 9.41 65.55 9.4 65.55 9.4 65.55 9.4 65.55 9.39 65.55H9.38L9.38 65.55H9.38L9.29 65.56 9.2 65.59 2.03 68.17C1.27 68.44 0.54 67.71 0.81 66.95L3.39 59.78 3.42 59.69 3.43 59.6V59.59C3.43 59.58 3.43 59.58 3.43 59.58 3.43 59.57 3.44 59.56 3.44 59.55L3.43 59.46 3.42 59.38C3.41 59.3 3.38 59.23 3.34 59.15 2.15 56.93 1.47 54.38 1.47 51.67 1.47 42.93 8.56 35.84 17.3 35.84Z"/>
<group>
<clip-path
android:pathData="M17.3 35.09C8.14 35.09 0.72 42.51 0.72 51.68 0.72 54.51 1.43 57.17 2.68 59.51 2.68 59.51 2.69 59.52 2.69 59.53 2.69 59.53 2.69 59.53 2.69 59.53L0.1 66.7C-0.38 68.05 0.93 69.36 2.28 68.88L9.45 66.29C9.45 66.29 9.45 66.29 9.45 66.29 9.46 66.29 9.46 66.3 9.47 66.3 11.81 67.55 14.47 68.26 17.3 68.26 26.47 68.26 33.89 60.84 33.89 51.68 33.89 42.51 26.47 35.09 17.3 35.09Z"/>
<path
android:fillColor="#FFD9E0EE"
android:pathData="M15.08 32.54C6.8 32.54 0.09 39.25 0.09 47.52 0.09 50.08 0.73 52.49 1.86 54.6 1.87 54.61 1.87 54.61 1.87 54.62 1.87 54.62 1.87 54.62 1.87 54.62L-0.46 61.1C-0.91 62.32 0.28 63.51 1.5 63.06L7.98 60.73C7.98 60.73 7.98 60.73 7.98 60.73 7.99 60.73 7.99 60.73 8 60.74 10.11 61.87 12.52 62.51 15.08 62.51 23.35 62.51 30.06 55.8 30.06 47.52 30.06 39.25 23.35 32.54 15.08 32.54Z"/>
<path
android:fillColor="#FFEAEEF6"
android:pathData="M-10.766 37.64a16.5872 16.5872 0 1 0 33.1744 0a16.5872 16.5872 0 1 0 -33.1744 0Z"/>
</group>
<path
android:fillColor="#FF3B45FD"
android:fillType="evenOdd"
android:pathData="M4.17 53c0-7.64 6.19-13.83 13.83-13.83S31.83 45.36 31.83 53 25.64 66.83 18 66.83c-2.4 0-4.65-0.6-6.61-1.68l-5 1.8c-1.45 0.53-2.87-0.89-2.34-2.34l1.8-5C4.78 57.65 4.17 55.4 4.17 53ZM18 41.5c-6.35 0-11.5 5.15-11.5 11.5 0 2.06 0.54 3.98 1.48 5.65 0.26 0.46 0.33 1.02 0.14 1.54L6.6 64.4l4.2-1.5c0.53-0.2 1.1-0.13 1.55 0.13 1.67 0.94 3.6 1.48 5.65 1.48 6.35 0 11.5-5.15 11.5-11.5S24.35 41.5 18 41.5Z"/>
android:strokeColor="#FF4A5775"
android:strokeWidth="2"
android:pathData="M17.3 36.09C25.91 36.09 32.89 43.07 32.89 51.67 32.89 60.28 25.91 67.26 17.3 67.26 14.64 67.26 12.14 66.59 9.95 65.42L9.85 65.37C9.78 65.35 9.71 65.33 9.64 65.31L9.54 65.3 9.43 65.29C9.41 65.3 9.4 65.3 9.39 65.3 9.38 65.3 9.38 65.3 9.37 65.3H9.36L9.36 65.3H9.36L9.45 66.29 9.36 65.3 9.23 65.31 9.11 65.35 1.94 67.93C1.38 68.14 0.84 67.6 1.04 67.04L3.63 59.87 3.67 59.75 3.68 59.62V59.62H3.68V59.61C3.68 59.61 3.68 59.61 3.68 59.61 3.68 59.6 3.68 59.6 3.68 59.59 3.68 59.58 3.68 59.57 3.68 59.55 3.69 59.53 3.69 59.49 3.68 59.44 3.67 59.3 3.63 59.16 3.56 59.03 2.38 56.84 1.72 54.34 1.72 51.67 1.72 43.07 8.7 36.09 17.3 36.09Z"/>
<path
android:strokeColor="#FF3B45FD"
android:strokeWidth="1"
android:pathData="M19.37 40.66l-4.11 0.91-4.57 1.37-1.83 3.2-2.29 3.66-0.46 5.49 1.83 4.11-1.37 5.94 6.4-0.91L18 65.34l5.94-0.45c1.37-1.22 4.12-3.75 4.12-4.12 0-0.36 2.13-2.9 3.2-4.11l-0.46-5.49-0.91-4.57-5.95-4.57-4.57-1.37Z"/>
android:fillColor="#FFD9E0EE"
android:strokeColor="#FF4A5775"
android:strokeWidth="1.5"
android:pathData="M60.56 21.41H79.56C83.01 21.41 85.81 24.21 85.81 27.66V40.66C85.81 44.11 83.01 46.91 79.56 46.91H60.56C57.11 46.91 54.31 44.11 54.31 40.66V27.66C54.31 24.21 57.11 21.41 60.56 21.41Z"/>
<group>
<clip-path
android:pathData="M60.56 21.41H79.56C83.01 21.41 85.81 24.21 85.81 27.66V40.66C85.81 44.11 83.01 46.91 79.56 46.91H60.56C57.11 46.91 54.31 44.11 54.31 40.66V27.66C54.31 24.21 57.11 21.41 60.56 21.41Z"/>
<path
android:fillColor="#FFAFBDDB"
android:strokeColor="#FF4A5775"
android:strokeWidth="1.5"
android:pathData="M60.58 36.4L54.26 42.76C53.82 43.2 53.61 43.82 53.69 44.44L53.83 45.43C53.96 46.42 54.81 47.16 55.81 47.16H86.56C87.67 47.16 88.56 46.26 88.56 45.16V43.65C88.56 43.12 88.35 42.61 87.98 42.24L77.89 32.09C77.11 31.3 75.84 31.3 75.05 32.09L68.81 38.36C68.1 39.08 66.96 39.15 66.16 38.53L63.23 36.23C62.44 35.61 61.3 35.68 60.58 36.4Z"/>
</group>
<path
android:strokeColor="#FF3B45FD"
android:strokeWidth="1"
android:pathData="M4.17 53c0-7.64 6.19-13.83 13.83-13.83S31.83 45.36 31.83 53 25.64 66.83 18 66.83c-2.4 0-4.65-0.6-6.61-1.68l-5 1.8c-1.45 0.53-2.87-0.89-2.34-2.34l1.8-5C4.78 57.65 4.17 55.4 4.17 53ZM18 41.5c-6.35 0-11.5 5.15-11.5 11.5 0 2.06 0.54 3.98 1.48 5.65 0.26 0.46 0.33 1.02 0.14 1.54L6.6 64.4l4.2-1.5c0.53-0.2 1.1-0.13 1.55 0.13 1.67 0.94 3.6 1.48 5.65 1.48 6.35 0 11.5-5.15 11.5-11.5S24.35 41.5 18 41.5Z"/>
android:strokeColor="#FF4A5775"
android:strokeWidth="2"
android:pathData="M60.56 21.66H79.56C82.88 21.66 85.56 24.35 85.56 27.66V40.66C85.56 43.97 82.88 46.66 79.56 46.66H60.56C57.25 46.66 54.56 43.97 54.56 40.66V27.66C54.56 24.35 57.25 21.66 60.56 21.66Z"/>
<path
android:fillColor="#FFE0E5FF"
android:pathData="M48.82 17.77c-0.14 4.61-0.43 14.08-0.43 15.12l1.3 2.16 6.04-5.18 4.32 2.59 8.2-6.48 7.35 5.61 0.43-12.09-3.45-3.45L52.7 15.6l-3.89 2.16Z"/>
<path
android:fillColor="#FFE0E5FF"
android:pathData="M55.41 30.2l-6.58 6.14v0.44l2.2 3.07 7.46 0.44 13.6-0.44 3.52-3.07 0.88-4.39-8.34-6.15-7.47 6.15-5.27-2.2Z"/>
<path
android:fillColor="#FF3B45FD"
android:pathData="M53.38 23.13c0-1.45 1.17-2.63 2.62-2.63 1.45 0 2.63 1.18 2.63 2.63 0 1.44-1.18 2.62-2.63 2.62s-2.63-1.18-2.63-2.63Z"/>
<path
android:fillColor="#FF3B45FD"
android:fillType="evenOdd"
android:pathData="M77.56 24.34v7.32c0 1.42 0 2.57-0.07 3.5-0.08 0.95-0.25 1.8-0.64 2.57-0.63 1.23-1.64 2.24-2.87 2.87-0.78 0.4-1.62 0.56-2.57 0.64-0.93 0.07-2.08 0.07-3.5 0.07H56.09c-1.42 0-2.57 0-3.5-0.07-0.95-0.08-1.8-0.25-2.57-0.64-1.23-0.63-2.24-1.64-2.87-2.87-0.4-0.78-0.56-1.62-0.64-2.57-0.07-0.93-0.07-2.08-0.07-3.5v-7.32c0-1.42 0-2.57 0.07-3.5 0.08-0.95 0.25-1.8 0.64-2.57 0.63-1.23 1.64-2.24 2.87-2.87 0.78-0.4 1.62-0.56 2.57-0.64 0.93-0.07 2.08-0.07 3.5-0.07h11.82c1.42 0 2.57 0 3.5 0.07 0.95 0.08 1.8 0.25 2.57 0.64 1.23 0.63 2.24 1.64 2.87 2.87 0.4 0.78 0.56 1.62 0.64 2.57 0.07 0.93 0.07 2.08 0.07 3.5Zm-2.69-3.28c-0.06-0.8-0.19-1.25-0.36-1.6-0.38-0.74-0.98-1.34-1.72-1.72-0.35-0.17-0.8-0.3-1.6-0.36-0.8-0.07-1.85-0.07-3.34-0.07h-11.7c-1.5 0-2.53 0-3.34 0.07-0.8 0.06-1.25 0.19-1.6 0.36-0.74 0.38-1.34 0.98-1.72 1.72-0.17 0.35-0.3 0.8-0.36 1.6-0.07 0.8-0.07 1.85-0.07 3.34v7.2c0 0.88 0 1.6 0.02 2.22l3.87-3.88c1.68-1.68 4.42-1.68 6.1 0l1.08 1.08 4.82-4.83c1.68-1.68 4.42-1.68 6.1 0l3.89 3.9V24.4c0-1.5 0-2.53-0.07-3.34Zm-23.66 17.2c-0.61-0.31-1.13-0.78-1.5-1.36l5.1-5.1c0.66-0.66 1.72-0.66 2.38 0l2 2c0.52 0.52 1.35 0.52 1.86 0l5.76-5.75c0.66-0.66 1.72-0.66 2.38 0l5.73 5.73c0 0.44-0.02 0.82-0.05 1.16-0.06 0.8-0.19 1.25-0.36 1.6-0.38 0.74-0.98 1.34-1.72 1.72-0.35 0.17-0.8 0.3-1.6 0.36-0.8 0.07-1.85 0.07-3.34 0.07h-11.7c-1.5 0-2.53 0-3.34-0.07-0.8-0.06-1.25-0.19-1.6-0.36Z"/>
<path
android:strokeColor="#FF3B45FD"
android:strokeWidth="0.5"
android:pathData="M48.82 17.77c-0.14 4.61-0.43 14.08-0.43 15.12l1.3 2.16 6.04-5.18 4.32 2.59 8.2-6.48 7.35 5.61 0.43-12.09-3.45-3.45L52.7 15.6l-3.89 2.16Z"/>
<path
android:strokeColor="#FF3B45FD"
android:strokeWidth="0.5"
android:pathData="M55.41 30.2l-6.58 6.14v0.44l2.2 3.07 7.46 0.44 13.6-0.44 3.52-3.07 0.88-4.39-8.34-6.15-7.47 6.15-5.27-2.2Z"/>
<path
android:strokeColor="#FF3B45FD"
android:strokeWidth="0.5"
android:pathData="M53.38 23.13c0-1.45 1.17-2.63 2.62-2.63 1.45 0 2.63 1.18 2.63 2.63 0 1.44-1.18 2.62-2.63 2.62s-2.63-1.18-2.63-2.63Z"/>
<path
android:strokeColor="#FF3B45FD"
android:strokeWidth="0.5"
android:pathData="M77.56 24.34v7.32c0 1.42 0 2.57-0.07 3.5-0.08 0.95-0.25 1.8-0.64 2.57-0.63 1.23-1.64 2.24-2.87 2.87-0.78 0.4-1.62 0.56-2.57 0.64-0.93 0.07-2.08 0.07-3.5 0.07H56.09c-1.42 0-2.57 0-3.5-0.07-0.95-0.08-1.8-0.25-2.57-0.64-1.23-0.63-2.24-1.64-2.87-2.87-0.4-0.78-0.56-1.62-0.64-2.57-0.07-0.93-0.07-2.08-0.07-3.5v-7.32c0-1.42 0-2.57 0.07-3.5 0.08-0.95 0.25-1.8 0.64-2.57 0.63-1.23 1.64-2.24 2.87-2.87 0.78-0.4 1.62-0.56 2.57-0.64 0.93-0.07 2.08-0.07 3.5-0.07h11.82c1.42 0 2.57 0 3.5 0.07 0.95 0.08 1.8 0.25 2.57 0.64 1.23 0.63 2.24 1.64 2.87 2.87 0.4 0.78 0.56 1.62 0.64 2.57 0.07 0.93 0.07 2.08 0.07 3.5Zm-2.69-3.28c-0.06-0.8-0.19-1.25-0.36-1.6-0.38-0.74-0.98-1.34-1.72-1.72-0.35-0.17-0.8-0.3-1.6-0.36-0.8-0.07-1.85-0.07-3.34-0.07h-11.7c-1.5 0-2.53 0-3.34 0.07-0.8 0.06-1.25 0.19-1.6 0.36-0.74 0.38-1.34 0.98-1.72 1.72-0.17 0.35-0.3 0.8-0.36 1.6-0.07 0.8-0.07 1.85-0.07 3.34v7.2c0 0.88 0 1.6 0.02 2.22l3.87-3.88c1.68-1.68 4.42-1.68 6.1 0l1.08 1.08 4.82-4.83c1.68-1.68 4.42-1.68 6.1 0l3.89 3.9V24.4c0-1.5 0-2.53-0.07-3.34Zm-23.66 17.2c-0.61-0.31-1.13-0.78-1.5-1.36l5.1-5.1c0.66-0.66 1.72-0.66 2.38 0l2 2c0.52 0.52 1.35 0.52 1.86 0l5.76-5.75c0.66-0.66 1.72-0.66 2.38 0l5.73 5.73c0 0.44-0.02 0.82-0.05 1.16-0.06 0.8-0.19 1.25-0.36 1.6-0.38 0.74-0.98 1.34-1.72 1.72-0.35 0.17-0.8 0.3-1.6 0.36-0.8 0.07-1.85 0.07-3.34 0.07h-11.7c-1.5 0-2.53 0-3.34-0.07-0.8-0.06-1.25-0.19-1.6-0.36Z"/>
android:fillColor="#FF4A5775"
android:pathData="M59.86 28.79C59.86 27.06 61.27 25.66 63 25.66 64.74 25.66 66.14 27.06 66.14 28.79 66.14 30.52 64.74 31.93 63 31.93 61.27 31.93 59.86 30.52 59.86 28.79Z"/>
</vector>
-4
View File
@@ -9016,10 +9016,6 @@
<string name="MessageBackupsEducationScreen__optional_always">Opsioneel, altyd</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">Skrap jou rugsteun te eniger tyd</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">Aktiveer rugsteun</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">Vind meer uit</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9808,10 +9808,6 @@
<string name="MessageBackupsEducationScreen__optional_always">اختيارية، دائمًا</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">احذف نسختك الاحتياطية في أي وقت</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">تفعيل النسخ الاحتياطية</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">اعرف المزيد</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9016,10 +9016,6 @@
<string name="MessageBackupsEducationScreen__optional_always">Hər zaman ixtiyari</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">Ehtiyat nüsxəni istədiyiniz zaman silin</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">Nüsxələməni fəallaşdır</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">Daha ətraflı</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9412,10 +9412,6 @@
<string name="MessageBackupsEducationScreen__optional_always">Неабавязкова, як заўсёды</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">Выдаліць рэзервовую копію ў любы час</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">Уключыць рэзервовыя копіі</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">Даведацца больш</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9016,10 +9016,6 @@
<string name="MessageBackupsEducationScreen__optional_always">По желание, винаги</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">Можете да изтриете резервното копие по всяко време</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">Активиране на архиви</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">Научете повече</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9016,10 +9016,6 @@
<string name="MessageBackupsEducationScreen__optional_always">ঐচ্ছিক, সবসময়</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">যেকোনো সময় আপনার ব্যাকআপ মুছে ফেলুন</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">ব্যাকআপ সক্ষম করুন</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">আরো জানুন</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9412,10 +9412,6 @@
<string name="MessageBackupsEducationScreen__optional_always">Nije obavezno</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">Izbrišite sigurnosnu kopiju bilo kada</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">Aktiviraj</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">Saznaj više</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9016,10 +9016,6 @@
<string name="MessageBackupsEducationScreen__optional_always">Opcional, sempre</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">Elimina la teva còpia de seguretat en qualsevol moment</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">Activa les còpies de seguretat</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">Més informació</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9412,10 +9412,6 @@
<string name="MessageBackupsEducationScreen__optional_always">Volitelné, vždy</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">Zálohu můžete kdykoli odstranit</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">Povolit zálohování</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">Zjistit více</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9016,10 +9016,6 @@
<string name="MessageBackupsEducationScreen__optional_always">Altid valgfrit</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">Slet din sikkerhedskopi når som helst</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">Aktivér sikkerhedskopier</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">Få mere at vide</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9016,10 +9016,6 @@
<string name="MessageBackupsEducationScreen__optional_always">Optional</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">Lösche dein Backup jederzeit</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">Backups aktivieren</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">Mehr erfahren</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9016,10 +9016,6 @@
<string name="MessageBackupsEducationScreen__optional_always">Προαιρετικά, πάντα</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">Διαγραφή αντιγράφων ασφαλείας ανά πάσα στιγμή</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">Ενεργοποίηση αντίγραφων ασφαλείας</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">Μάθε περισσότερα</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9016,10 +9016,6 @@
<string name="MessageBackupsEducationScreen__optional_always">Servicio opcional, en todo momento</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">Copias de seguridad que puedes eliminar en cualquier momento</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">Habilitar copias de seguridad</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">Más información</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9016,10 +9016,6 @@
<string name="MessageBackupsEducationScreen__optional_always">Alati vabatahtlik</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">Võid oma varukoopia igal ajal kustutada</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">Luba varundamine</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">Rohkem teavet</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9016,10 +9016,6 @@
<string name="MessageBackupsEducationScreen__optional_always">Aukerakoa, beti</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">Ezabatu babeskopia nahi duzunean</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">Gaitu babeskopiak</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">Informazio gehiago</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9016,10 +9016,6 @@
<string name="MessageBackupsEducationScreen__optional_always">اختیاری، همیشه</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">هر موقع خواستید، نسخه پشتیبان خود را حذف کنید</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">فعال‌سازی پشتیبان‌ها</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">اطلاعات بیشتر</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9016,10 +9016,6 @@
<string name="MessageBackupsEducationScreen__optional_always">Aina valinnainen</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">Poista varmuuskopio milloin tahansa</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">Ota varmuuskopiot käyttöön</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">Lue lisää</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9016,10 +9016,6 @@
<string name="MessageBackupsEducationScreen__optional_always">La liberté de choisir un service en option</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">Des sauvegardes que vous pouvez supprimer à tout moment</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">Activer les sauvegardes</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">En savoir plus</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9610,10 +9610,6 @@
<string name="MessageBackupsEducationScreen__optional_always">Roghnach, i gcónaí</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">Scrios do chúltaca ag am ar bith</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">Cumasaigh cúltacaithe</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">Tuilleadh faisnéise</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9016,10 +9016,6 @@
<string name="MessageBackupsEducationScreen__optional_always">Escolle usalo cando queiras</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">Elimina a copia de seguranza cando queiras</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">Activar copias de seguranza</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">Máis información</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9016,10 +9016,6 @@
<string name="MessageBackupsEducationScreen__optional_always">વૈકલ્પિક, હંમેશા</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">તમારા બેકઅપને કોઈ પણ સમયે ડિલીટ કરો</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">બેકઅપ સક્ષમ કરો</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">વધુ જાણો</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9016,10 +9016,6 @@
<string name="MessageBackupsEducationScreen__optional_always">वैकल्पिक, हमेशा</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">अपना बैकअप कभी भी डिलीट करें</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">बैकअप की सुविधा चालू करें</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">और जानें</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9412,10 +9412,6 @@
<string name="MessageBackupsEducationScreen__optional_always">Neobavezno</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">Brisanje sigurnosne kopije moguće je u bilo kojem trenutku</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">Omogući sigurnosne kopije</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">Saznajte više</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9016,10 +9016,6 @@
<string name="MessageBackupsEducationScreen__optional_always">Sosem kötelező</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">A biztonsági másolatok bármikor törölhetők</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">Biztonsági mentések bekapcsolása</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">Tudj meg többet</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -8818,10 +8818,6 @@
<string name="MessageBackupsEducationScreen__optional_always">Opsional, selalu</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">Hapus cadangan Anda kapan saja</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">Aktifkan pencadangan</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">Pelajari selengkapnya</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9016,10 +9016,6 @@
<string name="MessageBackupsEducationScreen__optional_always">Sempre facoltativo</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">Elimina il tuo backup quando vuoi</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">Abilita i backup</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">Scopri di più</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9412,10 +9412,6 @@
<string name="MessageBackupsEducationScreen__optional_always">אופציונלי, תמיד</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">אפשר למחוק את הגיבוי בכל עת</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">אפשר גיבויים</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">למידע נוסף</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -8818,10 +8818,6 @@
<string name="MessageBackupsEducationScreen__optional_always">任意でいつでも利用できます</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">バックアップはいつでも消去可能です</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">バックアップを有効にする</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">詳しく見る</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9016,10 +9016,6 @@
<string name="MessageBackupsEducationScreen__optional_always">ყოველთვის ნებაყოფლობითი</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">წაშალე შენი სარეზერვო კოპიები ნებისმიერ დროს</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">სარეზერვო კოპირების ჩართვა</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">გაიგე მეტი</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9016,10 +9016,6 @@
<string name="MessageBackupsEducationScreen__optional_always">Міндетті емес, әрдайым</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">Резервтік көшірмеңізді кез келген уақытты жойыңыз</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">Резервтік көшірмелерді қосу</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">Толық ақпарат</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -8818,10 +8818,6 @@
<string name="MessageBackupsEducationScreen__optional_always">ជាជម្រើសជានិច្ច</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">លុបការបម្រុងទុករបស់អ្នកនៅពេលណាក៏បាន</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">បើកការបម្រុងទុក</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">ស្វែងយល់បន្ថែម</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9016,10 +9016,6 @@
<string name="MessageBackupsEducationScreen__optional_always">ಐಚ್ಛಿಕ, ಯಾವಾಗಲೂ</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">ನಿಮ್ಮ ಬ್ಯಾಕಪ್ ಅನ್ನು ಯಾವಾಗ ಬೇಕಾದರೂ ಅಳಿಸಿ</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">ಬ್ಯಾಕಪ್‌ಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -8818,10 +8818,6 @@
<string name="MessageBackupsEducationScreen__optional_always">필수가 아닌 선택 사항</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">언제나 백업 삭제 가능</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">백업 활성화</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">자세히 알아보기</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9016,10 +9016,6 @@
<string name="MessageBackupsEducationScreen__optional_always">Ар дайым өзүңүз каалагандай</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">Камдык көчүрмөлөрдү каалаган учурда өчүрүп коесуз</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">Камдык көчүрмөлөрдү иштетүү</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">Кененирээк маалымат</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9412,10 +9412,6 @@
<string name="MessageBackupsEducationScreen__optional_always">Neprivaloma</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">Atsarginę kopiją galima bet kada ištrinti</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">Įjungti atsargines kopijas</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">Sužinoti daugiau</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9214,10 +9214,6 @@
<string name="MessageBackupsEducationScreen__optional_always">Pēc izvēles</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">Dzēsiet rezerves kopiju jebkurā laikā</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">Iespējot rezerves kopēšanu</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">Uzzināt vairāk</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9016,10 +9016,6 @@
<string name="MessageBackupsEducationScreen__optional_always">Секогаш незадолжително</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">Можете да ја избришете вашата резерва копија во секое време</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">Вклучи резервна копија</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">Дознајте повеќе</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9016,10 +9016,6 @@
<string name="MessageBackupsEducationScreen__optional_always">ഓപ്ഷണൽ, എപ്പോഴും</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">എപ്പോൾ വേണമെങ്കിലും നിങ്ങളുടെ ബാക്കപ്പ് ഇല്ലാതാക്കുക</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">ബാക്കപ്പുകൾ പ്രവർത്തനക്ഷമമാക്കുക</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">കൂടുതലറിയുക</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9016,10 +9016,6 @@
<string name="MessageBackupsEducationScreen__optional_always">वैकल्पिक, नेहमी</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">आपला बॅकअप कधीही हटवा</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">बॅकअप सक्षम करा</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">अधिक जाणून घ्या</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -8818,10 +8818,6 @@
<string name="MessageBackupsEducationScreen__optional_always">Terpulang kepada anda</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">Padamkan sandaran anda pada bila-bila masa</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">Mendayakan sandaran</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">Ketahui lebih lanjut</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -8818,10 +8818,6 @@
<string name="MessageBackupsEducationScreen__optional_always">အမြဲတမ်း ရွေးချယ်နိုင်သည်</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">သင်၏ဘက်ခ်အပ်ကို အချိန်မရွေး ဖျက်နိုင်သည်</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">ဘက်ခ်အပ် လုပ်ဆောင်မည်</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">ပိုမိုလေ့လာရန်</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9016,10 +9016,6 @@
<string name="MessageBackupsEducationScreen__optional_always">Alltid valgfritt</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">Slett sikkerhetskopien når som helst</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">Slå på sikkerhetskopiering</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">Les mer</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9016,10 +9016,6 @@
<string name="MessageBackupsEducationScreen__optional_always">Optioneel</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">Verwijder je back-up wanneer je wilt</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">Back-ups inschakelen</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">Meer informatie</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9016,10 +9016,6 @@
<string name="MessageBackupsEducationScreen__optional_always">ਵਿਕਲਪਿਕ, ਹਮੇਸ਼ਾ</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">ਕਿਸੇ ਵੀ ਸਮੇਂ ਆਪਣਾ ਬੈਕਅੱਪ ਮਿਟਾਓ</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">ਬੈਕਅੱਪ ਨੂੰ ਸਮਰੱਥ ਕਰੋ</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">ਹੋਰ ਜਾਣੋ</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9412,10 +9412,6 @@
<string name="MessageBackupsEducationScreen__optional_always">Dla chętnych (jak zwykle)</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">Możliwość usunięcia kopii zapasowej w dowolnym momencie</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">Włącz kopie zapasowe</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">Dowiedz się więcej</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
@@ -9016,10 +9016,6 @@
<string name="MessageBackupsEducationScreen__optional_always">Sempre opcional</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">Exclua seu backup quando quiser</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">Habilitar backups</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">Saiba mais</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9016,10 +9016,6 @@
<string name="MessageBackupsEducationScreen__optional_always">Opcional, sempre</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">Elimine a sua cópia de segurança a qualquer altura</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">Ativar cópias de segurança</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">Saber mais</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9214,10 +9214,6 @@
<string name="MessageBackupsEducationScreen__optional_always">Opțional, întotdeauna</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">Șterge oricând copia ta de rezervă</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">Activează backup-urile</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">Află mai multe</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9412,10 +9412,6 @@
<string name="MessageBackupsEducationScreen__optional_always">Всегда можно отключить</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">Удаляйте резервные копии в любое время</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">Включить резервные копии</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">Узнать больше</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9412,10 +9412,6 @@
<string name="MessageBackupsEducationScreen__optional_always">Voliteľné, zakaždým</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">Kedykoľvek môžete zálohu vymazať</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">Povoliť zálohovanie</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">Zistiť viac</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9412,10 +9412,6 @@
<string name="MessageBackupsEducationScreen__optional_always">Neobvezno, vedno</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">Kadarkoli izbrišite varnostno kopijo</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">Dovoli varnostno kopiranje</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">Preberite več</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9016,10 +9016,6 @@
<string name="MessageBackupsEducationScreen__optional_always">Opsionale, gjithmonë</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">Fshij kopjeruajtjen në çdo kohë</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">Aktivizoji kopjeruajtjet</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">Mëso më shumë</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9016,10 +9016,6 @@
<string name="MessageBackupsEducationScreen__optional_always">Увек опционо</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">Избришите резервну копију када год пожелите</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">Укључи резервне копије</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">Сазнајте више</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9016,10 +9016,6 @@
<string name="MessageBackupsEducationScreen__optional_always">Alltid valfritt</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">Ta bort din säkerhetskopia när som helst</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">Aktivera säkerhetskopior</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">Läs mer</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9016,10 +9016,6 @@
<string name="MessageBackupsEducationScreen__optional_always">Ya hiari, mara zote</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">Futa nakala yako muda wowote ule</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">Wezesha nakalahifadhi</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">Jifunze zaidi</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9016,10 +9016,6 @@
<string name="MessageBackupsEducationScreen__optional_always">விருப்பத்தேர்வுக்குரியது, எப்போதும்</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">உங்கள் காப்புப்பிரதியை எப்போது வேண்டுமானாலும் அழிக்கலாம்</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">காப்புப்பிரதிகளை இயக்கு</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">மேலும் அறிக</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9016,10 +9016,6 @@
<string name="MessageBackupsEducationScreen__optional_always">ఐచ్ఛికం, ఎల్లప్పుడు</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">మీ బ్యాకప్ ఎప్పుడైనా తొలగించండి</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">ప్రత్యామ్నాయ ప్రారంభించు</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">మరింత తెలుసుకోండి</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -8818,10 +8818,6 @@
<string name="MessageBackupsEducationScreen__optional_always">เลือกสมัครใช้บริการได้ตลอด</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">เลือกลบข้อมูลสำรองได้ทุกเมื่อ</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">เปิดใช้การสำรองข้อมูล</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">เรียนรู้เพิ่มเติม</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9016,10 +9016,6 @@
<string name="MessageBackupsEducationScreen__optional_always">Palaging optional</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">Burahin ang backup mo anumang oras</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">I-enable ang mga backup?</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">Matuto pa</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9016,10 +9016,6 @@
<string name="MessageBackupsEducationScreen__optional_always">İsteğe bağlı, daima</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">Yedeklemeni istediğin zaman sil</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">Yedekleri etkinleştir</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">Daha fazlasını öğren</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -8818,10 +8818,6 @@
<string name="MessageBackupsEducationScreen__optional_always">ئىختىيارىي ، ھەرقاچان</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">زاپاس مەلۇماتلار خالىغان ۋاقىتتا ئۆچۈرەلەيسىز</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">زاپاسلارنى قوزغات</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">تەپسىلاتى</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9412,10 +9412,6 @@
<string name="MessageBackupsEducationScreen__optional_always">Ніколи не буде обов\'язковим</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">Резервну копію можна видалити коли завгодно</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">Увімкнути</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">Дізнатися більше</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -9016,10 +9016,6 @@
<string name="MessageBackupsEducationScreen__optional_always">اختیاری، ہمیشہ</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">اپنا بیک اپ کسی بھی وقت حذف کریں</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">بیک اپ فعال کریں</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">مزید جانیں</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -8818,10 +8818,6 @@
<string name="MessageBackupsEducationScreen__optional_always">Lựa chọn không bắt buộc</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">Xóa bản sao lưu bất kỳ lúc nào</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">Bật sao lưu</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">Tìm hiểu thêm</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
-4
View File
@@ -8818,10 +8818,6 @@
<string name="MessageBackupsEducationScreen__optional_always">幾時都有得揀</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">隨時刪除備份</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">啟用備份</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">了解詳情</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
@@ -8818,10 +8818,6 @@
<string name="MessageBackupsEducationScreen__optional_always">始终任选</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">可随时删除备份</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">启用备份</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">了解详情</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
@@ -8818,10 +8818,6 @@
<string name="MessageBackupsEducationScreen__optional_always">永遠可自由選擇</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">隨時刪除你的備份</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">啟用備份</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">了解更多</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
@@ -8818,10 +8818,6 @@
<string name="MessageBackupsEducationScreen__optional_always">永遠可自由選擇</string>
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">隨時刪除你的備份</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">啟用備份</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">了解更多</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
+23 -3
View File
@@ -9024,9 +9024,9 @@
<!-- Backups feature label for informing the user that they can delete their backup at any time -->
<string name="MessageBackupsEducationScreen__delete_your_backup_anytime">Delete your backup anytime</string>
<!-- Action button label to proceed with backups activation -->
<string name="MessageBackupsEducationScreen__enable_backups">Enable backups</string>
<!-- Action button label to learn more -->
<string name="MessageBackupsEducationScreen__learn_more">Learn more</string>
<string name="MessageBackupsEducationScreen__continue">Continue</string>
<!-- Action button label to leave the backups activation flow without enabling backups -->
<string name="MessageBackupsEducationScreen__not_now">Not now</string>
<!-- MessageBackupsKeyEducationScreen -->
<!-- Screen headline -->
@@ -9160,6 +9160,26 @@
<string name="MessageBackupsKeyVerifyScreen__see_key_again">See key again</string>
<!-- Confirm your key button text to move onto next screen in flow -->
<string name="MessageBackupsKeyVerifyScreen__next">Next</string>
<!-- Confirm your key subtitle shown to users whose recovery key came with their Signal Login rather than being recorded during this flow -->
<string name="MessageBackupsKeyVerifyScreen__enter_the_recovery_key_from_your_signal_login">Enter the recovery key from your Signal Login</string>
<!-- MessageBackupsConfirmRecoveryKeyScreen -->
<!-- Screen headline asking the user to confirm the recovery key they received with their Signal Login -->
<string name="MessageBackupsConfirmRecoveryKeyScreen__confirm_your_recovery_key">Confirm your recovery key</string>
<!-- Screen subtitle explaining what the recovery key is and why it is needed -->
<string name="MessageBackupsConfirmRecoveryKeyScreen__your_recovery_key_is_a_64_character_code">Your recovery key is a 64-character code you received with your Signal Login. It\'s required to restore your backup. If you forget your key, you will not be able to recover your account.</string>
<!-- Caption above the action buttons warning the user that the password manager will prompt them next -->
<string name="MessageBackupsConfirmRecoveryKeyScreen__you_will_be_prompted_with_your_saved_password">You will be prompted with your saved password in the next step.</string>
<!-- Action button label to confirm the recovery key using the saved password manager credential -->
<string name="MessageBackupsConfirmRecoveryKeyScreen__confirm_recovery_key">Confirm recovery key</string>
<!-- Action button label to type the recovery key in by hand instead of using the password manager -->
<string name="MessageBackupsConfirmRecoveryKeyScreen__enter_manually">Enter manually</string>
<!-- Title of the dialog shown when the recovery key from the password manager did not match -->
<string name="MessageBackupsConfirmRecoveryKeyScreen__error_confirming_recovery_key">Error confirming recovery key</string>
<!-- Body of the dialog shown when the recovery key from the password manager did not match -->
<string name="MessageBackupsConfirmRecoveryKeyScreen__your_recovery_key_could_not_be_confirmed">Your recovery key could not be confirmed. Make sure you\'ve saved your Signal Login in your password manager, or enter your recovery key manually.</string>
<!-- Toast shown when the recovery key from the password manager matched -->
<string name="MessageBackupsConfirmRecoveryKeyScreen__recovery_key_confirmed">Recovery key confirmed</string>
<!-- Verify your key title -->
<string name="VerifyBackupPinScreen__enter_your_backup_key">Enter your recovery key</string>
@@ -0,0 +1,165 @@
/*
* Copyright 2026 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.thoughtcrime.securesms.backup.v2.ui.subscription
import android.app.Application
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.performScrollTo
import androidx.test.core.app.ApplicationProvider
import assertk.assertThat
import assertk.assertions.isFalse
import assertk.assertions.isTrue
import io.mockk.coEvery
import io.mockk.coVerify
import io.mockk.mockkObject
import io.mockk.unmockkAll
import org.junit.After
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
import org.signal.core.models.AccountEntropyPool
import org.signal.core.models.ServiceId
import org.signal.core.ui.CoreUiDependenciesRule
import org.signal.core.ui.compose.Dialogs
import org.signal.core.ui.compose.theme.SignalTheme
import org.signal.passwordmanager.SignalCredentialManager
import org.signal.passwordmanager.UsernamePasswordCredential
import org.signal.signallogin.SignalLoginTestTags
import java.util.UUID
/**
* Checks that the screen only advances when the password manager hands back the recovery key this device already has,
* and that every other path leaves the user a way to enter it manually.
*/
@RunWith(RobolectricTestRunner::class)
@Config(application = Application::class)
class MessageBackupsConfirmRecoveryKeyScreenTest {
companion object {
private val ACI = ServiceId.ACI.from(UUID.fromString("a6b28482-2e32-83d0-7f23-91360a4c2b91"))
private val AEP = AccountEntropyPool("uy38jh2778hjjhj8lk19ga61s672jsj089r023s6a57809bap92j2yh5t326vv7t")
private const val OTHER_KEY = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
}
@get:Rule
val composeTestRule = createComposeRule()
@get:Rule
val coreUiDependenciesRule = CoreUiDependenciesRule(ApplicationProvider.getApplicationContext())
private var confirmed = false
private var enteredManually = false
private var viewedDetails = false
@After
fun tearDown() {
unmockkAll()
}
@Test
fun `confirming a matching saved key advances the flow`() {
stubCredentialManager(AEP.displayValue)
setContent()
composeTestRule.onNodeWithTag(MessageBackupsConfirmRecoveryKeyTestTags.CONFIRM_BUTTON).performClick()
composeTestRule.waitForIdle()
assertThat(confirmed).isTrue()
}
@Test
fun `confirming a key that does not match shows the failure dialog instead of advancing`() {
stubCredentialManager(OTHER_KEY)
setContent()
composeTestRule.onNodeWithTag(MessageBackupsConfirmRecoveryKeyTestTags.CONFIRM_BUTTON).performClick()
composeTestRule.waitForIdle()
assertThat(confirmed).isFalse()
composeTestRule.onNodeWithTag(Dialogs.TEST_TAG_ALERT_DIALOG_CONFIRM_BUTTON).assertIsDisplayed()
}
@Test
fun `confirming with no saved credential shows the failure dialog instead of advancing`() {
stubCredentialManager(null)
setContent()
composeTestRule.onNodeWithTag(MessageBackupsConfirmRecoveryKeyTestTags.CONFIRM_BUTTON).performClick()
composeTestRule.waitForIdle()
assertThat(confirmed).isFalse()
composeTestRule.onNodeWithTag(Dialogs.TEST_TAG_ALERT_DIALOG_CONFIRM_BUTTON).assertIsDisplayed()
}
@Test
fun `the failure dialog sends the user to manual entry`() {
stubCredentialManager(OTHER_KEY)
setContent()
composeTestRule.onNodeWithTag(MessageBackupsConfirmRecoveryKeyTestTags.CONFIRM_BUTTON).performClick()
composeTestRule.waitForIdle()
composeTestRule.onNodeWithTag(Dialogs.TEST_TAG_ALERT_DIALOG_CONFIRM_BUTTON).performClick()
assertThat(enteredManually).isTrue()
}
@Test
fun `enter manually skips the password manager entirely`() {
stubCredentialManager(AEP.displayValue)
setContent()
composeTestRule.onNodeWithTag(MessageBackupsConfirmRecoveryKeyTestTags.ENTER_MANUALLY_BUTTON).performClick()
assertThat(enteredManually).isTrue()
assertThat(confirmed).isFalse()
}
@Test
fun `view details on the card opens the full login`() {
setContent()
composeTestRule.onNodeWithTag(SignalLoginTestTags.CARD_VIEW_DETAILS_BUTTON).performScrollTo().performClick()
assertThat(viewedDetails).isTrue()
}
@Test
fun `the credential is requested under the account key`() {
stubCredentialManager(AEP.displayValue)
setContent()
composeTestRule.onNodeWithTag(MessageBackupsConfirmRecoveryKeyTestTags.CONFIRM_BUTTON).performClick()
composeTestRule.waitForIdle()
coVerify { SignalCredentialManager.getCredential(any(), ACI.toString().uppercase()) }
}
private fun stubCredentialManager(password: String?) {
mockkObject(SignalCredentialManager)
coEvery { SignalCredentialManager.getCredential(any(), any()) } returns password?.let {
UsernamePasswordCredential(username = ACI.toString().uppercase(), password = it)
}
}
private fun setContent() {
composeTestRule.setContent {
SignalTheme {
MessageBackupsConfirmRecoveryKeyScreen(
aci = ACI,
aep = AEP,
onViewDetailsClick = { viewedDetails = true },
onConfirmed = { confirmed = true },
onEnterManuallyClick = { enteredManually = true }
)
}
}
}
}
@@ -0,0 +1,164 @@
/*
* Copyright 2026 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.thoughtcrime.securesms.backup.v2.ui.subscription
import android.app.Application
import assertk.assertThat
import assertk.assertions.isEqualTo
import io.mockk.coEvery
import io.mockk.every
import io.mockk.mockkObject
import io.mockk.unmockkAll
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.test.StandardTestDispatcher
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
import org.signal.core.models.AccountEntropyPool
import org.signal.core.models.ServiceId
import org.thoughtcrime.securesms.backup.v2.BackupRepository
import org.thoughtcrime.securesms.keyvalue.BackupValues
import org.thoughtcrime.securesms.testing.CoroutineDispatcherRule
import org.thoughtcrime.securesms.testutil.MockAppDependenciesRule
import org.thoughtcrime.securesms.testutil.MockSignalStoreRule
import java.util.UUID
/**
* Covers the stage machine, and in particular how it forks for accounts that already have a Signal Login and therefore
* already know their recovery key.
*/
@RunWith(RobolectricTestRunner::class)
@Config(manifest = Config.NONE, application = Application::class)
class MessageBackupsFlowViewModelTest {
companion object {
private val ACI = ServiceId.ACI.from(UUID.fromString("a6b28482-2e32-83d0-7f23-91360a4c2b91"))
private val AEP = AccountEntropyPool("uy38jh2778hjjhj8lk19ga61s672jsj089r023s6a57809bap92j2yh5t326vv7t")
}
@get:Rule
val appDependencies = MockAppDependenciesRule()
@get:Rule
val signalStore = MockSignalStoreRule(relaxed = setOf(BackupValues::class))
@get:Rule
val dispatcherRule = CoroutineDispatcherRule(StandardTestDispatcher())
@Before
fun setUp() {
every { signalStore.backup.backupTier } returns null
every { signalStore.backup.deletionStateFlow } returns emptyFlow()
every { signalStore.account.accountEntropyPool } returns AEP
every { signalStore.account.requireAci() } returns ACI
mockkObject(BackupRepository)
coEvery { BackupRepository.getBackupTypes(any()) } returns emptyList()
}
@After
fun tearDown() {
unmockkAll()
}
@Test
fun `an account with a Signal Login confirms its existing key instead of recording a new one`() {
val viewModel = createViewModel(isPhoneNumberless = true)
viewModel.goToNextStage()
assertThat(viewModel.stateFlow.value.stage).isEqualTo(MessageBackupsStage.CONFIRM_RECOVERY_KEY)
}
@Test
fun `an account with a phone number still records a new key`() {
val viewModel = createViewModel(isPhoneNumberless = false)
viewModel.goToNextStage()
assertThat(viewModel.stateFlow.value.stage).isEqualTo(MessageBackupsStage.BACKUP_KEY_EDUCATION)
}
@Test
fun `confirming the recovery key goes straight to plan selection`() {
val viewModel = createViewModel(isPhoneNumberless = true)
viewModel.goToNextStage()
viewModel.onRecoveryKeyConfirmed()
assertThat(viewModel.stateFlow.value.stage).isEqualTo(MessageBackupsStage.TYPE_SELECTION)
}
@Test
fun `entering the recovery key manually leads to plan selection by way of the verify screen`() {
val viewModel = createViewModel(isPhoneNumberless = true)
viewModel.goToNextStage()
viewModel.goToEnterRecoveryKeyManually()
assertThat(viewModel.stateFlow.value.stage).isEqualTo(MessageBackupsStage.BACKUP_KEY_VERIFY)
viewModel.goToNextStage()
assertThat(viewModel.stateFlow.value.stage).isEqualTo(MessageBackupsStage.TYPE_SELECTION)
}
@Test
fun `backing out of the verify screen returns to the confirmation screen`() {
val viewModel = createViewModel(isPhoneNumberless = true)
viewModel.goToNextStage()
viewModel.goToEnterRecoveryKeyManually()
viewModel.goToPreviousStage()
assertThat(viewModel.stateFlow.value.stage).isEqualTo(MessageBackupsStage.CONFIRM_RECOVERY_KEY)
}
@Test
fun `viewing the full login details is a detour off the confirmation screen`() {
val viewModel = createViewModel(isPhoneNumberless = true)
viewModel.goToNextStage()
viewModel.goToSignalLoginViewDetails()
assertThat(viewModel.stateFlow.value.stage).isEqualTo(MessageBackupsStage.SIGNAL_LOGIN_VIEW_DETAILS)
viewModel.goToPreviousStage()
assertThat(viewModel.stateFlow.value.stage).isEqualTo(MessageBackupsStage.CONFIRM_RECOVERY_KEY)
}
@Test
fun `backing out of the confirmation screen returns to education`() {
val viewModel = createViewModel(isPhoneNumberless = true)
viewModel.goToNextStage()
viewModel.goToPreviousStage()
assertThat(viewModel.stateFlow.value.stage).isEqualTo(MessageBackupsStage.EDUCATION)
}
@Test
fun `backing out of plan selection returns to the confirmation screen`() {
val viewModel = createViewModel(isPhoneNumberless = true)
viewModel.goToNextStage()
viewModel.onRecoveryKeyConfirmed()
viewModel.goToPreviousStage()
assertThat(viewModel.stateFlow.value.stage).isEqualTo(MessageBackupsStage.CONFIRM_RECOVERY_KEY)
}
private fun createViewModel(isPhoneNumberless: Boolean): MessageBackupsFlowViewModel {
return MessageBackupsFlowViewModel(
initialTierSelection = null,
googlePlayApiAvailability = 0,
isCredentialManagerSupported = true,
isPhoneNumberless = isPhoneNumberless,
startScreen = MessageBackupsStage.EDUCATION
)
}
}