mirror of
https://github.com/oxen-io/session-android.git
synced 2025-06-08 20:38:33 +00:00
Notify user during group create of members that do not support GV2.
This commit is contained in:
parent
d8daa83c79
commit
845f6a0a93
@ -31,6 +31,7 @@ import com.dd.CircularProgressButton;
|
|||||||
import org.thoughtcrime.securesms.LoggingFragment;
|
import org.thoughtcrime.securesms.LoggingFragment;
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
import org.thoughtcrime.securesms.groups.ui.GroupMemberListView;
|
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.AvatarSelectionActivity;
|
||||||
import org.thoughtcrime.securesms.mediasend.AvatarSelectionBottomSheetDialogFragment;
|
import org.thoughtcrime.securesms.mediasend.AvatarSelectionBottomSheetDialogFragment;
|
||||||
import org.thoughtcrime.securesms.mediasend.Media;
|
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.BitmapUtil;
|
||||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||||
import org.thoughtcrime.securesms.util.text.AfterTextChanged;
|
import org.thoughtcrime.securesms.util.text.AfterTextChanged;
|
||||||
|
import org.thoughtcrime.securesms.util.views.LearnMoreTextView;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -90,6 +92,7 @@ public class AddGroupDetailsFragment extends LoggingFragment {
|
|||||||
GroupMemberListView members = view.findViewById(R.id.member_list);
|
GroupMemberListView members = view.findViewById(R.id.member_list);
|
||||||
ImageView avatar = view.findViewById(R.id.group_avatar);
|
ImageView avatar = view.findViewById(R.id.group_avatar);
|
||||||
View mmsWarning = view.findViewById(R.id.mms_warning);
|
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());
|
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);
|
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 -> {
|
||||||
|
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 -> {
|
viewModel.getAvatar().observe(getViewLifecycleOwner(), avatarBytes -> {
|
||||||
if (avatarBytes == null) {
|
if (avatarBytes == null) {
|
||||||
avatar.setImageDrawable(new InsetDrawable(avatarPlaceholder, ViewUtil.dpToPx(AVATAR_PLACEHOLDER_INSET_DP)));
|
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.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.annotation.WorkerThread;
|
||||||
import androidx.core.util.Consumer;
|
import androidx.core.util.Consumer;
|
||||||
|
|
||||||
import com.annimon.stream.Stream;
|
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.GroupChangeBusyException;
|
||||||
import org.thoughtcrime.securesms.groups.GroupChangeException;
|
import org.thoughtcrime.securesms.groups.GroupChangeException;
|
||||||
import org.thoughtcrime.securesms.groups.GroupManager;
|
import org.thoughtcrime.securesms.groups.GroupManager;
|
||||||
|
import org.thoughtcrime.securesms.groups.GroupsV2CapabilityChecker;
|
||||||
import org.thoughtcrime.securesms.groups.ui.GroupMemberEntry;
|
import org.thoughtcrime.securesms.groups.ui.GroupMemberEntry;
|
||||||
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||||
import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;
|
import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;
|
||||||
@ -25,6 +28,8 @@ import java.util.Set;
|
|||||||
|
|
||||||
final class AddGroupDetailsRepository {
|
final class AddGroupDetailsRepository {
|
||||||
|
|
||||||
|
private static final String TAG = Log.tag(AddGroupDetailsRepository.class);
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
|
|
||||||
AddGroupDetailsRepository(@NonNull 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.Collectors;
|
||||||
import com.annimon.stream.Stream;
|
import com.annimon.stream.Stream;
|
||||||
|
|
||||||
|
import org.thoughtcrime.securesms.groups.GroupsV2CapabilityChecker;
|
||||||
import org.thoughtcrime.securesms.groups.ui.GroupMemberEntry;
|
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.recipients.RecipientId;
|
||||||
import org.thoughtcrime.securesms.util.DefaultValueLiveData;
|
import org.thoughtcrime.securesms.util.DefaultValueLiveData;
|
||||||
import org.thoughtcrime.securesms.util.SingleLiveEvent;
|
import org.thoughtcrime.securesms.util.SingleLiveEvent;
|
||||||
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
|
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -35,6 +39,7 @@ public final class AddGroupDetailsViewModel extends ViewModel {
|
|||||||
private final LiveData<Boolean> isMms;
|
private final LiveData<Boolean> isMms;
|
||||||
private final LiveData<Boolean> canSubmitForm;
|
private final LiveData<Boolean> canSubmitForm;
|
||||||
private final AddGroupDetailsRepository repository;
|
private final AddGroupDetailsRepository repository;
|
||||||
|
private final LiveData<List<Recipient>> nonGv2CapableMembers;
|
||||||
|
|
||||||
private AddGroupDetailsViewModel(@NonNull Collection<RecipientId> recipientIds,
|
private AddGroupDetailsViewModel(@NonNull Collection<RecipientId> recipientIds,
|
||||||
@NonNull AddGroupDetailsRepository repository)
|
@NonNull AddGroupDetailsRepository repository)
|
||||||
@ -44,9 +49,11 @@ public final class AddGroupDetailsViewModel extends ViewModel {
|
|||||||
MutableLiveData<List<GroupMemberEntry.NewGroupCandidate>> initialMembers = new MutableLiveData<>();
|
MutableLiveData<List<GroupMemberEntry.NewGroupCandidate>> initialMembers = new MutableLiveData<>();
|
||||||
|
|
||||||
LiveData<Boolean> isValidName = Transformations.map(name, name -> !TextUtils.isEmpty(name));
|
LiveData<Boolean> isValidName = Transformations.map(name, name -> !TextUtils.isEmpty(name));
|
||||||
members = LiveDataUtil.combineLatest(initialMembers, deleted, AddGroupDetailsViewModel::filterDeletedMembers);
|
|
||||||
isMms = Transformations.map(members, AddGroupDetailsViewModel::isAnyForcedSms);
|
members = LiveDataUtil.combineLatest(initialMembers, deleted, AddGroupDetailsViewModel::filterDeletedMembers);
|
||||||
canSubmitForm = LiveDataUtil.combineLatest(isMms, isValidName, (mms, validName) -> mms || validName);
|
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);
|
repository.resolveMembers(recipientIds, initialMembers::postValue);
|
||||||
}
|
}
|
||||||
@ -71,6 +78,10 @@ public final class AddGroupDetailsViewModel extends ViewModel {
|
|||||||
return isMms;
|
return isMms;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull LiveData<List<Recipient>> getNonGv2CapableMembers() {
|
||||||
|
return nonGv2CapableMembers;
|
||||||
|
}
|
||||||
|
|
||||||
void setAvatar(@Nullable byte[] avatar) {
|
void setAvatar(@Nullable byte[] avatar) {
|
||||||
this.avatar.setValue(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:textAppearance="@style/TextAppearance.Signal.Body2"
|
||||||
android:textColor="@color/white"
|
android:textColor="@color/white"
|
||||||
android:visibility="gone"
|
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"
|
app:layout_constraintTop_toBottomOf="@id/group_avatar"
|
||||||
tools:visibility="visible" />
|
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
|
<TextView
|
||||||
android:id="@+id/member_list_header"
|
android:id="@+id/member_list_header"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@ -68,7 +86,7 @@
|
|||||||
android:textAlignment="viewStart"
|
android:textAlignment="viewStart"
|
||||||
android:textAppearance="@style/TextAppearance.Signal.Subtitle2"
|
android:textAppearance="@style/TextAppearance.Signal.Subtitle2"
|
||||||
android:textColor="?attr/title_text_color_secondary"
|
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" />
|
app:layout_goneMarginTop="30dp" />
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.groups.ui.GroupMemberListView
|
<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__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>
|
||||||
|
<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 -->
|
<!-- ManageGroupActivity -->
|
||||||
<string name="ManageGroupActivity_disappearing_messages">Disappearing messages</string>
|
<string name="ManageGroupActivity_disappearing_messages">Disappearing messages</string>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user