mirror of
https://github.com/oxen-io/session-android.git
synced 2025-06-08 22:08:32 +00:00
Show reminder banner to administrators for pending group join requests.
This commit is contained in:
parent
b46589cd14
commit
837ed76f85
@ -0,0 +1,44 @@
|
|||||||
|
package org.thoughtcrime.securesms.components.reminder;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import org.thoughtcrime.securesms.R;
|
||||||
|
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||||
|
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||||
|
import org.thoughtcrime.securesms.util.PlayStoreUtil;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shown to admins when there are pending group join requests.
|
||||||
|
*/
|
||||||
|
public final class PendingGroupJoinRequestsReminder extends Reminder {
|
||||||
|
|
||||||
|
private PendingGroupJoinRequestsReminder(@Nullable CharSequence title,
|
||||||
|
@NonNull CharSequence text)
|
||||||
|
{
|
||||||
|
super(title, text);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Reminder create(@NonNull Context context, int count) {
|
||||||
|
String message = context.getResources().getQuantityString(R.plurals.PendingGroupJoinRequestsReminder_d_pending_member_requests, count, count);
|
||||||
|
Reminder reminder = new PendingGroupJoinRequestsReminder(null, message);
|
||||||
|
|
||||||
|
reminder.addAction(new Action(context.getString(R.string.PendingGroupJoinRequestsReminder_view), R.id.reminder_action_review_join_requests));
|
||||||
|
|
||||||
|
return reminder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDismissable() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NonNull Importance getImportance() {
|
||||||
|
return Importance.NORMAL;
|
||||||
|
}
|
||||||
|
}
|
@ -74,7 +74,7 @@ public abstract class Reminder {
|
|||||||
NORMAL, ERROR, TERMINAL
|
NORMAL, ERROR, TERMINAL
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class Action {
|
public static final class Action {
|
||||||
private final CharSequence title;
|
private final CharSequence title;
|
||||||
private final int actionId;
|
private final int actionId;
|
||||||
|
|
||||||
|
@ -115,6 +115,7 @@ import org.thoughtcrime.securesms.components.identity.UnverifiedBannerView;
|
|||||||
import org.thoughtcrime.securesms.components.location.SignalPlace;
|
import org.thoughtcrime.securesms.components.location.SignalPlace;
|
||||||
import org.thoughtcrime.securesms.components.mention.MentionAnnotation;
|
import org.thoughtcrime.securesms.components.mention.MentionAnnotation;
|
||||||
import org.thoughtcrime.securesms.components.reminder.ExpiredBuildReminder;
|
import org.thoughtcrime.securesms.components.reminder.ExpiredBuildReminder;
|
||||||
|
import org.thoughtcrime.securesms.components.reminder.PendingGroupJoinRequestsReminder;
|
||||||
import org.thoughtcrime.securesms.components.reminder.Reminder;
|
import org.thoughtcrime.securesms.components.reminder.Reminder;
|
||||||
import org.thoughtcrime.securesms.components.reminder.ReminderView;
|
import org.thoughtcrime.securesms.components.reminder.ReminderView;
|
||||||
import org.thoughtcrime.securesms.components.reminder.ServiceOutageReminder;
|
import org.thoughtcrime.securesms.components.reminder.ServiceOutageReminder;
|
||||||
@ -162,6 +163,7 @@ import org.thoughtcrime.securesms.groups.ui.GroupChangeFailureReason;
|
|||||||
import org.thoughtcrime.securesms.groups.ui.GroupChangeResult;
|
import org.thoughtcrime.securesms.groups.ui.GroupChangeResult;
|
||||||
import org.thoughtcrime.securesms.groups.ui.GroupErrors;
|
import org.thoughtcrime.securesms.groups.ui.GroupErrors;
|
||||||
import org.thoughtcrime.securesms.groups.ui.LeaveGroupDialog;
|
import org.thoughtcrime.securesms.groups.ui.LeaveGroupDialog;
|
||||||
|
import org.thoughtcrime.securesms.groups.ui.invitesandrequests.ManagePendingAndRequestingMembersActivity;
|
||||||
import org.thoughtcrime.securesms.groups.ui.managegroup.ManageGroupActivity;
|
import org.thoughtcrime.securesms.groups.ui.managegroup.ManageGroupActivity;
|
||||||
import org.thoughtcrime.securesms.insights.InsightsLauncher;
|
import org.thoughtcrime.securesms.insights.InsightsLauncher;
|
||||||
import org.thoughtcrime.securesms.invites.InviteReminderModel;
|
import org.thoughtcrime.securesms.invites.InviteReminderModel;
|
||||||
@ -444,6 +446,7 @@ public class ConversationActivity extends PassphraseRequiredActivity
|
|||||||
initializeGroupViewModel();
|
initializeGroupViewModel();
|
||||||
initializeMentionsViewModel();
|
initializeMentionsViewModel();
|
||||||
initializeEnabledCheck();
|
initializeEnabledCheck();
|
||||||
|
initializePendingRequestsBanner();
|
||||||
initializeSecurity(recipient.get().isRegistered(), isDefaultSms).addListener(new AssertedSuccessListener<Boolean>() {
|
initializeSecurity(recipient.get().isRegistered(), isDefaultSms).addListener(new AssertedSuccessListener<Boolean>() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(Boolean result) {
|
public void onSuccess(Boolean result) {
|
||||||
@ -1525,6 +1528,11 @@ public class ConversationActivity extends PassphraseRequiredActivity
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void initializePendingRequestsBanner() {
|
||||||
|
groupViewModel.getActionableRequestingMembers()
|
||||||
|
.observe(this, actionablePendingGroupRequests -> updateReminders());
|
||||||
|
}
|
||||||
|
|
||||||
private ListenableFuture<Boolean> initializeDraftFromDatabase() {
|
private ListenableFuture<Boolean> initializeDraftFromDatabase() {
|
||||||
SettableFuture<Boolean> future = new SettableFuture<>();
|
SettableFuture<Boolean> future = new SettableFuture<>();
|
||||||
|
|
||||||
@ -1679,6 +1687,7 @@ public class ConversationActivity extends PassphraseRequiredActivity
|
|||||||
|
|
||||||
protected void updateReminders() {
|
protected void updateReminders() {
|
||||||
Optional<Reminder> inviteReminder = inviteReminderModel.getReminder();
|
Optional<Reminder> inviteReminder = inviteReminderModel.getReminder();
|
||||||
|
Integer actionableRequestingMembers = groupViewModel.getActionableRequestingMembers().getValue();
|
||||||
|
|
||||||
if (UnauthorizedReminder.isEligible(this)) {
|
if (UnauthorizedReminder.isEligible(this)) {
|
||||||
reminderView.get().showReminder(new UnauthorizedReminder(this));
|
reminderView.get().showReminder(new UnauthorizedReminder(this));
|
||||||
@ -1696,6 +1705,13 @@ public class ConversationActivity extends PassphraseRequiredActivity
|
|||||||
reminderView.get().setOnActionClickListener(this::handleReminderAction);
|
reminderView.get().setOnActionClickListener(this::handleReminderAction);
|
||||||
reminderView.get().setOnDismissListener(() -> inviteReminderModel.dismissReminder());
|
reminderView.get().setOnDismissListener(() -> inviteReminderModel.dismissReminder());
|
||||||
reminderView.get().showReminder(inviteReminder.get());
|
reminderView.get().showReminder(inviteReminder.get());
|
||||||
|
} else if (actionableRequestingMembers != null && actionableRequestingMembers > 0 && FeatureFlags.groupsV2manageGroupLinks()) {
|
||||||
|
reminderView.get().showReminder(PendingGroupJoinRequestsReminder.create(this, actionableRequestingMembers));
|
||||||
|
reminderView.get().setOnActionClickListener(id -> {
|
||||||
|
if (id == R.id.reminder_action_review_join_requests) {
|
||||||
|
startActivity(ManagePendingAndRequestingMembersActivity.newIntent(this, getRecipient().getGroupId().get().requireV2()));
|
||||||
|
}
|
||||||
|
});
|
||||||
} else if (reminderView.resolved()) {
|
} else if (reminderView.resolved()) {
|
||||||
reminderView.get().hide();
|
reminderView.get().hide();
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ import org.thoughtcrime.securesms.groups.GroupManager;
|
|||||||
import org.thoughtcrime.securesms.groups.ui.GroupChangeFailureReason;
|
import org.thoughtcrime.securesms.groups.ui.GroupChangeFailureReason;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.util.AsynchronousCallback;
|
import org.thoughtcrime.securesms.util.AsynchronousCallback;
|
||||||
|
import org.thoughtcrime.securesms.util.FeatureFlags;
|
||||||
import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;
|
import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;
|
||||||
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
|
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
|
||||||
|
|
||||||
@ -30,6 +31,7 @@ final class ConversationGroupViewModel extends ViewModel {
|
|||||||
private final MutableLiveData<Recipient> liveRecipient;
|
private final MutableLiveData<Recipient> liveRecipient;
|
||||||
private final LiveData<GroupActiveState> groupActiveState;
|
private final LiveData<GroupActiveState> groupActiveState;
|
||||||
private final LiveData<GroupDatabase.MemberLevel> selfMembershipLevel;
|
private final LiveData<GroupDatabase.MemberLevel> selfMembershipLevel;
|
||||||
|
private final LiveData<Integer> actionableRequestingMembers;
|
||||||
|
|
||||||
private ConversationGroupViewModel() {
|
private ConversationGroupViewModel() {
|
||||||
this.liveRecipient = new MutableLiveData<>();
|
this.liveRecipient = new MutableLiveData<>();
|
||||||
@ -38,12 +40,20 @@ final class ConversationGroupViewModel extends ViewModel {
|
|||||||
|
|
||||||
this.groupActiveState = Transformations.distinctUntilChanged(Transformations.map(groupRecord, ConversationGroupViewModel::mapToGroupActiveState));
|
this.groupActiveState = Transformations.distinctUntilChanged(Transformations.map(groupRecord, ConversationGroupViewModel::mapToGroupActiveState));
|
||||||
this.selfMembershipLevel = Transformations.distinctUntilChanged(Transformations.map(groupRecord, ConversationGroupViewModel::mapToSelfMembershipLevel));
|
this.selfMembershipLevel = Transformations.distinctUntilChanged(Transformations.map(groupRecord, ConversationGroupViewModel::mapToSelfMembershipLevel));
|
||||||
|
this.actionableRequestingMembers = Transformations.distinctUntilChanged(Transformations.map(groupRecord, ConversationGroupViewModel::mapToActionableRequestingMemberCount));
|
||||||
}
|
}
|
||||||
|
|
||||||
void onRecipientChange(Recipient recipient) {
|
void onRecipientChange(Recipient recipient) {
|
||||||
liveRecipient.setValue(recipient);
|
liveRecipient.setValue(recipient);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of pending group join requests that can be actioned by this client.
|
||||||
|
*/
|
||||||
|
LiveData<Integer> getActionableRequestingMembers() {
|
||||||
|
return actionableRequestingMembers;
|
||||||
|
}
|
||||||
|
|
||||||
LiveData<GroupActiveState> getGroupActiveState() {
|
LiveData<GroupActiveState> getGroupActiveState() {
|
||||||
return groupActiveState;
|
return groupActiveState;
|
||||||
}
|
}
|
||||||
@ -62,6 +72,20 @@ final class ConversationGroupViewModel extends ViewModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int mapToActionableRequestingMemberCount(@Nullable GroupRecord record) {
|
||||||
|
if (record != null &&
|
||||||
|
FeatureFlags.groupsV2manageGroupLinks() &&
|
||||||
|
record.isV2Group() &&
|
||||||
|
record.memberLevel(Recipient.self()) == GroupDatabase.MemberLevel.ADMINISTRATOR)
|
||||||
|
{
|
||||||
|
return record.requireV2GroupProperties()
|
||||||
|
.getDecryptedGroup()
|
||||||
|
.getRequestingMembersCount();
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static GroupActiveState mapToGroupActiveState(@Nullable GroupRecord record) {
|
private static GroupActiveState mapToGroupActiveState(@Nullable GroupRecord record) {
|
||||||
if (record == null) {
|
if (record == null) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -7,4 +7,5 @@
|
|||||||
<item name="reminder_action_view_insights" type="id" />
|
<item name="reminder_action_view_insights" type="id" />
|
||||||
<item name="reminder_action_invite" type="id" />
|
<item name="reminder_action_invite" type="id" />
|
||||||
<item name="reminder_action_update_now" type="id" />
|
<item name="reminder_action_update_now" type="id" />
|
||||||
|
<item name="reminder_action_review_join_requests" type="id" />
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -435,6 +435,13 @@
|
|||||||
<string name="ExpiredBuildReminder_this_version_of_signal_has_expired">This version of Signal has expired. Update now to send and receive messages.</string>
|
<string name="ExpiredBuildReminder_this_version_of_signal_has_expired">This version of Signal has expired. Update now to send and receive messages.</string>
|
||||||
<string name="ExpiredBuildReminder_update_now">Update now</string>
|
<string name="ExpiredBuildReminder_update_now">Update now</string>
|
||||||
|
|
||||||
|
<!-- PendingGroupJoinRequestsReminder -->
|
||||||
|
<plurals name="PendingGroupJoinRequestsReminder_d_pending_member_requests">
|
||||||
|
<item quantity="one">%d pending member request.</item>
|
||||||
|
<item quantity="many">%d pending member requests.</item>
|
||||||
|
</plurals>
|
||||||
|
<string name="PendingGroupJoinRequestsReminder_view">View</string>
|
||||||
|
|
||||||
<!-- ShareActivity -->
|
<!-- ShareActivity -->
|
||||||
<string name="ShareActivity_share_with">Share with</string>
|
<string name="ShareActivity_share_with">Share with</string>
|
||||||
<string name="ShareActivity_multiple_attachments_are_only_supported">Multiple attachments are only supported for images and videos</string>
|
<string name="ShareActivity_multiple_attachments_are_only_supported">Multiple attachments are only supported for images and videos</string>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user