kopia lustrzana https://github.com/ryukoposting/Signal-Android
Fix a bunch UX bugs for donor badges.
rodzic
5047fc54f2
commit
ca24682366
|
@ -44,8 +44,15 @@ class BadgeImageView @JvmOverloads constructor(
|
|||
fun setBadgeFromRecipient(recipient: Recipient?, glideRequests: GlideRequests) {
|
||||
if (recipient == null || recipient.badges.isEmpty()) {
|
||||
setBadge(null, glideRequests)
|
||||
} else if (recipient.isSelf) {
|
||||
val badge = recipient.featuredBadge
|
||||
if (badge == null || !badge.visible || badge.isExpired()) {
|
||||
setBadge(null, glideRequests)
|
||||
} else {
|
||||
setBadge(badge, glideRequests)
|
||||
}
|
||||
} else {
|
||||
setBadge(recipient.badges[0], glideRequests)
|
||||
setBadge(recipient.featuredBadge, glideRequests)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -68,10 +68,11 @@ class BadgesOverviewFragment : DSLSettingsFragment(
|
|||
fadedBadgeId = state.fadedBadgeId
|
||||
)
|
||||
|
||||
switchPref(
|
||||
asyncSwitchPref(
|
||||
title = DSLSettingsText.from(R.string.BadgesOverviewFragment__display_badges_on_profile),
|
||||
isChecked = state.displayBadgesOnProfile,
|
||||
isEnabled = state.stage == BadgesOverviewState.Stage.READY && state.hasUnexpiredBadges,
|
||||
isProcessing = state.stage == BadgesOverviewState.Stage.UPDATING_BADGE_DISPLAY_STATE,
|
||||
onClick = {
|
||||
viewModel.setDisplayBadgesOnProfile(!state.displayBadgesOnProfile)
|
||||
}
|
||||
|
|
|
@ -15,6 +15,6 @@ data class BadgesOverviewState(
|
|||
enum class Stage {
|
||||
INIT,
|
||||
READY,
|
||||
UPDATING
|
||||
UPDATING_BADGE_DISPLAY_STATE
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,6 +61,7 @@ class BadgesOverviewViewModel(
|
|||
}
|
||||
|
||||
fun setDisplayBadgesOnProfile(displayBadgesOnProfile: Boolean) {
|
||||
store.update { it.copy(stage = BadgesOverviewState.Stage.UPDATING_BADGE_DISPLAY_STATE) }
|
||||
disposables += badgeRepository.setVisibilityForAllBadges(displayBadgesOnProfile)
|
||||
.subscribe(
|
||||
{
|
||||
|
|
|
@ -14,6 +14,7 @@ import androidx.core.content.ContextCompat;
|
|||
import com.annimon.stream.Stream;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.badges.BadgeImageView;
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.whispersystems.libsignal.util.Pair;
|
||||
|
@ -26,6 +27,9 @@ public class ConversationTypingView extends ConstraintLayout {
|
|||
private AvatarImageView avatar1;
|
||||
private AvatarImageView avatar2;
|
||||
private AvatarImageView avatar3;
|
||||
private BadgeImageView badge1;
|
||||
private BadgeImageView badge2;
|
||||
private BadgeImageView badge3;
|
||||
private View bubble;
|
||||
private TypingIndicatorView indicator;
|
||||
private TextView typistCount;
|
||||
|
@ -41,6 +45,9 @@ public class ConversationTypingView extends ConstraintLayout {
|
|||
avatar1 = findViewById(R.id.typing_avatar_1);
|
||||
avatar2 = findViewById(R.id.typing_avatar_2);
|
||||
avatar3 = findViewById(R.id.typing_avatar_3);
|
||||
badge1 = findViewById(R.id.typing_badge_1);
|
||||
badge2 = findViewById(R.id.typing_badge_2);
|
||||
badge3 = findViewById(R.id.typing_badge_3);
|
||||
typistCount = findViewById(R.id.typing_count);
|
||||
bubble = findViewById(R.id.typing_bubble);
|
||||
indicator = findViewById(R.id.typing_indicator);
|
||||
|
@ -55,6 +62,9 @@ public class ConversationTypingView extends ConstraintLayout {
|
|||
avatar1.setVisibility(GONE);
|
||||
avatar2.setVisibility(GONE);
|
||||
avatar3.setVisibility(GONE);
|
||||
badge1.setVisibility(GONE);
|
||||
badge2.setVisibility(GONE);
|
||||
badge3.setVisibility(GONE);
|
||||
typistCount.setVisibility(GONE);
|
||||
|
||||
if (isGroupThread) {
|
||||
|
@ -75,15 +85,21 @@ public class ConversationTypingView extends ConstraintLayout {
|
|||
private void presentGroupThreadAvatars(@NonNull GlideRequests glideRequests, @NonNull List<Recipient> typists) {
|
||||
avatar1.setAvatar(glideRequests, typists.get(0), typists.size() == 1);
|
||||
avatar1.setVisibility(VISIBLE);
|
||||
badge1.setBadgeFromRecipient(typists.get(0), glideRequests);
|
||||
badge1.setVisibility(VISIBLE);
|
||||
|
||||
if (typists.size() > 1) {
|
||||
avatar2.setAvatar(glideRequests, typists.get(1), false);
|
||||
avatar2.setVisibility(VISIBLE);
|
||||
badge2.setBadgeFromRecipient(typists.get(1), glideRequests);
|
||||
badge2.setVisibility(VISIBLE);
|
||||
}
|
||||
|
||||
if (typists.size() == 3) {
|
||||
avatar3.setAvatar(glideRequests, typists.get(2), false);
|
||||
avatar3.setVisibility(VISIBLE);
|
||||
badge3.setBadgeFromRecipient(typists.get(2), glideRequests);
|
||||
badge3.setVisibility(VISIBLE);
|
||||
}
|
||||
|
||||
if (typists.size() > 3) {
|
||||
|
|
|
@ -13,6 +13,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
|||
import com.google.android.material.switchmaterial.SwitchMaterial
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.components.settings.models.AsyncSwitch
|
||||
import org.thoughtcrime.securesms.components.settings.models.Button
|
||||
import org.thoughtcrime.securesms.components.settings.models.Space
|
||||
import org.thoughtcrime.securesms.components.settings.models.Text
|
||||
|
@ -37,6 +38,7 @@ class DSLSettingsAdapter : MappingAdapter() {
|
|||
Text.register(this)
|
||||
Space.register(this)
|
||||
Button.register(this)
|
||||
AsyncSwitch.register(this)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -415,6 +415,6 @@ class InternalSettingsFragment : DSLSettingsFragment(R.string.preferences__inter
|
|||
}
|
||||
|
||||
private fun enqueueSubscriptionRedemption() {
|
||||
SubscriptionReceiptRequestResponseJob.enqueueSubscriptionContinuation()
|
||||
SubscriptionReceiptRequestResponseJob.createSubscriptionContinuationJobChain().enqueue()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -132,11 +132,10 @@ class DonationPaymentRepository(activity: Activity) : StripeApi.PaymentIntentFet
|
|||
return Completable.create {
|
||||
stripeApi.confirmPaymentIntent(GooglePayPaymentSource(paymentData), paymentIntent).blockingSubscribe()
|
||||
|
||||
val jobId = BoostReceiptRequestResponseJob.enqueueChain(paymentIntent)
|
||||
val countDownLatch = CountDownLatch(1)
|
||||
|
||||
var finalJobState: JobTracker.JobState? = null
|
||||
ApplicationDependencies.getJobManager().addListener(jobId) { _, jobState ->
|
||||
|
||||
BoostReceiptRequestResponseJob.createJobChain(paymentIntent).enqueue { _, jobState ->
|
||||
if (jobState.isComplete) {
|
||||
finalJobState = jobState
|
||||
countDownLatch.countDown()
|
||||
|
@ -200,11 +199,10 @@ class DonationPaymentRepository(activity: Activity) : StripeApi.PaymentIntentFet
|
|||
}
|
||||
}.andThen {
|
||||
Log.d(TAG, "Enqueuing request response job chain.", true)
|
||||
val jobId = SubscriptionReceiptRequestResponseJob.enqueueSubscriptionContinuation()
|
||||
val countDownLatch = CountDownLatch(1)
|
||||
|
||||
var finalJobState: JobTracker.JobState? = null
|
||||
ApplicationDependencies.getJobManager().addListener(jobId) { _, jobState ->
|
||||
|
||||
SubscriptionReceiptRequestResponseJob.createSubscriptionContinuationJobChain().enqueue { _, jobState ->
|
||||
if (jobState.isComplete) {
|
||||
finalJobState = jobState
|
||||
countDownLatch.countDown()
|
||||
|
|
|
@ -11,6 +11,7 @@ import android.view.View
|
|||
import androidx.annotation.VisibleForTesting
|
||||
import androidx.appcompat.widget.AppCompatEditText
|
||||
import androidx.core.animation.doOnEnd
|
||||
import androidx.core.text.isDigitsOnly
|
||||
import androidx.core.widget.addTextChangedListener
|
||||
import androidx.lifecycle.DefaultLifecycleObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
|
@ -25,6 +26,7 @@ import org.thoughtcrime.securesms.util.MappingAdapter
|
|||
import org.thoughtcrime.securesms.util.MappingViewHolder
|
||||
import org.thoughtcrime.securesms.util.ViewUtil
|
||||
import java.lang.Integer.min
|
||||
import java.text.DecimalFormatSymbols
|
||||
import java.util.Currency
|
||||
import java.util.Locale
|
||||
import java.util.regex.Pattern
|
||||
|
@ -137,7 +139,10 @@ data class Boost(
|
|||
button.text = FiatMoneyUtil.format(
|
||||
context.resources,
|
||||
boost.price,
|
||||
FiatMoneyUtil.formatOptions().trimZerosAfterDecimal()
|
||||
FiatMoneyUtil
|
||||
.formatOptions()
|
||||
.numberOnly()
|
||||
.trimZerosAfterDecimal()
|
||||
)
|
||||
button.setOnClickListener {
|
||||
model.onBoostClick(it, boost)
|
||||
|
@ -181,11 +186,12 @@ data class Boost(
|
|||
}
|
||||
|
||||
@VisibleForTesting
|
||||
class MoneyFilter(val currency: Currency, private val onCustomAmountChanged: (String) -> Unit = {}) : DigitsKeyListener(), TextWatcher {
|
||||
class MoneyFilter(val currency: Currency, private val onCustomAmountChanged: (String) -> Unit = {}) : DigitsKeyListener(false, true), TextWatcher {
|
||||
|
||||
val separator = DecimalFormatSymbols.getInstance().decimalSeparator
|
||||
val separatorCount = min(1, currency.defaultFractionDigits)
|
||||
val prefix: String = currency.getSymbol(Locale.getDefault())
|
||||
val pattern: Pattern = "[0-9]*([.,]){0,$separatorCount}[0-9]{0,${currency.defaultFractionDigits}}".toPattern()
|
||||
val pattern: Pattern = "[0-9]*($separator){0,$separatorCount}[0-9]{0,${currency.defaultFractionDigits}}".toPattern()
|
||||
|
||||
override fun filter(
|
||||
source: CharSequence,
|
||||
|
@ -198,6 +204,11 @@ data class Boost(
|
|||
|
||||
val result = dest.subSequence(0, dstart).toString() + source.toString() + dest.subSequence(dend, dest.length)
|
||||
val resultWithoutCurrencyPrefix = result.removePrefix(prefix)
|
||||
|
||||
if (result.length == 1 && !result.isDigitsOnly() && result != separator.toString()) {
|
||||
return dest.subSequence(dstart, dend)
|
||||
}
|
||||
|
||||
val matcher = pattern.matcher(resultWithoutCurrencyPrefix)
|
||||
|
||||
if (!matcher.matches()) {
|
||||
|
|
|
@ -132,6 +132,11 @@ class BoostFragment : DSLSettingsBottomSheetFragment(
|
|||
}
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
processingDonationPaymentDialog.hide()
|
||||
}
|
||||
|
||||
private fun getConfiguration(state: BoostState): DSLConfiguration {
|
||||
if (state.stage == BoostState.Stage.PAYMENT_PIPELINE) {
|
||||
processingDonationPaymentDialog.show()
|
||||
|
|
|
@ -22,6 +22,7 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore
|
|||
import org.thoughtcrime.securesms.util.PlatformCurrencyUtil
|
||||
import org.thoughtcrime.securesms.util.livedata.Store
|
||||
import java.math.BigDecimal
|
||||
import java.text.DecimalFormatSymbols
|
||||
import java.util.Currency
|
||||
|
||||
class BoostViewModel(
|
||||
|
@ -190,7 +191,7 @@ class BoostViewModel(
|
|||
}
|
||||
|
||||
fun setCustomAmount(amount: String) {
|
||||
val bigDecimalAmount = if (amount.isEmpty()) {
|
||||
val bigDecimalAmount = if (amount.isEmpty() || amount == DecimalFormatSymbols.getInstance().decimalSeparator.toString()) {
|
||||
BigDecimal.ZERO
|
||||
} else {
|
||||
BigDecimal(amount)
|
||||
|
|
|
@ -109,6 +109,11 @@ class SubscribeFragment : DSLSettingsFragment(
|
|||
}
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
processingDonationPaymentDialog.hide()
|
||||
}
|
||||
|
||||
private fun getConfiguration(state: SubscribeState): DSLConfiguration {
|
||||
if (state.hasInProgressSubscriptionTransaction || state.stage == SubscribeState.Stage.PAYMENT_PIPELINE) {
|
||||
processingDonationPaymentDialog.show()
|
||||
|
|
|
@ -108,6 +108,7 @@ class ThanksForYourSupportBottomSheetDialogFragment : FixedRoundedCornerBottomSh
|
|||
|
||||
if (args.isBoost) {
|
||||
presentBoostCopy()
|
||||
badgeView.visibility = View.INVISIBLE
|
||||
lottie.visible = true
|
||||
lottie.playAnimation()
|
||||
lottie.addAnimatorListener(object : AnimationCompleteListener() {
|
||||
|
|
|
@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.components.settings
|
|||
import androidx.annotation.CallSuper
|
||||
import androidx.annotation.Px
|
||||
import androidx.annotation.StringRes
|
||||
import org.thoughtcrime.securesms.components.settings.models.AsyncSwitch
|
||||
import org.thoughtcrime.securesms.components.settings.models.Button
|
||||
import org.thoughtcrime.securesms.components.settings.models.Space
|
||||
import org.thoughtcrime.securesms.components.settings.models.Text
|
||||
|
@ -56,6 +57,17 @@ class DSLConfiguration {
|
|||
children.add(preference)
|
||||
}
|
||||
|
||||
fun asyncSwitchPref(
|
||||
title: DSLSettingsText,
|
||||
isEnabled: Boolean = true,
|
||||
isChecked: Boolean,
|
||||
isProcessing: Boolean,
|
||||
onClick: () -> Unit
|
||||
) {
|
||||
val preference = AsyncSwitch.Model(title, isEnabled, isChecked, isProcessing, onClick)
|
||||
children.add(preference)
|
||||
}
|
||||
|
||||
fun switchPref(
|
||||
title: DSLSettingsText,
|
||||
summary: DSLSettingsText? = null,
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
package org.thoughtcrime.securesms.components.settings.models
|
||||
|
||||
import android.view.View
|
||||
import android.widget.ViewSwitcher
|
||||
import com.google.android.material.switchmaterial.SwitchMaterial
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
|
||||
import org.thoughtcrime.securesms.components.settings.PreferenceModel
|
||||
import org.thoughtcrime.securesms.components.settings.PreferenceViewHolder
|
||||
import org.thoughtcrime.securesms.util.MappingAdapter
|
||||
|
||||
/**
|
||||
* Switch that will perform a long-running async operation (normally network) that requires a
|
||||
* progress spinner to replace the switch after a press.
|
||||
*/
|
||||
object AsyncSwitch {
|
||||
|
||||
fun register(adapter: MappingAdapter) {
|
||||
adapter.registerFactory(Model::class.java, MappingAdapter.LayoutFactory(AsyncSwitch::ViewHolder, R.layout.dsl_async_switch_preference_item))
|
||||
}
|
||||
|
||||
class Model(
|
||||
override val title: DSLSettingsText,
|
||||
override val isEnabled: Boolean,
|
||||
val isChecked: Boolean,
|
||||
val isProcessing: Boolean,
|
||||
val onClick: () -> Unit
|
||||
) : PreferenceModel<Model>() {
|
||||
override fun areContentsTheSame(newItem: Model): Boolean {
|
||||
return super.areContentsTheSame(newItem) && isChecked == newItem.isChecked && isProcessing == newItem.isProcessing
|
||||
}
|
||||
}
|
||||
|
||||
class ViewHolder(itemView: View) : PreferenceViewHolder<Model>(itemView) {
|
||||
private val switchWidget: SwitchMaterial = itemView.findViewById(R.id.switch_widget)
|
||||
private val switcher: ViewSwitcher = itemView.findViewById(R.id.switcher)
|
||||
|
||||
override fun bind(model: Model) {
|
||||
super.bind(model)
|
||||
switchWidget.isEnabled = model.isEnabled
|
||||
switchWidget.isChecked = model.isChecked
|
||||
itemView.isEnabled = !model.isProcessing
|
||||
switcher.displayedChild = if (model.isProcessing) 1 else 0
|
||||
|
||||
itemView.setOnClickListener {
|
||||
if (!model.isProcessing) {
|
||||
itemView.isEnabled = false
|
||||
switcher.displayedChild = 1
|
||||
model.onClick()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -19,6 +19,7 @@ import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
|||
|
||||
import org.signal.core.util.ThreadUtil;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.badges.BadgeImageView;
|
||||
import org.thoughtcrime.securesms.components.AvatarImageView;
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiTextView;
|
||||
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto;
|
||||
|
@ -55,9 +56,11 @@ public class CallParticipantView extends ConstraintLayout {
|
|||
|
||||
private AppCompatImageView backgroundAvatar;
|
||||
private AvatarImageView avatar;
|
||||
private BadgeImageView badge;
|
||||
private View rendererFrame;
|
||||
private TextureViewRenderer renderer;
|
||||
private ImageView pipAvatar;
|
||||
private BadgeImageView pipBadge;
|
||||
private ContactPhoto contactPhoto;
|
||||
private View audioMuted;
|
||||
private View infoOverlay;
|
||||
|
@ -92,6 +95,8 @@ public class CallParticipantView extends ConstraintLayout {
|
|||
infoIcon = findViewById(R.id.call_participant_info_icon);
|
||||
infoMessage = findViewById(R.id.call_participant_info_message);
|
||||
infoMoreInfo = findViewById(R.id.call_participant_info_more_info);
|
||||
badge = findViewById(R.id.call_participant_item_badge);
|
||||
pipBadge = findViewById(R.id.call_participant_item_pip_badge);
|
||||
|
||||
avatar.setFallbackPhotoProvider(FALLBACK_PHOTO_PROVIDER);
|
||||
useLargeAvatar();
|
||||
|
@ -120,7 +125,9 @@ public class CallParticipantView extends ConstraintLayout {
|
|||
renderer.attachBroadcastVideoSink(null);
|
||||
audioMuted.setVisibility(View.GONE);
|
||||
avatar.setVisibility(View.GONE);
|
||||
badge.setVisibility(View.GONE);
|
||||
pipAvatar.setVisibility(View.GONE);
|
||||
pipBadge.setVisibility(View.GONE);
|
||||
|
||||
infoOverlay.setVisibility(View.VISIBLE);
|
||||
|
||||
|
@ -157,8 +164,10 @@ public class CallParticipantView extends ConstraintLayout {
|
|||
|
||||
if (participantChanged || !Objects.equals(contactPhoto, participant.getRecipient().getContactPhoto())) {
|
||||
avatar.setAvatarUsingProfile(participant.getRecipient());
|
||||
badge.setBadgeFromRecipient(participant.getRecipient());
|
||||
AvatarUtil.loadBlurredIconIntoImageView(participant.getRecipient(), backgroundAvatar);
|
||||
setPipAvatar(participant.getRecipient());
|
||||
pipBadge.setBadgeFromRecipient(participant.getRecipient());
|
||||
contactPhoto = participant.getRecipient().getContactPhoto();
|
||||
}
|
||||
}
|
||||
|
@ -193,15 +202,19 @@ public class CallParticipantView extends ConstraintLayout {
|
|||
}
|
||||
|
||||
avatar.setVisibility(shouldRenderInPip ? View.GONE : View.VISIBLE);
|
||||
badge.setVisibility(shouldRenderInPip ? View.GONE : View.VISIBLE);
|
||||
pipAvatar.setVisibility(shouldRenderInPip ? View.VISIBLE : View.GONE);
|
||||
pipBadge.setVisibility(shouldRenderInPip ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
||||
void hideAvatar() {
|
||||
avatar.setAlpha(0f);
|
||||
badge.setAlpha(0f);
|
||||
}
|
||||
|
||||
void showAvatar() {
|
||||
avatar.setAlpha(1f);
|
||||
badge.setAlpha(1f);
|
||||
}
|
||||
|
||||
void useLargeAvatar() {
|
||||
|
|
|
@ -14,6 +14,7 @@ import androidx.annotation.Nullable;
|
|||
import androidx.annotation.StringRes;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.badges.BadgeImageView;
|
||||
import org.thoughtcrime.securesms.components.AvatarImageView;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
|
@ -29,6 +30,7 @@ public class CallParticipantsListUpdatePopupWindow extends PopupWindow {
|
|||
|
||||
private final ViewGroup parent;
|
||||
private final AvatarImageView avatarImageView;
|
||||
private final BadgeImageView badgeImageView;
|
||||
private final TextView descriptionTextView;
|
||||
|
||||
private final Set<CallParticipantListUpdate.Wrapper> pendingAdditions = new HashSet<>();
|
||||
|
@ -43,6 +45,7 @@ public class CallParticipantsListUpdatePopupWindow extends PopupWindow {
|
|||
|
||||
this.parent = parent;
|
||||
this.avatarImageView = getContentView().findViewById(R.id.avatar);
|
||||
this.badgeImageView = getContentView().findViewById(R.id.badge);
|
||||
this.descriptionTextView = getContentView().findViewById(R.id.description);
|
||||
|
||||
setOnDismissListener(this::showPending);
|
||||
|
@ -109,6 +112,7 @@ public class CallParticipantsListUpdatePopupWindow extends PopupWindow {
|
|||
|
||||
private void setAvatar(@Nullable Recipient recipient) {
|
||||
avatarImageView.setAvatarUsingProfile(recipient);
|
||||
badgeImageView.setBadgeFromRecipient(recipient);
|
||||
avatarImageView.setVisibility(recipient == null ? View.GONE : View.VISIBLE);
|
||||
}
|
||||
|
||||
|
|
|
@ -322,6 +322,8 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
|||
|
||||
SimpleTask.run(getViewLifecycleOwner().getLifecycle(), Recipient::self, this::initializeProfileIcon);
|
||||
|
||||
initializeSettingsTouchTarget();
|
||||
|
||||
if ((!searchToolbar.resolved() || !searchToolbar.get().isVisible()) && list.getAdapter() != defaultAdapter) {
|
||||
list.removeItemDecoration(searchAdapterDecoration);
|
||||
setAdapter(defaultAdapter);
|
||||
|
@ -527,7 +529,11 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
|||
imageView.setBadgeFromRecipient(recipient);
|
||||
|
||||
AvatarUtil.loadIconIntoImageView(recipient, icon, getResources().getDimensionPixelSize(R.dimen.toolbar_avatar_size));
|
||||
icon.setOnClickListener(v -> getNavigator().goToAppSettings());
|
||||
}
|
||||
|
||||
private void initializeSettingsTouchTarget() {
|
||||
View touchArea = requireView().findViewById(R.id.toolbar_settings_touch_area);
|
||||
touchArea.setOnClickListener(v -> getNavigator().goToAppSettings());
|
||||
}
|
||||
|
||||
private void initializeSearchListener() {
|
||||
|
|
|
@ -226,6 +226,8 @@ public final class ConversationListItem extends ConstraintLayout
|
|||
private void setBadgeFromRecipient(Recipient recipient) {
|
||||
if (!recipient.isSelf()) {
|
||||
badge.setBadgeFromRecipient(recipient);
|
||||
} else {
|
||||
badge.setBadge(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -462,6 +462,14 @@ public class JobManager implements ConstraintObserver.Notifier {
|
|||
jobManager.enqueueChain(this);
|
||||
}
|
||||
|
||||
public void enqueue(@NonNull JobTracker.JobListener listener) {
|
||||
List<Job> lastChain = jobs.get(jobs.size() - 1);
|
||||
Job lastJobInLastChain = lastChain.get(lastChain.size() - 1);
|
||||
|
||||
jobManager.addListener(lastJobInLastChain.getId(), listener);
|
||||
enqueue();
|
||||
}
|
||||
|
||||
private List<List<Job>> getJobListChain() {
|
||||
return jobs;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import org.signal.zkgroup.receipts.ReceiptSerial;
|
|||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobManager;
|
||||
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
||||
import org.thoughtcrime.securesms.subscription.SubscriptionNotification;
|
||||
import org.whispersystems.signalservice.internal.ServiceResponse;
|
||||
|
@ -56,18 +57,15 @@ public class BoostReceiptRequestResponseJob extends BaseJob {
|
|||
);
|
||||
}
|
||||
|
||||
public static String enqueueChain(StripeApi.PaymentIntent paymentIntent) {
|
||||
public static JobManager.Chain createJobChain(StripeApi.PaymentIntent paymentIntent) {
|
||||
BoostReceiptRequestResponseJob requestReceiptJob = createJob(paymentIntent);
|
||||
DonationReceiptRedemptionJob redeemReceiptJob = DonationReceiptRedemptionJob.createJobForBoost();
|
||||
RefreshOwnProfileJob refreshOwnProfileJob = new RefreshOwnProfileJob();
|
||||
|
||||
ApplicationDependencies.getJobManager()
|
||||
.startChain(requestReceiptJob)
|
||||
.then(redeemReceiptJob)
|
||||
.then(refreshOwnProfileJob)
|
||||
.enqueue();
|
||||
|
||||
return refreshOwnProfileJob.getId();
|
||||
return ApplicationDependencies.getJobManager()
|
||||
.startChain(requestReceiptJob)
|
||||
.then(redeemReceiptJob)
|
||||
.then(refreshOwnProfileJob);
|
||||
}
|
||||
|
||||
private BoostReceiptRequestResponseJob(@NonNull Parameters parameters,
|
||||
|
|
|
@ -8,6 +8,7 @@ import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
|||
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
||||
import org.thoughtcrime.securesms.subscription.SubscriptionNotification;
|
||||
import org.whispersystems.signalservice.internal.EmptyResponse;
|
||||
import org.whispersystems.signalservice.internal.ServiceResponse;
|
||||
|
||||
|
@ -63,6 +64,7 @@ public class DonationReceiptRedemptionJob extends BaseJob {
|
|||
|
||||
@Override
|
||||
public void onFailure() {
|
||||
SubscriptionNotification.RedemptionFailed.INSTANCE.show(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -70,8 +72,8 @@ public class DonationReceiptRedemptionJob extends BaseJob {
|
|||
Data inputData = getInputData();
|
||||
|
||||
if (inputData == null) {
|
||||
Log.w(TAG, "No input data. Failing.", null, true);
|
||||
throw new IllegalStateException("Expected a presentation object in input data.");
|
||||
Log.w(TAG, "No input data. Exiting.", null, true);
|
||||
return;
|
||||
}
|
||||
|
||||
byte[] presentationBytes = inputData.getStringAsBlob(INPUT_RECEIPT_CREDENTIAL_PRESENTATION);
|
||||
|
|
|
@ -11,7 +11,6 @@ import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
|||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.subscription.Subscriber;
|
||||
import org.whispersystems.signalservice.api.subscriptions.ActiveSubscription;
|
||||
import org.whispersystems.signalservice.api.subscriptions.SubscriberId;
|
||||
import org.whispersystems.signalservice.internal.EmptyResponse;
|
||||
import org.whispersystems.signalservice.internal.ServiceResponse;
|
||||
|
||||
|
@ -97,7 +96,7 @@ public class SubscriptionKeepAliveJob extends BaseJob {
|
|||
|
||||
if (activeSubscription.getActiveSubscription().getEndOfCurrentPeriod() > SignalStore.donationsValues().getLastEndOfPeriod()) {
|
||||
Log.i(TAG, "Last end of period change. Requesting receipt refresh.");
|
||||
SubscriptionReceiptRequestResponseJob.enqueueSubscriptionContinuation();
|
||||
SubscriptionReceiptRequestResponseJob.createSubscriptionContinuationJobChain().enqueue();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ import org.signal.zkgroup.receipts.ReceiptSerial;
|
|||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobManager;
|
||||
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.subscription.Subscriber;
|
||||
|
@ -62,19 +63,16 @@ public class SubscriptionReceiptRequestResponseJob extends BaseJob {
|
|||
);
|
||||
}
|
||||
|
||||
public static String enqueueSubscriptionContinuation() {
|
||||
public static JobManager.Chain createSubscriptionContinuationJobChain() {
|
||||
Subscriber subscriber = SignalStore.donationsValues().requireSubscriber();
|
||||
SubscriptionReceiptRequestResponseJob requestReceiptJob = createJob(subscriber.getSubscriberId());
|
||||
DonationReceiptRedemptionJob redeemReceiptJob = DonationReceiptRedemptionJob.createJobForSubscription();
|
||||
RefreshOwnProfileJob refreshOwnProfileJob = new RefreshOwnProfileJob();
|
||||
|
||||
ApplicationDependencies.getJobManager()
|
||||
.startChain(requestReceiptJob)
|
||||
.then(redeemReceiptJob)
|
||||
.then(refreshOwnProfileJob)
|
||||
.enqueue();
|
||||
|
||||
return refreshOwnProfileJob.getId();
|
||||
return ApplicationDependencies.getJobManager()
|
||||
.startChain(requestReceiptJob)
|
||||
.then(redeemReceiptJob)
|
||||
.then(refreshOwnProfileJob);
|
||||
}
|
||||
|
||||
private SubscriptionReceiptRequestResponseJob(@NonNull Parameters parameters,
|
||||
|
|
|
@ -226,7 +226,11 @@ public class ManageProfileFragment extends LoggingFragment {
|
|||
}
|
||||
|
||||
private void presentBadge(@NonNull Optional<Badge> badge) {
|
||||
badgeView.setBadge(badge.orNull());
|
||||
if (badge.isPresent() && badge.get().getVisible() && !badge.get().isExpired()) {
|
||||
badgeView.setBadge(badge.orNull());
|
||||
} else {
|
||||
badgeView.setBadge(null);
|
||||
}
|
||||
}
|
||||
|
||||
private void presentEvent(@NonNull ManageProfileViewModel.Event event) {
|
||||
|
|
|
@ -38,5 +38,31 @@ sealed class SubscriptionNotification {
|
|||
}
|
||||
}
|
||||
|
||||
object RedemptionFailed : SubscriptionNotification() {
|
||||
override fun show(context: Context) {
|
||||
val notification = NotificationCompat.Builder(context, NotificationChannels.FAILURES)
|
||||
.setSmallIcon(R.drawable.ic_notification)
|
||||
.setContentTitle(context.getString(R.string.Subscription__redemption_failed))
|
||||
.setContentText(context.getString(R.string.Subscription__please_contact_support_for_more_information))
|
||||
.addAction(
|
||||
NotificationCompat.Action.Builder(
|
||||
null,
|
||||
context.getString(R.string.Subscription__contact_support),
|
||||
PendingIntent.getActivity(
|
||||
context,
|
||||
0,
|
||||
AppSettingsActivity.help(context, HelpFragment.DONATION_INDEX),
|
||||
if (Build.VERSION.SDK_INT >= 23) PendingIntent.FLAG_ONE_SHOT else 0
|
||||
)
|
||||
).build()
|
||||
)
|
||||
.build()
|
||||
|
||||
NotificationManagerCompat
|
||||
.from(context)
|
||||
.notify(NotificationIds.SUBSCRIPTION_VERIFY_FAILED, notification)
|
||||
}
|
||||
}
|
||||
|
||||
abstract fun show(context: Context)
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import androidx.annotation.NonNull;
|
|||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.badges.BadgeImageView;
|
||||
import org.thoughtcrime.securesms.components.AvatarImageView;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.MappingAdapter;
|
||||
|
@ -16,6 +17,7 @@ import org.thoughtcrime.securesms.util.MappingViewHolder;
|
|||
public class RecipientViewHolder<T extends RecipientMappingModel<T>> extends MappingViewHolder<T> {
|
||||
|
||||
protected final @Nullable AvatarImageView avatar;
|
||||
protected final @Nullable BadgeImageView badge;
|
||||
protected final @Nullable TextView name;
|
||||
protected final @Nullable EventListener<T> eventListener;
|
||||
private final boolean quickContactEnabled;
|
||||
|
@ -30,6 +32,7 @@ public class RecipientViewHolder<T extends RecipientMappingModel<T>> extends Map
|
|||
this.quickContactEnabled = quickContactEnabled;
|
||||
|
||||
avatar = findViewById(R.id.recipient_view_avatar);
|
||||
badge = findViewById(R.id.recipient_view_badge);
|
||||
name = findViewById(R.id.recipient_view_name);
|
||||
}
|
||||
|
||||
|
@ -39,6 +42,10 @@ public class RecipientViewHolder<T extends RecipientMappingModel<T>> extends Map
|
|||
avatar.setRecipient(model.getRecipient(), quickContactEnabled);
|
||||
}
|
||||
|
||||
if (badge != null) {
|
||||
badge.setBadgeFromRecipient(model.getRecipient());
|
||||
}
|
||||
|
||||
if (name != null) {
|
||||
name.setText(model.getName(context));
|
||||
}
|
||||
|
|
|
@ -28,6 +28,21 @@
|
|||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:srcCompat="@tools:sample/avatars" />
|
||||
|
||||
<View
|
||||
android:id="@+id/call_participant_badge_offseter"
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="32dp"
|
||||
app:layout_constraintBottom_toBottomOf="@id/call_participant_item_avatar"
|
||||
app:layout_constraintEnd_toEndOf="@id/call_participant_item_avatar" />
|
||||
|
||||
<org.thoughtcrime.securesms.badges.BadgeImageView
|
||||
android:id="@+id/call_participant_item_badge"
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="36dp"
|
||||
app:badge_size="large"
|
||||
app:layout_constraintEnd_toEndOf="@id/call_participant_badge_offseter"
|
||||
app:layout_constraintTop_toTopOf="@id/call_participant_badge_offseter" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/call_participant_item_pip_avatar"
|
||||
android:layout_width="200dp"
|
||||
|
@ -39,6 +54,15 @@
|
|||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:srcCompat="@tools:sample/avatars" />
|
||||
|
||||
<org.thoughtcrime.securesms.badges.BadgeImageView
|
||||
android:id="@+id/call_participant_item_pip_badge"
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="36dp"
|
||||
android:visibility="gone"
|
||||
app:badge_size="large"
|
||||
app:layout_constraintBottom_toBottomOf="@id/call_participant_item_pip_avatar"
|
||||
app:layout_constraintEnd_toEndOf="@id/call_participant_item_pip_avatar" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/call_participant_renderer_frame"
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
@ -26,6 +26,18 @@
|
|||
tools:src="@drawable/ic_profile_80"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<org.thoughtcrime.securesms.badges.BadgeImageView
|
||||
android:id="@+id/badge"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginTop="22dp"
|
||||
android:contentDescription="@string/ImageView__badge"
|
||||
app:badge_size="medium"
|
||||
app:layout_constraintStart_toStartOf="@id/avatar"
|
||||
app:layout_constraintTop_toTopOf="@id/avatar"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/description"
|
||||
android:layout_width="0dp"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout 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:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -16,13 +16,25 @@
|
|||
android:layout_width="36dp"
|
||||
android:layout_height="36dp"
|
||||
app:fallbackImageSize="small"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:src="@tools:sample/avatars" />
|
||||
|
||||
<org.thoughtcrime.securesms.badges.BadgeImageView
|
||||
android:id="@+id/recipient_view_badge"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginTop="23dp"
|
||||
app:badge_size="small"
|
||||
app:layout_constraintStart_toStartOf="@id/recipient_view_avatar"
|
||||
app:layout_constraintTop_toTopOf="@id/recipient_view_avatar" />
|
||||
|
||||
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
|
||||
android:id="@+id/recipient_view_name"
|
||||
style="@style/TextAppearance.Signal.Body1"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
|
@ -30,29 +42,45 @@
|
|||
android:singleLine="true"
|
||||
android:textAlignment="viewStart"
|
||||
android:textAppearance="@style/Signal.Text.Preview"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/call_participant_video_muted"
|
||||
app:layout_constraintStart_toEndOf="@id/recipient_view_avatar"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="@tools:sample/full_names" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/call_participant_video_muted"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/call_participant_audio_muted"
|
||||
app:layout_constraintStart_toEndOf="@id/recipient_view_name"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@drawable/ic_video_off_solid_white_18"
|
||||
app:tint="@color/core_white"/>
|
||||
app:tint="@color/core_white" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/call_participant_audio_muted"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/call_participant_screen_sharing"
|
||||
app:layout_constraintStart_toEndOf="@id/call_participant_video_muted"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@drawable/ic_mic_off_solid_18"
|
||||
app:tint="@color/core_white"/>
|
||||
app:tint="@color/core_white" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/call_participant_screen_sharing"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/call_participant_audio_muted"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@drawable/ic_share_screen_20"
|
||||
app:tint="@color/core_white"/>
|
||||
app:tint="@color/core_white" />
|
||||
|
||||
</LinearLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
|
@ -54,6 +54,15 @@
|
|||
app:layout_constraintStart_toStartOf="@id/toolbar_icon"
|
||||
app:layout_constraintTop_toTopOf="@id/toolbar_icon" />
|
||||
|
||||
<View
|
||||
android:id="@+id/toolbar_settings_touch_area"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="@id/toolbar_icon"
|
||||
app:layout_constraintStart_toStartOf="@id/toolbar_icon"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<View
|
||||
android:id="@+id/unread_payments_indicator"
|
||||
android:layout_width="13dp"
|
||||
|
|
|
@ -24,6 +24,18 @@
|
|||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<org.thoughtcrime.securesms.badges.BadgeImageView
|
||||
android:id="@+id/typing_badge_1"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginStart="14dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:visibility="gone"
|
||||
app:badge_size="small"
|
||||
app:layout_constraintStart_toStartOf="@id/typing_avatar_1"
|
||||
app:layout_constraintTop_toTopOf="@id/typing_avatar_1"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<org.thoughtcrime.securesms.components.AvatarImageView
|
||||
android:id="@+id/typing_avatar_2"
|
||||
android:layout_width="@dimen/conversation_item_avatar_size"
|
||||
|
@ -39,6 +51,18 @@
|
|||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<org.thoughtcrime.securesms.badges.BadgeImageView
|
||||
android:id="@+id/typing_badge_2"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginStart="14dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:visibility="gone"
|
||||
app:badge_size="small"
|
||||
app:layout_constraintStart_toStartOf="@id/typing_avatar_2"
|
||||
app:layout_constraintTop_toTopOf="@id/typing_avatar_2"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<org.thoughtcrime.securesms.components.AvatarImageView
|
||||
android:id="@+id/typing_avatar_3"
|
||||
android:layout_width="@dimen/conversation_item_avatar_size"
|
||||
|
@ -53,6 +77,17 @@
|
|||
app:layout_constraintStart_toStartOf="@id/typing_avatar_2"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<org.thoughtcrime.securesms.badges.BadgeImageView
|
||||
android:id="@+id/typing_badge_3"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginStart="14dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:visibility="gone"
|
||||
app:badge_size="small"
|
||||
app:layout_constraintStart_toStartOf="@id/typing_avatar_3"
|
||||
app:layout_constraintTop_toTopOf="@id/typing_avatar_3" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/typing_count"
|
||||
android:layout_width="wrap_content"
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/dsl_preference_item_background"
|
||||
android:minHeight="56dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icon"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginStart="@dimen/dsl_settings_gutter"
|
||||
android:importantForAccessibility="no"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:srcCompat="@drawable/ic_advanced_24" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:textAppearance="@style/Signal.Text.Body"
|
||||
app:layout_constraintBottom_toTopOf="@id/summary"
|
||||
app:layout_constraintEnd_toStartOf="@id/switcher"
|
||||
app:layout_constraintStart_toEndOf="@id/icon"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_chainStyle="packed"
|
||||
app:layout_goneMarginBottom="16dp"
|
||||
app:layout_goneMarginStart="@dimen/dsl_settings_gutter"
|
||||
tools:text="Message font size" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/summary"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginEnd="@dimen/dsl_settings_gutter"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:lineSpacingExtra="4sp"
|
||||
android:textAppearance="@style/TextAppearance.Signal.Body2"
|
||||
android:textColor="@color/text_color_secondary_enabled_selector"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/switcher"
|
||||
app:layout_constraintStart_toEndOf="@id/icon"
|
||||
app:layout_constraintTop_toBottomOf="@id/title"
|
||||
app:layout_goneMarginStart="@dimen/dsl_settings_gutter"
|
||||
app:layout_goneMarginTop="16dp"
|
||||
tools:text="Some random text to get stuff onto more than one line but not absurdly long like lorem/random"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<ViewSwitcher
|
||||
android:id="@+id/switcher"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="@dimen/dsl_settings_gutter"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||
android:id="@+id/switch_widget"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:clickable="false" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/switch_progress"
|
||||
style="@style/Widget.MaterialComponents.CircularProgressIndicator"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:indeterminate="true" />
|
||||
|
||||
</ViewSwitcher>
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout 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:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -16,11 +16,25 @@
|
|||
android:layout_width="36dp"
|
||||
android:layout_height="36dp"
|
||||
app:fallbackImageSize="small"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/recipient_view_name"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:src="@tools:sample/avatars" />
|
||||
|
||||
<org.thoughtcrime.securesms.badges.BadgeImageView
|
||||
android:id="@+id/recipient_view_badge"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginTop="23dp"
|
||||
app:badge_size="small"
|
||||
app:layout_constraintStart_toStartOf="@id/recipient_view_avatar"
|
||||
app:layout_constraintTop_toTopOf="@id/recipient_view_avatar" />
|
||||
|
||||
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
|
||||
android:id="@+id/recipient_view_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
|
@ -28,6 +42,10 @@
|
|||
android:singleLine="true"
|
||||
android:textAlignment="viewStart"
|
||||
android:textAppearance="@style/Signal.Text.Preview"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/recipient_view_avatar"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="@tools:sample/full_names" />
|
||||
|
||||
</LinearLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
|
@ -19,6 +19,18 @@
|
|||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:src="@tools:sample/avatars" />
|
||||
|
||||
<org.thoughtcrime.securesms.badges.BadgeImageView
|
||||
android:id="@+id/recipient_view_badge"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginTop="22dp"
|
||||
android:contentDescription="@string/ImageView__badge"
|
||||
app:badge_size="medium"
|
||||
app:layout_constraintStart_toStartOf="@id/recipient_view_avatar"
|
||||
app:layout_constraintTop_toTopOf="@id/recipient_view_avatar"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/payments_home_payment_item_avatar_progress_overlay"
|
||||
android:layout_width="0dp"
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
|
||||
<org.thoughtcrime.securesms.badges.BadgeImageView
|
||||
android:id="@+id/badge"
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="200dp"
|
||||
android:layout_width="160dp"
|
||||
android:layout_height="160dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:contentDescription="@string/BadgesOverviewFragment__featured_badge"
|
||||
app:badge_size="xlarge"
|
||||
|
|
|
@ -3999,6 +3999,7 @@
|
|||
<string name="ExpiredBadgeBottomSheetDialogFragment__renew_subscription">Renew subscription</string>
|
||||
|
||||
<string name="Subscription__verification_failed">Subscription Verification Failed</string>
|
||||
<string name="Subscription__redemption_failed">Badge Redemption Failed</string>
|
||||
<string name="Subscription__please_contact_support_for_more_information">Please contact support for more information.</string>
|
||||
<string name="Subscription__contact_support">Contact Support</string>
|
||||
<string name="Subscription__earn_a_s_badge">Earn a %1$s badge</string>
|
||||
|
|
Ładowanie…
Reference in New Issue