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 fcda4c13f8..41f16bed26 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 d559f1b8d7..1f4747fc85 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 6dc16fb348..a58d4aeeaf 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 ebdb99b8e8..e12464b226 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 0000000000..93af10dbd1 --- /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 ef6c1b82e9..df8eaf721f 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 9dc8f7361c..2bdb8cc2a7 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 b35d250c5e..c43f5e3e1a 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 8a0e821680..2e7d54e5f9 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