kopia lustrzana https://github.com/ryukoposting/Signal-Android
Username UX refresh.
rodzic
3252871ed5
commit
28310a88f5
|
@ -12,14 +12,12 @@ import android.view.View;
|
||||||
import android.view.ViewAnimationUtils;
|
import android.view.ViewAnimationUtils;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.TextView;
|
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.RequiresApi;
|
import androidx.annotation.RequiresApi;
|
||||||
import androidx.appcompat.widget.Toolbar;
|
import androidx.core.content.ContextCompat;
|
||||||
import androidx.lifecycle.ViewModelProviders;
|
import androidx.lifecycle.ViewModelProviders;
|
||||||
import androidx.navigation.Navigation;
|
import androidx.navigation.Navigation;
|
||||||
|
|
||||||
|
@ -28,11 +26,13 @@ import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||||
|
|
||||||
import org.signal.core.util.EditTextUtil;
|
import org.signal.core.util.EditTextUtil;
|
||||||
import org.signal.core.util.StreamUtil;
|
import org.signal.core.util.StreamUtil;
|
||||||
|
import org.signal.core.util.concurrent.SimpleTask;
|
||||||
import org.signal.core.util.logging.Log;
|
import org.signal.core.util.logging.Log;
|
||||||
import org.thoughtcrime.securesms.LoggingFragment;
|
import org.thoughtcrime.securesms.LoggingFragment;
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
import org.thoughtcrime.securesms.avatar.Avatars;
|
import org.thoughtcrime.securesms.avatar.Avatars;
|
||||||
import org.thoughtcrime.securesms.avatar.picker.AvatarPickerFragment;
|
import org.thoughtcrime.securesms.avatar.picker.AvatarPickerFragment;
|
||||||
|
import org.thoughtcrime.securesms.databinding.ProfileCreateFragmentBinding;
|
||||||
import org.thoughtcrime.securesms.groups.GroupId;
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
import org.thoughtcrime.securesms.groups.ParcelableGroupId;
|
import org.thoughtcrime.securesms.groups.ParcelableGroupId;
|
||||||
import org.thoughtcrime.securesms.mediasend.Media;
|
import org.thoughtcrime.securesms.mediasend.Media;
|
||||||
|
@ -41,11 +41,8 @@ import org.thoughtcrime.securesms.profiles.manage.EditProfileNameFragment;
|
||||||
import org.thoughtcrime.securesms.providers.BlobProvider;
|
import org.thoughtcrime.securesms.providers.BlobProvider;
|
||||||
import org.thoughtcrime.securesms.util.CommunicationActions;
|
import org.thoughtcrime.securesms.util.CommunicationActions;
|
||||||
import org.thoughtcrime.securesms.util.FeatureFlags;
|
import org.thoughtcrime.securesms.util.FeatureFlags;
|
||||||
import org.signal.core.util.concurrent.SimpleTask;
|
|
||||||
import org.thoughtcrime.securesms.util.navigation.SafeNavigation;
|
import org.thoughtcrime.securesms.util.navigation.SafeNavigation;
|
||||||
import org.thoughtcrime.securesms.util.text.AfterTextChanged;
|
import org.thoughtcrime.securesms.util.text.AfterTextChanged;
|
||||||
import org.thoughtcrime.securesms.util.views.CircularProgressMaterialButton;
|
|
||||||
import org.thoughtcrime.securesms.util.views.LearnMoreTextView;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
@ -62,20 +59,10 @@ public class EditProfileFragment extends LoggingFragment {
|
||||||
private static final int MAX_DESCRIPTION_GLYPHS = 480;
|
private static final int MAX_DESCRIPTION_GLYPHS = 480;
|
||||||
private static final int MAX_DESCRIPTION_BYTES = 8192;
|
private static final int MAX_DESCRIPTION_BYTES = 8192;
|
||||||
|
|
||||||
private Toolbar toolbar;
|
|
||||||
private View title;
|
|
||||||
private ImageView avatar;
|
|
||||||
private CircularProgressMaterialButton finishButton;
|
|
||||||
private EditText givenName;
|
|
||||||
private EditText familyName;
|
|
||||||
private View reveal;
|
|
||||||
private TextView preview;
|
|
||||||
private ImageView avatarPreviewBackground;
|
|
||||||
private ImageView avatarPreview;
|
|
||||||
|
|
||||||
private Intent nextIntent;
|
private Intent nextIntent;
|
||||||
|
|
||||||
private EditProfileViewModel viewModel;
|
private EditProfileViewModel viewModel;
|
||||||
|
private ProfileCreateFragmentBinding binding;
|
||||||
|
|
||||||
private Controller controller;
|
private Controller controller;
|
||||||
|
|
||||||
|
@ -92,7 +79,8 @@ public class EditProfileFragment extends LoggingFragment {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Nullable View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
public @Nullable View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||||
return inflater.inflate(R.layout.profile_create_fragment, container, false);
|
binding = ProfileCreateFragmentBinding.inflate(inflater, container, false);
|
||||||
|
return binding.getRoot();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -108,7 +96,7 @@ public class EditProfileFragment extends LoggingFragment {
|
||||||
if (bundle.getBoolean(AvatarPickerFragment.SELECT_AVATAR_CLEAR)) {
|
if (bundle.getBoolean(AvatarPickerFragment.SELECT_AVATAR_CLEAR)) {
|
||||||
viewModel.setAvatarMedia(null);
|
viewModel.setAvatarMedia(null);
|
||||||
viewModel.setAvatar(null);
|
viewModel.setAvatar(null);
|
||||||
avatar.setImageDrawable(null);
|
binding.avatar.setImageDrawable(null);
|
||||||
} else {
|
} else {
|
||||||
Media media = bundle.getParcelable(AvatarPickerFragment.SELECT_AVATAR_MEDIA);
|
Media media = bundle.getParcelable(AvatarPickerFragment.SELECT_AVATAR_MEDIA);
|
||||||
handleMediaFromResult(media);
|
handleMediaFromResult(media);
|
||||||
|
@ -116,6 +104,12 @@ public class EditProfileFragment extends LoggingFragment {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroyView() {
|
||||||
|
super.onDestroyView();
|
||||||
|
binding = null;
|
||||||
|
}
|
||||||
|
|
||||||
private void handleMediaFromResult(@NonNull Media media) {
|
private void handleMediaFromResult(@NonNull Media media) {
|
||||||
SimpleTask.run(() -> {
|
SimpleTask.run(() -> {
|
||||||
try {
|
try {
|
||||||
|
@ -136,7 +130,7 @@ public class EditProfileFragment extends LoggingFragment {
|
||||||
.skipMemoryCache(true)
|
.skipMemoryCache(true)
|
||||||
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
||||||
.circleCrop()
|
.circleCrop()
|
||||||
.into(avatar);
|
.into(binding.avatar);
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(requireActivity(), R.string.CreateProfileActivity_error_setting_profile_photo, Toast.LENGTH_LONG).show();
|
Toast.makeText(requireActivity(), R.string.CreateProfileActivity_error_setting_profile_photo, Toast.LENGTH_LONG).show();
|
||||||
}
|
}
|
||||||
|
@ -162,111 +156,108 @@ public class EditProfileFragment extends LoggingFragment {
|
||||||
Bundle arguments = requireArguments();
|
Bundle arguments = requireArguments();
|
||||||
boolean isEditingGroup = groupId != null;
|
boolean isEditingGroup = groupId != null;
|
||||||
|
|
||||||
this.toolbar = view.findViewById(R.id.toolbar);
|
this.nextIntent = arguments.getParcelable(NEXT_INTENT);
|
||||||
this.title = view.findViewById(R.id.title);
|
|
||||||
this.avatar = view.findViewById(R.id.avatar);
|
|
||||||
this.givenName = view.findViewById(R.id.given_name);
|
|
||||||
this.familyName = view.findViewById(R.id.family_name);
|
|
||||||
this.finishButton = view.findViewById(R.id.finish_button);
|
|
||||||
this.reveal = view.findViewById(R.id.reveal);
|
|
||||||
this.preview = view.findViewById(R.id.name_preview);
|
|
||||||
this.avatarPreviewBackground = view.findViewById(R.id.avatar_background);
|
|
||||||
this.avatarPreview = view.findViewById(R.id.avatar_placeholder);
|
|
||||||
this.nextIntent = arguments.getParcelable(NEXT_INTENT);
|
|
||||||
|
|
||||||
this.avatar.setOnClickListener(v -> startAvatarSelection());
|
binding.avatar.setOnClickListener(v -> startAvatarSelection());
|
||||||
|
binding.mmsGroupHint.setVisibility(isEditingGroup && groupId.isMms() ? View.VISIBLE : View.GONE);
|
||||||
view.findViewById(R.id.mms_group_hint)
|
|
||||||
.setVisibility(isEditingGroup && groupId.isMms() ? View.VISIBLE : View.GONE);
|
|
||||||
|
|
||||||
if (isEditingGroup) {
|
if (isEditingGroup) {
|
||||||
EditTextUtil.addGraphemeClusterLimitFilter(givenName, FeatureFlags.getMaxGroupNameGraphemeLength());
|
EditTextUtil.addGraphemeClusterLimitFilter(binding.givenName, FeatureFlags.getMaxGroupNameGraphemeLength());
|
||||||
givenName.addTextChangedListener(new AfterTextChanged(s -> viewModel.setGivenName(s.toString())));
|
binding.profileDescriptionText.setVisibility(View.GONE);
|
||||||
givenName.setHint(R.string.EditProfileFragment__group_name);
|
binding.whoCanFindMeContainer.setVisibility(View.GONE);
|
||||||
givenName.requestFocus();
|
binding.givenName.addTextChangedListener(new AfterTextChanged(s -> viewModel.setGivenName(s.toString())));
|
||||||
toolbar.setTitle(R.string.EditProfileFragment__edit_group);
|
binding.givenNameWrapper.setHint(R.string.EditProfileFragment__group_name);
|
||||||
preview.setVisibility(View.GONE);
|
binding.givenName.requestFocus();
|
||||||
|
binding.toolbar.setTitle(R.string.EditProfileFragment__edit_group);
|
||||||
|
binding.namePreview.setVisibility(View.GONE);
|
||||||
|
|
||||||
if (groupId.isV2()) {
|
if (groupId.isV2()) {
|
||||||
EditTextUtil.addGraphemeClusterLimitFilter(familyName, MAX_DESCRIPTION_GLYPHS);
|
EditTextUtil.addGraphemeClusterLimitFilter(binding.familyName, MAX_DESCRIPTION_GLYPHS);
|
||||||
familyName.addTextChangedListener(new AfterTextChanged(s -> {
|
binding.familyName.addTextChangedListener(new AfterTextChanged(s -> {
|
||||||
EditProfileNameFragment.trimFieldToMaxByteLength(s, MAX_DESCRIPTION_BYTES);
|
EditProfileNameFragment.trimFieldToMaxByteLength(s, MAX_DESCRIPTION_BYTES);
|
||||||
viewModel.setFamilyName(s.toString());
|
viewModel.setFamilyName(s.toString());
|
||||||
}));
|
}));
|
||||||
familyName.setHint(R.string.EditProfileFragment__group_description);
|
binding.familyNameWrapper.setHint(R.string.EditProfileFragment__group_description);
|
||||||
familyName.setSingleLine(false);
|
binding.familyName.setSingleLine(false);
|
||||||
familyName.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES);
|
binding.familyName.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES);
|
||||||
|
|
||||||
LearnMoreTextView descriptionText = view.findViewById(R.id.description_text);
|
binding.groupDescriptionText.setLearnMoreVisible(false);
|
||||||
descriptionText.setLearnMoreVisible(false);
|
binding.groupDescriptionText.setText(R.string.CreateProfileActivity_group_descriptions_will_be_visible_to_members_of_this_group_and_people_who_have_been_invited);
|
||||||
descriptionText.setText(R.string.CreateProfileActivity_group_descriptions_will_be_visible_to_members_of_this_group_and_people_who_have_been_invited);
|
|
||||||
} else {
|
} else {
|
||||||
familyName.setVisibility(View.GONE);
|
binding.familyNameWrapper.setVisibility(View.GONE);
|
||||||
familyName.setEnabled(false);
|
binding.familyName.setEnabled(false);
|
||||||
view.findViewById(R.id.description_text).setVisibility(View.GONE);
|
binding.groupDescriptionText.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
view.<ImageView>findViewById(R.id.avatar_placeholder).setImageResource(R.drawable.ic_group_outline_40);
|
binding.avatarPlaceholder.setImageResource(R.drawable.ic_group_outline_40);
|
||||||
} else {
|
} else {
|
||||||
EditTextUtil.addGraphemeClusterLimitFilter(givenName, EditProfileNameFragment.NAME_MAX_GLYPHS);
|
EditTextUtil.addGraphemeClusterLimitFilter(binding.givenName, EditProfileNameFragment.NAME_MAX_GLYPHS);
|
||||||
EditTextUtil.addGraphemeClusterLimitFilter(familyName, EditProfileNameFragment.NAME_MAX_GLYPHS);
|
EditTextUtil.addGraphemeClusterLimitFilter(binding.familyName, EditProfileNameFragment.NAME_MAX_GLYPHS);
|
||||||
this.givenName.addTextChangedListener(new AfterTextChanged(s -> {
|
binding.givenName.addTextChangedListener(new AfterTextChanged(s -> {
|
||||||
EditProfileNameFragment.trimFieldToMaxByteLength(s);
|
EditProfileNameFragment.trimFieldToMaxByteLength(s);
|
||||||
viewModel.setGivenName(s.toString());
|
viewModel.setGivenName(s.toString());
|
||||||
}));
|
}));
|
||||||
this.familyName.addTextChangedListener(new AfterTextChanged(s -> {
|
binding.familyName.addTextChangedListener(new AfterTextChanged(s -> {
|
||||||
EditProfileNameFragment.trimFieldToMaxByteLength(s);
|
EditProfileNameFragment.trimFieldToMaxByteLength(s);
|
||||||
viewModel.setFamilyName(s.toString());
|
viewModel.setFamilyName(s.toString());
|
||||||
}));
|
}));
|
||||||
LearnMoreTextView descriptionText = view.findViewById(R.id.description_text);
|
binding.groupDescriptionText.setVisibility(View.GONE);
|
||||||
descriptionText.setLearnMoreVisible(true);
|
binding.profileDescriptionText.setLearnMoreVisible(true);
|
||||||
descriptionText.setOnLinkClickListener(v -> CommunicationActions.openBrowserLink(requireContext(), getString(R.string.EditProfileFragment__support_link)));
|
binding.profileDescriptionText.setLinkColor(ContextCompat.getColor(requireContext(), R.color.signal_colorPrimary));
|
||||||
|
binding.profileDescriptionText.setOnLinkClickListener(v -> CommunicationActions.openBrowserLink(requireContext(), getString(R.string.EditProfileFragment__support_link)));
|
||||||
|
|
||||||
|
if (FeatureFlags.phoneNumberPrivacy()) {
|
||||||
|
binding.whoCanFindMeContainer.setVisibility(View.VISIBLE);
|
||||||
|
binding.whoCanFindMeContainer.setOnClickListener(v -> SafeNavigation.safeNavigate(Navigation.findNavController(v), EditProfileFragmentDirections.actionCreateProfileFragmentToPhoneNumberPrivacy()));
|
||||||
|
// TODO [alex] -- Where does this value come from?
|
||||||
|
binding.whoCanFindMeDescription.setText(R.string.PhoneNumberPrivacy_everyone);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.finishButton.setOnClickListener(v -> {
|
binding.finishButton.setOnClickListener(v -> {
|
||||||
this.finishButton.setSpinning();
|
binding.finishButton.setSpinning();
|
||||||
handleUpload();
|
handleUpload();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.finishButton.setText(arguments.getInt(NEXT_BUTTON_TEXT, R.string.CreateProfileActivity_next));
|
binding.finishButton.setText(arguments.getInt(NEXT_BUTTON_TEXT, R.string.CreateProfileActivity_next));
|
||||||
|
|
||||||
if (arguments.getBoolean(SHOW_TOOLBAR, true)) {
|
if (arguments.getBoolean(SHOW_TOOLBAR, true)) {
|
||||||
this.toolbar.setVisibility(View.VISIBLE);
|
binding.toolbar.setVisibility(View.VISIBLE);
|
||||||
this.toolbar.setNavigationOnClickListener(v -> requireActivity().finish());
|
binding.toolbar.setNavigationOnClickListener(v -> requireActivity().finish());
|
||||||
this.title.setVisibility(View.GONE);
|
binding.title.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeProfileName() {
|
private void initializeProfileName() {
|
||||||
viewModel.isFormValid().observe(getViewLifecycleOwner(), isValid -> {
|
viewModel.isFormValid().observe(getViewLifecycleOwner(), isValid -> {
|
||||||
finishButton.setEnabled(isValid);
|
binding.finishButton.setEnabled(isValid);
|
||||||
finishButton.setAlpha(isValid ? 1f : 0.5f);
|
binding.finishButton.setAlpha(isValid ? 1f : 0.5f);
|
||||||
});
|
});
|
||||||
|
|
||||||
viewModel.givenName().observe(getViewLifecycleOwner(), givenName -> updateFieldIfNeeded(this.givenName, givenName));
|
viewModel.givenName().observe(getViewLifecycleOwner(), givenName -> updateFieldIfNeeded(binding.givenName, givenName));
|
||||||
|
|
||||||
viewModel.familyName().observe(getViewLifecycleOwner(), familyName -> updateFieldIfNeeded(this.familyName, familyName));
|
viewModel.familyName().observe(getViewLifecycleOwner(), familyName -> updateFieldIfNeeded(binding.familyName, familyName));
|
||||||
|
|
||||||
viewModel.profileName().observe(getViewLifecycleOwner(), profileName -> preview.setText(profileName.toString()));
|
viewModel.profileName().observe(getViewLifecycleOwner(), profileName -> binding.namePreview.setText(profileName.toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeProfileAvatar() {
|
private void initializeProfileAvatar() {
|
||||||
viewModel.avatar().observe(getViewLifecycleOwner(), bytes -> {
|
viewModel.avatar().observe(getViewLifecycleOwner(), bytes -> {
|
||||||
if (bytes == null) {
|
if (bytes == null) {
|
||||||
GlideApp.with(this).clear(avatar);
|
GlideApp.with(this).clear(binding.avatar);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
GlideApp.with(this)
|
GlideApp.with(this)
|
||||||
.load(bytes)
|
.load(bytes)
|
||||||
.circleCrop()
|
.circleCrop()
|
||||||
.into(avatar);
|
.into(binding.avatar);
|
||||||
});
|
});
|
||||||
|
|
||||||
viewModel.avatarColor().observe(getViewLifecycleOwner(), avatarColor -> {
|
viewModel.avatarColor().observe(getViewLifecycleOwner(), avatarColor -> {
|
||||||
Avatars.ForegroundColor foregroundColor = Avatars.getForegroundColor(avatarColor);
|
Avatars.ForegroundColor foregroundColor = Avatars.getForegroundColor(avatarColor);
|
||||||
|
|
||||||
avatarPreview.getDrawable().setColorFilter(new SimpleColorFilter(foregroundColor.getColorInt()));
|
binding.avatarPlaceholder.getDrawable().setColorFilter(new SimpleColorFilter(foregroundColor.getColorInt()));
|
||||||
avatarPreviewBackground.getDrawable().setColorFilter(new SimpleColorFilter(avatarColor.colorInt()));
|
binding.avatarBackground.getDrawable().setColorFilter(new SimpleColorFilter(avatarColor.colorInt()));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -312,7 +303,7 @@ public class EditProfileFragment extends LoggingFragment {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleFinishedLegacy() {
|
private void handleFinishedLegacy() {
|
||||||
finishButton.cancelSpinning();
|
binding.finishButton.cancelSpinning();
|
||||||
if (nextIntent != null) startActivity(nextIntent);
|
if (nextIntent != null) startActivity(nextIntent);
|
||||||
|
|
||||||
controller.onProfileNameUploadCompleted();
|
controller.onProfileNameUploadCompleted();
|
||||||
|
@ -323,16 +314,16 @@ public class EditProfileFragment extends LoggingFragment {
|
||||||
int[] finishButtonLocation = new int[2];
|
int[] finishButtonLocation = new int[2];
|
||||||
int[] revealLocation = new int[2];
|
int[] revealLocation = new int[2];
|
||||||
|
|
||||||
finishButton.getLocationInWindow(finishButtonLocation);
|
binding.finishButton.getLocationInWindow(finishButtonLocation);
|
||||||
reveal.getLocationInWindow(revealLocation);
|
binding.reveal.getLocationInWindow(revealLocation);
|
||||||
|
|
||||||
int finishX = finishButtonLocation[0] - revealLocation[0];
|
int finishX = finishButtonLocation[0] - revealLocation[0];
|
||||||
int finishY = finishButtonLocation[1] - revealLocation[1];
|
int finishY = finishButtonLocation[1] - revealLocation[1];
|
||||||
|
|
||||||
finishX += finishButton.getWidth() / 2;
|
finishX += binding.finishButton.getWidth() / 2;
|
||||||
finishY += finishButton.getHeight() / 2;
|
finishY += binding.finishButton.getHeight() / 2;
|
||||||
|
|
||||||
Animator animation = ViewAnimationUtils.createCircularReveal(reveal, finishX, finishY, 0f, (float) Math.max(reveal.getWidth(), reveal.getHeight()));
|
Animator animation = ViewAnimationUtils.createCircularReveal(binding.reveal, finishX, finishY, 0f, (float) Math.max(binding.reveal.getWidth(), binding.reveal.getHeight()));
|
||||||
animation.setDuration(500);
|
animation.setDuration(500);
|
||||||
animation.addListener(new Animator.AnimatorListener() {
|
animation.addListener(new Animator.AnimatorListener() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -340,7 +331,7 @@ public class EditProfileFragment extends LoggingFragment {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAnimationEnd(Animator animation) {
|
public void onAnimationEnd(Animator animation) {
|
||||||
finishButton.cancelSpinning();
|
binding.finishButton.cancelSpinning();
|
||||||
if (nextIntent != null && getActivity() != null) {
|
if (nextIntent != null && getActivity() != null) {
|
||||||
startActivity(nextIntent);
|
startActivity(nextIntent);
|
||||||
}
|
}
|
||||||
|
@ -355,7 +346,7 @@ public class EditProfileFragment extends LoggingFragment {
|
||||||
public void onAnimationRepeat(Animator animation) {}
|
public void onAnimationRepeat(Animator animation) {}
|
||||||
});
|
});
|
||||||
|
|
||||||
reveal.setVisibility(View.VISIBLE);
|
binding.reveal.setVisibility(View.VISIBLE);
|
||||||
animation.start();
|
animation.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
package org.thoughtcrime.securesms.profiles.edit.pnp
|
||||||
|
|
||||||
|
import androidx.fragment.app.viewModels
|
||||||
|
import org.thoughtcrime.securesms.R
|
||||||
|
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
|
||||||
|
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
|
||||||
|
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
|
||||||
|
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
|
||||||
|
import org.thoughtcrime.securesms.components.settings.configure
|
||||||
|
import org.thoughtcrime.securesms.util.FeatureFlags
|
||||||
|
import org.thoughtcrime.securesms.util.LifecycleDisposable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows the user to select who can see their phone number during registration.
|
||||||
|
*/
|
||||||
|
class WhoCanSeeMyPhoneNumberFragment : DSLSettingsFragment(titleId = R.string.WhoCanSeeMyPhoneNumberFragment__who_can_find_me_by_number) {
|
||||||
|
|
||||||
|
private val viewModel: WhoCanSeeMyPhoneNumberViewModel by viewModels()
|
||||||
|
private val lifecycleDisposable = LifecycleDisposable()
|
||||||
|
|
||||||
|
override fun bindAdapter(adapter: DSLSettingsAdapter) {
|
||||||
|
require(FeatureFlags.phoneNumberPrivacy())
|
||||||
|
|
||||||
|
lifecycleDisposable += viewModel.state.subscribe {
|
||||||
|
adapter.submitList(getConfiguration(it).toMappingModelList())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getConfiguration(state: WhoCanSeeMyPhoneNumberState): DSLConfiguration {
|
||||||
|
return configure {
|
||||||
|
radioPref(
|
||||||
|
title = DSLSettingsText.from(R.string.PhoneNumberPrivacy_everyone),
|
||||||
|
summary = DSLSettingsText.from(R.string.WhoCanSeeMyPhoneNumberFragment__anyone_who_has),
|
||||||
|
isChecked = state == WhoCanSeeMyPhoneNumberState.EVERYONE,
|
||||||
|
onClick = { viewModel.onEveryoneCanSeeMyPhoneNumberSelected() }
|
||||||
|
)
|
||||||
|
|
||||||
|
radioPref(
|
||||||
|
title = DSLSettingsText.from(R.string.PhoneNumberPrivacy_nobody),
|
||||||
|
summary = DSLSettingsText.from(R.string.WhoCanSeeMyPhoneNumberFragment__nobody_on_signal),
|
||||||
|
isChecked = state == WhoCanSeeMyPhoneNumberState.NOBODY,
|
||||||
|
onClick = { viewModel.onNobodyCanSeeMyPhoneNumberSelected() }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
package org.thoughtcrime.securesms.profiles.edit.pnp
|
||||||
|
|
||||||
|
enum class WhoCanSeeMyPhoneNumberState {
|
||||||
|
EVERYONE,
|
||||||
|
NOBODY
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
package org.thoughtcrime.securesms.profiles.edit.pnp
|
||||||
|
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||||
|
import io.reactivex.rxjava3.core.Flowable
|
||||||
|
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||||
|
import org.thoughtcrime.securesms.util.rx.RxStore
|
||||||
|
|
||||||
|
class WhoCanSeeMyPhoneNumberViewModel : ViewModel() {
|
||||||
|
|
||||||
|
private val store = RxStore(WhoCanSeeMyPhoneNumberState.EVERYONE)
|
||||||
|
private val disposables = CompositeDisposable()
|
||||||
|
|
||||||
|
val state: Flowable<WhoCanSeeMyPhoneNumberState> = store.stateFlowable.subscribeOn(AndroidSchedulers.mainThread())
|
||||||
|
|
||||||
|
fun onEveryoneCanSeeMyPhoneNumberSelected() {
|
||||||
|
store.update { WhoCanSeeMyPhoneNumberState.EVERYONE }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onNobodyCanSeeMyPhoneNumberSelected() {
|
||||||
|
store.update { WhoCanSeeMyPhoneNumberState.NOBODY }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCleared() {
|
||||||
|
disposables.clear()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
package org.thoughtcrime.securesms.profiles.manage
|
||||||
|
|
||||||
|
import org.thoughtcrime.securesms.databinding.CopyButtonBinding
|
||||||
|
import org.thoughtcrime.securesms.util.adapter.mapping.BindingFactory
|
||||||
|
import org.thoughtcrime.securesms.util.adapter.mapping.BindingViewHolder
|
||||||
|
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
|
||||||
|
import org.thoughtcrime.securesms.util.adapter.mapping.MappingModel
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Outlined button that allows the user to copy a piece of data.
|
||||||
|
*/
|
||||||
|
object CopyButton {
|
||||||
|
fun register(mappingAdapter: MappingAdapter) {
|
||||||
|
mappingAdapter.registerFactory(Model::class.java, BindingFactory(::ViewHolder, CopyButtonBinding::inflate))
|
||||||
|
}
|
||||||
|
|
||||||
|
class Model(
|
||||||
|
val text: CharSequence,
|
||||||
|
val onClick: (Model) -> Unit
|
||||||
|
) : MappingModel<Model> {
|
||||||
|
override fun areItemsTheSame(newItem: Model): Boolean = true
|
||||||
|
|
||||||
|
override fun areContentsTheSame(newItem: Model): Boolean = text == newItem.text
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ViewHolder(binding: CopyButtonBinding) : BindingViewHolder<Model, CopyButtonBinding>(binding) {
|
||||||
|
override fun bind(model: Model) {
|
||||||
|
binding.root.text = model.text
|
||||||
|
binding.root.setOnClickListener { model.onClick(model) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,33 +7,31 @@ import android.util.TypedValue;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.TextView;
|
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.appcompat.widget.Toolbar;
|
|
||||||
import androidx.core.content.res.ResourcesCompat;
|
import androidx.core.content.res.ResourcesCompat;
|
||||||
import androidx.lifecycle.LiveData;
|
import androidx.lifecycle.LiveData;
|
||||||
import androidx.lifecycle.Transformations;
|
import androidx.lifecycle.Transformations;
|
||||||
import androidx.lifecycle.ViewModelProviders;
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
import androidx.navigation.Navigation;
|
import androidx.navigation.Navigation;
|
||||||
|
|
||||||
import com.airbnb.lottie.SimpleColorFilter;
|
import com.airbnb.lottie.SimpleColorFilter;
|
||||||
import com.bumptech.glide.Glide;
|
import com.bumptech.glide.Glide;
|
||||||
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
|
|
||||||
import org.signal.core.util.logging.Log;
|
|
||||||
import org.thoughtcrime.securesms.AvatarPreviewActivity;
|
import org.thoughtcrime.securesms.AvatarPreviewActivity;
|
||||||
import org.thoughtcrime.securesms.LoggingFragment;
|
import org.thoughtcrime.securesms.LoggingFragment;
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
import org.thoughtcrime.securesms.avatar.Avatars;
|
import org.thoughtcrime.securesms.avatar.Avatars;
|
||||||
import org.thoughtcrime.securesms.avatar.picker.AvatarPickerFragment;
|
import org.thoughtcrime.securesms.avatar.picker.AvatarPickerFragment;
|
||||||
import org.thoughtcrime.securesms.badges.BadgeImageView;
|
|
||||||
import org.thoughtcrime.securesms.badges.models.Badge;
|
import org.thoughtcrime.securesms.badges.models.Badge;
|
||||||
import org.thoughtcrime.securesms.badges.self.none.BecomeASustainerFragment;
|
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.components.emoji.EmojiUtil;
|
||||||
|
import org.thoughtcrime.securesms.databinding.ManageProfileFragmentBinding;
|
||||||
import org.thoughtcrime.securesms.mediasend.Media;
|
import org.thoughtcrime.securesms.mediasend.Media;
|
||||||
import org.thoughtcrime.securesms.profiles.ProfileName;
|
import org.thoughtcrime.securesms.profiles.ProfileName;
|
||||||
import org.thoughtcrime.securesms.profiles.manage.ManageProfileViewModel.AvatarState;
|
import org.thoughtcrime.securesms.profiles.manage.ManageProfileViewModel.AvatarState;
|
||||||
|
@ -49,64 +47,42 @@ import java.util.Optional;
|
||||||
|
|
||||||
public class ManageProfileFragment extends LoggingFragment {
|
public class ManageProfileFragment extends LoggingFragment {
|
||||||
|
|
||||||
private static final String TAG = Log.tag(ManageProfileFragment.class);
|
private AlertDialog avatarProgress;
|
||||||
|
private ManageProfileViewModel viewModel;
|
||||||
private Toolbar toolbar;
|
private ManageProfileFragmentBinding binding;
|
||||||
private ImageView avatarView;
|
|
||||||
private ImageView avatarPlaceholderView;
|
|
||||||
private TextView profileNameView;
|
|
||||||
private View profileNameContainer;
|
|
||||||
private TextView usernameView;
|
|
||||||
private View usernameContainer;
|
|
||||||
private TextView aboutView;
|
|
||||||
private View aboutContainer;
|
|
||||||
private ImageView aboutEmojiView;
|
|
||||||
private AlertDialog avatarProgress;
|
|
||||||
private TextView avatarInitials;
|
|
||||||
private ImageView avatarBackground;
|
|
||||||
private View badgesContainer;
|
|
||||||
private BadgeImageView badgeView;
|
|
||||||
|
|
||||||
private ManageProfileViewModel viewModel;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Nullable View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
public @Nullable View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||||
return inflater.inflate(R.layout.manage_profile_fragment, container, false);
|
binding = ManageProfileFragmentBinding.inflate(inflater, container, false);
|
||||||
|
|
||||||
|
return binding.getRoot();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||||
this.toolbar = view.findViewById(R.id.toolbar);
|
new UsernameEditFragment.ResultContract().registerForResult(getParentFragmentManager(), getViewLifecycleOwner(), isUsernameCreated -> {
|
||||||
this.avatarView = view.findViewById(R.id.manage_profile_avatar);
|
Snackbar.make(view, R.string.ManageProfileFragment__username_created, Snackbar.LENGTH_SHORT).show();
|
||||||
this.avatarPlaceholderView = view.findViewById(R.id.manage_profile_avatar_placeholder);
|
});
|
||||||
this.profileNameView = view.findViewById(R.id.manage_profile_name);
|
|
||||||
this.profileNameContainer = view.findViewById(R.id.manage_profile_name_container);
|
UsernameShareBottomSheet.ResultContract.INSTANCE.registerForResult(getParentFragmentManager(), getViewLifecycleOwner(), isCopiedToClipboard -> {
|
||||||
this.usernameView = view.findViewById(R.id.manage_profile_username);
|
Snackbar.make(view, R.string.ManageProfileFragment__username_copied, Snackbar.LENGTH_SHORT).show();
|
||||||
this.usernameContainer = view.findViewById(R.id.manage_profile_username_container);
|
});
|
||||||
this.aboutView = view.findViewById(R.id.manage_profile_about);
|
|
||||||
this.aboutContainer = view.findViewById(R.id.manage_profile_about_container);
|
|
||||||
this.aboutEmojiView = view.findViewById(R.id.manage_profile_about_icon);
|
|
||||||
this.avatarInitials = view.findViewById(R.id.manage_profile_avatar_initials);
|
|
||||||
this.avatarBackground = view.findViewById(R.id.manage_profile_avatar_background);
|
|
||||||
this.badgesContainer = view.findViewById(R.id.manage_profile_badges_container);
|
|
||||||
this.badgeView = view.findViewById(R.id.manage_profile_badge);
|
|
||||||
|
|
||||||
initializeViewModel();
|
initializeViewModel();
|
||||||
|
|
||||||
this.toolbar.setNavigationOnClickListener(v -> requireActivity().finish());
|
binding.toolbar.setNavigationOnClickListener(v -> requireActivity().finish());
|
||||||
|
|
||||||
View editAvatar = view.findViewById(R.id.manage_profile_edit_photo);
|
binding.manageProfileEditPhoto.setOnClickListener(v -> onEditAvatarClicked());
|
||||||
editAvatar.setOnClickListener(v -> onEditAvatarClicked());
|
|
||||||
|
|
||||||
this.profileNameContainer.setOnClickListener(v -> {
|
binding.manageProfileNameContainer.setOnClickListener(v -> {
|
||||||
SafeNavigation.safeNavigate(Navigation.findNavController(v), ManageProfileFragmentDirections.actionManageProfileName());
|
SafeNavigation.safeNavigate(Navigation.findNavController(v), ManageProfileFragmentDirections.actionManageProfileName());
|
||||||
});
|
});
|
||||||
|
|
||||||
this.usernameContainer.setOnClickListener(v -> {
|
binding.manageProfileUsernameContainer.setOnClickListener(v -> {
|
||||||
SafeNavigation.safeNavigate(Navigation.findNavController(v), ManageProfileFragmentDirections.actionManageUsername());
|
SafeNavigation.safeNavigate(Navigation.findNavController(v), ManageProfileFragmentDirections.actionManageUsername());
|
||||||
});
|
});
|
||||||
|
|
||||||
this.aboutContainer.setOnClickListener(v -> {
|
binding.manageProfileAboutContainer.setOnClickListener(v -> {
|
||||||
SafeNavigation.safeNavigate(Navigation.findNavController(v), ManageProfileFragmentDirections.actionManageAbout());
|
SafeNavigation.safeNavigate(Navigation.findNavController(v), ManageProfileFragmentDirections.actionManageAbout());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -119,6 +95,7 @@ public class ManageProfileFragment extends LoggingFragment {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
EmojiTextView avatarInitials = binding.manageProfileAvatarInitials;
|
||||||
avatarInitials.addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
|
avatarInitials.addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
|
||||||
if (avatarInitials.length() > 0) {
|
if (avatarInitials.length() > 0) {
|
||||||
updateInitials(avatarInitials.getText().toString());
|
updateInitials(avatarInitials.getText().toString());
|
||||||
|
@ -126,7 +103,7 @@ public class ManageProfileFragment extends LoggingFragment {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (FeatureFlags.donorBadges()) {
|
if (FeatureFlags.donorBadges()) {
|
||||||
badgesContainer.setOnClickListener(v -> {
|
binding.manageProfileBadgesContainer.setOnClickListener(v -> {
|
||||||
if (Recipient.self().getBadges().isEmpty()) {
|
if (Recipient.self().getBadges().isEmpty()) {
|
||||||
BecomeASustainerFragment.show(getParentFragmentManager());
|
BecomeASustainerFragment.show(getParentFragmentManager());
|
||||||
} else {
|
} else {
|
||||||
|
@ -134,17 +111,27 @@ public class ManageProfileFragment extends LoggingFragment {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
badgesContainer.setVisibility(View.GONE);
|
binding.manageProfileBadgesContainer.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
avatarView.setOnClickListener(v -> {
|
binding.manageProfileAvatar.setOnClickListener(v -> {
|
||||||
startActivity(AvatarPreviewActivity.intentFromRecipientId(requireContext(), Recipient.self().getId()),
|
startActivity(AvatarPreviewActivity.intentFromRecipientId(requireContext(), Recipient.self().getId()),
|
||||||
AvatarPreviewActivity.createTransitionBundle(requireActivity(), avatarView));
|
AvatarPreviewActivity.createTransitionBundle(requireActivity(), binding.manageProfileAvatar));
|
||||||
|
});
|
||||||
|
|
||||||
|
binding.manageProfileUsernameShare.setOnClickListener(v -> {
|
||||||
|
SafeNavigation.safeNavigate(Navigation.findNavController(v), ManageProfileFragmentDirections.actionManageProfileFragmentToShareUsernameDialog());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroyView() {
|
||||||
|
super.onDestroyView();
|
||||||
|
binding = null;
|
||||||
|
}
|
||||||
|
|
||||||
private void initializeViewModel() {
|
private void initializeViewModel() {
|
||||||
viewModel = ViewModelProviders.of(this, new ManageProfileViewModel.Factory()).get(ManageProfileViewModel.class);
|
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())),
|
LiveData<Optional<byte[]>> avatarImage = Transformations.map(LiveDataUtil.distinctUntilChanged(viewModel.getAvatar(), (b1, b2) -> Arrays.equals(b1.getAvatar(), b2.getAvatar())),
|
||||||
b -> Optional.ofNullable(b.getAvatar()));
|
b -> Optional.ofNullable(b.getAvatar()));
|
||||||
|
@ -160,7 +147,7 @@ public class ManageProfileFragment extends LoggingFragment {
|
||||||
if (viewModel.shouldShowUsername()) {
|
if (viewModel.shouldShowUsername()) {
|
||||||
viewModel.getUsername().observe(getViewLifecycleOwner(), this::presentUsername);
|
viewModel.getUsername().observe(getViewLifecycleOwner(), this::presentUsername);
|
||||||
} else {
|
} else {
|
||||||
usernameContainer.setVisibility(View.GONE);
|
binding.manageProfileUsernameContainer.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,9 +156,9 @@ public class ManageProfileFragment extends LoggingFragment {
|
||||||
Glide.with(this)
|
Glide.with(this)
|
||||||
.load(avatarData.get())
|
.load(avatarData.get())
|
||||||
.circleCrop()
|
.circleCrop()
|
||||||
.into(avatarView);
|
.into(binding.manageProfileAvatar);
|
||||||
} else {
|
} else {
|
||||||
Glide.with(this).load((Drawable) null).into(avatarView);
|
Glide.with(this).load((Drawable) null).into(binding.manageProfileAvatar);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,21 +167,21 @@ public class ManageProfileFragment extends LoggingFragment {
|
||||||
CharSequence initials = NameUtil.getAbbreviation(avatarState.getSelf().getDisplayName(requireContext()));
|
CharSequence initials = NameUtil.getAbbreviation(avatarState.getSelf().getDisplayName(requireContext()));
|
||||||
Avatars.ForegroundColor foregroundColor = Avatars.getForegroundColor(avatarState.getSelf().getAvatarColor());
|
Avatars.ForegroundColor foregroundColor = Avatars.getForegroundColor(avatarState.getSelf().getAvatarColor());
|
||||||
|
|
||||||
avatarBackground.setColorFilter(new SimpleColorFilter(avatarState.getSelf().getAvatarColor().colorInt()));
|
binding.manageProfileAvatarBackground.setColorFilter(new SimpleColorFilter(avatarState.getSelf().getAvatarColor().colorInt()));
|
||||||
avatarPlaceholderView.setColorFilter(new SimpleColorFilter(foregroundColor.getColorInt()));
|
binding.manageProfileAvatarPlaceholder.setColorFilter(new SimpleColorFilter(foregroundColor.getColorInt()));
|
||||||
avatarInitials.setTextColor(foregroundColor.getColorInt());
|
binding.manageProfileAvatarInitials.setTextColor(foregroundColor.getColorInt());
|
||||||
|
|
||||||
if (TextUtils.isEmpty(initials)) {
|
if (TextUtils.isEmpty(initials)) {
|
||||||
avatarPlaceholderView.setVisibility(View.VISIBLE);
|
binding.manageProfileAvatarPlaceholder.setVisibility(View.VISIBLE);
|
||||||
avatarInitials.setVisibility(View.GONE);
|
binding.manageProfileAvatarInitials.setVisibility(View.GONE);
|
||||||
} else {
|
} else {
|
||||||
updateInitials(initials.toString());
|
updateInitials(initials.toString());
|
||||||
avatarPlaceholderView.setVisibility(View.GONE);
|
binding.manageProfileAvatarPlaceholder.setVisibility(View.GONE);
|
||||||
avatarInitials.setVisibility(View.VISIBLE);
|
binding.manageProfileAvatarInitials.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
avatarPlaceholderView.setVisibility(View.GONE);
|
binding.manageProfileAvatarPlaceholder.setVisibility(View.GONE);
|
||||||
avatarInitials.setVisibility(View.GONE);
|
binding.manageProfileAvatarInitials.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (avatarProgress == null && avatarState.getLoadingState() == ManageProfileViewModel.LoadingState.LOADING) {
|
if (avatarProgress == null && avatarState.getLoadingState() == ManageProfileViewModel.LoadingState.LOADING) {
|
||||||
|
@ -205,53 +192,59 @@ public class ManageProfileFragment extends LoggingFragment {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateInitials(String initials) {
|
private void updateInitials(String initials) {
|
||||||
avatarInitials.setTextSize(TypedValue.COMPLEX_UNIT_PX, Avatars.getTextSizeForLength(requireContext(), initials, avatarInitials.getMeasuredWidth() * 0.8f, avatarInitials.getMeasuredWidth() * 0.45f));
|
binding.manageProfileAvatarInitials.setTextSize(TypedValue.COMPLEX_UNIT_PX,
|
||||||
avatarInitials.setText(initials);
|
Avatars.getTextSizeForLength(requireContext(),
|
||||||
|
initials,
|
||||||
|
binding.manageProfileAvatarInitials.getMeasuredWidth() * 0.8f,
|
||||||
|
binding.manageProfileAvatarInitials.getMeasuredWidth() * 0.45f));
|
||||||
|
binding.manageProfileAvatarInitials.setText(initials);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void presentProfileName(@Nullable ProfileName profileName) {
|
private void presentProfileName(@Nullable ProfileName profileName) {
|
||||||
if (profileName == null || profileName.isEmpty()) {
|
if (profileName == null || profileName.isEmpty()) {
|
||||||
profileNameView.setText(R.string.ManageProfileFragment_profile_name);
|
binding.manageProfileName.setText(R.string.ManageProfileFragment_profile_name);
|
||||||
} else {
|
} else {
|
||||||
profileNameView.setText(profileName.toString());
|
binding.manageProfileName.setText(profileName.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void presentUsername(@Nullable String username) {
|
private void presentUsername(@Nullable String username) {
|
||||||
if (username == null || username.isEmpty()) {
|
if (username == null || username.isEmpty()) {
|
||||||
usernameView.setText(R.string.ManageProfileFragment_username);
|
binding.manageProfileUsername.setText(R.string.ManageProfileFragment_username);
|
||||||
|
binding.manageProfileUsernameShare.setVisibility(View.GONE);
|
||||||
} else {
|
} else {
|
||||||
usernameView.setText(username);
|
binding.manageProfileUsername.setText(username);
|
||||||
|
binding.manageProfileUsernameShare.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void presentAbout(@Nullable String about) {
|
private void presentAbout(@Nullable String about) {
|
||||||
if (about == null || about.isEmpty()) {
|
if (about == null || about.isEmpty()) {
|
||||||
aboutView.setText(R.string.ManageProfileFragment_about);
|
binding.manageProfileAbout.setText(R.string.ManageProfileFragment_about);
|
||||||
} else {
|
} else {
|
||||||
aboutView.setText(about);
|
binding.manageProfileAbout.setText(about);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void presentAboutEmoji(@NonNull String aboutEmoji) {
|
private void presentAboutEmoji(@NonNull String aboutEmoji) {
|
||||||
if (aboutEmoji == null || aboutEmoji.isEmpty()) {
|
if (aboutEmoji == null || aboutEmoji.isEmpty()) {
|
||||||
aboutEmojiView.setImageDrawable(ResourcesCompat.getDrawable(getResources(), R.drawable.ic_compose_24, null));
|
binding.manageProfileAboutIcon.setImageDrawable(ResourcesCompat.getDrawable(getResources(), R.drawable.ic_compose_24, null));
|
||||||
} else {
|
} else {
|
||||||
Drawable emoji = EmojiUtil.convertToDrawable(requireContext(), aboutEmoji);
|
Drawable emoji = EmojiUtil.convertToDrawable(requireContext(), aboutEmoji);
|
||||||
|
|
||||||
if (emoji != null) {
|
if (emoji != null) {
|
||||||
aboutEmojiView.setImageDrawable(emoji);
|
binding.manageProfileAboutIcon.setImageDrawable(emoji);
|
||||||
} else {
|
} else {
|
||||||
aboutEmojiView.setImageDrawable(ResourcesCompat.getDrawable(getResources(), R.drawable.ic_compose_24, null));
|
binding.manageProfileAboutIcon.setImageDrawable(ResourcesCompat.getDrawable(getResources(), R.drawable.ic_compose_24, null));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void presentBadge(@NonNull Optional<Badge> badge) {
|
private void presentBadge(@NonNull Optional<Badge> badge) {
|
||||||
if (badge.isPresent() && badge.get().getVisible() && !badge.get().isExpired()) {
|
if (badge.isPresent() && badge.get().getVisible() && !badge.get().isExpired()) {
|
||||||
badgeView.setBadge(badge.orElse(null));
|
binding.manageProfileBadge.setBadge(badge.orElse(null));
|
||||||
} else {
|
} else {
|
||||||
badgeView.setBadge(null);
|
binding.manageProfileBadge.setBadge(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
package org.thoughtcrime.securesms.profiles.manage
|
||||||
|
|
||||||
|
import org.thoughtcrime.securesms.databinding.ShareButtonBinding
|
||||||
|
import org.thoughtcrime.securesms.util.adapter.mapping.BindingFactory
|
||||||
|
import org.thoughtcrime.securesms.util.adapter.mapping.BindingViewHolder
|
||||||
|
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
|
||||||
|
import org.thoughtcrime.securesms.util.adapter.mapping.MappingModel
|
||||||
|
|
||||||
|
object ShareButton {
|
||||||
|
fun register(adapter: MappingAdapter) {
|
||||||
|
adapter.registerFactory(Model::class.java, BindingFactory(::ViewHolder, ShareButtonBinding::inflate))
|
||||||
|
}
|
||||||
|
|
||||||
|
class Model(
|
||||||
|
val text: CharSequence,
|
||||||
|
val onClick: (Model) -> Unit
|
||||||
|
) : MappingModel<Model> {
|
||||||
|
override fun areItemsTheSame(newItem: Model): Boolean = true
|
||||||
|
|
||||||
|
override fun areContentsTheSame(newItem: Model): Boolean = text == newItem.text
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ViewHolder(binding: ShareButtonBinding) : BindingViewHolder<Model, ShareButtonBinding>(binding) {
|
||||||
|
override fun bind(model: Model) {
|
||||||
|
binding.shareButton.setOnClickListener { model.onClick(model) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,38 +1,56 @@
|
||||||
package org.thoughtcrime.securesms.profiles.manage;
|
package org.thoughtcrime.securesms.profiles.manage;
|
||||||
|
|
||||||
|
import android.content.res.ColorStateList;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.inputmethod.EditorInfo;
|
import android.view.inputmethod.EditorInfo;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.widget.Toolbar;
|
import androidx.appcompat.widget.Toolbar;
|
||||||
import androidx.lifecycle.ViewModelProviders;
|
import androidx.core.content.ContextCompat;
|
||||||
|
import androidx.fragment.app.FragmentManager;
|
||||||
|
import androidx.lifecycle.LifecycleOwner;
|
||||||
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
import androidx.navigation.Navigation;
|
import androidx.navigation.Navigation;
|
||||||
import androidx.navigation.fragment.NavHostFragment;
|
import androidx.navigation.fragment.NavHostFragment;
|
||||||
|
|
||||||
|
import com.google.android.material.button.MaterialButton;
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||||
|
import com.google.android.material.textfield.TextInputLayout;
|
||||||
|
|
||||||
|
import org.signal.core.util.DimensionUnit;
|
||||||
import org.thoughtcrime.securesms.LoggingFragment;
|
import org.thoughtcrime.securesms.LoggingFragment;
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
import org.thoughtcrime.securesms.contactshare.SimpleTextWatcher;
|
import org.thoughtcrime.securesms.contactshare.SimpleTextWatcher;
|
||||||
|
import org.thoughtcrime.securesms.databinding.UsernameEditFragmentBinding;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
|
import org.thoughtcrime.securesms.util.FragmentResultContract;
|
||||||
|
import org.thoughtcrime.securesms.util.LifecycleDisposable;
|
||||||
import org.thoughtcrime.securesms.util.UsernameUtil;
|
import org.thoughtcrime.securesms.util.UsernameUtil;
|
||||||
|
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||||
import org.thoughtcrime.securesms.util.views.CircularProgressMaterialButton;
|
import org.thoughtcrime.securesms.util.views.CircularProgressMaterialButton;
|
||||||
|
import org.thoughtcrime.securesms.util.views.LearnMoreTextView;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
public class UsernameEditFragment extends LoggingFragment {
|
public class UsernameEditFragment extends LoggingFragment {
|
||||||
|
|
||||||
private static final float DISABLED_ALPHA = 0.5f;
|
private static final float DISABLED_ALPHA = 0.5f;
|
||||||
|
|
||||||
private UsernameEditViewModel viewModel;
|
private UsernameEditViewModel viewModel;
|
||||||
|
private UsernameEditFragmentBinding binding;
|
||||||
private EditText usernameInput;
|
private ImageView suffixProgress;
|
||||||
private TextView usernameSubtext;
|
private LifecycleDisposable lifecycleDisposable;
|
||||||
private CircularProgressMaterialButton submitButton;
|
|
||||||
private CircularProgressMaterialButton deleteButton;
|
|
||||||
|
|
||||||
public static UsernameEditFragment newInstance() {
|
public static UsernameEditFragment newInstance() {
|
||||||
return new UsernameEditFragment();
|
return new UsernameEditFragment();
|
||||||
|
@ -40,46 +58,97 @@ public class UsernameEditFragment extends LoggingFragment {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Nullable View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
public @Nullable View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||||
return inflater.inflate(R.layout.username_edit_fragment, container, false);
|
binding = UsernameEditFragmentBinding.inflate(inflater, container, false);
|
||||||
|
return binding.getRoot();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||||
usernameInput = view.findViewById(R.id.username_text);
|
binding.toolbar.setNavigationOnClickListener(v -> Navigation.findNavController(view).popBackStack());
|
||||||
usernameSubtext = view.findViewById(R.id.username_subtext);
|
|
||||||
submitButton = view.findViewById(R.id.username_submit_button);
|
|
||||||
deleteButton = view.findViewById(R.id.username_delete_button);
|
|
||||||
|
|
||||||
view.<Toolbar>findViewById(R.id.toolbar)
|
binding.usernameTextWrapper.setErrorIconDrawable(null);
|
||||||
.setNavigationOnClickListener(v -> Navigation.findNavController(view)
|
|
||||||
.popBackStack());
|
|
||||||
|
|
||||||
viewModel = ViewModelProviders.of(this, new UsernameEditViewModel.Factory()).get(UsernameEditViewModel.class);
|
lifecycleDisposable = new LifecycleDisposable();
|
||||||
|
lifecycleDisposable.bindTo(getViewLifecycleOwner());
|
||||||
|
|
||||||
viewModel.getUiState().observe(getViewLifecycleOwner(), this::onUiStateChanged);
|
viewModel = new ViewModelProvider(this, new UsernameEditViewModel.Factory()).get(UsernameEditViewModel.class);
|
||||||
|
|
||||||
|
lifecycleDisposable.add(viewModel.getUiState().subscribe(this::onUiStateChanged));
|
||||||
viewModel.getEvents().observe(getViewLifecycleOwner(), this::onEvent);
|
viewModel.getEvents().observe(getViewLifecycleOwner(), this::onEvent);
|
||||||
|
|
||||||
submitButton.setOnClickListener(v -> viewModel.onUsernameSubmitted(usernameInput.getText().toString()));
|
binding.usernameSubmitButton.setOnClickListener(v -> viewModel.onUsernameSubmitted(binding.usernameText.getText().toString()));
|
||||||
deleteButton.setOnClickListener(v -> viewModel.onUsernameDeleted());
|
binding.usernameDeleteButton.setOnClickListener(v -> viewModel.onUsernameDeleted());
|
||||||
|
|
||||||
usernameInput.setText(Recipient.self().getUsername().orElse(null));
|
binding.usernameText.setText(Recipient.self().getUsername().orElse(null));
|
||||||
usernameInput.addTextChangedListener(new SimpleTextWatcher() {
|
binding.usernameText.addTextChangedListener(new SimpleTextWatcher() {
|
||||||
@Override
|
@Override
|
||||||
public void onTextChanged(String text) {
|
public void onTextChanged(String text) {
|
||||||
viewModel.onUsernameUpdated(text);
|
viewModel.onUsernameUpdated(text);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
usernameInput.setOnEditorActionListener((v, actionId, event) -> {
|
binding.usernameText.setOnEditorActionListener((v, actionId, event) -> {
|
||||||
if (actionId == EditorInfo.IME_ACTION_DONE) {
|
if (actionId == EditorInfo.IME_ACTION_DONE) {
|
||||||
viewModel.onUsernameSubmitted(usernameInput.getText().toString());
|
viewModel.onUsernameSubmitted(binding.usernameText.getText().toString());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
binding.usernameDescription.setLinkColor(ContextCompat.getColor(requireContext(), R.color.signal_colorPrimary));
|
||||||
|
binding.usernameDescription.setLearnMoreVisible(true);
|
||||||
|
binding.usernameDescription.setOnLinkClickListener(this::onLearnMore);
|
||||||
|
|
||||||
|
initializeSuffix();
|
||||||
|
ViewUtil.focusAndShowKeyboard(binding.usernameText);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initializeSuffix() {
|
||||||
|
TextView suffixTextView = binding.usernameTextWrapper.getSuffixTextView();
|
||||||
|
Drawable pipe = Objects.requireNonNull(ContextCompat.getDrawable(requireContext(), R.drawable.pipe_divider));
|
||||||
|
|
||||||
|
pipe.setBounds(0, 0, (int) DimensionUnit.DP.toPixels(1f), (int) DimensionUnit.DP.toPixels(20f));
|
||||||
|
suffixTextView.setCompoundDrawablesRelative(pipe, null, null, null);
|
||||||
|
|
||||||
|
LinearLayout suffixParent = (LinearLayout) suffixTextView.getParent();
|
||||||
|
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT);
|
||||||
|
|
||||||
|
ViewUtil.setLeftMargin(suffixTextView, (int) DimensionUnit.DP.toPixels(16f));
|
||||||
|
|
||||||
|
binding.usernameTextWrapper.getSuffixTextView().setCompoundDrawablePadding((int) DimensionUnit.DP.toPixels(16f));
|
||||||
|
|
||||||
|
layoutParams.topMargin = suffixTextView.getPaddingTop();
|
||||||
|
layoutParams.bottomMargin = suffixTextView.getPaddingBottom();
|
||||||
|
|
||||||
|
suffixProgress = new ImageView(requireContext());
|
||||||
|
suffixProgress.setImageDrawable(UsernameSuffix.getInProgressDrawable(requireContext()));
|
||||||
|
suffixParent.addView(suffixProgress, 0, layoutParams);
|
||||||
|
|
||||||
|
suffixTextView.setOnClickListener(this::onLearnMore);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroyView() {
|
||||||
|
super.onDestroyView();
|
||||||
|
binding = null;
|
||||||
|
suffixProgress = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onLearnMore(@Nullable View unused) {
|
||||||
|
new MaterialAlertDialogBuilder(requireContext())
|
||||||
|
.setTitle(new StringBuilder("#\n").append(getString(R.string.UsernameEditFragment__what_is_this_number)))
|
||||||
|
.setMessage(R.string.UsernameEditFragment__these_digits_help_keep)
|
||||||
|
.setPositiveButton(android.R.string.ok, (dialog, which) -> {})
|
||||||
|
.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onUiStateChanged(@NonNull UsernameEditViewModel.State state) {
|
private void onUiStateChanged(@NonNull UsernameEditViewModel.State state) {
|
||||||
|
EditText usernameInput = binding.usernameText;
|
||||||
|
CircularProgressMaterialButton submitButton = binding.usernameSubmitButton;
|
||||||
|
CircularProgressMaterialButton deleteButton = binding.usernameDeleteButton;
|
||||||
|
TextInputLayout usernameInputWrapper = binding.usernameTextWrapper;
|
||||||
|
|
||||||
usernameInput.setEnabled(true);
|
usernameInput.setEnabled(true);
|
||||||
|
presentSuffix(state.getUsernameSuffix());
|
||||||
|
|
||||||
switch (state.getButtonState()) {
|
switch (state.getButtonState()) {
|
||||||
case SUBMIT:
|
case SUBMIT:
|
||||||
|
@ -128,39 +197,57 @@ public class UsernameEditFragment extends LoggingFragment {
|
||||||
|
|
||||||
switch (state.getUsernameStatus()) {
|
switch (state.getUsernameStatus()) {
|
||||||
case NONE:
|
case NONE:
|
||||||
usernameSubtext.setText("");
|
usernameInputWrapper.setError(null);
|
||||||
break;
|
break;
|
||||||
case TOO_SHORT:
|
case TOO_SHORT:
|
||||||
case TOO_LONG:
|
case TOO_LONG:
|
||||||
usernameSubtext.setText(getResources().getString(R.string.UsernameEditFragment_usernames_must_be_between_a_and_b_characters, UsernameUtil.MIN_LENGTH, UsernameUtil.MAX_LENGTH));
|
usernameInputWrapper.setError(getResources().getString(R.string.UsernameEditFragment_usernames_must_be_between_a_and_b_characters, UsernameUtil.MIN_LENGTH, UsernameUtil.MAX_LENGTH));
|
||||||
usernameSubtext.setTextColor(getResources().getColor(R.color.core_red));
|
usernameInputWrapper.setErrorTextColor(ColorStateList.valueOf(getResources().getColor(R.color.signal_colorError)));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case INVALID_CHARACTERS:
|
case INVALID_CHARACTERS:
|
||||||
usernameSubtext.setText(R.string.UsernameEditFragment_usernames_can_only_include);
|
usernameInputWrapper.setError(getResources().getString(R.string.UsernameEditFragment_usernames_can_only_include));
|
||||||
usernameSubtext.setTextColor(getResources().getColor(R.color.core_red));
|
usernameInputWrapper.setErrorTextColor(ColorStateList.valueOf(getResources().getColor(R.color.signal_colorError)));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case CANNOT_START_WITH_NUMBER:
|
case CANNOT_START_WITH_NUMBER:
|
||||||
usernameSubtext.setText(R.string.UsernameEditFragment_usernames_cannot_begin_with_a_number);
|
usernameInputWrapper.setError(getResources().getString(R.string.UsernameEditFragment_usernames_cannot_begin_with_a_number));
|
||||||
usernameSubtext.setTextColor(getResources().getColor(R.color.core_red));
|
usernameInputWrapper.setErrorTextColor(ColorStateList.valueOf(getResources().getColor(R.color.signal_colorError)));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case INVALID_GENERIC:
|
case INVALID_GENERIC:
|
||||||
usernameSubtext.setText(R.string.UsernameEditFragment_username_is_invalid);
|
usernameInputWrapper.setError(getResources().getString(R.string.UsernameEditFragment_username_is_invalid));
|
||||||
usernameSubtext.setTextColor(getResources().getColor(R.color.core_red));
|
usernameInputWrapper.setErrorTextColor(ColorStateList.valueOf(getResources().getColor(R.color.signal_colorError)));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case TAKEN:
|
case TAKEN:
|
||||||
usernameSubtext.setText(R.string.UsernameEditFragment_this_username_is_taken);
|
usernameInputWrapper.setError(getResources().getString(R.string.UsernameEditFragment_this_username_is_taken));
|
||||||
usernameSubtext.setTextColor(getResources().getColor(R.color.core_red));
|
usernameInputWrapper.setErrorTextColor(ColorStateList.valueOf(getResources().getColor(R.color.signal_colorError)));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case AVAILABLE:
|
case AVAILABLE:
|
||||||
usernameSubtext.setText(R.string.UsernameEditFragment_this_username_is_available);
|
usernameInputWrapper.setError(getResources().getString(R.string.UsernameEditFragment_this_username_is_available));
|
||||||
usernameSubtext.setTextColor(getResources().getColor(R.color.core_green));
|
usernameInputWrapper.setErrorTextColor(ColorStateList.valueOf(getResources().getColor(R.color.signal_accent_green)));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void presentSuffix(@NonNull UsernameSuffix usernameSuffix) {
|
||||||
|
binding.usernameTextWrapper.setSuffixText(usernameSuffix.getCharSequence());
|
||||||
|
|
||||||
|
boolean isInProgress = usernameSuffix.isInProgress();
|
||||||
|
|
||||||
|
if (isInProgress) {
|
||||||
|
suffixProgress.setVisibility(View.VISIBLE);
|
||||||
|
} else {
|
||||||
|
suffixProgress.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void onEvent(@NonNull UsernameEditViewModel.Event event) {
|
private void onEvent(@NonNull UsernameEditViewModel.Event event) {
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case SUBMIT_SUCCESS:
|
case SUBMIT_SUCCESS:
|
||||||
|
ResultContract.setUsernameCreated(getParentFragmentManager());
|
||||||
Toast.makeText(requireContext(), R.string.UsernameEditFragment_successfully_set_username, Toast.LENGTH_SHORT).show();
|
Toast.makeText(requireContext(), R.string.UsernameEditFragment_successfully_set_username, Toast.LENGTH_SHORT).show();
|
||||||
NavHostFragment.findNavController(this).popBackStack();
|
NavHostFragment.findNavController(this).popBackStack();
|
||||||
break;
|
break;
|
||||||
|
@ -179,4 +266,23 @@ public class UsernameEditFragment extends LoggingFragment {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class ResultContract extends FragmentResultContract<Boolean> {
|
||||||
|
private static final String REQUEST_KEY = "username_created";
|
||||||
|
|
||||||
|
protected ResultContract() {
|
||||||
|
super(REQUEST_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setUsernameCreated(@NonNull FragmentManager fragmentManager) {
|
||||||
|
Bundle bundle = new Bundle();
|
||||||
|
bundle.putBoolean(REQUEST_KEY, true);
|
||||||
|
fragmentManager.setFragmentResult(REQUEST_KEY, bundle);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Boolean getResult(@NonNull Bundle bundle) {
|
||||||
|
return bundle.getBoolean(REQUEST_KEY, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ import android.text.TextUtils;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.lifecycle.LiveData;
|
import androidx.lifecycle.LiveData;
|
||||||
import androidx.lifecycle.MutableLiveData;
|
|
||||||
import androidx.lifecycle.ViewModel;
|
import androidx.lifecycle.ViewModel;
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
|
|
||||||
|
@ -16,81 +15,80 @@ import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.util.SingleLiveEvent;
|
import org.thoughtcrime.securesms.util.SingleLiveEvent;
|
||||||
import org.thoughtcrime.securesms.util.UsernameUtil;
|
import org.thoughtcrime.securesms.util.UsernameUtil;
|
||||||
import org.thoughtcrime.securesms.util.UsernameUtil.InvalidReason;
|
import org.thoughtcrime.securesms.util.UsernameUtil.InvalidReason;
|
||||||
|
import org.thoughtcrime.securesms.util.rx.RxStore;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||||
|
import io.reactivex.rxjava3.core.Flowable;
|
||||||
|
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||||
|
|
||||||
|
|
||||||
class UsernameEditViewModel extends ViewModel {
|
class UsernameEditViewModel extends ViewModel {
|
||||||
|
|
||||||
private static final String TAG = Log.tag(UsernameEditViewModel.class);
|
private static final String TAG = Log.tag(UsernameEditViewModel.class);
|
||||||
|
|
||||||
private final Application application;
|
private final Application application;
|
||||||
private final MutableLiveData<State> uiState;
|
|
||||||
private final SingleLiveEvent<Event> events;
|
private final SingleLiveEvent<Event> events;
|
||||||
private final UsernameEditRepository repo;
|
private final UsernameEditRepository repo;
|
||||||
|
private final RxStore<State> uiState;
|
||||||
|
|
||||||
private UsernameEditViewModel() {
|
private UsernameEditViewModel() {
|
||||||
this.application = ApplicationDependencies.getApplication();
|
this.application = ApplicationDependencies.getApplication();
|
||||||
this.repo = new UsernameEditRepository();
|
this.repo = new UsernameEditRepository();
|
||||||
this.uiState = new MutableLiveData<>();
|
this.uiState = new RxStore<>(new State(ButtonState.SUBMIT_DISABLED, UsernameStatus.NONE, UsernameSuffix.NONE), Schedulers.computation());
|
||||||
this.events = new SingleLiveEvent<>();
|
this.events = new SingleLiveEvent<>();
|
||||||
|
|
||||||
uiState.setValue(new State(ButtonState.SUBMIT_DISABLED, UsernameStatus.NONE));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void onUsernameUpdated(@NonNull String username) {
|
void onUsernameUpdated(@NonNull String username) {
|
||||||
if (TextUtils.isEmpty(username) && Recipient.self().getUsername().isPresent()) {
|
uiState.update(state -> {
|
||||||
uiState.setValue(new State(ButtonState.DELETE, UsernameStatus.NONE));
|
if (TextUtils.isEmpty(username) && Recipient.self().getUsername().isPresent()) {
|
||||||
return;
|
return new State(ButtonState.DELETE, UsernameStatus.NONE, state.usernameSuffix);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (username.equals(Recipient.self().getUsername().orElse(null))) {
|
if (username.equals(Recipient.self().getUsername().orElse(null))) {
|
||||||
uiState.setValue(new State(ButtonState.SUBMIT_DISABLED, UsernameStatus.NONE));
|
return new State(ButtonState.SUBMIT_DISABLED, UsernameStatus.NONE, state.usernameSuffix);
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Optional<InvalidReason> invalidReason = UsernameUtil.checkUsername(username);
|
Optional<InvalidReason> invalidReason = UsernameUtil.checkUsername(username);
|
||||||
|
|
||||||
if (invalidReason.isPresent()) {
|
return invalidReason.map(reason -> new State(ButtonState.SUBMIT_DISABLED, mapUsernameError(reason), state.usernameSuffix))
|
||||||
uiState.setValue(new State(ButtonState.SUBMIT_DISABLED, mapUsernameError(invalidReason.get())));
|
.orElseGet(() -> new State(ButtonState.SUBMIT, UsernameStatus.NONE, state.usernameSuffix));
|
||||||
return;
|
});
|
||||||
}
|
|
||||||
|
|
||||||
uiState.setValue(new State(ButtonState.SUBMIT, UsernameStatus.NONE));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void onUsernameSubmitted(@NonNull String username) {
|
void onUsernameSubmitted(@NonNull String username) {
|
||||||
if (username.equals(Recipient.self().getUsername().orElse(null))) {
|
if (username.equals(Recipient.self().getUsername().orElse(null))) {
|
||||||
uiState.setValue(new State(ButtonState.SUBMIT_DISABLED, UsernameStatus.NONE));
|
uiState.update(state -> new State(ButtonState.SUBMIT_DISABLED, UsernameStatus.NONE, state.usernameSuffix));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<InvalidReason> invalidReason = UsernameUtil.checkUsername(username);
|
Optional<InvalidReason> invalidReason = UsernameUtil.checkUsername(username);
|
||||||
|
|
||||||
if (invalidReason.isPresent()) {
|
if (invalidReason.isPresent()) {
|
||||||
uiState.setValue(new State(ButtonState.SUBMIT_DISABLED, mapUsernameError(invalidReason.get())));
|
uiState.update(state -> new State(ButtonState.SUBMIT_DISABLED, mapUsernameError(invalidReason.get()), state.usernameSuffix));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uiState.setValue(new State(ButtonState.SUBMIT_LOADING, UsernameStatus.NONE));
|
uiState.update(state -> new State(ButtonState.SUBMIT_LOADING, UsernameStatus.NONE, state.usernameSuffix));
|
||||||
|
|
||||||
repo.setUsername(username, (result) -> {
|
repo.setUsername(username, (result) -> {
|
||||||
ThreadUtil.runOnMain(() -> {
|
ThreadUtil.runOnMain(() -> {
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case SUCCESS:
|
case SUCCESS:
|
||||||
uiState.setValue(new State(ButtonState.SUBMIT_DISABLED, UsernameStatus.NONE));
|
uiState.update(state -> new State(ButtonState.SUBMIT_DISABLED, UsernameStatus.NONE, state.usernameSuffix));
|
||||||
events.postValue(Event.SUBMIT_SUCCESS);
|
events.postValue(Event.SUBMIT_SUCCESS);
|
||||||
break;
|
break;
|
||||||
case USERNAME_INVALID:
|
case USERNAME_INVALID:
|
||||||
uiState.setValue(new State(ButtonState.SUBMIT_DISABLED, UsernameStatus.INVALID_GENERIC));
|
uiState.update(state -> new State(ButtonState.SUBMIT_DISABLED, UsernameStatus.INVALID_GENERIC, state.usernameSuffix));
|
||||||
events.postValue(Event.SUBMIT_FAIL_INVALID);
|
events.postValue(Event.SUBMIT_FAIL_INVALID);
|
||||||
break;
|
break;
|
||||||
case USERNAME_UNAVAILABLE:
|
case USERNAME_UNAVAILABLE:
|
||||||
uiState.setValue(new State(ButtonState.SUBMIT_DISABLED, UsernameStatus.TAKEN));
|
uiState.update(state -> new State(ButtonState.SUBMIT_DISABLED, UsernameStatus.TAKEN, state.usernameSuffix));
|
||||||
events.postValue(Event.SUBMIT_FAIL_TAKEN);
|
events.postValue(Event.SUBMIT_FAIL_TAKEN);
|
||||||
break;
|
break;
|
||||||
case NETWORK_ERROR:
|
case NETWORK_ERROR:
|
||||||
uiState.setValue(new State(ButtonState.SUBMIT, UsernameStatus.NONE));
|
uiState.update(state -> new State(ButtonState.SUBMIT, UsernameStatus.NONE, state.usernameSuffix));
|
||||||
events.postValue(Event.NETWORK_FAILURE);
|
events.postValue(Event.NETWORK_FAILURE);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -99,17 +97,17 @@ class UsernameEditViewModel extends ViewModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
void onUsernameDeleted() {
|
void onUsernameDeleted() {
|
||||||
uiState.setValue(new State(ButtonState.DELETE_LOADING, UsernameStatus.NONE));
|
uiState.update(state -> new State(ButtonState.DELETE_LOADING, UsernameStatus.NONE, state.usernameSuffix));
|
||||||
|
|
||||||
repo.deleteUsername((result) -> {
|
repo.deleteUsername((result) -> {
|
||||||
ThreadUtil.runOnMain(() -> {
|
ThreadUtil.runOnMain(() -> {
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case SUCCESS:
|
case SUCCESS:
|
||||||
uiState.postValue(new State(ButtonState.DELETE_DISABLED, UsernameStatus.NONE));
|
uiState.update(state -> new State(ButtonState.DELETE_DISABLED, UsernameStatus.NONE, state.usernameSuffix));
|
||||||
events.postValue(Event.DELETE_SUCCESS);
|
events.postValue(Event.DELETE_SUCCESS);
|
||||||
break;
|
break;
|
||||||
case NETWORK_ERROR:
|
case NETWORK_ERROR:
|
||||||
uiState.postValue(new State(ButtonState.DELETE, UsernameStatus.NONE));
|
uiState.update(state -> new State(ButtonState.DELETE, UsernameStatus.NONE, state.usernameSuffix));
|
||||||
events.postValue(Event.NETWORK_FAILURE);
|
events.postValue(Event.NETWORK_FAILURE);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -117,8 +115,8 @@ class UsernameEditViewModel extends ViewModel {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull LiveData<State> getUiState() {
|
@NonNull Flowable<State> getUiState() {
|
||||||
return uiState;
|
return uiState.getStateFlowable().observeOn(AndroidSchedulers.mainThread());
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull LiveData<Event> getEvents() {
|
@NonNull LiveData<Event> getEvents() {
|
||||||
|
@ -138,12 +136,15 @@ class UsernameEditViewModel extends ViewModel {
|
||||||
static class State {
|
static class State {
|
||||||
private final ButtonState buttonState;
|
private final ButtonState buttonState;
|
||||||
private final UsernameStatus usernameStatus;
|
private final UsernameStatus usernameStatus;
|
||||||
|
private final UsernameSuffix usernameSuffix;
|
||||||
|
|
||||||
private State(@NonNull ButtonState buttonState,
|
private State(@NonNull ButtonState buttonState,
|
||||||
@NonNull UsernameStatus usernameStatus)
|
@NonNull UsernameStatus usernameStatus,
|
||||||
|
@NonNull UsernameSuffix usernameSuffix)
|
||||||
{
|
{
|
||||||
this.buttonState = buttonState;
|
this.buttonState = buttonState;
|
||||||
this.usernameStatus = usernameStatus;
|
this.usernameStatus = usernameStatus;
|
||||||
|
this.usernameSuffix = usernameSuffix;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull ButtonState getButtonState() {
|
@NonNull ButtonState getButtonState() {
|
||||||
|
@ -153,6 +154,10 @@ class UsernameEditViewModel extends ViewModel {
|
||||||
@NonNull UsernameStatus getUsernameStatus() {
|
@NonNull UsernameStatus getUsernameStatus() {
|
||||||
return usernameStatus;
|
return usernameStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull UsernameSuffix getUsernameSuffix() {
|
||||||
|
return usernameSuffix;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum UsernameStatus {
|
enum UsernameStatus {
|
||||||
|
|
|
@ -0,0 +1,120 @@
|
||||||
|
package org.thoughtcrime.securesms.profiles.manage
|
||||||
|
|
||||||
|
import android.content.ActivityNotFoundException
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.core.app.ShareCompat
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.fragment.app.setFragmentResult
|
||||||
|
import androidx.navigation.fragment.findNavController
|
||||||
|
import org.signal.core.util.DimensionUnit
|
||||||
|
import org.thoughtcrime.securesms.R
|
||||||
|
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
|
||||||
|
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
|
||||||
|
import org.thoughtcrime.securesms.components.settings.DSLSettingsBottomSheetFragment
|
||||||
|
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
|
||||||
|
import org.thoughtcrime.securesms.components.settings.configure
|
||||||
|
import org.thoughtcrime.securesms.recipients.Recipient
|
||||||
|
import org.thoughtcrime.securesms.util.FragmentResultContract
|
||||||
|
import org.thoughtcrime.securesms.util.LifecycleDisposable
|
||||||
|
import org.thoughtcrime.securesms.util.Util
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows the user to either share their username directly or to copy it to their clipboard.
|
||||||
|
*/
|
||||||
|
class UsernameShareBottomSheet : DSLSettingsBottomSheetFragment() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val REQUEST_KEY = "copy_username"
|
||||||
|
}
|
||||||
|
|
||||||
|
private val lifecycleDisposable = LifecycleDisposable()
|
||||||
|
|
||||||
|
override fun bindAdapter(adapter: DSLSettingsAdapter) {
|
||||||
|
CopyButton.register(adapter)
|
||||||
|
ShareButton.register(adapter)
|
||||||
|
|
||||||
|
lifecycleDisposable += Recipient.observable(Recipient.self().id).subscribe {
|
||||||
|
adapter.submitList(getConfiguration(it).toMappingModelList())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getConfiguration(recipient: Recipient): DSLConfiguration {
|
||||||
|
return configure {
|
||||||
|
noPadTextPref(
|
||||||
|
title = DSLSettingsText.from(
|
||||||
|
R.string.UsernameShareBottomSheet__copy_or_share_a_username_link,
|
||||||
|
DSLSettingsText.TextAppearanceModifier(R.style.Signal_Text_BodyMedium),
|
||||||
|
DSLSettingsText.CenterModifier,
|
||||||
|
DSLSettingsText.ColorModifier(
|
||||||
|
ContextCompat.getColor(requireContext(), R.color.signal_colorOnSurfaceVariant),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
space(DimensionUnit.DP.toPixels(32f).toInt())
|
||||||
|
|
||||||
|
val username = recipient.username.get()
|
||||||
|
customPref(
|
||||||
|
CopyButton.Model(
|
||||||
|
text = username,
|
||||||
|
onClick = {
|
||||||
|
copyToClipboard(it)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
space(DimensionUnit.DP.toPixels(20f).toInt())
|
||||||
|
|
||||||
|
customPref(
|
||||||
|
CopyButton.Model(
|
||||||
|
text = getString(R.string.signal_me_url, username),
|
||||||
|
onClick = {
|
||||||
|
copyToClipboard(it)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
space(DimensionUnit.DP.toPixels(24f).toInt())
|
||||||
|
|
||||||
|
customPref(
|
||||||
|
ShareButton.Model(
|
||||||
|
text = getString(R.string.signal_me_url, username),
|
||||||
|
onClick = {
|
||||||
|
openShareSheet(it.text)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
space(DimensionUnit.DP.toPixels(18f).toInt())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun copyToClipboard(model: CopyButton.Model) {
|
||||||
|
Util.copyToClipboard(requireContext(), model.text)
|
||||||
|
setFragmentResult(REQUEST_KEY, Bundle().apply { putBoolean(REQUEST_KEY, true) })
|
||||||
|
findNavController().popBackStack()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun openShareSheet(charSequence: CharSequence) {
|
||||||
|
val mimeType = Intent.normalizeMimeType("text/plain")
|
||||||
|
val shareIntent = ShareCompat.IntentBuilder(requireContext())
|
||||||
|
.setText(charSequence)
|
||||||
|
.setType(mimeType)
|
||||||
|
.createChooserIntent()
|
||||||
|
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||||
|
|
||||||
|
try {
|
||||||
|
startActivity(shareIntent)
|
||||||
|
} catch (e: ActivityNotFoundException) {
|
||||||
|
Toast.makeText(requireContext(), R.string.MediaPreviewActivity_cant_find_an_app_able_to_share_this_media, Toast.LENGTH_LONG).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object ResultContract : FragmentResultContract<Boolean>(REQUEST_KEY) {
|
||||||
|
override fun getResult(bundle: Bundle): Boolean {
|
||||||
|
return bundle.getBoolean(REQUEST_KEY, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
package org.thoughtcrime.securesms.profiles.manage
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import com.google.android.material.progressindicator.CircularProgressIndicatorSpec
|
||||||
|
import com.google.android.material.progressindicator.IndeterminateDrawable
|
||||||
|
import org.signal.core.util.DimensionUnit
|
||||||
|
import org.thoughtcrime.securesms.R
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes the state of the username suffix, which is a spanned CharSequence.
|
||||||
|
*/
|
||||||
|
data class UsernameSuffix(
|
||||||
|
val charSequence: CharSequence?
|
||||||
|
) {
|
||||||
|
|
||||||
|
val isInProgress = charSequence == null
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@JvmField
|
||||||
|
val LOADING = UsernameSuffix(null)
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
val NONE = UsernameSuffix("")
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun fromCode(code: Int) = UsernameSuffix("#$code")
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun getInProgressDrawable(context: Context): IndeterminateDrawable<CircularProgressIndicatorSpec> {
|
||||||
|
val progressIndicatorSpec = CircularProgressIndicatorSpec(context, null).apply {
|
||||||
|
indicatorInset = 0
|
||||||
|
indicatorSize = DimensionUnit.DP.toPixels(16f).toInt()
|
||||||
|
trackColor = ContextCompat.getColor(context, R.color.signal_colorOnSurfaceVariant)
|
||||||
|
trackThickness = DimensionUnit.DP.toPixels(1f).toInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
return IndeterminateDrawable.createCircularDrawable(context, progressIndicatorSpec).apply {
|
||||||
|
setBounds(0, 0, DimensionUnit.DP.toPixels(16f).toInt(), DimensionUnit.DP.toPixels(16f).toInt())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
package org.thoughtcrime.securesms.util
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.fragment.app.FragmentManager
|
||||||
|
import androidx.lifecycle.LifecycleOwner
|
||||||
|
import java.util.function.Consumer
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic Fragment result contract.
|
||||||
|
*/
|
||||||
|
abstract class FragmentResultContract<T> protected constructor(private val resultKey: String) {
|
||||||
|
|
||||||
|
protected abstract fun getResult(bundle: Bundle): T
|
||||||
|
|
||||||
|
fun registerForResult(fragmentManager: FragmentManager, lifecycleOwner: LifecycleOwner, consumer: Consumer<T>) {
|
||||||
|
fragmentManager.setFragmentResultListener(resultKey, lifecycleOwner) { key, bundle ->
|
||||||
|
if (key == resultKey) {
|
||||||
|
val result = getResult(bundle)
|
||||||
|
consumer.accept(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
package org.thoughtcrime.securesms.util.adapter.mapping
|
||||||
|
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.viewbinding.ViewBinding
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows ViewHolders to be generated with a ViewBinding. Intended usage is as follows:
|
||||||
|
*
|
||||||
|
* BindingFactory(::MyBindingViewHolder, MyBinding::inflate)
|
||||||
|
*/
|
||||||
|
class BindingFactory<T : MappingModel<T>, B : ViewBinding>(
|
||||||
|
private val creator: (B) -> BindingViewHolder<T, B>,
|
||||||
|
private val inflater: (LayoutInflater, ViewGroup, Boolean) -> B
|
||||||
|
) : Factory<T> {
|
||||||
|
override fun createViewHolder(parent: ViewGroup): MappingViewHolder<T> {
|
||||||
|
val binding = inflater(LayoutInflater.from(parent.context), parent, false)
|
||||||
|
return creator(binding)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
package org.thoughtcrime.securesms.util.adapter.mapping
|
||||||
|
|
||||||
|
import androidx.viewbinding.ViewBinding
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A ViewHolder which is populated with a ViewBinding, used in conjunction with BindingFactory
|
||||||
|
*/
|
||||||
|
abstract class BindingViewHolder<T, B : ViewBinding>(protected val binding: B) : MappingViewHolder<T>(binding.root)
|
|
@ -13,7 +13,7 @@ import io.reactivex.rxjava3.subjects.PublishSubject
|
||||||
*/
|
*/
|
||||||
class RxStore<T : Any>(
|
class RxStore<T : Any>(
|
||||||
defaultValue: T,
|
defaultValue: T,
|
||||||
private val scheduler: Scheduler = Schedulers.computation()
|
scheduler: Scheduler = Schedulers.computation()
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private val behaviorProcessor = BehaviorProcessor.createDefault(defaultValue)
|
private val behaviorProcessor = BehaviorProcessor.createDefault(defaultValue)
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape android:shape="rectangle" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="@color/signal_colorOutline" />
|
||||||
|
</shape>
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<com.google.android.material.button.MaterialButton 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"
|
||||||
|
style="@style/Signal.Widget.Button.Base.Secondary"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="@dimen/dsl_settings_gutter"
|
||||||
|
android:layout_marginEnd="@dimen/dsl_settings_gutter"
|
||||||
|
android:minHeight="56dp"
|
||||||
|
android:paddingHorizontal="16dp"
|
||||||
|
android:textAlignment="viewStart"
|
||||||
|
android:textColor="@color/signal_colorOnSurface"
|
||||||
|
app:cornerRadius="12dp"
|
||||||
|
app:icon="@drawable/ic_copy_24"
|
||||||
|
app:iconGravity="end"
|
||||||
|
app:iconSize="24dp"
|
||||||
|
app:iconTint="@color/signal_colorOnSurface"
|
||||||
|
app:rippleColor="@color/signal_colorOutline"
|
||||||
|
app:strokeColor="@color/signal_colorOutline_38"
|
||||||
|
app:strokeWidth="1dp"
|
||||||
|
tools:text="maya#2342" />
|
|
@ -1,297 +1,310 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
<ScrollView
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
tools:viewBindingIgnore="true"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<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"
|
|
||||||
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" />
|
|
||||||
|
|
||||||
<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">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/manage_profile_name_icon"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:srcCompat="@drawable/ic_profile_name_24"
|
|
||||||
app:tint="@color/signal_text_primary"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="@id/manage_profile_name"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/manage_profile_name_subtitle"/>
|
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
|
|
||||||
android:id="@+id/manage_profile_name"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="24dp"
|
|
||||||
style="@style/Signal.Text.Body"
|
|
||||||
android:textAlignment="viewStart"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/manage_profile_name_icon"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
tools:text="Peter Parker"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/manage_profile_name_subtitle"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
style="@style/Signal.Text.Preview"
|
|
||||||
android:text="@string/ManageProfileFragment_your_name"
|
|
||||||
android:textColor="@color/signal_text_secondary"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/manage_profile_name"
|
|
||||||
app:layout_constraintStart_toStartOf="@id/manage_profile_name"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:id="@+id/manage_profile_username_container"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content">
|
||||||
android:paddingStart="@dimen/dsl_settings_gutter"
|
|
||||||
android:paddingEnd="@dimen/dsl_settings_gutter"
|
|
||||||
android:paddingTop="16dp"
|
|
||||||
android:paddingBottom="16dp"
|
|
||||||
android:background="?selectableItemBackground"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/manage_profile_name_container">
|
|
||||||
|
|
||||||
<ImageView
|
<androidx.appcompat.widget.Toolbar
|
||||||
android:id="@+id/manage_profile_username_icon"
|
android:id="@+id/toolbar"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="@dimen/signal_m3_toolbar_height"
|
||||||
app:srcCompat="@drawable/ic_at_24"
|
android:minHeight="@dimen/signal_m3_toolbar_height"
|
||||||
app:tint="@color/signal_text_primary"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="@id/manage_profile_username"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/manage_profile_username_subtitle"/>
|
app:navigationIcon="@drawable/ic_arrow_left_24"
|
||||||
|
app:title="@string/CreateProfileActivity__profile" />
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
android:id="@+id/manage_profile_username"
|
android:id="@+id/manage_profile_avatar_background"
|
||||||
android:layout_width="0dp"
|
android:layout_width="80dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="80dp"
|
||||||
android:layout_marginStart="24dp"
|
android:layout_marginTop="16dp"
|
||||||
style="@style/Signal.Text.Body"
|
android:src="@drawable/circle_tintable"
|
||||||
android:textAlignment="viewStart"
|
android:tint="@color/core_grey_05"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toEndOf="@id/manage_profile_username_icon"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintTop_toBottomOf="@id/toolbar"
|
||||||
tools:text="\@spiderman"/>
|
app:layout_goneMarginTop="?attr/actionBarSize" />
|
||||||
|
|
||||||
<TextView
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
android:id="@+id/manage_profile_username_subtitle"
|
android:id="@+id/manage_profile_avatar_placeholder"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="0dp"
|
||||||
style="@style/Signal.Text.Preview"
|
android:layout_marginStart="16dp"
|
||||||
android:text="@string/ManageProfileFragment_your_username"
|
android:layout_marginEnd="16dp"
|
||||||
android:textColor="@color/signal_text_secondary"
|
android:tint="@color/core_grey_75"
|
||||||
app:layout_constraintTop_toBottomOf="@id/manage_profile_username"
|
app:layout_constraintBottom_toBottomOf="@+id/manage_profile_avatar_background"
|
||||||
app:layout_constraintStart_toStartOf="@id/manage_profile_username"
|
app:layout_constraintEnd_toEndOf="@+id/manage_profile_avatar_background"
|
||||||
app:layout_constraintEnd_toEndOf="parent" />
|
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" />
|
||||||
|
|
||||||
|
<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">
|
||||||
|
|
||||||
|
<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/ic_profile_name_24"
|
||||||
|
app:tint="@color/signal_text_primary" />
|
||||||
|
|
||||||
|
<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" />
|
||||||
|
|
||||||
|
<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">
|
||||||
|
|
||||||
|
<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/ic_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/ic_share_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/ic_compose_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/ic_badge_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="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" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</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:paddingStart="@dimen/dsl_settings_gutter"
|
|
||||||
android:paddingEnd="@dimen/dsl_settings_gutter"
|
|
||||||
android:paddingTop="16dp"
|
|
||||||
android:paddingBottom="16dp"
|
|
||||||
android:background="?selectableItemBackground"
|
|
||||||
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:srcCompat="@drawable/ic_compose_24"
|
|
||||||
app:tint="@color/signal_text_primary"
|
|
||||||
app:layout_constraintTop_toTopOf="@id/manage_profile_about"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/manage_profile_about_subtitle"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"/>
|
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
|
|
||||||
android:id="@+id/manage_profile_about"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="24dp"
|
|
||||||
style="@style/Signal.Text.Body"
|
|
||||||
android:textAlignment="viewStart"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/manage_profile_about_icon"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:emoji_forceCustom="true"
|
|
||||||
tools:text="Photographer for the Daily Bugle"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/manage_profile_about_subtitle"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
style="@style/Signal.Text.Preview"
|
|
||||||
android:text="@string/ManageProfileFragment_write_a_few_words_about_yourself"
|
|
||||||
android:textColor="@color/signal_text_secondary"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/manage_profile_about"
|
|
||||||
app:layout_constraintStart_toStartOf="@id/manage_profile_about"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent" />
|
|
||||||
|
|
||||||
</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:paddingStart="@dimen/dsl_settings_gutter"
|
|
||||||
android:paddingEnd="@dimen/dsl_settings_gutter"
|
|
||||||
android:paddingTop="16dp"
|
|
||||||
android:paddingBottom="16dp"
|
|
||||||
android:background="?selectableItemBackground"
|
|
||||||
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:srcCompat="@drawable/ic_badge_24"
|
|
||||||
app:tint="@color/signal_text_primary"
|
|
||||||
app:layout_constraintTop_toTopOf="@id/manage_profile_badges"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/manage_profile_badges"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"/>
|
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
|
|
||||||
android:id="@+id/manage_profile_badges"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="24dp"
|
|
||||||
style="@style/Signal.Text.Body"
|
|
||||||
android:textAlignment="viewStart"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/manage_profile_badges_icon"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
android:text="@string/ManageProfileFragment_badges"
|
|
||||||
app:emoji_forceCustom="true" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.util.views.LearnMoreTextView
|
|
||||||
android:id="@+id/description_text"
|
|
||||||
style="@style/Signal.Text.Preview"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="16dp"
|
|
||||||
android:layout_marginBottom="16dp"
|
|
||||||
android:layout_marginStart="@dimen/dsl_settings_gutter"
|
|
||||||
android:layout_marginEnd="@dimen/dsl_settings_gutter"
|
|
||||||
android:text="@string/CreateProfileActivity_signal_profiles_are_end_to_end_encrypted"
|
|
||||||
android:textColor="@color/signal_colorOnSurfaceVariant"
|
|
||||||
android:textAppearance="@style/Signal.Text.BodyMedium"
|
|
||||||
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" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
<FrameLayout 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:app="http://schemas.android.com/apk/res-auto"
|
||||||
tools:viewBindingIgnore="true"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
@ -37,13 +36,12 @@
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/title"
|
android:id="@+id/title"
|
||||||
style="@style/TextAppearance.Signal.Title2.Bold"
|
style="@style/Signal.Text.TitleLarge"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:layout_marginTop="32dp"
|
android:layout_marginTop="32dp"
|
||||||
android:layout_marginEnd="8dp"
|
android:paddingHorizontal="@dimen/dsl_settings_gutter"
|
||||||
android:text="@string/CreateProfileActivity_set_up_your_profile"
|
android:text="@string/CreateProfileActivity_set_up_your_profile"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintHorizontal_bias="0.5"
|
app:layout_constraintHorizontal_bias="0.5"
|
||||||
|
@ -52,15 +50,28 @@
|
||||||
app:layout_constraintVertical_bias="0.0"
|
app:layout_constraintVertical_bias="0.0"
|
||||||
app:layout_constraintVertical_chainStyle="spread_inside" />
|
app:layout_constraintVertical_chainStyle="spread_inside" />
|
||||||
|
|
||||||
|
<org.thoughtcrime.securesms.util.views.LearnMoreTextView
|
||||||
|
android:id="@+id/profile_description_text"
|
||||||
|
style="@style/Signal.Text.BodyMedium"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="@dimen/dsl_settings_gutter"
|
||||||
|
android:layout_marginTop="11dp"
|
||||||
|
android:layout_marginEnd="@dimen/dsl_settings_gutter"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
android:text="@string/ProfileCreateFragment__profiles_are_only_visible_to_people_you_message"
|
||||||
|
android:textColor="@color/core_grey_60"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/title" />
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatImageView
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
android:id="@+id/avatar_background"
|
android:id="@+id/avatar_background"
|
||||||
android:layout_width="96dp"
|
android:layout_width="72dp"
|
||||||
android:layout_height="96dp"
|
android:layout_height="72dp"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="16dp"
|
||||||
android:src="@drawable/circle_tintable"
|
android:src="@drawable/circle_tintable"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/title"
|
app:layout_constraintTop_toBottomOf="@+id/profile_description_text"
|
||||||
app:layout_goneMarginTop="?attr/actionBarSize" />
|
app:layout_goneMarginTop="?attr/actionBarSize" />
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatImageView
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
|
@ -100,8 +111,8 @@
|
||||||
android:id="@+id/camera_icon"
|
android:id="@+id/camera_icon"
|
||||||
android:layout_width="48dp"
|
android:layout_width="48dp"
|
||||||
android:layout_height="48dp"
|
android:layout_height="48dp"
|
||||||
android:layout_marginStart="56dp"
|
android:layout_marginStart="32dp"
|
||||||
android:layout_marginTop="56dp"
|
android:layout_marginTop="32dp"
|
||||||
android:background="@drawable/circle_tintable_padded"
|
android:background="@drawable/circle_tintable_padded"
|
||||||
android:cropToPadding="false"
|
android:cropToPadding="false"
|
||||||
android:elevation="4dp"
|
android:elevation="4dp"
|
||||||
|
@ -122,66 +133,131 @@
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/name_preview">
|
app:layout_constraintTop_toBottomOf="@+id/name_preview">
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.components.emoji.EmojiEditText
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
android:id="@+id/given_name"
|
android:id="@+id/given_name_wrapper"
|
||||||
style="@style/Signal.Text.Body"
|
style="@style/Widget.Signal.TextInputLayout.FilledBox.ContactNameEditor"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_vertical"
|
|
||||||
android:layout_marginStart="16dp"
|
|
||||||
android:layout_marginTop="13dp"
|
android:layout_marginTop="13dp"
|
||||||
android:layout_marginEnd="16dp"
|
android:hint="@string/CreateProfileActivity_first_name_required">
|
||||||
android:layout_weight="1"
|
|
||||||
android:autofillHints="personGivenName"
|
<org.thoughtcrime.securesms.components.emoji.EmojiEditText
|
||||||
android:hint="@string/CreateProfileActivity_first_name_required"
|
android:id="@+id/given_name"
|
||||||
android:inputType="textPersonName"
|
style="@style/Signal.Text.Body"
|
||||||
android:singleLine="true" />
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:autofillHints="personGivenName"
|
||||||
|
android:inputType="textPersonName"
|
||||||
|
android:singleLine="true" />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/mms_group_hint"
|
android:id="@+id/mms_group_hint"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="20dp"
|
android:layout_marginStart="@dimen/dsl_settings_gutter"
|
||||||
android:layout_marginEnd="20dp"
|
android:layout_marginEnd="@dimen/dsl_settings_gutter"
|
||||||
android:text="@string/CreateProfileActivity_custom_mms_group_names_and_photos_will_only_be_visible_to_you"
|
android:text="@string/CreateProfileActivity_custom_mms_group_names_and_photos_will_only_be_visible_to_you"
|
||||||
android:textAppearance="@style/Signal.Text.Caption"
|
android:textAppearance="@style/Signal.Text.Caption"
|
||||||
android:textColor="@color/signal_text_secondary"
|
android:textColor="@color/signal_text_secondary"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.components.emoji.EmojiEditText
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
android:id="@+id/family_name"
|
android:id="@+id/family_name_wrapper"
|
||||||
style="@style/Signal.Text.Body"
|
style="@style/Widget.Signal.TextInputLayout.FilledBox.ContactNameEditor"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_vertical"
|
|
||||||
android:layout_marginStart="16dp"
|
|
||||||
android:layout_marginTop="13dp"
|
android:layout_marginTop="13dp"
|
||||||
android:layout_marginEnd="16dp"
|
android:hint="@string/CreateProfileActivity_last_name_optional">
|
||||||
android:layout_weight="1"
|
|
||||||
android:autofillHints="personFamilyName"
|
|
||||||
android:hint="@string/CreateProfileActivity_last_name_optional"
|
|
||||||
android:inputType="textPersonName"
|
|
||||||
android:singleLine="true" />
|
|
||||||
|
|
||||||
|
<org.thoughtcrime.securesms.components.emoji.EmojiEditText
|
||||||
|
android:id="@+id/family_name"
|
||||||
|
style="@style/Signal.Text.Body"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:autofillHints="personFamilyName"
|
||||||
|
android:inputType="textPersonName"
|
||||||
|
android:singleLine="true" />
|
||||||
|
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.util.views.LearnMoreTextView
|
<org.thoughtcrime.securesms.util.views.LearnMoreTextView
|
||||||
android:id="@+id/description_text"
|
android:id="@+id/group_description_text"
|
||||||
style="@style/Signal.Text.Preview"
|
style="@style/Signal.Text.BodyMedium"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="@dimen/dsl_settings_gutter"
|
||||||
android:layout_marginTop="11dp"
|
android:layout_marginTop="11dp"
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="@dimen/dsl_settings_gutter"
|
||||||
android:layout_marginBottom="16dp"
|
android:layout_marginBottom="16dp"
|
||||||
android:text="@string/CreateProfileActivity_signal_profiles_are_end_to_end_encrypted"
|
android:text="@string/CreateProfileActivity_group_descriptions_will_be_visible_to_members_of_this_group_and_people_who_have_been_invited"
|
||||||
android:textColor="@color/core_grey_60"
|
android:textColor="@color/core_grey_60"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/name_container"
|
app:layout_constraintTop_toBottomOf="@+id/name_container"
|
||||||
app:layout_constraintVertical_bias="1.0" />
|
app:layout_constraintVertical_bias="1.0" />
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:id="@+id/who_can_find_me_container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="23dp"
|
||||||
|
android:background="?selectableItemBackground"
|
||||||
|
android:minHeight="72dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/group_description_text"
|
||||||
|
tools:visibility="visible">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/who_can_find_me_icon"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_marginStart="@dimen/dsl_settings_gutter"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
android:scaleType="centerInside"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:srcCompat="@drawable/ic_group_24" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/who_can_find_me_title"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="24dp"
|
||||||
|
android:layout_marginEnd="@dimen/dsl_settings_gutter"
|
||||||
|
android:text="@string/ProfileCreateFragment__who_can_find_me"
|
||||||
|
android:textAppearance="@style/Signal.Text.BodyLarge"
|
||||||
|
android:textColor="@color/signal_colorOnSurface"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/who_can_find_me_description"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/who_can_find_me_icon"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintVertical_chainStyle="packed" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/who_can_find_me_description"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="24dp"
|
||||||
|
android:layout_marginEnd="@dimen/dsl_settings_gutter"
|
||||||
|
android:textAppearance="@style/Signal.Text.BodyMedium"
|
||||||
|
android:textColor="@color/signal_colorOnSurfaceVariant"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/who_can_find_me_icon"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/who_can_find_me_title"
|
||||||
|
tools:text="@string/PhoneNumberPrivacy_everyone" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
@ -196,8 +272,8 @@
|
||||||
android:layout_marginEnd="32dp"
|
android:layout_marginEnd="32dp"
|
||||||
android:layout_marginBottom="16dp"
|
android:layout_marginBottom="16dp"
|
||||||
android:enabled="false"
|
android:enabled="false"
|
||||||
app:materialThemeOverlay="@style/ThemeOverlay.Signal.CircularProgressIndicator.Primary"
|
app:circularProgressMaterialButton__label="@string/CreateProfileActivity_next"
|
||||||
app:circularProgressMaterialButton__label="@string/CreateProfileActivity_next" />
|
app:materialThemeOverlay="@style/ThemeOverlay.Signal.CircularProgressIndicator.Primary" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/share_button"
|
||||||
|
style="@style/Signal.Widget.Button.Medium.Tonal"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:text="@string/preferences_share"
|
||||||
|
app:icon="@drawable/ic_share_24"
|
||||||
|
app:iconSize="20dp" />
|
||||||
|
</FrameLayout>
|
|
@ -1,7 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
tools:viewBindingIgnore="true"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
@ -10,59 +9,94 @@
|
||||||
<androidx.appcompat.widget.Toolbar
|
<androidx.appcompat.widget.Toolbar
|
||||||
android:id="@+id/toolbar"
|
android:id="@+id/toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="@dimen/signal_m3_toolbar_height"
|
||||||
|
android:minHeight="@dimen/signal_m3_toolbar_height"
|
||||||
android:visibility="visible"
|
android:visibility="visible"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:navigationIcon="@drawable/ic_arrow_left_24"
|
app:navigationIcon="@drawable/ic_x_24"
|
||||||
app:title="@string/UsernameEditFragment_username" />
|
app:title="@string/UsernameEditFragment_username"
|
||||||
|
app:titleTextAppearance="@style/Signal.Text.TitleLarge" />
|
||||||
|
|
||||||
<EditText
|
<ImageView
|
||||||
android:id="@+id/username_text"
|
android:id="@+id/icon"
|
||||||
style="@style/Signal.Text.Body"
|
android:layout_width="64dp"
|
||||||
android:layout_width="0dp"
|
android:layout_height="64dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_marginTop="32dp"
|
||||||
android:layout_marginStart="16dp"
|
android:background="@drawable/circle_tintable"
|
||||||
android:layout_marginTop="8dp"
|
android:importantForAccessibility="no"
|
||||||
android:layout_marginEnd="16dp"
|
android:padding="14dp"
|
||||||
android:hint="@string/UsernameEditFragment_username"
|
app:backgroundTint="@color/signal_colorSurface2"
|
||||||
android:imeOptions="actionDone"
|
|
||||||
android:importantForAutofill="no"
|
|
||||||
android:inputType="text"
|
|
||||||
android:maxLines="1"
|
|
||||||
android:minHeight="56dp"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/toolbar" />
|
app:layout_constraintTop_toBottomOf="@id/toolbar"
|
||||||
|
app:srcCompat="@drawable/ic_at_24" />
|
||||||
|
|
||||||
<TextView
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
android:id="@+id/username_subtext"
|
android:id="@+id/username_text_wrapper"
|
||||||
style="@style/Signal.Text.Caption"
|
style="@style/Widget.Signal.TextInputLayout.FilledBox.ContactNameEditor"
|
||||||
android:layout_width="0dp"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginTop="24dp"
|
||||||
android:layout_marginTop="16dp"
|
app:boxStrokeColor="@color/signal_colorPrimary"
|
||||||
android:layout_marginEnd="16dp"
|
app:boxStrokeWidthFocused="2dp"
|
||||||
|
app:expandedHintEnabled="false"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/username_text"
|
app:layout_constraintTop_toBottomOf="@id/summary"
|
||||||
tools:text="Some error code" />
|
app:suffixTextColor="@color/signal_colorOnSurface"
|
||||||
|
tools:suffixText="| #1234">
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/username_text"
|
||||||
|
style="@style/Signal.Text.Body"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/UsernameEditFragment_username"
|
||||||
|
android:imeOptions="actionDone"
|
||||||
|
android:importantForAutofill="no"
|
||||||
|
android:inputType="text"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:minHeight="56dp">
|
||||||
|
|
||||||
|
<requestFocus />
|
||||||
|
</EditText>
|
||||||
|
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
android:id="@+id/summary"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="@dimen/dsl_settings_gutter"
|
||||||
|
android:layout_marginTop="12dp"
|
||||||
|
android:layout_marginEnd="@dimen/dsl_settings_gutter"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="@string/UsernameEditFragment__choose_your_username"
|
||||||
|
android:textAppearance="@style/Signal.Text.BodyLarge"
|
||||||
|
android:textColor="@color/signal_colorOnSurfaceVariant"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/icon" />
|
||||||
|
|
||||||
|
<org.thoughtcrime.securesms.util.views.LearnMoreTextView
|
||||||
android:id="@+id/username_description"
|
android:id="@+id/username_description"
|
||||||
style="@style/Signal.Text.Caption"
|
style="@style/Signal.Text.Caption"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="0dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="@dimen/dsl_settings_gutter"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="24dp"
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="@dimen/dsl_settings_gutter"
|
||||||
android:layout_marginBottom="16dp"
|
android:layout_marginBottom="24dp"
|
||||||
android:text="@string/UsernameEditFragment_usernames_on_signal_are_optional"
|
android:text="@string/UsernameEditFragment__usernames_let_others_message"
|
||||||
|
android:textAppearance="@style/Signal.Text.BodyMedium"
|
||||||
|
android:textColor="@color/signal_colorOnSurfaceVariant"
|
||||||
app:layout_constraintBottom_toTopOf="@id/username_button_barrier"
|
app:layout_constraintBottom_toTopOf="@id/username_button_barrier"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/username_subtext" />
|
app:layout_constraintTop_toBottomOf="@id/username_text_wrapper"
|
||||||
|
app:layout_constraintVertical_bias="0" />
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.util.views.CircularProgressMaterialButton
|
<org.thoughtcrime.securesms.util.views.CircularProgressMaterialButton
|
||||||
android:id="@+id/username_submit_button"
|
android:id="@+id/username_submit_button"
|
||||||
|
|
|
@ -37,6 +37,14 @@
|
||||||
app:nullable="true" />
|
app:nullable="true" />
|
||||||
</action>
|
</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>
|
</fragment>
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
|
@ -47,4 +55,10 @@
|
||||||
|
|
||||||
<include app:graph="@navigation/avatar_picker" />
|
<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>
|
</navigation>
|
|
@ -62,6 +62,9 @@
|
||||||
app:exitAnim="@anim/nav_default_exit_anim"
|
app:exitAnim="@anim/nav_default_exit_anim"
|
||||||
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
|
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
|
||||||
app:popExitAnim="@anim/nav_default_pop_exit_anim" />
|
app:popExitAnim="@anim/nav_default_pop_exit_anim" />
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_manageProfileFragment_to_shareUsernameDialog"
|
||||||
|
app:destination="@id/shareUsernameDialog" />
|
||||||
|
|
||||||
</fragment>
|
</fragment>
|
||||||
|
|
||||||
|
@ -87,4 +90,9 @@
|
||||||
|
|
||||||
<include app:graph="@navigation/avatar_picker" />
|
<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>
|
</navigation>
|
|
@ -11,6 +11,7 @@
|
||||||
<string name="sustainer_boost_and_badges" translatable="false">https://support.signal.org/hc/articles/4408365318426</string>
|
<string name="sustainer_boost_and_badges" translatable="false">https://support.signal.org/hc/articles/4408365318426</string>
|
||||||
<string name="google_pay_url" translatable="false">https://pay.google.com</string>
|
<string name="google_pay_url" translatable="false">https://pay.google.com</string>
|
||||||
<string name="donation_decline_code_error_url" translatable="false">https://support.signal.org/hc/articles/4408365318426#errors</string>
|
<string name="donation_decline_code_error_url" translatable="false">https://support.signal.org/hc/articles/4408365318426#errors</string>
|
||||||
|
<string name="signal_me_url" translatable="false">https://signal.me/%1$s</string>
|
||||||
|
|
||||||
<string name="yes">Yes</string>
|
<string name="yes">Yes</string>
|
||||||
<string name="no">No</string>
|
<string name="no">No</string>
|
||||||
|
@ -503,6 +504,20 @@
|
||||||
<string name="CreateProfileActivity_signal_profiles_are_end_to_end_encrypted">Your profile is end-to-end encrypted. Your profile and changes to it will be visible to your contacts, when you initiate or accept new conversations, and when you join new groups.</string>
|
<string name="CreateProfileActivity_signal_profiles_are_end_to_end_encrypted">Your profile is end-to-end encrypted. Your profile and changes to it will be visible to your contacts, when you initiate or accept new conversations, and when you join new groups.</string>
|
||||||
<string name="CreateProfileActivity_set_avatar_description">Set avatar</string>
|
<string name="CreateProfileActivity_set_avatar_description">Set avatar</string>
|
||||||
|
|
||||||
|
<!-- ProfileCreateFragment -->
|
||||||
|
<!-- Displayed at the top of the screen and explains how profiles can be viewed. -->
|
||||||
|
<string name="ProfileCreateFragment__profiles_are_only_visible_to_people_you_message">Profiles are only visible to people you message.</string>
|
||||||
|
<!-- Title of clickable row to select phone number privacy settings -->
|
||||||
|
<string name="ProfileCreateFragment__who_can_find_me">Who can find me by number?</string>
|
||||||
|
|
||||||
|
<!-- WhoCanSeeMyPhoneNumberFragment -->
|
||||||
|
<!-- Toolbar title for this screen -->
|
||||||
|
<string name="WhoCanSeeMyPhoneNumberFragment__who_can_find_me_by_number">Who can find me by number?</string>
|
||||||
|
<!-- Description for radio item stating anyone can see your phone number -->
|
||||||
|
<string name="WhoCanSeeMyPhoneNumberFragment__anyone_who_has">Anyone who has your phone number in their contacts will see you as a contact on Signal. Others will be able to find you with your number in search.</string>
|
||||||
|
<!-- Description for radio item stating no one will be able to see your phone number -->
|
||||||
|
<string name="WhoCanSeeMyPhoneNumberFragment__nobody_on_signal">Nobody on Signal will be able to find you with your phone number.</string>
|
||||||
|
|
||||||
<!-- ChooseBackupFragment -->
|
<!-- ChooseBackupFragment -->
|
||||||
<string name="ChooseBackupFragment__restore_from_backup">Restore from backup?</string>
|
<string name="ChooseBackupFragment__restore_from_backup">Restore from backup?</string>
|
||||||
<string name="ChooseBackupFragment__restore_your_messages_and_media">Restore your messages and media from a local backup. If you don\'t restore now, you won\'t be able to restore later.</string>
|
<string name="ChooseBackupFragment__restore_your_messages_and_media">Restore your messages and media from a local backup. If you don\'t restore now, you won\'t be able to restore later.</string>
|
||||||
|
@ -856,6 +871,11 @@
|
||||||
<string name="ManageProfileFragment_failed_to_set_avatar">Failed to set avatar</string>
|
<string name="ManageProfileFragment_failed_to_set_avatar">Failed to set avatar</string>
|
||||||
<string name="ManageProfileFragment_badges">Badges</string>
|
<string name="ManageProfileFragment_badges">Badges</string>
|
||||||
<string name="ManageProfileFragment__edit_photo">Edit photo</string>
|
<string name="ManageProfileFragment__edit_photo">Edit photo</string>
|
||||||
|
<!-- Snackbar message after creating username -->
|
||||||
|
<string name="ManageProfileFragment__username_created">Username created</string>
|
||||||
|
<!-- Snackbar message after copying username -->
|
||||||
|
<string name="ManageProfileFragment__username_copied">Username copied</string>
|
||||||
|
|
||||||
|
|
||||||
<!-- ManageRecipientActivity -->
|
<!-- ManageRecipientActivity -->
|
||||||
<string name="ManageRecipientActivity_no_groups_in_common">No groups in common</string>
|
<string name="ManageRecipientActivity_no_groups_in_common">No groups in common</string>
|
||||||
|
@ -1851,6 +1871,8 @@
|
||||||
<string name="UnverifiedSendDialog_send">Send</string>
|
<string name="UnverifiedSendDialog_send">Send</string>
|
||||||
|
|
||||||
<!-- UsernameEditFragment -->
|
<!-- UsernameEditFragment -->
|
||||||
|
<!-- Instructional text at the top of the username edit screen -->
|
||||||
|
<string name="UsernameEditFragment__choose_your_username">Choose your username</string>
|
||||||
<string name="UsernameEditFragment_username">Username</string>
|
<string name="UsernameEditFragment_username">Username</string>
|
||||||
<string name="UsernameEditFragment_delete">Delete</string>
|
<string name="UsernameEditFragment_delete">Delete</string>
|
||||||
<string name="UsernameEditFragment_successfully_set_username">Successfully set username.</string>
|
<string name="UsernameEditFragment_successfully_set_username">Successfully set username.</string>
|
||||||
|
@ -1862,13 +1884,21 @@
|
||||||
<string name="UsernameEditFragment_usernames_cannot_begin_with_a_number">Usernames cannot begin with a number.</string>
|
<string name="UsernameEditFragment_usernames_cannot_begin_with_a_number">Usernames cannot begin with a number.</string>
|
||||||
<string name="UsernameEditFragment_username_is_invalid">Username is invalid.</string>
|
<string name="UsernameEditFragment_username_is_invalid">Username is invalid.</string>
|
||||||
<string name="UsernameEditFragment_usernames_must_be_between_a_and_b_characters">Usernames must be between %1$d and %2$d characters.</string>
|
<string name="UsernameEditFragment_usernames_must_be_between_a_and_b_characters">Usernames must be between %1$d and %2$d characters.</string>
|
||||||
<string name="UsernameEditFragment_usernames_on_signal_are_optional">Usernames on Signal are optional. If you choose to create a username, other Signal users will be able to find you by this username and contact you without knowing your phone number.</string>
|
<!-- Explanation about what usernames provide -->
|
||||||
|
<string name="UsernameEditFragment__usernames_let_others_message">Usernames let others message you without needing your phone number. They are paired with a set of digits to help keep your address private.</string>
|
||||||
|
<!-- Dialog title for explanation about numbers at the end of the username -->
|
||||||
|
<string name="UsernameEditFragment__what_is_this_number">What is this number?</string>
|
||||||
|
<string name="UsernameEditFragment__these_digits_help_keep">These digits help keep your username private so you can avoid unwanted messages. Share your username with only the people and groups you\'d like to chat with. If you change usernames you\'ll get a new set of digits.</string>
|
||||||
|
|
||||||
<plurals name="UserNotificationMigrationJob_d_contacts_are_on_signal">
|
<plurals name="UserNotificationMigrationJob_d_contacts_are_on_signal">
|
||||||
<item quantity="one">%d contact is on Signal!</item>
|
<item quantity="one">%d contact is on Signal!</item>
|
||||||
<item quantity="other">%d contacts are on Signal!</item>
|
<item quantity="other">%d contacts are on Signal!</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
|
|
||||||
|
<!-- UsernameShareBottomSheet -->
|
||||||
|
<!-- Explanation of what the sheet enables the user to do -->
|
||||||
|
<string name="UsernameShareBottomSheet__copy_or_share_a_username_link">Copy or share a username link</string>
|
||||||
|
|
||||||
<!-- VerifyIdentityActivity -->
|
<!-- VerifyIdentityActivity -->
|
||||||
<string name="VerifyIdentityActivity_your_contact_is_running_an_old_version_of_signal">Your contact is running an old version of Signal. Please ask them to update before verifying your safety number.</string>
|
<string name="VerifyIdentityActivity_your_contact_is_running_an_old_version_of_signal">Your contact is running an old version of Signal. Please ask them to update before verifying your safety number.</string>
|
||||||
<string name="VerifyIdentityActivity_your_contact_is_running_a_newer_version_of_Signal">Your contact is running a newer version of Signal with an incompatible QR code format. Please update to compare.</string>
|
<string name="VerifyIdentityActivity_your_contact_is_running_a_newer_version_of_Signal">Your contact is running a newer version of Signal with an incompatible QR code format. Please update to compare.</string>
|
||||||
|
|
Ładowanie…
Reference in New Issue