mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-05-08 09:18:39 +01:00
Finalize wallpaper UX.
Co-authored-by: Greyson Parrelli <greyson@signal.org> Co-authored-by: Alan Evans <alan@signal.org>
This commit is contained in:
committed by
Greyson Parrelli
parent
a8ad1e718e
commit
c244a98962
@@ -309,7 +309,7 @@ public final class ContactSelectionListFragment extends LoggingFragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
recyclerView.setAdapter(concatenateAdapter);
|
recyclerView.setAdapter(concatenateAdapter);
|
||||||
recyclerView.addItemDecoration(new StickyHeaderDecoration(concatenateAdapter, true, true));
|
recyclerView.addItemDecoration(new StickyHeaderDecoration(concatenateAdapter, true, true, 0));
|
||||||
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
|
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
|
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
|
||||||
|
|||||||
+2
-2
@@ -266,12 +266,12 @@ public class ContactSelectionListAdapter extends CursorRecyclerViewAdapter<ViewH
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public HeaderViewHolder onCreateHeaderViewHolder(ViewGroup parent, int position) {
|
public HeaderViewHolder onCreateHeaderViewHolder(ViewGroup parent, int position, int type) {
|
||||||
return new HeaderViewHolder(LayoutInflater.from(getContext()).inflate(R.layout.contact_selection_recyclerview_header, parent, false));
|
return new HeaderViewHolder(LayoutInflater.from(getContext()).inflate(R.layout.contact_selection_recyclerview_header, parent, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBindHeaderViewHolder(HeaderViewHolder viewHolder, int position) {
|
public void onBindHeaderViewHolder(HeaderViewHolder viewHolder, int position, int type) {
|
||||||
((TextView)viewHolder.itemView).setText(getSpannedHeaderString(position));
|
((TextView)viewHolder.itemView).setText(getSpannedHeaderString(position));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -429,6 +429,7 @@ public class ConversationActivity extends PassphraseRequiredActivity
|
|||||||
setContentView(R.layout.conversation_activity);
|
setContentView(R.layout.conversation_activity);
|
||||||
|
|
||||||
getWindow().getDecorView().setBackgroundResource(R.color.signal_background_primary);
|
getWindow().getDecorView().setBackgroundResource(R.color.signal_background_primary);
|
||||||
|
WindowUtil.setLightNavigationBar(getWindow());
|
||||||
|
|
||||||
fragment = initFragment(R.id.fragment_content, new ConversationFragment(), dynamicLanguage.getCurrentLocale());
|
fragment = initFragment(R.id.fragment_content, new ConversationFragment(), dynamicLanguage.getCurrentLocale());
|
||||||
|
|
||||||
@@ -1989,6 +1990,7 @@ public class ConversationActivity extends PassphraseRequiredActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateWallpaper(@Nullable ChatWallpaper chatWallpaper) {
|
private void updateWallpaper(@Nullable ChatWallpaper chatWallpaper) {
|
||||||
|
Log.d(TAG, "Setting wallpaper.");
|
||||||
if (chatWallpaper != null) {
|
if (chatWallpaper != null) {
|
||||||
chatWallpaper.loadInto(wallpaper);
|
chatWallpaper.loadInto(wallpaper);
|
||||||
ChatWallpaperDimLevelUtil.applyDimLevelForNightMode(wallpaperDim, chatWallpaper);
|
ChatWallpaperDimLevelUtil.applyDimLevelForNightMode(wallpaperDim, chatWallpaper);
|
||||||
@@ -1996,6 +1998,7 @@ public class ConversationActivity extends PassphraseRequiredActivity
|
|||||||
wallpaper.setImageDrawable(null);
|
wallpaper.setImageDrawable(null);
|
||||||
wallpaperDim.setVisibility(View.GONE);
|
wallpaperDim.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
fragment.onWallpaperChanged(chatWallpaper);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void initializeActionBar() {
|
protected void initializeActionBar() {
|
||||||
@@ -2105,6 +2108,7 @@ public class ConversationActivity extends PassphraseRequiredActivity
|
|||||||
this.viewModel = ViewModelProviders.of(this, new ConversationViewModel.Factory()).get(ConversationViewModel.class);
|
this.viewModel = ViewModelProviders.of(this, new ConversationViewModel.Factory()).get(ConversationViewModel.class);
|
||||||
|
|
||||||
this.viewModel.setArgs(args);
|
this.viewModel.setArgs(args);
|
||||||
|
this.viewModel.getWallpaper().observe(this, this::updateWallpaper);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeGroupViewModel() {
|
private void initializeGroupViewModel() {
|
||||||
@@ -2290,7 +2294,6 @@ 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();
|
||||||
|
|||||||
@@ -73,6 +73,10 @@ public class ConversationAdapter
|
|||||||
|
|
||||||
private static final String TAG = Log.tag(ConversationAdapter.class);
|
private static final String TAG = Log.tag(ConversationAdapter.class);
|
||||||
|
|
||||||
|
public static final int HEADER_TYPE_POPOVER_DATE = 1;
|
||||||
|
public static final int HEADER_TYPE_INLINE_DATE = 2;
|
||||||
|
public static final int HEADER_TYPE_LAST_SEEN = 3;
|
||||||
|
|
||||||
private static final int MESSAGE_TYPE_OUTGOING_MULTIMEDIA = 0;
|
private static final int MESSAGE_TYPE_OUTGOING_MULTIMEDIA = 0;
|
||||||
private static final int MESSAGE_TYPE_OUTGOING_TEXT = 1;
|
private static final int MESSAGE_TYPE_OUTGOING_TEXT = 1;
|
||||||
private static final int MESSAGE_TYPE_INCOMING_MULTIMEDIA = 2;
|
private static final int MESSAGE_TYPE_INCOMING_MULTIMEDIA = 2;
|
||||||
@@ -102,6 +106,7 @@ public class ConversationAdapter
|
|||||||
private View headerView;
|
private View headerView;
|
||||||
private View footerView;
|
private View footerView;
|
||||||
private PagingController pagingController;
|
private PagingController pagingController;
|
||||||
|
private boolean hasWallpaper;
|
||||||
|
|
||||||
ConversationAdapter(@NonNull LifecycleOwner lifecycleOwner,
|
ConversationAdapter(@NonNull LifecycleOwner lifecycleOwner,
|
||||||
@NonNull GlideRequests glideRequests,
|
@NonNull GlideRequests glideRequests,
|
||||||
@@ -132,6 +137,7 @@ public class ConversationAdapter
|
|||||||
this.releasedFastRecords = new HashSet<>();
|
this.releasedFastRecords = new HashSet<>();
|
||||||
this.calendar = Calendar.getInstance();
|
this.calendar = Calendar.getInstance();
|
||||||
this.digest = getMessageDigestOrThrow();
|
this.digest = getMessageDigestOrThrow();
|
||||||
|
this.hasWallpaper = recipient.hasWallpaper();
|
||||||
|
|
||||||
setHasStableIds(true);
|
setHasStableIds(true);
|
||||||
}
|
}
|
||||||
@@ -243,7 +249,7 @@ public class ConversationAdapter
|
|||||||
recipient,
|
recipient,
|
||||||
searchQuery,
|
searchQuery,
|
||||||
conversationMessage == recordToPulse,
|
conversationMessage == recordToPulse,
|
||||||
recipient.hasWallpaper());
|
hasWallpaper);
|
||||||
|
|
||||||
if (conversationMessage == recordToPulse) {
|
if (conversationMessage == recordToPulse) {
|
||||||
recordToPulse = null;
|
recordToPulse = null;
|
||||||
@@ -290,19 +296,27 @@ public class ConversationAdapter
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public StickyHeaderViewHolder onCreateHeaderViewHolder(ViewGroup parent, int position) {
|
public StickyHeaderViewHolder onCreateHeaderViewHolder(ViewGroup parent, int position, int type) {
|
||||||
return new StickyHeaderViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.conversation_item_header, parent, false));
|
return new StickyHeaderViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.conversation_item_header, parent, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBindHeaderViewHolder(StickyHeaderViewHolder viewHolder, int position) {
|
public void onBindHeaderViewHolder(StickyHeaderViewHolder viewHolder, int position, int type) {
|
||||||
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()) {
|
if (type == HEADER_TYPE_POPOVER_DATE) {
|
||||||
viewHolder.setBackgroundRes(R.drawable.wallpaper_bubble_background_8);
|
if (hasWallpaper) {
|
||||||
} else {
|
viewHolder.setBackgroundRes(R.drawable.wallpaper_bubble_background_8);
|
||||||
viewHolder.clearBackground();
|
} else {
|
||||||
|
viewHolder.setBackgroundRes(R.drawable.sticky_date_header_background);
|
||||||
|
}
|
||||||
|
} else if (type == HEADER_TYPE_INLINE_DATE) {
|
||||||
|
if (hasWallpaper) {
|
||||||
|
viewHolder.setBackgroundRes(R.drawable.wallpaper_bubble_background_8);
|
||||||
|
} else {
|
||||||
|
viewHolder.clearBackground();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -334,7 +348,7 @@ 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()) {
|
if (hasWallpaper) {
|
||||||
viewHolder.setBackgroundRes(R.drawable.wallpaper_bubble_background_8);
|
viewHolder.setBackgroundRes(R.drawable.wallpaper_bubble_background_8);
|
||||||
} else {
|
} else {
|
||||||
viewHolder.clearBackground();
|
viewHolder.clearBackground();
|
||||||
@@ -435,6 +449,17 @@ public class ConversationAdapter
|
|||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lets the adapter know that the wallpaper state has changed.
|
||||||
|
*/
|
||||||
|
void onHasWallpaperChanged(boolean hasWallpaper) {
|
||||||
|
if (this.hasWallpaper != hasWallpaper) {
|
||||||
|
Log.d(TAG, "Resetting adapter due to wallpaper change.");
|
||||||
|
this.hasWallpaper = hasWallpaper;
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a record to a memory cache to allow it to be rendered immediately, as opposed to waiting
|
* Adds a record to a memory cache to allow it to be rendered immediately, as opposed to waiting
|
||||||
* for a database change.
|
* for a database change.
|
||||||
|
|||||||
+18
-10
@@ -141,6 +141,7 @@ import org.thoughtcrime.securesms.util.WindowUtil;
|
|||||||
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
|
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
|
||||||
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
|
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
|
||||||
import org.thoughtcrime.securesms.util.views.AdaptiveActionsToolbar;
|
import org.thoughtcrime.securesms.util.views.AdaptiveActionsToolbar;
|
||||||
|
import org.thoughtcrime.securesms.wallpaper.ChatWallpaper;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -171,7 +172,7 @@ public class ConversationFragment extends LoggingFragment {
|
|||||||
private Locale locale;
|
private Locale locale;
|
||||||
private RecyclerView list;
|
private RecyclerView list;
|
||||||
private RecyclerView.ItemDecoration lastSeenDecoration;
|
private RecyclerView.ItemDecoration lastSeenDecoration;
|
||||||
private RecyclerView.ItemDecoration stickyHeaderDecoration;
|
private RecyclerView.ItemDecoration popoverDateDecoration;
|
||||||
private ViewSwitcher topLoadMoreView;
|
private ViewSwitcher topLoadMoreView;
|
||||||
private ViewSwitcher bottomLoadMoreView;
|
private ViewSwitcher bottomLoadMoreView;
|
||||||
private ConversationTypingView typingView;
|
private ConversationTypingView typingView;
|
||||||
@@ -390,6 +391,13 @@ public class ConversationFragment extends LoggingFragment {
|
|||||||
snapToTopDataObserver.requestScrollPosition(position);
|
snapToTopDataObserver.requestScrollPosition(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void onWallpaperChanged(@Nullable ChatWallpaper wallpaper) {
|
||||||
|
if (list != null) {
|
||||||
|
Log.d(TAG, "Notifying adapter that wallpaper state has changed.");
|
||||||
|
getListAdapter().onHasWallpaperChanged(wallpaper != null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private int getStartPosition() {
|
private int getStartPosition() {
|
||||||
return conversationViewModel.getArgs().getStartingPosition();
|
return conversationViewModel.getArgs().getStartingPosition();
|
||||||
}
|
}
|
||||||
@@ -488,7 +496,7 @@ public class ConversationFragment extends LoggingFragment {
|
|||||||
this.threadId = conversationViewModel.getArgs().getThreadId();
|
this.threadId = conversationViewModel.getArgs().getThreadId();
|
||||||
this.markReadHelper = new MarkReadHelper(threadId, requireContext());
|
this.markReadHelper = new MarkReadHelper(threadId, requireContext());
|
||||||
|
|
||||||
conversationViewModel.onConversationDataAvailable(threadId, startingPosition);
|
conversationViewModel.onConversationDataAvailable(recipient.getId(), threadId, startingPosition);
|
||||||
messageCountsViewModel.setThreadId(threadId);
|
messageCountsViewModel.setThreadId(threadId);
|
||||||
|
|
||||||
messageCountsViewModel.getUnreadMessagesCount().observe(getViewLifecycleOwner(), scrollToBottomButton::setUnreadCount);
|
messageCountsViewModel.getUnreadMessagesCount().observe(getViewLifecycleOwner(), scrollToBottomButton::setUnreadCount);
|
||||||
@@ -511,7 +519,7 @@ public class ConversationFragment extends LoggingFragment {
|
|||||||
ConversationAdapter adapter = new ConversationAdapter(this, GlideApp.with(this), locale, selectionClickListener, this.recipient.get());
|
ConversationAdapter adapter = new ConversationAdapter(this, GlideApp.with(this), locale, selectionClickListener, this.recipient.get());
|
||||||
adapter.setPagingController(conversationViewModel.getPagingController());
|
adapter.setPagingController(conversationViewModel.getPagingController());
|
||||||
list.setAdapter(adapter);
|
list.setAdapter(adapter);
|
||||||
setStickyHeaderDecoration(adapter);
|
setPopoverDateDecoration(adapter);
|
||||||
ConversationAdapter.initializePool(list.getRecycledViewPool());
|
ConversationAdapter.initializePool(list.getRecycledViewPool());
|
||||||
|
|
||||||
adapter.registerAdapterDataObserver(snapToTopDataObserver);
|
adapter.registerAdapterDataObserver(snapToTopDataObserver);
|
||||||
@@ -638,7 +646,7 @@ public class ConversationFragment extends LoggingFragment {
|
|||||||
messageRequestViewModel.setConversationInfo(recipient.getId(), threadId);
|
messageRequestViewModel.setConversationInfo(recipient.getId(), threadId);
|
||||||
|
|
||||||
snapToTopDataObserver.requestScrollPosition(0);
|
snapToTopDataObserver.requestScrollPosition(0);
|
||||||
conversationViewModel.onConversationDataAvailable(threadId, -1);
|
conversationViewModel.onConversationDataAvailable(recipient.getId(), threadId, -1);
|
||||||
messageCountsViewModel.setThreadId(threadId);
|
messageCountsViewModel.setThreadId(threadId);
|
||||||
initializeListAdapter();
|
initializeListAdapter();
|
||||||
}
|
}
|
||||||
@@ -652,13 +660,13 @@ public class ConversationFragment extends LoggingFragment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setStickyHeaderDecoration(@NonNull ConversationAdapter adapter) {
|
public void setPopoverDateDecoration(@NonNull ConversationAdapter adapter) {
|
||||||
if (stickyHeaderDecoration != null) {
|
if (popoverDateDecoration != null) {
|
||||||
list.removeItemDecoration(stickyHeaderDecoration);
|
list.removeItemDecoration(popoverDateDecoration);
|
||||||
}
|
}
|
||||||
|
|
||||||
stickyHeaderDecoration = new StickyHeaderDecoration(adapter, false, false);
|
popoverDateDecoration = new StickyHeaderDecoration(adapter, false, false, ConversationAdapter.HEADER_TYPE_INLINE_DATE);
|
||||||
list.addItemDecoration(stickyHeaderDecoration);
|
list.addItemDecoration(popoverDateDecoration);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLastSeen(long lastSeen) {
|
public void setLastSeen(long lastSeen) {
|
||||||
@@ -1180,7 +1188,7 @@ public class ConversationFragment extends LoggingFragment {
|
|||||||
|
|
||||||
private void bindScrollHeader(StickyHeaderViewHolder headerViewHolder, int positionId) {
|
private void bindScrollHeader(StickyHeaderViewHolder headerViewHolder, int positionId) {
|
||||||
if (((ConversationAdapter)list.getAdapter()).getHeaderId(positionId) != -1) {
|
if (((ConversationAdapter)list.getAdapter()).getHeaderId(positionId) != -1) {
|
||||||
((ConversationAdapter) list.getAdapter()).onBindHeaderViewHolder(headerViewHolder, positionId);
|
((ConversationAdapter) list.getAdapter()).onBindHeaderViewHolder(headerViewHolder, positionId, ConversationAdapter.HEADER_TYPE_POPOVER_DATE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -142,7 +142,7 @@ public final class ConversationReactionOverlay extends RelativeLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setListVerticalTranslation(float translationY) {
|
public void setListVerticalTranslation(float translationY) {
|
||||||
maskView.setTargetParentTranslationY(translationY);
|
maskView.setTargetParentTranslationY(translationY - ViewUtil.getStatusBarHeight(maskView));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void show(@NonNull Activity activity,
|
public void show(@NonNull Activity activity,
|
||||||
|
|||||||
+16
-1
@@ -19,7 +19,11 @@ import org.thoughtcrime.securesms.database.DatabaseObserver;
|
|||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
import org.thoughtcrime.securesms.mediasend.Media;
|
import org.thoughtcrime.securesms.mediasend.Media;
|
||||||
import org.thoughtcrime.securesms.mediasend.MediaRepository;
|
import org.thoughtcrime.securesms.mediasend.MediaRepository;
|
||||||
|
import org.thoughtcrime.securesms.recipients.LiveRecipient;
|
||||||
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
|
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||||
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
|
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
|
||||||
|
import org.thoughtcrime.securesms.wallpaper.ChatWallpaper;
|
||||||
import org.whispersystems.libsignal.util.Pair;
|
import org.whispersystems.libsignal.util.Pair;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -41,6 +45,8 @@ class ConversationViewModel extends ViewModel {
|
|||||||
private final LiveData<Boolean> canShowAsBubble;
|
private final LiveData<Boolean> canShowAsBubble;
|
||||||
private final ProxyPagingController pagingController;
|
private final ProxyPagingController pagingController;
|
||||||
private final DatabaseObserver.Observer messageObserver;
|
private final DatabaseObserver.Observer messageObserver;
|
||||||
|
private final MutableLiveData<RecipientId> recipientId;
|
||||||
|
private final LiveData<ChatWallpaper> wallpaper;
|
||||||
|
|
||||||
private ConversationIntents.Args args;
|
private ConversationIntents.Args args;
|
||||||
private int jumpToPosition;
|
private int jumpToPosition;
|
||||||
@@ -53,6 +59,7 @@ class ConversationViewModel extends ViewModel {
|
|||||||
this.threadId = new MutableLiveData<>();
|
this.threadId = new MutableLiveData<>();
|
||||||
this.showScrollButtons = new MutableLiveData<>(false);
|
this.showScrollButtons = new MutableLiveData<>(false);
|
||||||
this.hasUnreadMentions = new MutableLiveData<>(false);
|
this.hasUnreadMentions = new MutableLiveData<>(false);
|
||||||
|
this.recipientId = new MutableLiveData<>();
|
||||||
this.pagingController = new ProxyPagingController();
|
this.pagingController = new ProxyPagingController();
|
||||||
this.messageObserver = pagingController::onDataInvalidated;
|
this.messageObserver = pagingController::onDataInvalidated;
|
||||||
|
|
||||||
@@ -97,6 +104,9 @@ class ConversationViewModel extends ViewModel {
|
|||||||
|
|
||||||
conversationMetadata = Transformations.switchMap(messages, m -> metadata);
|
conversationMetadata = Transformations.switchMap(messages, m -> metadata);
|
||||||
canShowAsBubble = LiveDataUtil.mapAsync(threadId, conversationRepository::canShowAsBubble);
|
canShowAsBubble = LiveDataUtil.mapAsync(threadId, conversationRepository::canShowAsBubble);
|
||||||
|
wallpaper = Transformations.distinctUntilChanged(Transformations.map(Transformations.switchMap(recipientId,
|
||||||
|
id -> Recipient.live(id).getLiveData()),
|
||||||
|
Recipient::getWallpaper));
|
||||||
}
|
}
|
||||||
|
|
||||||
void onAttachmentKeyboardOpen() {
|
void onAttachmentKeyboardOpen() {
|
||||||
@@ -104,11 +114,12 @@ class ConversationViewModel extends ViewModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@MainThread
|
@MainThread
|
||||||
void onConversationDataAvailable(long threadId, int startingPosition) {
|
void onConversationDataAvailable(@NonNull RecipientId recipientId, long threadId, int startingPosition) {
|
||||||
Log.d(TAG, "[onConversationDataAvailable] threadId: " + threadId + ", startingPosition: " + startingPosition);
|
Log.d(TAG, "[onConversationDataAvailable] threadId: " + threadId + ", startingPosition: " + startingPosition);
|
||||||
this.jumpToPosition = startingPosition;
|
this.jumpToPosition = startingPosition;
|
||||||
|
|
||||||
this.threadId.setValue(threadId);
|
this.threadId.setValue(threadId);
|
||||||
|
this.recipientId.setValue(recipientId);
|
||||||
}
|
}
|
||||||
|
|
||||||
void clearThreadId() {
|
void clearThreadId() {
|
||||||
@@ -128,6 +139,10 @@ class ConversationViewModel extends ViewModel {
|
|||||||
return Transformations.distinctUntilChanged(LiveDataUtil.combineLatest(showScrollButtons, hasUnreadMentions, (a, b) -> a && b));
|
return Transformations.distinctUntilChanged(LiveDataUtil.combineLatest(showScrollButtons, hasUnreadMentions, (a, b) -> a && b));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull LiveData<ChatWallpaper> getWallpaper() {
|
||||||
|
return wallpaper;
|
||||||
|
}
|
||||||
|
|
||||||
void setHasUnreadMentions(boolean hasUnreadMentions) {
|
void setHasUnreadMentions(boolean hasUnreadMentions) {
|
||||||
this.hasUnreadMentions.setValue(hasUnreadMentions);
|
this.hasUnreadMentions.setValue(hasUnreadMentions);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ class LastSeenHeader extends StickyHeaderDecoration {
|
|||||||
private final long lastSeenTimestamp;
|
private final long lastSeenTimestamp;
|
||||||
|
|
||||||
LastSeenHeader(ConversationAdapter adapter, long lastSeenTimestamp) {
|
LastSeenHeader(ConversationAdapter adapter, long lastSeenTimestamp) {
|
||||||
super(adapter, false, false);
|
super(adapter, false, false, ConversationAdapter.HEADER_TYPE_LAST_SEEN);
|
||||||
this.adapter = adapter;
|
this.adapter = adapter;
|
||||||
this.lastSeenTimestamp = lastSeenTimestamp;
|
this.lastSeenTimestamp = lastSeenTimestamp;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -481,7 +481,7 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
|||||||
private void initializeListAdapters() {
|
private void initializeListAdapters() {
|
||||||
defaultAdapter = new ConversationListAdapter(GlideApp.with(this), this);
|
defaultAdapter = new ConversationListAdapter(GlideApp.with(this), this);
|
||||||
searchAdapter = new ConversationListSearchAdapter(GlideApp.with(this), this, Locale.getDefault());
|
searchAdapter = new ConversationListSearchAdapter(GlideApp.with(this), this, Locale.getDefault());
|
||||||
searchAdapterDecoration = new StickyHeaderDecoration(searchAdapter, false, false);
|
searchAdapterDecoration = new StickyHeaderDecoration(searchAdapter, false, false, 0);
|
||||||
|
|
||||||
setAdapter(defaultAdapter);
|
setAdapter(defaultAdapter);
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -94,13 +94,13 @@ class ConversationListSearchAdapter extends RecyclerView.Adapter<Conversation
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public HeaderViewHolder onCreateHeaderViewHolder(ViewGroup parent, int position) {
|
public HeaderViewHolder onCreateHeaderViewHolder(ViewGroup parent, int position, int type) {
|
||||||
return new HeaderViewHolder(LayoutInflater.from(parent.getContext())
|
return new HeaderViewHolder(LayoutInflater.from(parent.getContext())
|
||||||
.inflate(R.layout.search_result_list_divider, parent, false));
|
.inflate(R.layout.search_result_list_divider, parent, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBindHeaderViewHolder(HeaderViewHolder viewHolder, int position) {
|
public void onBindHeaderViewHolder(HeaderViewHolder viewHolder, int position, int type) {
|
||||||
viewHolder.bind((int) getHeaderId(position));
|
viewHolder.bind((int) getHeaderId(position));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -855,6 +855,10 @@ public class Recipient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasOwnWallpaper() {
|
||||||
|
return wallpaper != null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A cheap way to check if wallpaper is set without doing any unnecessary proto parsing.
|
* A cheap way to check if wallpaper is set without doing any unnecessary proto parsing.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -30,15 +30,17 @@ public class StickyHeaderDecoration extends RecyclerView.ItemDecoration {
|
|||||||
private final StickyHeaderAdapter adapter;
|
private final StickyHeaderAdapter adapter;
|
||||||
private final boolean renderInline;
|
private final boolean renderInline;
|
||||||
private final boolean sticky;
|
private final boolean sticky;
|
||||||
|
private final int type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param adapter the sticky header adapter to use
|
* @param adapter the sticky header adapter to use
|
||||||
*/
|
*/
|
||||||
public StickyHeaderDecoration(StickyHeaderAdapter adapter, boolean renderInline, boolean sticky) {
|
public StickyHeaderDecoration(StickyHeaderAdapter adapter, boolean renderInline, boolean sticky, int type) {
|
||||||
this.adapter = adapter;
|
this.adapter = adapter;
|
||||||
this.headerCache = new HashMap<>();
|
this.headerCache = new HashMap<>();
|
||||||
this.renderInline = renderInline;
|
this.renderInline = renderInline;
|
||||||
this.sticky = sticky;
|
this.sticky = sticky;
|
||||||
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -88,9 +90,9 @@ public class StickyHeaderDecoration extends RecyclerView.ItemDecoration {
|
|||||||
if (headerHolder == null) {
|
if (headerHolder == null) {
|
||||||
|
|
||||||
if (key != StickyHeaderAdapter.NO_HEADER_ID) {
|
if (key != StickyHeaderAdapter.NO_HEADER_ID) {
|
||||||
headerHolder = adapter.onCreateHeaderViewHolder(parent, position);
|
headerHolder = adapter.onCreateHeaderViewHolder(parent, position, type);
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
adapter.onBindHeaderViewHolder(headerHolder, position);
|
adapter.onBindHeaderViewHolder(headerHolder, position, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (headerHolder == null) {
|
if (headerHolder == null) {
|
||||||
@@ -221,7 +223,7 @@ public class StickyHeaderDecoration extends RecyclerView.ItemDecoration {
|
|||||||
* @param position position in the adapter
|
* @param position position in the adapter
|
||||||
* @return a view holder for the created view
|
* @return a view holder for the created view
|
||||||
*/
|
*/
|
||||||
T onCreateHeaderViewHolder(ViewGroup parent, int position);
|
T onCreateHeaderViewHolder(ViewGroup parent, int position, int type);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the header view to reflect the header data for the given position.
|
* Updates the header view to reflect the header data for the given position.
|
||||||
@@ -229,7 +231,7 @@ public class StickyHeaderDecoration extends RecyclerView.ItemDecoration {
|
|||||||
* @param viewHolder the header view holder
|
* @param viewHolder the header view holder
|
||||||
* @param position the header's item position
|
* @param position the header's item position
|
||||||
*/
|
*/
|
||||||
void onBindHeaderViewHolder(T viewHolder, int position);
|
void onBindHeaderViewHolder(T viewHolder, int position, int type);
|
||||||
|
|
||||||
int getItemCount();
|
int getItemCount();
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -20,18 +20,18 @@ public final class RecyclerViewConcatenateAdapterStickyHeader extends Recycle
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RecyclerView.ViewHolder onCreateHeaderViewHolder(ViewGroup parent, int position) {
|
public RecyclerView.ViewHolder onCreateHeaderViewHolder(ViewGroup parent, int position, int type) {
|
||||||
return getForPosition(position).transform(p -> p.first().onCreateHeaderViewHolder(parent, p.second())).orNull();
|
return getForPosition(position).transform(p -> p.first().onCreateHeaderViewHolder(parent, p.second(), type)).orNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBindHeaderViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
|
public void onBindHeaderViewHolder(RecyclerView.ViewHolder viewHolder, int position, int type) {
|
||||||
Optional<Pair<StickyHeaderDecoration.StickyHeaderAdapter, Integer>> forPosition = getForPosition(position);
|
Optional<Pair<StickyHeaderDecoration.StickyHeaderAdapter, Integer>> forPosition = getForPosition(position);
|
||||||
|
|
||||||
if (forPosition.isPresent()) {
|
if (forPosition.isPresent()) {
|
||||||
Pair<StickyHeaderDecoration.StickyHeaderAdapter, Integer> stickyHeaderAdapterIntegerPair = forPosition.get();
|
Pair<StickyHeaderDecoration.StickyHeaderAdapter, Integer> stickyHeaderAdapterIntegerPair = forPosition.get();
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
stickyHeaderAdapterIntegerPair.first().onBindHeaderViewHolder(viewHolder, stickyHeaderAdapterIntegerPair.second());
|
stickyHeaderAdapterIntegerPair.first().onBindHeaderViewHolder(viewHolder, stickyHeaderAdapterIntegerPair.second(), type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+43
@@ -0,0 +1,43 @@
|
|||||||
|
package org.thoughtcrime.securesms.wallpaper;
|
||||||
|
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
class ChatWallpaperAlignmentDecoration extends RecyclerView.ItemDecoration {
|
||||||
|
@Override
|
||||||
|
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
|
||||||
|
int itemPosition = parent.getChildAdapterPosition(view);
|
||||||
|
int itemCount = state.getItemCount();
|
||||||
|
|
||||||
|
if (itemCount > 0 && itemPosition == itemCount - 1) {
|
||||||
|
outRect.set(0, 0, 0, 0);
|
||||||
|
|
||||||
|
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
|
||||||
|
int viewWidth = view.getMeasuredWidth() + params.rightMargin + params.leftMargin;
|
||||||
|
int availableWidth = (parent.getRight() - parent.getPaddingRight()) - (parent.getLeft() + parent.getPaddingLeft());
|
||||||
|
int itemsPerRow = availableWidth / viewWidth;
|
||||||
|
|
||||||
|
if (itemsPerRow == 1 || (itemPosition + 1) % itemsPerRow == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int extraCellsNeeded = itemsPerRow - ((itemPosition + 1) % itemsPerRow);
|
||||||
|
|
||||||
|
setEnd(outRect, view.getLayoutDirection(), extraCellsNeeded * viewWidth);
|
||||||
|
} else {
|
||||||
|
super.getItemOffsets(outRect, view, parent, state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setEnd(@NonNull Rect outRect, int layoutDirection, int end) {
|
||||||
|
if (layoutDirection == View.LAYOUT_DIRECTION_LTR) {
|
||||||
|
outRect.right = end;
|
||||||
|
} else {
|
||||||
|
outRect.left = end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.thoughtcrime.securesms.wallpaper;
|
package org.thoughtcrime.securesms.wallpaper;
|
||||||
|
|
||||||
|
import android.app.AlertDialog;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -8,6 +9,7 @@ import android.widget.ImageView;
|
|||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.annotation.StringRes;
|
||||||
import androidx.appcompat.widget.SwitchCompat;
|
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;
|
||||||
@@ -18,6 +20,12 @@ import org.thoughtcrime.securesms.R;
|
|||||||
import org.thoughtcrime.securesms.util.ThemeUtil;
|
import org.thoughtcrime.securesms.util.ThemeUtil;
|
||||||
|
|
||||||
public class ChatWallpaperFragment extends Fragment {
|
public class ChatWallpaperFragment extends Fragment {
|
||||||
|
|
||||||
|
private boolean isSettingDimFromViewModel;
|
||||||
|
private View clearWallpaper;
|
||||||
|
private View resetAllWallpaper;
|
||||||
|
private View divider;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NonNull View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
public @NonNull View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||||
return inflater.inflate(R.layout.chat_wallpaper_fragment, container, false);
|
return inflater.inflate(R.layout.chat_wallpaper_fragment, container, false);
|
||||||
@@ -30,8 +38,10 @@ public class ChatWallpaperFragment extends Fragment {
|
|||||||
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);
|
SwitchCompat dimInNightMode = view.findViewById(R.id.chat_wallpaper_dark_theme_dims_wallpaper);
|
||||||
View chatWallpaperDim = view.findViewById(R.id.chat_wallpaper_dim);
|
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);
|
clearWallpaper = view.findViewById(R.id.chat_wallpaper_clear_wallpaper);
|
||||||
|
resetAllWallpaper = view.findViewById(R.id.chat_wallpaper_reset_all_wallpapers);
|
||||||
|
divider = view.findViewById(R.id.chat_wallpaper_divider);
|
||||||
|
|
||||||
viewModel.getCurrentWallpaper().observe(getViewLifecycleOwner(), wallpaper -> {
|
viewModel.getCurrentWallpaper().observe(getViewLifecycleOwner(), wallpaper -> {
|
||||||
if (wallpaper.isPresent()) {
|
if (wallpaper.isPresent()) {
|
||||||
@@ -40,36 +50,78 @@ public class ChatWallpaperFragment extends Fragment {
|
|||||||
chatWallpaperPreview.setImageDrawable(null);
|
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 -> {
|
viewModel.getDimInDarkTheme().observe(getViewLifecycleOwner(), shouldDimInNightMode -> {
|
||||||
if (shouldDimInNightMode != dimInNightMode.isChecked()) {
|
if (shouldDimInNightMode != dimInNightMode.isChecked()) {
|
||||||
|
isSettingDimFromViewModel = true;
|
||||||
dimInNightMode.setChecked(shouldDimInNightMode);
|
dimInNightMode.setChecked(shouldDimInNightMode);
|
||||||
|
isSettingDimFromViewModel = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
chatWallpaperDim.setAlpha(ChatWallpaper.FIXED_DIM_LEVEL_FOR_DARK_THEME);
|
chatWallpaperDim.setAlpha(ChatWallpaper.FIXED_DIM_LEVEL_FOR_DARK_THEME);
|
||||||
chatWallpaperDim.setVisibility(shouldDimInNightMode && ThemeUtil.isDarkTheme(requireContext()) ? View.VISIBLE : View.GONE);
|
chatWallpaperDim.setVisibility(shouldDimInNightMode && ThemeUtil.isDarkTheme(requireContext()) ? View.VISIBLE : View.GONE);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
viewModel.getEnableWallpaperControls().observe(getViewLifecycleOwner(), enableWallpaperControls -> {
|
||||||
|
dimInNightMode.setEnabled(enableWallpaperControls);
|
||||||
|
clearWallpaper.setVisibility(enableWallpaperControls ? View.VISIBLE : View.GONE);
|
||||||
|
updateDividerVisibility();
|
||||||
|
});
|
||||||
|
|
||||||
|
chatWallpaperPreview.setOnClickListener(unused -> setWallpaper.performClick());
|
||||||
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.setVisibility(viewModel.isGlobal() ? View.VISIBLE : View.GONE);
|
||||||
|
updateDividerVisibility();
|
||||||
|
|
||||||
|
clearWallpaper.setOnClickListener(unused -> {
|
||||||
|
confirmAction(R.string.ChatWallpaperFragment__clear_wallpaper_question_mark,
|
||||||
|
R.string.ChatWallpaperFragment__clear,
|
||||||
|
() -> {
|
||||||
|
viewModel.setWallpaper(null);
|
||||||
|
viewModel.setDimInDarkTheme(false);
|
||||||
|
viewModel.saveWallpaperSelection();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
resetAllWallpaper.setOnClickListener(unused -> {
|
resetAllWallpaper.setOnClickListener(unused -> {
|
||||||
viewModel.setWallpaper(null);
|
confirmAction(R.string.ChatWallpaperFragment__reset_all_wallpapers_question_mark,
|
||||||
viewModel.setDimInDarkTheme(false);
|
R.string.ChatWallpaperFragment__reset,
|
||||||
viewModel.resetAllWallpaper();
|
() -> {
|
||||||
|
viewModel.setWallpaper(null);
|
||||||
|
viewModel.setDimInDarkTheme(false);
|
||||||
|
viewModel.resetAllWallpaper();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
dimInNightMode.setOnCheckedChangeListener((buttonView, isChecked) -> viewModel.setDimInDarkTheme(isChecked));
|
dimInNightMode.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
||||||
|
if (!isSettingDimFromViewModel) {
|
||||||
|
viewModel.setDimInDarkTheme(isChecked);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateDividerVisibility() {
|
||||||
|
if (clearWallpaper.getVisibility() == View.VISIBLE || resetAllWallpaper.getVisibility() == View.VISIBLE) {
|
||||||
|
divider.setVisibility(View.VISIBLE);
|
||||||
|
} else {
|
||||||
|
divider.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void confirmAction(@StringRes int title, @StringRes int positiveActionLabel, @NonNull Runnable onPositiveAction) {
|
||||||
|
new AlertDialog.Builder(requireContext())
|
||||||
|
.setMessage(title)
|
||||||
|
.setPositiveButton(positiveActionLabel, (dialog, which) -> {
|
||||||
|
onPositiveAction.run();
|
||||||
|
dialog.dismiss();
|
||||||
|
})
|
||||||
|
.setNegativeButton(android.R.string.cancel, (dialog, which) -> {
|
||||||
|
dialog.dismiss();
|
||||||
|
})
|
||||||
|
.setCancelable(true)
|
||||||
|
.show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+21
-2
@@ -2,24 +2,30 @@ package org.thoughtcrime.securesms.wallpaper;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.graphics.PorterDuff;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
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.core.graphics.drawable.DrawableCompat;
|
||||||
|
import androidx.core.view.ViewCompat;
|
||||||
import androidx.viewpager2.widget.ViewPager2;
|
import androidx.viewpager2.widget.ViewPager2;
|
||||||
|
|
||||||
import com.annimon.stream.Stream;
|
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.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||||
import org.thoughtcrime.securesms.util.ActivityTransitionUtil;
|
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 org.thoughtcrime.securesms.util.MappingModel;
|
||||||
|
import org.thoughtcrime.securesms.util.WindowUtil;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
||||||
@@ -27,14 +33,16 @@ public class ChatWallpaperPreviewActivity extends PassphraseRequiredActivity {
|
|||||||
|
|
||||||
public static final String EXTRA_CHAT_WALLPAPER = "extra.chat.wallpaper";
|
public static final String EXTRA_CHAT_WALLPAPER = "extra.chat.wallpaper";
|
||||||
private static final String EXTRA_DIM_IN_DARK_MODE = "extra.dim.in.dark.mode";
|
private static final String EXTRA_DIM_IN_DARK_MODE = "extra.dim.in.dark.mode";
|
||||||
|
private static final String EXTRA_RECIPIENT_ID = "extra.recipient.id";
|
||||||
|
|
||||||
private final DynamicTheme dynamicTheme = new DynamicNoActionBarTheme();
|
private final DynamicTheme dynamicTheme = new DynamicNoActionBarTheme();
|
||||||
|
|
||||||
public static @NonNull Intent create(@NonNull Context context, @NonNull ChatWallpaper selection, boolean dimInDarkMode) {
|
public static @NonNull Intent create(@NonNull Context context, @NonNull ChatWallpaper selection, @NonNull RecipientId recipientId, 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_DIM_IN_DARK_MODE, dimInDarkMode);
|
intent.putExtra(EXTRA_DIM_IN_DARK_MODE, dimInDarkMode);
|
||||||
|
intent.putExtra(EXTRA_RECIPIENT_ID, recipientId);
|
||||||
|
|
||||||
return intent;
|
return intent;
|
||||||
}
|
}
|
||||||
@@ -52,6 +60,8 @@ public class ChatWallpaperPreviewActivity extends PassphraseRequiredActivity {
|
|||||||
ChatWallpaper selected = getIntent().getParcelableExtra(EXTRA_CHAT_WALLPAPER);
|
ChatWallpaper selected = getIntent().getParcelableExtra(EXTRA_CHAT_WALLPAPER);
|
||||||
boolean dim = getIntent().getBooleanExtra(EXTRA_DIM_IN_DARK_MODE, false);
|
boolean dim = getIntent().getBooleanExtra(EXTRA_DIM_IN_DARK_MODE, false);
|
||||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||||
|
View bubble1 = findViewById(R.id.preview_bubble_1);
|
||||||
|
TextView bubble2 = findViewById(R.id.preview_bubble_2_text);
|
||||||
|
|
||||||
toolbar.setNavigationOnClickListener(unused -> {
|
toolbar.setNavigationOnClickListener(unused -> {
|
||||||
finish();
|
finish();
|
||||||
@@ -62,7 +72,7 @@ public class ChatWallpaperPreviewActivity extends PassphraseRequiredActivity {
|
|||||||
|
|
||||||
adapter.submitList(Collections.singletonList(new ChatWallpaperSelectionMappingModel(selected)));
|
adapter.submitList(Collections.singletonList(new ChatWallpaperSelectionMappingModel(selected)));
|
||||||
repository.getAllWallpaper(wallpapers -> adapter.submitList(Stream.of(wallpapers)
|
repository.getAllWallpaper(wallpapers -> adapter.submitList(Stream.of(wallpapers)
|
||||||
.map(wallpaper -> ChatWallpaperFactory.updateWithDimming(wallpaper, dim ? 1f : 0f))
|
.map(wallpaper -> ChatWallpaperFactory.updateWithDimming(wallpaper, dim ? ChatWallpaper.FIXED_DIM_LEVEL_FOR_DARK_THEME : 0f))
|
||||||
.<MappingModel<?>>map(ChatWallpaperSelectionMappingModel::new)
|
.<MappingModel<?>>map(ChatWallpaperSelectionMappingModel::new)
|
||||||
.toList()));
|
.toList()));
|
||||||
|
|
||||||
@@ -73,7 +83,16 @@ public class ChatWallpaperPreviewActivity extends PassphraseRequiredActivity {
|
|||||||
finish();
|
finish();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
RecipientId recipientId = getIntent().getParcelableExtra(EXTRA_RECIPIENT_ID);
|
||||||
|
if (recipientId != null) {
|
||||||
|
Recipient recipient = Recipient.live(recipientId).get();
|
||||||
|
bubble1.getBackground().setColorFilter(recipient.getColor().toConversationColor(this), PorterDuff.Mode.SRC_IN);
|
||||||
|
bubble2.setText(getString(R.string.ChatWallpaperPreviewActivity__set_wallpaper_for_s, recipient.getDisplayName(this)));
|
||||||
|
}
|
||||||
|
|
||||||
new FullscreenHelper(this).showSystemUI();
|
new FullscreenHelper(this).showSystemUI();
|
||||||
|
WindowUtil.setLightStatusBarFromTheme(this);
|
||||||
|
WindowUtil.setLightNavigationBarFromTheme(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+22
-4
@@ -14,6 +14,8 @@ import org.thoughtcrime.securesms.recipients.RecipientId;
|
|||||||
import org.thoughtcrime.securesms.util.concurrent.SerialExecutor;
|
import org.thoughtcrime.securesms.util.concurrent.SerialExecutor;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
@@ -24,14 +26,19 @@ class ChatWallpaperRepository {
|
|||||||
@MainThread
|
@MainThread
|
||||||
@Nullable ChatWallpaper getCurrentWallpaper(@Nullable RecipientId recipientId) {
|
@Nullable ChatWallpaper getCurrentWallpaper(@Nullable RecipientId recipientId) {
|
||||||
if (recipientId != null) {
|
if (recipientId != null) {
|
||||||
return Recipient.resolved(recipientId).getWallpaper();
|
return Recipient.live(recipientId).get().getWallpaper();
|
||||||
} else {
|
} else {
|
||||||
return SignalStore.wallpaper().getWallpaper();
|
return SignalStore.wallpaper().getWallpaper();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void getAllWallpaper(@NonNull Consumer<List<ChatWallpaper>> consumer) {
|
void getAllWallpaper(@NonNull Consumer<List<ChatWallpaper>> consumer) {
|
||||||
consumer.accept(ChatWallpaper.BUILTINS);
|
EXECUTOR.execute(() -> {
|
||||||
|
List<ChatWallpaper> wallpapers = new ArrayList<>(ChatWallpaper.BUILTINS);
|
||||||
|
|
||||||
|
wallpapers.addAll(WallpaperStorage.getAll(ApplicationDependencies.getApplication()));
|
||||||
|
consumer.accept(wallpapers);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void saveWallpaper(@Nullable RecipientId recipientId, @Nullable ChatWallpaper chatWallpaper) {
|
void saveWallpaper(@Nullable RecipientId recipientId, @Nullable ChatWallpaper chatWallpaper) {
|
||||||
@@ -52,10 +59,21 @@ class ChatWallpaperRepository {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void setDimInDarkTheme(@NonNull RecipientId recipientId, boolean dimInDarkTheme) {
|
void setDimInDarkTheme(@Nullable RecipientId recipientId, boolean dimInDarkTheme) {
|
||||||
if (recipientId != null) {
|
if (recipientId != null) {
|
||||||
EXECUTOR.execute(() -> {
|
EXECUTOR.execute(() -> {
|
||||||
DatabaseFactory.getRecipientDatabase(ApplicationDependencies.getApplication()).setDimWallpaperInDarkTheme(recipientId, dimInDarkTheme);
|
Recipient recipient = Recipient.resolved(recipientId);
|
||||||
|
if (recipient.hasOwnWallpaper()) {
|
||||||
|
DatabaseFactory.getRecipientDatabase(ApplicationDependencies.getApplication()).setDimWallpaperInDarkTheme(recipientId, dimInDarkTheme);
|
||||||
|
} else if (recipient.hasWallpaper()) {
|
||||||
|
DatabaseFactory.getRecipientDatabase(ApplicationDependencies.getApplication())
|
||||||
|
.setWallpaper(recipientId,
|
||||||
|
ChatWallpaperFactory.updateWithDimming(recipient.getWallpaper(),
|
||||||
|
dimInDarkTheme ? ChatWallpaper.FIXED_DIM_LEVEL_FOR_DARK_THEME
|
||||||
|
: 0f));
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException("Unexpected call to setDimInDarkTheme, no wallpaper has been set on the given recipient or globally.");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
SignalStore.wallpaper().setDimInDarkTheme(dimInDarkTheme);
|
SignalStore.wallpaper().setDimInDarkTheme(dimInDarkTheme);
|
||||||
|
|||||||
+27
-3
@@ -1,11 +1,13 @@
|
|||||||
package org.thoughtcrime.securesms.wallpaper;
|
package org.thoughtcrime.securesms.wallpaper;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
@@ -14,10 +16,12 @@ import androidx.lifecycle.ViewModelProviders;
|
|||||||
import androidx.navigation.Navigation;
|
import androidx.navigation.Navigation;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import com.google.android.flexbox.AlignContent;
|
||||||
import com.google.android.flexbox.FlexboxLayoutManager;
|
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.permissions.Permissions;
|
||||||
import org.thoughtcrime.securesms.util.ActivityTransitionUtil;
|
import org.thoughtcrime.securesms.util.ActivityTransitionUtil;
|
||||||
import org.thoughtcrime.securesms.wallpaper.crop.WallpaperImageSelectionActivity;
|
import org.thoughtcrime.securesms.wallpaper.crop.WallpaperImageSelectionActivity;
|
||||||
|
|
||||||
@@ -39,23 +43,30 @@ public class ChatWallpaperSelectionFragment extends Fragment {
|
|||||||
FlexboxLayoutManager flexboxLayoutManager = new FlexboxLayoutManager(requireContext());
|
FlexboxLayoutManager flexboxLayoutManager = new FlexboxLayoutManager(requireContext());
|
||||||
|
|
||||||
chooseFromPhotos.setOnClickListener(unused -> {
|
chooseFromPhotos.setOnClickListener(unused -> {
|
||||||
startActivityForResult(WallpaperImageSelectionActivity.getIntent(requireContext(), viewModel.getRecipientId()), CHOOSE_WALLPAPER);
|
askForPermissionIfNeededAndLaunchPhotoSelection();
|
||||||
});
|
});
|
||||||
|
|
||||||
@SuppressWarnings("CodeBlock2Expr")
|
@SuppressWarnings("CodeBlock2Expr")
|
||||||
ChatWallpaperSelectionAdapter adapter = new ChatWallpaperSelectionAdapter(chatWallpaper -> {
|
ChatWallpaperSelectionAdapter adapter = new ChatWallpaperSelectionAdapter(chatWallpaper -> {
|
||||||
startActivityForResult(ChatWallpaperPreviewActivity.create(requireActivity(), chatWallpaper, viewModel.getDimInDarkTheme().getValue()), CHOOSE_WALLPAPER);
|
startActivityForResult(ChatWallpaperPreviewActivity.create(requireActivity(), chatWallpaper, viewModel.getRecipientId(), viewModel.getDimInDarkTheme().getValue()), CHOOSE_WALLPAPER);
|
||||||
ActivityTransitionUtil.setSlideInTransition(requireActivity());
|
ActivityTransitionUtil.setSlideInTransition(requireActivity());
|
||||||
});
|
});
|
||||||
|
|
||||||
flexboxLayoutManager.setJustifyContent(JustifyContent.SPACE_AROUND);
|
flexboxLayoutManager.setJustifyContent(JustifyContent.CENTER);
|
||||||
recyclerView.setLayoutManager(flexboxLayoutManager);
|
recyclerView.setLayoutManager(flexboxLayoutManager);
|
||||||
recyclerView.setAdapter(adapter);
|
recyclerView.setAdapter(adapter);
|
||||||
|
recyclerView.addItemDecoration(new ChatWallpaperAlignmentDecoration());
|
||||||
|
|
||||||
viewModel = ViewModelProviders.of(requireActivity()).get(ChatWallpaperViewModel.class);
|
viewModel = ViewModelProviders.of(requireActivity()).get(ChatWallpaperViewModel.class);
|
||||||
viewModel.getWallpapers().observe(getViewLifecycleOwner(), adapter::submitList);
|
viewModel.getWallpapers().observe(getViewLifecycleOwner(), adapter::submitList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
viewModel.refreshWallpaper();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
|
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
|
||||||
if (requestCode == CHOOSE_WALLPAPER && resultCode == Activity.RESULT_OK && data != null) {
|
if (requestCode == CHOOSE_WALLPAPER && resultCode == Activity.RESULT_OK && data != null) {
|
||||||
@@ -67,4 +78,17 @@ public class ChatWallpaperSelectionFragment extends Fragment {
|
|||||||
super.onActivityResult(requestCode, resultCode, data);
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void askForPermissionIfNeededAndLaunchPhotoSelection() {
|
||||||
|
Permissions.with(this)
|
||||||
|
.request(Manifest.permission.READ_EXTERNAL_STORAGE)
|
||||||
|
.ifNecessary()
|
||||||
|
.onAllGranted(() -> {
|
||||||
|
startActivityForResult(WallpaperImageSelectionActivity.getIntent(requireContext(), viewModel.getRecipientId()), CHOOSE_WALLPAPER);
|
||||||
|
ActivityTransitionUtil.setSlideInTransition(requireActivity());
|
||||||
|
})
|
||||||
|
.onAnyDenied(() -> Toast.makeText(requireContext(), R.string.ChatWallpaperPreviewActivity__viewing_your_gallery_requires_the_storage_permission, Toast.LENGTH_SHORT)
|
||||||
|
.show())
|
||||||
|
.execute();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import androidx.lifecycle.ViewModelProvider;
|
|||||||
|
|
||||||
import com.annimon.stream.Stream;
|
import com.annimon.stream.Stream;
|
||||||
|
|
||||||
|
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||||
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
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.thoughtcrime.securesms.util.livedata.LiveDataUtil;
|
||||||
@@ -19,10 +21,11 @@ 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 MutableLiveData<Boolean> dimInDarkTheme = new MutableLiveData<>();
|
||||||
|
private final MutableLiveData<Boolean> enableWallpaperControls = new MutableLiveData<>();
|
||||||
private final RecipientId recipientId;
|
private final RecipientId recipientId;
|
||||||
|
|
||||||
private ChatWallpaperViewModel(@Nullable RecipientId recipientId) {
|
private ChatWallpaperViewModel(@Nullable RecipientId recipientId) {
|
||||||
@@ -30,7 +33,11 @@ public class ChatWallpaperViewModel extends ViewModel {
|
|||||||
|
|
||||||
ChatWallpaper currentWallpaper = repository.getCurrentWallpaper(recipientId);
|
ChatWallpaper currentWallpaper = repository.getCurrentWallpaper(recipientId);
|
||||||
dimInDarkTheme.setValue(currentWallpaper != null && currentWallpaper.getDimLevelForDarkTheme() > 0f);
|
dimInDarkTheme.setValue(currentWallpaper != null && currentWallpaper.getDimLevelForDarkTheme() > 0f);
|
||||||
|
enableWallpaperControls.setValue(hasClearableWallpaper());
|
||||||
wallpaper.setValue(Optional.fromNullable(currentWallpaper));
|
wallpaper.setValue(Optional.fromNullable(currentWallpaper));
|
||||||
|
}
|
||||||
|
|
||||||
|
void refreshWallpaper() {
|
||||||
repository.getAllWallpaper(builtins::postValue);
|
repository.getAllWallpaper(builtins::postValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,7 +60,18 @@ public class ChatWallpaperViewModel extends ViewModel {
|
|||||||
|
|
||||||
if (!wallpaper.isPresent()) {
|
if (!wallpaper.isPresent()) {
|
||||||
repository.saveWallpaper(recipientId, null);
|
repository.saveWallpaper(recipientId, null);
|
||||||
|
|
||||||
|
if (recipientId != null) {
|
||||||
|
ChatWallpaper globalWallpaper = SignalStore.wallpaper().getWallpaper();
|
||||||
|
|
||||||
|
this.wallpaper.setValue(Optional.fromNullable(globalWallpaper));
|
||||||
|
this.dimInDarkTheme.setValue(globalWallpaper != null && globalWallpaper.getDimLevelForDarkTheme() > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
enableWallpaperControls.setValue(false);
|
||||||
return;
|
return;
|
||||||
|
} else {
|
||||||
|
enableWallpaperControls.setValue(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<ChatWallpaper> updated = wallpaper.transform(paper -> ChatWallpaperFactory.updateWithDimming(paper, dimInDarkTheme ? ChatWallpaper.FIXED_DIM_LEVEL_FOR_DARK_THEME : 0f));
|
Optional<ChatWallpaper> updated = wallpaper.transform(paper -> ChatWallpaperFactory.updateWithDimming(paper, dimInDarkTheme ? ChatWallpaper.FIXED_DIM_LEVEL_FOR_DARK_THEME : 0f));
|
||||||
@@ -67,30 +85,39 @@ public class ChatWallpaperViewModel extends ViewModel {
|
|||||||
repository.resetAllWallpaper();
|
repository.resetAllWallpaper();
|
||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable RecipientId getRecipientId() {
|
@Nullable RecipientId getRecipientId() {
|
||||||
return recipientId;
|
return recipientId;
|
||||||
}
|
}
|
||||||
|
|
||||||
LiveData<Optional<ChatWallpaper>> getCurrentWallpaper() {
|
@NonNull LiveData<Optional<ChatWallpaper>> getCurrentWallpaper() {
|
||||||
return wallpaper;
|
return wallpaper;
|
||||||
}
|
}
|
||||||
|
|
||||||
LiveData<List<MappingModel<?>>> getWallpapers() {
|
@NonNull LiveData<List<MappingModel<?>>> getWallpapers() {
|
||||||
return LiveDataUtil.combineLatest(builtins, dimInDarkTheme, (wallpapers, dimInDarkMode) ->
|
return LiveDataUtil.combineLatest(builtins, dimInDarkTheme, (wallpapers, dimInDarkMode) ->
|
||||||
Stream.of(wallpapers)
|
Stream.of(wallpapers)
|
||||||
.map(paper -> ChatWallpaperFactory.updateWithDimming(paper, dimInDarkMode ? 1f : 0f))
|
.map(paper -> ChatWallpaperFactory.updateWithDimming(paper, dimInDarkMode ? ChatWallpaper.FIXED_DIM_LEVEL_FOR_DARK_THEME : 0f))
|
||||||
.<MappingModel<?>>map(ChatWallpaperSelectionMappingModel::new).toList()
|
.<MappingModel<?>>map(ChatWallpaperSelectionMappingModel::new).toList()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
LiveData<Boolean> getDimInDarkTheme() {
|
@NonNull LiveData<Boolean> getDimInDarkTheme() {
|
||||||
return dimInDarkTheme;
|
return dimInDarkTheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull LiveData<Boolean> getEnableWallpaperControls() {
|
||||||
|
return enableWallpaperControls;
|
||||||
|
}
|
||||||
|
|
||||||
boolean isGlobal() {
|
boolean isGlobal() {
|
||||||
return recipientId == null;
|
return recipientId == null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean hasClearableWallpaper() {
|
||||||
|
return (isGlobal() && SignalStore.wallpaper().hasWallpaperSet()) ||
|
||||||
|
(recipientId != null && Recipient.live(recipientId).get().hasOwnWallpaper());
|
||||||
|
}
|
||||||
|
|
||||||
public static class Factory implements ViewModelProvider.Factory {
|
public static class Factory implements ViewModelProvider.Factory {
|
||||||
|
|
||||||
private final RecipientId recipientId;
|
private final RecipientId recipientId;
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import java.io.File;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
@@ -39,9 +40,9 @@ public final class WallpaperStorage {
|
|||||||
* Saves the provided input stream as a new wallpaper file.
|
* Saves the provided input stream as a new wallpaper file.
|
||||||
*/
|
*/
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
public static @NonNull ChatWallpaper save(@NonNull Context context, @NonNull InputStream wallpaperStream) throws IOException {
|
public static @NonNull ChatWallpaper save(@NonNull Context context, @NonNull InputStream wallpaperStream, @NonNull String extension) throws IOException {
|
||||||
File directory = context.getDir(DIRECTORY, Context.MODE_PRIVATE);
|
File directory = context.getDir(DIRECTORY, Context.MODE_PRIVATE);
|
||||||
File file = File.createTempFile(FILENAME_BASE, "", directory);
|
File file = File.createTempFile(FILENAME_BASE, "." + extension, directory);
|
||||||
|
|
||||||
StreamUtil.copy(wallpaperStream, getOutputStream(context, file));
|
StreamUtil.copy(wallpaperStream, getOutputStream(context, file));
|
||||||
|
|
||||||
@@ -61,11 +62,15 @@ public final class WallpaperStorage {
|
|||||||
File directory = context.getDir(DIRECTORY, Context.MODE_PRIVATE);
|
File directory = context.getDir(DIRECTORY, Context.MODE_PRIVATE);
|
||||||
File[] allFiles = directory.listFiles(pathname -> pathname.getName().contains(FILENAME_BASE));
|
File[] allFiles = directory.listFiles(pathname -> pathname.getName().contains(FILENAME_BASE));
|
||||||
|
|
||||||
return Stream.of(allFiles)
|
if (allFiles != null) {
|
||||||
.map(File::getName)
|
return Stream.of(allFiles)
|
||||||
.map(PartAuthority::getWallpaperUri)
|
.map(File::getName)
|
||||||
.map(ChatWallpaperFactory::create)
|
.map(PartAuthority::getWallpaperUri)
|
||||||
.toList();
|
.map(ChatWallpaperFactory::create)
|
||||||
|
.toList();
|
||||||
|
} else {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import androidx.annotation.Nullable;
|
|||||||
import androidx.annotation.StyleRes;
|
import androidx.annotation.StyleRes;
|
||||||
import androidx.appcompat.app.ActionBar;
|
import androidx.appcompat.app.ActionBar;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
|
import androidx.appcompat.app.AppCompatDelegate;
|
||||||
import androidx.appcompat.widget.SwitchCompat;
|
import androidx.appcompat.widget.SwitchCompat;
|
||||||
import androidx.appcompat.widget.Toolbar;
|
import androidx.appcompat.widget.Toolbar;
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
@@ -62,6 +63,12 @@ public final class WallpaperCropActivity extends BaseActivity {
|
|||||||
return intent;
|
return intent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void attachBaseContext(@NonNull Context newBase) {
|
||||||
|
getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_YES);
|
||||||
|
super.attachBaseContext(newBase);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|||||||
+1
-1
@@ -33,7 +33,7 @@ final class WallpaperCropRepository {
|
|||||||
@WorkerThread
|
@WorkerThread
|
||||||
@NonNull ChatWallpaper setWallPaper(byte[] bytes) throws IOException {
|
@NonNull ChatWallpaper setWallPaper(byte[] bytes) throws IOException {
|
||||||
try (InputStream inputStream = new ByteArrayInputStream(bytes)) {
|
try (InputStream inputStream = new ByteArrayInputStream(bytes)) {
|
||||||
ChatWallpaper wallpaper = WallpaperStorage.save(context, inputStream);
|
ChatWallpaper wallpaper = WallpaperStorage.save(context, inputStream, "webp");
|
||||||
|
|
||||||
if (recipientId != null) {
|
if (recipientId != null) {
|
||||||
Log.i(TAG, "Setting image wallpaper for " + recipientId);
|
Log.i(TAG, "Setting image wallpaper for " + recipientId);
|
||||||
|
|||||||
+3
@@ -1,11 +1,13 @@
|
|||||||
package org.thoughtcrime.securesms.wallpaper.crop;
|
package org.thoughtcrime.securesms.wallpaper.crop;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.annotation.RequiresPermission;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import androidx.appcompat.app.AppCompatDelegate;
|
import androidx.appcompat.app.AppCompatDelegate;
|
||||||
|
|
||||||
@@ -23,6 +25,7 @@ public final class WallpaperImageSelectionActivity extends AppCompatActivity
|
|||||||
private static final String EXTRA_RECIPIENT_ID = "RECIPIENT_ID";
|
private static final String EXTRA_RECIPIENT_ID = "RECIPIENT_ID";
|
||||||
private static final int CROP = 901;
|
private static final int CROP = 901;
|
||||||
|
|
||||||
|
@RequiresPermission(Manifest.permission.READ_EXTERNAL_STORAGE)
|
||||||
public static Intent getIntent(@NonNull Context context,
|
public static Intent getIntent(@NonNull Context context,
|
||||||
@Nullable RecipientId recipientId)
|
@Nullable RecipientId recipientId)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<solid android:color="@color/signal_background_secondary" />
|
||||||
|
<corners
|
||||||
|
android:radius="50dp" />
|
||||||
|
</shape>
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/signal_background_primary"
|
||||||
tools:layout_height="200dp">
|
tools:layout_height="200dp">
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
|||||||
@@ -55,6 +55,65 @@
|
|||||||
app:layout_constraintTop_toTopOf="@id/chat_wallpaper_preview_background"
|
app:layout_constraintTop_toTopOf="@id/chat_wallpaper_preview_background"
|
||||||
app:layout_constraintVertical_chainStyle="packed" />
|
app:layout_constraintVertical_chainStyle="packed" />
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
|
android:id="@+id/chat_wallpaper_preview_top_bar_navigation"
|
||||||
|
android:layout_width="10dp"
|
||||||
|
android:layout_height="10dp"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
android:layout_marginBottom="4dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/chat_wallpaper_preview_top_bar"
|
||||||
|
app:layout_constraintStart_toStartOf="@id/chat_wallpaper_preview_top_bar"
|
||||||
|
app:srcCompat="@drawable/ic_arrow_left_24"
|
||||||
|
app:tint="@color/core_white" />
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
|
android:id="@+id/chat_wallpaper_preview_top_bar_portrait"
|
||||||
|
android:layout_width="16dp"
|
||||||
|
android:layout_height="16dp"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
android:layout_marginBottom="2dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/chat_wallpaper_preview_top_bar"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/chat_wallpaper_preview_top_bar_navigation"
|
||||||
|
app:srcCompat="@drawable/circle_tintable"
|
||||||
|
app:tint="@color/core_white" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
android:layout_marginEnd="4dp"
|
||||||
|
android:layout_marginBottom="4dp"
|
||||||
|
android:text="@string/ChatWallpaperFragment__contact_name"
|
||||||
|
android:textAppearance="@style/Signal.Text.Body"
|
||||||
|
android:textColor="@color/core_white"
|
||||||
|
android:textSize="8sp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/chat_wallpaper_preview_top_bar"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/chat_wallpaper_preview_top_bar_video"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/chat_wallpaper_preview_top_bar_portrait"
|
||||||
|
tools:ignore="SmallSp" />
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
|
android:id="@+id/chat_wallpaper_preview_top_bar_video"
|
||||||
|
android:layout_width="10dp"
|
||||||
|
android:layout_height="10dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:layout_marginBottom="4dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/chat_wallpaper_preview_top_bar"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/chat_wallpaper_preview_top_bar_voice"
|
||||||
|
app:srcCompat="@drawable/ic_video_solid_24"
|
||||||
|
app:tint="@color/core_white" />
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
|
android:id="@+id/chat_wallpaper_preview_top_bar_voice"
|
||||||
|
android:layout_width="10dp"
|
||||||
|
android:layout_height="10dp"
|
||||||
|
android:layout_marginEnd="6dp"
|
||||||
|
android:layout_marginBottom="4dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/chat_wallpaper_preview_top_bar"
|
||||||
|
app:layout_constraintEnd_toEndOf="@id/chat_wallpaper_preview_top_bar"
|
||||||
|
app:srcCompat="@drawable/ic_phone_right_solid_24"
|
||||||
|
app:tint="@color/core_white" />
|
||||||
|
|
||||||
<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"
|
||||||
@@ -64,6 +123,33 @@
|
|||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent" />
|
app:layout_constraintStart_toStartOf="parent" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/chat_wallpaper_preview_bottom_bar_input"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="14dp"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:background="@drawable/chat_wallpaper_preview_input"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/chat_wallpaper_preview_bottom_bar"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/chat_wallpaper_preview_bottom_bar_plus"
|
||||||
|
app:layout_constraintStart_toStartOf="@id/chat_wallpaper_preview_bottom_bar"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/chat_wallpaper_preview_bottom_bar" />
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
|
android:id="@+id/chat_wallpaper_preview_bottom_bar_plus"
|
||||||
|
android:layout_width="14dp"
|
||||||
|
android:layout_height="14dp"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:background="@drawable/circle_tintable"
|
||||||
|
android:padding="2dp"
|
||||||
|
app:backgroundTint="@color/signal_accent_primary"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/chat_wallpaper_preview_bottom_bar"
|
||||||
|
app:layout_constraintEnd_toEndOf="@id/chat_wallpaper_preview_bottom_bar"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/chat_wallpaper_preview_bottom_bar_input"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/chat_wallpaper_preview_bottom_bar"
|
||||||
|
app:srcCompat="@drawable/ic_plus_24"
|
||||||
|
app:tint="@color/core_white" />
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatImageView
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
android:id="@+id/chat_wallpaper_preview_today"
|
android:id="@+id/chat_wallpaper_preview_today"
|
||||||
android:layout_width="24dp"
|
android:layout_width="24dp"
|
||||||
@@ -95,7 +181,7 @@
|
|||||||
app:layout_constraintEnd_toEndOf="@id/chat_wallpaper_preview_background"
|
app:layout_constraintEnd_toEndOf="@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"
|
||||||
app:srcCompat="@drawable/chat_wallpaper_preview_bubble_10"
|
app:srcCompat="@drawable/chat_wallpaper_preview_bubble_10"
|
||||||
app:tint="@color/signal_background_tertiary" />
|
app:tint="@color/signal_background_secondary" />
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
@@ -141,6 +227,8 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="1dp"
|
android:layout_height="1dp"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="16dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible"
|
||||||
android:background="@color/signal_inverse_transparent_15"
|
android:background="@color/signal_inverse_transparent_15"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
@@ -158,9 +246,11 @@
|
|||||||
android:text="@string/ChatWallpaperFragment__clear_wallpaper"
|
android:text="@string/ChatWallpaperFragment__clear_wallpaper"
|
||||||
android:textAppearance="@style/Signal.Text.Body"
|
android:textAppearance="@style/Signal.Text.Body"
|
||||||
android:textColor="@color/signal_text_primary"
|
android:textColor="@color/signal_text_primary"
|
||||||
|
android:visibility="gone"
|
||||||
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_divider" />
|
app:layout_constraintTop_toBottomOf="@id/chat_wallpaper_divider"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/chat_wallpaper_reset_all_wallpapers"
|
android:id="@+id/chat_wallpaper_reset_all_wallpapers"
|
||||||
|
|||||||
@@ -65,14 +65,15 @@
|
|||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/ChatWallpaperPreviewActivity__this_wallpaper_will_be_set_for_all_chats"
|
android:maxWidth="194dp"
|
||||||
|
android:text="@string/ChatWallpaperPreviewActivity__swipe_to_preview_more_wallpapers"
|
||||||
android:textAppearance="@style/Signal.Text.Body"
|
android:textAppearance="@style/Signal.Text.Body"
|
||||||
android:textColor="@color/core_white" />
|
android:textColor="@color/core_white" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/ChatWallpaperPreviewActivity__10_49_am"
|
android:text="@string/DateUtils_just_now"
|
||||||
android:textAppearance="@style/Signal.Text.Caption"
|
android:textAppearance="@style/Signal.Text.Caption"
|
||||||
android:textColor="@color/transparent_white_80" />
|
android:textColor="@color/transparent_white_80" />
|
||||||
|
|
||||||
@@ -95,10 +96,12 @@
|
|||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/preview_bubble_1">
|
app:layout_constraintTop_toBottomOf="@id/preview_bubble_1">
|
||||||
|
|
||||||
<TextView
|
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
|
||||||
|
android:id="@+id/preview_bubble_2_text"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/ChatWallpaperPreviewActivity__besides_those_you_manually_override"
|
android:maxWidth="194dp"
|
||||||
|
android:text="@string/ChatWallpaperPreviewActivity__set_wallpaper_for_all_chats"
|
||||||
android:textAppearance="@style/Signal.Text.Body"
|
android:textAppearance="@style/Signal.Text.Body"
|
||||||
android:textColor="@color/signal_text_primary" />
|
android:textColor="@color/signal_text_primary" />
|
||||||
|
|
||||||
@@ -107,7 +110,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="end"
|
android:layout_gravity="end"
|
||||||
android:drawablePadding="4dp"
|
android:drawablePadding="4dp"
|
||||||
android:text="@string/ChatWallpaperPreviewActivity__10_49_am"
|
android:text="@string/DateUtils_just_now"
|
||||||
android:textAppearance="@style/Signal.Text.Caption"
|
android:textAppearance="@style/Signal.Text.Caption"
|
||||||
android:textColor="@color/signal_text_secondary"
|
android:textColor="@color/signal_text_secondary"
|
||||||
app:drawableEndCompat="@drawable/ic_delivery_status_read"
|
app:drawableEndCompat="@drawable/ic_delivery_status_read"
|
||||||
|
|||||||
@@ -8,14 +8,17 @@
|
|||||||
android:background="@drawable/conversation_item_background"
|
android:background="@drawable/conversation_item_background"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
android:paddingStart="26dp"
|
android:paddingStart="26dp"
|
||||||
android:paddingEnd="26dp">
|
android:paddingEnd="26dp"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:clipChildren="false">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/conversation_update_background"
|
android:id="@+id/conversation_update_background"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:layout_marginBottom="3dp"
|
android:layout_marginTop="2dp"
|
||||||
|
android:layout_marginBottom="2dp"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:paddingTop="8dp"
|
android:paddingTop="8dp"
|
||||||
|
|||||||
@@ -2829,7 +2829,12 @@
|
|||||||
<string name="ChatWallpaperFragment__set_wallpaper">Set wallpaper</string>
|
<string name="ChatWallpaperFragment__set_wallpaper">Set wallpaper</string>
|
||||||
<string name="ChatWallpaperFragment__dark_theme_dims_wallpaper">Dark theme dims wallpaper</string>
|
<string name="ChatWallpaperFragment__dark_theme_dims_wallpaper">Dark theme dims wallpaper</string>
|
||||||
<string name="ChatWallpaperFragment__clear_wallpaper">Clear wallpaper</string>
|
<string name="ChatWallpaperFragment__clear_wallpaper">Clear wallpaper</string>
|
||||||
|
<string name="ChatWallpaperFragment__clear_wallpaper_question_mark">Clear wallpaper?</string>
|
||||||
<string name="ChatWallpaperFragment__reset_all_wallpapers">Reset all wallpapers</string>
|
<string name="ChatWallpaperFragment__reset_all_wallpapers">Reset all wallpapers</string>
|
||||||
|
<string name="ChatWallpaperFragment__reset_all_wallpapers_question_mark">Reset all wallpapers?</string>
|
||||||
|
<string name="ChatWallpaperFragment__contact_name">Contact name</string>
|
||||||
|
<string name="ChatWallpaperFragment__reset">Reset</string>
|
||||||
|
<string name="ChatWallpaperFragment__clear">Clear</string>
|
||||||
|
|
||||||
<!-- ChatWallpaperSelectionFragment -->
|
<!-- ChatWallpaperSelectionFragment -->
|
||||||
<string name="ChatWallpaperSelectionFragment__choose_from_photos">Choose from photos</string>
|
<string name="ChatWallpaperSelectionFragment__choose_from_photos">Choose from photos</string>
|
||||||
@@ -2838,9 +2843,10 @@
|
|||||||
<!-- ChatWallpaperPreviewActivity -->
|
<!-- ChatWallpaperPreviewActivity -->
|
||||||
<string name="ChatWallpaperPreviewActivity__preview">Preview</string>
|
<string name="ChatWallpaperPreviewActivity__preview">Preview</string>
|
||||||
<string name="ChatWallpaperPreviewActivity__set_wallpaper">Set wallpaper</string>
|
<string name="ChatWallpaperPreviewActivity__set_wallpaper">Set wallpaper</string>
|
||||||
<string name="ChatWallpaperPreviewActivity__10_49_am">10:49 am</string>
|
<string name="ChatWallpaperPreviewActivity__swipe_to_preview_more_wallpapers">Swipe to preview more wallpapers</string>
|
||||||
<string name="ChatWallpaperPreviewActivity__this_wallpaper_will_be_set_for_all_chats">This wallpaper will be set for all chats</string>
|
<string name="ChatWallpaperPreviewActivity__set_wallpaper_for_all_chats">Set wallpaper for all chats</string>
|
||||||
<string name="ChatWallpaperPreviewActivity__besides_those_you_manually_override">Besides those you manually override</string>
|
<string name="ChatWallpaperPreviewActivity__set_wallpaper_for_s">Set wallpaper for %1$s</string>
|
||||||
|
<string name="ChatWallpaperPreviewActivity__viewing_your_gallery_requires_the_storage_permission">Viewing your gallery requires the storage permission.</string>
|
||||||
|
|
||||||
<!-- WallpaperImageSelectionActivity -->
|
<!-- WallpaperImageSelectionActivity -->
|
||||||
<string name="WallpaperImageSelectionActivity__choose_wallpaper_image">Choose wallpaper image</string>
|
<string name="WallpaperImageSelectionActivity__choose_wallpaper_image">Choose wallpaper image</string>
|
||||||
|
|||||||
Reference in New Issue
Block a user