Add a QR code link and tooltip in the profile settings.

This commit is contained in:
Greyson Parrelli 2023-11-03 10:47:35 -04:00
parent 528ccc1e9d
commit 29350ab7b0
15 changed files with 346 additions and 159 deletions

View file

@ -14,6 +14,7 @@ public class TooltipValues extends SignalStoreValues {
private static final String GROUP_CALL_TOOLTIP_DISPLAY_COUNT = "tooltip.group_call_tooltip_display_count";
private static final String MULTI_FORWARD_DIALOG = "tooltip.multi.forward.dialog";
private static final String BUBBLE_OPT_OUT = "tooltip.bubble.opt.out";
private static final String PROFILE_SETTINGS_QR_CODE = "tooltip.profile_settings_qr_code";
TooltipValues(@NonNull KeyValueStore store) {
@ -73,4 +74,12 @@ public class TooltipValues extends SignalStoreValues {
public void markBubbleOptOutTooltipSeen() {
putBoolean(BUBBLE_OPT_OUT, true);
}
public boolean showProfileSettingsQrCodeTooltop() {
return getBoolean(PROFILE_SETTINGS_QR_CODE, true);
}
public void markProfileSettingsQrCodeTooltipSeen() {
putBoolean(PROFILE_SETTINGS_QR_CODE, false);
}
}

View file

@ -52,7 +52,7 @@ public class CreateProfileActivity extends BaseActivity implements CreateProfile
setContentView(R.layout.create_profile_activity);
if (bundle == null) {
NavHostFragment fragment = NavHostFragment.create(R.navigation.edit_profile, getIntent().getExtras());
NavHostFragment fragment = NavHostFragment.create(R.navigation.create_profile, getIntent().getExtras());
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container, fragment)
.commit();

View file

@ -12,12 +12,12 @@ import io.reactivex.rxjava3.subjects.PublishSubject;
public final class EditAboutViewModel extends ViewModel {
private final ManageProfileRepository repository;
private final EditProfileRepository repository;
private final BehaviorSubject<SaveState> saveState;
private final PublishSubject<Event> events;
public EditAboutViewModel() {
this.repository = new ManageProfileRepository();
this.repository = new EditProfileRepository();
this.saveState = BehaviorSubject.createDefault(SaveState.IDLE);
this.events = PublishSubject.create();
}

View file

@ -14,6 +14,7 @@ import androidx.core.content.res.ResourcesCompat
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.map
import androidx.navigation.Navigation.findNavController
import androidx.navigation.fragment.findNavController
import com.airbnb.lottie.SimpleColorFilter
import com.bumptech.glide.Glide
import com.google.android.material.dialog.MaterialAlertDialogBuilder
@ -32,9 +33,10 @@ import org.thoughtcrime.securesms.databinding.EditProfileFragmentBinding
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.profiles.manage.EditProfileViewModel.AvatarState
import org.thoughtcrime.securesms.profiles.manage.UsernameRepository.UsernameDeleteResult
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.util.FeatureFlags
import org.thoughtcrime.securesms.util.NameUtil.getAbbreviation
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil
import org.thoughtcrime.securesms.util.navigation.safeNavigate
@ -49,7 +51,7 @@ class EditProfileFragment : LoggingFragment() {
private var avatarProgress: AlertDialog? = null
private lateinit var viewModel: ManageProfileViewModel
private lateinit var viewModel: EditProfileViewModel
private lateinit var binding: EditProfileFragmentBinding
private lateinit var disposables: LifecycleDisposable
@ -128,10 +130,26 @@ class EditProfileFragment : LoggingFragment() {
AvatarPreviewActivity.createTransitionBundle(requireActivity(), binding.manageProfileAvatar)
)
}
if (FeatureFlags.usernames() && SignalStore.account().username != null) {
binding.usernameLinkContainer.setOnClickListener {
findNavController().safeNavigate(EditProfileFragmentDirections.actionManageProfileFragmentToUsernameLinkFragment())
}
if (SignalStore.tooltips().showProfileSettingsQrCodeTooltop()) {
binding.usernameLinkTooltip.visibility = View.VISIBLE
binding.linkTooltipCloseButton.setOnClickListener {
binding.usernameLinkTooltip.visibility = View.GONE
SignalStore.tooltips().markProfileSettingsQrCodeTooltipSeen()
}
}
} else {
binding.usernameLinkContainer.visibility = View.GONE
}
}
private fun initializeViewModel() {
viewModel = ViewModelProvider(this, ManageProfileViewModel.Factory()).get(ManageProfileViewModel::class.java)
viewModel = ViewModelProvider(this, EditProfileViewModel.Factory()).get(EditProfileViewModel::class.java)
LiveDataUtil
.distinctUntilChanged(viewModel.avatar) { b1, b2 -> Arrays.equals(b1.avatar, b2.avatar) }
@ -185,9 +203,9 @@ class EditProfileFragment : LoggingFragment() {
binding.manageProfileAvatarInitials.visibility = View.GONE
}
if (avatarProgress == null && avatarState.loadingState == ManageProfileViewModel.LoadingState.LOADING) {
if (avatarProgress == null && avatarState.loadingState == EditProfileViewModel.LoadingState.LOADING) {
avatarProgress = SimpleProgressDialog.show(requireContext())
} else if (avatarProgress != null && avatarState.loadingState == ManageProfileViewModel.LoadingState.LOADED) {
} else if (avatarProgress != null && avatarState.loadingState == EditProfileViewModel.LoadingState.LOADED) {
avatarProgress!!.dismiss()
}
}
@ -251,10 +269,10 @@ class EditProfileFragment : LoggingFragment() {
}
}
private fun presentEvent(event: ManageProfileViewModel.Event) {
private fun presentEvent(event: EditProfileViewModel.Event) {
when (event) {
ManageProfileViewModel.Event.AVATAR_DISK_FAILURE -> Toast.makeText(requireContext(), R.string.ManageProfileFragment_failed_to_set_avatar, Toast.LENGTH_LONG).show()
ManageProfileViewModel.Event.AVATAR_NETWORK_FAILURE -> Toast.makeText(requireContext(), R.string.EditProfileNameFragment_failed_to_save_due_to_network_issues_try_again_later, Toast.LENGTH_LONG).show()
EditProfileViewModel.Event.AVATAR_DISK_FAILURE -> Toast.makeText(requireContext(), R.string.ManageProfileFragment_failed_to_set_avatar, Toast.LENGTH_LONG).show()
EditProfileViewModel.Event.AVATAR_NETWORK_FAILURE -> Toast.makeText(requireContext(), R.string.EditProfileNameFragment_failed_to_save_due_to_network_issues_try_again_later, Toast.LENGTH_LONG).show()
}
}
@ -284,7 +302,10 @@ class EditProfileFragment : LoggingFragment() {
private fun handleUsernameDeletionResult(usernameDeleteResult: UsernameDeleteResult) {
when (usernameDeleteResult) {
UsernameDeleteResult.SUCCESS -> Snackbar.make(requireView(), R.string.ManageProfileFragment__username_deleted, Snackbar.LENGTH_SHORT).show()
UsernameDeleteResult.SUCCESS -> {
Snackbar.make(requireView(), R.string.ManageProfileFragment__username_deleted, Snackbar.LENGTH_SHORT).show()
binding.usernameLinkContainer.visibility = View.GONE
}
UsernameDeleteResult.NETWORK_ERROR -> Snackbar.make(requireView(), R.string.ManageProfileFragment__couldnt_delete_username, Snackbar.LENGTH_SHORT).show()
}
}

View file

@ -14,12 +14,12 @@ import org.signal.core.util.StringUtil;
public final class EditProfileNameViewModel extends ViewModel {
private final ManageProfileRepository repository;
private final EditProfileRepository repository;
private final MutableLiveData<SaveState> saveState;
private final SingleLiveEvent<Event> events;
public EditProfileNameViewModel() {
this.repository = new ManageProfileRepository();
this.repository = new EditProfileRepository();
this.saveState = new MutableLiveData<>(SaveState.IDLE);
this.events = new SingleLiveEvent<>();
}

View file

@ -20,9 +20,9 @@ import org.whispersystems.signalservice.api.util.StreamDetails;
import java.io.ByteArrayInputStream;
import java.io.IOException;
final class ManageProfileRepository {
final class EditProfileRepository {
private static final String TAG = Log.tag(ManageProfileRepository.class);
private static final String TAG = Log.tag(EditProfileRepository.class);
public void setName(@NonNull Context context, @NonNull ProfileName profileName, @NonNull Consumer<Result> callback) {
SignalExecutors.UNBOUNDED.execute(() -> {

View file

@ -37,9 +37,9 @@ import java.util.Optional;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.Single;
class ManageProfileViewModel extends ViewModel {
class EditProfileViewModel extends ViewModel {
private static final String TAG = Log.tag(ManageProfileViewModel.class);
private static final String TAG = Log.tag(EditProfileViewModel.class);
private final MutableLiveData<InternalAvatarState> internalAvatarState;
private final MutableLiveData<ProfileName> profileName;
@ -49,20 +49,20 @@ class ManageProfileViewModel extends ViewModel {
private final LiveData<AvatarState> avatarState;
private final SingleLiveEvent<Event> events;
private final RecipientForeverObserver observer;
private final ManageProfileRepository repository;
private final EditProfileRepository repository;
private final UsernameRepository usernameEditRepository;
private final MutableLiveData<Optional<Badge>> badge;
private byte[] previousAvatar;
public ManageProfileViewModel() {
public EditProfileViewModel() {
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.repository = new EditProfileRepository();
this.usernameEditRepository = new UsernameRepository();
this.badge = new DefaultValueLiveData<>(Optional.empty());
this.observer = this::onRecipientChanged;
@ -281,7 +281,7 @@ class ManageProfileViewModel extends ViewModel {
static class Factory extends ViewModelProvider.NewInstanceFactory {
@Override
public @NonNull <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
return Objects.requireNonNull(modelClass.cast(new ManageProfileViewModel()));
return Objects.requireNonNull(modelClass.cast(new EditProfileViewModel()));
}
}

View file

@ -232,6 +232,8 @@ class UsernameRepository {
return try {
accountManager.deleteUsername()
SignalDatabase.recipients.setUsername(Recipient.self().id, null)
SignalStore.account().username = null
SignalStore.account().usernameLink = null
SignalStore.account().usernameOutOfSync = false
Log.i(TAG, "[deleteUsername] Successfully deleted the username.")
UsernameDeleteResult.SUCCESS

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="20dp"
android:height="12dp"
android:viewportWidth="20"
android:viewportHeight="12">
<path
android:pathData="M10,-0L1,9L19,9L10,-0Z"
android:fillColor="#000000"/>
</vector>

View file

@ -17,6 +17,6 @@
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/manage_profile" />
app:navGraph="@navigation/edit_profile" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -12,7 +12,8 @@
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:animateLayoutChanges="true">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
@ -170,7 +171,40 @@
app:layout_goneMarginEnd="48dp"
tools:text="\@spiderman" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/username_link_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_username_container">
<ImageView
android:id="@+id/username_link_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:srcCompat="@drawable/symbol_qrcode_24"
app:tint="@color/signal_text_primary" />
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/username_link_text"
style="@style/Signal.Text.Body"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:textAlignment="viewStart"
android:text="@string/ManageProfileFragment_link_setting_text"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/username_link_icon"
app:layout_goneMarginEnd="48dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
@ -183,7 +217,7 @@
android:paddingTop="16dp"
android:paddingEnd="@dimen/dsl_settings_gutter"
android:paddingBottom="16dp"
app:layout_constraintTop_toBottomOf="@id/manage_profile_username_container">
app:layout_constraintTop_toBottomOf="@id/username_link_container">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/manage_profile_about_icon"
@ -267,6 +301,95 @@
app:layout_constraintTop_toBottomOf="@+id/manage_profile_badges_container"
app:layout_constraintVertical_bias="1.0" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/username_link_tooltip"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
android:clickable="true"
android:visibility="gone"
android:background="@color/transparent"
android:clipChildren="false"
android:clipToPadding="false"
tools:visibility="visible"
app:layout_constraintTop_toBottomOf="@id/username_link_container"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<FrameLayout
android:id="@+id/tooltip_arrow_top"
android:layout_width="19dp"
android:layout_height="14dp"
android:importantForAccessibility="no"
android:scaleType="fitXY"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:background="@drawable/ic_tooltip_arrow_up"
android:backgroundTint="@color/signal_colorPrimaryContainer" />
<FrameLayout
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="9dp"
android:background="@drawable/tooltip_background"
android:backgroundTint="@color/signal_colorPrimaryContainer"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="@id/tooltip_description"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
<ImageView
android:id="@+id/tooltip_share_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="25dp"
android:src="@drawable/symbol_share_android_24"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<TextView
android:id="@+id/tooltip_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="34dp"
android:text="@string/ManageProfileFragment__link_tooltip_title"
android:textAppearance="@style/Signal.Text.Body"
android:fontFamily="sans-serif-medium"
android:textColor="@color/signal_colorOnPrimaryContainer"
app:layout_constraintTop_toTopOf="@id/tooltip_share_icon"
app:layout_constraintStart_toEndOf="@id/tooltip_share_icon"
app:layout_constraintEnd_toEndOf="parent"/>
<TextView
android:id="@+id/tooltip_description"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:paddingBottom="15dp"
android:text="@string/ManageProfileFragment__link_tooltip_body"
android:textColor="@color/signal_colorOnSurfaceVariant"
app:layout_constraintTop_toBottomOf="@id/tooltip_title"
app:layout_constraintStart_toStartOf="@id/tooltip_title"
app:layout_constraintEnd_toEndOf="@id/tooltip_title"/>
<ImageView
android:id="@+id/link_tooltip_close_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="21dp"
android:layout_marginEnd="12dp"
android:src="@drawable/symbol_x_24"
android:foreground="?selectableItemBackgroundBorderless"
app:tint="@color/signal_colorOnSurfaceVariant"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>

View file

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<navigation 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:id="@+id/create_profile"
app:startDestination="@id/createProfileFragment">
<fragment
android:id="@+id/createProfileFragment"
android:name="org.thoughtcrime.securesms.profiles.edit.CreateProfileFragment"
android:label="fragment_create_profile"
tools:layout="@layout/create_profile_fragment">
<action
android:id="@+id/action_createProfileFragment_to_avatar_picker"
app:destination="@id/avatar_picker"
app:enterAnim="@anim/nav_default_enter_anim"
app:exitAnim="@anim/nav_default_exit_anim"
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
app:popExitAnim="@anim/nav_default_pop_exit_anim">
<argument
android:name="group_id"
app:argType="org.thoughtcrime.securesms.groups.ParcelableGroupId"
app:nullable="true" />
<argument
android:name="group_avatar_media"
app:argType="org.thoughtcrime.securesms.mediasend.Media"
app:nullable="true" />
</action>
<action
android:id="@+id/action_createProfileFragment_to_phoneNumberPrivacy"
app:destination="@id/phoneNumberPrivacy"
app:enterAnim="@anim/nav_default_enter_anim"
app:exitAnim="@anim/nav_default_exit_anim"
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
app:popExitAnim="@anim/nav_default_pop_exit_anim" />
</fragment>
<include app:graph="@navigation/avatar_picker" />
<fragment
android:id="@+id/phoneNumberPrivacy"
android:name="org.thoughtcrime.securesms.profiles.edit.pnp.WhoCanSeeMyPhoneNumberFragment"
android:label="fragment_phone_number_privacy"
tools:layout="@layout/dsl_settings_fragment" />
</navigation>

View file

@ -2,22 +2,47 @@
<navigation 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:id="@+id/create_profile"
app:startDestination="@id/createProfileFragment">
android:id="@+id/manage_profile"
app:startDestination="@id/manageProfileFragment">
<fragment
android:id="@+id/createProfileFragment"
android:name="org.thoughtcrime.securesms.profiles.edit.CreateProfileFragment"
android:label="fragment_create_profile"
tools:layout="@layout/create_profile_fragment">
android:id="@+id/manageProfileFragment"
android:name="org.thoughtcrime.securesms.profiles.manage.EditProfileFragment"
android:label="fragment_manage_profile"
tools:layout="@layout/edit_profile_fragment">
<action
android:id="@+id/action_createProfileFragment_to_avatar_picker"
android:id="@+id/action_manageUsername"
app:destination="@id/usernameManageFragment"
app:enterAnim="@anim/fragment_open_enter"
app:exitAnim="@anim/fragment_open_exit"
app:popEnterAnim="@anim/fragment_close_enter"
app:popExitAnim="@anim/fragment_close_exit" />
<action
android:id="@+id/action_manageProfileName"
app:destination="@id/profileNameManageFragment"
app:enterAnim="@anim/fragment_open_enter"
app:exitAnim="@anim/fragment_open_exit"
app:popEnterAnim="@anim/fragment_close_enter"
app:popExitAnim="@anim/fragment_close_exit" />
<action
android:id="@+id/action_manageAbout"
app:destination="@id/aboutManageFragment"
app:enterAnim="@anim/fragment_open_enter"
app:exitAnim="@anim/fragment_open_exit"
app:popEnterAnim="@anim/fragment_close_enter"
app:popExitAnim="@anim/fragment_close_exit" />
<action
android:id="@+id/action_manageProfileFragment_to_avatar_picker"
app:destination="@id/avatar_picker"
app:enterAnim="@anim/nav_default_enter_anim"
app:exitAnim="@anim/nav_default_exit_anim"
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
app:popExitAnim="@anim/nav_default_pop_exit_anim">
app:enterAnim="@anim/fragment_open_enter"
app:exitAnim="@anim/fragment_open_exit"
app:popEnterAnim="@anim/fragment_close_enter"
app:popExitAnim="@anim/fragment_close_exit">
<argument
android:name="group_id"
app:argType="org.thoughtcrime.securesms.groups.ParcelableGroupId"
@ -27,24 +52,80 @@
android:name="group_avatar_media"
app:argType="org.thoughtcrime.securesms.mediasend.Media"
app:nullable="true" />
</action>
<action
android:id="@+id/action_createProfileFragment_to_phoneNumberPrivacy"
app:destination="@id/phoneNumberPrivacy"
app:enterAnim="@anim/nav_default_enter_anim"
app:exitAnim="@anim/nav_default_exit_anim"
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
app:popExitAnim="@anim/nav_default_pop_exit_anim" />
android:id="@+id/action_manageProfileFragment_to_badgeManageFragment"
app:destination="@id/manage_badges"
app:enterAnim="@anim/fragment_open_enter"
app:exitAnim="@anim/fragment_open_exit"
app:popEnterAnim="@anim/fragment_close_enter"
app:popExitAnim="@anim/fragment_close_exit" />
<action
android:id="@+id/action_manageProfileFragment_to_shareUsernameDialog"
app:destination="@id/shareUsernameDialog" />
<action
android:id="@+id/action_manageProfileFragment_to_usernameEducationFragment"
app:destination="@id/usernameEducationFragment"
app:enterAnim="@anim/fragment_open_enter"
app:exitAnim="@anim/fragment_open_exit"
app:popEnterAnim="@anim/fragment_close_enter"
app:popExitAnim="@anim/fragment_close_exit" />
<action
android:id="@+id/action_manageProfileFragment_to_usernameLinkFragment"
app:destination="@id/usernameLinkFragment"
app:enterAnim="@anim/fragment_open_enter"
app:exitAnim="@anim/fragment_open_exit"
app:popEnterAnim="@anim/fragment_close_enter"
app:popExitAnim="@anim/fragment_close_exit" />
</fragment>
<include app:graph="@navigation/avatar_picker" />
<fragment
android:id="@+id/usernameManageFragment"
android:name="org.thoughtcrime.securesms.profiles.manage.UsernameEditFragment"
android:label="fragment_manage_username"
tools:layout="@layout/username_edit_fragment" />
<fragment
android:id="@+id/phoneNumberPrivacy"
android:name="org.thoughtcrime.securesms.profiles.edit.pnp.WhoCanSeeMyPhoneNumberFragment"
android:label="fragment_phone_number_privacy"
tools:layout="@layout/dsl_settings_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"
android:label="fragment_manage_profile_name"
tools:layout="@layout/edit_profile_name_fragment" />
<fragment
android:id="@+id/aboutManageFragment"
android:name="org.thoughtcrime.securesms.profiles.manage.EditAboutFragment"
android:label="fragment_manage_about"
tools:layout="@layout/edit_about_fragment" />
<fragment
android:id="@+id/usernameLinkFragment"
android:name="org.thoughtcrime.securesms.components.settings.app.usernamelinks.main.UsernameLinkSettingsFragment"
android:label="fragment_username_link" />
<include app:graph="@navigation/manage_badges" />
<include app:graph="@navigation/avatar_picker" />
<dialog
android:id="@+id/shareUsernameDialog"
android:name="org.thoughtcrime.securesms.profiles.manage.UsernameShareBottomSheet"
android:label="fragment_username_share" />
</navigation>

View file

@ -1,112 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<navigation 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:id="@+id/manage_profile"
app:startDestination="@id/manageProfileFragment">
<fragment
android:id="@+id/manageProfileFragment"
android:name="org.thoughtcrime.securesms.profiles.manage.EditProfileFragment"
android:label="fragment_manage_profile"
tools:layout="@layout/edit_profile_fragment">
<action
android:id="@+id/action_manageUsername"
app:destination="@id/usernameManageFragment"
app:enterAnim="@anim/fragment_open_enter"
app:exitAnim="@anim/fragment_open_exit"
app:popEnterAnim="@anim/fragment_close_enter"
app:popExitAnim="@anim/fragment_close_exit" />
<action
android:id="@+id/action_manageProfileName"
app:destination="@id/profileNameManageFragment"
app:enterAnim="@anim/fragment_open_enter"
app:exitAnim="@anim/fragment_open_exit"
app:popEnterAnim="@anim/fragment_close_enter"
app:popExitAnim="@anim/fragment_close_exit" />
<action
android:id="@+id/action_manageAbout"
app:destination="@id/aboutManageFragment"
app:enterAnim="@anim/fragment_open_enter"
app:exitAnim="@anim/fragment_open_exit"
app:popEnterAnim="@anim/fragment_close_enter"
app:popExitAnim="@anim/fragment_close_exit" />
<action
android:id="@+id/action_manageProfileFragment_to_avatar_picker"
app:destination="@id/avatar_picker"
app:enterAnim="@anim/fragment_open_enter"
app:exitAnim="@anim/fragment_open_exit"
app:popEnterAnim="@anim/fragment_close_enter"
app:popExitAnim="@anim/fragment_close_exit">
<argument
android:name="group_id"
app:argType="org.thoughtcrime.securesms.groups.ParcelableGroupId"
app:nullable="true" />
<argument
android:name="group_avatar_media"
app:argType="org.thoughtcrime.securesms.mediasend.Media"
app:nullable="true" />
</action>
<action
android:id="@+id/action_manageProfileFragment_to_badgeManageFragment"
app:destination="@id/manage_badges"
app:enterAnim="@anim/fragment_open_enter"
app:exitAnim="@anim/fragment_open_exit"
app:popEnterAnim="@anim/fragment_close_enter"
app:popExitAnim="@anim/fragment_close_exit" />
<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>
<fragment
android:id="@+id/usernameManageFragment"
android:name="org.thoughtcrime.securesms.profiles.manage.UsernameEditFragment"
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"
android:label="fragment_manage_profile_name"
tools:layout="@layout/edit_profile_name_fragment" />
<fragment
android:id="@+id/aboutManageFragment"
android:name="org.thoughtcrime.securesms.profiles.manage.EditAboutFragment"
android:label="fragment_manage_about"
tools:layout="@layout/edit_about_fragment" />
<include app:graph="@navigation/manage_badges" />
<include app:graph="@navigation/avatar_picker" />
<dialog
android:id="@+id/shareUsernameDialog"
android:name="org.thoughtcrime.securesms.profiles.manage.UsernameShareBottomSheet"
android:label="fragment_username_share" />
</navigation>

View file

@ -996,6 +996,10 @@
<!-- Text for a button that will take the user to the screen to manage their username link and QR code -->
<string name="ManageProfileFragment_link_setting_text">QR code or link</string>
<string name="ManageProfileFragment__edit_photo">Edit photo</string>
<!-- Title of a tooltip educating the user about a button on the screen that will take them to the username share screen -->
<string name="ManageProfileFragment__link_tooltip_title">Share your username</string>
<!-- Body of a tooltip educating the user about a button on the screen that will take them to the username share screen -->
<string name="ManageProfileFragment__link_tooltip_body">Let others start a chat with you by sharing your unique QR code or link.</string>
<!-- Snackbar message after creating username -->
<string name="ManageProfileFragment__username_created">Username created</string>
<!-- Snackbar message after copying username -->