Add support for Group V2 description field.

This commit is contained in:
Cody Henthorne
2021-05-07 13:43:31 -04:00
committed by Greyson Parrelli
parent b3aec58e69
commit 8c9df8d3be
56 changed files with 892 additions and 117 deletions

View File

@@ -78,17 +78,34 @@ class EditGroupProfileRepository implements EditProfileRepository {
}, nameConsumer::accept);
}
@Override
public void getCurrentDescription(@NonNull Consumer<String> descriptionConsumer) {
SimpleTask.run(() -> {
RecipientId recipientId = getRecipientId();
return DatabaseFactory.getGroupDatabase(context)
.getGroup(recipientId)
.transform(groupRecord -> {
String description = groupRecord.getDescription();
return description == null ? "" : description;
})
.or("");
}, descriptionConsumer::accept);
}
@Override
public void uploadProfile(@NonNull ProfileName profileName,
@NonNull String displayName,
boolean displayNameChanged,
@NonNull String description,
boolean descriptionChanged,
@Nullable byte[] avatar,
boolean avatarChanged,
@NonNull Consumer<UploadResult> uploadResultConsumer)
{
SimpleTask.run(() -> {
try {
GroupManager.updateGroupDetails(context, groupId, avatar, avatarChanged, displayName, displayNameChanged);
GroupManager.updateGroupDetails(context, groupId, avatar, avatarChanged, displayName, displayNameChanged, description, descriptionChanged);
return UploadResult.SUCCESS;
} catch (GroupChangeException | IOException e) {

View File

@@ -5,7 +5,7 @@ import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.text.Editable;
import android.text.InputType;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewAnimationUtils;
@@ -35,22 +35,20 @@ import org.thoughtcrime.securesms.mediasend.AvatarSelectionActivity;
import org.thoughtcrime.securesms.mediasend.AvatarSelectionBottomSheetDialogFragment;
import org.thoughtcrime.securesms.mediasend.Media;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.profiles.ProfileName;
import org.thoughtcrime.securesms.profiles.manage.EditProfileNameFragment;
import org.thoughtcrime.securesms.providers.BlobProvider;
import org.thoughtcrime.securesms.registration.RegistrationUtil;
import org.thoughtcrime.securesms.util.CommunicationActions;
import org.thoughtcrime.securesms.util.FeatureFlags;
import org.thoughtcrime.securesms.util.StringUtil;
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
import org.thoughtcrime.securesms.util.text.AfterTextChanged;
import org.thoughtcrime.securesms.util.views.LearnMoreTextView;
import org.whispersystems.libsignal.util.guava.Optional;
import java.io.IOException;
import java.io.InputStream;
import static android.app.Activity.RESULT_OK;
import static org.thoughtcrime.securesms.groups.v2.GroupDescriptionUtil.MAX_DESCRIPTION_LENGTH;
import static org.thoughtcrime.securesms.profiles.edit.EditProfileActivity.EXCLUDE_SYSTEM;
import static org.thoughtcrime.securesms.profiles.edit.EditProfileActivity.GROUP_ID;
import static org.thoughtcrime.securesms.profiles.edit.EditProfileActivity.NEXT_BUTTON_TEXT;
@@ -61,6 +59,8 @@ public class EditProfileFragment extends LoggingFragment {
private static final String TAG = Log.tag(EditProfileFragment.class);
private static final short REQUEST_CODE_SELECT_AVATAR = 31726;
private static final int MAX_DESCRIPTION_GLYPHS = 480;
private static final int MAX_DESCRIPTION_BYTES = 8192;
private Toolbar toolbar;
private View title;
@@ -97,8 +97,8 @@ public class EditProfileFragment extends LoggingFragment {
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
GroupId groupId = GroupId.parseNullableOrThrow(requireArguments().getString(GROUP_ID, null));
initializeResources(view, groupId);
initializeViewModel(requireArguments().getBoolean(EXCLUDE_SYSTEM, false), groupId, savedInstanceState != null);
initializeResources(view, groupId);
initializeProfileAvatar();
initializeProfileName();
}
@@ -183,9 +183,25 @@ public class EditProfileFragment extends LoggingFragment {
givenName.requestFocus();
toolbar.setTitle(R.string.EditProfileFragment__edit_group_name_and_photo);
preview.setVisibility(View.GONE);
familyName.setVisibility(View.GONE);
familyName.setEnabled(false);
view.findViewById(R.id.description_text).setVisibility(View.GONE);
if (FeatureFlags.groupsV2Description()) {
EditTextUtil.addGraphemeClusterLimitFilter(familyName, MAX_DESCRIPTION_GLYPHS);
familyName.addTextChangedListener(new AfterTextChanged(s -> {
EditProfileNameFragment.trimFieldToMaxByteLength(s, MAX_DESCRIPTION_BYTES);
viewModel.setFamilyName(s.toString());
}));
familyName.setHint(R.string.EditProfileFragment__group_description);
familyName.setSingleLine(false);
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);
descriptionText.setLearnMoreVisible(false);
descriptionText.setText(R.string.CreateProfileActivity_group_descriptions_will_be_visible_to_members_of_this_group_and_people_who_have_been_invited);
} else {
familyName.setVisibility(View.GONE);
familyName.setEnabled(false);
view.findViewById(R.id.description_text).setVisibility(View.GONE);
}
view.<ImageView>findViewById(R.id.avatar_placeholder).setImageResource(R.drawable.ic_group_outline_40);
} else {
EditTextUtil.addGraphemeClusterLimitFilter(givenName, EditProfileNameFragment.NAME_MAX_GLYPHS);

View File

@@ -17,9 +17,13 @@ interface EditProfileRepository {
void getCurrentName(@NonNull Consumer<String> nameConsumer);
void getCurrentDescription(@NonNull Consumer<String> descriptionConsumer);
void uploadProfile(@NonNull ProfileName profileName,
@NonNull String displayName,
boolean displayNameChanged,
@NonNull String description,
boolean descriptionChanged,
@Nullable byte[] avatar,
boolean avatarChanged,
@NonNull Consumer<UploadResult> uploadResultConsumer);

View File

@@ -13,24 +13,24 @@ import org.thoughtcrime.securesms.groups.GroupId;
import org.thoughtcrime.securesms.profiles.ProfileName;
import org.thoughtcrime.securesms.util.StringUtil;
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
import org.whispersystems.libsignal.util.guava.Optional;
import java.util.Arrays;
import java.util.Objects;
class EditProfileViewModel extends ViewModel {
private final MutableLiveData<String> givenName = new MutableLiveData<>();
private final MutableLiveData<String> familyName = new MutableLiveData<>();
private final LiveData<String> trimmedGivenName = Transformations.map(givenName, StringUtil::trimToVisualBounds);
private final LiveData<String> trimmedFamilyName = Transformations.map(familyName, StringUtil::trimToVisualBounds);
private final LiveData<ProfileName> internalProfileName = LiveDataUtil.combineLatest(trimmedGivenName, trimmedFamilyName, ProfileName::fromParts);
private final MutableLiveData<byte[]> internalAvatar = new MutableLiveData<>();
private final MutableLiveData<byte[]> originalAvatar = new MutableLiveData<>();
private final MutableLiveData<String> originalDisplayName = new MutableLiveData<>();
private final LiveData<Boolean> isFormValid;
private final EditProfileRepository repository;
private final GroupId groupId;
private final MutableLiveData<String> givenName = new MutableLiveData<>();
private final MutableLiveData<String> familyName = new MutableLiveData<>();
private final LiveData<String> trimmedGivenName = Transformations.map(givenName, StringUtil::trimToVisualBounds);
private final LiveData<String> trimmedFamilyName = Transformations.map(familyName, StringUtil::trimToVisualBounds);
private final LiveData<ProfileName> internalProfileName = LiveDataUtil.combineLatest(trimmedGivenName, trimmedFamilyName, ProfileName::fromParts);
private final MutableLiveData<byte[]> internalAvatar = new MutableLiveData<>();
private final MutableLiveData<byte[]> originalAvatar = new MutableLiveData<>();
private final MutableLiveData<String> originalDisplayName = new MutableLiveData<>();
private final LiveData<Boolean> isFormValid;
private final EditProfileRepository repository;
private final GroupId groupId;
private String originalDescription;
private EditProfileViewModel(@NonNull EditProfileRepository repository, boolean hasInstanceState, @Nullable GroupId groupId) {
this.repository = repository;
@@ -42,6 +42,10 @@ class EditProfileViewModel extends ViewModel {
if (groupId != null) {
repository.getCurrentDisplayName(originalDisplayName::setValue);
repository.getCurrentName(givenName::setValue);
repository.getCurrentDescription(d -> {
originalDescription = d;
familyName.setValue(d);
});
} else {
repository.getCurrentProfileName(name -> {
givenName.setValue(name.getGivenName());
@@ -103,6 +107,7 @@ class EditProfileViewModel extends ViewModel {
public void submitProfile(Consumer<EditProfileRepository.UploadResult> uploadResultConsumer) {
ProfileName profileName = isGroup() ? ProfileName.EMPTY : internalProfileName.getValue();
String displayName = isGroup() ? givenName.getValue() : "";
String description = isGroup() ? familyName.getValue() : "";
if (profileName == null || displayName == null) {
return;
@@ -111,10 +116,13 @@ class EditProfileViewModel extends ViewModel {
byte[] oldAvatar = originalAvatar.getValue();
byte[] newAvatar = internalAvatar.getValue();
String oldDisplayName = isGroup() ? originalDisplayName.getValue() : null;
String oldDescription = isGroup() ? originalDescription : null;
repository.uploadProfile(profileName,
displayName,
!Objects.equals(StringUtil.stripBidiProtection(oldDisplayName), displayName),
description,
!Objects.equals(StringUtil.stripBidiProtection(oldDescription), description),
newAvatar,
!Arrays.equals(oldAvatar, newAvatar),
uploadResultConsumer);

View File

@@ -107,10 +107,16 @@ public class EditSelfProfileRepository implements EditProfileRepository {
nameConsumer.accept("");
}
@Override public void getCurrentDescription(@NonNull Consumer<String> descriptionConsumer) {
descriptionConsumer.accept("");
}
@Override
public void uploadProfile(@NonNull ProfileName profileName,
@NonNull String displayName,
boolean displayNameChanged,
@NonNull String description,
boolean descriptionChanged,
@Nullable byte[] avatar,
boolean avatarChanged,
@NonNull Consumer<UploadResult> uploadResultConsumer)

View File

@@ -104,7 +104,11 @@ public class EditProfileNameFragment extends Fragment {
}
public static void trimFieldToMaxByteLength(Editable s) {
int trimmedLength = StringUtil.trimToFit(s.toString(), ProfileName.MAX_PART_LENGTH).length();
trimFieldToMaxByteLength(s, ProfileName.MAX_PART_LENGTH);
}
public static void trimFieldToMaxByteLength(Editable s, int length) {
int trimmedLength = StringUtil.trimToFit(s.toString(), length).length();
if (s.length() > trimmedLength) {
s.delete(trimmedLength, s.length());