mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-02-23 19:26:17 +00:00
Add username education screen.
This commit is contained in:
committed by
Greyson Parrelli
parent
dae69744c2
commit
4f387cf8d9
@@ -578,6 +578,13 @@ class InternalSettingsFragment : DSLSettingsFragment(R.string.preferences__inter
|
||||
}
|
||||
)
|
||||
|
||||
clickPref(
|
||||
title = DSLSettingsText.from("Clear Username education ui hint"),
|
||||
onClick = {
|
||||
SignalStore.uiHints().clearHasSeenUsernameEducation()
|
||||
}
|
||||
)
|
||||
|
||||
if (FeatureFlags.chatFilters()) {
|
||||
dividerPref()
|
||||
sectionHeaderPref(DSLSettingsText.from("Chat Filters"))
|
||||
|
||||
@@ -12,7 +12,8 @@ import java.util.List;
|
||||
public final class PhoneNumberPrivacyValues extends SignalStoreValues {
|
||||
|
||||
public static final String SHARING_MODE = "phoneNumberPrivacy.sharingMode";
|
||||
public static final String LISTING_MODE = "phoneNumberPrivacy.listingMode";
|
||||
public static final String LISTING_MODE = "phoneNumberPrivacy.listingMode";
|
||||
public static final String LISTING_TIMESTAMP = "phoneNumberPrivacy.listingMode.timestamp";
|
||||
|
||||
private static final Collection<CertificateType> REGULAR_CERTIFICATE = Collections.singletonList(CertificateType.UUID_AND_E164);
|
||||
private static final Collection<CertificateType> PRIVACY_CERTIFICATE = Collections.singletonList(CertificateType.UUID_ONLY);
|
||||
@@ -32,7 +33,7 @@ public final class PhoneNumberPrivacyValues extends SignalStoreValues {
|
||||
|
||||
@Override
|
||||
@NonNull List<String> getKeysToIncludeInBackup() {
|
||||
return Arrays.asList(SHARING_MODE, LISTING_MODE);
|
||||
return Arrays.asList(SHARING_MODE, LISTING_MODE, LISTING_TIMESTAMP);
|
||||
}
|
||||
|
||||
public @NonNull PhoneNumberSharingMode getPhoneNumberSharingMode() {
|
||||
@@ -56,7 +57,15 @@ public final class PhoneNumberPrivacyValues extends SignalStoreValues {
|
||||
}
|
||||
|
||||
public void setPhoneNumberListingMode(@NonNull PhoneNumberListingMode phoneNumberListingMode) {
|
||||
putInteger(LISTING_MODE, phoneNumberListingMode.serialize());
|
||||
getStore()
|
||||
.beginWrite()
|
||||
.putInteger(LISTING_MODE, phoneNumberListingMode.serialize())
|
||||
.putLong(LISTING_TIMESTAMP, System.currentTimeMillis())
|
||||
.apply();
|
||||
}
|
||||
|
||||
public long getPhoneNumberListingModeTimestamp() {
|
||||
return getLong(LISTING_TIMESTAMP, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,7 +2,7 @@ package org.thoughtcrime.securesms.keyvalue;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class UiHints extends SignalStoreValues {
|
||||
@@ -14,7 +14,7 @@ public class UiHints extends SignalStoreValues {
|
||||
private static final String HAS_SET_OR_SKIPPED_USERNAME_CREATION = "uihints.has_set_or_skipped_username_creation";
|
||||
private static final String NEVER_DISPLAY_PULL_TO_FILTER_TIP = "uihints.never_display_pull_to_filter_tip";
|
||||
private static final String HAS_SEEN_SCHEDULED_MESSAGES_INFO_ONCE = "uihints.has_seen_scheduled_messages_info_once";
|
||||
|
||||
private static final String HAS_SEEN_USERNAME_EDUCATION = "uihints.has_seen_username_education";
|
||||
UiHints(@NonNull KeyValueStore store) {
|
||||
super(store);
|
||||
}
|
||||
@@ -26,7 +26,7 @@ public class UiHints extends SignalStoreValues {
|
||||
|
||||
@Override
|
||||
@NonNull List<String> getKeysToIncludeInBackup() {
|
||||
return Collections.singletonList(NEVER_DISPLAY_PULL_TO_FILTER_TIP);
|
||||
return Arrays.asList(NEVER_DISPLAY_PULL_TO_FILTER_TIP, HAS_SEEN_USERNAME_EDUCATION);
|
||||
}
|
||||
|
||||
public void markHasSeenGroupSettingsMenuToast() {
|
||||
@@ -61,6 +61,19 @@ public class UiHints extends SignalStoreValues {
|
||||
putBoolean(HAS_SET_OR_SKIPPED_USERNAME_CREATION, true);
|
||||
}
|
||||
|
||||
public void markHasSeenUsernameEducation() {
|
||||
putBoolean(HAS_SEEN_USERNAME_EDUCATION, true);
|
||||
}
|
||||
|
||||
public boolean hasSeenUsernameEducation() {
|
||||
return getBoolean(HAS_SEEN_USERNAME_EDUCATION, false);
|
||||
}
|
||||
|
||||
public void clearHasSeenUsernameEducation() {
|
||||
putBoolean(HAS_SEEN_USERNAME_EDUCATION, false);
|
||||
}
|
||||
|
||||
|
||||
public void resetNeverDisplayPullToRefreshCount() {
|
||||
putInteger(NEVER_DISPLAY_PULL_TO_FILTER_TIP, 0);
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import androidx.annotation.WorkerThread;
|
||||
|
||||
import com.annimon.stream.Stream;
|
||||
|
||||
import org.signal.core.util.MapUtil;
|
||||
import org.signal.core.util.SetUtil;
|
||||
import org.signal.core.util.TranslationDetection;
|
||||
import org.signal.core.util.logging.Log;
|
||||
@@ -24,6 +25,7 @@ import org.thoughtcrime.securesms.database.model.RemoteMegaphoneRecord;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.exporter.flow.SmsExportActivity;
|
||||
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
||||
import org.thoughtcrime.securesms.keyvalue.PhoneNumberPrivacyValues;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.keyvalue.SmsExportPhase;
|
||||
import org.thoughtcrime.securesms.lock.SignalPinReminderDialog;
|
||||
@@ -54,13 +56,13 @@ import java.util.concurrent.TimeUnit;
|
||||
* - Add an enum to {@link Event}
|
||||
* - Return a megaphone in {@link #forRecord(Context, MegaphoneRecord)}
|
||||
* - Include the event in {@link #buildDisplayOrder(Context, Map)}
|
||||
*
|
||||
* <p>
|
||||
* Common patterns:
|
||||
* - For events that have a snooze-able recurring display schedule, use a {@link RecurringSchedule}.
|
||||
* - For events guarded by feature flags, set a {@link ForeverSchedule} with false in
|
||||
* {@link #buildDisplayOrder(Context, Map)}.
|
||||
* {@link #buildDisplayOrder(Context, Map)}.
|
||||
* - For events that change, return different megaphones in {@link #forRecord(Context, MegaphoneRecord)}
|
||||
* based on whatever properties you're interested in.
|
||||
* based on whatever properties you're interested in.
|
||||
*/
|
||||
public final class Megaphones {
|
||||
|
||||
@@ -80,7 +82,7 @@ public final class Megaphones {
|
||||
|
||||
List<Megaphone> megaphones = Stream.of(buildDisplayOrder(context, records))
|
||||
.filter(e -> {
|
||||
MegaphoneRecord record = Objects.requireNonNull(records.get(e.getKey()));
|
||||
MegaphoneRecord record = Objects.requireNonNull(records.get(e.getKey()));
|
||||
MegaphoneSchedule schedule = e.getValue();
|
||||
|
||||
return !record.isFinished() && schedule.shouldDisplay(record.getSeenCount(), record.getLastSeen(), record.getFirstVisible(), currentTime);
|
||||
@@ -100,7 +102,7 @@ public final class Megaphones {
|
||||
/**
|
||||
* The megaphones we want to display *in priority order*. This is a {@link LinkedHashMap}, so order is preserved.
|
||||
* We will render the first applicable megaphone in this collection.
|
||||
*
|
||||
* <p>
|
||||
* This is also when you would hide certain megaphones based on things like {@link FeatureFlags}.
|
||||
*/
|
||||
private static Map<Event, MegaphoneSchedule> buildDisplayOrder(@NonNull Context context, @NonNull Map<Event, MegaphoneRecord> records) {
|
||||
@@ -115,6 +117,7 @@ public final class Megaphones {
|
||||
put(Event.DONATE_Q2_2022, shouldShowDonateMegaphone(context, Event.DONATE_Q2_2022, records) ? ShowForDurationSchedule.showForDays(7) : NEVER);
|
||||
put(Event.REMOTE_MEGAPHONE, shouldShowRemoteMegaphone(records) ? RecurringSchedule.every(TimeUnit.DAYS.toMillis(1)) : NEVER);
|
||||
put(Event.PIN_REMINDER, new SignalPinReminderSchedule());
|
||||
put(Event.SET_UP_YOUR_USERNAME, shouldShowSetUpYourUsernameMegaphone(records) ? ALWAYS : NEVER);
|
||||
|
||||
// Feature-introduction megaphones should *probably* be added below this divider
|
||||
put(Event.ADD_A_PROFILE_PHOTO, shouldShowAddAProfilePhotoMegaphone(context) ? ALWAYS : NEVER);
|
||||
@@ -147,6 +150,9 @@ public final class Megaphones {
|
||||
return buildBackupPermissionMegaphone(context);
|
||||
case SMS_EXPORT:
|
||||
return buildSmsExportMegaphone(context);
|
||||
case SET_UP_YOUR_USERNAME:
|
||||
return buildSetUpYourUsernameMegaphone(context);
|
||||
|
||||
default:
|
||||
throw new IllegalArgumentException("Event not handled!");
|
||||
}
|
||||
@@ -155,110 +161,110 @@ public final class Megaphones {
|
||||
private static @NonNull Megaphone buildPinsForAllMegaphone(@NonNull MegaphoneRecord record) {
|
||||
if (PinsForAllSchedule.shouldDisplayFullScreen(record.getFirstVisible(), System.currentTimeMillis())) {
|
||||
return new Megaphone.Builder(Event.PINS_FOR_ALL, Megaphone.Style.FULLSCREEN)
|
||||
.enableSnooze(null)
|
||||
.setOnVisibleListener((megaphone, listener) -> {
|
||||
if (new NetworkConstraint.Factory(ApplicationDependencies.getApplication()).create().isMet()) {
|
||||
listener.onMegaphoneNavigationRequested(KbsMigrationActivity.createIntent(), KbsMigrationActivity.REQUEST_NEW_PIN);
|
||||
}
|
||||
})
|
||||
.build();
|
||||
.enableSnooze(null)
|
||||
.setOnVisibleListener((megaphone, listener) -> {
|
||||
if (new NetworkConstraint.Factory(ApplicationDependencies.getApplication()).create().isMet()) {
|
||||
listener.onMegaphoneNavigationRequested(KbsMigrationActivity.createIntent(), KbsMigrationActivity.REQUEST_NEW_PIN);
|
||||
}
|
||||
})
|
||||
.build();
|
||||
} else {
|
||||
return new Megaphone.Builder(Event.PINS_FOR_ALL, Megaphone.Style.BASIC)
|
||||
.setImage(R.drawable.kbs_pin_megaphone)
|
||||
.setTitle(R.string.KbsMegaphone__create_a_pin)
|
||||
.setBody(R.string.KbsMegaphone__pins_keep_information_thats_stored_with_signal_encrytped)
|
||||
.setActionButton(R.string.KbsMegaphone__create_pin, (megaphone, listener) -> {
|
||||
Intent intent = CreateKbsPinActivity.getIntentForPinCreate(ApplicationDependencies.getApplication());
|
||||
.setImage(R.drawable.kbs_pin_megaphone)
|
||||
.setTitle(R.string.KbsMegaphone__create_a_pin)
|
||||
.setBody(R.string.KbsMegaphone__pins_keep_information_thats_stored_with_signal_encrytped)
|
||||
.setActionButton(R.string.KbsMegaphone__create_pin, (megaphone, listener) -> {
|
||||
Intent intent = CreateKbsPinActivity.getIntentForPinCreate(ApplicationDependencies.getApplication());
|
||||
|
||||
listener.onMegaphoneNavigationRequested(intent, CreateKbsPinActivity.REQUEST_NEW_PIN);
|
||||
})
|
||||
.build();
|
||||
listener.onMegaphoneNavigationRequested(intent, CreateKbsPinActivity.REQUEST_NEW_PIN);
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("CodeBlock2Expr")
|
||||
private static @NonNull Megaphone buildPinReminderMegaphone(@NonNull Context context) {
|
||||
return new Megaphone.Builder(Event.PIN_REMINDER, Megaphone.Style.BASIC)
|
||||
.setTitle(R.string.Megaphones_verify_your_signal_pin)
|
||||
.setBody(R.string.Megaphones_well_occasionally_ask_you_to_verify_your_pin)
|
||||
.setImage(R.drawable.kbs_pin_megaphone)
|
||||
.setActionButton(R.string.Megaphones_verify_pin, (megaphone, controller) -> {
|
||||
SignalPinReminderDialog.show(controller.getMegaphoneActivity(), controller::onMegaphoneNavigationRequested, new SignalPinReminderDialog.Callback() {
|
||||
@Override
|
||||
public void onReminderDismissed(boolean includedFailure) {
|
||||
Log.i(TAG, "[PinReminder] onReminderDismissed(" + includedFailure + ")");
|
||||
if (includedFailure) {
|
||||
SignalStore.pinValues().onEntrySkipWithWrongGuess();
|
||||
}
|
||||
}
|
||||
.setTitle(R.string.Megaphones_verify_your_signal_pin)
|
||||
.setBody(R.string.Megaphones_well_occasionally_ask_you_to_verify_your_pin)
|
||||
.setImage(R.drawable.kbs_pin_megaphone)
|
||||
.setActionButton(R.string.Megaphones_verify_pin, (megaphone, controller) -> {
|
||||
SignalPinReminderDialog.show(controller.getMegaphoneActivity(), controller::onMegaphoneNavigationRequested, new SignalPinReminderDialog.Callback() {
|
||||
@Override
|
||||
public void onReminderDismissed(boolean includedFailure) {
|
||||
Log.i(TAG, "[PinReminder] onReminderDismissed(" + includedFailure + ")");
|
||||
if (includedFailure) {
|
||||
SignalStore.pinValues().onEntrySkipWithWrongGuess();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReminderCompleted(@NonNull String pin, boolean includedFailure) {
|
||||
Log.i(TAG, "[PinReminder] onReminderCompleted(" + includedFailure + ")");
|
||||
if (includedFailure) {
|
||||
SignalStore.pinValues().onEntrySuccessWithWrongGuess(pin);
|
||||
} else {
|
||||
SignalStore.pinValues().onEntrySuccess(pin);
|
||||
}
|
||||
@Override
|
||||
public void onReminderCompleted(@NonNull String pin, boolean includedFailure) {
|
||||
Log.i(TAG, "[PinReminder] onReminderCompleted(" + includedFailure + ")");
|
||||
if (includedFailure) {
|
||||
SignalStore.pinValues().onEntrySuccessWithWrongGuess(pin);
|
||||
} else {
|
||||
SignalStore.pinValues().onEntrySuccess(pin);
|
||||
}
|
||||
|
||||
controller.onMegaphoneSnooze(Event.PIN_REMINDER);
|
||||
controller.onMegaphoneToastRequested(controller.getMegaphoneActivity().getString(SignalPinReminders.getReminderString(SignalStore.pinValues().getCurrentInterval())));
|
||||
}
|
||||
});
|
||||
})
|
||||
.build();
|
||||
controller.onMegaphoneSnooze(Event.PIN_REMINDER);
|
||||
controller.onMegaphoneToastRequested(controller.getMegaphoneActivity().getString(SignalPinReminders.getReminderString(SignalStore.pinValues().getCurrentInterval())));
|
||||
}
|
||||
});
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
private static @NonNull Megaphone buildClientDeprecatedMegaphone(@NonNull Context context) {
|
||||
return new Megaphone.Builder(Event.CLIENT_DEPRECATED, Megaphone.Style.FULLSCREEN)
|
||||
.disableSnooze()
|
||||
.setOnVisibleListener((megaphone, listener) -> listener.onMegaphoneNavigationRequested(new Intent(context, ClientDeprecatedActivity.class)))
|
||||
.build();
|
||||
.disableSnooze()
|
||||
.setOnVisibleListener((megaphone, listener) -> listener.onMegaphoneNavigationRequested(new Intent(context, ClientDeprecatedActivity.class)))
|
||||
.build();
|
||||
}
|
||||
|
||||
private static @NonNull Megaphone buildOnboardingMegaphone() {
|
||||
return new Megaphone.Builder(Event.ONBOARDING, Megaphone.Style.ONBOARDING)
|
||||
.build();
|
||||
.build();
|
||||
}
|
||||
|
||||
private static @NonNull Megaphone buildNotificationsMegaphone(@NonNull Context context) {
|
||||
return new Megaphone.Builder(Event.NOTIFICATIONS, Megaphone.Style.BASIC)
|
||||
.setTitle(R.string.NotificationsMegaphone_turn_on_notifications)
|
||||
.setBody(R.string.NotificationsMegaphone_never_miss_a_message)
|
||||
.setImage(R.drawable.megaphone_notifications_64)
|
||||
.setActionButton(R.string.NotificationsMegaphone_turn_on, (megaphone, controller) -> {
|
||||
if (Build.VERSION.SDK_INT >= 26 && !NotificationChannels.getInstance().isMessageChannelEnabled()) {
|
||||
Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS);
|
||||
intent.putExtra(Settings.EXTRA_CHANNEL_ID, NotificationChannels.getInstance().getMessagesChannel());
|
||||
intent.putExtra(Settings.EXTRA_APP_PACKAGE, context.getPackageName());
|
||||
controller.onMegaphoneNavigationRequested(intent);
|
||||
} else if (Build.VERSION.SDK_INT >= 26 &&
|
||||
(!NotificationChannels.getInstance().areNotificationsEnabled() || !NotificationChannels.getInstance().isMessagesChannelGroupEnabled()))
|
||||
{
|
||||
Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
|
||||
intent.putExtra(Settings.EXTRA_APP_PACKAGE, context.getPackageName());
|
||||
controller.onMegaphoneNavigationRequested(intent);
|
||||
} else {
|
||||
controller.onMegaphoneNavigationRequested(AppSettingsActivity.notifications(context));
|
||||
}
|
||||
})
|
||||
.setSecondaryButton(R.string.NotificationsMegaphone_not_now, (megaphone, controller) -> controller.onMegaphoneSnooze(Event.NOTIFICATIONS))
|
||||
.build();
|
||||
.setTitle(R.string.NotificationsMegaphone_turn_on_notifications)
|
||||
.setBody(R.string.NotificationsMegaphone_never_miss_a_message)
|
||||
.setImage(R.drawable.megaphone_notifications_64)
|
||||
.setActionButton(R.string.NotificationsMegaphone_turn_on, (megaphone, controller) -> {
|
||||
if (Build.VERSION.SDK_INT >= 26 && !NotificationChannels.getInstance().isMessageChannelEnabled()) {
|
||||
Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS);
|
||||
intent.putExtra(Settings.EXTRA_CHANNEL_ID, NotificationChannels.getInstance().getMessagesChannel());
|
||||
intent.putExtra(Settings.EXTRA_APP_PACKAGE, context.getPackageName());
|
||||
controller.onMegaphoneNavigationRequested(intent);
|
||||
} else if (Build.VERSION.SDK_INT >= 26 &&
|
||||
(!NotificationChannels.getInstance().areNotificationsEnabled() || !NotificationChannels.getInstance().isMessagesChannelGroupEnabled()))
|
||||
{
|
||||
Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
|
||||
intent.putExtra(Settings.EXTRA_APP_PACKAGE, context.getPackageName());
|
||||
controller.onMegaphoneNavigationRequested(intent);
|
||||
} else {
|
||||
controller.onMegaphoneNavigationRequested(AppSettingsActivity.notifications(context));
|
||||
}
|
||||
})
|
||||
.setSecondaryButton(R.string.NotificationsMegaphone_not_now, (megaphone, controller) -> controller.onMegaphoneSnooze(Event.NOTIFICATIONS))
|
||||
.build();
|
||||
}
|
||||
|
||||
private static @NonNull Megaphone buildAddAProfilePhotoMegaphone(@NonNull Context context) {
|
||||
return new Megaphone.Builder(Event.ADD_A_PROFILE_PHOTO, Megaphone.Style.BASIC)
|
||||
.setTitle(R.string.AddAProfilePhotoMegaphone__add_a_profile_photo)
|
||||
.setImage(R.drawable.ic_add_a_profile_megaphone_image)
|
||||
.setBody(R.string.AddAProfilePhotoMegaphone__choose_a_look_and_color)
|
||||
.setActionButton(R.string.AddAProfilePhotoMegaphone__add_photo, (megaphone, listener) -> {
|
||||
listener.onMegaphoneNavigationRequested(ManageProfileActivity.getIntentForAvatarEdit(context));
|
||||
listener.onMegaphoneCompleted(Event.ADD_A_PROFILE_PHOTO);
|
||||
})
|
||||
.setSecondaryButton(R.string.AddAProfilePhotoMegaphone__not_now, (megaphone, listener) -> {
|
||||
listener.onMegaphoneCompleted(Event.ADD_A_PROFILE_PHOTO);
|
||||
})
|
||||
.build();
|
||||
.setTitle(R.string.AddAProfilePhotoMegaphone__add_a_profile_photo)
|
||||
.setImage(R.drawable.ic_add_a_profile_megaphone_image)
|
||||
.setBody(R.string.AddAProfilePhotoMegaphone__choose_a_look_and_color)
|
||||
.setActionButton(R.string.AddAProfilePhotoMegaphone__add_photo, (megaphone, listener) -> {
|
||||
listener.onMegaphoneNavigationRequested(ManageProfileActivity.getIntentForAvatarEdit(context));
|
||||
listener.onMegaphoneCompleted(Event.ADD_A_PROFILE_PHOTO);
|
||||
})
|
||||
.setSecondaryButton(R.string.AddAProfilePhotoMegaphone__not_now, (megaphone, listener) -> {
|
||||
listener.onMegaphoneCompleted(Event.ADD_A_PROFILE_PHOTO);
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
private static @NonNull Megaphone buildBecomeASustainerMegaphone(@NonNull Context context) {
|
||||
@@ -391,6 +397,19 @@ public final class Megaphones {
|
||||
}
|
||||
}
|
||||
|
||||
public static @NonNull Megaphone buildSetUpYourUsernameMegaphone(@NonNull Context context) {
|
||||
return new Megaphone.Builder(Event.SET_UP_YOUR_USERNAME, Megaphone.Style.BASIC)
|
||||
.setTitle(R.string.SetUpYourUsername__set_up_your_signal_username)
|
||||
.setBody(R.string.SetUpYourUsername__usernames_let_others)
|
||||
.setActionButton(R.string.SetUpYourUsername__continue, (megaphone, controller) -> {
|
||||
controller.onMegaphoneNavigationRequested(ManageProfileActivity.getIntentForUsernameEdit(context));
|
||||
})
|
||||
.setSecondaryButton(R.string.SetUpYourUsername__not_now, (megaphone, controller) -> {
|
||||
controller.onMegaphoneCompleted(Event.SET_UP_YOUR_USERNAME);
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
private static boolean shouldShowDonateMegaphone(@NonNull Context context, @NonNull Event event, @NonNull Map<Event, MegaphoneRecord> records) {
|
||||
long timeSinceLastDonatePrompt = timeSinceLastDonatePrompt(event, records);
|
||||
|
||||
@@ -422,10 +441,10 @@ public final class Megaphones {
|
||||
if (shouldShow) {
|
||||
Locale locale = DynamicLanguageContextWrapper.getUsersSelectedLocale(context);
|
||||
if (!new TranslationDetection(context, locale)
|
||||
.textExistsInUsersLanguage(R.string.NotificationsMegaphone_turn_on_notifications,
|
||||
R.string.NotificationsMegaphone_never_miss_a_message,
|
||||
R.string.NotificationsMegaphone_turn_on,
|
||||
R.string.NotificationsMegaphone_not_now))
|
||||
.textExistsInUsersLanguage(R.string.NotificationsMegaphone_turn_on_notifications,
|
||||
R.string.NotificationsMegaphone_never_miss_a_message,
|
||||
R.string.NotificationsMegaphone_turn_on,
|
||||
R.string.NotificationsMegaphone_not_now))
|
||||
{
|
||||
Log.i(TAG, "Would show NotificationsMegaphone but is not yet translated in " + locale);
|
||||
return false;
|
||||
@@ -448,6 +467,23 @@ public final class Megaphones {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prompt megaphone 3 days after turning off phone number discovery when no username is set.
|
||||
*/
|
||||
private static boolean shouldShowSetUpYourUsernameMegaphone(@NonNull Map<Event, MegaphoneRecord> records) {
|
||||
boolean hasUsername = SignalStore.account().isRegistered() && Recipient.self().getUsername().isPresent();
|
||||
boolean hasCompleted = MapUtil.mapOrDefault(records, Event.SET_UP_YOUR_USERNAME, MegaphoneRecord::isFinished, false);
|
||||
long phoneNumberDiscoveryDisabledAt = SignalStore.phoneNumberPrivacy().getPhoneNumberListingModeTimestamp();
|
||||
PhoneNumberPrivacyValues.PhoneNumberListingMode listingMode = SignalStore.phoneNumberPrivacy().getPhoneNumberListingMode();
|
||||
|
||||
return FeatureFlags.usernames() &&
|
||||
!hasUsername &&
|
||||
listingMode.isUnlisted() &&
|
||||
!hasCompleted &&
|
||||
phoneNumberDiscoveryDisabledAt > 0 &&
|
||||
(System.currentTimeMillis() - phoneNumberDiscoveryDisabledAt) >= TimeUnit.DAYS.toMillis(3);
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private static boolean shouldShowRemoteMegaphone(@NonNull Map<Event, MegaphoneRecord> records) {
|
||||
boolean canShowLocalDonate = timeSinceLastDonatePrompt(Event.REMOTE_MEGAPHONE, records) > MIN_TIME_BETWEEN_DONATE_MEGAPHONES;
|
||||
@@ -488,7 +524,8 @@ public final class Megaphones {
|
||||
TURN_OFF_CENSORSHIP_CIRCUMVENTION("turn_off_censorship_circumvention"),
|
||||
REMOTE_MEGAPHONE("remote_megaphone"),
|
||||
BACKUP_SCHEDULE_PERMISSION("backup_schedule_permission"),
|
||||
SMS_EXPORT("sms_export");
|
||||
SMS_EXPORT("sms_export"),
|
||||
SET_UP_YOUR_USERNAME("set_up_your_username");
|
||||
|
||||
private final String key;
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import androidx.navigation.fragment.NavHostFragment;
|
||||
|
||||
import org.thoughtcrime.securesms.PassphraseRequiredActivity;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.reactions.any.ReactWithAnyEmojiBottomSheetDialogFragment;
|
||||
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
|
||||
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||
@@ -63,8 +64,13 @@ public class ManageProfileActivity extends PassphraseRequiredActivity implements
|
||||
navController.setGraph(graph, extras != null ? extras : new Bundle());
|
||||
|
||||
if (extras != null && extras.getBoolean(START_AT_USERNAME, false)) {
|
||||
NavDirections action = ManageProfileFragmentDirections.actionManageUsername();
|
||||
SafeNavigation.safeNavigate(navController, action);
|
||||
if (SignalStore.uiHints().hasSeenUsernameEducation()) {
|
||||
NavDirections action = ManageProfileFragmentDirections.actionManageUsername();
|
||||
SafeNavigation.safeNavigate(navController, action);
|
||||
} else {
|
||||
NavDirections action = ManageProfileFragmentDirections.actionManageProfileFragmentToUsernameEducationFragment();
|
||||
SafeNavigation.safeNavigate(navController, action);
|
||||
}
|
||||
}
|
||||
|
||||
if (extras != null && extras.getBoolean(START_AT_AVATAR, false)) {
|
||||
|
||||
@@ -20,6 +20,7 @@ import androidx.navigation.Navigation;
|
||||
|
||||
import com.airbnb.lottie.SimpleColorFilter;
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
@@ -33,11 +34,12 @@ import org.thoughtcrime.securesms.badges.self.none.BecomeASustainerFragment;
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiTextView;
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiUtil;
|
||||
import org.thoughtcrime.securesms.databinding.ManageProfileFragmentBinding;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.mediasend.Media;
|
||||
import org.thoughtcrime.securesms.profiles.ProfileName;
|
||||
import org.thoughtcrime.securesms.profiles.manage.ManageProfileViewModel.AvatarState;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.FeatureFlags;
|
||||
import org.thoughtcrime.securesms.util.LifecycleDisposable;
|
||||
import org.thoughtcrime.securesms.util.NameUtil;
|
||||
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
|
||||
import org.thoughtcrime.securesms.util.navigation.SafeNavigation;
|
||||
@@ -49,6 +51,8 @@ import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
|
||||
import io.reactivex.rxjava3.disposables.Disposable;
|
||||
|
||||
public class ManageProfileFragment extends LoggingFragment {
|
||||
|
||||
private static final String TAG = Log.tag(ManageProfileFragment.class);
|
||||
@@ -56,6 +60,7 @@ public class ManageProfileFragment extends LoggingFragment {
|
||||
private AlertDialog avatarProgress;
|
||||
private ManageProfileViewModel viewModel;
|
||||
private ManageProfileFragmentBinding binding;
|
||||
private LifecycleDisposable disposables;
|
||||
|
||||
@Override
|
||||
public @Nullable View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
@@ -66,6 +71,9 @@ public class ManageProfileFragment extends LoggingFragment {
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
disposables = new LifecycleDisposable();
|
||||
disposables.bindTo(getViewLifecycleOwner());
|
||||
|
||||
new UsernameEditFragment.ResultContract().registerForResult(getParentFragmentManager(), getViewLifecycleOwner(), isUsernameCreated -> {
|
||||
Snackbar.make(view, R.string.ManageProfileFragment__username_created, Snackbar.LENGTH_SHORT).show();
|
||||
});
|
||||
@@ -85,7 +93,28 @@ public class ManageProfileFragment extends LoggingFragment {
|
||||
});
|
||||
|
||||
binding.manageProfileUsernameContainer.setOnClickListener(v -> {
|
||||
SafeNavigation.safeNavigate(Navigation.findNavController(v), ManageProfileFragmentDirections.actionManageUsername());
|
||||
if (SignalStore.uiHints().hasSeenUsernameEducation()) {
|
||||
if (Recipient.self().getUsername().isPresent()) {
|
||||
new MaterialAlertDialogBuilder(requireContext(), R.style.ThemeOverlay_Signal_MaterialAlertDialog_List)
|
||||
.setItems(R.array.username_edit_entries, (d, w) -> {
|
||||
switch (w) {
|
||||
case 0:
|
||||
SafeNavigation.safeNavigate(Navigation.findNavController(v), ManageProfileFragmentDirections.actionManageUsername());
|
||||
break;
|
||||
case 1:
|
||||
displayConfirmUsernameDeletionDialog();
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
})
|
||||
.show();
|
||||
} else {
|
||||
SafeNavigation.safeNavigate(Navigation.findNavController(v), ManageProfileFragmentDirections.actionManageUsername());
|
||||
}
|
||||
} else {
|
||||
SafeNavigation.safeNavigate(Navigation.findNavController(v), ManageProfileFragmentDirections.actionManageProfileFragmentToUsernameEducationFragment());
|
||||
}
|
||||
});
|
||||
|
||||
binding.manageProfileAboutContainer.setOnClickListener(v -> {
|
||||
@@ -272,4 +301,29 @@ public class ManageProfileFragment extends LoggingFragment {
|
||||
private void onEditAvatarClicked() {
|
||||
SafeNavigation.safeNavigate(Navigation.findNavController(requireView()), ManageProfileFragmentDirections.actionManageProfileFragmentToAvatarPicker(null, null));
|
||||
}
|
||||
|
||||
private void displayConfirmUsernameDeletionDialog() {
|
||||
new MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle("Delete Username?") // TODO [alex] -- Final copy
|
||||
.setMessage("This will remove your username, allowing other users to claim it. Are you sure?") // TODO [alex] -- Final copy
|
||||
.setPositiveButton(R.string.delete, (d, w) -> {
|
||||
onUserConfirmedUsernameDeletion();
|
||||
})
|
||||
.setNegativeButton(android.R.string.cancel, (d, w) -> {})
|
||||
.show();
|
||||
}
|
||||
|
||||
private void onUserConfirmedUsernameDeletion() {
|
||||
binding.progressCard.setVisibility(View.VISIBLE);
|
||||
Disposable disposable = viewModel.deleteUsername()
|
||||
.subscribe(result -> {
|
||||
binding.progressCard.setVisibility(View.GONE);
|
||||
handleUsernameDeletionResult(result);
|
||||
});
|
||||
disposables.add(disposable);
|
||||
}
|
||||
|
||||
private void handleUsernameDeletionResult(@NonNull UsernameEditRepository.UsernameDeleteResult usernameDeleteResult) {
|
||||
// TODO [alex] -- Snackbar?
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,9 @@ import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.rxjava3.core.Single;
|
||||
|
||||
class ManageProfileViewModel extends ViewModel {
|
||||
|
||||
private static final String TAG = Log.tag(ManageProfileViewModel.class);
|
||||
@@ -46,22 +49,24 @@ class ManageProfileViewModel extends ViewModel {
|
||||
private final LiveData<AvatarState> avatarState;
|
||||
private final SingleLiveEvent<Event> events;
|
||||
private final RecipientForeverObserver observer;
|
||||
private final ManageProfileRepository repository;
|
||||
private final MutableLiveData<Optional<Badge>> badge;
|
||||
private final ManageProfileRepository repository;
|
||||
private final UsernameEditRepository usernameEditRepository;
|
||||
private final MutableLiveData<Optional<Badge>> badge;
|
||||
|
||||
private byte[] previousAvatar;
|
||||
|
||||
public ManageProfileViewModel() {
|
||||
this.internalAvatarState = new MutableLiveData<>();
|
||||
this.profileName = new MutableLiveData<>();
|
||||
this.username = new MutableLiveData<>();
|
||||
this.about = new MutableLiveData<>();
|
||||
this.aboutEmoji = new MutableLiveData<>();
|
||||
this.events = new SingleLiveEvent<>();
|
||||
this.repository = new ManageProfileRepository();
|
||||
this.badge = new DefaultValueLiveData<>(Optional.empty());
|
||||
this.observer = this::onRecipientChanged;
|
||||
this.avatarState = LiveDataUtil.combineLatest(Recipient.self().live().getLiveData(), internalAvatarState, (self, state) -> new AvatarState(state, self));
|
||||
this.internalAvatarState = new MutableLiveData<>();
|
||||
this.profileName = new MutableLiveData<>();
|
||||
this.username = new MutableLiveData<>();
|
||||
this.about = new MutableLiveData<>();
|
||||
this.aboutEmoji = new MutableLiveData<>();
|
||||
this.events = new SingleLiveEvent<>();
|
||||
this.repository = new ManageProfileRepository();
|
||||
this.usernameEditRepository = new UsernameEditRepository();
|
||||
this.badge = new DefaultValueLiveData<>(Optional.empty());
|
||||
this.observer = this::onRecipientChanged;
|
||||
this.avatarState = LiveDataUtil.combineLatest(Recipient.self().live().getLiveData(), internalAvatarState, (self, state) -> new AvatarState(state, self));
|
||||
|
||||
SignalExecutors.BOUNDED.execute(() -> {
|
||||
onRecipientChanged(Recipient.self().fresh());
|
||||
@@ -99,6 +104,10 @@ class ManageProfileViewModel extends ViewModel {
|
||||
return events;
|
||||
}
|
||||
|
||||
public Single<UsernameEditRepository.UsernameDeleteResult> deleteUsername() {
|
||||
return usernameEditRepository.deleteUsername().observeOn(AndroidSchedulers.mainThread());
|
||||
}
|
||||
|
||||
public boolean shouldShowUsername() {
|
||||
return FeatureFlags.usernames();
|
||||
}
|
||||
@@ -271,7 +280,7 @@ class ManageProfileViewModel extends ViewModel {
|
||||
|
||||
static class Factory extends ViewModelProvider.NewInstanceFactory {
|
||||
@Override
|
||||
public @NonNull<T extends ViewModel> T create(@NonNull Class<T> modelClass) {
|
||||
public @NonNull <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
|
||||
return Objects.requireNonNull(modelClass.cast(new ManageProfileViewModel()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
import org.signal.core.util.Result;
|
||||
import org.signal.core.util.concurrent.SignalExecutors;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
@@ -17,7 +16,6 @@ import org.whispersystems.signalservice.api.push.exceptions.UsernameTakenExcepti
|
||||
import org.whispersystems.signalservice.internal.push.ReserveUsernameResponse;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import io.reactivex.rxjava3.core.Single;
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package org.thoughtcrime.securesms.profiles.manage
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.components.ViewBinderDelegate
|
||||
import org.thoughtcrime.securesms.databinding.UsernameEducationFragmentBinding
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.util.navigation.safeNavigate
|
||||
|
||||
/**
|
||||
* Displays a Username education screen which displays some basic information
|
||||
* about usernames and provides a learn-more link.
|
||||
*/
|
||||
class UsernameEducationFragment : Fragment(R.layout.username_education_fragment) {
|
||||
private val binding by ViewBinderDelegate(UsernameEducationFragmentBinding::bind)
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
binding.toolbar.setNavigationOnClickListener {
|
||||
findNavController().popBackStack()
|
||||
}
|
||||
|
||||
binding.usernameEducationLearnMore.setOnClickListener {
|
||||
// TODO [alex] -- Launch "Learn More" page.
|
||||
}
|
||||
|
||||
binding.continueButton.setOnClickListener {
|
||||
SignalStore.uiHints().markHasSeenUsernameEducation()
|
||||
findNavController().safeNavigate(UsernameEducationFragmentDirections.actionUsernameEducationFragmentToUsernameManageFragment())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,310 +1,324 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<FrameLayout 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="match_parent">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/signal_m3_toolbar_height"
|
||||
android:minHeight="@dimen/signal_m3_toolbar_height"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:navigationIcon="@drawable/ic_arrow_left_24"
|
||||
app:title="@string/CreateProfileActivity__profile" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/manage_profile_avatar_background"
|
||||
android:layout_width="80dp"
|
||||
android:layout_height="80dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:src="@drawable/circle_tintable"
|
||||
android:tint="@color/core_grey_05"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/toolbar"
|
||||
app:layout_goneMarginTop="?attr/actionBarSize" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/manage_profile_avatar_placeholder"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:tint="@color/core_grey_75"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/manage_profile_avatar_background"
|
||||
app:layout_constraintEnd_toEndOf="@+id/manage_profile_avatar_background"
|
||||
app:layout_constraintStart_toStartOf="@+id/manage_profile_avatar_background"
|
||||
app:layout_constraintTop_toTopOf="@+id/manage_profile_avatar_background"
|
||||
app:srcCompat="@drawable/ic_profile_outline_40" />
|
||||
|
||||
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
|
||||
android:id="@+id/manage_profile_avatar_initials"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
android:gravity="center"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="@id/manage_profile_avatar_background"
|
||||
app:layout_constraintEnd_toEndOf="@id/manage_profile_avatar_background"
|
||||
app:layout_constraintStart_toStartOf="@id/manage_profile_avatar_background"
|
||||
app:layout_constraintTop_toTopOf="@id/manage_profile_avatar_background"
|
||||
tools:ignore="SpUsage"
|
||||
tools:text="AF"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/manage_profile_avatar"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:contentDescription="@string/CreateProfileActivity_set_avatar_description"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/manage_profile_avatar_background"
|
||||
app:layout_constraintEnd_toEndOf="@+id/manage_profile_avatar_background"
|
||||
app:layout_constraintStart_toStartOf="@+id/manage_profile_avatar_background"
|
||||
app:layout_constraintTop_toTopOf="@+id/manage_profile_avatar_background" />
|
||||
|
||||
<org.thoughtcrime.securesms.badges.BadgeImageView
|
||||
android:id="@+id/manage_profile_badge"
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="36dp"
|
||||
android:layout_marginStart="44dp"
|
||||
android:layout_marginTop="52dp"
|
||||
app:badge_size="large"
|
||||
app:layout_constraintStart_toStartOf="@+id/manage_profile_avatar_background"
|
||||
app:layout_constraintTop_toTopOf="@+id/manage_profile_avatar_background" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/manage_profile_edit_photo"
|
||||
style="@style/Widget.Signal.Button.Small"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/dsl_settings_gutter"
|
||||
android:layout_marginTop="14dp"
|
||||
android:layout_marginEnd="@dimen/dsl_settings_gutter"
|
||||
android:text="@string/ManageProfileFragment__edit_photo"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/manage_profile_avatar_background" />
|
||||
android:layout_height="match_parent"
|
||||
android:fillViewport="true">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/manage_profile_name_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:background="?selectableItemBackground"
|
||||
android:paddingStart="@dimen/dsl_settings_gutter"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingEnd="@dimen/dsl_settings_gutter"
|
||||
android:paddingBottom="16dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/manage_profile_edit_photo">
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/manage_profile_name_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toBottomOf="@id/manage_profile_name_subtitle"
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/signal_m3_toolbar_height"
|
||||
android:minHeight="@dimen/signal_m3_toolbar_height"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/manage_profile_name"
|
||||
app:srcCompat="@drawable/symbol_person_24"
|
||||
app:tint="@color/signal_text_primary" />
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:navigationIcon="@drawable/ic_arrow_left_24"
|
||||
app:title="@string/CreateProfileActivity__profile" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/manage_profile_avatar_background"
|
||||
android:layout_width="80dp"
|
||||
android:layout_height="80dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:src="@drawable/circle_tintable"
|
||||
android:tint="@color/core_grey_05"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/toolbar"
|
||||
app:layout_goneMarginTop="?attr/actionBarSize" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/manage_profile_avatar_placeholder"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:tint="@color/core_grey_75"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/manage_profile_avatar_background"
|
||||
app:layout_constraintEnd_toEndOf="@+id/manage_profile_avatar_background"
|
||||
app:layout_constraintStart_toStartOf="@+id/manage_profile_avatar_background"
|
||||
app:layout_constraintTop_toTopOf="@+id/manage_profile_avatar_background"
|
||||
app:srcCompat="@drawable/ic_profile_outline_40" />
|
||||
|
||||
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
|
||||
android:id="@+id/manage_profile_name"
|
||||
style="@style/Signal.Text.Body"
|
||||
android:id="@+id/manage_profile_avatar_initials"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:textAlignment="viewStart"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/manage_profile_name_icon"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="Peter Parker" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/manage_profile_name_subtitle"
|
||||
style="@style/Signal.Text.Preview"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/ManageProfileFragment_your_name"
|
||||
android:textColor="@color/signal_text_secondary"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="@id/manage_profile_name"
|
||||
app:layout_constraintTop_toBottomOf="@id/manage_profile_name" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/manage_profile_username_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?selectableItemBackground"
|
||||
android:minHeight="72dp"
|
||||
android:paddingStart="@dimen/dsl_settings_gutter"
|
||||
android:paddingEnd="@dimen/safety_number_recipient_row_item_gutter"
|
||||
app:layout_constraintTop_toBottomOf="@id/manage_profile_name_container">
|
||||
android:layout_height="0dp"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
android:gravity="center"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="@id/manage_profile_avatar_background"
|
||||
app:layout_constraintEnd_toEndOf="@id/manage_profile_avatar_background"
|
||||
app:layout_constraintStart_toStartOf="@id/manage_profile_avatar_background"
|
||||
app:layout_constraintTop_toTopOf="@id/manage_profile_avatar_background"
|
||||
tools:ignore="SpUsage"
|
||||
tools:text="AF"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/manage_profile_username_icon"
|
||||
android:id="@+id/manage_profile_avatar"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:contentDescription="@string/CreateProfileActivity_set_avatar_description"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/manage_profile_avatar_background"
|
||||
app:layout_constraintEnd_toEndOf="@+id/manage_profile_avatar_background"
|
||||
app:layout_constraintStart_toStartOf="@+id/manage_profile_avatar_background"
|
||||
app:layout_constraintTop_toTopOf="@+id/manage_profile_avatar_background" />
|
||||
|
||||
<org.thoughtcrime.securesms.badges.BadgeImageView
|
||||
android:id="@+id/manage_profile_badge"
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="36dp"
|
||||
android:layout_marginStart="44dp"
|
||||
android:layout_marginTop="52dp"
|
||||
app:badge_size="large"
|
||||
app:layout_constraintStart_toStartOf="@+id/manage_profile_avatar_background"
|
||||
app:layout_constraintTop_toTopOf="@+id/manage_profile_avatar_background" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/manage_profile_edit_photo"
|
||||
style="@style/Widget.Signal.Button.Small"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toBottomOf="@id/manage_profile_username_subtitle"
|
||||
android:layout_marginStart="@dimen/dsl_settings_gutter"
|
||||
android:layout_marginTop="14dp"
|
||||
android:layout_marginEnd="@dimen/dsl_settings_gutter"
|
||||
android:text="@string/ManageProfileFragment__edit_photo"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/manage_profile_username"
|
||||
app:srcCompat="@drawable/symbol_at_24"
|
||||
app:tint="@color/signal_text_primary" />
|
||||
app:layout_constraintTop_toBottomOf="@id/manage_profile_avatar_background" />
|
||||
|
||||
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
|
||||
android:id="@+id/manage_profile_username"
|
||||
style="@style/Signal.Text.Body"
|
||||
android:layout_width="0dp"
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/manage_profile_name_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:textAlignment="viewStart"
|
||||
app:layout_constraintBottom_toTopOf="@id/manage_profile_username_subtitle"
|
||||
app:layout_constraintEnd_toStartOf="@id/manage_profile_username_share"
|
||||
app:layout_constraintStart_toEndOf="@id/manage_profile_username_icon"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_chainStyle="packed"
|
||||
app:layout_goneMarginEnd="48dp"
|
||||
tools:text="\@spiderman" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/manage_profile_username_subtitle"
|
||||
style="@style/Signal.Text.Preview"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/ManageProfileFragment_your_username"
|
||||
android:textColor="@color/signal_text_secondary"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/manage_profile_username_share"
|
||||
app:layout_constraintStart_toStartOf="@id/manage_profile_username"
|
||||
app:layout_constraintTop_toBottomOf="@id/manage_profile_username"
|
||||
app:layout_goneMarginEnd="48dp" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/manage_profile_username_share"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginTop="20dp"
|
||||
android:background="?selectableItemBackground"
|
||||
android:scaleType="centerInside"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@drawable/symbol_share_android_24"
|
||||
app:tint="@color/signal_colorOnSurface" />
|
||||
android:paddingStart="@dimen/dsl_settings_gutter"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingEnd="@dimen/dsl_settings_gutter"
|
||||
android:paddingBottom="16dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/manage_profile_edit_photo">
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
<ImageView
|
||||
android:id="@+id/manage_profile_name_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toBottomOf="@id/manage_profile_name_subtitle"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/manage_profile_name"
|
||||
app:srcCompat="@drawable/symbol_person_24"
|
||||
app:tint="@color/signal_text_primary" />
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/manage_profile_about_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?selectableItemBackground"
|
||||
android:paddingStart="@dimen/dsl_settings_gutter"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingEnd="@dimen/dsl_settings_gutter"
|
||||
android:paddingBottom="16dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/manage_profile_username_container">
|
||||
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
|
||||
android:id="@+id/manage_profile_name"
|
||||
style="@style/Signal.Text.Body"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:textAlignment="viewStart"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/manage_profile_name_icon"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="Peter Parker" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/manage_profile_about_icon"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:scaleType="fitCenter"
|
||||
app:layout_constraintBottom_toBottomOf="@id/manage_profile_about_subtitle"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/manage_profile_about"
|
||||
app:srcCompat="@drawable/symbol_edit_24"
|
||||
app:tint="@color/signal_text_primary" />
|
||||
<TextView
|
||||
android:id="@+id/manage_profile_name_subtitle"
|
||||
style="@style/Signal.Text.Preview"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/ManageProfileFragment_your_name"
|
||||
android:textColor="@color/signal_text_secondary"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="@id/manage_profile_name"
|
||||
app:layout_constraintTop_toBottomOf="@id/manage_profile_name" />
|
||||
|
||||
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
|
||||
android:id="@+id/manage_profile_about"
|
||||
style="@style/Signal.Text.Body"
|
||||
android:layout_width="0dp"
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/manage_profile_username_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:textAlignment="viewStart"
|
||||
app:emoji_forceCustom="true"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/manage_profile_about_icon"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="Photographer for the Daily Bugle" />
|
||||
android:background="?selectableItemBackground"
|
||||
android:minHeight="72dp"
|
||||
android:paddingStart="@dimen/dsl_settings_gutter"
|
||||
android:paddingEnd="@dimen/safety_number_recipient_row_item_gutter"
|
||||
app:layout_constraintTop_toBottomOf="@id/manage_profile_name_container">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/manage_profile_about_subtitle"
|
||||
<ImageView
|
||||
android:id="@+id/manage_profile_username_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toBottomOf="@id/manage_profile_username_subtitle"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/manage_profile_username"
|
||||
app:srcCompat="@drawable/symbol_at_24"
|
||||
app:tint="@color/signal_text_primary" />
|
||||
|
||||
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
|
||||
android:id="@+id/manage_profile_username"
|
||||
style="@style/Signal.Text.Body"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:textAlignment="viewStart"
|
||||
app:layout_constraintBottom_toTopOf="@id/manage_profile_username_subtitle"
|
||||
app:layout_constraintEnd_toStartOf="@id/manage_profile_username_share"
|
||||
app:layout_constraintStart_toEndOf="@id/manage_profile_username_icon"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_chainStyle="packed"
|
||||
app:layout_goneMarginEnd="48dp"
|
||||
tools:text="\@spiderman" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/manage_profile_username_subtitle"
|
||||
style="@style/Signal.Text.Preview"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/ManageProfileFragment_your_username"
|
||||
android:textColor="@color/signal_text_secondary"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/manage_profile_username_share"
|
||||
app:layout_constraintStart_toStartOf="@id/manage_profile_username"
|
||||
app:layout_constraintTop_toBottomOf="@id/manage_profile_username"
|
||||
app:layout_goneMarginEnd="48dp" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/manage_profile_username_share"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:background="?selectableItemBackground"
|
||||
android:scaleType="centerInside"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@drawable/symbol_share_android_24"
|
||||
app:tint="@color/signal_colorOnSurface" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/manage_profile_about_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?selectableItemBackground"
|
||||
android:paddingStart="@dimen/dsl_settings_gutter"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingEnd="@dimen/dsl_settings_gutter"
|
||||
android:paddingBottom="16dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/manage_profile_username_container">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/manage_profile_about_icon"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:scaleType="fitCenter"
|
||||
app:layout_constraintBottom_toBottomOf="@id/manage_profile_about_subtitle"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/manage_profile_about"
|
||||
app:srcCompat="@drawable/symbol_edit_24"
|
||||
app:tint="@color/signal_text_primary" />
|
||||
|
||||
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
|
||||
android:id="@+id/manage_profile_about"
|
||||
style="@style/Signal.Text.Body"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:textAlignment="viewStart"
|
||||
app:emoji_forceCustom="true"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/manage_profile_about_icon"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="Photographer for the Daily Bugle" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/manage_profile_about_subtitle"
|
||||
style="@style/Signal.Text.Preview"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/ManageProfileFragment_write_a_few_words_about_yourself"
|
||||
android:textColor="@color/signal_text_secondary"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="@id/manage_profile_about"
|
||||
app:layout_constraintTop_toBottomOf="@id/manage_profile_about" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/manage_profile_badges_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?selectableItemBackground"
|
||||
android:paddingStart="@dimen/dsl_settings_gutter"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingEnd="@dimen/dsl_settings_gutter"
|
||||
android:paddingBottom="16dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/manage_profile_about_container">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/manage_profile_badges_icon"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:scaleType="fitCenter"
|
||||
app:layout_constraintBottom_toBottomOf="@id/manage_profile_badges"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/manage_profile_badges"
|
||||
app:srcCompat="@drawable/symbol_badge_multi_24"
|
||||
app:tint="@color/signal_text_primary" />
|
||||
|
||||
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
|
||||
android:id="@+id/manage_profile_badges"
|
||||
style="@style/Signal.Text.Body"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:text="@string/ManageProfileFragment_badges"
|
||||
android:textAlignment="viewStart"
|
||||
app:emoji_forceCustom="true"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/manage_profile_badges_icon"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<org.thoughtcrime.securesms.util.views.LearnMoreTextView
|
||||
android:id="@+id/group_description_text"
|
||||
style="@style/Signal.Text.Preview"
|
||||
android:layout_width="0dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/ManageProfileFragment_write_a_few_words_about_yourself"
|
||||
android:textColor="@color/signal_text_secondary"
|
||||
android:layout_marginStart="@dimen/dsl_settings_gutter"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="@dimen/dsl_settings_gutter"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="@string/CreateProfileActivity_signal_profiles_are_end_to_end_encrypted"
|
||||
android:textAppearance="@style/Signal.Text.BodyMedium"
|
||||
android:textColor="@color/signal_colorOnSurfaceVariant"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="@id/manage_profile_about"
|
||||
app:layout_constraintTop_toBottomOf="@id/manage_profile_about" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/manage_profile_badges_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?selectableItemBackground"
|
||||
android:paddingStart="@dimen/dsl_settings_gutter"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingEnd="@dimen/dsl_settings_gutter"
|
||||
android:paddingBottom="16dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/manage_profile_about_container">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/manage_profile_badges_icon"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:scaleType="fitCenter"
|
||||
app:layout_constraintBottom_toBottomOf="@id/manage_profile_badges"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/manage_profile_badges"
|
||||
app:srcCompat="@drawable/symbol_badge_multi_24"
|
||||
app:tint="@color/signal_text_primary" />
|
||||
|
||||
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
|
||||
android:id="@+id/manage_profile_badges"
|
||||
style="@style/Signal.Text.Body"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:text="@string/ManageProfileFragment_badges"
|
||||
android:textAlignment="viewStart"
|
||||
app:emoji_forceCustom="true"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/manage_profile_badges_icon"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
app:layout_constraintTop_toBottomOf="@+id/manage_profile_badges_container"
|
||||
app:layout_constraintVertical_bias="1.0" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<org.thoughtcrime.securesms.util.views.LearnMoreTextView
|
||||
android:id="@+id/group_description_text"
|
||||
style="@style/Signal.Text.Preview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/dsl_settings_gutter"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="@dimen/dsl_settings_gutter"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="@string/CreateProfileActivity_signal_profiles_are_end_to_end_encrypted"
|
||||
android:textAppearance="@style/Signal.Text.BodyMedium"
|
||||
android:textColor="@color/signal_colorOnSurfaceVariant"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/manage_profile_badges_container"
|
||||
app:layout_constraintVertical_bias="1.0" />
|
||||
</ScrollView>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
<org.thoughtcrime.securesms.components.ProgressCard
|
||||
android:id="@+id/progress_card"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:visibility="gone" />
|
||||
|
||||
</ScrollView>
|
||||
</FrameLayout>
|
||||
|
||||
155
app/src/main/res/layout/username_education_fragment.xml
Normal file
155
app/src/main/res/layout/username_education_fragment.xml
Normal file
@@ -0,0 +1,155 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView 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="match_parent"
|
||||
android:fillViewport="true">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/signal_m3_toolbar_height"
|
||||
android:minHeight="@dimen/signal_m3_toolbar_height"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:navigationIcon="@drawable/ic_arrow_left_24" />
|
||||
|
||||
<com.google.android.material.imageview.ShapeableImageView
|
||||
android:id="@+id/username_symbol"
|
||||
android:layout_width="72dp"
|
||||
android:layout_height="72dp"
|
||||
android:layout_marginTop="64dp"
|
||||
android:background="@color/signal_colorSurface2"
|
||||
app:contentPadding="16dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.Signal.Circle"
|
||||
app:srcCompat="@drawable/symbol_at_24" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
style="@style/Signal.Text.HeadlineLarge"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="@dimen/dsl_settings_gutter"
|
||||
android:layout_marginTop="12dp"
|
||||
android:text="@string/UsernameEducationFragment__set_up_your_signal_username"
|
||||
android:textAlignment="center"
|
||||
android:textColor="@color/signal_colorOnSurface"
|
||||
app:layout_constrainedWidth="true"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/username_symbol" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/username_education_icon_1"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginTop="40dp"
|
||||
android:importantForAccessibility="no"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/title" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/username_education_text_1"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="32dp"
|
||||
android:textAppearance="@style/Signal.Text.BodyLarge"
|
||||
android:textColor="@color/signal_colorOnSurfaceVariant"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/username_education_icon_1"
|
||||
app:layout_constraintTop_toTopOf="@id/username_education_icon_1"
|
||||
tools:text="Usernames are paired with a set of digits and aren’t shared on your profile" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/username_education_icon_2"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginTop="36dp"
|
||||
android:importantForAccessibility="no"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/username_education_icon_1" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/username_education_text_2"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="32dp"
|
||||
android:textAppearance="@style/Signal.Text.BodyLarge"
|
||||
android:textColor="@color/signal_colorOnSurfaceVariant"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/username_education_icon_2"
|
||||
app:layout_constraintTop_toTopOf="@id/username_education_icon_2"
|
||||
tools:text="Each username has a unique link you can share with your friends to start a chat with you" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/username_education_icon_3"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginTop="36dp"
|
||||
android:importantForAccessibility="no"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/username_education_icon_2" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/username_education_text_3"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="32dp"
|
||||
android:textAppearance="@style/Signal.Text.BodyLarge"
|
||||
android:textColor="@color/signal_colorOnSurfaceVariant"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/username_education_icon_3"
|
||||
app:layout_constraintTop_toTopOf="@id/username_education_icon_3"
|
||||
tools:text="Turn off phone number discovery under Settings > Phone Number > Who can find my number, to use your username as the primary way
|
||||
others can contact you." />
|
||||
|
||||
<androidx.constraintlayout.widget.Barrier
|
||||
android:id="@+id/username_education_row_3_barrier"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:barrierDirection="bottom"
|
||||
app:constraint_referenced_ids="username_education_icon_3,username_education_text_3" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/username_education_learn_more"
|
||||
style="@style/Widget.Signal.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
android:text="@string/LearnMoreTextView_learn_more"
|
||||
android:textAppearance="@style/Signal.Text.BodyLarge"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/username_education_row_3_barrier" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/continue_button"
|
||||
style="@style/Signal.Widget.Button.Large.Tonal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="64dp"
|
||||
android:text="@string/UsernameEducationFragment__continue"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/username_education_learn_more"
|
||||
app:layout_constraintVertical_bias="1" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</ScrollView>
|
||||
@@ -65,6 +65,9 @@
|
||||
<action
|
||||
android:id="@+id/action_manageProfileFragment_to_shareUsernameDialog"
|
||||
app:destination="@id/shareUsernameDialog" />
|
||||
<action
|
||||
android:id="@+id/action_manageProfileFragment_to_usernameEducationFragment"
|
||||
app:destination="@id/usernameEducationFragment" />
|
||||
|
||||
</fragment>
|
||||
|
||||
@@ -74,6 +77,17 @@
|
||||
android:label="fragment_manage_username"
|
||||
tools:layout="@layout/username_edit_fragment" />
|
||||
|
||||
<fragment
|
||||
android:id="@+id/usernameEducationFragment"
|
||||
android:name="org.thoughtcrime.securesms.profiles.manage.UsernameEducationFragment"
|
||||
android:label="fragment_username_education"
|
||||
tools:layout="@layout/username_education_fragment">
|
||||
<action
|
||||
android:id="@+id/action_usernameEducationFragment_to_usernameManageFragment"
|
||||
app:destination="@id/usernameManageFragment"
|
||||
app:popUpTo="@id/manageProfileFragment" />
|
||||
</fragment>
|
||||
|
||||
<fragment
|
||||
android:id="@+id/profileNameManageFragment"
|
||||
android:name="org.thoughtcrime.securesms.profiles.manage.EditProfileNameFragment"
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<string-array name="username_edit_entries">
|
||||
<item>@string/UsernameEditDialog__edit_username</item>
|
||||
<item>@string/UsernameEditDialog__delete_username</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="language_entries">
|
||||
<!-- zz --><item>@string/preferences__system_default</item>
|
||||
|
||||
@@ -234,6 +234,11 @@
|
||||
<item name="alertDialogStyle">@style/Signal.MaterialAlertDialog.Wide</item>
|
||||
</style>
|
||||
|
||||
<style name="ThemeOverlay.Signal.MaterialAlertDialog.List">
|
||||
<item name="materialAlertDialogBodyTextStyle">@style/Signal.Text.BodyLarge</item>
|
||||
<item name="listPreferredItemHeightSmall">56dp</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.Signal.CheckedTextView" parent="Widget.Material3.CheckedTextView">
|
||||
<item name="android:textAppearance">@style/Signal.Text.BodyLarge</item>
|
||||
<item name="android:textColor">@color/signal_colorOnSurfaceVariant</item>
|
||||
|
||||
@@ -5546,8 +5546,6 @@
|
||||
<string name="GroupStoryEducationSheet__next">Next</string>
|
||||
<string name="Registration_country_code_entry_hint">+0</string>
|
||||
|
||||
<!-- EOF -->
|
||||
|
||||
<!-- PaypalCompleteOrderBottomSheet -->
|
||||
<string name="PaypalCompleteOrderBottomSheet__donate">Donate</string>
|
||||
<string name="PaypalCompleteOrderBottomSheet__payment">Payment</string>
|
||||
@@ -5573,6 +5571,16 @@
|
||||
<!-- Button label on sms removal info/megaphone to start the export SMS flow -->
|
||||
<string name="SmsRemoval_export_sms">Export SMS</string>
|
||||
|
||||
<!-- Set up your username megaphone -->
|
||||
<!-- Displayed as a title on a megaphone which prompts user to set up a username -->
|
||||
<string name="SetUpYourUsername__set_up_your_signal_username">Set up your Signal username</string>
|
||||
<!-- Displayed as a description on a megaphone which prompts user to set up a username -->
|
||||
<string name="SetUpYourUsername__usernames_let_others">Usernames let others message you without needing your phone number</string>
|
||||
<!-- Displayed as an action on a megaphone which prompts user to set up a username -->
|
||||
<string name="SetUpYourUsername__not_now">Not now</string>
|
||||
<!-- Displayed as an action on a megaphone which prompts user to set up a username -->
|
||||
<string name="SetUpYourUsername__continue">Continue</string>
|
||||
|
||||
<!-- Text Formatting -->
|
||||
<!-- Popup menu label for applying bold style -->
|
||||
<string name="TextFormatting_bold">Bold</string>
|
||||
@@ -5582,4 +5590,18 @@
|
||||
<string name="TextFormatting_strikethrough">Strikethrough</string>
|
||||
<!-- Popup menu label for applying monospace font style -->
|
||||
<string name="TextFormatting_monospace">Monospace</string>
|
||||
|
||||
<!-- UsernameEducationFragment -->
|
||||
<!-- Continue button which takes the user to the add a username screen -->
|
||||
<string name="UsernameEducationFragment__continue">Continue</string>
|
||||
<!-- Displayed as a title on the username education screen -->
|
||||
<string name="UsernameEducationFragment__set_up_your_signal_username">Set up your Signal username</string>
|
||||
|
||||
<!-- Username edit dialog -->
|
||||
<!-- Option to open username editor displayed as a list item in a dialog -->
|
||||
<string name="UsernameEditDialog__edit_username">Edit username</string>
|
||||
<!-- Option to delete username displayed as a list item in a dialog -->
|
||||
<string name="UsernameEditDialog__delete_username">Delete username</string>
|
||||
|
||||
<!-- EOF -->
|
||||
</resources>
|
||||
|
||||
@@ -5,6 +5,7 @@ import android.os.Build;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
public final class MapUtil {
|
||||
|
||||
@@ -20,4 +21,10 @@ public final class MapUtil {
|
||||
return v == null ? defaultValue : v;
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static <K, V, M> M mapOrDefault(@NonNull Map<K, V> map, @NonNull K key, @NonNull Function<V, M> mapper, @NonNull M defaultValue) {
|
||||
V v = map.get(key);
|
||||
return v == null ? defaultValue : mapper.apply(v);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user