Improve wallpaper settings screen, conversation rendering.

Co-authored-by: Greyson Parrelli <greyson@signal.org>
fork-5.53.8
Alex Hart 2021-01-19 21:54:10 -05:00 zatwierdzone przez Greyson Parrelli
rodzic 6bcb0de43d
commit b5712f4bd1
63 zmienionych plików z 1100 dodań i 307 usunięć

Wyświetl plik

@ -36,7 +36,8 @@ public interface BindableConversationItem extends Unbindable {
@NonNull Set<ConversationMessage> batchSelected, @NonNull Set<ConversationMessage> batchSelected,
@NonNull Recipient recipients, @NonNull Recipient recipients,
@Nullable String searchQuery, @Nullable String searchQuery,
boolean pulseMention); boolean pulseMention,
boolean hasWallpaper);
ConversationMessage getConversationMessage(); ConversationMessage getConversationMessage();

Wyświetl plik

@ -12,6 +12,7 @@ import android.widget.ImageView;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
@ -130,6 +131,20 @@ public class ConversationItemFooter extends LinearLayout {
presentDeliveryStatus(messageRecord); presentDeliveryStatus(messageRecord);
} }
public void enableBubbleBackground(@DrawableRes int drawableRes, @Nullable Integer tint) {
setBackgroundResource(drawableRes);
if (tint != null) {
getBackground().setColorFilter(tint, PorterDuff.Mode.MULTIPLY);
} else {
getBackground().clearColorFilter();
}
}
public void disableBubbleBackground() {
setBackground(null);
}
private void presentDate(@NonNull MessageRecord messageRecord, @NonNull Locale locale) { private void presentDate(@NonNull MessageRecord messageRecord, @NonNull Locale locale) {
dateView.forceLayout(); dateView.forceLayout();
if (messageRecord.isFailed()) { if (messageRecord.isFailed()) {

Wyświetl plik

@ -61,6 +61,7 @@ import android.view.WindowManager;
import android.view.inputmethod.EditorInfo; import android.view.inputmethod.EditorInfo;
import android.widget.Button; import android.widget.Button;
import android.widget.ImageButton; import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
@ -258,6 +259,7 @@ import org.thoughtcrime.securesms.util.DynamicDarkToolbarTheme;
import org.thoughtcrime.securesms.util.DynamicLanguage; import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicTheme; import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.FeatureFlags; import org.thoughtcrime.securesms.util.FeatureFlags;
import org.thoughtcrime.securesms.util.FullscreenHelper;
import org.thoughtcrime.securesms.util.IdentityUtil; import org.thoughtcrime.securesms.util.IdentityUtil;
import org.thoughtcrime.securesms.util.MediaUtil; import org.thoughtcrime.securesms.util.MediaUtil;
import org.thoughtcrime.securesms.util.MessageUtil; import org.thoughtcrime.securesms.util.MessageUtil;
@ -267,6 +269,7 @@ import org.thoughtcrime.securesms.util.SmsUtil;
import org.thoughtcrime.securesms.util.SpanUtil; import org.thoughtcrime.securesms.util.SpanUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.TextSecurePreferences.MediaKeyboardMode; import org.thoughtcrime.securesms.util.TextSecurePreferences.MediaKeyboardMode;
import org.thoughtcrime.securesms.util.ThemeUtil;
import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.ViewUtil; import org.thoughtcrime.securesms.util.ViewUtil;
import org.thoughtcrime.securesms.util.WindowUtil; import org.thoughtcrime.securesms.util.WindowUtil;
@ -275,6 +278,8 @@ import org.thoughtcrime.securesms.util.concurrent.ListenableFuture;
import org.thoughtcrime.securesms.util.concurrent.SettableFuture; import org.thoughtcrime.securesms.util.concurrent.SettableFuture;
import org.thoughtcrime.securesms.util.concurrent.SimpleTask; import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
import org.thoughtcrime.securesms.util.views.Stub; import org.thoughtcrime.securesms.util.views.Stub;
import org.thoughtcrime.securesms.wallpaper.ChatWallpaper;
import org.thoughtcrime.securesms.wallpaper.ChatWallpaperDimLevelUtil;
import org.whispersystems.libsignal.InvalidMessageException; import org.whispersystems.libsignal.InvalidMessageException;
import org.whispersystems.libsignal.util.Pair; import org.whispersystems.libsignal.util.Pair;
import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.libsignal.util.guava.Optional;
@ -375,6 +380,8 @@ public class ConversationActivity extends PassphraseRequiredActivity
private Stub<View> mentionsSuggestions; private Stub<View> mentionsSuggestions;
private MaterialButton joinGroupCallButton; private MaterialButton joinGroupCallButton;
private boolean callingTooltipShown; private boolean callingTooltipShown;
private ImageView wallpaper;
private View wallpaperDim;
private LinkPreviewViewModel linkPreviewViewModel; private LinkPreviewViewModel linkPreviewViewModel;
private ConversationSearchViewModel searchViewModel; private ConversationSearchViewModel searchViewModel;
@ -414,6 +421,8 @@ public class ConversationActivity extends PassphraseRequiredActivity
return; return;
} }
new FullscreenHelper(this).showSystemUI();
ConversationIntents.Args args = ConversationIntents.Args.from(getIntent()); ConversationIntents.Args args = ConversationIntents.Args.from(getIntent());
reportShortcutLaunch(args.getRecipientId()); reportShortcutLaunch(args.getRecipientId());
@ -426,6 +435,7 @@ public class ConversationActivity extends PassphraseRequiredActivity
initializeReceivers(); initializeReceivers();
initializeActionBar(); initializeActionBar();
initializeViews(); initializeViews();
updateWallpaper(args.getWallpaper());
initializeResources(args); initializeResources(args);
initializeLinkPreviewObserver(); initializeLinkPreviewObserver();
initializeSearchObserver(); initializeSearchObserver();
@ -1910,6 +1920,8 @@ public class ConversationActivity extends PassphraseRequiredActivity
messageRequestBottomView = findViewById(R.id.conversation_activity_message_request_bottom_bar); messageRequestBottomView = findViewById(R.id.conversation_activity_message_request_bottom_bar);
reactionOverlay = findViewById(R.id.conversation_reaction_scrubber); reactionOverlay = findViewById(R.id.conversation_reaction_scrubber);
mentionsSuggestions = ViewUtil.findStubById(this, R.id.conversation_mention_suggestions_stub); mentionsSuggestions = ViewUtil.findStubById(this, R.id.conversation_mention_suggestions_stub);
wallpaper = findViewById(R.id.conversation_wallpaper);
wallpaperDim = findViewById(R.id.conversation_wallpaper_dim);
ImageButton quickCameraToggle = findViewById(R.id.quick_camera_toggle); ImageButton quickCameraToggle = findViewById(R.id.quick_camera_toggle);
ImageButton inlineAttachmentButton = findViewById(R.id.inline_attachment_button); ImageButton inlineAttachmentButton = findViewById(R.id.inline_attachment_button);
@ -1976,6 +1988,16 @@ public class ConversationActivity extends PassphraseRequiredActivity
joinGroupCallButton.setOnClickListener(v -> handleVideo(getRecipient())); joinGroupCallButton.setOnClickListener(v -> handleVideo(getRecipient()));
} }
private void updateWallpaper(@Nullable ChatWallpaper chatWallpaper) {
if (chatWallpaper != null) {
chatWallpaper.loadInto(wallpaper);
ChatWallpaperDimLevelUtil.applyDimLevelForNightMode(wallpaperDim, chatWallpaper);
} else {
wallpaper.setImageDrawable(null);
wallpaperDim.setVisibility(View.GONE);
}
}
protected void initializeActionBar() { protected void initializeActionBar() {
Toolbar toolbar = findViewById(R.id.toolbar); Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar); setSupportActionBar(toolbar);
@ -2268,6 +2290,7 @@ public class ConversationActivity extends PassphraseRequiredActivity
updateReminders(); updateReminders();
updateDefaultSubscriptionId(recipient.getDefaultSubscriptionId()); updateDefaultSubscriptionId(recipient.getDefaultSubscriptionId());
initializeSecurity(isSecureText, isDefaultSms); initializeSecurity(isSecureText, isDefaultSms);
updateWallpaper(recipient.getWallpaper());
if (searchViewItem == null || !searchViewItem.isActionViewExpanded()) { if (searchViewItem == null || !searchViewItem.isActionViewExpanded()) {
invalidateOptionsMenu(); invalidateOptionsMenu();

Wyświetl plik

@ -23,6 +23,7 @@ import android.widget.FrameLayout;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.AnyThread; import androidx.annotation.AnyThread;
import androidx.annotation.DrawableRes;
import androidx.annotation.LayoutRes; import androidx.annotation.LayoutRes;
import androidx.annotation.MainThread; import androidx.annotation.MainThread;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@ -241,7 +242,8 @@ public class ConversationAdapter
selected, selected,
recipient, recipient,
searchQuery, searchQuery,
conversationMessage == recordToPulse); conversationMessage == recordToPulse,
recipient.hasWallpaper());
if (conversationMessage == recordToPulse) { if (conversationMessage == recordToPulse) {
recordToPulse = null; recordToPulse = null;
@ -296,6 +298,12 @@ public class ConversationAdapter
public void onBindHeaderViewHolder(StickyHeaderViewHolder viewHolder, int position) { public void onBindHeaderViewHolder(StickyHeaderViewHolder viewHolder, int position) {
ConversationMessage conversationMessage = Objects.requireNonNull(getItem(position)); ConversationMessage conversationMessage = Objects.requireNonNull(getItem(position));
viewHolder.setText(DateUtils.getRelativeDate(viewHolder.itemView.getContext(), locale, conversationMessage.getMessageRecord().getDateReceived())); viewHolder.setText(DateUtils.getRelativeDate(viewHolder.itemView.getContext(), locale, conversationMessage.getMessageRecord().getDateReceived()));
if (recipient.hasWallpaper()) {
viewHolder.setBackgroundRes(R.drawable.wallpaper_bubble_background_8);
} else {
viewHolder.clearBackground();
}
} }
public @Nullable ConversationMessage getItem(int position) { public @Nullable ConversationMessage getItem(int position) {
@ -325,6 +333,12 @@ public class ConversationAdapter
void onBindLastSeenViewHolder(StickyHeaderViewHolder viewHolder, int position) { void onBindLastSeenViewHolder(StickyHeaderViewHolder viewHolder, int position) {
viewHolder.setText(viewHolder.itemView.getContext().getResources().getQuantityString(R.plurals.ConversationAdapter_n_unread_messages, (position + 1), (position + 1))); viewHolder.setText(viewHolder.itemView.getContext().getResources().getQuantityString(R.plurals.ConversationAdapter_n_unread_messages, (position + 1), (position + 1)));
if (recipient.hasWallpaper()) {
viewHolder.setBackgroundRes(R.drawable.wallpaper_bubble_background_8);
} else {
viewHolder.clearBackground();
}
} }
boolean hasNoConversationMessages() { boolean hasNoConversationMessages() {
@ -563,6 +577,14 @@ public class ConversationAdapter
public void setText(CharSequence text) { public void setText(CharSequence text) {
textView.setText(text); textView.setText(text);
} }
public void setBackgroundRes(@DrawableRes int resId) {
textView.setBackgroundResource(resId);
}
public void clearBackground() {
textView.setBackground(null);
}
} }
private static class HeaderFooterViewHolder extends RecyclerView.ViewHolder { private static class HeaderFooterViewHolder extends RecyclerView.ViewHolder {

Wyświetl plik

@ -62,6 +62,14 @@ public class ConversationBannerView extends ConstraintLayout {
contactDescription.setText(description); contactDescription.setText(description);
} }
public void showBackgroundBubble(boolean enabled) {
if (enabled) {
setBackgroundResource(R.drawable.wallpaper_bubble_background_12);
} else {
setBackground(null);
}
}
public void hideSubtitle() { public void hideSubtitle() {
contactSubtitle.setVisibility(View.GONE); contactSubtitle.setVisibility(View.GONE);
} }

Wyświetl plik

@ -422,6 +422,7 @@ public class ConversationFragment extends LoggingFragment {
if (recipient != null) { if (recipient != null) {
conversationBanner.setAvatar(GlideApp.with(context), recipient); conversationBanner.setAvatar(GlideApp.with(context), recipient);
conversationBanner.showBackgroundBubble(recipient.hasWallpaper());
String title = isSelf ? context.getString(R.string.note_to_self) : recipient.getDisplayNameOrUsername(context); String title = isSelf ? context.getString(R.string.note_to_self) : recipient.getDisplayNameOrUsername(context);
conversationBanner.setTitle(title); conversationBanner.setTitle(title);

Wyświetl plik

@ -9,8 +9,10 @@ import androidx.annotation.Nullable;
import org.thoughtcrime.securesms.database.ThreadDatabase; import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.mediasend.Media; import org.thoughtcrime.securesms.mediasend.Media;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId; import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.stickers.StickerLocator; import org.thoughtcrime.securesms.stickers.StickerLocator;
import org.thoughtcrime.securesms.wallpaper.ChatWallpaper;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
@ -147,6 +149,11 @@ public class ConversationIntents {
public boolean isFirstTimeInSelfCreatedGroup() { public boolean isFirstTimeInSelfCreatedGroup() {
return firstTimeInSelfCreatedGroup; return firstTimeInSelfCreatedGroup;
} }
public @Nullable ChatWallpaper getWallpaper() {
// TODO [greyson][wallpaper] Is it worth it to do this beforehand?
return Recipient.resolved(recipientId).getWallpaper();
}
} }
public final static class Builder { public final static class Builder {

Wyświetl plik

@ -155,7 +155,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
private boolean groupThread; private boolean groupThread;
private LiveRecipient recipient; private LiveRecipient recipient;
private GlideRequests glideRequests; private GlideRequests glideRequests;
private ValueAnimator pulseOutlinerAlphaAnimator; private ValueAnimator pulseOutlinerAlphaAnimator;
protected ConversationItemBodyBubble bodyBubble; protected ConversationItemBodyBubble bodyBubble;
protected View reply; protected View reply;
@ -165,7 +165,6 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
private ConversationItemFooter footer; private ConversationItemFooter footer;
private ConversationItemFooter stickerFooter; private ConversationItemFooter stickerFooter;
@Nullable private TextView groupSender; @Nullable private TextView groupSender;
@Nullable private TextView groupSenderProfileName;
@Nullable private View groupSenderHolder; @Nullable private View groupSenderHolder;
private AvatarImageView contactPhoto; private AvatarImageView contactPhoto;
private AlertView alertView; private AlertView alertView;
@ -223,7 +222,6 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
this.footer = findViewById(R.id.conversation_item_footer); this.footer = findViewById(R.id.conversation_item_footer);
this.stickerFooter = findViewById(R.id.conversation_item_sticker_footer); this.stickerFooter = findViewById(R.id.conversation_item_sticker_footer);
this.groupSender = findViewById(R.id.group_message_sender); this.groupSender = findViewById(R.id.group_message_sender);
this.groupSenderProfileName = findViewById(R.id.group_message_sender_profile);
this.alertView = findViewById(R.id.indicators_parent); this.alertView = findViewById(R.id.indicators_parent);
this.contactPhoto = findViewById(R.id.contact_photo); this.contactPhoto = findViewById(R.id.contact_photo);
this.contactPhotoHolder = findViewById(R.id.contact_photo_container); this.contactPhotoHolder = findViewById(R.id.contact_photo_container);
@ -256,7 +254,8 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
@NonNull Set<ConversationMessage> batchSelected, @NonNull Set<ConversationMessage> batchSelected,
@NonNull Recipient conversationRecipient, @NonNull Recipient conversationRecipient,
@Nullable String searchQuery, @Nullable String searchQuery,
boolean pulse) boolean pulse,
boolean hasWallpaper)
{ {
if (this.recipient != null) this.recipient.removeForeverObserver(this); if (this.recipient != null) this.recipient.removeForeverObserver(this);
if (this.conversationRecipient != null) this.conversationRecipient.removeForeverObserver(this); if (this.conversationRecipient != null) this.conversationRecipient.removeForeverObserver(this);
@ -279,17 +278,17 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
setMessageShape(messageRecord, previousMessageRecord, nextMessageRecord, groupThread); setMessageShape(messageRecord, previousMessageRecord, nextMessageRecord, groupThread);
setMediaAttributes(messageRecord, previousMessageRecord, nextMessageRecord, conversationRecipient, groupThread); setMediaAttributes(messageRecord, previousMessageRecord, nextMessageRecord, conversationRecipient, groupThread);
setBodyText(messageRecord, searchQuery); setBodyText(messageRecord, searchQuery);
setBubbleState(messageRecord); setBubbleState(messageRecord, hasWallpaper);
setInteractionState(conversationMessage, pulse); setInteractionState(conversationMessage, pulse);
setStatusIcons(messageRecord); setStatusIcons(messageRecord);
setContactPhoto(recipient.get()); setContactPhoto(recipient.get());
setGroupMessageStatus(messageRecord, recipient.get()); setGroupMessageStatus(messageRecord, recipient.get());
setGroupAuthorColor(messageRecord); setGroupAuthorColor(messageRecord, hasWallpaper);
setAuthor(messageRecord, previousMessageRecord, nextMessageRecord, groupThread); setAuthor(messageRecord, previousMessageRecord, nextMessageRecord, groupThread, hasWallpaper);
setQuote(messageRecord, previousMessageRecord, nextMessageRecord, groupThread); setQuote(messageRecord, previousMessageRecord, nextMessageRecord, groupThread);
setMessageSpacing(context, messageRecord, previousMessageRecord, nextMessageRecord, groupThread); setMessageSpacing(context, messageRecord, previousMessageRecord, nextMessageRecord, groupThread);
setReactions(messageRecord); setReactions(messageRecord);
setFooter(messageRecord, nextMessageRecord, locale, groupThread); setFooter(messageRecord, nextMessageRecord, locale, groupThread, hasWallpaper);
} }
@Override @Override
@ -344,12 +343,14 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
} }
} }
ConversationItemFooter activeFooter = getActiveFooter(messageRecord); if (!hasNoBubble(messageRecord)) {
int availableWidth = getAvailableMessageBubbleWidth(footer); ConversationItemFooter activeFooter = getActiveFooter(messageRecord);
int availableWidth = getAvailableMessageBubbleWidth(footer);
if (activeFooter.getVisibility() != GONE && activeFooter.getMeasuredWidth() != availableWidth) { if (activeFooter.getVisibility() != GONE && activeFooter.getMeasuredWidth() != availableWidth) {
activeFooter.getLayoutParams().width = availableWidth; activeFooter.getLayoutParams().width = availableWidth;
needsMeasure = true; needsMeasure = true;
}
} }
if (needsMeasure) { if (needsMeasure) {
@ -366,7 +367,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
@Override @Override
public void onRecipientChanged(@NonNull Recipient modified) { public void onRecipientChanged(@NonNull Recipient modified) {
setBubbleState(messageRecord); setBubbleState(messageRecord, modified.hasWallpaper());
if (recipient.getId().equals(modified.getId())) { if (recipient.getId().equals(modified.getId())) {
setContactPhoto(modified); setContactPhoto(modified);
setGroupMessageStatus(messageRecord, modified); setGroupMessageStatus(messageRecord, modified);
@ -409,16 +410,20 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
/// MessageRecord Attribute Parsers /// MessageRecord Attribute Parsers
private void setBubbleState(MessageRecord messageRecord) { private void setBubbleState(MessageRecord messageRecord, boolean hasWallpaper) {
if (messageRecord.isOutgoing() && !messageRecord.isRemoteDelete()) { if (messageRecord.isOutgoing() && !messageRecord.isRemoteDelete()) {
bodyBubble.getBackground().setColorFilter(defaultBubbleColor, PorterDuff.Mode.MULTIPLY); bodyBubble.getBackground().setColorFilter(defaultBubbleColor, PorterDuff.Mode.MULTIPLY);
footer.setTextColor(ContextCompat.getColor(context, R.color.signal_text_secondary)); footer.setTextColor(ContextCompat.getColor(context, R.color.signal_text_secondary));
footer.setIconColor(ContextCompat.getColor(context, R.color.signal_icon_tint_secondary)); footer.setIconColor(ContextCompat.getColor(context, R.color.signal_icon_tint_secondary));
footer.setOnlyShowSendingStatus(false, messageRecord); footer.setOnlyShowSendingStatus(false, messageRecord);
} else if (messageRecord.isRemoteDelete() || (isViewOnceMessage(messageRecord) && ViewOnceUtil.isViewed((MmsMessageRecord) messageRecord))) { } else if (messageRecord.isRemoteDelete() || (isViewOnceMessage(messageRecord) && ViewOnceUtil.isViewed((MmsMessageRecord) messageRecord))) {
bodyBubble.getBackground().setColorFilter(ContextCompat.getColor(context, R.color.signal_background_primary), PorterDuff.Mode.MULTIPLY); if (hasWallpaper) {
bodyBubble.getBackground().setColorFilter(ContextCompat.getColor(context, R.color.wallpaper_bubble_color), PorterDuff.Mode.SRC_IN);
} else {
bodyBubble.getBackground().setColorFilter(ContextCompat.getColor(context, R.color.signal_background_primary), PorterDuff.Mode.MULTIPLY);
footer.setIconColor(ContextCompat.getColor(context, R.color.signal_icon_tint_secondary));
}
footer.setTextColor(ContextCompat.getColor(context, R.color.signal_text_secondary)); footer.setTextColor(ContextCompat.getColor(context, R.color.signal_text_secondary));
footer.setIconColor(ContextCompat.getColor(context, R.color.signal_icon_tint_secondary));
footer.setOnlyShowSendingStatus(messageRecord.isRemoteDelete(), messageRecord); footer.setOnlyShowSendingStatus(messageRecord.isRemoteDelete(), messageRecord);
} else { } else {
bodyBubble.getBackground().setColorFilter(messageRecord.getRecipient().getColor().toConversationColor(context), PorterDuff.Mode.MULTIPLY); bodyBubble.getBackground().setColorFilter(messageRecord.getRecipient().getColor().toConversationColor(context), PorterDuff.Mode.MULTIPLY);
@ -433,7 +438,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
pulseOutliner.setStrokeWidth(ViewUtil.dpToPx(4)); pulseOutliner.setStrokeWidth(ViewUtil.dpToPx(4));
outliners.clear(); outliners.clear();
if (shouldDrawBodyBubbleOutline(messageRecord)) { if (shouldDrawBodyBubbleOutline(messageRecord, hasWallpaper)) {
outliners.add(outliner); outliners.add(outliner);
} }
outliners.add(pulseOutliner); outliners.add(pulseOutliner);
@ -515,9 +520,13 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
pulseOutliner.setAlpha(0); pulseOutliner.setAlpha(0);
} }
private boolean shouldDrawBodyBubbleOutline(MessageRecord messageRecord) { private boolean shouldDrawBodyBubbleOutline(MessageRecord messageRecord, boolean hasWallpaper) {
boolean isIncomingViewedOnce = !messageRecord.isOutgoing() && isViewOnceMessage(messageRecord) && ViewOnceUtil.isViewed((MmsMessageRecord) messageRecord); if (hasWallpaper) {
return isIncomingViewedOnce || messageRecord.isRemoteDelete(); return false;
} else {
boolean isIncomingViewedOnce = !messageRecord.isOutgoing() && isViewOnceMessage(messageRecord) && ViewOnceUtil.isViewed((MmsMessageRecord) messageRecord);
return isIncomingViewedOnce || messageRecord.isRemoteDelete();
}
} }
private boolean isCaptionlessMms(MessageRecord messageRecord) { private boolean isCaptionlessMms(MessageRecord messageRecord) {
@ -543,6 +552,10 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
((MmsMessageRecord)messageRecord).getSlideDeck().getThumbnailSlide().isBorderless(); ((MmsMessageRecord)messageRecord).getSlideDeck().getThumbnailSlide().isBorderless();
} }
private boolean hasNoBubble(MessageRecord messageRecord) {
return hasSticker(messageRecord) || isBorderless(messageRecord);
}
private boolean hasOnlyThumbnail(MessageRecord messageRecord) { private boolean hasOnlyThumbnail(MessageRecord messageRecord) {
return hasThumbnail(messageRecord) && return hasThumbnail(messageRecord) &&
!hasAudio(messageRecord) && !hasAudio(messageRecord) &&
@ -1074,7 +1087,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
}); });
} }
private void setFooter(@NonNull MessageRecord current, @NonNull Optional<MessageRecord> next, @NonNull Locale locale, boolean isGroupThread) { private void setFooter(@NonNull MessageRecord current, @NonNull Optional<MessageRecord> next, @NonNull Locale locale, boolean isGroupThread, boolean hasWallpaper) {
ViewUtil.updateLayoutParams(footer, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); ViewUtil.updateLayoutParams(footer, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
footer.setVisibility(GONE); footer.setVisibility(GONE);
@ -1090,11 +1103,27 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
ConversationItemFooter activeFooter = getActiveFooter(current); ConversationItemFooter activeFooter = getActiveFooter(current);
activeFooter.setVisibility(VISIBLE); activeFooter.setVisibility(VISIBLE);
activeFooter.setMessageRecord(current, locale); activeFooter.setMessageRecord(current, locale);
if (hasWallpaper && hasNoBubble((messageRecord))) {
if (messageRecord.isOutgoing()) {
activeFooter.enableBubbleBackground(R.drawable.wallpaper_bubble_background_tintable_11, defaultBubbleColor);
} else {
activeFooter.enableBubbleBackground(R.drawable.wallpaper_bubble_background_tintable_11, messageRecord.getRecipient().getColor().toConversationColor(context));
activeFooter.setTextColor(ContextCompat.getColor(context, R.color.conversation_item_received_text_secondary_color));
activeFooter.setIconColor(ContextCompat.getColor(context, R.color.conversation_item_received_text_secondary_color));
}
} else if (hasNoBubble(messageRecord)){
activeFooter.disableBubbleBackground();
activeFooter.setTextColor(ContextCompat.getColor(context, R.color.signal_text_secondary));
activeFooter.setIconColor(ContextCompat.getColor(context, R.color.signal_icon_tint_secondary));
} else {
activeFooter.disableBubbleBackground();
}
} }
} }
private ConversationItemFooter getActiveFooter(@NonNull MessageRecord messageRecord) { private ConversationItemFooter getActiveFooter(@NonNull MessageRecord messageRecord) {
if (hasSticker(messageRecord) || isBorderless(messageRecord)) { if (hasNoBubble(messageRecord)) {
return stickerFooter; return stickerFooter;
} else if (hasSharedContact(messageRecord) && TextUtils.isEmpty(messageRecord.getDisplayBody(getContext()))) { } else if (hasSharedContact(messageRecord) && TextUtils.isEmpty(messageRecord.getDisplayBody(getContext()))) {
return sharedContactStub.get().getFooter(); return sharedContactStub.get().getFooter();
@ -1118,30 +1147,27 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
private void setGroupMessageStatus(MessageRecord messageRecord, Recipient recipient) { private void setGroupMessageStatus(MessageRecord messageRecord, Recipient recipient) {
if (groupThread && !messageRecord.isOutgoing() && groupSender != null && groupSenderProfileName != null) { if (groupThread && !messageRecord.isOutgoing() && groupSender != null) {
groupSender.setText(recipient.getDisplayName(getContext())); groupSender.setText(recipient.getDisplayName(getContext()));
groupSenderProfileName.setVisibility(View.GONE);
} }
} }
private void setGroupAuthorColor(@NonNull MessageRecord messageRecord) { private void setGroupAuthorColor(@NonNull MessageRecord messageRecord, boolean hasWallpaper) {
if (groupSender != null && groupSenderProfileName != null) { if (groupSender != null) {
int stickerAuthorColor = ContextCompat.getColor(context, R.color.signal_text_primary); int stickerAuthorColor = ContextCompat.getColor(context, R.color.signal_text_primary);
if (shouldDrawBodyBubbleOutline(messageRecord)) {
if (shouldDrawBodyBubbleOutline(messageRecord, hasWallpaper)) {
groupSender.setTextColor(stickerAuthorColor); groupSender.setTextColor(stickerAuthorColor);
groupSenderProfileName.setTextColor(stickerAuthorColor); } else if (!hasWallpaper && hasNoBubble(messageRecord)) {
} else if (hasSticker(messageRecord) || isBorderless(messageRecord)) {
groupSender.setTextColor(stickerAuthorColor); groupSender.setTextColor(stickerAuthorColor);
groupSenderProfileName.setTextColor(stickerAuthorColor);
} else { } else {
groupSender.setTextColor(ContextCompat.getColor(context, R.color.conversation_item_received_text_primary_color)); groupSender.setTextColor(ContextCompat.getColor(context, R.color.conversation_item_received_text_primary_color));
groupSenderProfileName.setTextColor(ContextCompat.getColor(context, R.color.conversation_item_received_text_primary_color));
} }
} }
} }
@SuppressWarnings("ConstantConditions") @SuppressWarnings("ConstantConditions")
private void setAuthor(@NonNull MessageRecord current, @NonNull Optional<MessageRecord> previous, @NonNull Optional<MessageRecord> next, boolean isGroupThread) { private void setAuthor(@NonNull MessageRecord current, @NonNull Optional<MessageRecord> previous, @NonNull Optional<MessageRecord> next, boolean isGroupThread, boolean hasWallpaper) {
if (isGroupThread && !current.isOutgoing()) { if (isGroupThread && !current.isOutgoing()) {
contactPhotoHolder.setVisibility(VISIBLE); contactPhotoHolder.setVisibility(VISIBLE);
@ -1149,6 +1175,13 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
!DateUtils.isSameDay(previous.get().getTimestamp(), current.getTimestamp())) !DateUtils.isSameDay(previous.get().getTimestamp(), current.getTimestamp()))
{ {
groupSenderHolder.setVisibility(VISIBLE); groupSenderHolder.setVisibility(VISIBLE);
if (hasWallpaper && hasNoBubble(current)) {
groupSenderHolder.setBackgroundResource(R.drawable.wallpaper_bubble_background_tintable_11);
groupSenderHolder.getBackground().setColorFilter(messageRecord.getRecipient().getColor().toConversationColor(context), PorterDuff.Mode.MULTIPLY);
} else {
groupSenderHolder.setBackground(null);
}
} else { } else {
groupSenderHolder.setVisibility(GONE); groupSenderHolder.setVisibility(GONE);
} }

Wyświetl plik

@ -5,7 +5,7 @@ import android.text.Spannable;
import android.text.SpannableString; import android.text.SpannableString;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.View; import android.view.View;
import android.widget.LinearLayout; import android.widget.FrameLayout;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@ -41,7 +41,7 @@ import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
public final class ConversationUpdateItem extends LinearLayout public final class ConversationUpdateItem extends FrameLayout
implements BindableConversationItem implements BindableConversationItem
{ {
private static final String TAG = ConversationUpdateItem.class.getSimpleName(); private static final String TAG = ConversationUpdateItem.class.getSimpleName();
@ -50,6 +50,7 @@ public final class ConversationUpdateItem extends LinearLayout
private TextView body; private TextView body;
private TextView actionButton; private TextView actionButton;
private View background;
private ConversationMessage conversationMessage; private ConversationMessage conversationMessage;
private Recipient conversationRecipient; private Recipient conversationRecipient;
private Optional<MessageRecord> nextMessageRecord; private Optional<MessageRecord> nextMessageRecord;
@ -76,6 +77,7 @@ public final class ConversationUpdateItem extends LinearLayout
super.onFinishInflate(); super.onFinishInflate();
this.body = findViewById(R.id.conversation_update_body); this.body = findViewById(R.id.conversation_update_body);
this.actionButton = findViewById(R.id.conversation_update_action); this.actionButton = findViewById(R.id.conversation_update_action);
this.background = findViewById(R.id.conversation_update_background);
this.setOnClickListener(new InternalClickListener(null)); this.setOnClickListener(new InternalClickListener(null));
} }
@ -90,11 +92,12 @@ public final class ConversationUpdateItem extends LinearLayout
@NonNull Set<ConversationMessage> batchSelected, @NonNull Set<ConversationMessage> batchSelected,
@NonNull Recipient conversationRecipient, @NonNull Recipient conversationRecipient,
@Nullable String searchQuery, @Nullable String searchQuery,
boolean pulseMention) boolean pulseMention,
boolean hasWallpaper)
{ {
this.batchSelected = batchSelected; this.batchSelected = batchSelected;
bind(lifecycleOwner, conversationMessage, nextMessageRecord, conversationRecipient); bind(lifecycleOwner, conversationMessage, nextMessageRecord, conversationRecipient, hasWallpaper);
} }
@Override @Override
@ -110,7 +113,8 @@ public final class ConversationUpdateItem extends LinearLayout
private void bind(@NonNull LifecycleOwner lifecycleOwner, private void bind(@NonNull LifecycleOwner lifecycleOwner,
@NonNull ConversationMessage conversationMessage, @NonNull ConversationMessage conversationMessage,
@NonNull Optional<MessageRecord> nextMessageRecord, @NonNull Optional<MessageRecord> nextMessageRecord,
@NonNull Recipient conversationRecipient) @NonNull Recipient conversationRecipient,
boolean hasWallpaper)
{ {
this.conversationMessage = conversationMessage; this.conversationMessage = conversationMessage;
this.messageRecord = conversationMessage.getMessageRecord(); this.messageRecord = conversationMessage.getMessageRecord();
@ -125,6 +129,12 @@ public final class ConversationUpdateItem extends LinearLayout
groupObserver.observe(lifecycleOwner, null); groupObserver.observe(lifecycleOwner, null);
} }
if (hasWallpaper) {
background.setBackgroundResource(R.drawable.wallpaper_bubble_background_12);
} else {
background.setBackground(null);
}
UpdateDescription updateDescription = Objects.requireNonNull(messageRecord.getUpdateDisplayBody(getContext())); UpdateDescription updateDescription = Objects.requireNonNull(messageRecord.getUpdateDisplayBody(getContext()));
LiveData<Spannable> liveUpdateMessage = LiveUpdateMessage.fromMessageDescription(getContext(), updateDescription, ContextCompat.getColor(getContext(), R.color.conversation_item_update_text_color)); LiveData<Spannable> liveUpdateMessage = LiveUpdateMessage.fromMessageDescription(getContext(), updateDescription, ContextCompat.getColor(getContext(), R.color.conversation_item_update_text_color));
LiveData<Spannable> spannableMessage = loading(liveUpdateMessage); LiveData<Spannable> spannableMessage = loading(liveUpdateMessage);

Wyświetl plik

@ -359,7 +359,7 @@ public class RecipientDatabase extends Database {
LAST_GV1_MIGRATE_REMINDER + " INTEGER DEFAULT 0, " + LAST_GV1_MIGRATE_REMINDER + " INTEGER DEFAULT 0, " +
LAST_SESSION_RESET + " BLOB DEFAULT NULL, " + LAST_SESSION_RESET + " BLOB DEFAULT NULL, " +
WALLPAPER + " BLOB DEFAULT NULL, " + WALLPAPER + " BLOB DEFAULT NULL, " +
WALLPAPER_URI + " TEXT DEFAULT NULL);"; WALLPAPER_URI + " TEXT DEFAULT NULL);";
private static final String INSIGHTS_INVITEE_LIST = "SELECT " + TABLE_NAME + "." + ID + private static final String INSIGHTS_INVITEE_LIST = "SELECT " + TABLE_NAME + "." + ID +
" FROM " + TABLE_NAME + " FROM " + TABLE_NAME +
@ -1799,14 +1799,60 @@ public class RecipientDatabase extends Database {
} }
} }
public void setWallpaper(@NonNull RecipientId id, @NonNull ChatWallpaper chatWallpaper) { public void resetAllWallpaper() {
Wallpaper wallpaper = chatWallpaper.serialize(); SQLiteDatabase database = databaseHelper.getWritableDatabase();
Uri existingWallpaperUri = getWallpaperUri(id); String[] selection = SqlUtil.buildArgs(ID, WALLPAPER_URI);
String where = WALLPAPER + " IS NOT NULL";
List<Pair<RecipientId, String>> idWithWallpaper = new LinkedList<>();
database.beginTransaction();
try {
try (Cursor cursor = database.query(TABLE_NAME, selection, where, null, null, null, null)) {
while (cursor != null && cursor.moveToNext()) {
idWithWallpaper.add(new Pair<>(RecipientId.from(CursorUtil.requireInt(cursor, ID)),
CursorUtil.getString(cursor, WALLPAPER_URI).orNull()));
}
}
if (idWithWallpaper.isEmpty()) {
return;
}
ContentValues values = new ContentValues(2);
values.put(WALLPAPER_URI, (String) null);
values.put(WALLPAPER, (byte[]) null);
int rowsUpdated = database.update(TABLE_NAME, values, where, null);
if (rowsUpdated == idWithWallpaper.size()) {
for (Pair<RecipientId, String> pair : idWithWallpaper) {
Recipient.live(pair.first()).refresh();
if (pair.second() != null) {
WallpaperStorage.onWallpaperDeselected(context, Uri.parse(pair.second()));
}
}
} else {
throw new AssertionError("expected " + idWithWallpaper.size() + " but got " + rowsUpdated);
}
} finally {
database.setTransactionSuccessful();
database.endTransaction();
}
}
public void setWallpaper(@NonNull RecipientId id, @Nullable ChatWallpaper chatWallpaper) {
setWallpaper(id, chatWallpaper != null ? chatWallpaper.serialize() : null);
}
private void setWallpaper(@NonNull RecipientId id, @Nullable Wallpaper wallpaper) {
Uri existingWallpaperUri = getWallpaperUri(id);
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
values.put(WALLPAPER, wallpaper.toByteArray()); values.put(WALLPAPER, wallpaper != null ? wallpaper.toByteArray() : null);
if (wallpaper.hasFile()) { if (wallpaper != null && wallpaper.hasFile()) {
values.put(WALLPAPER_URI, wallpaper.getFile().getUri()); values.put(WALLPAPER_URI, wallpaper.getFile().getUri());
} else { } else {
values.putNull(WALLPAPER_URI); values.putNull(WALLPAPER_URI);
@ -1821,15 +1867,33 @@ public class RecipientDatabase extends Database {
} }
} }
private @Nullable Uri getWallpaperUri(@NonNull RecipientId id) { public void setDimWallpaperInDarkTheme(@NonNull RecipientId id, boolean enabled) {
Wallpaper wallpaper = getWallpaper(id);
if (wallpaper == null) {
throw new IllegalStateException("No wallpaper set for " + id);
}
Wallpaper updated = wallpaper.toBuilder()
.setDimLevelInDarkTheme(enabled ? ChatWallpaper.FIXED_DIM_LEVEL_FOR_DARK_THEME : 0)
.build();
setWallpaper(id, updated);
}
private @Nullable Wallpaper getWallpaper(@NonNull RecipientId id) {
SQLiteDatabase db = databaseHelper.getReadableDatabase(); SQLiteDatabase db = databaseHelper.getReadableDatabase();
try (Cursor cursor = db.query(TABLE_NAME, new String[] {WALLPAPER_URI}, ID_WHERE, SqlUtil.buildArgs(id), null, null, null)) { try (Cursor cursor = db.query(TABLE_NAME, new String[] {WALLPAPER}, ID_WHERE, SqlUtil.buildArgs(id), null, null, null)) {
if (cursor.moveToFirst()) { if (cursor.moveToFirst()) {
String raw = CursorUtil.requireString(cursor, WALLPAPER_URI); byte[] raw = CursorUtil.requireBlob(cursor, WALLPAPER);
if (raw != null) { if (raw != null) {
return Uri.parse(raw); try {
return Wallpaper.parseFrom(raw);
} catch (InvalidProtocolBufferException e) {
return null;
}
} else { } else {
return null; return null;
} }
@ -1839,12 +1903,22 @@ public class RecipientDatabase extends Database {
return null; return null;
} }
private @Nullable Uri getWallpaperUri(@NonNull RecipientId id) {
Wallpaper wallpaper = getWallpaper(id);
if (wallpaper != null && wallpaper.hasFile()) {
return Uri.parse(wallpaper.getFile().getUri());
} else {
return null;
}
}
public int getWallpaperUriUsageCount(@NonNull Uri uri) { public int getWallpaperUriUsageCount(@NonNull Uri uri) {
SQLiteDatabase db = databaseHelper.getReadableDatabase(); SQLiteDatabase db = databaseHelper.getReadableDatabase();
String query = WALLPAPER_URI + " = ?"; String query = WALLPAPER_URI + " = ?";
String[] args = SqlUtil.buildArgs(uri); String[] args = SqlUtil.buildArgs(uri);
try (Cursor cursor = db.query(TABLE_NAME, new String[] { "COUNT(*)"}, query, args, null, null, null)) { try (Cursor cursor = db.query(TABLE_NAME, new String[] { "COUNT(*)" }, query, args, null, null, null)) {
if (cursor.moveToFirst()) { if (cursor.moveToFirst()) {
return cursor.getInt(0); return cursor.getInt(0);
} }

Wyświetl plik

@ -62,6 +62,7 @@ import org.thoughtcrime.securesms.util.FeatureFlags;
import org.thoughtcrime.securesms.util.LifecycleCursorWrapper; import org.thoughtcrime.securesms.util.LifecycleCursorWrapper;
import org.thoughtcrime.securesms.util.views.LearnMoreTextView; import org.thoughtcrime.securesms.util.views.LearnMoreTextView;
import org.thoughtcrime.securesms.util.views.SimpleProgressDialog; import org.thoughtcrime.securesms.util.views.SimpleProgressDialog;
import org.thoughtcrime.securesms.wallpaper.ChatWallpaperActivity;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
@ -114,6 +115,7 @@ public class ManageGroupFragment extends LoggingFragment {
private View toggleAllMembers; private View toggleAllMembers;
private View groupLinkRow; private View groupLinkRow;
private TextView groupLinkButton; private TextView groupLinkButton;
private View wallpaperButton;
private final Recipient.FallbackPhotoProvider fallbackPhotoProvider = new Recipient.FallbackPhotoProvider() { private final Recipient.FallbackPhotoProvider fallbackPhotoProvider = new Recipient.FallbackPhotoProvider() {
@Override @Override
@ -175,6 +177,7 @@ public class ManageGroupFragment extends LoggingFragment {
toggleAllMembers = view.findViewById(R.id.toggle_all_members); toggleAllMembers = view.findViewById(R.id.toggle_all_members);
groupLinkRow = view.findViewById(R.id.group_link_row); groupLinkRow = view.findViewById(R.id.group_link_row);
groupLinkButton = view.findViewById(R.id.group_link_button); groupLinkButton = view.findViewById(R.id.group_link_button);
wallpaperButton = view.findViewById(R.id.chat_wallpaper);
return view; return view;
} }
@ -240,6 +243,7 @@ public class ManageGroupFragment extends LoggingFragment {
}); });
customNotificationsRow.setOnClickListener(v -> CustomNotificationsDialogFragment.create(groupRecipient.getId()) customNotificationsRow.setOnClickListener(v -> CustomNotificationsDialogFragment.create(groupRecipient.getId())
.show(requireFragmentManager(), DIALOG_TAG)); .show(requireFragmentManager(), DIALOG_TAG));
wallpaperButton.setOnClickListener(v -> startActivity(ChatWallpaperActivity.createIntent(requireContext(), groupRecipient.getId())));
}); });
if (groupId.isV2()) { if (groupId.isV2()) {

Wyświetl plik

@ -27,7 +27,6 @@ public final class WallpaperValues extends SignalStoreValues {
@Override @Override
void onFirstEverAppLaunch() { void onFirstEverAppLaunch() {
} }
public void setWallpaper(@NonNull Context context, @Nullable ChatWallpaper wallpaper) { public void setWallpaper(@NonNull Context context, @Nullable ChatWallpaper wallpaper) {
@ -44,7 +43,9 @@ public final class WallpaperValues extends SignalStoreValues {
getStore().beginWrite().remove(KEY_WALLPAPER).apply(); getStore().beginWrite().remove(KEY_WALLPAPER).apply();
} }
WallpaperStorage.onWallpaperDeselected(context, currentUri); if (currentUri != null) {
WallpaperStorage.onWallpaperDeselected(context, currentUri);
}
} }
public @Nullable ChatWallpaper getWallpaper() { public @Nullable ChatWallpaper getWallpaper() {
@ -57,7 +58,30 @@ public final class WallpaperValues extends SignalStoreValues {
} }
} }
public @Nullable Uri getCurrentWallpaperUri() { public boolean hasWallpaperSet() {
return getStore().getBlob(KEY_WALLPAPER, null) != null;
}
public void setDimInDarkTheme(boolean enabled) {
Wallpaper currentWallpaper = getCurrentWallpaper();
if (currentWallpaper != null) {
putBlob(KEY_WALLPAPER,
currentWallpaper.toBuilder()
.setDimLevelInDarkTheme(enabled ? 0.2f : 0)
.build()
.toByteArray());
} else {
throw new IllegalStateException("No wallpaper currently set!");
}
}
/**
* Retrieves the URI of the current wallpaper. Note that this will only return a value if the
* wallpaper is both set *and* it's an image.
*/
public @Nullable Uri getWallpaperUri() {
Wallpaper currentWallpaper = getCurrentWallpaper(); Wallpaper currentWallpaper = getCurrentWallpaper();
if (currentWallpaper != null && currentWallpaper.hasFile()) { if (currentWallpaper != null && currentWallpaper.hasFile()) {

Wyświetl plik

@ -88,7 +88,7 @@ final class MessageHeaderViewHolder extends RecyclerView.ViewHolder {
conversationItem = (ConversationItem) receivedStub.inflate(); conversationItem = (ConversationItem) receivedStub.inflate();
} }
} }
conversationItem.bind(lifecycleOwner, conversationMessage, Optional.absent(), Optional.absent(), glideRequests, Locale.getDefault(), new HashSet<>(), conversationMessage.getMessageRecord().getRecipient(), null, false); conversationItem.bind(lifecycleOwner, conversationMessage, Optional.absent(), Optional.absent(), glideRequests, Locale.getDefault(), new HashSet<>(), conversationMessage.getMessageRecord().getRecipient(), null, false, false);
} }
private void bindErrorState(MessageRecord messageRecord) { private void bindErrorState(MessageRecord messageRecord) {

Wyświetl plik

@ -8,6 +8,7 @@ import androidx.preference.ListPreference;
import org.thoughtcrime.securesms.ApplicationPreferencesActivity; import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.util.ActivityTransitionUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.wallpaper.ChatWallpaperActivity; import org.thoughtcrime.securesms.wallpaper.ChatWallpaperActivity;
@ -24,7 +25,8 @@ public class AppearancePreferenceFragment extends ListSummaryPreferenceFragment
this.findPreference(TextSecurePreferences.THEME_PREF).setOnPreferenceChangeListener(new ListSummaryListener()); this.findPreference(TextSecurePreferences.THEME_PREF).setOnPreferenceChangeListener(new ListSummaryListener());
this.findPreference(TextSecurePreferences.LANGUAGE_PREF).setOnPreferenceChangeListener(new ListSummaryListener()); this.findPreference(TextSecurePreferences.LANGUAGE_PREF).setOnPreferenceChangeListener(new ListSummaryListener());
this.findPreference(WALLPAPER_PREF).setOnPreferenceClickListener(preference -> { this.findPreference(WALLPAPER_PREF).setOnPreferenceClickListener(preference -> {
startActivity(ChatWallpaperActivity.getIntent(requireContext())); startActivity(ChatWallpaperActivity.createIntent(requireContext()));
ActivityTransitionUtil.setSlideInTransition(requireActivity());
return true; return true;
}); });
initializeListSummary((ListPreference)findPreference(TextSecurePreferences.THEME_PREF)); initializeListSummary((ListPreference)findPreference(TextSecurePreferences.THEME_PREF));

Wyświetl plik

@ -848,7 +848,18 @@ public class Recipient {
} }
public @Nullable ChatWallpaper getWallpaper() { public @Nullable ChatWallpaper getWallpaper() {
return wallpaper; if (wallpaper != null) {
return wallpaper;
} else {
return SignalStore.wallpaper().getWallpaper();
}
}
/**
* A cheap way to check if wallpaper is set without doing any unnecessary proto parsing.
*/
public boolean hasWallpaper() {
return wallpaper != null || SignalStore.wallpaper().hasWallpaperSet();
} }
public boolean isSystemContact() { public boolean isSystemContact() {

Wyświetl plik

@ -54,6 +54,7 @@ import org.thoughtcrime.securesms.util.DateUtils;
import org.thoughtcrime.securesms.util.LifecycleCursorWrapper; import org.thoughtcrime.securesms.util.LifecycleCursorWrapper;
import org.thoughtcrime.securesms.util.ServiceUtil; import org.thoughtcrime.securesms.util.ServiceUtil;
import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.wallpaper.ChatWallpaperActivity;
import java.util.Locale; import java.util.Locale;
import java.util.Objects; import java.util.Objects;
@ -105,6 +106,7 @@ public class ManageRecipientFragment extends LoggingFragment {
private View secureCallButton; private View secureCallButton;
private View insecureCallButton; private View insecureCallButton;
private View secureVideoCallButton; private View secureVideoCallButton;
private View chatWallpaperButton;
static ManageRecipientFragment newInstance(@NonNull RecipientId recipientId, boolean fromConversation) { static ManageRecipientFragment newInstance(@NonNull RecipientId recipientId, boolean fromConversation) {
ManageRecipientFragment fragment = new ManageRecipientFragment(); ManageRecipientFragment fragment = new ManageRecipientFragment();
@ -161,6 +163,7 @@ public class ManageRecipientFragment extends LoggingFragment {
secureCallButton = view.findViewById(R.id.recipient_voice_call); secureCallButton = view.findViewById(R.id.recipient_voice_call);
insecureCallButton = view.findViewById(R.id.recipient_insecure_voice_call); insecureCallButton = view.findViewById(R.id.recipient_insecure_voice_call);
secureVideoCallButton = view.findViewById(R.id.recipient_video_call); secureVideoCallButton = view.findViewById(R.id.recipient_video_call);
chatWallpaperButton = view.findViewById(R.id.chat_wallpaper);
return view; return view;
} }
@ -270,6 +273,7 @@ public class ManageRecipientFragment extends LoggingFragment {
secureCallButton.setOnClickListener(v -> viewModel.onSecureCall(requireActivity())); secureCallButton.setOnClickListener(v -> viewModel.onSecureCall(requireActivity()));
insecureCallButton.setOnClickListener(v -> viewModel.onInsecureCall(requireActivity())); insecureCallButton.setOnClickListener(v -> viewModel.onInsecureCall(requireActivity()));
secureVideoCallButton.setOnClickListener(v -> viewModel.onSecureVideoCall(requireActivity())); secureVideoCallButton.setOnClickListener(v -> viewModel.onSecureVideoCall(requireActivity()));
chatWallpaperButton.setOnClickListener(v -> startActivity(ChatWallpaperActivity.createIntent(requireContext(), recipientId)));
} }
@Override @Override

Wyświetl plik

@ -0,0 +1,26 @@
package org.thoughtcrime.securesms.util;
import androidx.activity.ComponentActivity;
import androidx.annotation.NonNull;
import org.thoughtcrime.securesms.R;
public final class ActivityTransitionUtil {
private ActivityTransitionUtil() {}
/**
* To be used with finish
*/
public static void setSlideOutTransition(@NonNull ComponentActivity activity) {
activity.overridePendingTransition(R.anim.slide_from_start, R.anim.slide_to_end);
}
/**
* To be used with startActivity
*/
public static void setSlideInTransition(@NonNull ComponentActivity activity) {
activity.overridePendingTransition(R.anim.slide_from_end, R.anim.slide_to_start);
}
}

Wyświetl plik

@ -12,20 +12,31 @@ import java.util.List;
public interface ChatWallpaper extends Parcelable { public interface ChatWallpaper extends Parcelable {
List<ChatWallpaper> BUILTINS = Arrays.asList(GradientChatWallpaper.SOLID_1, float FIXED_DIM_LEVEL_FOR_DARK_THEME = 0.2f;
GradientChatWallpaper.SOLID_2,
GradientChatWallpaper.SOLID_3, List<ChatWallpaper> BUILTINS = Arrays.asList(SingleColorChatWallpaper.SOLID_1,
GradientChatWallpaper.SOLID_4, SingleColorChatWallpaper.SOLID_2,
GradientChatWallpaper.SOLID_5, SingleColorChatWallpaper.SOLID_3,
GradientChatWallpaper.SOLID_6, SingleColorChatWallpaper.SOLID_4,
GradientChatWallpaper.SOLID_7, SingleColorChatWallpaper.SOLID_5,
GradientChatWallpaper.SOLID_8, SingleColorChatWallpaper.SOLID_6,
GradientChatWallpaper.SOLID_9, SingleColorChatWallpaper.SOLID_7,
GradientChatWallpaper.SOLID_10, SingleColorChatWallpaper.SOLID_8,
GradientChatWallpaper.SOLID_11, SingleColorChatWallpaper.SOLID_9,
GradientChatWallpaper.SOLID_12, SingleColorChatWallpaper.SOLID_10,
SingleColorChatWallpaper.SOLID_11,
SingleColorChatWallpaper.SOLID_12,
GradientChatWallpaper.GRADIENT_1, GradientChatWallpaper.GRADIENT_1,
GradientChatWallpaper.GRADIENT_2); GradientChatWallpaper.GRADIENT_2,
GradientChatWallpaper.GRADIENT_3,
GradientChatWallpaper.GRADIENT_4,
GradientChatWallpaper.GRADIENT_5,
GradientChatWallpaper.GRADIENT_6,
GradientChatWallpaper.GRADIENT_7,
GradientChatWallpaper.GRADIENT_8,
GradientChatWallpaper.GRADIENT_9);
float getDimLevelForDarkTheme();
void loadInto(@NonNull ImageView imageView); void loadInto(@NonNull ImageView imageView);

Wyświetl plik

@ -14,6 +14,7 @@ import androidx.navigation.Navigation;
import org.thoughtcrime.securesms.PassphraseRequiredActivity; import org.thoughtcrime.securesms.PassphraseRequiredActivity;
import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.recipients.RecipientId; import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.ActivityTransitionUtil;
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme; import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
import org.thoughtcrime.securesms.util.DynamicTheme; import org.thoughtcrime.securesms.util.DynamicTheme;
@ -23,11 +24,11 @@ public final class ChatWallpaperActivity extends PassphraseRequiredActivity {
private final DynamicTheme dynamicTheme = new DynamicNoActionBarTheme(); private final DynamicTheme dynamicTheme = new DynamicNoActionBarTheme();
public static @NonNull Intent getIntent(@NonNull Context context) { public static @NonNull Intent createIntent(@NonNull Context context) {
return getIntent(context, null); return createIntent(context, null);
} }
public static @NonNull Intent getIntent(@NonNull Context context, @Nullable RecipientId recipientId) { public static @NonNull Intent createIntent(@NonNull Context context, @Nullable RecipientId recipientId) {
Intent intent = new Intent(context, ChatWallpaperActivity.class); Intent intent = new Intent(context, ChatWallpaperActivity.class);
intent.putExtra(EXTRA_RECIPIENT_ID, recipientId); intent.putExtra(EXTRA_RECIPIENT_ID, recipientId);
return intent; return intent;
@ -35,8 +36,7 @@ public final class ChatWallpaperActivity extends PassphraseRequiredActivity {
@Override @Override
protected void onCreate(Bundle savedInstanceState, boolean ready) { protected void onCreate(Bundle savedInstanceState, boolean ready) {
ChatWallpaperViewModel.Factory factory = new ChatWallpaperViewModel.Factory(getIntent(this).getParcelableExtra(EXTRA_RECIPIENT_ID)); ChatWallpaperViewModel.Factory factory = new ChatWallpaperViewModel.Factory(getIntent().getParcelableExtra(EXTRA_RECIPIENT_ID));
ViewModelProviders.of(this, factory).get(ChatWallpaperViewModel.class); ViewModelProviders.of(this, factory).get(ChatWallpaperViewModel.class);
dynamicTheme.onCreate(this); dynamicTheme.onCreate(this);
@ -47,6 +47,7 @@ public final class ChatWallpaperActivity extends PassphraseRequiredActivity {
toolbar.setNavigationOnClickListener(unused -> { toolbar.setNavigationOnClickListener(unused -> {
if (!Navigation.findNavController(this, R.id.nav_host_fragment).popBackStack()) { if (!Navigation.findNavController(this, R.id.nav_host_fragment).popBackStack()) {
finish(); finish();
ActivityTransitionUtil.setSlideOutTransition(this);
} }
}); });
@ -58,6 +59,12 @@ public final class ChatWallpaperActivity extends PassphraseRequiredActivity {
} }
} }
@Override
public void onBackPressed() {
super.onBackPressed();
ActivityTransitionUtil.setSlideOutTransition(this);
}
@Override @Override
protected void onResume() { protected void onResume() {
super.onResume(); super.onResume();

Wyświetl plik

@ -0,0 +1,22 @@
package org.thoughtcrime.securesms.wallpaper;
import android.view.View;
import androidx.annotation.NonNull;
import org.thoughtcrime.securesms.util.ThemeUtil;
public final class ChatWallpaperDimLevelUtil {
private ChatWallpaperDimLevelUtil() {
}
public static void applyDimLevelForNightMode(@NonNull View dimmer, @NonNull ChatWallpaper chatWallpaper) {
if (ThemeUtil.isDarkTheme(dimmer.getContext())) {
dimmer.setAlpha(chatWallpaper.getDimLevelForDarkTheme());
dimmer.setVisibility(View.VISIBLE);
} else {
dimmer.setVisibility(View.GONE);
}
}
}

Wyświetl plik

@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.wallpaper;
import android.net.Uri; import android.net.Uri;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import org.thoughtcrime.securesms.database.model.databaseprotos.Wallpaper; import org.thoughtcrime.securesms.database.model.databaseprotos.Wallpaper;
@ -9,25 +10,37 @@ import org.thoughtcrime.securesms.database.model.databaseprotos.Wallpaper;
/** /**
* Converts persisted models of wallpaper into usable {@link ChatWallpaper} instances. * Converts persisted models of wallpaper into usable {@link ChatWallpaper} instances.
*/ */
public class ChatWallpaperFactory { public final class ChatWallpaperFactory {
private ChatWallpaperFactory() {}
public static @NonNull ChatWallpaper create(@NonNull Wallpaper model) { public static @NonNull ChatWallpaper create(@NonNull Wallpaper model) {
if (model.hasSingleColor()) { if (model.hasSingleColor()) {
return new GradientChatWallpaper(model.getSingleColor().getColor()); return buildForSingleColor(model.getSingleColor(), model.getDimLevelInDarkTheme());
} else if (model.hasLinearGradient()) { } else if (model.hasLinearGradient()) {
return buildForLinearGradinent(model.getLinearGradient()); return buildForLinearGradinent(model.getLinearGradient(), model.getDimLevelInDarkTheme());
} else if (model.hasFile()) { } else if (model.hasFile()) {
return buildForFile(model.getFile()); return buildForFile(model.getFile(), model.getDimLevelInDarkTheme());
} else { } else {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
} }
public static @NonNull ChatWallpaper create(@NonNull Uri uri) { public static @NonNull ChatWallpaper updateWithDimming(@NonNull ChatWallpaper wallpaper, float dimLevelInDarkTheme) {
return new UriChatWallpaper(uri); Wallpaper model = wallpaper.serialize();
return create(model.toBuilder().setDimLevelInDarkTheme(dimLevelInDarkTheme).build());
} }
private static @NonNull ChatWallpaper buildForLinearGradinent(@NonNull Wallpaper.LinearGradient gradient) { public static @NonNull ChatWallpaper create(@NonNull Uri uri) {
return new UriChatWallpaper(uri, 0f);
}
private static @NonNull ChatWallpaper buildForSingleColor(@NonNull Wallpaper.SingleColor singleColor, float dimLevelInDarkTheme) {
return new SingleColorChatWallpaper(singleColor.getColor(), dimLevelInDarkTheme);
}
private static @NonNull ChatWallpaper buildForLinearGradinent(@NonNull Wallpaper.LinearGradient gradient, float dimLevelInDarkTheme) {
int[] colors = new int[gradient.getColorsCount()]; int[] colors = new int[gradient.getColorsCount()];
for (int i = 0; i < colors.length; i++) { for (int i = 0; i < colors.length; i++) {
colors[i] = gradient.getColors(i); colors[i] = gradient.getColors(i);
@ -38,11 +51,11 @@ public class ChatWallpaperFactory {
positions[i] = gradient.getPositions(i); positions[i] = gradient.getPositions(i);
} }
return new GradientChatWallpaper(gradient.getRotation(), colors, positions); return new GradientChatWallpaper(gradient.getRotation(), colors, positions, dimLevelInDarkTheme);
} }
private static @NonNull ChatWallpaper buildForFile(@NonNull Wallpaper.File file) { private static @NonNull ChatWallpaper buildForFile(@NonNull Wallpaper.File file, float dimLevelInDarkTheme) {
Uri uri = Uri.parse(file.getUri()); Uri uri = Uri.parse(file.getUri());
return new UriChatWallpaper(uri); return new UriChatWallpaper(uri, dimLevelInDarkTheme);
} }
} }

Wyświetl plik

@ -8,12 +8,14 @@ import android.widget.ImageView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.widget.SwitchCompat;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProviders; import androidx.lifecycle.ViewModelProviders;
import androidx.navigation.Navigation; import androidx.navigation.Navigation;
import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.util.ThemeUtil;
public class ChatWallpaperFragment extends Fragment { public class ChatWallpaperFragment extends Fragment {
@Override @Override
@ -26,18 +28,48 @@ public class ChatWallpaperFragment extends Fragment {
ChatWallpaperViewModel viewModel = ViewModelProviders.of(requireActivity()).get(ChatWallpaperViewModel.class); ChatWallpaperViewModel viewModel = ViewModelProviders.of(requireActivity()).get(ChatWallpaperViewModel.class);
ImageView chatWallpaperPreview = view.findViewById(R.id.chat_wallpaper_preview_background); ImageView chatWallpaperPreview = view.findViewById(R.id.chat_wallpaper_preview_background);
View setWallpaper = view.findViewById(R.id.chat_wallpaper_set_wallpaper); View setWallpaper = view.findViewById(R.id.chat_wallpaper_set_wallpaper);
SwitchCompat dimInNightMode = view.findViewById(R.id.chat_wallpaper_dark_theme_dims_wallpaper);
viewModel.setWallpaper(GradientChatWallpaper.GRADIENT_1); View chatWallpaperDim = view.findViewById(R.id.chat_wallpaper_dim);
View clearWallpaper = view.findViewById(R.id.chat_wallpaper_clear_wallpaper);
View resetAllWallpaper = view.findViewById(R.id.chat_wallpaper_reset_all_wallpapers);
viewModel.getCurrentWallpaper().observe(getViewLifecycleOwner(), wallpaper -> { viewModel.getCurrentWallpaper().observe(getViewLifecycleOwner(), wallpaper -> {
if (wallpaper.isPresent()) { if (wallpaper.isPresent()) {
wallpaper.get().loadInto(chatWallpaperPreview); wallpaper.get().loadInto(chatWallpaperPreview);
} else { } else {
chatWallpaperPreview.setImageDrawable(null);
chatWallpaperPreview.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.signal_background_primary)); chatWallpaperPreview.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.signal_background_primary));
} }
dimInNightMode.setEnabled(wallpaper.isPresent());
});
viewModel.getDimInDarkTheme().observe(getViewLifecycleOwner(), shouldDimInNightMode -> {
if (shouldDimInNightMode != dimInNightMode.isChecked()) {
dimInNightMode.setChecked(shouldDimInNightMode);
}
chatWallpaperDim.setAlpha(ChatWallpaper.FIXED_DIM_LEVEL_FOR_DARK_THEME);
chatWallpaperDim.setVisibility(shouldDimInNightMode && ThemeUtil.isDarkTheme(requireContext()) ? View.VISIBLE : View.GONE);
}); });
setWallpaper.setOnClickListener(unused -> Navigation.findNavController(view) setWallpaper.setOnClickListener(unused -> Navigation.findNavController(view)
.navigate(R.id.action_chatWallpaperFragment_to_chatWallpaperSelectionFragment)); .navigate(R.id.action_chatWallpaperFragment_to_chatWallpaperSelectionFragment));
clearWallpaper.setOnClickListener(unused -> {
viewModel.setWallpaper(null);
viewModel.setDimInDarkTheme(false);
viewModel.saveWallpaperSelection();
});
resetAllWallpaper.setVisibility(viewModel.isGlobal() ? View.VISIBLE : View.GONE);
resetAllWallpaper.setOnClickListener(unused -> {
viewModel.setWallpaper(null);
viewModel.setDimInDarkTheme(false);
viewModel.resetAllWallpaper();
});
dimInNightMode.setOnCheckedChangeListener((buttonView, isChecked) -> viewModel.setDimInDarkTheme(isChecked));
} }
} }

Wyświetl plik

@ -8,30 +8,33 @@ import android.view.View;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.widget.Toolbar; import androidx.appcompat.widget.Toolbar;
import androidx.lifecycle.ViewModelProviders;
import androidx.viewpager2.widget.ViewPager2; import androidx.viewpager2.widget.ViewPager2;
import com.annimon.stream.Stream;
import org.thoughtcrime.securesms.PassphraseRequiredActivity; import org.thoughtcrime.securesms.PassphraseRequiredActivity;
import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.recipients.RecipientId; import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.ActivityTransitionUtil;
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme; import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
import org.thoughtcrime.securesms.util.DynamicTheme; import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.FullscreenHelper; import org.thoughtcrime.securesms.util.FullscreenHelper;
import org.thoughtcrime.securesms.util.MappingModel;
import java.util.Collections; import java.util.Collections;
public class ChatWallpaperPreviewActivity extends PassphraseRequiredActivity { public class ChatWallpaperPreviewActivity extends PassphraseRequiredActivity {
private static final String EXTRA_CHAT_WALLPAPER = "extra.chat.wallpaper"; public static final String EXTRA_CHAT_WALLPAPER = "extra.chat.wallpaper";
private static final String EXTRA_RECIPIENT_ID = "extra.recipient.id"; private static final String EXTRA_DIM_IN_DARK_MODE = "extra.dim.in.dark.mode";
private final DynamicTheme dynamicTheme = new DynamicNoActionBarTheme(); private final DynamicTheme dynamicTheme = new DynamicNoActionBarTheme();
public static @NonNull Intent create(@NonNull Context context, @NonNull ChatWallpaper selection, @Nullable RecipientId recipientId) { public static @NonNull Intent create(@NonNull Context context, @NonNull ChatWallpaper selection, boolean dimInDarkMode) {
Intent intent = new Intent(context, ChatWallpaperPreviewActivity.class); Intent intent = new Intent(context, ChatWallpaperPreviewActivity.class);
intent.putExtra(EXTRA_CHAT_WALLPAPER, selection); intent.putExtra(EXTRA_CHAT_WALLPAPER, selection);
intent.putExtra(EXTRA_RECIPIENT_ID, recipientId); intent.putExtra(EXTRA_DIM_IN_DARK_MODE, dimInDarkMode);
return intent; return intent;
} }
@ -42,32 +45,43 @@ public class ChatWallpaperPreviewActivity extends PassphraseRequiredActivity {
setContentView(R.layout.chat_wallpaper_preview_activity); setContentView(R.layout.chat_wallpaper_preview_activity);
ViewPager2 viewPager = findViewById(R.id.preview_pager); ViewPager2 viewPager = findViewById(R.id.preview_pager);
ChatWallpaperPreviewAdapter adapter = new ChatWallpaperPreviewAdapter(); ChatWallpaperPreviewAdapter adapter = new ChatWallpaperPreviewAdapter();
View submit = findViewById(R.id.preview_set_wallpaper); View submit = findViewById(R.id.preview_set_wallpaper);
ChatWallpaperViewModel.Factory factory = new ChatWallpaperViewModel.Factory(getIntent().getParcelableExtra(EXTRA_RECIPIENT_ID)); ChatWallpaperRepository repository = new ChatWallpaperRepository();
ChatWallpaperViewModel viewModel = ViewModelProviders.of(this, factory).get(ChatWallpaperViewModel.class); ChatWallpaper selected = getIntent().getParcelableExtra(EXTRA_CHAT_WALLPAPER);
ChatWallpaper selected = getIntent().getParcelableExtra(EXTRA_CHAT_WALLPAPER); boolean dim = getIntent().getBooleanExtra(EXTRA_DIM_IN_DARK_MODE, false);
Toolbar toolbar = findViewById(R.id.toolbar); Toolbar toolbar = findViewById(R.id.toolbar);
toolbar.setNavigationOnClickListener(unused -> finish()); toolbar.setNavigationOnClickListener(unused -> {
finish();
ActivityTransitionUtil.setSlideOutTransition(this);
});
viewPager.setAdapter(adapter); viewPager.setAdapter(adapter);
adapter.submitList(Collections.singletonList(new ChatWallpaperSelectionMappingModel(selected))); adapter.submitList(Collections.singletonList(new ChatWallpaperSelectionMappingModel(selected)));
viewModel.getWallpapers().observe(this, adapter::submitList); repository.getAllWallpaper(wallpapers -> adapter.submitList(Stream.of(wallpapers)
.map(wallpaper -> ChatWallpaperFactory.updateWithDimming(wallpaper, dim ? 1f : 0f))
.<MappingModel<?>>map(ChatWallpaperSelectionMappingModel::new)
.toList()));
submit.setOnClickListener(unused -> { submit.setOnClickListener(unused -> {
ChatWallpaperSelectionMappingModel model = (ChatWallpaperSelectionMappingModel) adapter.getCurrentList().get(viewPager.getCurrentItem()); ChatWallpaperSelectionMappingModel model = (ChatWallpaperSelectionMappingModel) adapter.getCurrentList().get(viewPager.getCurrentItem());
viewModel.saveWallpaperSelection(model.getWallpaper()); setResult(RESULT_OK, new Intent().putExtra(EXTRA_CHAT_WALLPAPER, model.getWallpaper()));
setResult(RESULT_OK);
finish(); finish();
}); });
new FullscreenHelper(this).showSystemUI(); new FullscreenHelper(this).showSystemUI();
} }
@Override
public void onBackPressed() {
super.onBackPressed();
ActivityTransitionUtil.setSlideOutTransition(this);
}
@Override @Override
protected void onResume() { protected void onResume() {
super.onResume(); super.onResume();

Wyświetl plik

@ -1,14 +1,64 @@
package org.thoughtcrime.securesms.wallpaper; package org.thoughtcrime.securesms.wallpaper;
import androidx.annotation.MainThread;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.util.Consumer; import androidx.core.util.Consumer;
import org.signal.core.util.concurrent.SignalExecutors;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.concurrent.SerialExecutor;
import org.whispersystems.libsignal.util.guava.Optional;
import java.util.List; import java.util.List;
import java.util.concurrent.Executor;
class ChatWallpaperRepository { class ChatWallpaperRepository {
private static final Executor EXECUTOR = new SerialExecutor(SignalExecutors.BOUNDED);
@MainThread
@Nullable ChatWallpaper getCurrentWallpaper(@Nullable RecipientId recipientId) {
if (recipientId != null) {
return Recipient.resolved(recipientId).getWallpaper();
} else {
return SignalStore.wallpaper().getWallpaper();
}
}
void getAllWallpaper(@NonNull Consumer<List<ChatWallpaper>> consumer) { void getAllWallpaper(@NonNull Consumer<List<ChatWallpaper>> consumer) {
consumer.accept(ChatWallpaper.BUILTINS); consumer.accept(ChatWallpaper.BUILTINS);
} }
void saveWallpaper(@Nullable RecipientId recipientId, @Nullable ChatWallpaper chatWallpaper) {
if (recipientId != null) {
//noinspection CodeBlock2Expr
EXECUTOR.execute(() -> {
DatabaseFactory.getRecipientDatabase(ApplicationDependencies.getApplication()).setWallpaper(recipientId, chatWallpaper);
});
} else {
SignalStore.wallpaper().setWallpaper(ApplicationDependencies.getApplication(), chatWallpaper);
}
}
void resetAllWallpaper() {
SignalStore.wallpaper().setWallpaper(ApplicationDependencies.getApplication(), null);
EXECUTOR.execute(() -> {
DatabaseFactory.getRecipientDatabase(ApplicationDependencies.getApplication()).resetAllWallpaper();
});
}
void setDimInDarkTheme(@NonNull RecipientId recipientId, boolean dimInDarkTheme) {
if (recipientId != null) {
EXECUTOR.execute(() -> {
DatabaseFactory.getRecipientDatabase(ApplicationDependencies.getApplication()).setDimWallpaperInDarkTheme(recipientId, dimInDarkTheme);
});
} else {
SignalStore.wallpaper().setDimInDarkTheme(dimInDarkTheme);
}
}
} }

Wyświetl plik

@ -19,6 +19,7 @@ import com.google.android.flexbox.FlexboxLayoutManager;
import com.google.android.flexbox.JustifyContent; import com.google.android.flexbox.JustifyContent;
import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.util.ActivityTransitionUtil;
public class ChatWallpaperSelectionFragment extends Fragment { public class ChatWallpaperSelectionFragment extends Fragment {
@ -45,7 +46,8 @@ public class ChatWallpaperSelectionFragment extends Fragment {
@SuppressWarnings("CodeBlock2Expr") @SuppressWarnings("CodeBlock2Expr")
ChatWallpaperSelectionAdapter adapter = new ChatWallpaperSelectionAdapter(chatWallpaper -> { ChatWallpaperSelectionAdapter adapter = new ChatWallpaperSelectionAdapter(chatWallpaper -> {
startActivityForResult(ChatWallpaperPreviewActivity.create(requireActivity(), chatWallpaper, viewModel.getRecipientId()), PREVIEW); startActivityForResult(ChatWallpaperPreviewActivity.create(requireActivity(), chatWallpaper, viewModel.getDimInDarkTheme().getValue()), PREVIEW);
ActivityTransitionUtil.setSlideInTransition(requireActivity());
}); });
flexboxLayoutManager.setJustifyContent(JustifyContent.SPACE_AROUND); flexboxLayoutManager.setJustifyContent(JustifyContent.SPACE_AROUND);
@ -63,9 +65,15 @@ public class ChatWallpaperSelectionFragment extends Fragment {
if (uri == null || uri == Uri.EMPTY) { if (uri == null || uri == Uri.EMPTY) {
throw new AssertionError("Should never have an empty uri."); throw new AssertionError("Should never have an empty uri.");
} else { } else {
startActivityForResult(ChatWallpaperPreviewActivity.create(requireActivity(), new UriChatWallpaper(uri), viewModel.getRecipientId()), PREVIEW); ChatWallpaper wallpaper = ChatWallpaperFactory.create(uri);
viewModel.setWallpaper(wallpaper);
viewModel.saveWallpaperSelection();
Navigation.findNavController(requireView()).popBackStack();
} }
} else if (requestCode == PREVIEW && resultCode == Activity.RESULT_OK) { } else if (requestCode == PREVIEW && resultCode == Activity.RESULT_OK && data != null) {
ChatWallpaper chatWallpaper = data.getParcelableExtra(ChatWallpaperPreviewActivity.EXTRA_CHAT_WALLPAPER);
viewModel.setWallpaper(chatWallpaper);
viewModel.saveWallpaperSelection();
Navigation.findNavController(requireView()).popBackStack(); Navigation.findNavController(requireView()).popBackStack();
} else { } else {
super.onActivityResult(requestCode, resultCode, data); super.onActivityResult(requestCode, resultCode, data);

Wyświetl plik

@ -11,15 +11,18 @@ import androidx.recyclerview.widget.RecyclerView;
import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.util.MappingAdapter; import org.thoughtcrime.securesms.util.MappingAdapter;
import org.thoughtcrime.securesms.util.MappingViewHolder; import org.thoughtcrime.securesms.util.MappingViewHolder;
import org.thoughtcrime.securesms.util.ThemeUtil;
class ChatWallpaperViewHolder extends MappingViewHolder<ChatWallpaperSelectionMappingModel> { class ChatWallpaperViewHolder extends MappingViewHolder<ChatWallpaperSelectionMappingModel> {
private final ImageView preview; private final ImageView preview;
private final View dimmer;
private final EventListener eventListener; private final EventListener eventListener;
public ChatWallpaperViewHolder(@NonNull View itemView, @Nullable EventListener eventListener) { public ChatWallpaperViewHolder(@NonNull View itemView, @Nullable EventListener eventListener) {
super(itemView); super(itemView);
this.preview = itemView.findViewById(R.id.chat_wallpaper_preview); this.preview = itemView.findViewById(R.id.chat_wallpaper_preview);
this.dimmer = itemView.findViewById(R.id.chat_wallpaper_dim);
this.eventListener = eventListener; this.eventListener = eventListener;
} }
@ -27,6 +30,8 @@ class ChatWallpaperViewHolder extends MappingViewHolder<ChatWallpaperSelectionMa
public void bind(@NonNull ChatWallpaperSelectionMappingModel model) { public void bind(@NonNull ChatWallpaperSelectionMappingModel model) {
model.loadInto(preview); model.loadInto(preview);
ChatWallpaperDimLevelUtil.applyDimLevelForNightMode(dimmer, model.getWallpaper());
if (eventListener != null) { if (eventListener != null) {
preview.setOnClickListener(unused -> { preview.setOnClickListener(unused -> {
if (getAdapterPosition() != RecyclerView.NO_POSITION) { if (getAdapterPosition() != RecyclerView.NO_POSITION) {

Wyświetl plik

@ -4,7 +4,6 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.lifecycle.LiveData; import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Transformations;
import androidx.lifecycle.ViewModel; import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelProvider;
@ -12,6 +11,7 @@ import com.annimon.stream.Stream;
import org.thoughtcrime.securesms.recipients.RecipientId; import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.MappingModel; import org.thoughtcrime.securesms.util.MappingModel;
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.libsignal.util.guava.Optional;
import java.util.List; import java.util.List;
@ -19,23 +19,52 @@ import java.util.Objects;
public class ChatWallpaperViewModel extends ViewModel { public class ChatWallpaperViewModel extends ViewModel {
private final ChatWallpaperRepository repository = new ChatWallpaperRepository(); private final ChatWallpaperRepository repository = new ChatWallpaperRepository();
private final MutableLiveData<Optional<ChatWallpaper>> wallpaper = new MutableLiveData<>(); private final MutableLiveData<Optional<ChatWallpaper>> wallpaper = new MutableLiveData<>();
private final MutableLiveData<List<ChatWallpaper>> builtins = new MutableLiveData<>(); private final MutableLiveData<List<ChatWallpaper>> builtins = new MutableLiveData<>();
private final MutableLiveData<Boolean> dimInDarkTheme = new MutableLiveData<>();
private final RecipientId recipientId; private final RecipientId recipientId;
private ChatWallpaperViewModel(@Nullable RecipientId recipientId) { private ChatWallpaperViewModel(@Nullable RecipientId recipientId) {
this.recipientId = recipientId; this.recipientId = recipientId;
ChatWallpaper currentWallpaper = repository.getCurrentWallpaper(recipientId);
dimInDarkTheme.setValue(currentWallpaper != null && currentWallpaper.getDimLevelForDarkTheme() > 0f);
wallpaper.setValue(Optional.fromNullable(currentWallpaper));
repository.getAllWallpaper(builtins::postValue); repository.getAllWallpaper(builtins::postValue);
} }
void setDimInDarkTheme(boolean shouldDimInDarkTheme) {
dimInDarkTheme.setValue(shouldDimInDarkTheme);
Optional<ChatWallpaper> wallpaper = this.wallpaper.getValue();
if (wallpaper.isPresent()) {
repository.setDimInDarkTheme(recipientId, shouldDimInDarkTheme);
}
}
void setWallpaper(@Nullable ChatWallpaper chatWallpaper) { void setWallpaper(@Nullable ChatWallpaper chatWallpaper) {
wallpaper.setValue(Optional.fromNullable(chatWallpaper)); wallpaper.setValue(Optional.fromNullable(chatWallpaper));
} }
void saveWallpaperSelection(@NonNull ChatWallpaper selected) { void saveWallpaperSelection() {
// TODO Optional<ChatWallpaper> wallpaper = this.wallpaper.getValue();
boolean dimInDarkTheme = this.dimInDarkTheme.getValue();
if (!wallpaper.isPresent()) {
repository.saveWallpaper(recipientId, null);
return;
}
Optional<ChatWallpaper> updated = wallpaper.transform(paper -> ChatWallpaperFactory.updateWithDimming(paper, dimInDarkTheme ? ChatWallpaper.FIXED_DIM_LEVEL_FOR_DARK_THEME : 0f));
if (updated.isPresent()) {
repository.saveWallpaper(recipientId, updated.get());
}
}
void resetAllWallpaper() {
repository.resetAllWallpaper();
} }
public @Nullable RecipientId getRecipientId() { public @Nullable RecipientId getRecipientId() {
@ -47,8 +76,19 @@ public class ChatWallpaperViewModel extends ViewModel {
} }
LiveData<List<MappingModel<?>>> getWallpapers() { LiveData<List<MappingModel<?>>> getWallpapers() {
return Transformations.map(Transformations.distinctUntilChanged(builtins), return LiveDataUtil.combineLatest(builtins, dimInDarkTheme, (wallpapers, dimInDarkMode) ->
wallpapers -> Stream.of(wallpapers).<MappingModel<?>>map(ChatWallpaperSelectionMappingModel::new).toList()); Stream.of(wallpapers)
.map(paper -> ChatWallpaperFactory.updateWithDimming(paper, dimInDarkMode ? 1f : 0f))
.<MappingModel<?>>map(ChatWallpaperSelectionMappingModel::new).toList()
);
}
LiveData<Boolean> getDimInDarkTheme() {
return dimInDarkTheme;
}
boolean isGlobal() {
return recipientId == null;
} }
public static class Factory implements ViewModelProvider.Factory { public static class Factory implements ViewModelProvider.Factory {

Wyświetl plik

@ -23,43 +23,61 @@ import java.util.Objects;
final class GradientChatWallpaper implements ChatWallpaper, Parcelable { final class GradientChatWallpaper implements ChatWallpaper, Parcelable {
public static final GradientChatWallpaper SOLID_1 = new GradientChatWallpaper(0xFFE26983); public static final ChatWallpaper GRADIENT_1 = new GradientChatWallpaper(167.96f,
public static final GradientChatWallpaper SOLID_2 = new GradientChatWallpaper(0xFFDF9171); new int[] { 0xFFF3DC47, 0xFFF3DA47, 0xFFF2D546, 0xFFF2CC46, 0xFFF1C146, 0xFFEFB445, 0xFFEEA544, 0xFFEC9644, 0xFFEB8743, 0xFFE97743, 0xFFE86942, 0xFFE65C41, 0xFFE55041, 0xFFE54841, 0xFFE44240, 0xFFE44040 },
public static final GradientChatWallpaper SOLID_3 = new GradientChatWallpaper(0xFF9E9887); new float[] { 0.0f, 0.0807f, 0.1554f, 0.225f, 0.2904f, 0.3526f, 0.4125f, 0.471f, 0.529f, 0.5875f, 0.6474f, 0.7096f, 0.775f, 0.8446f, 0.9193f, 1f },
public static final GradientChatWallpaper SOLID_4 = new GradientChatWallpaper(0xFF89AE8F); 0f);
public static final GradientChatWallpaper SOLID_5 = new GradientChatWallpaper(0xFF32C7E2); public static final ChatWallpaper GRADIENT_2 = new GradientChatWallpaper(180f,
public static final GradientChatWallpaper SOLID_6 = new GradientChatWallpaper(0xFF7C99B6); new int[] { 0xFF16161D, 0xFF17171E, 0xFF1A1A22, 0xFF1F1F28, 0xFF26262F, 0xFF2D2D38, 0xFF353542, 0xFF3E3E4C, 0xFF474757, 0xFF4F4F61, 0xFF57576B, 0xFF5F5F74, 0xFF65657C, 0xFF6A6A82, 0xFF6D6D85, 0xFF6E6E87 },
public static final GradientChatWallpaper SOLID_7 = new GradientChatWallpaper(0xFFC988E7); new float[] { 0.0000f, 0.0807f, 0.1554f, 0.2250f, 0.2904f, 0.3526f, 0.4125f, 0.4710f, 0.5290f, 0.5875f, 0.6474f, 0.7096f, 0.7750f, 0.8446f, 0.9193f, 1.0000f },
public static final GradientChatWallpaper SOLID_8 = new GradientChatWallpaper(0xFFE297C3); 0f);
public static final GradientChatWallpaper SOLID_9 = new GradientChatWallpaper(0xFFA2A2AA); public static final ChatWallpaper GRADIENT_3 = new GradientChatWallpaper(192.04f,
public static final GradientChatWallpaper SOLID_10 = new GradientChatWallpaper(0xFF146148); new int[] { 0xFFF53844, 0xFFF33845, 0xFFEC3848, 0xFFE2384C, 0xFFD63851, 0xFFC73857, 0xFFB6385E, 0xFFA43866, 0xFF93376D, 0xFF813775, 0xFF70377C, 0xFF613782, 0xFF553787, 0xFF4B378B, 0xFF44378E, 0xFF42378F },
public static final GradientChatWallpaper SOLID_11 = new GradientChatWallpaper(0xFF403B91); new float[] { 0.0000f, 0.0075f, 0.0292f, 0.0637f, 0.1097f, 0.1659f, 0.2310f, 0.3037f, 0.3827f, 0.4666f, 0.5541f, 0.6439f, 0.7347f, 0.8252f, 0.9141f, 1.0000f },
public static final GradientChatWallpaper SOLID_12 = new GradientChatWallpaper(0xFF624249); 0f);
public static final GradientChatWallpaper GRADIENT_1 = new GradientChatWallpaper(167.96f, public static final ChatWallpaper GRADIENT_4 = new GradientChatWallpaper(180f,
new int[] { 0xFFF3DC47, 0xFFF3DA47, 0xFFF2D546, 0xFFF2CC46, 0xFFF1C146, 0xFFEFB445, 0xFFEEA544, 0xFFEC9644, 0xFFEB8743, 0xFFE97743, 0xFFE86942, 0xFFE65C41, 0xFFE55041, 0xFFE54841, 0xFFE44240, 0xFFE44040 }, new int[] { 0xFF0093E9, 0xFF0294E9, 0xFF0696E7, 0xFF0D99E5, 0xFF169EE3, 0xFF21A3E0, 0xFF2DA8DD, 0xFF3AAEDA, 0xFF46B5D6, 0xFF53BBD3, 0xFF5FC0D0, 0xFF6AC5CD, 0xFF73CACB, 0xFF7ACDC9, 0xFF7ECFC7, 0xFF80D0C7 },
new float[] { 0.0f, 0.0807f, 0.1554f, 0.225f, 0.2904f, 0.3526f, 0.4125f, 0.471f, 0.529f, 0.5875f, 0.6474f, 0.7096f, 0.775f, 0.8446f, 0.9193f, 1f }); new float[] { 0.0000f, 0.0807f, 0.1554f, 0.2250f, 0.2904f, 0.3526f, 0.4125f, 0.4710f, 0.5290f, 0.5875f, 0.6474f, 0.7096f, 0.7750f, 0.8446f, 0.9193f, 1.0000f },
public static final GradientChatWallpaper GRADIENT_2 = new GradientChatWallpaper(180f, 0f);
new int[] { 0xFF16161D, 0xFF17171E, 0xFF1A1A22, 0xFF1F1F28, 0xFF26262F, 0xFF2D2D38, 0xFF353542, 0xFF3E3E4C, 0xFF474757, 0xFF4F4F61, 0xFF57576B, 0xFF5F5F74, 0xFF65657C, 0xFF6A6A82, 0xFF6D6D85, 0xFF6E6E87 }, public static final ChatWallpaper GRADIENT_5 = new GradientChatWallpaper(192.04f,
new float[] { 0.0000f, 0.0807f, 0.1554f, 0.2250f, 0.2904f, 0.3526f, 0.4125f, 0.4710f, 0.5290f, 0.5875f, 0.6474f, 0.7096f, 0.7750f, 0.8446f, 0.9193f, 1.0000f }); new int[] { 0xFFF04CE6, 0xFFEE4BE6, 0xFFE54AE5, 0xFFD949E5, 0xFFC946E4, 0xFFB644E3, 0xFFA141E3, 0xFF8B3FE2, 0xFF743CE1, 0xFF5E39E0, 0xFF4936DF, 0xFF3634DE, 0xFF2632DD, 0xFF1930DD, 0xFF112FDD, 0xFF0E2FDD },
new float[] { 0.0000f, 0.0807f, 0.1554f, 0.2250f, 0.2904f, 0.3526f, 0.4125f, 0.4710f, 0.5290f, 0.5875f, 0.6474f, 0.7096f, 0.7750f, 0.8446f, 0.9193f, 1.0000f },
0f);
public static final ChatWallpaper GRADIENT_6 = new GradientChatWallpaper(180f,
new int[] { 0xFF65CDAC, 0xFF64CDAB, 0xFF60CBA8, 0xFF5BC8A3, 0xFF55C49D, 0xFF4DC096, 0xFF45BB8F, 0xFF3CB687, 0xFF33B17F, 0xFF2AAC76, 0xFF21A76F, 0xFF1AA268, 0xFF139F62, 0xFF0E9C5E, 0xFF0B9A5B, 0xFF0A995A },
new float[] { 0.0000f, 0.0807f, 0.1554f, 0.2250f, 0.2904f, 0.3526f, 0.4125f, 0.4710f, 0.5290f, 0.5875f, 0.6474f, 0.7096f, 0.7750f, 0.8446f, 0.9193f, 1.0000f },
0f);
public static final ChatWallpaper GRADIENT_7 = new GradientChatWallpaper(180f,
new int[] { 0xFFD8E1FA, 0xFFD8E0F9, 0xFFD8DEF7, 0xFFD8DBF3, 0xFFD8D6EE, 0xFFD7D1E8, 0xFFD7CCE2, 0xFFD7C6DB, 0xFFD7BFD4, 0xFFD7B9CD, 0xFFD6B4C7, 0xFFD6AFC1, 0xFFD6AABC, 0xFFD6A7B8, 0xFFD6A5B6, 0xFFD6A4B5 },
new float[] { 0.0000f, 0.0807f, 0.1554f, 0.2250f, 0.2904f, 0.3526f, 0.4125f, 0.4710f, 0.5290f, 0.5875f, 0.6474f, 0.7096f, 0.7750f, 0.8446f, 0.9193f, 1.0000f },
0f);
public static final ChatWallpaper GRADIENT_8 = new GradientChatWallpaper(180f,
new int[] { 0xFFD8EBFD, 0xFFD7EAFD, 0xFFD5E9FD, 0xFFD2E7FD, 0xFFCDE5FD, 0xFFC8E3FD, 0xFFC3E0FD, 0xFFBDDDFC, 0xFFB7DAFC, 0xFFB2D7FC, 0xFFACD4FC, 0xFFA7D1FC, 0xFFA3CFFB, 0xFFA0CDFB, 0xFF9ECCFB, 0xFF9DCCFB },
new float[] { 0.0000f, 0.0807f, 0.1554f, 0.2250f, 0.2904f, 0.3526f, 0.4125f, 0.4710f, 0.5290f, 0.5875f, 0.6474f, 0.7096f, 0.7750f, 0.8446f, 0.9193f, 1.0000f },
0f);
public static final ChatWallpaper GRADIENT_9 = new GradientChatWallpaper(192.04f,
new int[] { 0xFFFFE5C2, 0xFFFFE4C1, 0xFFFFE2BF, 0xFFFFDFBD, 0xFFFEDBB9, 0xFFFED6B5, 0xFFFED1B1, 0xFFFDCCAC, 0xFFFDC6A8, 0xFFFDC0A3, 0xFFFCBB9F, 0xFFFCB69B, 0xFFFCB297, 0xFFFCAF95, 0xFFFCAD93, 0xFFFCAC92 },
new float[] { 0.0000f, 0.0807f, 0.1554f, 0.2250f, 0.2904f, 0.3526f, 0.4125f, 0.4710f, 0.5290f, 0.5875f, 0.6474f, 0.7096f, 0.7750f, 0.8446f, 0.9193f, 1.0000f },
0f);
private final float degrees; private final float degrees;
private final int[] colors; private final int[] colors;
private final float[] positions; private final float[] positions;
private final float dimLevelInDarkTheme;
GradientChatWallpaper(int color) { GradientChatWallpaper(float degrees, int[] colors, float[] positions, float dimLevelInDarkTheme) {
this(0f, new int[]{color, color}, null); this.degrees = degrees;
} this.colors = colors;
this.positions = positions;
GradientChatWallpaper(float degrees, int[] colors, float[] positions) { this.dimLevelInDarkTheme = dimLevelInDarkTheme;
this.degrees = degrees;
this.colors = colors;
this.positions = positions;
} }
private GradientChatWallpaper(Parcel in) { private GradientChatWallpaper(Parcel in) {
degrees = in.readFloat(); degrees = in.readFloat();
colors = in.createIntArray(); colors = in.createIntArray();
positions = in.createFloatArray(); positions = in.createFloatArray();
dimLevelInDarkTheme = in.readFloat();
} }
@Override @Override
@ -67,6 +85,7 @@ final class GradientChatWallpaper implements ChatWallpaper, Parcelable {
dest.writeFloat(degrees); dest.writeFloat(degrees);
dest.writeIntArray(colors); dest.writeIntArray(colors);
dest.writeFloatArray(positions); dest.writeFloatArray(positions);
dest.writeFloat(dimLevelInDarkTheme);
} }
@Override @Override
@ -78,6 +97,11 @@ final class GradientChatWallpaper implements ChatWallpaper, Parcelable {
return new RotatableGradientDrawable(degrees, colors, positions); return new RotatableGradientDrawable(degrees, colors, positions);
} }
@Override
public float getDimLevelForDarkTheme() {
return dimLevelInDarkTheme;
}
@Override @Override
public void loadInto(@NonNull ImageView imageView) { public void loadInto(@NonNull ImageView imageView) {
imageView.setImageDrawable(buildDrawable()); imageView.setImageDrawable(buildDrawable());
@ -99,6 +123,7 @@ final class GradientChatWallpaper implements ChatWallpaper, Parcelable {
return Wallpaper.newBuilder() return Wallpaper.newBuilder()
.setLinearGradient(builder) .setLinearGradient(builder)
.setDimLevelInDarkTheme(dimLevelInDarkTheme)
.build(); .build();
} }
@ -109,12 +134,13 @@ final class GradientChatWallpaper implements ChatWallpaper, Parcelable {
GradientChatWallpaper that = (GradientChatWallpaper) o; GradientChatWallpaper that = (GradientChatWallpaper) o;
return Float.compare(that.degrees, degrees) == 0 && return Float.compare(that.degrees, degrees) == 0 &&
Arrays.equals(colors, that.colors) && Arrays.equals(colors, that.colors) &&
Arrays.equals(positions, that.positions); Arrays.equals(positions, that.positions) &&
Float.compare(that.dimLevelInDarkTheme, dimLevelInDarkTheme) == 0;
} }
@Override @Override
public int hashCode() { public int hashCode() {
int result = Objects.hash(degrees); int result = Objects.hash(degrees, dimLevelInDarkTheme);
result = 31 * result + Arrays.hashCode(colors); result = 31 * result + Arrays.hashCode(colors);
result = 31 * result + Arrays.hashCode(positions); result = 31 * result + Arrays.hashCode(positions);
return result; return result;

Wyświetl plik

@ -0,0 +1,100 @@
package org.thoughtcrime.securesms.wallpaper;
import android.graphics.drawable.ColorDrawable;
import android.os.Parcel;
import android.os.Parcelable;
import android.widget.ImageView;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import org.thoughtcrime.securesms.database.model.databaseprotos.Wallpaper;
import java.util.Objects;
final class SingleColorChatWallpaper implements ChatWallpaper, Parcelable {
public static final ChatWallpaper SOLID_1 = new SingleColorChatWallpaper(0xFFE26983, 0f);
public static final ChatWallpaper SOLID_2 = new SingleColorChatWallpaper(0xFFDF9171, 0f);
public static final ChatWallpaper SOLID_3 = new SingleColorChatWallpaper(0xFF9E9887, 0f);
public static final ChatWallpaper SOLID_4 = new SingleColorChatWallpaper(0xFF89AE8F, 0f);
public static final ChatWallpaper SOLID_5 = new SingleColorChatWallpaper(0xFF32C7E2, 0f);
public static final ChatWallpaper SOLID_6 = new SingleColorChatWallpaper(0xFF7C99B6, 0f);
public static final ChatWallpaper SOLID_7 = new SingleColorChatWallpaper(0xFFC988E7, 0f);
public static final ChatWallpaper SOLID_8 = new SingleColorChatWallpaper(0xFFE297C3, 0f);
public static final ChatWallpaper SOLID_9 = new SingleColorChatWallpaper(0xFFA2A2AA, 0f);
public static final ChatWallpaper SOLID_10 = new SingleColorChatWallpaper(0xFF146148, 0f);
public static final ChatWallpaper SOLID_11 = new SingleColorChatWallpaper(0xFF403B91, 0f);
public static final ChatWallpaper SOLID_12 = new SingleColorChatWallpaper(0xFF624249, 0f);
private final @ColorInt int color;
private final float dimLevelInDarkTheme;
SingleColorChatWallpaper(@ColorInt int color, float dimLevelInDarkTheme) {
this.color = color;
this.dimLevelInDarkTheme = dimLevelInDarkTheme;
}
private SingleColorChatWallpaper(Parcel in) {
color = in.readInt();
dimLevelInDarkTheme = in.readFloat();
}
@Override
public float getDimLevelForDarkTheme() {
return dimLevelInDarkTheme;
}
@Override
public void loadInto(@NonNull ImageView imageView) {
imageView.setImageDrawable(new ColorDrawable(color));
}
@Override
public @NonNull Wallpaper serialize() {
Wallpaper.SingleColor.Builder builder = Wallpaper.SingleColor.newBuilder();
builder.setColor(color);
return Wallpaper.newBuilder()
.setSingleColor(builder)
.setDimLevelInDarkTheme(dimLevelInDarkTheme)
.build();
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(color);
dest.writeFloat(dimLevelInDarkTheme);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SingleColorChatWallpaper that = (SingleColorChatWallpaper) o;
return color == that.color && Float.compare(dimLevelInDarkTheme, that.dimLevelInDarkTheme) == 0;
}
@Override
public int hashCode() {
return Objects.hash(color, dimLevelInDarkTheme);
}
public static final Creator<SingleColorChatWallpaper> CREATOR = new Creator<SingleColorChatWallpaper>() {
@Override
public SingleColorChatWallpaper createFromParcel(Parcel in) {
return new SingleColorChatWallpaper(in);
}
@Override
public SingleColorChatWallpaper[] newArray(int size) {
return new SingleColorChatWallpaper[size];
}
};
}

Wyświetl plik

@ -10,12 +10,21 @@ import androidx.annotation.NonNull;
import org.thoughtcrime.securesms.database.model.databaseprotos.Wallpaper; import org.thoughtcrime.securesms.database.model.databaseprotos.Wallpaper;
import org.thoughtcrime.securesms.mms.GlideApp; import org.thoughtcrime.securesms.mms.GlideApp;
import java.util.Objects;
final class UriChatWallpaper implements ChatWallpaper, Parcelable { final class UriChatWallpaper implements ChatWallpaper, Parcelable {
private final Uri uri; private final Uri uri;
private final float dimLevelInDarkTheme;
public UriChatWallpaper(@NonNull Uri uri) { public UriChatWallpaper(@NonNull Uri uri, float dimLevelInDarkTheme) {
this.uri = uri; this.uri = uri;
this.dimLevelInDarkTheme = dimLevelInDarkTheme;
}
@Override
public float getDimLevelForDarkTheme() {
return dimLevelInDarkTheme;
} }
@Override @Override
@ -29,6 +38,7 @@ final class UriChatWallpaper implements ChatWallpaper, Parcelable {
public @NonNull Wallpaper serialize() { public @NonNull Wallpaper serialize() {
return Wallpaper.newBuilder() return Wallpaper.newBuilder()
.setFile(Wallpaper.File.newBuilder().setUri(uri.toString())) .setFile(Wallpaper.File.newBuilder().setUri(uri.toString()))
.setDimLevelInDarkTheme(dimLevelInDarkTheme)
.build(); .build();
} }
@ -40,12 +50,27 @@ final class UriChatWallpaper implements ChatWallpaper, Parcelable {
@Override @Override
public void writeToParcel(Parcel dest, int flags) { public void writeToParcel(Parcel dest, int flags) {
dest.writeString(uri.toString()); dest.writeString(uri.toString());
dest.writeFloat(dimLevelInDarkTheme);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
UriChatWallpaper that = (UriChatWallpaper) o;
return Float.compare(that.dimLevelInDarkTheme, dimLevelInDarkTheme) == 0 &&
uri.equals(that.uri);
}
@Override
public int hashCode() {
return Objects.hash(uri, dimLevelInDarkTheme);
} }
public static final Creator<UriChatWallpaper> CREATOR = new Creator<UriChatWallpaper>() { public static final Creator<UriChatWallpaper> CREATOR = new Creator<UriChatWallpaper>() {
@Override @Override
public UriChatWallpaper createFromParcel(Parcel in) { public UriChatWallpaper createFromParcel(Parcel in) {
return new UriChatWallpaper(Uri.parse(in.readString())); return new UriChatWallpaper(Uri.parse(in.readString()), in.readFloat());
} }
@Override @Override

Wyświetl plik

@ -74,7 +74,7 @@ public final class WallpaperStorage {
*/ */
@WorkerThread @WorkerThread
public static void onWallpaperDeselected(@NonNull Context context, @NonNull Uri uri) { public static void onWallpaperDeselected(@NonNull Context context, @NonNull Uri uri) {
Uri globalUri = SignalStore.wallpaper().getCurrentWallpaperUri(); Uri globalUri = SignalStore.wallpaper().getWallpaperUri();
if (Objects.equals(uri, globalUri)) { if (Objects.equals(uri, globalUri)) {
return; return;
} }

Wyświetl plik

@ -96,11 +96,13 @@ message Wallpaper {
message SingleColor { message SingleColor {
int32 color = 1; int32 color = 1;
} }
message LinearGradient { message LinearGradient {
float rotation = 1; float rotation = 1;
repeated int32 colors = 2; repeated int32 colors = 2;
repeated float positions = 3; repeated float positions = 3;
} }
message File { message File {
string uri = 1; string uri = 1;
} }
@ -111,5 +113,5 @@ message Wallpaper {
File file = 3; File file = 3;
} }
float dimLevelInDarkMode = 4; float dimLevelInDarkTheme = 4;
} }

Wyświetl plik

@ -1,5 +1,14 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<shape android:shape="rectangle" xmlns:android="http://schemas.android.com/apk/res/android"> <layer-list>
<solid android:color="@color/signal_background_primary" /> <item>
<corners android:bottomLeftRadius="8dp" android:bottomRightRadius="8dp" /> <shape android:shape="rectangle" xmlns:android="http://schemas.android.com/apk/res/android">
</shape> <solid android:color="@color/signal_background_tertiary" />
</shape>
</item>
<item>
<shape android:shape="rectangle" xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/signal_background_primary" />
<corners android:bottomLeftRadius="8dp" android:bottomRightRadius="8dp" />
</shape>
</item>
</layer-list>

Wyświetl plik

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape android:shape="rectangle" xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/core_white" />
<corners android:radius="10dp" />
</shape>

Wyświetl plik

@ -1,5 +1,14 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<shape android:shape="rectangle" xmlns:android="http://schemas.android.com/apk/res/android"> <layer-list>
<solid android:color="@color/signal_accent_primary" /> <item>
<corners android:topLeftRadius="8dp" android:topRightRadius="8dp" /> <shape android:shape="rectangle" xmlns:android="http://schemas.android.com/apk/res/android">
</shape> <solid android:color="@color/signal_background_tertiary" />
</shape>
</item>
<item>
<shape android:shape="rectangle" xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/signal_accent_primary" />
<corners android:topLeftRadius="8dp" android:topRightRadius="8dp" />
</shape>
</item>
</layer-list>

Wyświetl plik

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/wallpaper_bubble_color" />
<corners android:radius="11dp" />
</shape>

Wyświetl plik

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/wallpaper_bubble_color" />
<corners android:radius="12dp" />
</shape>

Wyświetl plik

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/wallpaper_bubble_color" />
<corners android:radius="8dp" />
</shape>

Wyświetl plik

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/core_white" />
<corners android:radius="11dp" />
</shape>

Wyświetl plik

@ -15,44 +15,65 @@
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="320dp" android:layout_height="320dp"
android:background="@color/signal_background_tertiary" android:background="@color/signal_background_tertiary"
app:layout_constraintBottom_toBottomOf="@id/chat_wallpaper_preview_bottom_bar" app:layout_constraintBottom_toBottomOf="@id/chat_wallpaper_preview_background"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="@id/chat_wallpaper_preview_background" />
<View
android:id="@+id/chat_wallpaper_preview_top_bar"
android:layout_width="156dp"
android:layout_height="30dp"
android:background="@drawable/chat_wallpaper_preview_top_bar"
app:layout_constraintBottom_toTopOf="@id/chat_wallpaper_preview_background"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed" />
<ImageView <ImageView
android:id="@+id/chat_wallpaper_preview_background" android:id="@+id/chat_wallpaper_preview_background"
android:layout_width="156dp" android:layout_width="156dp"
android:layout_height="228dp" android:layout_height="288dp"
android:layout_marginTop="16dp"
android:background="@color/signal_background_primary"
android:importantForAccessibility="no" android:importantForAccessibility="no"
android:scaleType="fitXY" android:scaleType="fitXY"
android:src="@drawable/test_gradient"
app:layout_constraintBottom_toTopOf="@id/chat_wallpaper_preview_bottom_bar"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@drawable/test_gradient" />
<View
android:id="@+id/chat_wallpaper_dim"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@color/black"
android:visibility="gone"
app:layout_constraintBottom_toTopOf="@id/chat_wallpaper_preview_bottom_bar"
app:layout_constraintEnd_toEndOf="@id/chat_wallpaper_preview_background"
app:layout_constraintStart_toStartOf="@id/chat_wallpaper_preview_background"
app:layout_constraintTop_toBottomOf="@id/chat_wallpaper_preview_top_bar" app:layout_constraintTop_toBottomOf="@id/chat_wallpaper_preview_top_bar"
tools:background="@color/signal_background_primary" /> tools:visibility="visible" />
<View
android:id="@+id/chat_wallpaper_preview_top_bar"
android:layout_width="156dp"
android:layout_height="28dp"
android:background="@drawable/chat_wallpaper_preview_top_bar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/chat_wallpaper_preview_background"
app:layout_constraintVertical_chainStyle="packed" />
<View <View
android:id="@+id/chat_wallpaper_preview_bottom_bar" android:id="@+id/chat_wallpaper_preview_bottom_bar"
android:layout_width="156dp" android:layout_width="156dp"
android:layout_height="30dp" android:layout_height="24dp"
android:background="@drawable/chat_wallpaper_preview_bottom_bar" android:background="@drawable/chat_wallpaper_preview_bottom_bar"
app:layout_constraintBottom_toBottomOf="@id/chat_wallpaper_preview_lightbox" app:layout_constraintBottom_toBottomOf="@id/chat_wallpaper_preview_background"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent" />
app:layout_constraintTop_toBottomOf="@id/chat_wallpaper_preview_background" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/chat_wallpaper_preview_today"
android:layout_width="24dp"
android:layout_height="10dp"
android:layout_marginTop="12dp"
app:layout_constraintEnd_toEndOf="@id/chat_wallpaper_preview_background"
app:layout_constraintStart_toStartOf="@id/chat_wallpaper_preview_background"
app:layout_constraintTop_toBottomOf="@id/chat_wallpaper_preview_top_bar"
app:srcCompat="@drawable/chat_wallpaper_preview_bubble_10"
app:tint="@color/signal_background_tertiary" />
<androidx.appcompat.widget.AppCompatImageView <androidx.appcompat.widget.AppCompatImageView
android:id="@+id/chat_wallpaper_preview_bubble_1" android:id="@+id/chat_wallpaper_preview_bubble_1"
@ -61,8 +82,8 @@
android:layout_marginStart="8dp" android:layout_marginStart="8dp"
android:layout_marginTop="30dp" android:layout_marginTop="30dp"
app:layout_constraintStart_toStartOf="@id/chat_wallpaper_preview_background" app:layout_constraintStart_toStartOf="@id/chat_wallpaper_preview_background"
app:layout_constraintTop_toTopOf="@id/chat_wallpaper_preview_background" app:layout_constraintTop_toBottomOf="@id/chat_wallpaper_preview_top_bar"
app:srcCompat="@drawable/chat_wallpaper_preview_bubble" app:srcCompat="@drawable/chat_wallpaper_preview_bubble_10"
app:tint="@color/signal_accent_primary" /> app:tint="@color/signal_accent_primary" />
<androidx.appcompat.widget.AppCompatImageView <androidx.appcompat.widget.AppCompatImageView
@ -72,8 +93,8 @@
android:layout_marginTop="66dp" android:layout_marginTop="66dp"
android:layout_marginEnd="8dp" android:layout_marginEnd="8dp"
app:layout_constraintEnd_toEndOf="@id/chat_wallpaper_preview_background" app:layout_constraintEnd_toEndOf="@id/chat_wallpaper_preview_background"
app:layout_constraintTop_toTopOf="@id/chat_wallpaper_preview_background" app:layout_constraintTop_toBottomOf="@id/chat_wallpaper_preview_top_bar"
app:srcCompat="@drawable/chat_wallpaper_preview_bubble" app:srcCompat="@drawable/chat_wallpaper_preview_bubble_10"
app:tint="@color/signal_background_tertiary" /> app:tint="@color/signal_background_tertiary" />
<View <View

Wyświetl plik

@ -5,19 +5,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<androidx.constraintlayout.widget.Guideline <include layout="@layout/system_ui_guidelines" />
android:id="@+id/status_bar_guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
tools:layout_constraintGuide_begin="48dp" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/navigation_bar_guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
tools:layout_constraintGuide_end="48dp" />
<androidx.viewpager2.widget.ViewPager2 <androidx.viewpager2.widget.ViewPager2
android:id="@+id/preview_pager" android:id="@+id/preview_pager"

Wyświetl plik

@ -1,9 +1,23 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android" <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/chat_wallpaper_preview"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent">
android:scaleType="centerCrop"
tools:src="@drawable/test_gradient" /> <ImageView
android:id="@+id/chat_wallpaper_preview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
tools:src="@drawable/test_gradient" />
<View
android:id="@+id/chat_wallpaper_dim"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black"
android:visibility="gone"
tools:alpha="0.2f"
tools:visibility="visible" />
</FrameLayout>

Wyświetl plik

@ -1,11 +1,26 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android" <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/chat_wallpaper_preview"
android:layout_width="117dp" android:layout_width="117dp"
android:layout_height="206dp" android:layout_height="206dp"
android:layout_marginStart="2dp" android:layout_marginStart="2dp"
android:layout_marginEnd="2dp" android:layout_marginEnd="2dp"
android:layout_marginBottom="4dp" android:layout_marginBottom="4dp">
android:scaleType="fitXY"
tools:src="@drawable/test_gradient" /> <ImageView
android:id="@+id/chat_wallpaper_preview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitXY"
tools:src="@drawable/test_gradient" />
<View
android:id="@+id/chat_wallpaper_dim"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black"
android:visibility="gone"
tools:alpha="0.2f"
tools:visibility="visible" />
</FrameLayout>

Wyświetl plik

@ -1,11 +1,31 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" <org.thoughtcrime.securesms.components.InsetAwareConstraintLayout
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"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<include layout="@layout/system_ui_guidelines" />
<ImageView
android:importantForAccessibility="no"
android:id="@+id/conversation_wallpaper"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<View
android:id="@+id/conversation_wallpaper_dim"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black"
android:visibility="gone"
tools:alpha="0.2f"
tools:visibility="visible" />
<com.google.android.material.appbar.AppBarLayout <com.google.android.material.appbar.AppBarLayout
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/status_bar_guideline"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
@ -56,7 +76,9 @@
<org.thoughtcrime.securesms.components.InputAwareLayout <org.thoughtcrime.securesms.components.InputAwareLayout
android:id="@+id/layout_container" android:id="@+id/layout_container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="0dp"
app:layout_constraintTop_toTopOf="@id/status_bar_guideline"
app:layout_constraintBottom_toBottomOf="@id/navigation_bar_guideline">
<LinearLayout <LinearLayout
android:id="@+id/conversation_container" android:id="@+id/conversation_container"
@ -196,4 +218,4 @@
</org.thoughtcrime.securesms.components.InputAwareLayout> </org.thoughtcrime.securesms.components.InputAwareLayout>
<include layout="@layout/conversation_reaction_scrubber" /> <include layout="@layout/conversation_reaction_scrubber" />
</FrameLayout> </org.thoughtcrime.securesms.components.InsetAwareConstraintLayout>

Wyświetl plik

@ -4,13 +4,13 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:padding="24dp"
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout"> tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
<org.thoughtcrime.securesms.components.AvatarImageView <org.thoughtcrime.securesms.components.AvatarImageView
android:id="@+id/message_request_avatar" android:id="@+id/message_request_avatar"
android:layout_width="112dp" android:layout_width="112dp"
android:layout_height="112dp" android:layout_height="112dp"
android:layout_marginTop="32dp"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
@ -35,8 +35,6 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="2dp" android:layout_marginTop="2dp"
android:gravity="center" android:gravity="center"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:textAppearance="@style/Signal.Text.MessageRequest.Subtitle" android:textAppearance="@style/Signal.Text.MessageRequest.Subtitle"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
@ -48,10 +46,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="15dp" android:layout_marginTop="15dp"
android:layout_marginBottom="15dp"
android:gravity="center" android:gravity="center"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:textAppearance="@style/Signal.Text.MessageRequest.Description" android:textAppearance="@style/Signal.Text.MessageRequest.Description"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"

Wyświetl plik

@ -7,6 +7,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical" android:orientation="vertical"
android:background="@color/signal_background_primary"
android:clipChildren="false" android:clipChildren="false"
android:clipToPadding="false"> android:clipToPadding="false">

Wyświetl plik

@ -1,4 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<org.thoughtcrime.securesms.conversation.ConversationBannerView xmlns:android="http://schemas.android.com/apk/res/android" <org.thoughtcrime.securesms.conversation.ConversationBannerView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" /> android:layout_height="wrap_content"
android:layout_margin="32dp"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:paddingTop="24dp"
android:paddingBottom="24dp"/>

Wyświetl plik

@ -5,6 +5,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical" android:orientation="vertical"
android:gravity="center"
android:paddingTop="12dp" android:paddingTop="12dp"
android:paddingBottom="13dp" android:paddingBottom="13dp"
android:paddingStart="28dp" android:paddingStart="28dp"
@ -12,11 +13,14 @@
<TextView <TextView
android:id="@+id/text" android:id="@+id/text"
android:layout_width="match_parent" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="center"
style="@style/Signal.Text.Preview" style="@style/Signal.Text.Preview"
android:textColor="@color/conversation_item_update_text_color" android:textColor="@color/conversation_item_update_text_color"
android:paddingStart="10dp"
android:paddingEnd="10dp"
android:paddingTop="4dp"
android:paddingBottom="4dp"
tools:text="March 1, 2015" /> tools:text="March 1, 2015" />
</LinearLayout> </LinearLayout>

Wyświetl plik

@ -19,6 +19,10 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_gravity="center"
android:paddingStart="10dp"
android:paddingEnd="10dp"
android:paddingTop="4dp"
android:paddingBottom="4dp"
style="@style/Signal.Text.Caption" style="@style/Signal.Text.Caption"
android:fontFamily="sans-serif-medium" android:fontFamily="sans-serif-medium"
android:textColor="@color/signal_text_primary" android:textColor="@color/signal_text_primary"

Wyświetl plik

@ -61,10 +61,11 @@
android:id="@+id/group_sender_holder" android:id="@+id/group_sender_holder"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="@dimen/message_bubble_horizontal_padding" android:layout_marginTop="3dp"
android:layout_marginTop="@dimen/message_bubble_top_padding" android:paddingTop="3dp"
android:layout_marginEnd="@dimen/message_bubble_horizontal_padding" android:paddingBottom="3dp"
android:layout_marginBottom="2dp" android:paddingStart="@dimen/message_bubble_horizontal_padding"
android:paddingEnd="@dimen/message_bubble_horizontal_padding"
android:orientation="horizontal" android:orientation="horizontal"
android:visibility="gone" android:visibility="gone"
tools:visibility="visible"> tools:visibility="visible">
@ -82,20 +83,6 @@
tools:text="+14152222222" tools:text="+14152222222"
tools:visibility="visible" /> tools:visibility="visible" />
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/group_message_sender_profile"
style="@style/Signal.Text.Preview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:fontFamily="sans-serif-regular"
android:maxLines="1"
android:paddingStart="4sp"
android:paddingEnd="4sp"
android:textColor="@color/conversation_item_received_text_primary_color"
android:textStyle="italic"
tools:text="~Clement Duval" />
</LinearLayout> </LinearLayout>
<org.thoughtcrime.securesms.components.QuoteView <org.thoughtcrime.securesms.components.QuoteView
@ -203,9 +190,12 @@
android:id="@+id/conversation_item_sticker_footer" android:id="@+id/conversation_item_sticker_footer"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:layout_marginStart="@dimen/message_bubble_horizontal_padding" android:layout_marginStart="@dimen/message_bubble_horizontal_padding"
android:layout_marginTop="6dp" android:paddingStart="@dimen/message_bubble_horizontal_padding"
android:layout_marginEnd="@dimen/message_bubble_horizontal_padding" android:paddingEnd="@dimen/message_bubble_horizontal_padding"
android:paddingTop="3dp"
android:paddingBottom="3dp"
android:clipChildren="false" android:clipChildren="false"
android:clipToPadding="false" android:clipToPadding="false"
android:gravity="start" android:gravity="start"

Wyświetl plik

@ -61,10 +61,11 @@
android:id="@+id/group_sender_holder" android:id="@+id/group_sender_holder"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="@dimen/message_bubble_horizontal_padding" android:layout_marginTop="3dp"
android:layout_marginTop="@dimen/message_bubble_top_padding" android:paddingTop="3dp"
android:layout_marginEnd="@dimen/message_bubble_horizontal_padding" android:paddingBottom="3dp"
android:layout_marginBottom="2dp" android:paddingStart="@dimen/message_bubble_horizontal_padding"
android:paddingEnd="@dimen/message_bubble_horizontal_padding"
android:orientation="horizontal" android:orientation="horizontal"
android:visibility="gone" android:visibility="gone"
tools:visibility="visible"> tools:visibility="visible">
@ -82,20 +83,6 @@
tools:text="+14152222222" tools:text="+14152222222"
tools:visibility="visible" /> tools:visibility="visible" />
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/group_message_sender_profile"
style="@style/Signal.Text.Preview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:fontFamily="sans-serif-regular"
android:maxLines="1"
android:paddingStart="4sp"
android:paddingEnd="4sp"
android:textColor="@color/conversation_item_received_text_primary_color"
android:textStyle="italic"
tools:text="~Clement Duval" />
</LinearLayout> </LinearLayout>
<org.thoughtcrime.securesms.components.emoji.EmojiTextView <org.thoughtcrime.securesms.components.emoji.EmojiTextView

Wyświetl plik

@ -142,9 +142,11 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="end" android:layout_gravity="end"
android:layout_marginStart="@dimen/message_bubble_horizontal_padding" android:layout_marginTop="3dp"
android:layout_marginTop="6dp" android:paddingStart="@dimen/message_bubble_horizontal_padding"
android:layout_marginEnd="@dimen/message_bubble_horizontal_padding" android:paddingEnd="@dimen/message_bubble_horizontal_padding"
android:paddingTop="3dp"
android:paddingBottom="3dp"
android:clipChildren="false" android:clipChildren="false"
android:clipToPadding="false" android:clipToPadding="false"
android:gravity="end" android:gravity="end"

Wyświetl plik

@ -7,30 +7,41 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="@drawable/conversation_item_background" android:background="@drawable/conversation_item_background"
android:focusable="true" android:focusable="true"
android:gravity="center" android:paddingStart="26dp"
android:orientation="vertical" android:paddingEnd="26dp">
android:paddingBottom="6dp"
android:paddingStart="28dp"
android:paddingEnd="28dp"
android:paddingTop="8dp">
<org.thoughtcrime.securesms.components.emoji.EmojiTextView <LinearLayout
android:id="@+id/conversation_update_body" android:id="@+id/conversation_update_background"
style="@style/Signal.Text.Preview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="@color/conversation_item_update_text_color"
tools:text="Gwen Stacy set the disappearing message timer to 1 hour" />
<com.google.android.material.button.MaterialButton
android:id="@+id/conversation_update_action"
style="@style/Signal.Widget.Button.Small.Primary"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp" android:layout_gravity="center"
android:visibility="gone" android:layout_marginBottom="3dp"
tools:text="Learn more" android:orientation="vertical"
tools:visibility="visible" /> android:gravity="center"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:paddingStart="10dp"
android:paddingEnd="10dp">
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/conversation_update_body"
style="@style/Signal.Text.Preview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="@color/conversation_item_update_text_color"
tools:text="Gwen Stacy set the disappearing message timer to 1 hour" />
<com.google.android.material.button.MaterialButton
android:id="@+id/conversation_update_action"
style="@style/Signal.Widget.Button.Small.Primary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:visibility="gone"
tools:text="Learn more"
tools:visibility="visible" />
</LinearLayout>
</org.thoughtcrime.securesms.conversation.ConversationUpdateItem> </org.thoughtcrime.securesms.conversation.ConversationUpdateItem>

Wyświetl plik

@ -4,7 +4,9 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/conversation_reaction_scrubber" android:id="@+id/conversation_reaction_scrubber"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="0dp"
app:layout_constraintTop_toTopOf="@+id/status_bar_guideline"
app:layout_constraintBottom_toBottomOf="@+id/navigation_bar_guideline"
android:elevation="1000dp" android:elevation="1000dp"
android:visibility="gone" android:visibility="gone"
tools:visibility="visible"> tools:visibility="visible">

Wyświetl plik

@ -329,6 +329,18 @@
</LinearLayout> </LinearLayout>
<TextView
android:id="@+id/chat_wallpaper"
android:layout_width="match_parent"
android:layout_height="56dp"
android:background="?selectableItemBackground"
android:gravity="start|center_vertical"
android:paddingStart="@dimen/group_manage_fragment_row_horizontal_padding"
android:paddingEnd="@dimen/group_manage_fragment_row_horizontal_padding"
android:text="@string/ManageGroupActivity_chat_wallpaper"
android:textAlignment="viewStart"
android:textAppearance="@style/Signal.Text.Body"/>
</LinearLayout> </LinearLayout>
</androidx.cardview.widget.CardView> </androidx.cardview.widget.CardView>

Wyświetl plik

@ -472,37 +472,56 @@
app:layout_constraintTop_toBottomOf="@id/recipient_media_card"> app:layout_constraintTop_toBottomOf="@id/recipient_media_card">
<LinearLayout <LinearLayout
android:id="@+id/color_row" android:orientation="vertical"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="@dimen/group_manage_fragment_row_height" android:layout_height="wrap_content">
android:background="?selectableItemBackground"
android:clickable="true" <LinearLayout
android:focusable="true" android:id="@+id/color_row"
android:orientation="horizontal"> android:layout_width="match_parent"
android:layout_height="@dimen/group_manage_fragment_row_height"
android:background="?selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal"
android:layout_weight="1"
android:gravity="center_vertical|start"
android:paddingStart="@dimen/group_manage_fragment_row_horizontal_padding"
android:paddingEnd="@dimen/group_manage_fragment_row_horizontal_padding"
android:text="@string/ManageRecipientActivity_chat_color"
android:textAlignment="viewStart"
android:textAppearance="@style/Signal.Text.Body" />
<ImageView
android:id="@+id/color_chip"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical"
android:layout_marginEnd="@dimen/group_manage_fragment_row_horizontal_padding"
android:contentDescription="@string/ManageRecipientActivity_chat_color"
android:gravity="center"
tools:src="@drawable/circle_tintable"
tools:tint="@color/core_ultramarine_light" />
</LinearLayout>
<TextView <TextView
android:layout_width="0dp" android:id="@+id/chat_wallpaper"
android:layout_height="match_parent" android:layout_width="match_parent"
android:layout_height="56dp"
android:layout_gravity="center_horizontal" android:layout_gravity="center_horizontal"
android:layout_weight="1" android:background="?selectableItemBackground"
android:gravity="center_vertical|start" android:gravity="center_vertical|start"
android:paddingStart="@dimen/group_manage_fragment_row_horizontal_padding" android:paddingStart="@dimen/group_manage_fragment_row_horizontal_padding"
android:paddingEnd="@dimen/group_manage_fragment_row_horizontal_padding" android:paddingEnd="@dimen/group_manage_fragment_row_horizontal_padding"
android:text="@string/ManageRecipientActivity_chat_color" android:text="@string/ManageRecipientActivity_chat_wallpaper"
android:textAlignment="viewStart" android:textAlignment="viewStart"
android:textAppearance="@style/Signal.Text.Body" /> android:textAppearance="@style/Signal.Text.Body" />
<ImageView
android:id="@+id/color_chip"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical"
android:layout_marginEnd="@dimen/group_manage_fragment_row_horizontal_padding"
android:contentDescription="@string/ManageRecipientActivity_chat_color"
android:gravity="center"
tools:src="@drawable/circle_tintable"
tools:tint="@color/core_ultramarine_light" />
</LinearLayout> </LinearLayout>
</androidx.cardview.widget.CardView> </androidx.cardview.widget.CardView>

Wyświetl plik

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/status_bar_guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
tools:layout_constraintGuide_begin="48dp" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/navigation_bar_guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
tools:layout_constraintGuide_end="48dp" />
</merge>

Wyświetl plik

@ -13,7 +13,11 @@
<action <action
android:id="@+id/action_chatWallpaperFragment_to_chatWallpaperSelectionFragment" android:id="@+id/action_chatWallpaperFragment_to_chatWallpaperSelectionFragment"
app:destination="@id/chatWallpaperSelectionFragment" /> app:destination="@id/chatWallpaperSelectionFragment"
app:enterAnim="@anim/slide_from_end"
app:exitAnim="@anim/slide_to_start"
app:popEnterAnim="@anim/slide_from_start"
app:popExitAnim="@anim/slide_to_end" />
</fragment> </fragment>
<fragment <fragment
android:id="@+id/chatWallpaperSelectionFragment" android:id="@+id/chatWallpaperSelectionFragment"

Wyświetl plik

@ -69,6 +69,8 @@
<color name="conversation_item_sent_icon_color">@color/core_grey_25</color> <color name="conversation_item_sent_icon_color">@color/core_grey_25</color>
<color name="conversation_item_quote_text_color">@color/core_grey_05</color> <color name="conversation_item_quote_text_color">@color/core_grey_05</color>
<color name="wallpaper_bubble_color">@color/transparent_black_80</color>
<color name="conversation_scroll_to_bottom_foreground_color">@color/core_white</color> <color name="conversation_scroll_to_bottom_foreground_color">@color/core_white</color>
<color name="conversation_list_camera_button_background">@color/core_grey_85</color> <color name="conversation_list_camera_button_background">@color/core_grey_85</color>

Wyświetl plik

@ -50,5 +50,4 @@
<color name="storage_color_videos">#ff9BCFBD</color> <color name="storage_color_videos">#ff9BCFBD</color>
<color name="storage_color_audio">@color/core_ultramarine</color> <color name="storage_color_audio">@color/core_ultramarine</color>
<color name="storage_color_files">#ffA23474</color> <color name="storage_color_files">#ffA23474</color>
</resources> </resources>

Wyświetl plik

@ -69,6 +69,8 @@
<color name="conversation_item_sent_icon_color">@color/core_grey_60</color> <color name="conversation_item_sent_icon_color">@color/core_grey_60</color>
<color name="conversation_item_quote_text_color">@color/core_grey_90</color> <color name="conversation_item_quote_text_color">@color/core_grey_90</color>
<color name="wallpaper_bubble_color">@color/transparent_white_80</color>
<color name="conversation_scroll_to_bottom_foreground_color">@color/grey_600</color> <color name="conversation_scroll_to_bottom_foreground_color">@color/grey_600</color>
<color name="conversation_list_camera_button_background">@color/core_white</color> <color name="conversation_list_camera_button_background">@color/core_white</color>

Wyświetl plik

@ -701,6 +701,7 @@
<string name="ManageGroupActivity_mute_notifications">Mute notifications</string> <string name="ManageGroupActivity_mute_notifications">Mute notifications</string>
<string name="ManageGroupActivity_custom_notifications">Custom notifications</string> <string name="ManageGroupActivity_custom_notifications">Custom notifications</string>
<string name="ManageGroupActivity_mentions">Mentions</string> <string name="ManageGroupActivity_mentions">Mentions</string>
<string name="ManageGroupActivity_chat_wallpaper">Chat wallpaper</string>
<string name="ManageGroupActivity_until_s">Until %1$s</string> <string name="ManageGroupActivity_until_s">Until %1$s</string>
<string name="ManageGroupActivity_off">Off</string> <string name="ManageGroupActivity_off">Off</string>
<string name="ManageGroupActivity_on">On</string> <string name="ManageGroupActivity_on">On</string>
@ -752,6 +753,7 @@
<string name="ManageRecipientActivity_this_person_is_in_your_contacts">This person is in your contacts</string> <string name="ManageRecipientActivity_this_person_is_in_your_contacts">This person is in your contacts</string>
<string name="ManageRecipientActivity_disappearing_messages">Disappearing messages</string> <string name="ManageRecipientActivity_disappearing_messages">Disappearing messages</string>
<string name="ManageRecipientActivity_chat_color">Chat color</string> <string name="ManageRecipientActivity_chat_color">Chat color</string>
<string name="ManageRecipientActivity_chat_wallpaper">Chat wallpaper</string>
<string name="ManageRecipientActivity_block">Block</string> <string name="ManageRecipientActivity_block">Block</string>
<string name="ManageRecipientActivity_unblock">Unblock</string> <string name="ManageRecipientActivity_unblock">Unblock</string>
<string name="ManageRecipientActivity_view_safety_number">View safety number</string> <string name="ManageRecipientActivity_view_safety_number">View safety number</string>