Pop the "Create backup now" sheet after different instances of subscribing to backups.

This commit is contained in:
Alex Hart
2024-08-08 15:35:47 -03:00
committed by mtang-signal
parent 3bdbd69a7d
commit 1d6917476e
19 changed files with 245 additions and 86 deletions

View File

@@ -5,6 +5,7 @@
package org.thoughtcrime.securesms.backup.v2.ui
import android.content.DialogInterface
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
@@ -24,26 +25,38 @@ 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 androidx.core.os.bundleOf
import androidx.fragment.app.setFragmentResult
import org.signal.core.ui.BottomSheets
import org.signal.core.ui.Buttons
import org.signal.core.ui.Icons
import org.signal.core.ui.Previews
import org.signal.core.ui.SignalPreview
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.settings.app.AppSettingsActivity
import org.thoughtcrime.securesms.compose.ComposeBottomSheetDialogFragment
import org.thoughtcrime.securesms.jobs.BackupMessagesJob
/**
* Bottom sheet allowing the user to immediately start a backup or delay.
*
* If the result key is true, then the user has enqueued a backup and should be directed to the
* remote backup settings screen.
*/
class CreateBackupBottomSheet : ComposeBottomSheetDialogFragment() {
companion object {
const val REQUEST_KEY = "CreateBackupBottomSheet"
}
private var isResultSet = false
@Composable
override fun SheetContent() {
CreateBackupBottomSheetContent(
onBackupNowClick = {
BackupMessagesJob.enqueue()
startActivity(AppSettingsActivity.remoteBackups(requireContext()))
setFragmentResult(REQUEST_KEY, bundleOf(REQUEST_KEY to Result.BACKUP_STARTED))
isResultSet = true
dismissAllowingStateLoss()
},
onBackupLaterClick = {
@@ -51,6 +64,19 @@ class CreateBackupBottomSheet : ComposeBottomSheetDialogFragment() {
}
)
}
enum class Result {
BACKUP_STARTED,
BACKUP_DELAYED
}
override fun onDismiss(dialog: DialogInterface) {
if (!isResultSet) {
setFragmentResult(REQUEST_KEY, bundleOf(REQUEST_KEY to Result.BACKUP_DELAYED))
}
super.onDismiss(dialog)
}
}
@Composable

View File

@@ -187,6 +187,12 @@ class MessageBackupsFlowFragment : ComposeFragment(), InAppPaymentCheckoutDelega
return@LaunchedEffect
}
if (state.screen == MessageBackupsScreen.PROCESS_FREE) {
checkoutDelegate.setActivityResult(InAppPaymentProcessorAction.UPDATE_SUBSCRIPTION, InAppPaymentType.RECURRING_BACKUP)
viewModel.goToNextScreen()
return@LaunchedEffect
}
val routeScreen = MessageBackupsScreen.valueOf(route)
if (routeScreen.isAfter(state.screen)) {
navController.popBackStack()

View File

@@ -76,6 +76,7 @@ class MessageBackupsFlowViewModel : ViewModel() {
MessageBackupsScreen.CANCELLATION_DIALOG -> it.copy(screen = MessageBackupsScreen.PROCESS_CANCELLATION)
MessageBackupsScreen.PROCESS_PAYMENT -> it.copy(screen = MessageBackupsScreen.COMPLETED)
MessageBackupsScreen.PROCESS_CANCELLATION -> it.copy(screen = MessageBackupsScreen.COMPLETED)
MessageBackupsScreen.PROCESS_FREE -> it.copy(screen = MessageBackupsScreen.COMPLETED)
MessageBackupsScreen.COMPLETED -> error("Unsupported state transition from terminal state COMPLETED")
}
}
@@ -95,6 +96,7 @@ class MessageBackupsFlowViewModel : ViewModel() {
MessageBackupsScreen.CREATING_IN_APP_PAYMENT -> MessageBackupsScreen.TYPE_SELECTION
MessageBackupsScreen.PROCESS_PAYMENT -> MessageBackupsScreen.TYPE_SELECTION
MessageBackupsScreen.PROCESS_CANCELLATION -> MessageBackupsScreen.TYPE_SELECTION
MessageBackupsScreen.PROCESS_FREE -> MessageBackupsScreen.TYPE_SELECTION
MessageBackupsScreen.CANCELLATION_DIALOG -> MessageBackupsScreen.TYPE_SELECTION
MessageBackupsScreen.COMPLETED -> error("Unsupported state transition from terminal state COMPLETED")
}
@@ -170,8 +172,7 @@ class MessageBackupsFlowViewModel : ViewModel() {
SignalStore.backup.areBackupsEnabled = true
SignalStore.backup.backupTier = MessageBackupTier.FREE
// TODO [message-backups] -- Trigger backup now?
state.copy(screen = MessageBackupsScreen.COMPLETED)
state.copy(screen = MessageBackupsScreen.PROCESS_FREE)
}
}
MessageBackupTier.PAID -> state.copy(screen = MessageBackupsScreen.CHECKOUT_SHEET)

View File

@@ -15,6 +15,7 @@ enum class MessageBackupsScreen {
CREATING_IN_APP_PAYMENT,
PROCESS_PAYMENT,
PROCESS_CANCELLATION,
PROCESS_FREE,
COMPLETED;
fun isAfter(other: MessageBackupsScreen): Boolean = ordinal > other.ordinal

View File

@@ -55,8 +55,8 @@ class AppSettingsActivity : DSLSettingsActivity(), InAppPaymentComponent {
StartLocation.PROXY -> AppSettingsFragmentDirections.actionDirectToEditProxyFragment()
StartLocation.NOTIFICATIONS -> AppSettingsFragmentDirections.actionDirectToNotificationsSettingsFragment()
StartLocation.CHANGE_NUMBER -> AppSettingsFragmentDirections.actionDirectToChangeNumberFragment()
StartLocation.SUBSCRIPTIONS -> AppSettingsFragmentDirections.actionDirectToCheckout(InAppPaymentType.RECURRING_DONATION)
StartLocation.BOOST -> AppSettingsFragmentDirections.actionDirectToCheckout(InAppPaymentType.ONE_TIME_DONATION)
StartLocation.SUBSCRIPTIONS -> AppSettingsFragmentDirections.actionDirectToManageDonations().setDirectToCheckoutType(InAppPaymentType.RECURRING_DONATION)
StartLocation.BOOST -> AppSettingsFragmentDirections.actionDirectToManageDonations().setDirectToCheckoutType(InAppPaymentType.ONE_TIME_DONATION)
StartLocation.MANAGE_SUBSCRIPTIONS -> AppSettingsFragmentDirections.actionDirectToManageDonations()
StartLocation.NOTIFICATION_PROFILES -> AppSettingsFragmentDirections.actionDirectToNotificationProfiles()
StartLocation.CREATE_NOTIFICATION_PROFILE -> AppSettingsFragmentDirections.actionDirectToCreateNotificationProfiles()

View File

@@ -1,13 +1,15 @@
package org.thoughtcrime.securesms.components.settings.app.chats
import androidx.activity.result.ActivityResultLauncher
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.Navigation
import androidx.navigation.fragment.findNavController
import org.signal.donations.InAppPaymentType
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
import org.thoughtcrime.securesms.components.settings.app.subscription.donate.CheckoutFlowActivity
import org.thoughtcrime.securesms.components.settings.app.subscription.InAppPaymentCheckoutLauncher.createBackupsCheckoutLauncher
import org.thoughtcrime.securesms.components.settings.configure
import org.thoughtcrime.securesms.util.RemoteConfig
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
@@ -16,6 +18,7 @@ import org.thoughtcrime.securesms.util.navigation.safeNavigate
class ChatsSettingsFragment : DSLSettingsFragment(R.string.preferences_chats__chats) {
private lateinit var viewModel: ChatsSettingsViewModel
private lateinit var checkoutLauncher: ActivityResultLauncher<InAppPaymentType>
override fun onResume() {
super.onResume()
@@ -24,6 +27,10 @@ class ChatsSettingsFragment : DSLSettingsFragment(R.string.preferences_chats__ch
@Suppress("ReplaceGetOrSet")
override fun bindAdapter(adapter: MappingAdapter) {
checkoutLauncher = createBackupsCheckoutLauncher {
findNavController().safeNavigate(ChatsSettingsFragmentDirections.actionChatsSettingsFragmentToRemoteBackupsSettingsFragment().setBackupLaterSelected(it))
}
viewModel = ViewModelProvider(this).get(ChatsSettingsViewModel::class.java)
viewModel.state.observe(viewLifecycleOwner) {
@@ -92,7 +99,7 @@ class ChatsSettingsFragment : DSLSettingsFragment(R.string.preferences_chats__ch
if (state.canAccessRemoteBackupsSettings) {
Navigation.findNavController(requireView()).safeNavigate(R.id.action_chatsSettingsFragment_to_remoteBackupsSettingsFragment)
} else {
startActivity(CheckoutFlowActivity.createIntent(requireContext(), InAppPaymentType.RECURRING_BACKUP))
checkoutLauncher.launch(InAppPaymentType.RECURRING_BACKUP)
}
}
)

View File

@@ -7,6 +7,7 @@ package org.thoughtcrime.securesms.components.settings.app.chats.backups
import android.os.Bundle
import android.view.View
import androidx.activity.result.ActivityResultLauncher
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
@@ -44,7 +45,9 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.DialogProperties
import androidx.fragment.app.setFragmentResultListener
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
import kotlinx.collections.immutable.persistentListOf
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
@@ -65,7 +68,8 @@ import org.thoughtcrime.securesms.backup.v2.BackupFrequency
import org.thoughtcrime.securesms.backup.v2.BackupV2Event
import org.thoughtcrime.securesms.backup.v2.MessageBackupTier
import org.thoughtcrime.securesms.backup.v2.ui.subscription.MessageBackupsType
import org.thoughtcrime.securesms.components.settings.app.subscription.donate.CheckoutFlowActivity
import org.thoughtcrime.securesms.components.settings.app.chats.backups.type.BackupsTypeSettingsFragment
import org.thoughtcrime.securesms.components.settings.app.subscription.InAppPaymentCheckoutLauncher.createBackupsCheckoutLauncher
import org.thoughtcrime.securesms.compose.ComposeFragment
import org.thoughtcrime.securesms.conversation.v2.registerForLifecycle
import org.thoughtcrime.securesms.payments.FiatMoneyUtil
@@ -86,6 +90,10 @@ class RemoteBackupsSettingsFragment : ComposeFragment() {
RemoteBackupsSettingsViewModel()
}
private val args: RemoteBackupsSettingsFragmentArgs by navArgs()
private lateinit var checkoutLauncher: ActivityResultLauncher<InAppPaymentType>
@Composable
override fun FragmentContent() {
val state by viewModel.state.collectAsState()
@@ -111,7 +119,7 @@ class RemoteBackupsSettingsFragment : ComposeFragment() {
}
override fun onEnableBackupsClick() {
startActivity(CheckoutFlowActivity.createIntent(requireContext(), InAppPaymentType.RECURRING_BACKUP))
checkoutLauncher.launch(InAppPaymentType.RECURRING_BACKUP)
}
override fun onBackUpUsingCellularClick(canUseCellular: Boolean) {
@@ -163,6 +171,22 @@ class RemoteBackupsSettingsFragment : ComposeFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
EventBus.getDefault().registerForLifecycle(subscriber = this, lifecycleOwner = viewLifecycleOwner)
checkoutLauncher = createBackupsCheckoutLauncher { backUpLater ->
if (backUpLater) {
viewModel.requestSnackbar(RemoteBackupsSettingsState.Snackbar.BACKUP_WILL_BE_CREATED_OVERNIGHT)
}
}
setFragmentResultListener(BackupsTypeSettingsFragment.REQUEST_KEY) { _, bundle ->
val backUpLater = bundle.getBoolean(BackupsTypeSettingsFragment.REQUEST_KEY)
if (backUpLater) {
viewModel.requestSnackbar(RemoteBackupsSettingsState.Snackbar.BACKUP_WILL_BE_CREATED_OVERNIGHT)
}
}
if (savedInstanceState == null && args.backupLaterSelected) {
viewModel.requestSnackbar(RemoteBackupsSettingsState.Snackbar.BACKUP_WILL_BE_CREATED_OVERNIGHT)
}
}
override fun onResume() {
@@ -346,6 +370,7 @@ private fun RemoteBackupsSettingsContent(
RemoteBackupsSettingsState.Snackbar.BACKUP_TYPE_CHANGED_AND_SUBSCRIPTION_CANCELLED -> R.string.RemoteBackupsSettingsFragment__backup_type_changed_and_subcription_deleted
RemoteBackupsSettingsState.Snackbar.SUBSCRIPTION_CANCELLED -> R.string.RemoteBackupsSettingsFragment__subscription_cancelled
RemoteBackupsSettingsState.Snackbar.DOWNLOAD_COMPLETE -> R.string.RemoteBackupsSettingsFragment__download_complete
RemoteBackupsSettingsState.Snackbar.BACKUP_WILL_BE_CREATED_OVERNIGHT -> R.string.RemoteBackupsSettingsFragment__backup_will_be_created_overnight
}
}
@@ -359,9 +384,9 @@ private fun RemoteBackupsSettingsContent(
else -> {
snackbarHostState.showSnackbar(snackbarText)
contentCallbacks.onSnackbarDismissed()
}
}
contentCallbacks.onSnackbarDismissed()
}
}

View File

@@ -32,6 +32,7 @@ data class RemoteBackupsSettingsState(
BACKUP_DELETED_AND_TURNED_OFF,
BACKUP_TYPE_CHANGED_AND_SUBSCRIPTION_CANCELLED,
SUBSCRIPTION_CANCELLED,
DOWNLOAD_COMPLETE
DOWNLOAD_COMPLETE,
BACKUP_WILL_BE_CREATED_OVERNIGHT
}
}

View File

@@ -5,6 +5,9 @@
package org.thoughtcrime.securesms.components.settings.app.chats.backups.type
import android.os.Bundle
import android.view.View
import androidx.activity.result.ActivityResultLauncher
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
@@ -18,6 +21,8 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.core.os.bundleOf
import androidx.fragment.app.setFragmentResult
import androidx.navigation.fragment.findNavController
import kotlinx.collections.immutable.persistentListOf
import org.signal.core.ui.Previews
@@ -30,7 +35,7 @@ import org.signal.donations.PaymentSourceType
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.backup.v2.MessageBackupTier
import org.thoughtcrime.securesms.backup.v2.ui.subscription.MessageBackupsType
import org.thoughtcrime.securesms.components.settings.app.subscription.donate.CheckoutFlowActivity
import org.thoughtcrime.securesms.components.settings.app.subscription.InAppPaymentCheckoutLauncher.createBackupsCheckoutLauncher
import org.thoughtcrime.securesms.compose.ComposeFragment
import org.thoughtcrime.securesms.payments.FiatMoneyUtil
import org.thoughtcrime.securesms.util.DateUtils
@@ -45,10 +50,24 @@ import java.util.Locale
*/
class BackupsTypeSettingsFragment : ComposeFragment() {
companion object {
const val REQUEST_KEY = "BackupsTypeSettingsFragment__result"
}
private val viewModel: BackupsTypeSettingsViewModel by viewModel {
BackupsTypeSettingsViewModel()
}
private lateinit var checkoutLauncher: ActivityResultLauncher<InAppPaymentType>
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
checkoutLauncher = createBackupsCheckoutLauncher { backUpLater ->
findNavController().popBackStack()
setFragmentResult(REQUEST_KEY, bundleOf(REQUEST_KEY to backUpLater))
}
}
@Composable
override fun FragmentContent() {
val contentCallbacks = remember {
@@ -73,7 +92,7 @@ class BackupsTypeSettingsFragment : ComposeFragment() {
}
override fun onChangeOrCancelSubscriptionClick() {
startActivity(CheckoutFlowActivity.createIntent(requireContext(), InAppPaymentType.RECURRING_BACKUP))
checkoutLauncher.launch(InAppPaymentType.RECURRING_BACKUP)
}
}

View File

@@ -5,6 +5,9 @@
package org.thoughtcrime.securesms.components.settings.app.storage
import android.os.Bundle
import android.view.View
import androidx.activity.result.ActivityResultLauncher
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
@@ -35,7 +38,7 @@ import org.thoughtcrime.securesms.backup.v2.ui.BackupsIconColors
import org.thoughtcrime.securesms.backup.v2.ui.subscription.MessageBackupsType
import org.thoughtcrime.securesms.backup.v2.ui.subscription.MessageBackupsTypeBlock
import org.thoughtcrime.securesms.backup.v2.ui.subscription.testBackupTypes
import org.thoughtcrime.securesms.components.settings.app.subscription.donate.CheckoutFlowActivity
import org.thoughtcrime.securesms.components.settings.app.subscription.InAppPaymentCheckoutLauncher.createBackupsCheckoutLauncher
import org.thoughtcrime.securesms.compose.ComposeBottomSheetDialogFragment
/**
@@ -47,13 +50,20 @@ class UpgradeToEnableOptimizedStorageSheet : ComposeBottomSheetDialogFragment()
private val viewModel: UpgradeToEnableOptimizedStorageViewModel by viewModels()
private lateinit var checkoutLauncher: ActivityResultLauncher<InAppPaymentType>
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
checkoutLauncher = createBackupsCheckoutLauncher()
}
@Composable
override fun SheetContent() {
val type by viewModel.messageBackupsType
UpgradeToEnableOptimizedStorageSheetContent(
messageBackupsType = type,
onUpgradeNowClick = {
startActivity(CheckoutFlowActivity.createIntent(requireContext(), InAppPaymentType.RECURRING_BACKUP))
checkoutLauncher.launch(InAppPaymentType.RECURRING_BACKUP)
dismissAllowingStateLoss()
},
onCancelClick = {

View File

@@ -0,0 +1,39 @@
/*
* Copyright 2024 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.thoughtcrime.securesms.components.settings.app.subscription
import androidx.activity.result.ActivityResultLauncher
import androidx.fragment.app.Fragment
import org.signal.core.util.getSerializableCompat
import org.signal.donations.InAppPaymentType
import org.thoughtcrime.securesms.backup.v2.ui.CreateBackupBottomSheet
import org.thoughtcrime.securesms.components.settings.app.subscription.donate.CheckoutFlowActivity
import org.thoughtcrime.securesms.components.settings.app.subscription.donate.InAppPaymentProcessorAction
import org.thoughtcrime.securesms.util.BottomSheetUtil
object InAppPaymentCheckoutLauncher {
fun Fragment.createBackupsCheckoutLauncher(
onCreateBackupBottomSheetResultListener: OnCreateBackupBottomSheetResultListener = {} as OnCreateBackupBottomSheetResultListener
): ActivityResultLauncher<InAppPaymentType> {
childFragmentManager.setFragmentResultListener(CreateBackupBottomSheet.REQUEST_KEY, viewLifecycleOwner) { requestKey, bundle ->
if (requestKey == CreateBackupBottomSheet.REQUEST_KEY) {
val result = bundle.getSerializableCompat(CreateBackupBottomSheet.REQUEST_KEY, CreateBackupBottomSheet.Result::class.java)
onCreateBackupBottomSheetResultListener.onCreateBackupBottomSheetResult(result != CreateBackupBottomSheet.Result.BACKUP_STARTED)
}
}
return registerForActivityResult(CheckoutFlowActivity.Contract()) { result ->
if (result?.action == InAppPaymentProcessorAction.PROCESS_NEW_IN_APP_PAYMENT || result?.action == InAppPaymentProcessorAction.UPDATE_SUBSCRIPTION) {
CreateBackupBottomSheet().show(childFragmentManager, BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG)
}
}
}
fun interface OnCreateBackupBottomSheetResultListener {
fun onCreateBackupBottomSheetResult(backUpLater: Boolean)
}
}

View File

@@ -238,7 +238,7 @@ object RecurringInAppPaymentRepository {
it.state == InAppPaymentTable.State.END
}.take(1).map {
if (it.data.error != null) {
Log.d(TAG, "Failure during redemption chain.", true)
Log.d(TAG, "Failure during redemption chain: ${it.data.error}", true)
throw DonationError.genericBadgeRedemptionFailure(errorSource)
}
it

View File

@@ -7,10 +7,14 @@ package org.thoughtcrime.securesms.components.settings.app.subscription.donate
import android.content.Context
import android.content.Intent
import android.os.Parcelable
import androidx.activity.result.contract.ActivityResultContract
import androidx.fragment.app.Fragment
import androidx.navigation.navArgs
import io.reactivex.rxjava3.subjects.PublishSubject
import io.reactivex.rxjava3.subjects.Subject
import kotlinx.parcelize.Parcelize
import org.signal.core.util.getParcelableExtraCompat
import org.signal.core.util.getSerializableCompat
import org.signal.donations.InAppPaymentType
import org.thoughtcrime.securesms.components.FragmentWrapperActivity
import org.thoughtcrime.securesms.components.settings.app.subscription.InAppPaymentComponent
@@ -22,20 +26,23 @@ import org.thoughtcrime.securesms.components.settings.app.subscription.StripeRep
class CheckoutFlowActivity : FragmentWrapperActivity(), InAppPaymentComponent {
companion object {
private const val ARG_IN_APP_PAYMENT_TYPE = "in_app_payment_type"
const val RESULT_DATA = "result_data"
fun createIntent(context: Context, inAppPaymentType: InAppPaymentType): Intent {
return Intent(context, CheckoutFlowActivity::class.java).putExtras(
CheckoutFlowActivityArgs.Builder(inAppPaymentType).build().toBundle()
)
return Contract().createIntent(context, inAppPaymentType)
}
}
override val stripeRepository: StripeRepository by lazy { StripeRepository(this) }
override val googlePayResultPublisher: Subject<InAppPaymentComponent.GooglePayResult> = PublishSubject.create()
private val args by navArgs<CheckoutFlowActivityArgs>()
private val inAppPaymentType: InAppPaymentType by lazy {
intent.extras!!.getSerializableCompat(ARG_IN_APP_PAYMENT_TYPE, InAppPaymentType::class.java)!!
}
override fun getFragment(): Fragment {
return CheckoutNavHostFragment.create(args.inAppPaymentType)
return CheckoutNavHostFragment.create(inAppPaymentType)
}
@Suppress("DEPRECATION")
@@ -43,4 +50,21 @@ class CheckoutFlowActivity : FragmentWrapperActivity(), InAppPaymentComponent {
super.onActivityResult(requestCode, resultCode, data)
googlePayResultPublisher.onNext(InAppPaymentComponent.GooglePayResult(requestCode, resultCode, data))
}
class Contract : ActivityResultContract<InAppPaymentType, Result?>() {
override fun createIntent(context: Context, input: InAppPaymentType): Intent {
return Intent(context, CheckoutFlowActivity::class.java).putExtra(ARG_IN_APP_PAYMENT_TYPE, input)
}
override fun parseResult(resultCode: Int, intent: Intent?): Result? {
return intent?.getParcelableExtraCompat(RESULT_DATA, Result::class.java)
}
}
@Parcelize
data class Result(
val action: InAppPaymentProcessorAction,
val inAppPaymentType: InAppPaymentType
) : Parcelable
}

View File

@@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.components.settings.app.subscription.donate
import android.app.Activity
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import androidx.fragment.app.Fragment
import androidx.fragment.app.setFragmentResultListener
import androidx.fragment.app.viewModels
@@ -114,6 +115,10 @@ class InAppPaymentCheckoutDelegate(
}
}
fun setActivityResult(action: InAppPaymentProcessorAction, inAppPaymentType: InAppPaymentType) {
fragment.requireActivity().setResult(Activity.RESULT_OK, Intent().putExtra(CheckoutFlowActivity.RESULT_DATA, CheckoutFlowActivity.Result(action, inAppPaymentType)))
}
private fun handleDonationProcessorActionResult(result: InAppPaymentProcessorActionResult) {
when (result.status) {
InAppPaymentProcessorActionResult.Status.SUCCESS -> handleSuccessfulDonationProcessorActionResult(result)
@@ -124,10 +129,11 @@ class InAppPaymentCheckoutDelegate(
}
private fun handleSuccessfulDonationProcessorActionResult(result: InAppPaymentProcessorActionResult) {
setActivityResult(result.action, result.inAppPaymentType)
if (result.action == InAppPaymentProcessorAction.CANCEL_SUBSCRIPTION) {
callback.onSubscriptionCancelled(result.inAppPaymentType)
} else {
fragment.requireActivity().setResult(Activity.RESULT_OK)
callback.onPaymentComplete(result.inAppPayment!!)
}
}

View File

@@ -3,10 +3,12 @@ package org.thoughtcrime.securesms.components.settings.app.subscription.manage
import android.os.Bundle
import android.text.SpannableStringBuilder
import android.view.View
import androidx.activity.result.ActivityResultLauncher
import androidx.appcompat.widget.Toolbar
import androidx.core.content.ContextCompat
import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.signal.core.util.dp
import org.signal.core.util.money.FiatMoney
@@ -21,6 +23,7 @@ import org.thoughtcrime.securesms.components.settings.DSLSettingsText
import org.thoughtcrime.securesms.components.settings.app.AppSettingsActivity
import org.thoughtcrime.securesms.components.settings.app.subscription.DonationSerializationHelper.toFiatMoney
import org.thoughtcrime.securesms.components.settings.app.subscription.completed.InAppPaymentsBottomSheetDelegate
import org.thoughtcrime.securesms.components.settings.app.subscription.donate.CheckoutFlowActivity
import org.thoughtcrime.securesms.components.settings.app.subscription.models.NetworkFailure
import org.thoughtcrime.securesms.components.settings.configure
import org.thoughtcrime.securesms.components.settings.models.IndeterminateLoadingCircle
@@ -54,6 +57,9 @@ class ManageDonationsFragment :
const val DONATE_TROUBLESHOOTING_URL = "https://support.signal.org/hc/articles/360031949872#fix"
}
private val args: ManageDonationsFragmentArgs by navArgs()
private lateinit var launcher: ActivityResultLauncher<InAppPaymentType>
private val supportTechSummary: CharSequence by lazy {
SpannableStringBuilder(SpanUtil.color(ContextCompat.getColor(requireContext(), R.color.signal_colorOnSurfaceVariant), requireContext().getString(R.string.DonateToSignalFragment__private_messaging)))
.append(" ")
@@ -69,6 +75,13 @@ class ManageDonationsFragment :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
viewLifecycleOwner.lifecycle.addObserver(InAppPaymentsBottomSheetDelegate(childFragmentManager, viewLifecycleOwner))
super.onViewCreated(view, savedInstanceState)
val contract = CheckoutFlowActivity.Contract()
launcher = registerForActivityResult(contract) { }
if (savedInstanceState == null && args.directToCheckoutType != InAppPaymentType.UNKNOWN) {
launcher.launch(args.directToCheckoutType)
}
}
override fun onResume() {
@@ -159,7 +172,7 @@ class ManageDonationsFragment :
primaryWrappedButton(
text = DSLSettingsText.from(R.string.ManageDonationsFragment__donate_to_signal),
onClick = {
findNavController().safeNavigate(ManageDonationsFragmentDirections.actionManageDonationsFragmentToDonateToSignalFragment(InAppPaymentType.ONE_TIME_DONATION))
launcher.launch(InAppPaymentType.ONE_TIME_DONATION)
}
)
@@ -269,7 +282,7 @@ class ManageDonationsFragment :
subscriberRequiresCancel = state.subscriberRequiresCancel,
onRowClick = {
if (it != ManageDonationsState.RedemptionState.IN_PROGRESS) {
findNavController().safeNavigate(ManageDonationsFragmentDirections.actionManageDonationsFragmentToDonateToSignalFragment(InAppPaymentType.RECURRING_DONATION))
launcher.launch(InAppPaymentType.RECURRING_DONATION)
}
},
onPendingClick = {
@@ -337,7 +350,7 @@ class ManageDonationsFragment :
title = DSLSettingsText.from(R.string.ManageDonationsFragment__donate_for_a_friend),
icon = DSLSettingsIcon.from(R.drawable.symbol_gift_24),
onClick = {
findNavController().safeNavigate(ManageDonationsFragmentDirections.actionManageDonationsFragmentToDonateToSignalFragment(InAppPaymentType.ONE_TIME_GIFT))
launcher.launch(InAppPaymentType.ONE_TIME_GIFT)
}
)
}
@@ -437,6 +450,6 @@ class ManageDonationsFragment :
}
override fun onMakeAMonthlyDonation() {
findNavController().safeNavigate(ManageDonationsFragmentDirections.actionManageDonationsFragmentToDonateToSignalFragment(InAppPaymentType.RECURRING_DONATION))
launcher.launch(InAppPaymentType.ONE_TIME_DONATION)
}
}

View File

@@ -382,6 +382,10 @@ class ConversationFragment :
MessageRequestRepository(requireContext())
}
private val checkoutLauncher by lazy {
registerForActivityResult(CheckoutFlowActivity.Contract()) {}
}
private val disposables = LifecycleDisposable()
private val binding by ViewBinderDelegate(V2ConversationFragmentBinding::bind) { _binding ->
_binding.conversationInputPanel.embeddedTextEditor.apply {
@@ -2959,7 +2963,7 @@ class ConversationFragment :
override fun onCallToAction(action: String) {
if ("gift_badge" == action) {
startActivity(CheckoutFlowActivity.createIntent(requireContext(), InAppPaymentType.ONE_TIME_GIFT))
checkoutLauncher.launch(InAppPaymentType.ONE_TIME_GIFT)
} else if ("username_edit" == action) {
startActivity(EditProfileActivity.getIntentForUsernameEdit(requireContext()))
}

View File

@@ -532,17 +532,13 @@
app:popEnterAnim="@anim/fragment_close_enter"
app:popExitAnim="@anim/fragment_close_exit"
app:popUpTo="@id/app_settings"
app:popUpToInclusive="true" />
app:popUpToInclusive="true">
<action
android:id="@+id/action_direct_to_checkout"
app:destination="@id/checkoutFlowActivity"
app:enterAnim="@anim/fragment_open_enter"
app:exitAnim="@anim/fragment_open_exit"
app:popEnterAnim="@anim/fragment_close_enter"
app:popExitAnim="@anim/fragment_close_exit"
app:popUpTo="@id/app_settings"
app:popUpToInclusive="true" />
<argument
android:name="direct_to_checkout_type"
android:defaultValue="UNKNOWN"
app:argType="org.signal.donations.InAppPaymentType" />
</action>
<action
android:id="@+id/action_direct_to_notificationProfiles"
@@ -741,13 +737,10 @@
<action
android:id="@+id/action_manageDonationsFragment_to_subscribeLearnMoreBottomSheetDialog"
app:destination="@id/subscribeLearnMoreBottomSheetDialog" />
<action
android:id="@+id/action_manageDonationsFragment_to_donateToSignalFragment"
app:destination="@id/checkoutFlowActivity"
app:enterAnim="@anim/fragment_open_enter"
app:exitAnim="@anim/fragment_open_exit"
app:popEnterAnim="@anim/fragment_close_enter"
app:popExitAnim="@anim/fragment_close_exit" />
<argument
android:name="direct_to_checkout_type"
android:defaultValue="UNKNOWN"
app:argType="org.signal.donations.InAppPaymentType" />
</fragment>
<fragment
@@ -985,6 +978,11 @@
app:exitAnim="@anim/fragment_open_exit"
app:popEnterAnim="@anim/fragment_close_enter"
app:popExitAnim="@anim/fragment_close_exit" />
<argument
android:name="backup_later_selected"
app:argType="boolean"
android:defaultValue="false" />
</fragment>
<fragment
@@ -1002,19 +1000,9 @@
<fragment
android:id="@+id/remoteBackupsPaymentHistoryFragment"
android:name="org.thoughtcrime.securesms.components.settings.app.chats.backups.history.RemoteBackupsPaymentHistoryFragment"/>
android:name="org.thoughtcrime.securesms.components.settings.app.chats.backups.history.RemoteBackupsPaymentHistoryFragment" />
<include app:graph="@navigation/username_link_settings" />
<include app:graph="@navigation/story_privacy_settings" />
<activity
android:id="@+id/checkoutFlowActivity"
android:name="org.thoughtcrime.securesms.components.settings.app.subscription.donate.CheckoutFlowActivity"
android:label="checkout_flow_activity">
<argument
android:name="in_app_payment_type"
app:argType="org.signal.donations.InAppPaymentType" />
</activity>
</navigation>

View File

@@ -532,17 +532,13 @@
app:popEnterAnim="@anim/fragment_close_enter"
app:popExitAnim="@anim/fragment_close_exit"
app:popUpTo="@id/app_settings"
app:popUpToInclusive="true" />
app:popUpToInclusive="true">
<action
android:id="@+id/action_direct_to_checkout"
app:destination="@id/checkoutFlowActivity"
app:enterAnim="@anim/fragment_open_enter"
app:exitAnim="@anim/fragment_open_exit"
app:popEnterAnim="@anim/fragment_close_enter"
app:popExitAnim="@anim/fragment_close_exit"
app:popUpTo="@id/app_settings"
app:popUpToInclusive="true" />
<argument
android:name="direct_to_checkout_type"
android:defaultValue="UNKNOWN"
app:argType="org.signal.donations.InAppPaymentType" />
</action>
<action
android:id="@+id/action_direct_to_notificationProfiles"
@@ -741,13 +737,10 @@
<action
android:id="@+id/action_manageDonationsFragment_to_subscribeLearnMoreBottomSheetDialog"
app:destination="@id/subscribeLearnMoreBottomSheetDialog" />
<action
android:id="@+id/action_manageDonationsFragment_to_donateToSignalFragment"
app:destination="@id/checkoutFlowActivity"
app:enterAnim="@anim/fragment_open_enter"
app:exitAnim="@anim/fragment_open_exit"
app:popEnterAnim="@anim/fragment_close_enter"
app:popExitAnim="@anim/fragment_close_exit" />
<argument
android:name="direct_to_checkout_type"
android:defaultValue="UNKNOWN"
app:argType="org.signal.donations.InAppPaymentType" />
</fragment>
<fragment
@@ -985,12 +978,16 @@
app:exitAnim="@anim/fragment_open_exit"
app:popEnterAnim="@anim/fragment_close_enter"
app:popExitAnim="@anim/fragment_close_exit" />
<argument
android:name="backup_later_selected"
app:argType="boolean"
android:defaultValue="false" />
</fragment>
<fragment
android:id="@+id/remoteBackupsPaymentHistoryFragment"
android:name="org.thoughtcrime.securesms.components.settings.app.chats.backups.history.RemoteBackupsPaymentHistoryFragment">
</fragment>
android:name="org.thoughtcrime.securesms.components.settings.app.chats.backups.history.RemoteBackupsPaymentHistoryFragment"></fragment>
<fragment
android:id="@+id/backupsTypeSettingsFragment"
@@ -1008,14 +1005,4 @@
<include app:graph="@navigation/username_link_settings" />
<include app:graph="@navigation/story_privacy_settings" />
<activity
android:id="@+id/checkoutFlowActivity"
android:name="org.thoughtcrime.securesms.components.settings.app.subscription.donate.CheckoutFlowActivity"
android:label="checkout_flow_activity">
<argument
android:name="in_app_payment_type"
app:argType="org.signal.donations.InAppPaymentType" />
</activity>
</navigation>

View File

@@ -7311,6 +7311,8 @@
<string name="RemoteBackupsSettingsFragment__subscription_cancelled">Subscription cancelled</string>
<!-- Snackbar text displayed when backup is successfully downloaded -->
<string name="RemoteBackupsSettingsFragment__download_complete">Download complete</string>
<!-- Snackbar text displayed when backup will be created overnight -->
<string name="RemoteBackupsSettingsFragment__backup_will_be_created_overnight">Backup will be created overnight.</string>
<!-- Title text in row detailing selected backup type -->
<string name="RemoteBackupsSettingsFragment__backup_type">Backup type</string>
<!-- Subtitle text in row detailing selected backup type displayed when backups are disabled -->