mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-26 19:56:02 +01:00
Join group via invite link.
This commit is contained in:
@@ -227,6 +227,7 @@ import org.thoughtcrime.securesms.stickers.StickerLocator;
|
||||
import org.thoughtcrime.securesms.stickers.StickerManagementActivity;
|
||||
import org.thoughtcrime.securesms.stickers.StickerPackInstallEvent;
|
||||
import org.thoughtcrime.securesms.stickers.StickerSearchRepository;
|
||||
import org.thoughtcrime.securesms.util.AsynchronousCallback;
|
||||
import org.thoughtcrime.securesms.util.Base64;
|
||||
import org.thoughtcrime.securesms.util.BitmapUtil;
|
||||
import org.thoughtcrime.securesms.util.CharacterCalculator.CharacterState;
|
||||
@@ -356,6 +357,8 @@ public class ConversationActivity extends PassphraseRequiredActivity
|
||||
private InputPanel inputPanel;
|
||||
private View panelParent;
|
||||
private View noLongerMemberBanner;
|
||||
private View requestingMemberBanner;
|
||||
private View cancelJoinRequest;
|
||||
private Stub<View> mentionsSuggestions;
|
||||
|
||||
private LinkPreviewViewModel linkPreviewViewModel;
|
||||
@@ -383,12 +386,21 @@ public class ConversationActivity extends PassphraseRequiredActivity
|
||||
long threadId,
|
||||
int distributionType,
|
||||
int startingPosition)
|
||||
{
|
||||
Intent intent = buildIntent(context, recipientId, threadId);
|
||||
intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, distributionType);
|
||||
intent.putExtra(ConversationActivity.STARTING_POSITION_EXTRA, startingPosition);
|
||||
|
||||
return intent;
|
||||
}
|
||||
|
||||
public static @NonNull Intent buildIntent(@NonNull Context context,
|
||||
@NonNull RecipientId recipientId,
|
||||
long threadId)
|
||||
{
|
||||
Intent intent = new Intent(context, ConversationActivity.class);
|
||||
intent.putExtra(ConversationActivity.RECIPIENT_EXTRA, recipientId);
|
||||
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, threadId);
|
||||
intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, distributionType);
|
||||
intent.putExtra(ConversationActivity.STARTING_POSITION_EXTRA, startingPosition);
|
||||
|
||||
return intent;
|
||||
}
|
||||
@@ -1452,14 +1464,64 @@ public class ConversationActivity extends PassphraseRequiredActivity
|
||||
}
|
||||
|
||||
private void initializeEnabledCheck() {
|
||||
groupViewModel.getGroupActiveState().observe(this, state -> {
|
||||
boolean inactivePushGroup = state != null && isPushGroupConversation() && !state.isActiveGroup();
|
||||
boolean enabled = !inactivePushGroup;
|
||||
noLongerMemberBanner.setVisibility(enabled ? View.GONE : View.VISIBLE);
|
||||
inputPanel.setVisibility(enabled ? View.VISIBLE : View.GONE);
|
||||
inputPanel.setEnabled(enabled);
|
||||
sendButton.setEnabled(enabled);
|
||||
attachButton.setEnabled(enabled);
|
||||
groupViewModel.getSelfMemberLevel().observe(this, selfMemberShip -> {
|
||||
boolean canSendMessages;
|
||||
boolean leftGroup;
|
||||
boolean canCancelRequest;
|
||||
|
||||
if (selfMemberShip == null) {
|
||||
leftGroup = false;
|
||||
canSendMessages = true;
|
||||
canCancelRequest = false;
|
||||
} else {
|
||||
switch (selfMemberShip) {
|
||||
case NOT_A_MEMBER:
|
||||
leftGroup = true;
|
||||
canSendMessages = false;
|
||||
canCancelRequest = false;
|
||||
break;
|
||||
case PENDING_MEMBER:
|
||||
leftGroup = false;
|
||||
canSendMessages = false;
|
||||
canCancelRequest = false;
|
||||
break;
|
||||
case REQUESTING_MEMBER:
|
||||
leftGroup = false;
|
||||
canSendMessages = false;
|
||||
canCancelRequest = true;
|
||||
break;
|
||||
case FULL_MEMBER:
|
||||
case ADMINISTRATOR:
|
||||
leftGroup = false;
|
||||
canSendMessages = true;
|
||||
canCancelRequest = false;
|
||||
break;
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
noLongerMemberBanner.setVisibility(leftGroup ? View.VISIBLE : View.GONE);
|
||||
requestingMemberBanner.setVisibility(canCancelRequest ? View.VISIBLE : View.GONE);
|
||||
if (canCancelRequest) {
|
||||
cancelJoinRequest.setOnClickListener(v -> ConversationGroupViewModel.onCancelJoinRequest(getRecipient(), new AsynchronousCallback.MainThread<Void, GroupChangeFailureReason>() {
|
||||
@Override
|
||||
public void onComplete(@Nullable Void result) {
|
||||
Log.d(TAG, "Cancel request complete");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(@Nullable GroupChangeFailureReason error) {
|
||||
Log.d(TAG, "Cancel join request failed " + error);
|
||||
Toast.makeText(ConversationActivity.this, GroupErrors.getUserDisplayMessage(error), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}.toWorkerCallback()));
|
||||
}
|
||||
|
||||
inputPanel.setVisibility(canSendMessages ? View.VISIBLE : View.GONE);
|
||||
inputPanel.setEnabled(canSendMessages);
|
||||
sendButton.setEnabled(canSendMessages);
|
||||
attachButton.setEnabled(canSendMessages);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1754,7 +1816,9 @@ public class ConversationActivity extends PassphraseRequiredActivity
|
||||
ImageButton quickCameraToggle = ViewUtil.findById(this, R.id.quick_camera_toggle);
|
||||
ImageButton inlineAttachmentButton = ViewUtil.findById(this, R.id.inline_attachment_button);
|
||||
|
||||
noLongerMemberBanner = findViewById(R.id.conversation_no_longer_member_banner);
|
||||
noLongerMemberBanner = findViewById(R.id.conversation_no_longer_member_banner);
|
||||
requestingMemberBanner = findViewById(R.id.conversation_requesting_banner);
|
||||
cancelJoinRequest = findViewById(R.id.conversation_cancel_request);
|
||||
|
||||
container.addOnKeyboardShownListener(this);
|
||||
inputPanel.setListener(this);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.thoughtcrime.securesms.conversation;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
@@ -54,6 +55,7 @@ public class ConversationBannerView extends ConstraintLayout {
|
||||
|
||||
public void setSubtitle(@Nullable CharSequence subtitle) {
|
||||
contactSubtitle.setText(subtitle);
|
||||
contactSubtitle.setVisibility(TextUtils.isEmpty(subtitle) ? GONE : VISIBLE);
|
||||
}
|
||||
|
||||
public void setDescription(@Nullable CharSequence description) {
|
||||
|
||||
@@ -77,8 +77,8 @@ import org.thoughtcrime.securesms.conversation.ConversationAdapter.ItemClickList
|
||||
import org.thoughtcrime.securesms.conversation.ConversationAdapter.StickyHeaderViewHolder;
|
||||
import org.thoughtcrime.securesms.conversation.ConversationMessage.ConversationMessageFactory;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||
import org.thoughtcrime.securesms.database.MessageDatabase;
|
||||
import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
||||
import org.thoughtcrime.securesms.database.SmsDatabase;
|
||||
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord;
|
||||
@@ -402,9 +402,11 @@ public class ConversationFragment extends LoggingFragment {
|
||||
conversationBanner.setSubtitle(context.getResources()
|
||||
.getQuantityString(R.plurals.MessageRequestProfileView_members_and_invited, memberCount,
|
||||
memberCount, pendingMemberCount));
|
||||
} else {
|
||||
} else if (memberCount > 0) {
|
||||
conversationBanner.setSubtitle(context.getResources().getQuantityString(R.plurals.MessageRequestProfileView_members, memberCount,
|
||||
memberCount));
|
||||
} else {
|
||||
conversationBanner.setSubtitle(null);
|
||||
}
|
||||
} else if (isSelf) {
|
||||
conversationBanner.setSubtitle(context.getString(R.string.ConversationFragment__you_can_add_notes_for_yourself_in_this_conversation));
|
||||
|
||||
@@ -14,18 +14,30 @@ import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||
import org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.groups.GroupChangeBusyException;
|
||||
import org.thoughtcrime.securesms.groups.GroupChangeFailedException;
|
||||
import org.thoughtcrime.securesms.groups.GroupManager;
|
||||
import org.thoughtcrime.securesms.groups.ui.GroupChangeFailureReason;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.AsynchronousCallback;
|
||||
import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;
|
||||
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
|
||||
|
||||
class ConversationGroupViewModel extends ViewModel {
|
||||
import java.io.IOException;
|
||||
|
||||
private final MutableLiveData<Recipient> liveRecipient;
|
||||
private final LiveData<GroupActiveState> groupActiveState;
|
||||
final class ConversationGroupViewModel extends ViewModel {
|
||||
|
||||
private final MutableLiveData<Recipient> liveRecipient;
|
||||
private final LiveData<GroupActiveState> groupActiveState;
|
||||
private final LiveData<GroupDatabase.MemberLevel> selfMembershipLevel;
|
||||
|
||||
private ConversationGroupViewModel() {
|
||||
liveRecipient = new MutableLiveData<>();
|
||||
LiveData<GroupRecord> groupRecord = LiveDataUtil.mapAsync(liveRecipient, this::getGroupRecordForRecipient);
|
||||
groupActiveState = Transformations.distinctUntilChanged(Transformations.map(groupRecord, this::mapToGroupActiveState));
|
||||
this.liveRecipient = new MutableLiveData<>();
|
||||
|
||||
LiveData<GroupRecord> groupRecord = LiveDataUtil.mapAsync(liveRecipient, ConversationGroupViewModel::getGroupRecordForRecipient);
|
||||
|
||||
this.groupActiveState = Transformations.distinctUntilChanged(Transformations.map(groupRecord, ConversationGroupViewModel::mapToGroupActiveState));
|
||||
this.selfMembershipLevel = Transformations.distinctUntilChanged(Transformations.map(groupRecord, ConversationGroupViewModel::mapToSelfMembershipLevel));
|
||||
}
|
||||
|
||||
void onRecipientChange(Recipient recipient) {
|
||||
@@ -36,7 +48,11 @@ class ConversationGroupViewModel extends ViewModel {
|
||||
return groupActiveState;
|
||||
}
|
||||
|
||||
private GroupRecord getGroupRecordForRecipient(Recipient recipient) {
|
||||
LiveData<GroupDatabase.MemberLevel> getSelfMemberLevel() {
|
||||
return selfMembershipLevel;
|
||||
}
|
||||
|
||||
private static @Nullable GroupRecord getGroupRecordForRecipient(@Nullable Recipient recipient) {
|
||||
if (recipient != null && recipient.isGroup()) {
|
||||
Application context = ApplicationDependencies.getApplication();
|
||||
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
||||
@@ -46,13 +62,37 @@ class ConversationGroupViewModel extends ViewModel {
|
||||
}
|
||||
}
|
||||
|
||||
private GroupActiveState mapToGroupActiveState(@Nullable GroupRecord record) {
|
||||
private static GroupActiveState mapToGroupActiveState(@Nullable GroupRecord record) {
|
||||
if (record == null) {
|
||||
return null;
|
||||
}
|
||||
return new GroupActiveState(record.isActive(), record.isV2Group());
|
||||
}
|
||||
|
||||
private static GroupDatabase.MemberLevel mapToSelfMembershipLevel(@Nullable GroupRecord record) {
|
||||
if (record == null) {
|
||||
return null;
|
||||
}
|
||||
return record.memberLevel(Recipient.self());
|
||||
}
|
||||
|
||||
public static void onCancelJoinRequest(@NonNull Recipient recipient,
|
||||
@NonNull AsynchronousCallback.WorkerThread<Void, GroupChangeFailureReason> callback)
|
||||
{
|
||||
SignalExecutors.UNBOUNDED.execute(() -> {
|
||||
if (!recipient.isPushV2Group()) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
try {
|
||||
GroupManager.cancelJoinRequest(ApplicationDependencies.getApplication(), recipient.getGroupId().get().requireV2());
|
||||
callback.onComplete(null);
|
||||
} catch (GroupChangeFailedException | GroupChangeBusyException | IOException e) {
|
||||
callback.onError(GroupChangeFailureReason.fromException(e));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static final class GroupActiveState {
|
||||
private final boolean isActive;
|
||||
private final boolean isActiveV2;
|
||||
|
||||
Reference in New Issue
Block a user