From 1425b651d4d046ed68da547a5ae133a7b6bd8f71 Mon Sep 17 00:00:00 2001 From: Alex Hart Date: Thu, 27 Aug 2020 10:49:45 -0300 Subject: [PATCH] Update username UX and UI. --- .../ApplicationPreferencesActivity.java | 45 +++++ .../conversation/ConversationActivity.java | 6 +- .../conversation/ConversationFragment.java | 4 +- .../conversation/ConversationTitleView.java | 2 +- .../ui/mentions/MentionViewHolder.java | 3 - .../ui/mentions/MentionViewState.java | 4 - .../groups/ui/GroupMemberListAdapter.java | 3 +- .../securesms/jobs/RetrieveProfileJob.java | 8 +- .../keyvalue/MiscellaneousValues.java | 9 + .../mediasend/MediaSendActivity.java | 6 +- .../widgets/UsernamePreference.java | 49 +++++ .../profiles/edit/EditProfileActivity.java | 29 ++- .../edit/EditSelfProfileRepository.java | 15 +- .../securesms/recipients/Recipient.java | 26 +-- .../RecipientBottomSheetDialogFragment.java | 2 +- .../ManageRecipientViewModel.java | 3 +- .../username/UsernameEditFragment.java | 9 +- .../username/UsernameEditRepository.java | 7 - .../username/UsernameEditViewModel.java | 7 +- .../securesms/util/FeatureFlags.java | 1 + .../securesms/util/TextSecurePreferences.java | 8 - .../preference_username_background_dark.xml | 5 + .../preference_username_background_light.xml | 5 + .../mentions_picker_recipient_list_item.xml | 11 -- .../main/res/layout/preference_username.xml | 24 +++ .../res/layout/username_edit_fragment.xml | 173 ++++++++++-------- app/src/main/res/values/attrs.xml | 2 + app/src/main/res/values/strings.xml | 7 +- app/src/main/res/values/themes.xml | 4 + app/src/main/res/xml/preferences.xml | 7 +- .../api/profiles/SignalServiceProfile.java | 7 - 31 files changed, 311 insertions(+), 180 deletions(-) create mode 100644 app/src/main/java/org/thoughtcrime/securesms/preferences/widgets/UsernamePreference.java create mode 100644 app/src/main/res/drawable/preference_username_background_dark.xml create mode 100644 app/src/main/res/drawable/preference_username_background_light.xml create mode 100644 app/src/main/res/layout/preference_username.xml diff --git a/app/src/main/java/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java b/app/src/main/java/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java index 951d404bad..e5c5297d60 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java @@ -17,12 +17,15 @@ */ package org.thoughtcrime.securesms; +import android.app.AlertDialog; +import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.graphics.PorterDuff; import android.os.Build; import android.os.Bundle; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; @@ -30,6 +33,7 @@ import androidx.fragment.app.FragmentTransaction; import androidx.preference.Preference; import org.thoughtcrime.securesms.help.HelpFragment; +import org.thoughtcrime.securesms.keyvalue.SignalStore; import org.thoughtcrime.securesms.preferences.AdvancedPreferenceFragment; import org.thoughtcrime.securesms.preferences.AppProtectionPreferenceFragment; import org.thoughtcrime.securesms.preferences.AppearancePreferenceFragment; @@ -39,10 +43,13 @@ import org.thoughtcrime.securesms.preferences.NotificationsPreferenceFragment; import org.thoughtcrime.securesms.preferences.SmsMmsPreferenceFragment; import org.thoughtcrime.securesms.preferences.StoragePreferenceFragment; import org.thoughtcrime.securesms.preferences.widgets.ProfilePreference; +import org.thoughtcrime.securesms.preferences.widgets.UsernamePreference; import org.thoughtcrime.securesms.profiles.edit.EditProfileActivity; +import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.service.KeyCachingService; import org.thoughtcrime.securesms.util.DynamicLanguage; import org.thoughtcrime.securesms.util.DynamicTheme; +import org.thoughtcrime.securesms.util.FeatureFlags; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.ThemeUtil; @@ -60,6 +67,7 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActivity private static final String TAG = ApplicationPreferencesActivity.class.getSimpleName(); private static final String PREFERENCE_CATEGORY_PROFILE = "preference_category_profile"; + private static final String PREFERENCE_CATEGORY_USERNAME = "preference_category_username"; private static final String PREFERENCE_CATEGORY_SMS_MMS = "preference_category_sms_mms"; private static final String PREFERENCE_CATEGORY_NOTIFICATIONS = "preference_category_notifications"; private static final String PREFERENCE_CATEGORY_APP_PROTECTION = "preference_category_app_protection"; @@ -142,6 +150,8 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActivity this.findPreference(PREFERENCE_CATEGORY_PROFILE) .setOnPreferenceClickListener(new ProfileClickListener()); + this.findPreference(PREFERENCE_CATEGORY_USERNAME) + .setOnPreferenceClickListener(new UsernameClickListener()); this.findPreference(PREFERENCE_CATEGORY_SMS_MMS) .setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_SMS_MMS)); this.findPreference(PREFERENCE_CATEGORY_NOTIFICATIONS) @@ -174,6 +184,24 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActivity @Override public void onCreatePreferences(@Nullable Bundle savedInstanceState, String rootKey) { addPreferencesFromResource(R.xml.preferences); + + if (FeatureFlags.usernames()) { + UsernamePreference pref = (UsernamePreference) findPreference(PREFERENCE_CATEGORY_USERNAME); + pref.setVisible(shouldDisplayUsernameReminder()); + pref.setOnLongClickListener(v -> { + new AlertDialog.Builder(requireContext()) + .setMessage(R.string.ApplicationPreferencesActivity_hide_reminder) + .setPositiveButton(R.string.ApplicationPreferencesActivity_hide, (dialog, which) -> { + dialog.dismiss(); + SignalStore.misc().hideUsernameReminder(); + findPreference(PREFERENCE_CATEGORY_USERNAME).setVisible(false); + }) + .setNegativeButton(android.R.string.cancel, ((dialog, which) -> dialog.dismiss())) + .setCancelable(true) + .show(); + return true; + }); + } } @Override @@ -188,6 +216,11 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActivity private void setCategorySummaries() { ((ProfilePreference)this.findPreference(PREFERENCE_CATEGORY_PROFILE)).refresh(); + if (FeatureFlags.usernames()) { + this.findPreference(PREFERENCE_CATEGORY_USERNAME) + .setVisible(shouldDisplayUsernameReminder()); + } + this.findPreference(PREFERENCE_CATEGORY_SMS_MMS) .setSummary(SmsMmsPreferenceFragment.getSummary(getActivity())); this.findPreference(PREFERENCE_CATEGORY_NOTIFICATIONS) @@ -207,6 +240,10 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActivity } } + private static boolean shouldDisplayUsernameReminder() { + return FeatureFlags.usernames() && !Recipient.self().getUsername().isPresent() && SignalStore.misc().shouldShowUsernameReminder(); + } + private class CategoryClickListener implements Preference.OnPreferenceClickListener { private String category; @@ -276,6 +313,14 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActivity return true; } } + + private class UsernameClickListener implements Preference.OnPreferenceClickListener { + @Override + public boolean onPreferenceClick(Preference preference) { + requireActivity().startActivity(EditProfileActivity.getIntentForUsernameEdit(preference.getContext())); + return true; + } + } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java index 982dfa79a4..fcedbdba5e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java @@ -2015,11 +2015,7 @@ public class ConversationActivity extends PassphraseRequiredActivity }); mentionsViewModel.getSelectedRecipient().observe(this, recipient -> { - String replacementDisplayName = recipient.getDisplayName(this); - if (replacementDisplayName.equals(recipient.getDisplayUsername())) { - replacementDisplayName = recipient.getUsername().or(replacementDisplayName); - } - composeText.replaceTextWithMention(replacementDisplayName, recipient.getId()); + composeText.replaceTextWithMention(recipient.getDisplayName(this), recipient.getId()); }); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java index 69494e2162..8525f44df3 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java @@ -394,7 +394,7 @@ public class ConversationFragment extends LoggingFragment { if (recipient != null) { conversationBanner.setAvatar(GlideApp.with(context), recipient); - String title = isSelf ? context.getString(R.string.note_to_self) : recipient.getDisplayName(context); + String title = isSelf ? context.getString(R.string.note_to_self) : recipient.getDisplayNameOrUsername(context); conversationBanner.setTitle(title); if (recipient.isGroup()) { @@ -411,7 +411,7 @@ public class ConversationFragment extends LoggingFragment { } else if (isSelf) { conversationBanner.setSubtitle(context.getString(R.string.ConversationFragment__you_can_add_notes_for_yourself_in_this_conversation)); } else { - String subtitle = recipient.getUsername().or(recipient.getE164()).orNull(); + String subtitle = recipient.getE164().orNull(); if (subtitle == null || subtitle.equals(title)) { conversationBanner.hideSubtitle(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationTitleView.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationTitleView.java index a88e1f072e..bb9d4f2c27 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationTitleView.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationTitleView.java @@ -159,7 +159,7 @@ public class ConversationTitleView extends RelativeLayout { } private void setIndividualRecipientTitle(Recipient recipient) { - final String displayName = recipient.getDisplayName(getContext()); + final String displayName = recipient.getDisplayNameOrUsername(getContext()); this.title.setText(displayName); this.subtitle.setText(null); updateVerifiedSubtitleVisibility(); 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 067aa4cd52..b05b899fc0 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 @@ -16,7 +16,6 @@ public class MentionViewHolder extends MappingViewHolder { private final AvatarImageView avatar; private final TextView name; - private final TextView username; @Nullable private final MentionEventsListener mentionEventsListener; @@ -26,14 +25,12 @@ public class MentionViewHolder extends MappingViewHolder { avatar = findViewById(R.id.mention_recipient_avatar); name = findViewById(R.id.mention_recipient_name); - username = findViewById(R.id.mention_recipient_username); } @Override public void bind(@NonNull MentionViewState model) { avatar.setRecipient(model.getRecipient()); name.setText(model.getName(context)); - username.setText(model.getUsername()); itemView.setOnClickListener(v -> { if (mentionEventsListener != null) { mentionEventsListener.onMentionClicked(model.getRecipient()); diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ui/mentions/MentionViewState.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ui/mentions/MentionViewState.java index b7f2033bf8..8a596c5350 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ui/mentions/MentionViewState.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ui/mentions/MentionViewState.java @@ -27,10 +27,6 @@ public final class MentionViewState implements MappingModel { return recipient; } - @NonNull String getUsername() { - return Util.emptyIfNull(recipient.getDisplayUsername()); - } - @Override public boolean areItemsTheSame(@NonNull MentionViewState newItem) { return recipient.getId().equals(newItem.recipient.getId()); diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/ui/GroupMemberListAdapter.java b/app/src/main/java/org/thoughtcrime/securesms/groups/ui/GroupMemberListAdapter.java index 6bdb94e3d0..708e3c3ff1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/ui/GroupMemberListAdapter.java +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/ui/GroupMemberListAdapter.java @@ -18,6 +18,7 @@ import org.thoughtcrime.securesms.components.AvatarImageView; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.util.LifecycleRecyclerAdapter; import org.thoughtcrime.securesms.util.LifecycleViewHolder; +import org.thoughtcrime.securesms.util.Util; import java.util.ArrayList; import java.util.HashSet; @@ -333,7 +334,7 @@ final class GroupMemberListAdapter extends LifecycleRecyclerAdapter { - String replacementDisplayName = recipient.getDisplayName(this); - if (replacementDisplayName.equals(recipient.getDisplayUsername())) { - replacementDisplayName = recipient.getUsername().or(replacementDisplayName); - } - composeText.replaceTextWithMention(replacementDisplayName, recipient.getId()); + composeText.replaceTextWithMention(recipient.getDisplayName(this), recipient.getId()); }); MentionPickerPlacer mentionPickerPlacer = new MentionPickerPlacer(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/preferences/widgets/UsernamePreference.java b/app/src/main/java/org/thoughtcrime/securesms/preferences/widgets/UsernamePreference.java new file mode 100644 index 0000000000..5b70d93c0b --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/preferences/widgets/UsernamePreference.java @@ -0,0 +1,49 @@ +package org.thoughtcrime.securesms.preferences.widgets; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; + +import androidx.preference.Preference; +import androidx.preference.PreferenceViewHolder; + +import org.thoughtcrime.securesms.R; + +public class UsernamePreference extends Preference { + + private View.OnLongClickListener onLongClickListener; + + public UsernamePreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + initialize(); + } + + public UsernamePreference(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initialize(); + } + + public UsernamePreference(Context context, AttributeSet attrs) { + super(context, attrs); + initialize(); + } + + public UsernamePreference(Context context) { + super(context); + initialize(); + } + + private void initialize() { + setLayoutResource(R.layout.preference_username); + } + + public void setOnLongClickListener(View.OnLongClickListener onLongClickListener) { + this.onLongClickListener = onLongClickListener; + } + + @Override + public void onBindViewHolder(PreferenceViewHolder holder) { + super.onBindViewHolder(holder); + holder.itemView.setOnLongClickListener(onLongClickListener); + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/profiles/edit/EditProfileActivity.java b/app/src/main/java/org/thoughtcrime/securesms/profiles/edit/EditProfileActivity.java index afa280e88d..9b263bade6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/profiles/edit/EditProfileActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/profiles/edit/EditProfileActivity.java @@ -7,6 +7,7 @@ import android.content.Intent; import android.os.Bundle; import androidx.annotation.NonNull; +import androidx.navigation.NavDirections; import androidx.navigation.NavGraph; import androidx.navigation.Navigation; @@ -19,12 +20,13 @@ import org.thoughtcrime.securesms.util.DynamicTheme; @SuppressLint("StaticFieldLeak") public class EditProfileActivity extends BaseActivity implements EditProfileFragment.Controller { - public static final String NEXT_INTENT = "next_intent"; - public static final String EXCLUDE_SYSTEM = "exclude_system"; - public static final String DISPLAY_USERNAME = "display_username"; - public static final String NEXT_BUTTON_TEXT = "next_button_text"; - public static final String SHOW_TOOLBAR = "show_back_arrow"; - public static final String GROUP_ID = "group_id"; + public static final String NEXT_INTENT = "next_intent"; + public static final String EXCLUDE_SYSTEM = "exclude_system"; + public static final String DISPLAY_USERNAME = "display_username"; + public static final String NEXT_BUTTON_TEXT = "next_button_text"; + public static final String SHOW_TOOLBAR = "show_back_arrow"; + public static final String GROUP_ID = "group_id"; + public static final String START_AT_USERNAME = "start_at_username"; private final DynamicTheme dynamicTheme = new DynamicRegistrationTheme(); @@ -50,6 +52,14 @@ public class EditProfileActivity extends BaseActivity implements EditProfileFrag return intent; } + public static @NonNull Intent getIntentForUsernameEdit(@NonNull Context context) { + Intent intent = new Intent(context, EditProfileActivity.class); + intent.putExtra(EditProfileActivity.SHOW_TOOLBAR, true); + intent.putExtra(EditProfileActivity.DISPLAY_USERNAME, true); + intent.putExtra(EditProfileActivity.START_AT_USERNAME, true); + return intent; + } + @Override public void onCreate(Bundle bundle) { super.onCreate(bundle); @@ -63,6 +73,13 @@ public class EditProfileActivity extends BaseActivity implements EditProfileFrag NavGraph graph = Navigation.findNavController(this, R.id.nav_host_fragment).getGraph(); Navigation.findNavController(this, R.id.nav_host_fragment).setGraph(graph, extras != null ? extras : new Bundle()); + + if (extras != null && + extras.getBoolean(DISPLAY_USERNAME, false) && + extras.getBoolean(START_AT_USERNAME, false)) { + NavDirections action = EditProfileFragmentDirections.actionEditUsername(); + Navigation.findNavController(this, R.id.nav_host_fragment).navigate(action); + } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/profiles/edit/EditSelfProfileRepository.java b/app/src/main/java/org/thoughtcrime/securesms/profiles/edit/EditSelfProfileRepository.java index 0982365666..a96328ad14 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/profiles/edit/EditSelfProfileRepository.java +++ b/app/src/main/java/org/thoughtcrime/securesms/profiles/edit/EditSelfProfileRepository.java @@ -144,19 +144,6 @@ class EditSelfProfileRepository implements EditProfileRepository { @Override public void getCurrentUsername(@NonNull Consumer> callback) { - callback.accept(Optional.fromNullable(TextSecurePreferences.getLocalUsername(context))); - SignalExecutors.UNBOUNDED.execute(() -> callback.accept(getUsernameInternal())); - } - - @WorkerThread - private @NonNull Optional getUsernameInternal() { - try { - SignalServiceProfile profile = ProfileUtil.retrieveProfile(context, Recipient.self(), SignalServiceProfile.RequestType.PROFILE).get(5, TimeUnit.SECONDS).getProfile(); - TextSecurePreferences.setLocalUsername(context, profile.getUsername()); - DatabaseFactory.getRecipientDatabase(context).setUsername(Recipient.self().getId(), profile.getUsername()); - } catch (TimeoutException | InterruptedException | ExecutionException e) { - Log.w(TAG, "Failed to retrieve username remotely! Using locally-cached version."); - } - return Optional.fromNullable(TextSecurePreferences.getLocalUsername(context)); + callback.accept(Recipient.self().getUsername()); } } 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 779bf045d3..9ee867d496 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/recipients/Recipient.java +++ b/app/src/main/java/org/thoughtcrime/securesms/recipients/Recipient.java @@ -398,15 +398,13 @@ public class Recipient { * False iff it {@link #getDisplayName} would fall back to e164, email or unknown. */ public boolean hasAUserSetDisplayName(@NonNull Context context) { - return !TextUtils.isEmpty(getName(context)) || - !TextUtils.isEmpty(getProfileName().toString()) || - !TextUtils.isEmpty(getDisplayUsername()); + return !TextUtils.isEmpty(getName(context)) || + !TextUtils.isEmpty(getProfileName().toString()); } public @NonNull String getDisplayName(@NonNull Context context) { String name = Util.getFirstNonEmpty(getName(context), getProfileName().toString(), - getDisplayUsername(), e164, email, context.getString(R.string.Recipient_unknown)); @@ -414,10 +412,20 @@ public class Recipient { return StringUtil.isolateBidi(name); } + public @NonNull String getDisplayNameOrUsername(@NonNull Context context) { + String name = Util.getFirstNonEmpty(getName(context), + getProfileName().toString(), + e164, + email, + username, + context.getString(R.string.Recipient_unknown)); + + 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)); @@ -817,14 +825,6 @@ public class Recipient { return ApplicationDependencies.getRecipientCache().getLive(id); } - public @Nullable String getDisplayUsername() { - if (!TextUtils.isEmpty(username)) { - return "@" + username; - } else { - return null; - } - } - public @NonNull MentionSetting getMentionSetting() { return mentionSetting; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/bottomsheet/RecipientBottomSheetDialogFragment.java b/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/bottomsheet/RecipientBottomSheetDialogFragment.java index 8188da50d0..53c289b97a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/bottomsheet/RecipientBottomSheetDialogFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/bottomsheet/RecipientBottomSheetDialogFragment.java @@ -157,7 +157,7 @@ public final class RecipientBottomSheetDialogFragment extends BottomSheetDialogF } String usernameNumberString = recipient.hasAUserSetDisplayName(requireContext()) && !recipient.isLocalNumber() - ? String.format("%s %s", recipient.getUsername().or(""), recipient.getSmsAddress().or("")).trim() + ? recipient.getSmsAddress().or("").trim() : ""; usernameNumber.setText(usernameNumberString); usernameNumber.setVisibility(TextUtils.isEmpty(usernameNumberString) ? View.GONE : View.VISIBLE); diff --git a/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/managerecipient/ManageRecipientViewModel.java b/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/managerecipient/ManageRecipientViewModel.java index 19c9cb2fb3..e8a5945c0f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/managerecipient/ManageRecipientViewModel.java +++ b/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/managerecipient/ManageRecipientViewModel.java @@ -124,8 +124,7 @@ public final class ManageRecipientViewModel extends ViewModel { private static @NonNull String getDisplaySubtitle(@NonNull Recipient recipient, @NonNull Context context) { if (!recipient.isLocalNumber() && recipient.hasAUserSetDisplayName(context)) { - return String.format("%s %s", recipient.getUsername().or(""), recipient.getSmsAddress().or("")) - .trim(); + return recipient.getSmsAddress().or("").trim(); } else { return ""; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/usernames/username/UsernameEditFragment.java b/app/src/main/java/org/thoughtcrime/securesms/usernames/username/UsernameEditFragment.java index 90a359fd50..67dafb388f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/usernames/username/UsernameEditFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/usernames/username/UsernameEditFragment.java @@ -13,8 +13,10 @@ import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.appcompat.widget.Toolbar; import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProviders; +import androidx.navigation.Navigation; import androidx.navigation.fragment.NavHostFragment; import com.dd.CircularProgressButton; @@ -22,6 +24,7 @@ import com.dd.CircularProgressButton; import org.thoughtcrime.securesms.LoggingFragment; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.contactshare.SimpleTextWatcher; +import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.UsernameUtil; @@ -52,6 +55,10 @@ public class UsernameEditFragment extends LoggingFragment { submitButton = view.findViewById(R.id.username_submit_button); deleteButton = view.findViewById(R.id.username_delete_button); + view.findViewById(R.id.toolbar) + .setNavigationOnClickListener(v -> Navigation.findNavController(view) + .popBackStack()); + viewModel = ViewModelProviders.of(this, new UsernameEditViewModel.Factory()).get(UsernameEditViewModel.class); viewModel.getUiState().observe(getViewLifecycleOwner(), this::onUiStateChanged); @@ -60,7 +67,7 @@ public class UsernameEditFragment extends LoggingFragment { submitButton.setOnClickListener(v -> viewModel.onUsernameSubmitted(usernameInput.getText().toString())); deleteButton.setOnClickListener(v -> viewModel.onUsernameDeleted()); - usernameInput.setText(TextSecurePreferences.getLocalUsername(requireContext())); + usernameInput.setText(Recipient.self().getUsername().orNull()); usernameInput.addTextChangedListener(new SimpleTextWatcher() { @Override public void onTextChanged(String text) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/usernames/username/UsernameEditRepository.java b/app/src/main/java/org/thoughtcrime/securesms/usernames/username/UsernameEditRepository.java index 7b257fb546..3f971f015d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/usernames/username/UsernameEditRepository.java +++ b/app/src/main/java/org/thoughtcrime/securesms/usernames/username/UsernameEditRepository.java @@ -12,16 +12,11 @@ import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.util.concurrent.SignalExecutors; -import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.signalservice.api.SignalServiceAccountManager; -import org.whispersystems.signalservice.api.profiles.SignalServiceProfile; -import org.whispersystems.signalservice.api.push.exceptions.NotFoundException; import org.whispersystems.signalservice.api.push.exceptions.UsernameMalformedException; import org.whispersystems.signalservice.api.push.exceptions.UsernameTakenException; -import org.whispersystems.signalservice.api.util.UuidUtil; import java.io.IOException; -import java.util.UUID; import java.util.concurrent.Executor; class UsernameEditRepository { @@ -50,7 +45,6 @@ class UsernameEditRepository { private @NonNull UsernameSetResult setUsernameInternal(@NonNull String username) { try { accountManager.setUsername(username); - TextSecurePreferences.setLocalUsername(application, username); DatabaseFactory.getRecipientDatabase(application).setUsername(Recipient.self().getId(), username); Log.i(TAG, "[setUsername] Successfully set username."); return UsernameSetResult.SUCCESS; @@ -70,7 +64,6 @@ class UsernameEditRepository { private @NonNull UsernameDeleteResult deleteUsernameInternal() { try { accountManager.deleteUsername(); - TextSecurePreferences.setLocalUsername(application, null); DatabaseFactory.getRecipientDatabase(application).setUsername(Recipient.self().getId(), null); Log.i(TAG, "[deleteUsername] Successfully deleted the username."); return UsernameDeleteResult.SUCCESS; diff --git a/app/src/main/java/org/thoughtcrime/securesms/usernames/username/UsernameEditViewModel.java b/app/src/main/java/org/thoughtcrime/securesms/usernames/username/UsernameEditViewModel.java index 15fe83406c..65d6da89c9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/usernames/username/UsernameEditViewModel.java +++ b/app/src/main/java/org/thoughtcrime/securesms/usernames/username/UsernameEditViewModel.java @@ -12,6 +12,7 @@ import androidx.lifecycle.ViewModelProvider; import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; import org.thoughtcrime.securesms.logging.Log; +import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.util.Debouncer; import org.thoughtcrime.securesms.util.SingleLiveEvent; import org.thoughtcrime.securesms.util.TextSecurePreferences; @@ -39,12 +40,12 @@ class UsernameEditViewModel extends ViewModel { } void onUsernameUpdated(@NonNull String username) { - if (TextUtils.isEmpty(username) && TextSecurePreferences.getLocalUsername(application) != null) { + if (TextUtils.isEmpty(username) && Recipient.self().getUsername().isPresent()) { uiState.setValue(new State(ButtonState.DELETE, UsernameStatus.NONE)); return; } - if (username.equals(TextSecurePreferences.getLocalUsername(application))) { + if (username.equals(Recipient.self().getUsername().orNull())) { uiState.setValue(new State(ButtonState.SUBMIT_DISABLED, UsernameStatus.NONE)); return; } @@ -60,7 +61,7 @@ class UsernameEditViewModel extends ViewModel { } void onUsernameSubmitted(@NonNull String username) { - if (username.equals(TextSecurePreferences.getLocalUsername(application))) { + if (username.equals(Recipient.self().getUsername().orNull())) { uiState.setValue(new State(ButtonState.SUBMIT_DISABLED, UsernameStatus.NONE)); return; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/FeatureFlags.java b/app/src/main/java/org/thoughtcrime/securesms/util/FeatureFlags.java index 84cc1c9db4..afdde5f5df 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/FeatureFlags.java +++ b/app/src/main/java/org/thoughtcrime/securesms/util/FeatureFlags.java @@ -79,6 +79,7 @@ public final class FeatureFlags { GROUPS_V2_LINKS_VERSION, CDS, INTERNAL_USER, + USERNAMES, MENTIONS, VERIFY_V2 ); diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/TextSecurePreferences.java b/app/src/main/java/org/thoughtcrime/securesms/util/TextSecurePreferences.java index 51580d5d89..e879ebf28c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/TextSecurePreferences.java +++ b/app/src/main/java/org/thoughtcrime/securesms/util/TextSecurePreferences.java @@ -694,14 +694,6 @@ public class TextSecurePreferences { setStringPreference(context, LOCAL_UUID_PREF, uuid.toString()); } - public static String getLocalUsername(Context context) { - return getStringPreference(context, LOCAL_USERNAME_PREF, null); - } - - public static void setLocalUsername(Context context, String username) { - setStringPreference(context, LOCAL_USERNAME_PREF, username); - } - public static String getPushServerPassword(Context context) { return getStringPreference(context, GCM_PASSWORD_PREF, null); } diff --git a/app/src/main/res/drawable/preference_username_background_dark.xml b/app/src/main/res/drawable/preference_username_background_dark.xml new file mode 100644 index 0000000000..9129a90e53 --- /dev/null +++ b/app/src/main/res/drawable/preference_username_background_dark.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/preference_username_background_light.xml b/app/src/main/res/drawable/preference_username_background_light.xml new file mode 100644 index 0000000000..11e0349e88 --- /dev/null +++ b/app/src/main/res/drawable/preference_username_background_light.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/mentions_picker_recipient_list_item.xml b/app/src/main/res/layout/mentions_picker_recipient_list_item.xml index 81ca1d6770..a162e9032f 100644 --- a/app/src/main/res/layout/mentions_picker_recipient_list_item.xml +++ b/app/src/main/res/layout/mentions_picker_recipient_list_item.xml @@ -30,15 +30,4 @@ android:textAppearance="@style/Signal.Text.Preview" tools:text="@tools:sample/full_names" /> - - diff --git a/app/src/main/res/layout/preference_username.xml b/app/src/main/res/layout/preference_username.xml new file mode 100644 index 0000000000..87d3123e41 --- /dev/null +++ b/app/src/main/res/layout/preference_username.xml @@ -0,0 +1,24 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/username_edit_fragment.xml b/app/src/main/res/layout/username_edit_fragment.xml index 25ca7d3a03..57b07b3db1 100644 --- a/app/src/main/res/layout/username_edit_fragment.xml +++ b/app/src/main/res/layout/username_edit_fragment.xml @@ -4,89 +4,108 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - android:layout_marginStart="16dp" - android:layout_marginEnd="16dp" - android:layout_marginBottom="16dp" android:orientation="vertical"> - + - + - + - + - + - + + + \ No newline at end of file diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index 152b7e1fd0..7f4489f1ed 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -253,6 +253,8 @@ + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d604b0df83..cfa2c1fcd3 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -56,6 +56,8 @@ PINs are required for registration lock. To disable PINs, please first disable registration lock. PIN created. PIN disabled. + Hide + Hide reminder? @@ -1381,7 +1383,6 @@ Username - Submit Delete Successfully set username. Successfully removed username. @@ -1392,7 +1393,7 @@ Usernames cannot begin with a number. Username is invalid. Usernames must be between %1$d and %2$d characters. - Other Signal users can send message requests to your unique username without knowing your phone number. Choosing a username is optional. + Usernames on Signal are optional. If you choose to create a username, other Signal users will be able to find you by this username and contact you without knowing your phone number. Your contact is running an old version of Signal. Please ask them to update before verifying your safety number. @@ -2125,6 +2126,7 @@ Mentions Notify me Receive notifications when you’re mentioned in muted chats + Setup a username Internal Preferences @@ -2595,7 +2597,6 @@ Legacy Groups can’t be converted into New Groups, but you can create a New Group with the same members. To create a New Group, all members should update to the latest version of Signal. - Share via Signal Copy diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index a68b6f852f..0f79bcfab9 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -431,6 +431,8 @@ @drawable/preference_divider_light + @drawable/preference_username_background_light + @color/core_grey_60 @color/core_grey_70 @@ -758,6 +760,8 @@ @drawable/preference_divider_dark + @drawable/preference_username_background_dark + @color/core_grey_05 @color/core_white diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 6225977848..052e35cfed 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -1,10 +1,15 @@ - + + + diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/profiles/SignalServiceProfile.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/profiles/SignalServiceProfile.java index 93ee98a8f6..21d0f0ad74 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/profiles/SignalServiceProfile.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/profiles/SignalServiceProfile.java @@ -41,9 +41,6 @@ public class SignalServiceProfile { @JsonProperty private Capabilities capabilities; - @JsonProperty - private String username; - @JsonProperty @JsonSerialize(using = JsonUtil.UuidSerializer.class) @JsonDeserialize(using = JsonUtil.UuidDeserializer.class) @@ -81,10 +78,6 @@ public class SignalServiceProfile { return capabilities; } - public String getUsername() { - return username; - } - public UUID getUuid() { return uuid; }