diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/manage/ManageDonationsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/manage/ManageDonationsFragment.kt index fcda4c13f..41f16bed2 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/manage/ManageDonationsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/manage/ManageDonationsFragment.kt @@ -98,31 +98,31 @@ class ManageDonationsFragment : DSLSettingsFragment(), ExpiredGiftSheet.Callback if (activeSubscription != null) { val subscription: Subscription? = state.availableSubscriptions.firstOrNull { activeSubscription.level == it.level } if (subscription != null) { - presentSubscriptionSettings(state.hasReceipts, activeSubscription, subscription, state.getRedemptionState()) + presentSubscriptionSettings(activeSubscription, subscription, state.getRedemptionState()) } else { customPref(IndeterminateLoadingCircle) } } else { - presentNoSubscriptionSettings(state.hasReceipts) + presentNoSubscriptionSettings() } } else if (state.transactionState == ManageDonationsState.TransactionState.NetworkFailure) { - presentNetworkFailureSettings(state.hasReceipts, state.getRedemptionState()) + presentNetworkFailureSettings(state.getRedemptionState()) } else { customPref(IndeterminateLoadingCircle) } } } - private fun DSLConfiguration.presentNetworkFailureSettings(hasReceipts: Boolean, redemptionState: ManageDonationsState.SubscriptionRedemptionState) { + private fun DSLConfiguration.presentNetworkFailureSettings(redemptionState: ManageDonationsState.SubscriptionRedemptionState) { if (SignalStore.donationsValues().isLikelyASustainer()) { - presentSubscriptionSettingsWithNetworkError(hasReceipts, redemptionState) + presentSubscriptionSettingsWithNetworkError(redemptionState) } else { - presentNoSubscriptionSettings(hasReceipts) + presentNoSubscriptionSettings() } } - private fun DSLConfiguration.presentSubscriptionSettingsWithNetworkError(hasReceipts: Boolean, redemptionState: ManageDonationsState.SubscriptionRedemptionState) { - presentSubscriptionSettingsWithState(hasReceipts, redemptionState) { + private fun DSLConfiguration.presentSubscriptionSettingsWithNetworkError(redemptionState: ManageDonationsState.SubscriptionRedemptionState) { + presentSubscriptionSettingsWithState(redemptionState) { customPref( NetworkFailure.Model( onRetryClick = { @@ -134,12 +134,11 @@ class ManageDonationsFragment : DSLSettingsFragment(), ExpiredGiftSheet.Callback } private fun DSLConfiguration.presentSubscriptionSettings( - hasReceipts: Boolean, activeSubscription: ActiveSubscription.Subscription, subscription: Subscription, redemptionState: ManageDonationsState.SubscriptionRedemptionState ) { - presentSubscriptionSettingsWithState(hasReceipts, redemptionState) { + presentSubscriptionSettingsWithState(redemptionState) { val activeCurrency = Currency.getInstance(activeSubscription.currency) val activeAmount = activeSubscription.amount.movePointLeft(activeCurrency.defaultFractionDigits) @@ -160,7 +159,6 @@ class ManageDonationsFragment : DSLSettingsFragment(), ExpiredGiftSheet.Callback } private fun DSLConfiguration.presentSubscriptionSettingsWithState( - hasReceipts: Boolean, redemptionState: ManageDonationsState.SubscriptionRedemptionState, subscriptionBlock: DSLConfiguration.() -> Unit ) { @@ -198,9 +196,7 @@ class ManageDonationsFragment : DSLSettingsFragment(), ExpiredGiftSheet.Callback sectionHeaderPref(R.string.ManageDonationsFragment__more) - if (hasReceipts) { - presentDonationReceipts() - } + presentDonationReceipts() externalLinkPref( title = DSLSettingsText.from(R.string.ManageDonationsFragment__subscription_faq), @@ -209,7 +205,7 @@ class ManageDonationsFragment : DSLSettingsFragment(), ExpiredGiftSheet.Callback ) } - private fun DSLConfiguration.presentNoSubscriptionSettings(hasReceipts: Boolean) { + private fun DSLConfiguration.presentNoSubscriptionSettings() { space(DimensionUnit.DP.toPixels(16f).toInt()) noPadTextPref( @@ -227,11 +223,9 @@ class ManageDonationsFragment : DSLSettingsFragment(), ExpiredGiftSheet.Callback presentOtherWaysToGive() - if (hasReceipts) { - sectionHeaderPref(R.string.ManageDonationsFragment__receipts) + sectionHeaderPref(R.string.ManageDonationsFragment__receipts) - presentDonationReceipts() - } + presentDonationReceipts() } private fun DSLConfiguration.presentOtherWaysToGive() { diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/manage/ManageDonationsState.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/manage/ManageDonationsState.kt index d559f1b8d..1f4747fc8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/manage/ManageDonationsState.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/manage/ManageDonationsState.kt @@ -8,7 +8,6 @@ data class ManageDonationsState( val featuredBadge: Badge? = null, val transactionState: TransactionState = TransactionState.Init, val availableSubscriptions: List = emptyList(), - val hasReceipts: Boolean = false, private val subscriptionRedemptionState: SubscriptionRedemptionState = SubscriptionRedemptionState.NONE ) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/manage/ManageDonationsViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/manage/ManageDonationsViewModel.kt index 6dc16fb34..a58d4aeea 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/manage/ManageDonationsViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/manage/ManageDonationsViewModel.kt @@ -9,10 +9,8 @@ import io.reactivex.rxjava3.disposables.CompositeDisposable import io.reactivex.rxjava3.disposables.Disposable import io.reactivex.rxjava3.kotlin.plusAssign import io.reactivex.rxjava3.kotlin.subscribeBy -import io.reactivex.rxjava3.schedulers.Schedulers import org.signal.core.util.logging.Log import org.thoughtcrime.securesms.components.settings.app.subscription.SubscriptionsRepository -import org.thoughtcrime.securesms.database.SignalDatabase import org.thoughtcrime.securesms.jobmanager.JobTracker import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.subscription.LevelUpdate @@ -107,14 +105,6 @@ class ManageDonationsViewModel( Log.w(TAG, "Error retrieving subscriptions data", it) } ) - - disposables += Single.fromCallable { SignalDatabase.donationReceipts.hasReceipts() } - .subscribeOn(Schedulers.io()) - .subscribe { hasReceipts -> - store.update { - it.copy(hasReceipts = hasReceipts) - } - } } class Factory( diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/receipts/list/DonationReceiptListPageFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/receipts/list/DonationReceiptListPageFragment.kt index ebdb99b8e..e12464b22 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/receipts/list/DonationReceiptListPageFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/receipts/list/DonationReceiptListPageFragment.kt @@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.components.settings.app.subscription.receipts import android.os.Bundle import android.view.View +import androidx.constraintlayout.widget.Group import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController @@ -14,6 +15,7 @@ import org.thoughtcrime.securesms.database.model.DonationReceiptRecord import org.thoughtcrime.securesms.util.StickyHeaderDecoration import org.thoughtcrime.securesms.util.livedata.LiveDataUtil import org.thoughtcrime.securesms.util.navigation.safeNavigate +import org.thoughtcrime.securesms.util.visible class DonationReceiptListPageFragment : Fragment(R.layout.donation_receipt_list_page_fragment) { @@ -31,6 +33,8 @@ class DonationReceiptListPageFragment : Fragment(R.layout.donation_receipt_list_ private val type: DonationReceiptRecord.Type? get() = requireArguments().getString(ARG_TYPE)?.let { DonationReceiptRecord.Type.fromCode(it) } + private lateinit var emptyStateGroup: Group + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { val adapter = DonationReceiptListAdapter { model -> findNavController().safeNavigate(DonationReceiptListFragmentDirections.actionDonationReceiptListFragmentToDonationReceiptDetailFragment(model.record.id)) @@ -41,22 +45,29 @@ class DonationReceiptListPageFragment : Fragment(R.layout.donation_receipt_list_ addItemDecoration(StickyHeaderDecoration(adapter, false, true, 0)) } + emptyStateGroup = view.findViewById(R.id.empty_state) + LiveDataUtil.combineLatest( viewModel.state, sharedViewModel.state - ) { records, badges -> - records.map { DonationReceiptListItem.Model(it, getBadgeForRecord(it, badges)) } - }.observe(viewLifecycleOwner) { records -> - adapter.submitList( - records + - TextPreference( - title = null, - summary = DSLSettingsText.from( - R.string.DonationReceiptListFragment__if_you_have, - DSLSettingsText.TextAppearanceModifier(R.style.TextAppearance_Signal_Subtitle) + ) { state, badges -> + state.isLoaded to state.records.map { DonationReceiptListItem.Model(it, getBadgeForRecord(it, badges)) } + }.observe(viewLifecycleOwner) { (isLoaded, records) -> + if (records.isNotEmpty()) { + emptyStateGroup.visible = false + adapter.submitList( + records + + TextPreference( + title = null, + summary = DSLSettingsText.from( + R.string.DonationReceiptListFragment__if_you_have, + DSLSettingsText.TextAppearanceModifier(R.style.TextAppearance_Signal_Subtitle) + ) ) - ) - ) + ) + } else { + emptyStateGroup.visible = isLoaded + } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/receipts/list/DonationReceiptListPageState.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/receipts/list/DonationReceiptListPageState.kt new file mode 100644 index 000000000..93af10dbd --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/receipts/list/DonationReceiptListPageState.kt @@ -0,0 +1,8 @@ +package org.thoughtcrime.securesms.components.settings.app.subscription.receipts.list + +import org.thoughtcrime.securesms.database.model.DonationReceiptRecord + +data class DonationReceiptListPageState( + val records: List = emptyList(), + val isLoaded: Boolean = false +) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/receipts/list/DonationReceiptListPageViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/receipts/list/DonationReceiptListPageViewModel.kt index ef6c1b82e..df8eaf721 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/receipts/list/DonationReceiptListPageViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/receipts/list/DonationReceiptListPageViewModel.kt @@ -1,24 +1,29 @@ package org.thoughtcrime.securesms.components.settings.app.subscription.receipts.list import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import io.reactivex.rxjava3.disposables.CompositeDisposable import io.reactivex.rxjava3.kotlin.plusAssign import org.thoughtcrime.securesms.database.model.DonationReceiptRecord +import org.thoughtcrime.securesms.util.livedata.Store class DonationReceiptListPageViewModel(type: DonationReceiptRecord.Type?, repository: DonationReceiptListPageRepository) : ViewModel() { private val disposables = CompositeDisposable() - private val internalState = MutableLiveData>() + private val store = Store(DonationReceiptListPageState()) - val state: LiveData> = internalState + val state: LiveData = store.stateLiveData init { disposables += repository.getRecords(type) .subscribe { records -> - internalState.postValue(records) + store.update { + it.copy( + records = records, + isLoaded = true + ) + } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/DonationReceiptDatabase.kt b/app/src/main/java/org/thoughtcrime/securesms/database/DonationReceiptDatabase.kt index 9dc8f7361..2bdb8cc2a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/DonationReceiptDatabase.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/DonationReceiptDatabase.kt @@ -6,7 +6,6 @@ import androidx.core.content.contentValuesOf import org.signal.core.util.CursorUtil import org.signal.core.util.SqlUtil import org.signal.core.util.money.FiatMoney -import org.signal.core.util.select import org.thoughtcrime.securesms.database.model.DonationReceiptRecord import java.math.BigDecimal import java.util.Currency @@ -40,15 +39,6 @@ class DonationReceiptDatabase(context: Context, databaseHelper: SignalDatabase) ) } - fun hasReceipts(): Boolean { - return readableDatabase.select("1") - .from(TABLE_NAME) - .where("") - .limit(1) - .run() - .use { it.moveToFirst() } - } - fun addReceipt(record: DonationReceiptRecord) { require(record.id == -1L) diff --git a/app/src/main/res/layout/donation_receipt_list_page_fragment.xml b/app/src/main/res/layout/donation_receipt_list_page_fragment.xml index b35d250c5..c43f5e3e1 100644 --- a/app/src/main/res/layout/donation_receipt_list_page_fragment.xml +++ b/app/src/main/res/layout/donation_receipt_list_page_fragment.xml @@ -1,7 +1,50 @@ - \ No newline at end of file + android:layout_height="match_parent"> + + + + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8a0e82168..2e7d54e5f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -4473,6 +4473,8 @@ Thank you for supporting Signal. Your contribution helps fuel the mission of developing open source privacy technology that protects free expression and enables secure global communication for millions around the world. If you’re a resident of the United States, please retain this receipt for your tax records. Signal Technology Foundation is a tax–exempt nonprofit organization in the United States under section 501c3 of the Internal Revenue Code. Our Federal Tax ID is 82–4506840. %1$s - %2$s + + No receipts