kopia lustrzana https://github.com/ryukoposting/Signal-Android
Always display donation receipts page.
rodzic
eaf36be9f6
commit
68ba3433a3
|
@ -98,31 +98,31 @@ class ManageDonationsFragment : DSLSettingsFragment(), ExpiredGiftSheet.Callback
|
||||||
if (activeSubscription != null) {
|
if (activeSubscription != null) {
|
||||||
val subscription: Subscription? = state.availableSubscriptions.firstOrNull { activeSubscription.level == it.level }
|
val subscription: Subscription? = state.availableSubscriptions.firstOrNull { activeSubscription.level == it.level }
|
||||||
if (subscription != null) {
|
if (subscription != null) {
|
||||||
presentSubscriptionSettings(state.hasReceipts, activeSubscription, subscription, state.getRedemptionState())
|
presentSubscriptionSettings(activeSubscription, subscription, state.getRedemptionState())
|
||||||
} else {
|
} else {
|
||||||
customPref(IndeterminateLoadingCircle)
|
customPref(IndeterminateLoadingCircle)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
presentNoSubscriptionSettings(state.hasReceipts)
|
presentNoSubscriptionSettings()
|
||||||
}
|
}
|
||||||
} else if (state.transactionState == ManageDonationsState.TransactionState.NetworkFailure) {
|
} else if (state.transactionState == ManageDonationsState.TransactionState.NetworkFailure) {
|
||||||
presentNetworkFailureSettings(state.hasReceipts, state.getRedemptionState())
|
presentNetworkFailureSettings(state.getRedemptionState())
|
||||||
} else {
|
} else {
|
||||||
customPref(IndeterminateLoadingCircle)
|
customPref(IndeterminateLoadingCircle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun DSLConfiguration.presentNetworkFailureSettings(hasReceipts: Boolean, redemptionState: ManageDonationsState.SubscriptionRedemptionState) {
|
private fun DSLConfiguration.presentNetworkFailureSettings(redemptionState: ManageDonationsState.SubscriptionRedemptionState) {
|
||||||
if (SignalStore.donationsValues().isLikelyASustainer()) {
|
if (SignalStore.donationsValues().isLikelyASustainer()) {
|
||||||
presentSubscriptionSettingsWithNetworkError(hasReceipts, redemptionState)
|
presentSubscriptionSettingsWithNetworkError(redemptionState)
|
||||||
} else {
|
} else {
|
||||||
presentNoSubscriptionSettings(hasReceipts)
|
presentNoSubscriptionSettings()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun DSLConfiguration.presentSubscriptionSettingsWithNetworkError(hasReceipts: Boolean, redemptionState: ManageDonationsState.SubscriptionRedemptionState) {
|
private fun DSLConfiguration.presentSubscriptionSettingsWithNetworkError(redemptionState: ManageDonationsState.SubscriptionRedemptionState) {
|
||||||
presentSubscriptionSettingsWithState(hasReceipts, redemptionState) {
|
presentSubscriptionSettingsWithState(redemptionState) {
|
||||||
customPref(
|
customPref(
|
||||||
NetworkFailure.Model(
|
NetworkFailure.Model(
|
||||||
onRetryClick = {
|
onRetryClick = {
|
||||||
|
@ -134,12 +134,11 @@ class ManageDonationsFragment : DSLSettingsFragment(), ExpiredGiftSheet.Callback
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun DSLConfiguration.presentSubscriptionSettings(
|
private fun DSLConfiguration.presentSubscriptionSettings(
|
||||||
hasReceipts: Boolean,
|
|
||||||
activeSubscription: ActiveSubscription.Subscription,
|
activeSubscription: ActiveSubscription.Subscription,
|
||||||
subscription: Subscription,
|
subscription: Subscription,
|
||||||
redemptionState: ManageDonationsState.SubscriptionRedemptionState
|
redemptionState: ManageDonationsState.SubscriptionRedemptionState
|
||||||
) {
|
) {
|
||||||
presentSubscriptionSettingsWithState(hasReceipts, redemptionState) {
|
presentSubscriptionSettingsWithState(redemptionState) {
|
||||||
val activeCurrency = Currency.getInstance(activeSubscription.currency)
|
val activeCurrency = Currency.getInstance(activeSubscription.currency)
|
||||||
val activeAmount = activeSubscription.amount.movePointLeft(activeCurrency.defaultFractionDigits)
|
val activeAmount = activeSubscription.amount.movePointLeft(activeCurrency.defaultFractionDigits)
|
||||||
|
|
||||||
|
@ -160,7 +159,6 @@ class ManageDonationsFragment : DSLSettingsFragment(), ExpiredGiftSheet.Callback
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun DSLConfiguration.presentSubscriptionSettingsWithState(
|
private fun DSLConfiguration.presentSubscriptionSettingsWithState(
|
||||||
hasReceipts: Boolean,
|
|
||||||
redemptionState: ManageDonationsState.SubscriptionRedemptionState,
|
redemptionState: ManageDonationsState.SubscriptionRedemptionState,
|
||||||
subscriptionBlock: DSLConfiguration.() -> Unit
|
subscriptionBlock: DSLConfiguration.() -> Unit
|
||||||
) {
|
) {
|
||||||
|
@ -198,9 +196,7 @@ class ManageDonationsFragment : DSLSettingsFragment(), ExpiredGiftSheet.Callback
|
||||||
|
|
||||||
sectionHeaderPref(R.string.ManageDonationsFragment__more)
|
sectionHeaderPref(R.string.ManageDonationsFragment__more)
|
||||||
|
|
||||||
if (hasReceipts) {
|
presentDonationReceipts()
|
||||||
presentDonationReceipts()
|
|
||||||
}
|
|
||||||
|
|
||||||
externalLinkPref(
|
externalLinkPref(
|
||||||
title = DSLSettingsText.from(R.string.ManageDonationsFragment__subscription_faq),
|
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())
|
space(DimensionUnit.DP.toPixels(16f).toInt())
|
||||||
|
|
||||||
noPadTextPref(
|
noPadTextPref(
|
||||||
|
@ -227,11 +223,9 @@ class ManageDonationsFragment : DSLSettingsFragment(), ExpiredGiftSheet.Callback
|
||||||
|
|
||||||
presentOtherWaysToGive()
|
presentOtherWaysToGive()
|
||||||
|
|
||||||
if (hasReceipts) {
|
sectionHeaderPref(R.string.ManageDonationsFragment__receipts)
|
||||||
sectionHeaderPref(R.string.ManageDonationsFragment__receipts)
|
|
||||||
|
|
||||||
presentDonationReceipts()
|
presentDonationReceipts()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun DSLConfiguration.presentOtherWaysToGive() {
|
private fun DSLConfiguration.presentOtherWaysToGive() {
|
||||||
|
|
|
@ -8,7 +8,6 @@ data class ManageDonationsState(
|
||||||
val featuredBadge: Badge? = null,
|
val featuredBadge: Badge? = null,
|
||||||
val transactionState: TransactionState = TransactionState.Init,
|
val transactionState: TransactionState = TransactionState.Init,
|
||||||
val availableSubscriptions: List<Subscription> = emptyList(),
|
val availableSubscriptions: List<Subscription> = emptyList(),
|
||||||
val hasReceipts: Boolean = false,
|
|
||||||
private val subscriptionRedemptionState: SubscriptionRedemptionState = SubscriptionRedemptionState.NONE
|
private val subscriptionRedemptionState: SubscriptionRedemptionState = SubscriptionRedemptionState.NONE
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
|
|
@ -9,10 +9,8 @@ import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||||
import io.reactivex.rxjava3.disposables.Disposable
|
import io.reactivex.rxjava3.disposables.Disposable
|
||||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||||
import io.reactivex.rxjava3.kotlin.subscribeBy
|
import io.reactivex.rxjava3.kotlin.subscribeBy
|
||||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
|
||||||
import org.signal.core.util.logging.Log
|
import org.signal.core.util.logging.Log
|
||||||
import org.thoughtcrime.securesms.components.settings.app.subscription.SubscriptionsRepository
|
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.jobmanager.JobTracker
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient
|
import org.thoughtcrime.securesms.recipients.Recipient
|
||||||
import org.thoughtcrime.securesms.subscription.LevelUpdate
|
import org.thoughtcrime.securesms.subscription.LevelUpdate
|
||||||
|
@ -107,14 +105,6 @@ class ManageDonationsViewModel(
|
||||||
Log.w(TAG, "Error retrieving subscriptions data", it)
|
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(
|
class Factory(
|
||||||
|
|
|
@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.components.settings.app.subscription.receipts
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import androidx.constraintlayout.widget.Group
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.viewModels
|
import androidx.fragment.app.viewModels
|
||||||
import androidx.navigation.fragment.findNavController
|
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.StickyHeaderDecoration
|
||||||
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil
|
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil
|
||||||
import org.thoughtcrime.securesms.util.navigation.safeNavigate
|
import org.thoughtcrime.securesms.util.navigation.safeNavigate
|
||||||
|
import org.thoughtcrime.securesms.util.visible
|
||||||
|
|
||||||
class DonationReceiptListPageFragment : Fragment(R.layout.donation_receipt_list_page_fragment) {
|
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?
|
private val type: DonationReceiptRecord.Type?
|
||||||
get() = requireArguments().getString(ARG_TYPE)?.let { DonationReceiptRecord.Type.fromCode(it) }
|
get() = requireArguments().getString(ARG_TYPE)?.let { DonationReceiptRecord.Type.fromCode(it) }
|
||||||
|
|
||||||
|
private lateinit var emptyStateGroup: Group
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
val adapter = DonationReceiptListAdapter { model ->
|
val adapter = DonationReceiptListAdapter { model ->
|
||||||
findNavController().safeNavigate(DonationReceiptListFragmentDirections.actionDonationReceiptListFragmentToDonationReceiptDetailFragment(model.record.id))
|
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))
|
addItemDecoration(StickyHeaderDecoration(adapter, false, true, 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emptyStateGroup = view.findViewById(R.id.empty_state)
|
||||||
|
|
||||||
LiveDataUtil.combineLatest(
|
LiveDataUtil.combineLatest(
|
||||||
viewModel.state,
|
viewModel.state,
|
||||||
sharedViewModel.state
|
sharedViewModel.state
|
||||||
) { records, badges ->
|
) { state, badges ->
|
||||||
records.map { DonationReceiptListItem.Model(it, getBadgeForRecord(it, badges)) }
|
state.isLoaded to state.records.map { DonationReceiptListItem.Model(it, getBadgeForRecord(it, badges)) }
|
||||||
}.observe(viewLifecycleOwner) { records ->
|
}.observe(viewLifecycleOwner) { (isLoaded, records) ->
|
||||||
adapter.submitList(
|
if (records.isNotEmpty()) {
|
||||||
records +
|
emptyStateGroup.visible = false
|
||||||
TextPreference(
|
adapter.submitList(
|
||||||
title = null,
|
records +
|
||||||
summary = DSLSettingsText.from(
|
TextPreference(
|
||||||
R.string.DonationReceiptListFragment__if_you_have,
|
title = null,
|
||||||
DSLSettingsText.TextAppearanceModifier(R.style.TextAppearance_Signal_Subtitle)
|
summary = DSLSettingsText.from(
|
||||||
|
R.string.DonationReceiptListFragment__if_you_have,
|
||||||
|
DSLSettingsText.TextAppearanceModifier(R.style.TextAppearance_Signal_Subtitle)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
} else {
|
||||||
|
emptyStateGroup.visible = isLoaded
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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<DonationReceiptRecord> = emptyList(),
|
||||||
|
val isLoaded: Boolean = false
|
||||||
|
)
|
|
@ -1,24 +1,29 @@
|
||||||
package org.thoughtcrime.securesms.components.settings.app.subscription.receipts.list
|
package org.thoughtcrime.securesms.components.settings.app.subscription.receipts.list
|
||||||
|
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||||
import org.thoughtcrime.securesms.database.model.DonationReceiptRecord
|
import org.thoughtcrime.securesms.database.model.DonationReceiptRecord
|
||||||
|
import org.thoughtcrime.securesms.util.livedata.Store
|
||||||
|
|
||||||
class DonationReceiptListPageViewModel(type: DonationReceiptRecord.Type?, repository: DonationReceiptListPageRepository) : ViewModel() {
|
class DonationReceiptListPageViewModel(type: DonationReceiptRecord.Type?, repository: DonationReceiptListPageRepository) : ViewModel() {
|
||||||
|
|
||||||
private val disposables = CompositeDisposable()
|
private val disposables = CompositeDisposable()
|
||||||
private val internalState = MutableLiveData<List<DonationReceiptRecord>>()
|
private val store = Store(DonationReceiptListPageState())
|
||||||
|
|
||||||
val state: LiveData<List<DonationReceiptRecord>> = internalState
|
val state: LiveData<DonationReceiptListPageState> = store.stateLiveData
|
||||||
|
|
||||||
init {
|
init {
|
||||||
disposables += repository.getRecords(type)
|
disposables += repository.getRecords(type)
|
||||||
.subscribe { records ->
|
.subscribe { records ->
|
||||||
internalState.postValue(records)
|
store.update {
|
||||||
|
it.copy(
|
||||||
|
records = records,
|
||||||
|
isLoaded = true
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@ import androidx.core.content.contentValuesOf
|
||||||
import org.signal.core.util.CursorUtil
|
import org.signal.core.util.CursorUtil
|
||||||
import org.signal.core.util.SqlUtil
|
import org.signal.core.util.SqlUtil
|
||||||
import org.signal.core.util.money.FiatMoney
|
import org.signal.core.util.money.FiatMoney
|
||||||
import org.signal.core.util.select
|
|
||||||
import org.thoughtcrime.securesms.database.model.DonationReceiptRecord
|
import org.thoughtcrime.securesms.database.model.DonationReceiptRecord
|
||||||
import java.math.BigDecimal
|
import java.math.BigDecimal
|
||||||
import java.util.Currency
|
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) {
|
fun addReceipt(record: DonationReceiptRecord) {
|
||||||
require(record.id == -1L)
|
require(record.id == -1L)
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,50 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:id="@+id/recycler"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent">
|
||||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/recycler"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/empty_title"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:paddingHorizontal="32dp"
|
||||||
|
android:text="@string/DonationReceiptListFragment__no_receipts"
|
||||||
|
android:textAppearance="@style/Signal.Text.Body"
|
||||||
|
android:textColor="@color/signal_text_secondary"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/empty_description"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintVertical_chainStyle="packed" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/empty_description"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center"
|
||||||
|
android:paddingHorizontal="32dp"
|
||||||
|
android:text="@string/DonationReceiptListFragment__if_you_have"
|
||||||
|
android:textAppearance="@style/TextAppearance.Signal.Subtitle"
|
||||||
|
android:textColor="@color/signal_text_secondary"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/empty_title" />
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.Group
|
||||||
|
android:id="@+id/empty_state"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:constraint_referenced_ids="empty_title,empty_description" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
|
@ -4473,6 +4473,8 @@
|
||||||
<string name="DonationReceiptDetailsFragment__thank_you_for_supporting">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.</string>
|
<string name="DonationReceiptDetailsFragment__thank_you_for_supporting">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.</string>
|
||||||
<!-- Donation receipt type -->
|
<!-- Donation receipt type -->
|
||||||
<string name="DonationReceiptDetailsFragment__s_dash_s">%1$s - %2$s</string>
|
<string name="DonationReceiptDetailsFragment__s_dash_s">%1$s - %2$s</string>
|
||||||
|
<!-- Donation reciepts screen empty state title -->
|
||||||
|
<string name="DonationReceiptListFragment__no_receipts">No receipts</string>
|
||||||
|
|
||||||
<!-- region "Stories Tab" -->
|
<!-- region "Stories Tab" -->
|
||||||
|
|
||||||
|
|
Ładowanie…
Reference in New Issue