From 88b39a062cca179a1c2ed6f6dd1b60d3570bbbe5 Mon Sep 17 00:00:00 2001 From: Alex Hart Date: Tue, 22 Oct 2024 14:52:40 -0300 Subject: [PATCH] Add polish to various backups ui elements. --- .../MessageBackupsCheckoutActivity.kt | 14 ++++ .../MessageBackupsEducationScreen.kt | 2 +- .../MessageBackupsFlowFragment.kt | 2 +- .../MessageBackupsKeyRecordScreen.kt | 25 +++++- .../MessageBackupsTypeSelectionScreen.kt | 80 ++++++++++--------- app/src/main/res/values/strings.xml | 2 + .../java/org/signal/billing/BillingApiImpl.kt | 2 +- 7 files changed, 85 insertions(+), 42 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ui/subscription/MessageBackupsCheckoutActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ui/subscription/MessageBackupsCheckoutActivity.kt index f2131345fa..efb1a2daeb 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ui/subscription/MessageBackupsCheckoutActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ui/subscription/MessageBackupsCheckoutActivity.kt @@ -9,11 +9,14 @@ import android.content.Context import android.content.Intent import androidx.activity.result.contract.ActivityResultContract import androidx.core.content.IntentCompat +import androidx.core.os.bundleOf import androidx.fragment.app.Fragment import org.signal.core.util.getParcelableExtraCompat +import org.signal.donations.InAppPaymentType import org.thoughtcrime.securesms.backup.v2.MessageBackupTier import org.thoughtcrime.securesms.components.FragmentWrapperActivity import org.thoughtcrime.securesms.components.settings.app.subscription.donate.CheckoutFlowActivity.Result +import org.thoughtcrime.securesms.components.settings.app.subscription.donate.InAppPaymentProcessorAction /** * Self-contained activity for message backups checkout, which utilizes Google Play Billing @@ -24,6 +27,17 @@ class MessageBackupsCheckoutActivity : FragmentWrapperActivity() { companion object { private const val TIER = "tier" private const val RESULT_DATA = "result_data" + + fun createResultData(): Intent { + val data = bundleOf( + RESULT_DATA to Result( + action = InAppPaymentProcessorAction.PROCESS_NEW_IN_APP_PAYMENT, + inAppPaymentType = InAppPaymentType.RECURRING_BACKUP + ) + ) + + return Intent().putExtras(data) + } } override fun getFragment(): Fragment = MessageBackupsFlowFragment.create( diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ui/subscription/MessageBackupsEducationScreen.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ui/subscription/MessageBackupsEducationScreen.kt index bcf1e958d4..1842f52e85 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ui/subscription/MessageBackupsEducationScreen.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ui/subscription/MessageBackupsEducationScreen.kt @@ -62,7 +62,7 @@ fun MessageBackupsEducationScreen( ) { item { Image( - painter = painterResource(id = R.drawable.image_signal_backups), // TODO [message-backups] Final image asset + painter = painterResource(id = R.drawable.image_signal_backups), contentDescription = null, modifier = Modifier .padding(top = 24.dp) diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ui/subscription/MessageBackupsFlowFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ui/subscription/MessageBackupsFlowFragment.kt index 8ce04bff5d..e19da17df1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ui/subscription/MessageBackupsFlowFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ui/subscription/MessageBackupsFlowFragment.kt @@ -142,7 +142,7 @@ class MessageBackupsFlowFragment : ComposeFragment(), InAppPaymentCheckoutDelega } if (state.stage == MessageBackupsStage.COMPLETED) { - requireActivity().setResult(Activity.RESULT_OK) + requireActivity().setResult(Activity.RESULT_OK, MessageBackupsCheckoutActivity.createResultData()) requireActivity().finishAfterTransition() } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ui/subscription/MessageBackupsKeyRecordScreen.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ui/subscription/MessageBackupsKeyRecordScreen.kt index 39244f3ebc..73e2101f9e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ui/subscription/MessageBackupsKeyRecordScreen.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ui/subscription/MessageBackupsKeyRecordScreen.kt @@ -7,9 +7,11 @@ package org.thoughtcrime.securesms.backup.v2.ui.subscription import androidx.compose.foundation.Image import androidx.compose.foundation.background +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.defaultMinSize import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding @@ -30,6 +32,7 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource @@ -210,7 +213,11 @@ private fun BottomSheetContent( Row( verticalAlignment = Alignment.CenterVertically, - modifier = Modifier.padding(vertical = 24.dp) + modifier = Modifier + .padding(vertical = 24.dp) + .defaultMinSize(minWidth = 220.dp) + .clip(shape = RoundedCornerShape(percent = 50)) + .clickable(onClick = { checked = !checked }) ) { Checkbox( checked = checked, @@ -226,14 +233,18 @@ private fun BottomSheetContent( Buttons.LargeTonal( enabled = checked, onClick = onContinueClick, - modifier = Modifier.padding(bottom = 16.dp) + modifier = Modifier + .padding(bottom = 16.dp) + .defaultMinSize(minWidth = 220.dp) ) { Text(text = stringResource(R.string.MessageBackupsKeyRecordScreen__continue)) } TextButton( onClick = onSeeKeyAgainClick, - modifier = Modifier.padding(bottom = 24.dp) + modifier = Modifier + .padding(bottom = 24.dp) + .defaultMinSize(minWidth = 220.dp) ) { Text( text = stringResource(R.string.MessageBackupsKeyRecordScreen__see_key_again) @@ -251,3 +262,11 @@ private fun MessageBackupsKeyRecordScreenPreview() { ) } } + +@SignalPreview +@Composable +private fun BottomSheetContentPreview() { + Previews.BottomSheetPreview { + BottomSheetContent({}, {}) + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ui/subscription/MessageBackupsTypeSelectionScreen.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ui/subscription/MessageBackupsTypeSelectionScreen.kt index e78e542116..d12d628858 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ui/subscription/MessageBackupsTypeSelectionScreen.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/ui/subscription/MessageBackupsTypeSelectionScreen.kt @@ -9,7 +9,6 @@ import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement.Absolute.spacedBy -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth @@ -19,7 +18,6 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.ClickableText -import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -55,6 +53,8 @@ import org.signal.core.util.bytes import org.signal.core.util.money.FiatMoney import org.thoughtcrime.securesms.R import org.thoughtcrime.securesms.backup.v2.MessageBackupTier +import org.thoughtcrime.securesms.fonts.SignalSymbols +import org.thoughtcrime.securesms.fonts.SignalSymbols.SignalSymbol import org.thoughtcrime.securesms.payments.FiatMoneyUtil import org.thoughtcrime.securesms.util.ByteUnit import java.math.BigDecimal @@ -242,7 +242,7 @@ fun MessageBackupsTypeBlock( SignalTheme.colors.colorSurface2 } - Box( + Column( modifier = modifier .fillMaxWidth() .background(color = background, shape = RoundedCornerShape(18.dp)) @@ -251,44 +251,52 @@ fun MessageBackupsTypeBlock( .clickable(onClick = onSelected, enabled = enabled) .padding(vertical = 16.dp, horizontal = 20.dp) ) { - Column { + if (isCurrent) { Text( - text = getFormattedPricePerMonth(messageBackupsType), - style = MaterialTheme.typography.titleSmall - ) - - Text( - text = when (messageBackupsType) { - is MessageBackupsType.Free -> pluralStringResource(id = R.plurals.MessageBackupsTypeSelectionScreen__text_plus_d_days_of_media, messageBackupsType.mediaRetentionDays, messageBackupsType.mediaRetentionDays) - is MessageBackupsType.Paid -> stringResource(id = R.string.MessageBackupsTypeSelectionScreen__text_plus_all_your_media) + text = buildAnnotatedString { + SignalSymbol(weight = SignalSymbols.Weight.REGULAR, glyph = SignalSymbols.Glyph.CHECKMARK) + append(" ") + append(stringResource(R.string.MessageBackupsTypeSelectionScreen__current_plan)) }, - style = MaterialTheme.typography.titleMedium - ) - - val featureIconTint = if (isSelected) { - iconColors.iconColorSelected - } else { - iconColors.iconColorNormal - } - - Column( - verticalArrangement = spacedBy(4.dp), + color = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier - .padding(top = 8.dp) - .padding(horizontal = 16.dp) - ) { - getFeatures(messageBackupsType = messageBackupsType).forEach { - MessageBackupsTypeFeatureRow(messageBackupsTypeFeature = it, iconTint = featureIconTint) - } - } + .padding(bottom = 12.dp) + .background( + color = SignalTheme.colors.colorTransparent1, + shape = RoundedCornerShape(14.dp) + ) + .padding(vertical = 4.dp, horizontal = 12.dp) + ) } - if (isCurrent) { - Icon( - painter = painterResource(id = R.drawable.symbol_check_24), - contentDescription = null, - modifier = Modifier.align(Alignment.TopEnd) - ) + Text( + text = getFormattedPricePerMonth(messageBackupsType), + style = MaterialTheme.typography.titleSmall + ) + + Text( + text = when (messageBackupsType) { + is MessageBackupsType.Free -> pluralStringResource(id = R.plurals.MessageBackupsTypeSelectionScreen__text_plus_d_days_of_media, messageBackupsType.mediaRetentionDays, messageBackupsType.mediaRetentionDays) + is MessageBackupsType.Paid -> stringResource(id = R.string.MessageBackupsTypeSelectionScreen__text_plus_all_your_media) + }, + style = MaterialTheme.typography.titleMedium + ) + + val featureIconTint = if (isSelected) { + iconColors.iconColorSelected + } else { + iconColors.iconColorNormal + } + + Column( + verticalArrangement = spacedBy(4.dp), + modifier = Modifier + .padding(top = 8.dp) + .padding(horizontal = 16.dp) + ) { + getFeatures(messageBackupsType = messageBackupsType).forEach { + MessageBackupsTypeFeatureRow(messageBackupsTypeFeature = it, iconTint = featureIconTint) + } } } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2b658e0462..8a6655dd42 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -7737,6 +7737,8 @@ Last %1$d day of media Last %1$d days of media + + Current plan diff --git a/billing/src/main/java/org/signal/billing/BillingApiImpl.kt b/billing/src/main/java/org/signal/billing/BillingApiImpl.kt index bb54fb4c21..922d0db320 100644 --- a/billing/src/main/java/org/signal/billing/BillingApiImpl.kt +++ b/billing/src/main/java/org/signal/billing/BillingApiImpl.kt @@ -151,7 +151,7 @@ internal class BillingApiImpl( init { coroutineScope.launch { createConnectionFlow() - .retry { it is RetryException } // TODO [message-backups] - consider a delay here + .retry { it is RetryException } .collect { newState -> Log.d(TAG, "Updating Google Play Billing connection state: $newState") connectionState.update {