Update Mention UI/UX to match latest designs.
This commit is contained in:
parent
d63e5165eb
commit
724f3e872b
30 changed files with 353 additions and 201 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,6 +46,6 @@ public class MentionViewHolder extends MappingViewHolder<MentionViewState> {
|
|||
}
|
||||
|
||||
public static MappingAdapter.Factory<MentionViewState> 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<MappingModel<?>> previousList, @NonNull List<MappingModel<?>> currentList) {
|
||||
super.onCurrentListChanged(previousList, currentList);
|
||||
currentListChangedListener.run();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<View> 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<MappingModel<?>> 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,11 +29,13 @@ public class MentionsPickerViewModel extends ViewModel {
|
|||
private final LiveData<List<MappingModel<?>>> mentionList;
|
||||
private final MutableLiveData<LiveGroup> group;
|
||||
private final MutableLiveData<Query> liveQuery;
|
||||
private final MutableLiveData<Boolean> isShowing;
|
||||
|
||||
MentionsPickerViewModel(@NonNull MentionsPickerRepository mentionsPickerRepository) {
|
||||
group = new MutableLiveData<>();
|
||||
liveQuery = new MutableLiveData<>(Query.NONE);
|
||||
selectedRecipient = new SingleLiveEvent<>();
|
||||
isShowing = new MutableLiveData<>(false);
|
||||
|
||||
LiveData<List<FullMember>> fullMembers = Transformations.distinctUntilChanged(Transformations.switchMap(group, LiveGroup::getFullMembers));
|
||||
LiveData<Query> 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<Recipient> getSelectedRecipient() {
|
||||
return selectedRecipient;
|
||||
}
|
||||
|
||||
public @NonNull LiveData<Boolean> isShowing() {
|
||||
return isShowing;
|
||||
}
|
||||
|
||||
public void onQueryChange(@Nullable String query) {
|
||||
liveQuery.setValue(query == null ? Query.NONE : new Query(query));
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ public final class MentionUtil {
|
|||
|
||||
@WorkerThread
|
||||
public static @NonNull UpdatedBodyAndMentions updateBodyAndMentionsWithDisplayNames(@NonNull Context context, @NonNull CharSequence body, @NonNull List<Mention> 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<Mention> 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:
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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<Pair<HudState, Boolean>> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,21 +15,6 @@
|
|||
android:paddingRight="?attr/dialogPreferredPadding"
|
||||
android:text="@string/GroupMentionSettingDialog_receive_notifications_when_youre_mentioned_in_muted_chats" />
|
||||
|
||||
<CheckedTextView
|
||||
android:id="@+id/group_mention_setting_default"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?selectableItemBackground"
|
||||
android:drawableStart="?android:attr/listChoiceIndicatorSingle"
|
||||
android:drawablePadding="20dp"
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="?attr/listPreferredItemHeightSmall"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="?attr/dialogPreferredPadding"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textColor="?attr/textColorAlertDialogListItem"
|
||||
tools:text="@string/GroupMentionSettingDialog_default_notify_me" />
|
||||
|
||||
<CheckedTextView
|
||||
android:id="@+id/group_mention_setting_always_notify"
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
@ -27,13 +27,6 @@
|
|||
android:clickable="true"
|
||||
android:background="@color/transparent_black_40">
|
||||
|
||||
<ViewStub
|
||||
android:id="@+id/mediasend_mention_suggestions_stub"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout="@layout/conversation_mention_suggestions_stub"/>
|
||||
|
||||
<org.thoughtcrime.securesms.components.emoji.EmojiEditText
|
||||
android:id="@+id/mediasend_caption"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -192,4 +185,17 @@
|
|||
|
||||
</org.thoughtcrime.securesms.components.InputAwareLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ViewStub
|
||||
android:id="@+id/mediasend_mention_suggestions_stub"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="bottom"
|
||||
android:layout="@layout/conversation_mention_suggestions_stub"/>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</FrameLayout>
|
|
@ -2,28 +2,40 @@
|
|||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="match_parent"
|
||||
android:clipChildren="false">
|
||||
|
||||
<LinearLayout
|
||||
<FrameLayout
|
||||
android:id="@+id/mentions_picker_bottom_sheet"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
app:behavior_hideable="false"
|
||||
app:behavior_peekHeight="0dp"
|
||||
app:behavior_peekHeight="236dp"
|
||||
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
|
||||
|
||||
<View
|
||||
android:id="@+id/mentions_picker_top_divider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="?conversation_mention_divider_color"/>
|
||||
android:layout_height="2dp"
|
||||
android:layout_gravity="top"
|
||||
android:layout_marginTop="-2dp"
|
||||
android:background="@drawable/compose_divider_background"
|
||||
android:visibility="gone" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/mentions_picker_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?android:attr/windowBackground" />
|
||||
android:background="?mention_picker_background_color" />
|
||||
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
|
||||
<View
|
||||
android:id="@+id/mentions_picker_bottom_divider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="2dp"
|
||||
android:layout_gravity="bottom"
|
||||
android:background="@drawable/compose_divider_background"
|
||||
android:visibility="gone" />
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
|
|
@ -1,19 +1,21 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?selectableItemBackground"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="12dp"
|
||||
android:paddingTop="10dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingBottom="10dp">
|
||||
android:paddingBottom="8dp">
|
||||
|
||||
<org.thoughtcrime.securesms.components.AvatarImageView
|
||||
android:id="@+id/mention_recipient_avatar"
|
||||
android:layout_width="28dp"
|
||||
android:layout_height="28dp"
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="36dp"
|
||||
app:fallbackImageSize="small"
|
||||
tools:src="@tools:sample/avatars" />
|
||||
|
||||
<TextView
|
|
@ -90,7 +90,8 @@
|
|||
<attr name="conversation_title_color" format="reference" />
|
||||
<attr name="conversation_subtitle_color" format="reference" />
|
||||
<attr name="conversation_mention_background_color" format="reference" />
|
||||
<attr name="conversation_mention_divider_color" format="reference" />
|
||||
|
||||
<attr name="mention_picker_background_color" format="reference" />
|
||||
|
||||
<attr name="emoji_tab_strip_background" format="color" />
|
||||
<attr name="emoji_tab_indicator" format="color" />
|
||||
|
|
|
@ -159,6 +159,4 @@
|
|||
<dimen name="group_manage_fragment_row_horizontal_padding">16dp</dimen>
|
||||
|
||||
<dimen name="wave_form_bar_width">2dp</dimen>
|
||||
|
||||
<dimen name="mentions_picker_peek_height">216dp</dimen>
|
||||
</resources>
|
||||
|
|
|
@ -263,7 +263,8 @@
|
|||
<item name="conversation_title_color">@color/white</item>
|
||||
<item name="conversation_subtitle_color">@color/transparent_white_90</item>
|
||||
<item name="conversation_mention_background_color">@color/core_grey_20</item>
|
||||
<item name="conversation_mention_divider_color">@color/core_grey_05</item>
|
||||
|
||||
<item name="mention_picker_background_color">@color/core_white</item>
|
||||
|
||||
<item name="safety_number_change_dialog_button_background">@color/core_grey_05</item>
|
||||
<item name="safety_number_change_dialog_button_text_color">@color/core_ultramarine</item>
|
||||
|
@ -624,11 +625,12 @@
|
|||
<item name="conversation_popup_theme">@style/ThemeOverlay.AppCompat.Dark</item>
|
||||
<item name="conversation_title_color">@color/transparent_white_90</item>
|
||||
<item name="conversation_subtitle_color">@color/transparent_white_80</item>
|
||||
<item name="conversation_mention_background_color">@color/core_grey_75</item>
|
||||
<item name="conversation_mention_divider_color">@color/core_grey_25</item>
|
||||
<item name="conversation_mention_background_color">@color/core_grey_60</item>
|
||||
<item name="conversation_scroll_to_bottom_background">@drawable/scroll_to_bottom_background_dark</item>
|
||||
<item name="conversation_scroll_to_bottom_foreground_color">@color/core_white</item>
|
||||
|
||||
<item name="mention_picker_background_color">@color/core_grey_90</item>
|
||||
|
||||
<item name="reactions_overlay_toolbar_icon_tint">@color/core_white</item>
|
||||
<item name="reactions_overlay_toolbar_overflow_style">@style/Signal.Toolbar.Overflow</item>
|
||||
<item name="reactions_overlay_toolbar_background_color">@color/action_mode_status_bar</item>
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<PreferenceCategory android:layout="@layout/preference_divider"/>
|
||||
|
||||
<PreferenceCategory android:title="@string/preferences_notifications__mentions">
|
||||
<org.thoughtcrime.securesms.components.SwitchPreferenceCompat
|
||||
android:key="notifications.mentions.notify_me"
|
||||
android:title="@string/preferences_notifications__notify_me"
|
||||
android:summary="@string/preferences_notifications__receive_notifications_when_youre_mentioned_in_muted_chats"
|
||||
android:defaultValue="true" />
|
||||
</PreferenceCategory>
|
||||
|
||||
</PreferenceScreen>
|
Loading…
Add table
Reference in a new issue