mirror of
https://github.com/oxen-io/session-android.git
synced 2025-08-26 02:38:01 +00:00
Allow setting local group names and avatars for MMS groups.
This commit is contained in:
@@ -30,6 +30,7 @@ import org.thoughtcrime.securesms.recipients.RecipientId;
|
|||||||
import org.thoughtcrime.securesms.tracing.Trace;
|
import org.thoughtcrime.securesms.tracing.Trace;
|
||||||
import org.thoughtcrime.securesms.util.CursorUtil;
|
import org.thoughtcrime.securesms.util.CursorUtil;
|
||||||
import org.thoughtcrime.securesms.util.SqlUtil;
|
import org.thoughtcrime.securesms.util.SqlUtil;
|
||||||
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupUtil;
|
import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupUtil;
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer;
|
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer;
|
||||||
@@ -38,7 +39,6 @@ import org.whispersystems.signalservice.api.util.UuidUtil;
|
|||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -254,7 +254,7 @@ public final class GroupDatabase extends Database {
|
|||||||
.requireMms();
|
.requireMms();
|
||||||
} else {
|
} else {
|
||||||
GroupId.Mms groupId = GroupId.createMms(new SecureRandom());
|
GroupId.Mms groupId = GroupId.createMms(new SecureRandom());
|
||||||
create(groupId, members);
|
create(groupId, null, members);
|
||||||
return groupId;
|
return groupId;
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
@@ -364,9 +364,10 @@ public final class GroupDatabase extends Database {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void create(@NonNull GroupId.Mms groupId,
|
public void create(@NonNull GroupId.Mms groupId,
|
||||||
|
@Nullable String title,
|
||||||
@NonNull Collection<RecipientId> members)
|
@NonNull Collection<RecipientId> members)
|
||||||
{
|
{
|
||||||
create(groupId, null, members, null, null, null, null);
|
create(groupId, Util.isEmpty(title) ? null : title, members, null, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public GroupId.V2 create(@NonNull GroupMasterKey groupMasterKey,
|
public GroupId.V2 create(@NonNull GroupMasterKey groupMasterKey,
|
||||||
@@ -575,6 +576,18 @@ public final class GroupDatabase extends Database {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void updateTitle(@NonNull GroupId.V1 groupId, String title) {
|
public void updateTitle(@NonNull GroupId.V1 groupId, String title) {
|
||||||
|
updateTitle((GroupId) groupId, title);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateTitle(@NonNull GroupId.Mms groupId, @Nullable String title) {
|
||||||
|
updateTitle((GroupId) groupId, Util.isEmpty(title) ? null : title);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateTitle(@NonNull GroupId groupId, String title) {
|
||||||
|
if (!groupId.isV1() && !groupId.isMms()) {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
|
||||||
ContentValues contentValues = new ContentValues();
|
ContentValues contentValues = new ContentValues();
|
||||||
contentValues.put(TITLE, title);
|
contentValues.put(TITLE, title);
|
||||||
databaseHelper.getWritableDatabase().update(TABLE_NAME, contentValues, GROUP_ID + " = ?",
|
databaseHelper.getWritableDatabase().update(TABLE_NAME, contentValues, GROUP_ID + " = ?",
|
||||||
@@ -587,7 +600,7 @@ public final class GroupDatabase extends Database {
|
|||||||
/**
|
/**
|
||||||
* Used to bust the Glide cache when an avatar changes.
|
* Used to bust the Glide cache when an avatar changes.
|
||||||
*/
|
*/
|
||||||
public void onAvatarUpdated(@NonNull GroupId.Push groupId, boolean hasAvatar) {
|
public void onAvatarUpdated(@NonNull GroupId groupId, boolean hasAvatar) {
|
||||||
ContentValues contentValues = new ContentValues(1);
|
ContentValues contentValues = new ContentValues(1);
|
||||||
contentValues.put(AVATAR_ID, hasAvatar ? Math.abs(new SecureRandom().nextLong()) : 0);
|
contentValues.put(AVATAR_ID, hasAvatar ? Math.abs(new SecureRandom().nextLong()) : 0);
|
||||||
|
|
||||||
@@ -962,7 +975,7 @@ public final class GroupDatabase extends Database {
|
|||||||
}
|
}
|
||||||
return GroupAccessControl.ONLY_ADMINS;
|
return GroupAccessControl.ONLY_ADMINS;
|
||||||
} else {
|
} else {
|
||||||
return id.isV1() ? GroupAccessControl.ALL_MEMBERS : GroupAccessControl.ONLY_ADMINS;
|
return GroupAccessControl.ALL_MEMBERS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -73,13 +73,15 @@ public final class GroupManager {
|
|||||||
try (GroupManagerV2.GroupEditor edit = new GroupManagerV2(context).edit(groupId.requireV2())) {
|
try (GroupManagerV2.GroupEditor edit = new GroupManagerV2(context).edit(groupId.requireV2())) {
|
||||||
return edit.updateGroupTitleAndAvatar(nameChanged ? name : null, avatar, avatarChanged);
|
return edit.updateGroupTitleAndAvatar(nameChanged ? name : null, avatar, avatarChanged);
|
||||||
}
|
}
|
||||||
} else {
|
} else if (groupId.isV1()) {
|
||||||
List<Recipient> members = DatabaseFactory.getGroupDatabase(context)
|
List<Recipient> members = DatabaseFactory.getGroupDatabase(context)
|
||||||
.getGroupMembers(groupId, GroupDatabase.MemberSet.FULL_MEMBERS_EXCLUDING_SELF);
|
.getGroupMembers(groupId, GroupDatabase.MemberSet.FULL_MEMBERS_EXCLUDING_SELF);
|
||||||
|
|
||||||
Set<RecipientId> recipientIds = getMemberIds(new HashSet<>(members));
|
Set<RecipientId> recipientIds = getMemberIds(new HashSet<>(members));
|
||||||
|
|
||||||
return GroupManagerV1.updateGroup(context, groupId.requireV1(), recipientIds, avatar, name, 0);
|
return GroupManagerV1.updateGroup(context, groupId.requireV1(), recipientIds, avatar, name, 0);
|
||||||
|
} else {
|
||||||
|
return GroupManagerV1.updateGroup(context, groupId.requireMms(), avatar, name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -74,7 +74,15 @@ final class GroupManagerV1 {
|
|||||||
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(groupRecipient.getId(), true);
|
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(groupRecipient.getId(), true);
|
||||||
return sendGroupUpdate(context, groupIdV1, memberIds, name, avatarBytes, memberIds.size() - 1);
|
return sendGroupUpdate(context, groupIdV1, memberIds, name, avatarBytes, memberIds.size() - 1);
|
||||||
} else {
|
} else {
|
||||||
groupDatabase.create(groupId.requireMms(), memberIds);
|
groupDatabase.create(groupId.requireMms(), name, memberIds);
|
||||||
|
|
||||||
|
try {
|
||||||
|
AvatarHelper.setAvatar(context, groupRecipientId, avatarBytes != null ? new ByteArrayInputStream(avatarBytes) : null);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.w(TAG, "Failed to save avatar!", e);
|
||||||
|
}
|
||||||
|
groupDatabase.onAvatarUpdated(groupId, avatarBytes != null);
|
||||||
|
|
||||||
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipient, ThreadDatabase.DistributionTypes.CONVERSATION);
|
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipient, ThreadDatabase.DistributionTypes.CONVERSATION);
|
||||||
return new GroupActionResult(groupRecipient, threadId, memberIds.size() - 1, Collections.emptyList());
|
return new GroupActionResult(groupRecipient, threadId, memberIds.size() - 1, Collections.emptyList());
|
||||||
}
|
}
|
||||||
@@ -112,6 +120,28 @@ final class GroupManagerV1 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GroupActionResult updateGroup(@NonNull Context context,
|
||||||
|
@NonNull GroupId.Mms groupId,
|
||||||
|
@Nullable byte[] avatarBytes,
|
||||||
|
@Nullable String name)
|
||||||
|
{
|
||||||
|
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
||||||
|
RecipientId groupRecipientId = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(groupId);
|
||||||
|
Recipient groupRecipient = Recipient.resolved(groupRecipientId);
|
||||||
|
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipient);
|
||||||
|
|
||||||
|
groupDatabase.updateTitle(groupId, name);
|
||||||
|
groupDatabase.onAvatarUpdated(groupId, avatarBytes != null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
AvatarHelper.setAvatar(context, groupRecipientId, avatarBytes != null ? new ByteArrayInputStream(avatarBytes) : null);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.w(TAG, "Failed to save avatar!", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new GroupActionResult(groupRecipient, threadId, 0, Collections.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
private static GroupActionResult sendGroupUpdate(@NonNull Context context,
|
private static GroupActionResult sendGroupUpdate(@NonNull Context context,
|
||||||
@NonNull GroupId.V1 groupId,
|
@NonNull GroupId.V1 groupId,
|
||||||
@NonNull Set<RecipientId> members,
|
@NonNull Set<RecipientId> members,
|
||||||
|
@@ -116,8 +116,7 @@ public class AddGroupDetailsFragment extends LoggingFragment {
|
|||||||
viewModel.getCanSubmitForm().observe(getViewLifecycleOwner(), isFormValid -> setCreateEnabled(isFormValid, true));
|
viewModel.getCanSubmitForm().observe(getViewLifecycleOwner(), isFormValid -> setCreateEnabled(isFormValid, true));
|
||||||
viewModel.getIsMms().observe(getViewLifecycleOwner(), isMms -> {
|
viewModel.getIsMms().observe(getViewLifecycleOwner(), isMms -> {
|
||||||
mmsWarning.setVisibility(isMms ? View.VISIBLE : View.GONE);
|
mmsWarning.setVisibility(isMms ? View.VISIBLE : View.GONE);
|
||||||
name.setVisibility(isMms ? View.GONE : View.VISIBLE);
|
name.setHint(isMms ? R.string.AddGroupDetailsFragment__group_name_optional : R.string.AddGroupDetailsFragment__group_name_required);
|
||||||
avatar.setVisibility(isMms ? View.GONE : View.VISIBLE);
|
|
||||||
toolbar.setTitle(isMms ? R.string.AddGroupDetailsFragment__create_group : R.string.AddGroupDetailsFragment__name_this_group);
|
toolbar.setTitle(isMms ? R.string.AddGroupDetailsFragment__create_group : R.string.AddGroupDetailsFragment__name_this_group);
|
||||||
});
|
});
|
||||||
viewModel.getNonGv2CapableMembers().observe(getViewLifecycleOwner(), nonGv2CapableMembers -> {
|
viewModel.getNonGv2CapableMembers().observe(getViewLifecycleOwner(), nonGv2CapableMembers -> {
|
||||||
|
@@ -48,11 +48,11 @@ final class AddGroupDetailsRepository {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void createPushGroup(@NonNull Set<RecipientId> members,
|
void createGroup(@NonNull Set<RecipientId> members,
|
||||||
@Nullable byte[] avatar,
|
@Nullable byte[] avatar,
|
||||||
@Nullable String name,
|
@Nullable String name,
|
||||||
boolean mms,
|
boolean mms,
|
||||||
Consumer<GroupCreateResult> resultConsumer)
|
Consumer<GroupCreateResult> resultConsumer)
|
||||||
{
|
{
|
||||||
SignalExecutors.BOUNDED.execute(() -> {
|
SignalExecutors.BOUNDED.execute(() -> {
|
||||||
Set<Recipient> recipients = new HashSet<>(Stream.of(members).map(Recipient::resolved).toList());
|
Set<Recipient> recipients = new HashSet<>(Stream.of(members).map(Recipient::resolved).toList());
|
||||||
|
@@ -117,7 +117,7 @@ public final class AddGroupDetailsViewModel extends ViewModel {
|
|||||||
Set<RecipientId> memberIds = Stream.of(members).map(member -> member.getMember().getId()).collect(Collectors.toSet());
|
Set<RecipientId> memberIds = Stream.of(members).map(member -> member.getMember().getId()).collect(Collectors.toSet());
|
||||||
byte[] avatarBytes = avatar.getValue();
|
byte[] avatarBytes = avatar.getValue();
|
||||||
boolean isGroupMms = isMms.getValue() == Boolean.TRUE;
|
boolean isGroupMms = isMms.getValue() == Boolean.TRUE;
|
||||||
String groupName = isGroupMms ? "" : name.getValue();
|
String groupName = name.getValue();
|
||||||
|
|
||||||
if (!isGroupMms && TextUtils.isEmpty(groupName)) {
|
if (!isGroupMms && TextUtils.isEmpty(groupName)) {
|
||||||
groupCreateResult.postValue(GroupCreateResult.error(GroupCreateResult.Error.Type.ERROR_INVALID_NAME));
|
groupCreateResult.postValue(GroupCreateResult.error(GroupCreateResult.Error.Type.ERROR_INVALID_NAME));
|
||||||
@@ -129,11 +129,11 @@ public final class AddGroupDetailsViewModel extends ViewModel {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
repository.createPushGroup(memberIds,
|
repository.createGroup(memberIds,
|
||||||
avatarBytes,
|
avatarBytes,
|
||||||
groupName,
|
groupName,
|
||||||
isGroupMms,
|
isGroupMms,
|
||||||
groupCreateResult::postValue);
|
groupCreateResult::postValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static @NonNull List<GroupMemberEntry.NewGroupCandidate> filterDeletedMembers(@NonNull List<GroupMemberEntry.NewGroupCandidate> members, @NonNull Set<RecipientId> deleted) {
|
private static @NonNull List<GroupMemberEntry.NewGroupCandidate> filterDeletedMembers(@NonNull List<GroupMemberEntry.NewGroupCandidate> members, @NonNull Set<RecipientId> deleted) {
|
||||||
|
@@ -416,7 +416,7 @@ public class ManageGroupFragment extends LoggingFragment {
|
|||||||
|
|
||||||
public boolean onMenuItemSelected(@NonNull MenuItem item) {
|
public boolean onMenuItemSelected(@NonNull MenuItem item) {
|
||||||
if (item.getItemId() == R.id.action_edit) {
|
if (item.getItemId() == R.id.action_edit) {
|
||||||
startActivity(EditProfileActivity.getIntentForGroupProfile(requireActivity(), getGroupId().requirePush()));
|
startActivity(EditProfileActivity.getIntentForGroupProfile(requireActivity(), getGroupId()));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -8,6 +8,7 @@ import androidx.annotation.WorkerThread;
|
|||||||
import androidx.core.util.Consumer;
|
import androidx.core.util.Consumer;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
|
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||||
import org.thoughtcrime.securesms.groups.GroupChangeException;
|
import org.thoughtcrime.securesms.groups.GroupChangeException;
|
||||||
import org.thoughtcrime.securesms.groups.GroupId;
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
import org.thoughtcrime.securesms.groups.GroupManager;
|
import org.thoughtcrime.securesms.groups.GroupManager;
|
||||||
@@ -22,14 +23,14 @@ import org.whispersystems.libsignal.util.guava.Optional;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
class EditPushGroupProfileRepository implements EditProfileRepository {
|
class EditGroupProfileRepository implements EditProfileRepository {
|
||||||
|
|
||||||
private static final String TAG = Log.tag(EditPushGroupProfileRepository.class);
|
private static final String TAG = Log.tag(EditGroupProfileRepository.class);
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final GroupId.Push groupId;
|
private final GroupId groupId;
|
||||||
|
|
||||||
EditPushGroupProfileRepository(@NonNull Context context, @NonNull GroupId.Push groupId) {
|
EditGroupProfileRepository(@NonNull Context context, @NonNull GroupId groupId) {
|
||||||
this.context = context.getApplicationContext();
|
this.context = context.getApplicationContext();
|
||||||
this.groupId = groupId;
|
this.groupId = groupId;
|
||||||
}
|
}
|
||||||
@@ -64,7 +65,18 @@ class EditPushGroupProfileRepository implements EditProfileRepository {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void getCurrentName(@NonNull Consumer<String> nameConsumer) {
|
public void getCurrentName(@NonNull Consumer<String> nameConsumer) {
|
||||||
SimpleTask.run(() -> Recipient.resolved(getRecipientId()).getName(context), nameConsumer::accept);
|
SimpleTask.run(() -> {
|
||||||
|
RecipientId recipientId = getRecipientId();
|
||||||
|
Recipient recipient = Recipient.resolved(recipientId);
|
||||||
|
|
||||||
|
return DatabaseFactory.getGroupDatabase(context)
|
||||||
|
.getGroup(recipientId)
|
||||||
|
.transform(groupRecord -> {
|
||||||
|
String title = groupRecord.getTitle();
|
||||||
|
return title == null ? "" : title;
|
||||||
|
})
|
||||||
|
.or(() -> recipient.getName(context));
|
||||||
|
}, nameConsumer::accept);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
@@ -44,7 +44,7 @@ public class EditProfileActivity extends BaseActivity implements EditProfileFrag
|
|||||||
return intent;
|
return intent;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static @NonNull Intent getIntentForGroupProfile(@NonNull Context context, @NonNull GroupId.Push groupId) {
|
public static @NonNull Intent getIntentForGroupProfile(@NonNull Context context, @NonNull GroupId groupId) {
|
||||||
Intent intent = new Intent(context, EditProfileActivity.class);
|
Intent intent = new Intent(context, EditProfileActivity.class);
|
||||||
intent.putExtra(EditProfileActivity.SHOW_TOOLBAR, true);
|
intent.putExtra(EditProfileActivity.SHOW_TOOLBAR, true);
|
||||||
intent.putExtra(EditProfileActivity.GROUP_ID, groupId.toString());
|
intent.putExtra(EditProfileActivity.GROUP_ID, groupId.toString());
|
||||||
|
@@ -119,11 +119,10 @@ public class EditProfileFragment extends LoggingFragment {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||||
final GroupId groupId = GroupId.parseNullableOrThrow(requireArguments().getString(GROUP_ID, null));
|
GroupId groupId = GroupId.parseNullableOrThrow(requireArguments().getString(GROUP_ID, null));
|
||||||
final GroupId.Push pushGroupId = groupId != null ? groupId.requirePush() : null;
|
|
||||||
|
|
||||||
initializeResources(view, pushGroupId != null);
|
initializeResources(view, groupId);
|
||||||
initializeViewModel(requireArguments().getBoolean(EXCLUDE_SYSTEM, false), pushGroupId, savedInstanceState != null);
|
initializeViewModel(requireArguments().getBoolean(EXCLUDE_SYSTEM, false), groupId, savedInstanceState != null);
|
||||||
initializeProfileAvatar();
|
initializeProfileAvatar();
|
||||||
initializeProfileName();
|
initializeProfileName();
|
||||||
initializeUsername();
|
initializeUsername();
|
||||||
@@ -174,11 +173,11 @@ public class EditProfileFragment extends LoggingFragment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeViewModel(boolean excludeSystem, @Nullable GroupId.Push groupId, boolean hasSavedInstanceState) {
|
private void initializeViewModel(boolean excludeSystem, @Nullable GroupId groupId, boolean hasSavedInstanceState) {
|
||||||
EditProfileRepository repository;
|
EditProfileRepository repository;
|
||||||
|
|
||||||
if (groupId != null) {
|
if (groupId != null) {
|
||||||
repository = new EditPushGroupProfileRepository(requireContext(), groupId);
|
repository = new EditGroupProfileRepository(requireContext(), groupId);
|
||||||
} else {
|
} else {
|
||||||
repository = new EditSelfProfileRepository(requireContext(), excludeSystem);
|
repository = new EditSelfProfileRepository(requireContext(), excludeSystem);
|
||||||
}
|
}
|
||||||
@@ -189,8 +188,9 @@ public class EditProfileFragment extends LoggingFragment {
|
|||||||
.get(EditProfileViewModel.class);
|
.get(EditProfileViewModel.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeResources(@NonNull View view, boolean isEditingGroup) {
|
private void initializeResources(@NonNull View view, @Nullable GroupId groupId) {
|
||||||
Bundle arguments = requireArguments();
|
Bundle arguments = requireArguments();
|
||||||
|
boolean isEditingGroup = groupId != null;
|
||||||
|
|
||||||
this.toolbar = view.findViewById(R.id.toolbar);
|
this.toolbar = view.findViewById(R.id.toolbar);
|
||||||
this.title = view.findViewById(R.id.title);
|
this.title = view.findViewById(R.id.title);
|
||||||
@@ -213,10 +213,13 @@ public class EditProfileFragment extends LoggingFragment {
|
|||||||
|
|
||||||
this.avatar.setOnClickListener(v -> startAvatarSelection());
|
this.avatar.setOnClickListener(v -> startAvatarSelection());
|
||||||
|
|
||||||
this.givenName .addTextChangedListener(new AfterTextChanged(s -> {
|
this.givenName.addTextChangedListener(new AfterTextChanged(s -> {
|
||||||
trimInPlace(s, isEditingGroup);
|
trimInPlace(s, isEditingGroup);
|
||||||
viewModel.setGivenName(s.toString());
|
viewModel.setGivenName(s.toString());
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
view.findViewById(R.id.mms_group_hint)
|
||||||
|
.setVisibility(isEditingGroup && groupId.isMms() ? View.VISIBLE : View.GONE);
|
||||||
|
|
||||||
if (isEditingGroup) {
|
if (isEditingGroup) {
|
||||||
givenName.setHint(R.string.EditProfileFragment__group_name);
|
givenName.setHint(R.string.EditProfileFragment__group_name);
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
package org.thoughtcrime.securesms.profiles.edit;
|
package org.thoughtcrime.securesms.profiles.edit;
|
||||||
|
|
||||||
import androidx.annotation.MainThread;
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.core.util.Consumer;
|
import androidx.core.util.Consumer;
|
||||||
@@ -30,13 +29,15 @@ class EditProfileViewModel extends ViewModel {
|
|||||||
private final MutableLiveData<byte[]> originalAvatar = new MutableLiveData<>();
|
private final MutableLiveData<byte[]> originalAvatar = new MutableLiveData<>();
|
||||||
private final MutableLiveData<Optional<String>> internalUsername = new MutableLiveData<>();
|
private final MutableLiveData<Optional<String>> internalUsername = new MutableLiveData<>();
|
||||||
private final MutableLiveData<String> originalDisplayName = new MutableLiveData<>();
|
private final MutableLiveData<String> originalDisplayName = new MutableLiveData<>();
|
||||||
private final LiveData<Boolean> isFormValid = Transformations.map(trimmedGivenName, s -> s.length() > 0);
|
private final LiveData<Boolean> isFormValid;
|
||||||
private final EditProfileRepository repository;
|
private final EditProfileRepository repository;
|
||||||
private final GroupId groupId;
|
private final GroupId groupId;
|
||||||
|
|
||||||
private EditProfileViewModel(@NonNull EditProfileRepository repository, boolean hasInstanceState, @Nullable GroupId groupId) {
|
private EditProfileViewModel(@NonNull EditProfileRepository repository, boolean hasInstanceState, @Nullable GroupId groupId) {
|
||||||
this.repository = repository;
|
this.repository = repository;
|
||||||
this.groupId = groupId;
|
this.groupId = groupId;
|
||||||
|
this.isFormValid = groupId != null && groupId.isMms() ? LiveDataUtil.just(true)
|
||||||
|
: Transformations.map(trimmedGivenName, s -> s.length() > 0);
|
||||||
|
|
||||||
if (!hasInstanceState) {
|
if (!hasInstanceState) {
|
||||||
if (groupId != null) {
|
if (groupId != null) {
|
||||||
|
@@ -40,23 +40,41 @@
|
|||||||
app:layout_constraintStart_toEndOf="@id/group_avatar"
|
app:layout_constraintStart_toEndOf="@id/group_avatar"
|
||||||
app:layout_constraintTop_toTopOf="@id/group_avatar" />
|
app:layout_constraintTop_toTopOf="@id/group_avatar" />
|
||||||
|
|
||||||
<TextView
|
<LinearLayout
|
||||||
android:id="@+id/mms_warning"
|
android:id="@+id/mms_warning"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="16dp"
|
||||||
android:background="?colorAccent"
|
android:orientation="vertical"
|
||||||
android:paddingStart="16dp"
|
|
||||||
android:paddingTop="8dp"
|
|
||||||
android:paddingEnd="16dp"
|
|
||||||
android:paddingBottom="8dp"
|
|
||||||
android:text="@string/AddGroupDetailsFragment__youve_selected_a_contact_that_doesnt"
|
|
||||||
android:textAppearance="@style/TextAppearance.Signal.Body2"
|
|
||||||
android:textColor="@color/white"
|
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
app:layout_constraintBottom_toTopOf="@id/gv2_warning"
|
app:layout_constraintBottom_toTopOf="@id/gv2_warning"
|
||||||
app:layout_constraintTop_toBottomOf="@id/group_avatar"
|
app:layout_constraintTop_toBottomOf="@id/group_avatar"
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?colorAccent"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:paddingTop="8dp"
|
||||||
|
android:paddingEnd="16dp"
|
||||||
|
android:text="@string/AddGroupDetailsFragment_custom_mms_group_names_and_photos_will_only_be_visible_to_you"
|
||||||
|
android:textAppearance="@style/TextAppearance.Signal.Body2"
|
||||||
|
android:textColor="@color/white" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?colorAccent"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:paddingTop="8dp"
|
||||||
|
android:paddingEnd="16dp"
|
||||||
|
android:paddingBottom="8dp"
|
||||||
|
android:text="@string/AddGroupDetailsFragment__youve_selected_a_contact_that_doesnt"
|
||||||
|
android:textAppearance="@style/TextAppearance.Signal.Body2"
|
||||||
|
android:textColor="@color/white" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.util.views.LearnMoreTextView
|
<org.thoughtcrime.securesms.util.views.LearnMoreTextView
|
||||||
android:id="@+id/gv2_warning"
|
android:id="@+id/gv2_warning"
|
||||||
|
@@ -137,6 +137,18 @@
|
|||||||
android:inputType="textPersonName"
|
android:inputType="textPersonName"
|
||||||
android:singleLine="true" />
|
android:singleLine="true" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/mms_group_hint"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="20dp"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
android:text="@string/CreateProfileActivity_custom_mms_group_names_and_photos_will_only_be_visible_to_you"
|
||||||
|
android:textAppearance="@style/Signal.Text.Caption"
|
||||||
|
android:textColor="@color/signal_text_secondary"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.components.emoji.EmojiEditText
|
<org.thoughtcrime.securesms.components.emoji.EmojiEditText
|
||||||
android:id="@+id/family_name"
|
android:id="@+id/family_name"
|
||||||
style="@style/Signal.Text.Body"
|
style="@style/Signal.Text.Body"
|
||||||
|
@@ -690,11 +690,13 @@
|
|||||||
<string name="AddGroupDetailsFragment__create">Create</string>
|
<string name="AddGroupDetailsFragment__create">Create</string>
|
||||||
<string name="AddGroupDetailsFragment__members">Members</string>
|
<string name="AddGroupDetailsFragment__members">Members</string>
|
||||||
<string name="AddGroupDetailsFragment__group_name_required">Group name (required)</string>
|
<string name="AddGroupDetailsFragment__group_name_required">Group name (required)</string>
|
||||||
|
<string name="AddGroupDetailsFragment__group_name_optional">Group name (optional)</string>
|
||||||
<string name="AddGroupDetailsFragment__this_field_is_required">This field is required.</string>
|
<string name="AddGroupDetailsFragment__this_field_is_required">This field is required.</string>
|
||||||
<string name="AddGroupDetailsFragment__groups_require_at_least_two_members">Groups require at least two members.</string>
|
<string name="AddGroupDetailsFragment__groups_require_at_least_two_members">Groups require at least two members.</string>
|
||||||
<string name="AddGroupDetailsFragment__group_creation_failed">Group creation failed.</string>
|
<string name="AddGroupDetailsFragment__group_creation_failed">Group creation failed.</string>
|
||||||
<string name="AddGroupDetailsFragment__try_again_later">Try again later.</string>
|
<string name="AddGroupDetailsFragment__try_again_later">Try again later.</string>
|
||||||
<string name="AddGroupDetailsFragment__youve_selected_a_contact_that_doesnt">You\'ve selected a contact that doesn\'t support Signal groups, so this group will be MMS.</string>
|
<string name="AddGroupDetailsFragment__youve_selected_a_contact_that_doesnt">You\'ve selected a contact that doesn\'t support Signal groups, so this group will be MMS.</string>
|
||||||
|
<string name="AddGroupDetailsFragment_custom_mms_group_names_and_photos_will_only_be_visible_to_you">Custom MMS group names and photos will only be visible to you.</string>
|
||||||
<string name="AddGroupDetailsFragment__remove">Remove</string>
|
<string name="AddGroupDetailsFragment__remove">Remove</string>
|
||||||
<string name="AddGroupDetailsFragment__sms_contact">SMS contact</string>
|
<string name="AddGroupDetailsFragment__sms_contact">SMS contact</string>
|
||||||
<string name="AddGroupDetailsFragment__remove_s_from_this_group">Remove %1$s from this group?</string>
|
<string name="AddGroupDetailsFragment__remove_s_from_this_group">Remove %1$s from this group?</string>
|
||||||
@@ -2073,6 +2075,7 @@
|
|||||||
<string name="CreateProfileActivity_next">Next</string>
|
<string name="CreateProfileActivity_next">Next</string>
|
||||||
<string name="CreateProfileActivity__username">Username</string>
|
<string name="CreateProfileActivity__username">Username</string>
|
||||||
<string name="CreateProfileActivity__create_a_username">Create a username</string>
|
<string name="CreateProfileActivity__create_a_username">Create a username</string>
|
||||||
|
<string name="CreateProfileActivity_custom_mms_group_names_and_photos_will_only_be_visible_to_you">Custom MMS group names and photos will only be visible to you.</string>
|
||||||
|
|
||||||
<!-- EditProfileFragment -->
|
<!-- EditProfileFragment -->
|
||||||
<string name="EditProfileFragment__edit_group_name_and_photo">Edit group name and photo</string>
|
<string name="EditProfileFragment__edit_group_name_and_photo">Edit group name and photo</string>
|
||||||
|
Reference in New Issue
Block a user