mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-02-26 20:55:10 +00:00
Add a QR code link and tooltip in the profile settings.
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<>();
|
||||
}
|
||||
|
||||
@@ -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(() -> {
|
||||
@@ -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()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user