diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiTextView.java b/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiTextView.java index a1147ff94..210f209dd 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiTextView.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiTextView.java @@ -4,12 +4,6 @@ import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.drawable.Drawable; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.core.content.ContextCompat; -import androidx.core.widget.TextViewCompat; -import androidx.appcompat.widget.AppCompatTextView; - import android.text.Annotation; import android.text.SpannableStringBuilder; import android.text.Spanned; @@ -17,12 +11,18 @@ import android.text.TextUtils; import android.util.AttributeSet; import android.util.TypedValue; +import androidx.annotation.ColorInt; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.widget.AppCompatTextView; +import androidx.core.content.ContextCompat; +import androidx.core.widget.TextViewCompat; + import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.components.emoji.EmojiProvider.EmojiDrawable; import org.thoughtcrime.securesms.components.emoji.parsing.EmojiParser; import org.thoughtcrime.securesms.components.mention.MentionAnnotation; import org.thoughtcrime.securesms.components.mention.MentionRendererDelegate; -import org.thoughtcrime.securesms.util.FeatureFlags; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.Util; import org.whispersystems.libsignal.util.guava.Optional; @@ -242,4 +242,10 @@ public class EmojiTextView extends AppCompatTextView { this.originalFontSize = TypedValue.applyDimension(unit, size, getResources().getDisplayMetrics()); super.setTextSize(unit, size); } + + public void setMentionBackgroundTint(@ColorInt int mentionBackgroundTint) { + if (renderMentions) { + mentionRendererDelegate.setTint(mentionBackgroundTint); + } + } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/mention/MentionRendererDelegate.java b/app/src/main/java/org/thoughtcrime/securesms/components/mention/MentionRendererDelegate.java index 76984d63b..4c087cfe3 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/mention/MentionRendererDelegate.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/mention/MentionRendererDelegate.java @@ -9,10 +9,10 @@ import android.text.Spanned; import androidx.annotation.ColorInt; import androidx.annotation.NonNull; -import androidx.annotation.Px; -import androidx.core.content.ContextCompat; +import androidx.core.graphics.drawable.DrawableCompat; import org.thoughtcrime.securesms.R; +import org.thoughtcrime.securesms.util.ContextUtil; import org.thoughtcrime.securesms.util.DrawableUtil; import org.thoughtcrime.securesms.util.ViewUtil; @@ -27,25 +27,28 @@ public class MentionRendererDelegate { private final MentionRenderer single; private final MentionRenderer multi; private final int horizontalPadding; + private final Drawable drawable; + private final Drawable drawableLeft; + private final Drawable drawableMid; + private final Drawable drawableEnd; public MentionRendererDelegate(@NonNull Context context, @ColorInt int tint) { this.horizontalPadding = ViewUtil.dpToPx(2); - Drawable drawable = ContextCompat.getDrawable(context, R.drawable.mention_text_bg); - Drawable drawableLeft = ContextCompat.getDrawable(context, R.drawable.mention_text_bg_left); - Drawable drawableMid = ContextCompat.getDrawable(context, R.drawable.mention_text_bg_mid); - Drawable drawableEnd = ContextCompat.getDrawable(context, R.drawable.mention_text_bg_right); + drawable = DrawableUtil.tint(ContextUtil.requireDrawable(context, R.drawable.mention_text_bg), tint); + drawableLeft = DrawableUtil.tint(ContextUtil.requireDrawable(context, R.drawable.mention_text_bg_left), tint); + drawableMid = DrawableUtil.tint(ContextUtil.requireDrawable(context, R.drawable.mention_text_bg_mid), tint); + drawableEnd = DrawableUtil.tint(ContextUtil.requireDrawable(context, R.drawable.mention_text_bg_right), tint); - //noinspection ConstantConditions single = new MentionRenderer.SingleLineMentionRenderer(horizontalPadding, 0, - DrawableUtil.tint(drawable, tint)); - //noinspection ConstantConditions + drawable); + multi = new MentionRenderer.MultiLineMentionRenderer(horizontalPadding, 0, - DrawableUtil.tint(drawableLeft, tint), - DrawableUtil.tint(drawableMid, tint), - DrawableUtil.tint(drawableEnd, tint)); + drawableLeft, + drawableMid, + drawableEnd); } public void draw(@NonNull Canvas canvas, @NonNull Spanned text, @NonNull Layout layout) { @@ -65,4 +68,11 @@ public class MentionRendererDelegate { } } } + + public void setTint(@ColorInt int tint) { + DrawableCompat.setTint(drawable, tint); + DrawableCompat.setTint(drawableLeft, tint); + DrawableCompat.setTint(drawableMid, tint); + DrawableCompat.setTint(drawableEnd, tint); + } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java index 23b6b9435..b7eadcd9b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java @@ -52,6 +52,7 @@ import androidx.annotation.DimenRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; +import androidx.core.content.ContextCompat; import com.annimon.stream.Stream; @@ -63,6 +64,7 @@ import org.thoughtcrime.securesms.attachments.DatabaseAttachment; import org.thoughtcrime.securesms.components.AlertView; import org.thoughtcrime.securesms.components.AudioView; import org.thoughtcrime.securesms.components.AvatarImageView; +import org.thoughtcrime.securesms.components.BorderlessImageView; import org.thoughtcrime.securesms.components.ConversationItemFooter; import org.thoughtcrime.securesms.components.ConversationItemThumbnail; import org.thoughtcrime.securesms.components.DocumentView; @@ -70,7 +72,6 @@ import org.thoughtcrime.securesms.components.LinkPreviewView; import org.thoughtcrime.securesms.components.Outliner; import org.thoughtcrime.securesms.components.QuoteView; import org.thoughtcrime.securesms.components.SharedContactView; -import org.thoughtcrime.securesms.components.BorderlessImageView; import org.thoughtcrime.securesms.components.emoji.EmojiTextView; import org.thoughtcrime.securesms.components.mention.MentionAnnotation; import org.thoughtcrime.securesms.contactshare.Contact; @@ -113,6 +114,7 @@ import org.thoughtcrime.securesms.util.LongClickMovementMethod; import org.thoughtcrime.securesms.util.SearchUtil; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.ThemeUtil; +import org.thoughtcrime.securesms.util.VibrateUtil; import org.thoughtcrime.securesms.util.ViewUtil; import org.thoughtcrime.securesms.util.views.Stub; import org.whispersystems.libsignal.util.guava.Optional; @@ -123,6 +125,8 @@ import java.util.List; import java.util.Locale; import java.util.Set; +import static org.thoughtcrime.securesms.util.ThemeUtil.isDarkTheme; + /** * A view that displays an individual conversation item within a conversation * thread. Used by ComposeMessageActivity's ListActivity via a ConversationAdapter. @@ -564,6 +568,12 @@ public class ConversationItem extends LinearLayout implements BindableConversati bodyText.setOverflowText(null); } + if (messageRecord.isOutgoing()) { + bodyText.setMentionBackgroundTint(ContextCompat.getColor(context, isDarkTheme(context) ? R.color.core_grey_60 : R.color.core_grey_20)); + } else { + bodyText.setMentionBackgroundTint(ContextCompat.getColor(context, R.color.transparent_black_40)); + } + bodyText.setText(styledText); bodyText.setVisibility(View.VISIBLE); } @@ -1423,6 +1433,7 @@ public class ConversationItem extends LinearLayout implements BindableConversati @Override public void onClick(@NonNull View widget) { if (eventListener != null && !Recipient.resolved(mentionedRecipientId).isLocalNumber()) { + VibrateUtil.vibrateTick(context); eventListener.onGroupMemberClicked(mentionedRecipientId, conversationRecipient.get().requireGroupId()); } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ui/mentions/MentionViewHolder.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ui/mentions/MentionViewHolder.java index 6f18e6ac1..067aa4cd5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ui/mentions/MentionViewHolder.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ui/mentions/MentionViewHolder.java @@ -46,6 +46,6 @@ public class MentionViewHolder extends MappingViewHolder { } public static MappingAdapter.Factory createFactory(@Nullable MentionEventsListener mentionEventsListener) { - return new MappingAdapter.LayoutFactory<>(view -> new MentionViewHolder(view, mentionEventsListener), R.layout.mentions_recipient_list_item); + return new MappingAdapter.LayoutFactory<>(view -> new MentionViewHolder(view, mentionEventsListener), R.layout.mentions_picker_recipient_list_item); } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ui/mentions/MentionsPickerAdapter.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ui/mentions/MentionsPickerAdapter.java index 37243a0b0..eb4b3be6c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ui/mentions/MentionsPickerAdapter.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ui/mentions/MentionsPickerAdapter.java @@ -1,12 +1,25 @@ package org.thoughtcrime.securesms.conversation.ui.mentions; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import org.thoughtcrime.securesms.conversation.ui.mentions.MentionViewHolder.MentionEventsListener; import org.thoughtcrime.securesms.util.MappingAdapter; +import org.thoughtcrime.securesms.util.MappingModel; + +import java.util.List; public class MentionsPickerAdapter extends MappingAdapter { - public MentionsPickerAdapter(@Nullable MentionEventsListener mentionEventsListener) { + private final Runnable currentListChangedListener; + + public MentionsPickerAdapter(@Nullable MentionEventsListener mentionEventsListener, @NonNull Runnable currentListChangedListener) { + this.currentListChangedListener = currentListChangedListener; registerFactory(MentionViewState.class, MentionViewHolder.createFactory(mentionEventsListener)); } + + @Override + public void onCurrentListChanged(@NonNull List> previousList, @NonNull List> currentList) { + super.onCurrentListChanged(previousList, currentList); + currentListChangedListener.run(); + } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ui/mentions/MentionsPickerFragment.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ui/mentions/MentionsPickerFragment.java index cef3bb84a..2d55bdbbd 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ui/mentions/MentionsPickerFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ui/mentions/MentionsPickerFragment.java @@ -17,25 +17,30 @@ import org.thoughtcrime.securesms.LoggingFragment; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.util.MappingModel; -import org.thoughtcrime.securesms.util.ViewUtil; +import org.thoughtcrime.securesms.util.VibrateUtil; +import java.util.Collections; import java.util.List; public class MentionsPickerFragment extends LoggingFragment { private MentionsPickerAdapter adapter; private RecyclerView list; + private View topDivider; + private View bottomDivider; private BottomSheetBehavior behavior; private MentionsPickerViewModel viewModel; - private int defaultPeekHeight; @Override public @Nullable View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.mentions_picker_fragment, container, false); - list = view.findViewById(R.id.mentions_picker_list); - behavior = BottomSheetBehavior.from(view.findViewById(R.id.mentions_picker_bottom_sheet)); - defaultPeekHeight = view.getContext().getResources().getDimensionPixelSize(R.dimen.mentions_picker_peek_height); + list = view.findViewById(R.id.mentions_picker_list); + topDivider = view.findViewById(R.id.mentions_picker_top_divider); + bottomDivider = view.findViewById(R.id.mentions_picker_bottom_divider); + behavior = BottomSheetBehavior.from(view.findViewById(R.id.mentions_picker_bottom_sheet)); + + initializeBehavior(); return view; } @@ -43,24 +48,43 @@ public class MentionsPickerFragment extends LoggingFragment { @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); + viewModel = ViewModelProviders.of(requireActivity()).get(MentionsPickerViewModel.class); + initializeList(); - viewModel = ViewModelProviders.of(requireActivity()).get(MentionsPickerViewModel.class); viewModel.getMentionList().observe(getViewLifecycleOwner(), this::updateList); + + viewModel.isShowing().observe(getViewLifecycleOwner(), isShowing -> { + if (isShowing) { + VibrateUtil.vibrateTick(requireContext()); + } + }); + } + + private void initializeBehavior() { + behavior.setState(BottomSheetBehavior.STATE_HIDDEN); + + behavior.addBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() { + @Override + public void onStateChanged(@NonNull View bottomSheet, int newState) { + if (newState == BottomSheetBehavior.STATE_HIDDEN) { + adapter.submitList(Collections.emptyList()); + } else { + showDividers(true); + } + } + + @Override + public void onSlide(@NonNull View bottomSheet, float slideOffset) { + showDividers(Float.isNaN(slideOffset) || slideOffset > -0.8f); + } + }); } private void initializeList() { - adapter = new MentionsPickerAdapter(this::handleMentionClicked); + adapter = new MentionsPickerAdapter(this::handleMentionClicked, () -> updateBottomSheetBehavior(adapter.getItemCount())); - RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(requireContext()) { - @Override - public void onLayoutCompleted(RecyclerView.State state) { - super.onLayoutCompleted(state); - updateBottomSheetBehavior(adapter.getItemCount()); - } - }; - - list.setLayoutManager(layoutManager); + list.setLayoutManager(new LinearLayoutManager(requireContext())); list.setAdapter(adapter); list.setItemAnimator(null); } @@ -70,24 +94,31 @@ public class MentionsPickerFragment extends LoggingFragment { } private void updateList(@NonNull List> mappingModels) { - adapter.submitList(mappingModels); - if (mappingModels.isEmpty()) { + if (adapter.getItemCount() > 0 && mappingModels.isEmpty()) { updateBottomSheetBehavior(0); + } else { + adapter.submitList(mappingModels); } - list.scrollToPosition(0); } private void updateBottomSheetBehavior(int count) { - if (count > 0) { - if (behavior.getPeekHeight() == 0) { - behavior.setPeekHeight(defaultPeekHeight, true); - behavior.setState(BottomSheetBehavior.STATE_COLLAPSED); - } else { - list.scrollToPosition(0); - } - } else { + boolean isShowing = count > 0; + + viewModel.setIsShowing(isShowing); + + if (isShowing) { + list.scrollToPosition(0); behavior.setState(BottomSheetBehavior.STATE_COLLAPSED); - behavior.setPeekHeight(0); + list.post(() -> behavior.setHideable(false)); + showDividers(true); + } else { + behavior.setHideable(true); + behavior.setState(BottomSheetBehavior.STATE_HIDDEN); } } + + private void showDividers(boolean showDividers) { + topDivider.setVisibility(showDividers ? View.VISIBLE : View.GONE); + bottomDivider.setVisibility(showDividers ? View.VISIBLE : View.GONE); + } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ui/mentions/MentionsPickerViewModel.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ui/mentions/MentionsPickerViewModel.java index cc6627067..d212bb47d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ui/mentions/MentionsPickerViewModel.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ui/mentions/MentionsPickerViewModel.java @@ -29,11 +29,13 @@ public class MentionsPickerViewModel extends ViewModel { private final LiveData>> mentionList; private final MutableLiveData group; private final MutableLiveData liveQuery; + private final MutableLiveData isShowing; MentionsPickerViewModel(@NonNull MentionsPickerRepository mentionsPickerRepository) { group = new MutableLiveData<>(); liveQuery = new MutableLiveData<>(Query.NONE); selectedRecipient = new SingleLiveEvent<>(); + isShowing = new MutableLiveData<>(false); LiveData> fullMembers = Transformations.distinctUntilChanged(Transformations.switchMap(group, LiveGroup::getFullMembers)); LiveData query = Transformations.distinctUntilChanged(liveQuery); @@ -50,10 +52,21 @@ public class MentionsPickerViewModel extends ViewModel { selectedRecipient.setValue(recipient); } + void setIsShowing(boolean isShowing) { + if (Objects.equals(this.isShowing.getValue(), isShowing)) { + return; + } + this.isShowing.setValue(isShowing); + } + public @NonNull LiveData getSelectedRecipient() { return selectedRecipient; } + public @NonNull LiveData isShowing() { + return isShowing; + } + public void onQueryChange(@Nullable String query) { liveQuery.setValue(query == null ? Query.NONE : new Query(query)); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MentionUtil.java b/app/src/main/java/org/thoughtcrime/securesms/database/MentionUtil.java index 1316c4b43..b3b9a37bc 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MentionUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MentionUtil.java @@ -56,7 +56,7 @@ public final class MentionUtil { @WorkerThread public static @NonNull UpdatedBodyAndMentions updateBodyAndMentionsWithDisplayNames(@NonNull Context context, @NonNull CharSequence body, @NonNull List mentions) { - return update(body, mentions, m -> MENTION_STARTER + Recipient.resolved(m.getRecipientId()).getDisplayName(context)); + return update(body, mentions, m -> MENTION_STARTER + Recipient.resolved(m.getRecipientId()).getMentionDisplayName(context)); } public static @NonNull UpdatedBodyAndMentions updateBodyAndMentionsWithPlaceholders(@Nullable CharSequence body, @NonNull List mentions) { @@ -131,9 +131,6 @@ public final class MentionUtil { public static @NonNull String getMentionSettingDisplayValue(@NonNull Context context, @NonNull MentionSetting mentionSetting) { switch (mentionSetting) { - case GLOBAL: - return context.getString(SignalStore.notificationSettings().isMentionNotifiesMeEnabled() ? R.string.GroupMentionSettingDialog_default_notify_me - : R.string.GroupMentionSettingDialog_default_dont_notify_me); case ALWAYS_NOTIFY: return context.getString(R.string.GroupMentionSettingDialog_always_notify_me); case DO_NOT_NOTIFY: diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/RecipientDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/RecipientDatabase.java index 7bbd58439..8c82df623 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/RecipientDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/RecipientDatabase.java @@ -279,7 +279,7 @@ public class RecipientDatabase extends Database { } public enum MentionSetting { - GLOBAL(0), ALWAYS_NOTIFY(1), DO_NOT_NOTIFY(2); + ALWAYS_NOTIFY(0), DO_NOT_NOTIFY(1); private final int id; @@ -336,7 +336,7 @@ public class RecipientDatabase extends Database { GROUPS_V2_CAPABILITY + " INTEGER DEFAULT " + Recipient.Capability.UNKNOWN.serialize() + ", " + STORAGE_SERVICE_ID + " TEXT UNIQUE DEFAULT NULL, " + DIRTY + " INTEGER DEFAULT " + DirtyState.CLEAN.getId() + ", " + - MENTION_SETTING + " INTEGER DEFAULT " + MentionSetting.GLOBAL.getId() + ");"; + MENTION_SETTING + " INTEGER DEFAULT " + MentionSetting.ALWAYS_NOTIFY.getId() + ");"; private static final String INSIGHTS_INVITEE_LIST = "SELECT " + TABLE_NAME + "." + ID + " FROM " + TABLE_NAME + @@ -1160,7 +1160,7 @@ public class RecipientDatabase extends Database { } byte[] storageKey = storageKeyRaw != null ? Base64.decodeOrThrow(storageKeyRaw) : null; - byte[] identityKey = identityKeyRaw.transform(Base64::decodeOrThrow).orNull();; + byte[] identityKey = identityKeyRaw.transform(Base64::decodeOrThrow).orNull(); IdentityDatabase.VerifiedStatus identityStatus = identityStatusRaw.transform(IdentityDatabase.VerifiedStatus::forState).or(IdentityDatabase.VerifiedStatus.DEFAULT); @@ -2288,7 +2288,7 @@ public class RecipientDatabase extends Database { uuidValues.put(SYSTEM_CONTACT_URI, e164Settings.getSystemContactUri()); uuidValues.put(PROFILE_SHARING, uuidSettings.isProfileSharing() || e164Settings.isProfileSharing()); uuidValues.put(GROUPS_V2_CAPABILITY, uuidSettings.getGroupsV2Capability() != Recipient.Capability.UNKNOWN ? uuidSettings.getGroupsV2Capability().serialize() : e164Settings.getGroupsV2Capability().serialize()); - uuidValues.put(MENTION_SETTING, uuidSettings.getMentionSetting() != MentionSetting.GLOBAL ? uuidSettings.getMentionSetting().getId() : e164Settings.getMentionSetting().getId()); + uuidValues.put(MENTION_SETTING, uuidSettings.getMentionSetting() != MentionSetting.ALWAYS_NOTIFY ? uuidSettings.getMentionSetting().getId() : e164Settings.getMentionSetting().getId()); if (uuidSettings.getProfileKey() != null) { updateProfileValuesForMerge(uuidValues, uuidSettings); } else if (e164Settings.getProfileKey() != null) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java index c4d27dbe7..5cd53e894 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java @@ -142,8 +142,9 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper { private static final int REMAPPED_RECORDS = 67; private static final int MENTIONS = 68; private static final int PINNED_CONVERSATIONS = 69; + private static final int MENTION_GLOBAL_SETTING_MIGRATION = 70; - private static final int DATABASE_VERSION = 69; + private static final int DATABASE_VERSION = 70; private static final String DATABASE_NAME = "signal.db"; private final Context context; @@ -997,6 +998,16 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper { db.execSQL("CREATE INDEX IF NOT EXISTS thread_pinned_index ON thread (pinned)"); } + if (oldVersion < MENTION_GLOBAL_SETTING_MIGRATION) { + ContentValues updateAlways = new ContentValues(); + updateAlways.put("mention_setting", 0); + db.update("recipient", updateAlways, "mention_setting = 1", null); + + ContentValues updateNever = new ContentValues(); + updateNever.put("mention_setting", 1); + db.update("recipient", updateNever, "mention_setting = 2", null); + } + db.setTransactionSuccessful(); } finally { db.endTransaction(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/ui/managegroup/ManageGroupViewModel.java b/app/src/main/java/org/thoughtcrime/securesms/groups/ui/managegroup/ManageGroupViewModel.java index da1ce74bc..640559d0f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/ui/managegroup/ManageGroupViewModel.java +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/ui/managegroup/ManageGroupViewModel.java @@ -23,7 +23,6 @@ import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.contacts.ContactsCursorLoader; import org.thoughtcrime.securesms.database.MediaDatabase; import org.thoughtcrime.securesms.database.MentionUtil; -import org.thoughtcrime.securesms.database.RecipientDatabase; import org.thoughtcrime.securesms.database.loaders.MediaLoader; import org.thoughtcrime.securesms.database.loaders.ThreadMediaLoader; import org.thoughtcrime.securesms.groups.GroupAccessControl; @@ -261,7 +260,7 @@ public class ManageGroupViewModel extends ViewModel { } void handleMentionNotificationSelection() { - manageGroupRepository.getRecipient(r -> GroupMentionSettingDialog.show(context, r.getMentionSetting(), mentionSetting -> manageGroupRepository.setMentionSetting(mentionSetting))); + manageGroupRepository.getRecipient(r -> GroupMentionSettingDialog.show(context, r.getMentionSetting(), manageGroupRepository::setMentionSetting)); } private void onBlockAndLeaveConfirmed() { diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/ui/managegroup/dialogs/GroupMentionSettingDialog.java b/app/src/main/java/org/thoughtcrime/securesms/groups/ui/managegroup/dialogs/GroupMentionSettingDialog.java index dae3c0fb9..fd22004b9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/ui/managegroup/dialogs/GroupMentionSettingDialog.java +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/ui/managegroup/dialogs/GroupMentionSettingDialog.java @@ -14,7 +14,6 @@ import androidx.core.util.Consumer; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.database.RecipientDatabase.MentionSetting; -import org.thoughtcrime.securesms.keyvalue.SignalStore; public final class GroupMentionSettingDialog { @@ -32,31 +31,24 @@ public final class GroupMentionSettingDialog { @SuppressLint("InflateParams") private static View getView(@NonNull Context context, @NonNull MentionSetting mentionSetting, @NonNull SelectionCallback selectionCallback) { View root = LayoutInflater.from(context).inflate(R.layout.group_mention_setting_dialog, null, false); - CheckedTextView defaultOption = root.findViewById(R.id.group_mention_setting_default); CheckedTextView alwaysNotify = root.findViewById(R.id.group_mention_setting_always_notify); CheckedTextView dontNotify = root.findViewById(R.id.group_mention_setting_dont_notify); - defaultOption.setText(SignalStore.notificationSettings().isMentionNotifiesMeEnabled() ? R.string.GroupMentionSettingDialog_default_notify_me - : R.string.GroupMentionSettingDialog_default_dont_notify_me); - View.OnClickListener listener = (v) -> { - defaultOption.setChecked(defaultOption == v); alwaysNotify.setChecked(alwaysNotify == v); dontNotify.setChecked(dontNotify == v); - if (defaultOption.isChecked()) selectionCallback.selection = MentionSetting.GLOBAL; - else if (alwaysNotify.isChecked()) selectionCallback.selection = MentionSetting.ALWAYS_NOTIFY; - else if (dontNotify.isChecked()) selectionCallback.selection = MentionSetting.DO_NOT_NOTIFY; + if (alwaysNotify.isChecked()) { + selectionCallback.selection = MentionSetting.ALWAYS_NOTIFY; + } else if (dontNotify.isChecked()) { + selectionCallback.selection = MentionSetting.DO_NOT_NOTIFY; + } }; - defaultOption.setOnClickListener(listener); alwaysNotify.setOnClickListener(listener); dontNotify.setOnClickListener(listener); switch (mentionSetting) { - case GLOBAL: - listener.onClick(defaultOption); - break; case ALWAYS_NOTIFY: listener.onClick(alwaysNotify); break; diff --git a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/NotificationSettings.java b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/NotificationSettings.java deleted file mode 100644 index 80590400e..000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/NotificationSettings.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.thoughtcrime.securesms.keyvalue; - -import androidx.annotation.NonNull; - -public class NotificationSettings extends SignalStoreValues { - - public static final String MENTIONS_NOTIFY_ME = "notifications.mentions.notify_me"; - - NotificationSettings(@NonNull KeyValueStore store) { - super(store); - } - - @Override - void onFirstEverAppLaunch() { - } - - public boolean isMentionNotifiesMeEnabled() { - return getBoolean(MENTIONS_NOTIFY_ME, true); - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/SignalStore.java b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/SignalStore.java index 5d45aac67..0d7be52f7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/SignalStore.java +++ b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/SignalStore.java @@ -24,7 +24,6 @@ public final class SignalStore { private final MiscellaneousValues misc; private final InternalValues internalValues; private final EmojiValues emojiValues; - private final NotificationSettings notificationSettings; private SignalStore() { this.store = ApplicationDependencies.getKeyValueStore(); @@ -38,7 +37,6 @@ public final class SignalStore { this.misc = new MiscellaneousValues(store); this.internalValues = new InternalValues(store); this.emojiValues = new EmojiValues(store); - this.notificationSettings = new NotificationSettings(store); } public static void onFirstEverAppLaunch() { @@ -51,7 +49,6 @@ public final class SignalStore { tooltips().onFirstEverAppLaunch(); misc().onFirstEverAppLaunch(); internalValues().onFirstEverAppLaunch(); - notificationSettings().onFirstEverAppLaunch(); } public static @NonNull KbsValues kbsValues() { @@ -94,10 +91,6 @@ public final class SignalStore { return INSTANCE.emojiValues; } - public static @NonNull NotificationSettings notificationSettings() { - return INSTANCE.notificationSettings; - } - public static @NonNull GroupsV2AuthorizationSignalStoreCache groupsV2AuthorizationCache() { return new GroupsV2AuthorizationSignalStoreCache(getStore()); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/longmessage/LongMessageActivity.java b/app/src/main/java/org/thoughtcrime/securesms/longmessage/LongMessageActivity.java index 2653e2e1c..c5ca3500d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/longmessage/LongMessageActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/longmessage/LongMessageActivity.java @@ -1,13 +1,11 @@ package org.thoughtcrime.securesms.longmessage; -import androidx.lifecycle.ViewModelProviders; import android.content.Context; import android.content.Intent; import android.graphics.PorterDuff; import android.graphics.drawable.ColorDrawable; import android.os.Build; import android.os.Bundle; -import androidx.annotation.NonNull; import android.text.SpannableString; import android.text.method.LinkMovementMethod; import android.text.style.URLSpan; @@ -16,15 +14,19 @@ import android.util.TypedValue; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; -import android.widget.TextView; import android.widget.Toast; +import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; +import androidx.lifecycle.ViewModelProviders; + import com.annimon.stream.Stream; import org.thoughtcrime.securesms.PassphraseRequiredActivity; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.color.MaterialColor; import org.thoughtcrime.securesms.components.ConversationItemFooter; +import org.thoughtcrime.securesms.components.emoji.EmojiTextView; import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil; import org.thoughtcrime.securesms.recipients.LiveRecipient; import org.thoughtcrime.securesms.recipients.Recipient; @@ -36,6 +38,8 @@ import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.ThemeUtil; import org.thoughtcrime.securesms.util.views.Stub; +import static org.thoughtcrime.securesms.util.ThemeUtil.isDarkTheme; + public class LongMessageActivity extends PassphraseRequiredActivity { private static final String KEY_CONVERSATION_RECIPIENT = "recipient_id"; @@ -144,7 +148,7 @@ public class LongMessageActivity extends PassphraseRequiredActivity { bubble.getBackground().setColorFilter(message.get().getMessageRecord().getRecipient().getColor().toConversationColor(this), PorterDuff.Mode.MULTIPLY); } - TextView text = bubble.findViewById(R.id.longmessage_text); + EmojiTextView text = bubble.findViewById(R.id.longmessage_text); ConversationItemFooter footer = bubble.findViewById(R.id.longmessage_footer); CharSequence trimmedBody = getTrimmedBody(message.get().getFullBody(this)); @@ -154,6 +158,11 @@ public class LongMessageActivity extends PassphraseRequiredActivity { text.setText(styledBody); text.setMovementMethod(LinkMovementMethod.getInstance()); text.setTextSize(TypedValue.COMPLEX_UNIT_SP, TextSecurePreferences.getMessageBodyTextSize(this)); + if (message.get().getMessageRecord().isOutgoing()) { + text.setMentionBackgroundTint(ContextCompat.getColor(this, isDarkTheme(this) ? R.color.core_grey_60 : R.color.core_grey_20)); + } else { + text.setMentionBackgroundTint(ContextCompat.getColor(this, R.color.transparent_black_40)); + } footer.setMessageRecord(message.get().getMessageRecord(), dynamicLanguage.getCurrentLocale()); }); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/MediaSendActivity.java b/app/src/main/java/org/thoughtcrime/securesms/mediasend/MediaSendActivity.java index 1dc78d7a3..fced32eff 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/MediaSendActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/MediaSendActivity.java @@ -23,9 +23,12 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.view.ContextThemeWrapper; +import androidx.core.util.Pair; import androidx.core.util.Supplier; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.ViewModelProviders; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -51,6 +54,7 @@ import org.thoughtcrime.securesms.conversation.ui.mentions.MentionsPickerViewMod import org.thoughtcrime.securesms.imageeditor.model.EditorModel; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.mediapreview.MediaRailAdapter; +import org.thoughtcrime.securesms.mediasend.MediaSendViewModel.HudState; import org.thoughtcrime.securesms.mediasend.MediaSendViewModel.ViewOnceState; import org.thoughtcrime.securesms.mms.GlideApp; import org.thoughtcrime.securesms.permissions.Permissions; @@ -66,8 +70,11 @@ import org.thoughtcrime.securesms.util.IOFunction; import org.thoughtcrime.securesms.util.MediaUtil; import org.thoughtcrime.securesms.util.ServiceUtil; import org.thoughtcrime.securesms.util.TextSecurePreferences; +import org.thoughtcrime.securesms.util.ThemeUtil; import org.thoughtcrime.securesms.util.Util; +import org.thoughtcrime.securesms.util.ViewUtil; import org.thoughtcrime.securesms.util.concurrent.SimpleTask; +import org.thoughtcrime.securesms.util.livedata.LiveDataUtil; import org.thoughtcrime.securesms.util.views.SimpleProgressDialog; import org.thoughtcrime.securesms.util.views.Stub; import org.thoughtcrime.securesms.video.VideoUtil; @@ -82,6 +89,7 @@ import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Objects; import java.util.Set; /** @@ -120,8 +128,9 @@ public class MediaSendActivity extends PassphraseRequiredActivity implements Med private @Nullable LiveRecipient recipient; - private TransportOption transport; - private MediaSendViewModel viewModel; + private TransportOption transport; + private MediaSendViewModel viewModel; + private MentionsPickerViewModel mentionsViewModel; private InputAwareLayout hud; private View captionAndRail; @@ -317,8 +326,8 @@ public class MediaSendActivity extends PassphraseRequiredActivity implements Med emojiToggle.setOnClickListener(this::onEmojiToggleClicked); } - initViewModel(); if (FeatureFlags.mentions()) initializeMentionsViewModel(); + initViewModel(); revealButton.setOnClickListener(v -> viewModel.onRevealButtonToggled()); continueButton.setOnClickListener(v -> navigateToContactSelect()); @@ -610,6 +619,27 @@ public class MediaSendActivity extends PassphraseRequiredActivity implements Med } private void initViewModel() { + LiveData> hudStateAndMentionShowing = LiveDataUtil.combineLatest(viewModel.getHudState(), + mentionsViewModel != null ? mentionsViewModel.isShowing() + : new MutableLiveData<>(false), + Pair::new); + + hudStateAndMentionShowing.observe(this, p -> { + HudState state = Objects.requireNonNull(p.first); + boolean isMentionPickerShowing = Objects.requireNonNull(p.second); + int captionBackground = R.color.transparent_black_40; + + if (state.getRailState() == MediaSendViewModel.RailState.VIEWABLE) { + captionBackground = R.color.core_grey_90; + } else if (state.getViewOnceState() == ViewOnceState.ENABLED) { + captionBackground = 0; + } else if (isMentionPickerShowing){ + captionBackground = ThemeUtil.getThemedResourceId(this, R.attr.mention_picker_background_color); + } + + captionAndRail.setBackgroundResource(captionBackground); + }); + viewModel.getHudState().observe(this, state -> { if (state == null) return; @@ -617,18 +647,6 @@ public class MediaSendActivity extends PassphraseRequiredActivity implements Med composeContainer.setVisibility(state.isComposeVisible() ? View.VISIBLE : (state.getViewOnceState() == ViewOnceState.GONE ? View.GONE : View.INVISIBLE)); captionText.setVisibility(state.isCaptionVisible() ? View.VISIBLE : View.GONE); - int captionBackground; - - if (state.getRailState() == MediaSendViewModel.RailState.VIEWABLE) { - captionBackground = R.color.core_grey_90; - } else if (state.getViewOnceState() == ViewOnceState.ENABLED) { - captionBackground = 0; - } else { - captionBackground = R.color.transparent_black_40; - } - - captionAndRail.setBackgroundResource(captionBackground); - switch (state.getButtonState()) { case SEND: sendButtonContainer.setVisibility(View.VISIBLE); @@ -766,7 +784,7 @@ public class MediaSendActivity extends PassphraseRequiredActivity implements Med return; } - MentionsPickerViewModel mentionsViewModel = ViewModelProviders.of(this, new MentionsPickerViewModel.Factory()).get(MentionsPickerViewModel.class); + mentionsViewModel = ViewModelProviders.of(this, new MentionsPickerViewModel.Factory()).get(MentionsPickerViewModel.class); recipient.observe(this, mentionsViewModel::onRecipientChange); composeText.setMentionQueryChangedListener(query -> { @@ -799,6 +817,17 @@ public class MediaSendActivity extends PassphraseRequiredActivity implements Med } composeText.replaceTextWithMention(replacementDisplayName, recipient.getId()); }); + + MentionPickerPlacer mentionPickerPlacer = new MentionPickerPlacer(); + + mentionsViewModel.isShowing().observe(this, isShowing -> { + if (isShowing) { + composeRow.getViewTreeObserver().addOnGlobalLayoutListener(mentionPickerPlacer); + } else { + composeRow.getViewTreeObserver().removeOnGlobalLayoutListener(mentionPickerPlacer); + } + mentionPickerPlacer.onGlobalLayout(); + }); } private void presentRecipient(@Nullable Recipient recipient) { @@ -979,4 +1008,34 @@ public class MediaSendActivity extends PassphraseRequiredActivity implements Med @Override public void onFocusChange(View v, boolean hasFocus) {} } + + private class MentionPickerPlacer implements ViewTreeObserver.OnGlobalLayoutListener { + + private final int composeMargin; + private final ViewGroup parent; + private final Rect composeCoordinates; + private int previousBottomMargin; + + public MentionPickerPlacer() { + parent = findViewById(android.R.id.content); + composeMargin = ViewUtil.dpToPx(12); + composeCoordinates = new Rect(); + } + + @Override + public void onGlobalLayout() { + composeRow.getDrawingRect(composeCoordinates); + parent.offsetDescendantRectToMyCoords(composeRow, composeCoordinates); + + int marginBottom = parent.getHeight() - composeCoordinates.top + composeMargin; + + if (marginBottom != previousBottomMargin) { + ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) mentionSuggestions.get().getLayoutParams(); + params.setMargins(0, 0, 0, marginBottom); + mentionSuggestions.get().setLayoutParams(params); + + previousBottomMargin = marginBottom; + } + } + } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/notifications/DefaultMessageNotifier.java b/app/src/main/java/org/thoughtcrime/securesms/notifications/DefaultMessageNotifier.java index 7b06e1442..e2bd4f996 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/notifications/DefaultMessageNotifier.java +++ b/app/src/main/java/org/thoughtcrime/securesms/notifications/DefaultMessageNotifier.java @@ -536,12 +536,9 @@ public class DefaultMessageNotifier implements MessageNotifier { boolean includeMessage = true; if (threadRecipients != null && threadRecipients.isMuted()) { - RecipientDatabase.MentionSetting mentionSetting = threadRecipients.getMentionSetting(); + boolean mentionsOverrideMute = threadRecipients.getMentionSetting() == RecipientDatabase.MentionSetting.ALWAYS_NOTIFY; - boolean overrideMuted = (mentionSetting == RecipientDatabase.MentionSetting.GLOBAL && SignalStore.notificationSettings().isMentionNotifiesMeEnabled()) || - mentionSetting == RecipientDatabase.MentionSetting.ALWAYS_NOTIFY; - - includeMessage = FeatureFlags.mentions() && overrideMuted && record.hasSelfMention(); + includeMessage = FeatureFlags.mentions() && mentionsOverrideMute && record.hasSelfMention(); } if (threadRecipients == null || includeMessage) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/preferences/NotificationsPreferenceFragment.java b/app/src/main/java/org/thoughtcrime/securesms/preferences/NotificationsPreferenceFragment.java index 3c5005c69..23709a566 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/preferences/NotificationsPreferenceFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/preferences/NotificationsPreferenceFragment.java @@ -9,21 +9,17 @@ import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.provider.Settings; +import android.text.TextUtils; + import androidx.annotation.Nullable; import androidx.preference.ListPreference; import androidx.preference.Preference; -import androidx.preference.PreferenceDataStore; - -import android.text.TextUtils; import org.thoughtcrime.securesms.ApplicationPreferencesActivity; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.components.SwitchPreferenceCompat; import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; -import org.thoughtcrime.securesms.keyvalue.NotificationSettings; -import org.thoughtcrime.securesms.keyvalue.SignalStore; import org.thoughtcrime.securesms.notifications.NotificationChannels; -import org.thoughtcrime.securesms.util.FeatureFlags; import org.thoughtcrime.securesms.util.TextSecurePreferences; import static android.app.Activity.RESULT_OK; @@ -120,18 +116,11 @@ public class NotificationsPreferenceFragment extends ListSummaryPreferenceFragme initializeCallRingtoneSummary(findPreference(TextSecurePreferences.CALL_RINGTONE_PREF)); initializeMessageVibrateSummary((SwitchPreferenceCompat)findPreference(TextSecurePreferences.VIBRATE_PREF)); initializeCallVibrateSummary((SwitchPreferenceCompat)findPreference(TextSecurePreferences.CALL_VIBRATE_PREF)); - - if (FeatureFlags.mentions()) { - initializeMentionsNotifyMeSummary((SwitchPreferenceCompat)findPreference(NotificationSettings.MENTIONS_NOTIFY_ME)); - } } @Override public void onCreatePreferences(@Nullable Bundle savedInstanceState, String rootKey) { addPreferencesFromResource(R.xml.preferences_notifications); - if (FeatureFlags.mentions()) { - addPreferencesFromResource(R.xml.preferences_notifications_mentions); - } } @Override @@ -209,11 +198,6 @@ public class NotificationsPreferenceFragment extends ListSummaryPreferenceFragme pref.setChecked(TextSecurePreferences.isCallNotificationVibrateEnabled(getContext())); } - private void initializeMentionsNotifyMeSummary(SwitchPreferenceCompat pref) { - pref.setPreferenceDataStore(SignalStore.getPreferenceDataStore()); - pref.setChecked(SignalStore.notificationSettings().isMentionNotifiesMeEnabled()); - } - public static CharSequence getSummary(Context context) { final int onCapsResId = R.string.ApplicationPreferencesActivity_On; final int offCapsResId = R.string.ApplicationPreferencesActivity_Off; diff --git a/app/src/main/java/org/thoughtcrime/securesms/recipients/Recipient.java b/app/src/main/java/org/thoughtcrime/securesms/recipients/Recipient.java index a58741f26..330121ca2 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/recipients/Recipient.java +++ b/app/src/main/java/org/thoughtcrime/securesms/recipients/Recipient.java @@ -318,7 +318,7 @@ public class Recipient { this.storageId = null; this.identityKey = null; this.identityStatus = VerifiedStatus.DEFAULT; - this.mentionSetting = MentionSetting.GLOBAL; + this.mentionSetting = MentionSetting.ALWAYS_NOTIFY; } public Recipient(@NonNull RecipientId id, @NonNull RecipientDetails details, boolean resolved) { @@ -413,6 +413,17 @@ public class Recipient { return StringUtil.isolateBidi(name); } + public @NonNull String getMentionDisplayName(@NonNull Context context) { + String name = Util.getFirstNonEmpty(localNumber ? getProfileName().toString() : getName(context), + localNumber ? getName(context) : getProfileName().toString(), + getDisplayUsername(), + e164, + email, + context.getString(R.string.Recipient_unknown)); + + return StringUtil.isolateBidi(name); + } + public @NonNull String getShortDisplayName(@NonNull Context context) { String name = Util.getFirstNonEmpty(getName(context), getProfileName().getGivenName(), diff --git a/app/src/main/java/org/thoughtcrime/securesms/recipients/RecipientDetails.java b/app/src/main/java/org/thoughtcrime/securesms/recipients/RecipientDetails.java index df30570e1..010f12ce2 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/recipients/RecipientDetails.java +++ b/app/src/main/java/org/thoughtcrime/securesms/recipients/RecipientDetails.java @@ -164,7 +164,7 @@ public class RecipientDetails { this.storageId = null; this.identityKey = null; this.identityStatus = VerifiedStatus.DEFAULT; - this.mentionSetting = MentionSetting.GLOBAL; + this.mentionSetting = MentionSetting.ALWAYS_NOTIFY; } public static @NonNull RecipientDetails forIndividual(@NonNull Context context, @NonNull RecipientSettings settings) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/ContextUtil.java b/app/src/main/java/org/thoughtcrime/securesms/util/ContextUtil.java new file mode 100644 index 000000000..3d7ce0e4e --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/util/ContextUtil.java @@ -0,0 +1,18 @@ +package org.thoughtcrime.securesms.util; + +import android.content.Context; +import android.graphics.drawable.Drawable; + +import androidx.annotation.DrawableRes; +import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; + +import java.util.Objects; + +public final class ContextUtil { + private ContextUtil() {} + + public static @NonNull Drawable requireDrawable(@NonNull Context context, @DrawableRes int drawable) { + return Objects.requireNonNull(ContextCompat.getDrawable(context, drawable)); + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/VibrateUtil.java b/app/src/main/java/org/thoughtcrime/securesms/util/VibrateUtil.java new file mode 100644 index 000000000..569213de5 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/util/VibrateUtil.java @@ -0,0 +1,26 @@ +package org.thoughtcrime.securesms.util; + +import android.content.Context; +import android.os.Build; +import android.os.VibrationEffect; +import android.os.Vibrator; + +import androidx.annotation.NonNull; + +public final class VibrateUtil { + + private static final int TICK_LENGTH = 30; + + private VibrateUtil() { } + + public static void vibrateTick(@NonNull Context context) { + Vibrator vibrator = ServiceUtil.getVibrator(context); + + if (Build.VERSION.SDK_INT >= 26) { + VibrationEffect effect = VibrationEffect.createOneShot(TICK_LENGTH, 64); + vibrator.vibrate(effect); + } else { + vibrator.vibrate(TICK_LENGTH); + } + } +} diff --git a/app/src/main/res/layout/group_mention_setting_dialog.xml b/app/src/main/res/layout/group_mention_setting_dialog.xml index e10bc5b70..8f00ecf76 100644 --- a/app/src/main/res/layout/group_mention_setting_dialog.xml +++ b/app/src/main/res/layout/group_mention_setting_dialog.xml @@ -15,21 +15,6 @@ android:paddingRight="?attr/dialogPreferredPadding" android:text="@string/GroupMentionSettingDialog_receive_notifications_when_youre_mentioned_in_muted_chats" /> - - - - + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/mentions_picker_fragment.xml b/app/src/main/res/layout/mentions_picker_fragment.xml index 39b86abcd..9b83092a3 100644 --- a/app/src/main/res/layout/mentions_picker_fragment.xml +++ b/app/src/main/res/layout/mentions_picker_fragment.xml @@ -2,28 +2,40 @@ + android:layout_height="match_parent" + android:clipChildren="false"> - - + + android:layout_height="2dp" + android:layout_gravity="top" + android:layout_marginTop="-2dp" + android:background="@drawable/compose_divider_background" + android:visibility="gone" /> + android:background="?mention_picker_background_color" /> - + + + diff --git a/app/src/main/res/layout/mentions_recipient_list_item.xml b/app/src/main/res/layout/mentions_picker_recipient_list_item.xml similarity index 86% rename from app/src/main/res/layout/mentions_recipient_list_item.xml rename to app/src/main/res/layout/mentions_picker_recipient_list_item.xml index 08e532081..81ca1d677 100644 --- a/app/src/main/res/layout/mentions_recipient_list_item.xml +++ b/app/src/main/res/layout/mentions_picker_recipient_list_item.xml @@ -1,19 +1,21 @@ + android:paddingBottom="8dp"> - + + diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index f6c1fd029..6ba6768e3 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -159,6 +159,4 @@ 16dp 2dp - - 216dp diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index f6e152672..b762d8198 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -263,7 +263,8 @@ @color/white @color/transparent_white_90 @color/core_grey_20 - @color/core_grey_05 + + @color/core_white @color/core_grey_05 @color/core_ultramarine @@ -624,11 +625,12 @@ @style/ThemeOverlay.AppCompat.Dark @color/transparent_white_90 @color/transparent_white_80 - @color/core_grey_75 - @color/core_grey_25 + @color/core_grey_60 @drawable/scroll_to_bottom_background_dark @color/core_white + @color/core_grey_90 + @color/core_white @style/Signal.Toolbar.Overflow @color/action_mode_status_bar diff --git a/app/src/main/res/xml/preferences_notifications_mentions.xml b/app/src/main/res/xml/preferences_notifications_mentions.xml deleted file mode 100644 index 09e27bc1d..000000000 --- a/app/src/main/res/xml/preferences_notifications_mentions.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - -