Add polish to various backups ui elements.

This commit is contained in:
Alex Hart
2024-10-22 14:52:40 -03:00
committed by Greyson Parrelli
parent 1b2b4a869c
commit 88b39a062c
7 changed files with 85 additions and 42 deletions

View File

@@ -9,11 +9,14 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import androidx.activity.result.contract.ActivityResultContract import androidx.activity.result.contract.ActivityResultContract
import androidx.core.content.IntentCompat import androidx.core.content.IntentCompat
import androidx.core.os.bundleOf
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import org.signal.core.util.getParcelableExtraCompat import org.signal.core.util.getParcelableExtraCompat
import org.signal.donations.InAppPaymentType
import org.thoughtcrime.securesms.backup.v2.MessageBackupTier import org.thoughtcrime.securesms.backup.v2.MessageBackupTier
import org.thoughtcrime.securesms.components.FragmentWrapperActivity 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.CheckoutFlowActivity.Result
import org.thoughtcrime.securesms.components.settings.app.subscription.donate.InAppPaymentProcessorAction
/** /**
* Self-contained activity for message backups checkout, which utilizes Google Play Billing * Self-contained activity for message backups checkout, which utilizes Google Play Billing
@@ -24,6 +27,17 @@ class MessageBackupsCheckoutActivity : FragmentWrapperActivity() {
companion object { companion object {
private const val TIER = "tier" private const val TIER = "tier"
private const val RESULT_DATA = "result_data" 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( override fun getFragment(): Fragment = MessageBackupsFlowFragment.create(

View File

@@ -62,7 +62,7 @@ fun MessageBackupsEducationScreen(
) { ) {
item { item {
Image( 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, contentDescription = null,
modifier = Modifier modifier = Modifier
.padding(top = 24.dp) .padding(top = 24.dp)

View File

@@ -142,7 +142,7 @@ class MessageBackupsFlowFragment : ComposeFragment(), InAppPaymentCheckoutDelega
} }
if (state.stage == MessageBackupsStage.COMPLETED) { if (state.stage == MessageBackupsStage.COMPLETED) {
requireActivity().setResult(Activity.RESULT_OK) requireActivity().setResult(Activity.RESULT_OK, MessageBackupsCheckoutActivity.createResultData())
requireActivity().finishAfterTransition() requireActivity().finishAfterTransition()
} }
} }

View File

@@ -7,9 +7,11 @@ package org.thoughtcrime.securesms.backup.v2.ui.subscription
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
@@ -30,6 +32,7 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
@@ -210,7 +213,11 @@ private fun BottomSheetContent(
Row( Row(
verticalAlignment = Alignment.CenterVertically, 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( Checkbox(
checked = checked, checked = checked,
@@ -226,14 +233,18 @@ private fun BottomSheetContent(
Buttons.LargeTonal( Buttons.LargeTonal(
enabled = checked, enabled = checked,
onClick = onContinueClick, 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)) Text(text = stringResource(R.string.MessageBackupsKeyRecordScreen__continue))
} }
TextButton( TextButton(
onClick = onSeeKeyAgainClick, onClick = onSeeKeyAgainClick,
modifier = Modifier.padding(bottom = 24.dp) modifier = Modifier
.padding(bottom = 24.dp)
.defaultMinSize(minWidth = 220.dp)
) { ) {
Text( Text(
text = stringResource(R.string.MessageBackupsKeyRecordScreen__see_key_again) text = stringResource(R.string.MessageBackupsKeyRecordScreen__see_key_again)
@@ -251,3 +262,11 @@ private fun MessageBackupsKeyRecordScreenPreview() {
) )
} }
} }
@SignalPreview
@Composable
private fun BottomSheetContentPreview() {
Previews.BottomSheetPreview {
BottomSheetContent({}, {})
}
}

View File

@@ -9,7 +9,6 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.border import androidx.compose.foundation.border
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement.Absolute.spacedBy 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.Column
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth 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.lazy.itemsIndexed
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.ClickableText import androidx.compose.foundation.text.ClickableText
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@@ -55,6 +53,8 @@ import org.signal.core.util.bytes
import org.signal.core.util.money.FiatMoney import org.signal.core.util.money.FiatMoney
import org.thoughtcrime.securesms.R import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.backup.v2.MessageBackupTier 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.payments.FiatMoneyUtil
import org.thoughtcrime.securesms.util.ByteUnit import org.thoughtcrime.securesms.util.ByteUnit
import java.math.BigDecimal import java.math.BigDecimal
@@ -242,7 +242,7 @@ fun MessageBackupsTypeBlock(
SignalTheme.colors.colorSurface2 SignalTheme.colors.colorSurface2
} }
Box( Column(
modifier = modifier modifier = modifier
.fillMaxWidth() .fillMaxWidth()
.background(color = background, shape = RoundedCornerShape(18.dp)) .background(color = background, shape = RoundedCornerShape(18.dp))
@@ -251,44 +251,52 @@ fun MessageBackupsTypeBlock(
.clickable(onClick = onSelected, enabled = enabled) .clickable(onClick = onSelected, enabled = enabled)
.padding(vertical = 16.dp, horizontal = 20.dp) .padding(vertical = 16.dp, horizontal = 20.dp)
) { ) {
Column { if (isCurrent) {
Text( Text(
text = getFormattedPricePerMonth(messageBackupsType), text = buildAnnotatedString {
style = MaterialTheme.typography.titleSmall SignalSymbol(weight = SignalSymbols.Weight.REGULAR, glyph = SignalSymbols.Glyph.CHECKMARK)
) append(" ")
append(stringResource(R.string.MessageBackupsTypeSelectionScreen__current_plan))
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 color = MaterialTheme.colorScheme.onSurfaceVariant,
)
val featureIconTint = if (isSelected) {
iconColors.iconColorSelected
} else {
iconColors.iconColorNormal
}
Column(
verticalArrangement = spacedBy(4.dp),
modifier = Modifier modifier = Modifier
.padding(top = 8.dp) .padding(bottom = 12.dp)
.padding(horizontal = 16.dp) .background(
) { color = SignalTheme.colors.colorTransparent1,
getFeatures(messageBackupsType = messageBackupsType).forEach { shape = RoundedCornerShape(14.dp)
MessageBackupsTypeFeatureRow(messageBackupsTypeFeature = it, iconTint = featureIconTint) )
} .padding(vertical = 4.dp, horizontal = 12.dp)
} )
} }
if (isCurrent) { Text(
Icon( text = getFormattedPricePerMonth(messageBackupsType),
painter = painterResource(id = R.drawable.symbol_check_24), style = MaterialTheme.typography.titleSmall
contentDescription = null, )
modifier = Modifier.align(Alignment.TopEnd)
) 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)
}
} }
} }
} }

View File

@@ -7737,6 +7737,8 @@
<item quantity="one">Last %1$d day of media</item> <item quantity="one">Last %1$d day of media</item>
<item quantity="other">Last %1$d days of media</item> <item quantity="other">Last %1$d days of media</item>
</plurals> </plurals>
<!-- Text designating that an option is your current plan -->
<string name="MessageBackupsTypeSelectionScreen__current_plan">Current plan</string>
<!-- ConfirmBackupCancellationDialog --> <!-- ConfirmBackupCancellationDialog -->
<!-- Dialog title --> <!-- Dialog title -->

View File

@@ -151,7 +151,7 @@ internal class BillingApiImpl(
init { init {
coroutineScope.launch { coroutineScope.launch {
createConnectionFlow() createConnectionFlow()
.retry { it is RetryException } // TODO [message-backups] - consider a delay here .retry { it is RetryException }
.collect { newState -> .collect { newState ->
Log.d(TAG, "Updating Google Play Billing connection state: $newState") Log.d(TAG, "Updating Google Play Billing connection state: $newState")
connectionState.update { connectionState.update {