Notify user during group create of members that do not support GV2.
parent
d8daa83c79
commit
845f6a0a93
|
@ -31,6 +31,7 @@ import com.dd.CircularProgressButton;
|
|||
import org.thoughtcrime.securesms.LoggingFragment;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.groups.ui.GroupMemberListView;
|
||||
import org.thoughtcrime.securesms.groups.ui.creategroup.dialogs.NonGv2MemberDialog;
|
||||
import org.thoughtcrime.securesms.mediasend.AvatarSelectionActivity;
|
||||
import org.thoughtcrime.securesms.mediasend.AvatarSelectionBottomSheetDialogFragment;
|
||||
import org.thoughtcrime.securesms.mediasend.Media;
|
||||
|
@ -43,6 +44,7 @@ import org.thoughtcrime.securesms.recipients.RecipientId;
|
|||
import org.thoughtcrime.securesms.util.BitmapUtil;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
import org.thoughtcrime.securesms.util.text.AfterTextChanged;
|
||||
import org.thoughtcrime.securesms.util.views.LearnMoreTextView;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
@ -90,6 +92,7 @@ public class AddGroupDetailsFragment extends LoggingFragment {
|
|||
GroupMemberListView members = view.findViewById(R.id.member_list);
|
||||
ImageView avatar = view.findViewById(R.id.group_avatar);
|
||||
View mmsWarning = view.findViewById(R.id.mms_warning);
|
||||
LearnMoreTextView gv2Warning = view.findViewById(R.id.gv2_warning);
|
||||
|
||||
avatarPlaceholder = VectorDrawableCompat.create(getResources(), R.drawable.ic_camera_outline_32_ultramarine, requireActivity().getTheme());
|
||||
|
||||
|
@ -118,6 +121,12 @@ public class AddGroupDetailsFragment extends LoggingFragment {
|
|||
avatar.setVisibility(isMms ? View.GONE : View.VISIBLE);
|
||||
toolbar.setTitle(isMms ? R.string.AddGroupDetailsFragment__create_group : R.string.AddGroupDetailsFragment__name_this_group);
|
||||
});
|
||||
viewModel.getNonGv2CapableMembers().observe(getViewLifecycleOwner(), nonGv2CapableMembers -> {
|
||||
gv2Warning.setVisibility(nonGv2CapableMembers.isEmpty() ? View.GONE : View.VISIBLE);
|
||||
gv2Warning.setText(requireContext().getResources().getQuantityString(R.plurals.AddGroupDetailsFragment__d_members_do_not_support_new_groups, nonGv2CapableMembers.size(), nonGv2CapableMembers.size()));
|
||||
gv2Warning.setLearnMoreVisible(true);
|
||||
gv2Warning.setOnLinkClickListener(v -> NonGv2MemberDialog.showNonGv2Members(requireContext(), nonGv2CapableMembers));
|
||||
});
|
||||
viewModel.getAvatar().observe(getViewLifecycleOwner(), avatarBytes -> {
|
||||
if (avatarBytes == null) {
|
||||
avatar.setImageDrawable(new InsetDrawable(avatarPlaceholder, ViewUtil.dpToPx(AVATAR_PLACEHOLDER_INSET_DP)));
|
||||
|
|
|
@ -4,6 +4,7 @@ import android.content.Context;
|
|||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.WorkerThread;
|
||||
import androidx.core.util.Consumer;
|
||||
|
||||
import com.annimon.stream.Stream;
|
||||
|
@ -11,7 +12,9 @@ import com.annimon.stream.Stream;
|
|||
import org.thoughtcrime.securesms.groups.GroupChangeBusyException;
|
||||
import org.thoughtcrime.securesms.groups.GroupChangeException;
|
||||
import org.thoughtcrime.securesms.groups.GroupManager;
|
||||
import org.thoughtcrime.securesms.groups.GroupsV2CapabilityChecker;
|
||||
import org.thoughtcrime.securesms.groups.ui.GroupMemberEntry;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;
|
||||
|
@ -25,6 +28,8 @@ import java.util.Set;
|
|||
|
||||
final class AddGroupDetailsRepository {
|
||||
|
||||
private static final String TAG = Log.tag(AddGroupDetailsRepository.class);
|
||||
|
||||
private final Context context;
|
||||
|
||||
AddGroupDetailsRepository(@NonNull Context context) {
|
||||
|
@ -65,4 +70,17 @@ final class AddGroupDetailsRepository {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
List<Recipient> checkCapabilities(@NonNull Collection<RecipientId> newPotentialMemberList) {
|
||||
try {
|
||||
GroupsV2CapabilityChecker.refreshCapabilitiesIfNecessary(Recipient.resolvedList(newPotentialMemberList));
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, "Could not get latest profiles for users, using known gv2 capability state", e);
|
||||
}
|
||||
|
||||
return Stream.of(Recipient.resolvedList(newPotentialMemberList))
|
||||
.filter(m -> m.getGroupsV2Capability() != Recipient.Capability.SUPPORTED)
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,12 +13,16 @@ import androidx.lifecycle.ViewModelProvider;
|
|||
import com.annimon.stream.Collectors;
|
||||
import com.annimon.stream.Stream;
|
||||
|
||||
import org.thoughtcrime.securesms.groups.GroupsV2CapabilityChecker;
|
||||
import org.thoughtcrime.securesms.groups.ui.GroupMemberEntry;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.DefaultValueLiveData;
|
||||
import org.thoughtcrime.securesms.util.SingleLiveEvent;
|
||||
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
@ -35,6 +39,7 @@ public final class AddGroupDetailsViewModel extends ViewModel {
|
|||
private final LiveData<Boolean> isMms;
|
||||
private final LiveData<Boolean> canSubmitForm;
|
||||
private final AddGroupDetailsRepository repository;
|
||||
private final LiveData<List<Recipient>> nonGv2CapableMembers;
|
||||
|
||||
private AddGroupDetailsViewModel(@NonNull Collection<RecipientId> recipientIds,
|
||||
@NonNull AddGroupDetailsRepository repository)
|
||||
|
@ -44,9 +49,11 @@ public final class AddGroupDetailsViewModel extends ViewModel {
|
|||
MutableLiveData<List<GroupMemberEntry.NewGroupCandidate>> initialMembers = new MutableLiveData<>();
|
||||
|
||||
LiveData<Boolean> isValidName = Transformations.map(name, name -> !TextUtils.isEmpty(name));
|
||||
members = LiveDataUtil.combineLatest(initialMembers, deleted, AddGroupDetailsViewModel::filterDeletedMembers);
|
||||
isMms = Transformations.map(members, AddGroupDetailsViewModel::isAnyForcedSms);
|
||||
canSubmitForm = LiveDataUtil.combineLatest(isMms, isValidName, (mms, validName) -> mms || validName);
|
||||
|
||||
members = LiveDataUtil.combineLatest(initialMembers, deleted, AddGroupDetailsViewModel::filterDeletedMembers);
|
||||
nonGv2CapableMembers = LiveDataUtil.mapAsync(members, memberList -> repository.checkCapabilities(Stream.of(memberList).map(newGroupCandidate -> newGroupCandidate.getMember().getId()).toList()));
|
||||
isMms = Transformations.map(members, AddGroupDetailsViewModel::isAnyForcedSms);
|
||||
canSubmitForm = LiveDataUtil.combineLatest(isMms, isValidName, (mms, validName) -> mms || validName);
|
||||
|
||||
repository.resolveMembers(recipientIds, initialMembers::postValue);
|
||||
}
|
||||
|
@ -71,6 +78,10 @@ public final class AddGroupDetailsViewModel extends ViewModel {
|
|||
return isMms;
|
||||
}
|
||||
|
||||
@NonNull LiveData<List<Recipient>> getNonGv2CapableMembers() {
|
||||
return nonGv2CapableMembers;
|
||||
}
|
||||
|
||||
void setAvatar(@Nullable byte[] avatar) {
|
||||
this.avatar.setValue(avatar);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
package org.thoughtcrime.securesms.groups.ui.creategroup.dialogs;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.groups.ui.GroupMemberEntry;
|
||||
import org.thoughtcrime.securesms.groups.ui.GroupMemberListView;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public final class NonGv2MemberDialog {
|
||||
|
||||
private NonGv2MemberDialog() {
|
||||
}
|
||||
|
||||
public static @Nullable Dialog showNonGv2Members(@NonNull Context context, @NonNull List<Recipient> recipients) {
|
||||
int size = recipients.size();
|
||||
if (size == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(context)
|
||||
// TODO: GV2 Need a URL for learn more
|
||||
// .setNegativeButton(R.string.NonGv2MemberDialog_learn_more, (dialog, which) -> {
|
||||
// })
|
||||
.setPositiveButton(android.R.string.ok, null);
|
||||
if (size == 1) {
|
||||
builder.setMessage(context.getString(R.string.NonGv2MemberDialog_single_users_are_non_gv2_capable, recipients.get(0).getDisplayName(context)));
|
||||
} else {
|
||||
builder.setMessage(context.getResources().getQuantityString(R.plurals.NonGv2MemberDialog_d_users_are_non_gv2_capable, size, size))
|
||||
.setView(R.layout.dialog_multiple_members_non_gv2_capable);
|
||||
}
|
||||
|
||||
Dialog dialog = builder.show();
|
||||
if (size > 1) {
|
||||
GroupMemberListView nonGv2CapableMembers = dialog.findViewById(R.id.list_non_gv2_members);
|
||||
|
||||
List<GroupMemberEntry.NewGroupCandidate> pendingMembers = new ArrayList<>(recipients.size());
|
||||
for (Recipient r : recipients) {
|
||||
pendingMembers.add(new GroupMemberEntry.NewGroupCandidate(r));
|
||||
}
|
||||
|
||||
//noinspection ConstantConditions
|
||||
nonGv2CapableMembers.setMembers(pendingMembers);
|
||||
}
|
||||
|
||||
return dialog;
|
||||
}
|
||||
}
|
|
@ -54,10 +54,28 @@
|
|||
android:textAppearance="@style/TextAppearance.Signal.Body2"
|
||||
android:textColor="@color/white"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toTopOf="@id/member_list_header"
|
||||
app:layout_constraintBottom_toTopOf="@id/gv2_warning"
|
||||
app:layout_constraintTop_toBottomOf="@id/group_avatar"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<org.thoughtcrime.securesms.util.views.LearnMoreTextView
|
||||
android:id="@+id/gv2_warning"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:background="?secondary_background"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:textAppearance="@style/TextAppearance.Signal.Body2"
|
||||
android:textColor="?title_text_color_secondary"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toTopOf="@id/member_list_header"
|
||||
app:layout_constraintTop_toBottomOf="@id/mms_warning"
|
||||
tools:text="8 members do not support New Groups, so this group will be a Legacy Group. Learn more"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/member_list_header"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -68,7 +86,7 @@
|
|||
android:textAlignment="viewStart"
|
||||
android:textAppearance="@style/TextAppearance.Signal.Subtitle2"
|
||||
android:textColor="?attr/title_text_color_secondary"
|
||||
app:layout_constraintTop_toBottomOf="@id/mms_warning"
|
||||
app:layout_constraintTop_toBottomOf="@id/gv2_warning"
|
||||
app:layout_goneMarginTop="30dp" />
|
||||
|
||||
<org.thoughtcrime.securesms.groups.ui.GroupMemberListView
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout 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">
|
||||
|
||||
<org.thoughtcrime.securesms.groups.ui.GroupMemberListView
|
||||
android:id="@+id/list_non_gv2_members"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="16dp"
|
||||
android:scrollIndicators="top|bottom"
|
||||
android:scrollbars="vertical"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:maxHeight="180dp" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -525,6 +525,17 @@
|
|||
<string name="AddGroupDetailsFragment__remove">Remove</string>
|
||||
<string name="AddGroupDetailsFragment__sms_contact">SMS contact</string>
|
||||
<string name="AddGroupDetailsFragment__remove_s_from_this_group">Remove %1$s from this group?</string>
|
||||
<plurals name="AddGroupDetailsFragment__d_members_do_not_support_new_groups">
|
||||
<item quantity="one">%d member does not support New Groups, so this will be a Legacy Group.</item>
|
||||
<item quantity="other">%d members do not support New Groups, so this group will be a Legacy Group.</item>
|
||||
</plurals>
|
||||
|
||||
<!-- NonGv2MemberDialog -->
|
||||
<string name="NonGv2MemberDialog_single_users_are_non_gv2_capable">A Legacy Group will be created because “%1$s” is using an old version of Signal. You can create a New Style Group with them after they update Signal, or remove them before creating the group.</string>
|
||||
<plurals name="NonGv2MemberDialog_d_users_are_non_gv2_capable">
|
||||
<item quantity="one">A Legacy Group will be created because %1$d member is using an old version of Signal. You can create a New Style Group with them after they update Signal, or remove them before creating the group.</item>
|
||||
<item quantity="other">A Legacy Group will be created because %1$d members are using an old version of Signal. You can create a New Style Group with them after they update Signal, or remove them before creating the group.</item>
|
||||
</plurals>
|
||||
|
||||
<!-- ManageGroupActivity -->
|
||||
<string name="ManageGroupActivity_disappearing_messages">Disappearing messages</string>
|
||||
|
|
Loading…
Reference in New Issue