Convert EditProfileFragment to kotlin.
This commit is contained in:
parent
3a20375567
commit
d00f2aa8d0
4 changed files with 300 additions and 326 deletions
|
@ -1,322 +0,0 @@
|
|||
package org.thoughtcrime.securesms.profiles.manage;
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.TypedValue;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.core.content.res.ResourcesCompat;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.Transformations;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
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;
|
||||
import org.thoughtcrime.securesms.AvatarPreviewActivity;
|
||||
import org.thoughtcrime.securesms.LoggingFragment;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.avatar.Avatars;
|
||||
import org.thoughtcrime.securesms.avatar.picker.AvatarPickerFragment;
|
||||
import org.thoughtcrime.securesms.badges.models.Badge;
|
||||
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.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.recipients.Recipient;
|
||||
import org.signal.core.util.concurrent.LifecycleDisposable;
|
||||
import org.thoughtcrime.securesms.util.NameUtil;
|
||||
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
|
||||
import org.thoughtcrime.securesms.util.navigation.SafeNavigation;
|
||||
import org.thoughtcrime.securesms.util.views.SimpleProgressDialog;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
|
||||
import io.reactivex.rxjava3.disposables.Disposable;
|
||||
|
||||
/**
|
||||
* Fragment for editing your profile after you're already registered.
|
||||
*/
|
||||
public class EditProfileFragment extends LoggingFragment {
|
||||
|
||||
private static final String TAG = Log.tag(EditProfileFragment.class);
|
||||
|
||||
private AlertDialog avatarProgress;
|
||||
private ManageProfileViewModel viewModel;
|
||||
private EditProfileFragmentBinding binding;
|
||||
private LifecycleDisposable disposables;
|
||||
|
||||
@Override
|
||||
public @Nullable View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
binding = EditProfileFragmentBinding.inflate(inflater, container, false);
|
||||
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
@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();
|
||||
});
|
||||
|
||||
UsernameShareBottomSheet.ResultContract.INSTANCE.registerForResult(getParentFragmentManager(), getViewLifecycleOwner(), isCopiedToClipboard -> {
|
||||
Snackbar.make(view, R.string.ManageProfileFragment__username_copied, Snackbar.LENGTH_SHORT).show();
|
||||
});
|
||||
|
||||
initializeViewModel();
|
||||
|
||||
binding.toolbar.setNavigationOnClickListener(v -> requireActivity().finish());
|
||||
|
||||
binding.manageProfileEditPhoto.setOnClickListener(v -> onEditAvatarClicked());
|
||||
|
||||
binding.manageProfileNameContainer.setOnClickListener(v -> {
|
||||
SafeNavigation.safeNavigate(Navigation.findNavController(v), EditProfileFragmentDirections.actionManageProfileName());
|
||||
});
|
||||
|
||||
binding.manageProfileUsernameContainer.setOnClickListener(v -> {
|
||||
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), EditProfileFragmentDirections.actionManageUsername());
|
||||
break;
|
||||
case 1:
|
||||
displayConfirmUsernameDeletionDialog();
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
})
|
||||
.show();
|
||||
} else {
|
||||
SafeNavigation.safeNavigate(Navigation.findNavController(v), EditProfileFragmentDirections.actionManageUsername());
|
||||
}
|
||||
} else {
|
||||
SafeNavigation.safeNavigate(Navigation.findNavController(v), EditProfileFragmentDirections.actionManageProfileFragmentToUsernameEducationFragment());
|
||||
}
|
||||
});
|
||||
|
||||
binding.manageProfileAboutContainer.setOnClickListener(v -> {
|
||||
SafeNavigation.safeNavigate(Navigation.findNavController(v), EditProfileFragmentDirections.actionManageAbout());
|
||||
});
|
||||
|
||||
getParentFragmentManager().setFragmentResultListener(AvatarPickerFragment.REQUEST_KEY_SELECT_AVATAR, getViewLifecycleOwner(), (key, bundle) -> {
|
||||
if (bundle.getBoolean(AvatarPickerFragment.SELECT_AVATAR_CLEAR)) {
|
||||
viewModel.onAvatarSelected(requireContext(), null);
|
||||
} else {
|
||||
Media result = bundle.getParcelable(AvatarPickerFragment.SELECT_AVATAR_MEDIA);
|
||||
viewModel.onAvatarSelected(requireContext(), result);
|
||||
}
|
||||
});
|
||||
|
||||
EmojiTextView avatarInitials = binding.manageProfileAvatarInitials;
|
||||
avatarInitials.addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
|
||||
if (avatarInitials.length() > 0) {
|
||||
updateInitials(avatarInitials.getText().toString());
|
||||
}
|
||||
});
|
||||
|
||||
binding.manageProfileBadgesContainer.setOnClickListener(v -> {
|
||||
if (Recipient.self().getBadges().isEmpty()) {
|
||||
BecomeASustainerFragment.show(getParentFragmentManager());
|
||||
} else {
|
||||
SafeNavigation.safeNavigate(Navigation.findNavController(v), EditProfileFragmentDirections.actionManageProfileFragmentToBadgeManageFragment());
|
||||
}
|
||||
});
|
||||
|
||||
binding.manageProfileAvatar.setOnClickListener(v -> {
|
||||
startActivity(AvatarPreviewActivity.intentFromRecipientId(requireContext(), Recipient.self().getId()),
|
||||
AvatarPreviewActivity.createTransitionBundle(requireActivity(), binding.manageProfileAvatar));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
binding = null;
|
||||
}
|
||||
|
||||
private void initializeViewModel() {
|
||||
viewModel = new ViewModelProvider(this, new ManageProfileViewModel.Factory()).get(ManageProfileViewModel.class);
|
||||
|
||||
LiveData<Optional<byte[]>> avatarImage = Transformations.map(LiveDataUtil.distinctUntilChanged(viewModel.getAvatar(), (b1, b2) -> Arrays.equals(b1.getAvatar(), b2.getAvatar())),
|
||||
b -> Optional.ofNullable(b.getAvatar()));
|
||||
avatarImage.observe(getViewLifecycleOwner(), this::presentAvatarImage);
|
||||
|
||||
viewModel.getAvatar().observe(getViewLifecycleOwner(), this::presentAvatarPlaceholder);
|
||||
viewModel.getProfileName().observe(getViewLifecycleOwner(), this::presentProfileName);
|
||||
viewModel.getEvents().observe(getViewLifecycleOwner(), this::presentEvent);
|
||||
viewModel.getAbout().observe(getViewLifecycleOwner(), this::presentAbout);
|
||||
viewModel.getAboutEmoji().observe(getViewLifecycleOwner(), this::presentAboutEmoji);
|
||||
viewModel.getBadge().observe(getViewLifecycleOwner(), this::presentBadge);
|
||||
|
||||
if (viewModel.shouldShowUsername()) {
|
||||
viewModel.getUsername().observe(getViewLifecycleOwner(), this::presentUsername);
|
||||
} else {
|
||||
binding.manageProfileUsernameContainer.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
private void presentAvatarImage(@NonNull Optional<byte[]> avatarData) {
|
||||
if (avatarData.isPresent()) {
|
||||
Glide.with(this)
|
||||
.load(avatarData.get())
|
||||
.circleCrop()
|
||||
.into(binding.manageProfileAvatar);
|
||||
} else {
|
||||
Glide.with(this).load((Drawable) null).into(binding.manageProfileAvatar);
|
||||
}
|
||||
}
|
||||
|
||||
private void presentAvatarPlaceholder(@NonNull AvatarState avatarState) {
|
||||
if (avatarState.getAvatar() == null) {
|
||||
CharSequence initials = NameUtil.getAbbreviation(avatarState.getSelf().getDisplayName(requireContext()));
|
||||
Avatars.ForegroundColor foregroundColor = Avatars.getForegroundColor(avatarState.getSelf().getAvatarColor());
|
||||
|
||||
binding.manageProfileAvatarBackground.setColorFilter(new SimpleColorFilter(avatarState.getSelf().getAvatarColor().colorInt()));
|
||||
binding.manageProfileAvatarPlaceholder.setColorFilter(new SimpleColorFilter(foregroundColor.getColorInt()));
|
||||
binding.manageProfileAvatarInitials.setTextColor(foregroundColor.getColorInt());
|
||||
|
||||
if (TextUtils.isEmpty(initials)) {
|
||||
binding.manageProfileAvatarPlaceholder.setVisibility(View.VISIBLE);
|
||||
binding.manageProfileAvatarInitials.setVisibility(View.GONE);
|
||||
} else {
|
||||
updateInitials(initials.toString());
|
||||
binding.manageProfileAvatarPlaceholder.setVisibility(View.GONE);
|
||||
binding.manageProfileAvatarInitials.setVisibility(View.VISIBLE);
|
||||
}
|
||||
} else {
|
||||
binding.manageProfileAvatarPlaceholder.setVisibility(View.GONE);
|
||||
binding.manageProfileAvatarInitials.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (avatarProgress == null && avatarState.getLoadingState() == ManageProfileViewModel.LoadingState.LOADING) {
|
||||
avatarProgress = SimpleProgressDialog.show(requireContext());
|
||||
} else if (avatarProgress != null && avatarState.getLoadingState() == ManageProfileViewModel.LoadingState.LOADED) {
|
||||
avatarProgress.dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateInitials(String initials) {
|
||||
binding.manageProfileAvatarInitials.setTextSize(TypedValue.COMPLEX_UNIT_PX,
|
||||
Avatars.getTextSizeForLength(requireContext(),
|
||||
initials,
|
||||
binding.manageProfileAvatarInitials.getMeasuredWidth() * 0.8f,
|
||||
binding.manageProfileAvatarInitials.getMeasuredWidth() * 0.45f));
|
||||
binding.manageProfileAvatarInitials.setText(initials);
|
||||
}
|
||||
|
||||
private void presentProfileName(@Nullable ProfileName profileName) {
|
||||
if (profileName == null || profileName.isEmpty()) {
|
||||
binding.manageProfileName.setText(R.string.ManageProfileFragment_profile_name);
|
||||
} else {
|
||||
binding.manageProfileName.setText(profileName.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private void presentUsername(@Nullable String username) {
|
||||
if (username == null || username.isEmpty()) {
|
||||
binding.manageProfileUsername.setText(R.string.ManageProfileFragment_username);
|
||||
} else {
|
||||
binding.manageProfileUsername.setText(username);
|
||||
}
|
||||
}
|
||||
|
||||
private void presentAbout(@Nullable String about) {
|
||||
if (about == null || about.isEmpty()) {
|
||||
binding.manageProfileAbout.setText(R.string.ManageProfileFragment_about);
|
||||
} else {
|
||||
binding.manageProfileAbout.setText(about);
|
||||
}
|
||||
}
|
||||
|
||||
private void presentAboutEmoji(@NonNull String aboutEmoji) {
|
||||
if (aboutEmoji == null || aboutEmoji.isEmpty()) {
|
||||
binding.manageProfileAboutIcon.setImageDrawable(ResourcesCompat.getDrawable(getResources(), R.drawable.symbol_edit_24, null));
|
||||
} else {
|
||||
Drawable emoji = EmojiUtil.convertToDrawable(requireContext(), aboutEmoji);
|
||||
|
||||
if (emoji != null) {
|
||||
binding.manageProfileAboutIcon.setImageDrawable(emoji);
|
||||
} else {
|
||||
binding.manageProfileAboutIcon.setImageDrawable(ResourcesCompat.getDrawable(getResources(), R.drawable.symbol_edit_24, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void presentBadge(@NonNull Optional<Badge> badge) {
|
||||
if (badge.isPresent() && badge.get().getVisible() && !badge.get().isExpired()) {
|
||||
binding.manageProfileBadge.setBadge(badge.orElse(null));
|
||||
} else {
|
||||
binding.manageProfileBadge.setBadge(null);
|
||||
}
|
||||
}
|
||||
|
||||
private void presentEvent(@NonNull ManageProfileViewModel.Event event) {
|
||||
switch (event) {
|
||||
case AVATAR_DISK_FAILURE:
|
||||
Toast.makeText(requireContext(), R.string.ManageProfileFragment_failed_to_set_avatar, Toast.LENGTH_LONG).show();
|
||||
break;
|
||||
case AVATAR_NETWORK_FAILURE:
|
||||
Toast.makeText(requireContext(), R.string.EditProfileNameFragment_failed_to_save_due_to_network_issues_try_again_later, Toast.LENGTH_LONG).show();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void onEditAvatarClicked() {
|
||||
SafeNavigation.safeNavigate(Navigation.findNavController(requireView()), EditProfileFragmentDirections.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 UsernameRepository.UsernameDeleteResult usernameDeleteResult) {
|
||||
switch (usernameDeleteResult) {
|
||||
case SUCCESS:
|
||||
Snackbar.make(requireView(), R.string.ManageProfileFragment__username_deleted, Snackbar.LENGTH_SHORT).show();
|
||||
break;
|
||||
case NETWORK_ERROR:
|
||||
Snackbar.make(requireView(), R.string.ManageProfileFragment__couldnt_delete_username, Snackbar.LENGTH_SHORT).show();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,291 @@
|
|||
package org.thoughtcrime.securesms.profiles.manage
|
||||
|
||||
import android.content.DialogInterface
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.Bundle
|
||||
import android.text.TextUtils
|
||||
import android.util.TypedValue
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.map
|
||||
import androidx.navigation.Navigation.findNavController
|
||||
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.concurrent.LifecycleDisposable
|
||||
import org.thoughtcrime.securesms.AvatarPreviewActivity
|
||||
import org.thoughtcrime.securesms.LoggingFragment
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.avatar.Avatars.getForegroundColor
|
||||
import org.thoughtcrime.securesms.avatar.Avatars.getTextSizeForLength
|
||||
import org.thoughtcrime.securesms.avatar.picker.AvatarPickerFragment
|
||||
import org.thoughtcrime.securesms.badges.models.Badge
|
||||
import org.thoughtcrime.securesms.badges.self.none.BecomeASustainerFragment.Companion.show
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiUtil
|
||||
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.UsernameRepository.UsernameDeleteResult
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.util.NameUtil.getAbbreviation
|
||||
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil
|
||||
import org.thoughtcrime.securesms.util.navigation.safeNavigate
|
||||
import org.thoughtcrime.securesms.util.views.SimpleProgressDialog
|
||||
import java.util.Arrays
|
||||
import java.util.Optional
|
||||
|
||||
/**
|
||||
* Fragment for editing your profile after you're already registered.
|
||||
*/
|
||||
class EditProfileFragment : LoggingFragment() {
|
||||
|
||||
private var avatarProgress: AlertDialog? = null
|
||||
|
||||
private lateinit var viewModel: ManageProfileViewModel
|
||||
private lateinit var binding: EditProfileFragmentBinding
|
||||
private lateinit var disposables: LifecycleDisposable
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
binding = EditProfileFragmentBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
disposables = LifecycleDisposable()
|
||||
disposables.bindTo(viewLifecycleOwner)
|
||||
|
||||
UsernameEditFragment.ResultContract().registerForResult(parentFragmentManager, viewLifecycleOwner) {
|
||||
Snackbar.make(view, R.string.ManageProfileFragment__username_created, Snackbar.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
UsernameShareBottomSheet.ResultContract.registerForResult(parentFragmentManager, viewLifecycleOwner) {
|
||||
Snackbar.make(view, R.string.ManageProfileFragment__username_copied, Snackbar.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
initializeViewModel()
|
||||
|
||||
binding.toolbar.setNavigationOnClickListener { requireActivity().finish() }
|
||||
binding.manageProfileEditPhoto.setOnClickListener { onEditAvatarClicked() }
|
||||
binding.manageProfileNameContainer.setOnClickListener { v: View -> findNavController(v).safeNavigate(EditProfileFragmentDirections.actionManageProfileName()) }
|
||||
|
||||
binding.manageProfileUsernameContainer.setOnClickListener { v: View ->
|
||||
if (SignalStore.uiHints().hasSeenUsernameEducation()) {
|
||||
if (SignalStore.account().username != null) {
|
||||
MaterialAlertDialogBuilder(requireContext(), R.style.ThemeOverlay_Signal_MaterialAlertDialog_List)
|
||||
.setItems(R.array.username_edit_entries) { _: DialogInterface?, w: Int ->
|
||||
when (w) {
|
||||
0 -> findNavController(v).safeNavigate(EditProfileFragmentDirections.actionManageUsername())
|
||||
1 -> displayConfirmUsernameDeletionDialog()
|
||||
else -> throw IllegalStateException()
|
||||
}
|
||||
}
|
||||
.show()
|
||||
} else {
|
||||
findNavController(v).safeNavigate(EditProfileFragmentDirections.actionManageUsername())
|
||||
}
|
||||
} else {
|
||||
findNavController(v).safeNavigate(EditProfileFragmentDirections.actionManageProfileFragmentToUsernameEducationFragment())
|
||||
}
|
||||
}
|
||||
|
||||
binding.manageProfileAboutContainer.setOnClickListener { v: View -> findNavController(v).safeNavigate(EditProfileFragmentDirections.actionManageAbout()) }
|
||||
|
||||
parentFragmentManager.setFragmentResultListener(AvatarPickerFragment.REQUEST_KEY_SELECT_AVATAR, viewLifecycleOwner) { _: String?, bundle: Bundle ->
|
||||
if (bundle.getBoolean(AvatarPickerFragment.SELECT_AVATAR_CLEAR)) {
|
||||
viewModel.onAvatarSelected(requireContext(), null)
|
||||
} else {
|
||||
val result = bundle.getParcelable<Media>(AvatarPickerFragment.SELECT_AVATAR_MEDIA)
|
||||
viewModel.onAvatarSelected(requireContext(), result)
|
||||
}
|
||||
}
|
||||
|
||||
val avatarInitials = binding.manageProfileAvatarInitials
|
||||
avatarInitials.addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ ->
|
||||
if (avatarInitials.length() > 0) {
|
||||
updateInitials(avatarInitials.text.toString())
|
||||
}
|
||||
}
|
||||
|
||||
binding.manageProfileBadgesContainer.setOnClickListener { v: View ->
|
||||
if (Recipient.self().badges.isEmpty()) {
|
||||
show(parentFragmentManager)
|
||||
} else {
|
||||
findNavController(v).safeNavigate(EditProfileFragmentDirections.actionManageProfileFragmentToBadgeManageFragment())
|
||||
}
|
||||
}
|
||||
|
||||
binding.manageProfileAvatar.setOnClickListener {
|
||||
startActivity(
|
||||
AvatarPreviewActivity.intentFromRecipientId(requireContext(), Recipient.self().id),
|
||||
AvatarPreviewActivity.createTransitionBundle(requireActivity(), binding.manageProfileAvatar)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun initializeViewModel() {
|
||||
viewModel = ViewModelProvider(this, ManageProfileViewModel.Factory()).get(ManageProfileViewModel::class.java)
|
||||
|
||||
LiveDataUtil
|
||||
.distinctUntilChanged(viewModel.avatar) { b1, b2 -> Arrays.equals(b1.avatar, b2.avatar) }
|
||||
.map { avatarState -> Optional.ofNullable(avatarState.avatar) }
|
||||
.observe(viewLifecycleOwner) { avatarData -> presentAvatarImage(avatarData) }
|
||||
|
||||
viewModel.avatar.observe(viewLifecycleOwner) { presentAvatarPlaceholder(it) }
|
||||
viewModel.profileName.observe(viewLifecycleOwner) { presentProfileName(it) }
|
||||
viewModel.events.observe(viewLifecycleOwner) { presentEvent(it) }
|
||||
viewModel.about.observe(viewLifecycleOwner) { presentAbout(it) }
|
||||
viewModel.aboutEmoji.observe(viewLifecycleOwner) { presentAboutEmoji(it) }
|
||||
viewModel.badge.observe(viewLifecycleOwner) { presentBadge(it) }
|
||||
|
||||
if (viewModel.shouldShowUsername()) {
|
||||
viewModel.username.observe(viewLifecycleOwner) { presentUsername(it) }
|
||||
} else {
|
||||
binding.manageProfileUsernameContainer.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
private fun presentAvatarImage(avatarData: Optional<ByteArray>) {
|
||||
if (avatarData.isPresent) {
|
||||
Glide.with(this)
|
||||
.load(avatarData.get())
|
||||
.circleCrop()
|
||||
.into(binding.manageProfileAvatar)
|
||||
} else {
|
||||
Glide.with(this).load(null as Drawable?).into(binding.manageProfileAvatar)
|
||||
}
|
||||
}
|
||||
|
||||
private fun presentAvatarPlaceholder(avatarState: AvatarState) {
|
||||
if (avatarState.avatar == null) {
|
||||
val initials: CharSequence? = getAbbreviation(avatarState.self.getDisplayName(requireContext()))
|
||||
val foregroundColor = getForegroundColor(avatarState.self.avatarColor)
|
||||
|
||||
binding.manageProfileAvatarBackground.colorFilter = SimpleColorFilter(avatarState.self.avatarColor.colorInt())
|
||||
binding.manageProfileAvatarPlaceholder.colorFilter = SimpleColorFilter(foregroundColor.colorInt)
|
||||
binding.manageProfileAvatarInitials.setTextColor(foregroundColor.colorInt)
|
||||
|
||||
if (TextUtils.isEmpty(initials)) {
|
||||
binding.manageProfileAvatarPlaceholder.visibility = View.VISIBLE
|
||||
binding.manageProfileAvatarInitials.visibility = View.GONE
|
||||
} else {
|
||||
updateInitials(initials.toString())
|
||||
binding.manageProfileAvatarPlaceholder.visibility = View.GONE
|
||||
binding.manageProfileAvatarInitials.visibility = View.VISIBLE
|
||||
}
|
||||
} else {
|
||||
binding.manageProfileAvatarPlaceholder.visibility = View.GONE
|
||||
binding.manageProfileAvatarInitials.visibility = View.GONE
|
||||
}
|
||||
|
||||
if (avatarProgress == null && avatarState.loadingState == ManageProfileViewModel.LoadingState.LOADING) {
|
||||
avatarProgress = SimpleProgressDialog.show(requireContext())
|
||||
} else if (avatarProgress != null && avatarState.loadingState == ManageProfileViewModel.LoadingState.LOADED) {
|
||||
avatarProgress!!.dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateInitials(initials: String) {
|
||||
binding.manageProfileAvatarInitials.setTextSize(
|
||||
TypedValue.COMPLEX_UNIT_PX,
|
||||
getTextSizeForLength(
|
||||
context = requireContext(),
|
||||
text = initials,
|
||||
maxWidth = binding.manageProfileAvatarInitials.measuredWidth * 0.8f,
|
||||
maxSize = binding.manageProfileAvatarInitials.measuredWidth * 0.45f
|
||||
)
|
||||
)
|
||||
|
||||
binding.manageProfileAvatarInitials.text = initials
|
||||
}
|
||||
|
||||
private fun presentProfileName(profileName: ProfileName?) {
|
||||
if (profileName == null || profileName.isEmpty) {
|
||||
binding.manageProfileName.setText(R.string.ManageProfileFragment_profile_name)
|
||||
} else {
|
||||
binding.manageProfileName.text = profileName.toString()
|
||||
}
|
||||
}
|
||||
|
||||
private fun presentUsername(username: String?) {
|
||||
if (username.isNullOrEmpty()) {
|
||||
binding.manageProfileUsername.setText(R.string.ManageProfileFragment_username)
|
||||
} else {
|
||||
binding.manageProfileUsername.text = username
|
||||
}
|
||||
}
|
||||
|
||||
private fun presentAbout(about: String?) {
|
||||
if (about.isNullOrEmpty()) {
|
||||
binding.manageProfileAbout.setText(R.string.ManageProfileFragment_about)
|
||||
} else {
|
||||
binding.manageProfileAbout.text = about
|
||||
}
|
||||
}
|
||||
|
||||
private fun presentAboutEmoji(aboutEmoji: String?) {
|
||||
if (aboutEmoji.isNullOrEmpty()) {
|
||||
binding.manageProfileAboutIcon.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.symbol_edit_24, null))
|
||||
} else {
|
||||
val emoji = EmojiUtil.convertToDrawable(requireContext(), aboutEmoji)
|
||||
if (emoji != null) {
|
||||
binding.manageProfileAboutIcon.setImageDrawable(emoji)
|
||||
} else {
|
||||
binding.manageProfileAboutIcon.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.symbol_edit_24, null))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun presentBadge(badge: Optional<Badge>) {
|
||||
if (badge.isPresent && badge.get().visible && !badge.get().isExpired()) {
|
||||
binding.manageProfileBadge.setBadge(badge.orElse(null))
|
||||
} else {
|
||||
binding.manageProfileBadge.setBadge(null)
|
||||
}
|
||||
}
|
||||
|
||||
private fun presentEvent(event: ManageProfileViewModel.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()
|
||||
}
|
||||
}
|
||||
|
||||
private fun onEditAvatarClicked() {
|
||||
findNavController(requireView()).safeNavigate(EditProfileFragmentDirections.actionManageProfileFragmentToAvatarPicker(null, null))
|
||||
}
|
||||
|
||||
private fun displayConfirmUsernameDeletionDialog() {
|
||||
MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(R.string.ManageProfileFragment__delete_username_dialog_title)
|
||||
.setMessage(requireContext().getString(R.string.ManageProfileFragment__delete_username_dialog_body, SignalStore.account().username))
|
||||
.setPositiveButton(R.string.delete) { _, _ -> onUserConfirmedUsernameDeletion() }
|
||||
.setNegativeButton(android.R.string.cancel) { d: DialogInterface?, w: Int -> }
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun onUserConfirmedUsernameDeletion() {
|
||||
binding.progressCard.visibility = View.VISIBLE
|
||||
|
||||
disposables += viewModel
|
||||
.deleteUsername()
|
||||
.subscribe { result: UsernameDeleteResult ->
|
||||
binding.progressCard.visibility = View.GONE
|
||||
handleUsernameDeletionResult(result)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleUsernameDeletionResult(usernameDeleteResult: UsernameDeleteResult) {
|
||||
when (usernameDeleteResult) {
|
||||
UsernameDeleteResult.SUCCESS -> Snackbar.make(requireView(), R.string.ManageProfileFragment__username_deleted, Snackbar.LENGTH_SHORT).show()
|
||||
UsernameDeleteResult.NETWORK_ERROR -> Snackbar.make(requireView(), R.string.ManageProfileFragment__couldnt_delete_username, Snackbar.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,7 +14,6 @@ import org.signal.core.util.Result
|
|||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.profiles.manage.UsernameRepository.UsernameDeleteResult
|
||||
import org.thoughtcrime.securesms.profiles.manage.UsernameRepository.UsernameSetResult
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.util.UsernameUtil.InvalidReason
|
||||
import org.thoughtcrime.securesms.util.UsernameUtil.checkUsername
|
||||
import org.thoughtcrime.securesms.util.rx.RxStore
|
||||
|
@ -41,7 +40,7 @@ internal class UsernameEditViewModel private constructor(private val isInRegistr
|
|||
defaultValue = State(
|
||||
buttonState = ButtonState.SUBMIT_DISABLED,
|
||||
usernameStatus = UsernameStatus.NONE,
|
||||
username = Recipient.self().username.map<UsernameState> { UsernameState.Set(it) }.orElse(UsernameState.NoUsername)
|
||||
username = SignalStore.account().username?.let { UsernameState.Set(it) } ?: UsernameState.NoUsername
|
||||
),
|
||||
scheduler = Schedulers.computation()
|
||||
)
|
||||
|
@ -60,7 +59,7 @@ internal class UsernameEditViewModel private constructor(private val isInRegistr
|
|||
|
||||
fun onNicknameUpdated(nickname: String) {
|
||||
uiState.update { state: State ->
|
||||
if (nickname.isBlank() && Recipient.self().username.isPresent) {
|
||||
if (nickname.isBlank() && SignalStore.account().username != null) {
|
||||
return@update State(
|
||||
buttonState = if (isInRegistration) ButtonState.SUBMIT_DISABLED else ButtonState.DELETE,
|
||||
usernameStatus = UsernameStatus.NONE,
|
||||
|
@ -102,7 +101,7 @@ internal class UsernameEditViewModel private constructor(private val isInRegistr
|
|||
return
|
||||
}
|
||||
|
||||
if (usernameState.username == Recipient.self().username.orElse(null)) {
|
||||
if (usernameState.username == SignalStore.account().username) {
|
||||
uiState.update { State(ButtonState.SUBMIT_DISABLED, UsernameStatus.NONE, it.username) }
|
||||
return
|
||||
}
|
||||
|
|
|
@ -993,6 +993,8 @@
|
|||
<string name="ManageProfileFragment_about">About</string>
|
||||
<string name="ManageProfileFragment_failed_to_set_avatar">Failed to set avatar</string>
|
||||
<string name="ManageProfileFragment_badges">Badges</string>
|
||||
<!-- 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>
|
||||
<!-- Snackbar message after creating username -->
|
||||
<string name="ManageProfileFragment__username_created">Username created</string>
|
||||
|
@ -1002,6 +1004,10 @@
|
|||
<string name="ManageProfileFragment__couldnt_delete_username">Couldn\'t delete username. Try again later.</string>
|
||||
<!-- Snackbar message after successful deletion of username -->
|
||||
<string name="ManageProfileFragment__username_deleted">Username deleted</string>
|
||||
<!-- The title of a pop-up dialog asking the user to confirm deleting their username -->
|
||||
<string name="ManageProfileFragment__delete_username_dialog_title">Delete username?</string>
|
||||
<!-- The body of a pop-up dialog asking the user to confirm deleting their username -->
|
||||
<string name="ManageProfileFragment__delete_username_dialog_body">This will remove your username and disable your QR code and link. "%1$s" will be available for others to claim. Are you sure?</string>
|
||||
|
||||
<!-- UsernameOutOfSyncReminder -->
|
||||
<!-- Displayed above the conversation list when a user needs to address an issue with their username -->
|
||||
|
|
Loading…
Add table
Reference in a new issue