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 {