Skip to content

Commit

Permalink
Add pending member activity.
Browse files Browse the repository at this point in the history
  • Loading branch information
alan-signal authored and greyson-signal committed Apr 21, 2020
1 parent ef0f26b commit 1290d0e
Show file tree
Hide file tree
Showing 17 changed files with 699 additions and 2 deletions.
4 changes: 4 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,10 @@
android:windowSoftInputMode="stateVisible"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>

<activity android:name=".groups.ui.pendingmemberinvites.PendingMemberInvitesActivity"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
android:theme="@style/TextSecure.LightNoActionBar" />

<activity android:name=".DatabaseMigrationActivity"
android:theme="@style/NoAnimation.Theme.AppCompat.Light.DarkActionBar"
android:launchMode="singleTask"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@
import org.thoughtcrime.securesms.events.ReminderUpdateEvent;
import org.thoughtcrime.securesms.giph.ui.GiphyActivity;
import org.thoughtcrime.securesms.groups.ui.LeaveGroupDialog;
import org.thoughtcrime.securesms.groups.ui.pendingmemberinvites.PendingMemberInvitesActivity;
import org.thoughtcrime.securesms.insights.InsightsLauncher;
import org.thoughtcrime.securesms.invites.InviteReminderModel;
import org.thoughtcrime.securesms.invites.InviteReminderRepository;
Expand Down Expand Up @@ -730,6 +731,8 @@ public boolean onPrepareOptionsMenu(Menu menu) {
} else {
menu.findItem(R.id.menu_distribution_conversation).setChecked(true);
}
} else if (isActiveV2Group()) {
inflater.inflate(R.menu.conversation_push_group_v2_options, menu);
} else if (isActiveGroup()) {
inflater.inflate(R.menu.conversation_push_group_options, menu);
}
Expand Down Expand Up @@ -835,6 +838,7 @@ public boolean onOptionsItemSelected(MenuItem item) {
case R.id.menu_distribution_broadcast: handleDistributionBroadcastEnabled(item); return true;
case R.id.menu_distribution_conversation: handleDistributionConversationEnabled(item); return true;
case R.id.menu_edit_group: handleEditPushGroup(); return true;
case R.id.menu_pending_members: handlePendingMembers(); return true;
case R.id.menu_leave: handleLeavePushGroup(); return true;
case R.id.menu_invite: handleInviteLink(); return true;
case R.id.menu_mute_notifications: handleMuteNotifications(); return true;
Expand Down Expand Up @@ -1130,6 +1134,10 @@ private void handleEditPushGroup() {
startActivityForResult(intent, GROUP_EDIT);
}

private void handlePendingMembers() {
startActivity(PendingMemberInvitesActivity.newIntent(ConversationActivity.this, recipient.get().requireGroupId().requireV2()));
}

private void handleDistributionBroadcastEnabled(MenuItem item) {
distributionType = ThreadDatabase.DistributionTypes.BROADCAST;
item.setChecked(true);
Expand Down Expand Up @@ -2108,6 +2116,13 @@ private boolean isActiveGroup() {
return record.isPresent() && record.get().isActive();
}

private boolean isActiveV2Group() {
if (!isGroupConversation()) return false;

Optional<GroupRecord> record = DatabaseFactory.getGroupDatabase(this).getGroup(getRecipient().getId());
return record.isPresent() && record.get().isActive() && record.get().isV2Group();
}

@SuppressWarnings("SimplifiableIfStatement")
private boolean isSelfConversation() {
if (!TextSecurePreferences.isPushRegistered(this)) return false;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package org.thoughtcrime.securesms.groups;

import android.content.Context;

import androidx.annotation.NonNull;
import androidx.annotation.WorkerThread;

import com.google.protobuf.ByteString;

import org.signal.storageservice.protos.groups.local.DecryptedPendingMember;
import org.signal.zkgroup.util.UUIDUtil;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations;

import java.util.UUID;

public final class GroupProtoUtil {

private GroupProtoUtil() {
}

@WorkerThread
public static Recipient pendingMemberToRecipient(@NonNull Context context, @NonNull DecryptedPendingMember pendingMember) {
return uuidByteStringToRecipient(context, pendingMember.getUuid());
}

@WorkerThread
public static Recipient uuidByteStringToRecipient(@NonNull Context context, @NonNull ByteString uuidByteString) {
UUID uuid = UUIDUtil.deserialize(uuidByteString.toByteArray());

if (uuid.equals(GroupsV2Operations.UNKNOWN_UUID)) {
return Recipient.UNKNOWN;
}

return Recipient.externalPush(context, uuid, null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public void setOnClick(@NonNull Runnable onClick) {
return onClick;
}

public static class FullMember extends GroupMemberEntry {
public final static class FullMember extends GroupMemberEntry {

private final Recipient member;

Expand All @@ -32,4 +32,40 @@ public Recipient getMember() {
return member;
}
}

public final static class PendingMember extends GroupMemberEntry {
private final Recipient invitee;
private final byte[] inviteeCipherText;

public PendingMember(@NonNull Recipient invitee, @NonNull byte[] inviteeCipherText) {
this.invitee = invitee;
this.inviteeCipherText = inviteeCipherText;
}

public Recipient getInvitee() {
return invitee;
}

public byte[] getInviteeCipherText() {
return inviteeCipherText;
}
}

public final static class UnknownPendingMemberCount extends GroupMemberEntry {
private Recipient inviter;
private int inviteCount;

public UnknownPendingMemberCount(@NonNull Recipient inviter, int inviteCount) {
this.inviter = inviter;
this.inviteCount = inviteCount;
}

public Recipient getInviter() {
return inviter;
}

public int getInviteCount() {
return inviteCount;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@

final class GroupMemberListAdapter extends RecyclerView.Adapter<GroupMemberListAdapter.ViewHolder> {

private static final int FULL_MEMBER = 0;
private static final int FULL_MEMBER = 0;
private static final int OWN_INVITE_PENDING = 1;
private static final int OTHER_INVITE_PENDING_COUNT = 2;

private final ArrayList<GroupMemberEntry> data = new ArrayList<>();

Expand All @@ -35,6 +37,14 @@ void updateData(@NonNull Collection<? extends GroupMemberEntry> recipients) {
return new FullMemberViewHolder(LayoutInflater.from(parent.getContext())
.inflate(R.layout.group_recipient_list_item,
parent, false));
case OWN_INVITE_PENDING:
return new OwnInvitePendingMemberViewHolder(LayoutInflater.from(parent.getContext())
.inflate(R.layout.group_recipient_list_item,
parent, false));
case OTHER_INVITE_PENDING_COUNT:
return new UnknownPendingMemberCountViewHolder(LayoutInflater.from(parent.getContext())
.inflate(R.layout.group_recipient_list_item,
parent, false));
default:
throw new AssertionError();
}
Expand All @@ -51,6 +61,10 @@ public int getItemViewType(int position) {

if (groupMemberEntry instanceof GroupMemberEntry.FullMember) {
return FULL_MEMBER;
} else if (groupMemberEntry instanceof GroupMemberEntry.PendingMember) {
return OWN_INVITE_PENDING;
} else if (groupMemberEntry instanceof GroupMemberEntry.UnknownPendingMemberCount) {
return OTHER_INVITE_PENDING_COUNT;
}

throw new AssertionError();
Expand Down Expand Up @@ -112,4 +126,41 @@ void bind(@NonNull GroupMemberEntry memberEntry) {
bindRecipient(fullMember.getMember());
}
}

final static class OwnInvitePendingMemberViewHolder extends ViewHolder {

OwnInvitePendingMemberViewHolder(@NonNull View itemView) {
super(itemView);
}

@Override
void bind(@NonNull GroupMemberEntry memberEntry) {
super.bind(memberEntry);

GroupMemberEntry.PendingMember pendingMember = (GroupMemberEntry.PendingMember) memberEntry;

bindRecipient(pendingMember.getInvitee());
}
}

final static class UnknownPendingMemberCountViewHolder extends ViewHolder {

UnknownPendingMemberCountViewHolder(@NonNull View itemView) {
super(itemView);
}

@Override
void bind(@NonNull GroupMemberEntry memberEntry) {
super.bind(memberEntry);
GroupMemberEntry.UnknownPendingMemberCount pendingMemberCount = (GroupMemberEntry.UnknownPendingMemberCount) memberEntry;

Recipient inviter = pendingMemberCount.getInviter();
String displayName = inviter.getDisplayName(itemView.getContext());
String displayText = context.getResources().getQuantityString(R.plurals.GroupMemberList_invited,
pendingMemberCount.getInviteCount(),
displayName, pendingMemberCount.getInviteCount());

bindImageAndText(inviter, displayText);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package org.thoughtcrime.securesms.groups.ui.pendingmemberinvites;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;

import androidx.annotation.NonNull;
import androidx.appcompat.widget.Toolbar;

import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.groups.GroupId;
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
import org.thoughtcrime.securesms.util.DynamicTheme;

public class PendingMemberInvitesActivity extends PassphraseRequiredActionBarActivity {

private static final String GROUP_ID = "GROUP_ID";

private final DynamicTheme dynamicTheme = new DynamicNoActionBarTheme();

public static Intent newIntent(@NonNull Context context, @NonNull GroupId.V2 groupId) {
Intent intent = new Intent(context, PendingMemberInvitesActivity.class);
intent.putExtra(GROUP_ID, groupId.toString());
return intent;
}

@Override
protected void onPreCreate() {
dynamicTheme.onCreate(this);
}

@Override
protected void onCreate(Bundle savedInstanceState, boolean ready) {
super.onCreate(savedInstanceState, ready);
setContentView(R.layout.group_pending_member_invites_activity);

if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.replace(R.id.container, PendingMemberInvitesFragment.newInstance(GroupId.parse(getIntent().getStringExtra(GROUP_ID)).requireV2()))
.commitNow();
}

Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}

@Override
public void onResume() {
super.onResume();
dynamicTheme.onResume(this);
}

@Override
public boolean onSupportNavigateUp() {
onBackPressed();
return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package org.thoughtcrime.securesms.groups.ui.pendingmemberinvites;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProviders;

import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.groups.GroupId;
import org.thoughtcrime.securesms.groups.ui.GroupMemberListView;

import java.util.Objects;

public class PendingMemberInvitesFragment extends Fragment {

private static final String GROUP_ID = "GROUP_ID";

private PendingMemberInvitesViewModel viewModel;
private GroupMemberListView youInvited;
private GroupMemberListView othersInvited;
private View youInvitedEmptyState;
private View othersInvitedEmptyState;

public static PendingMemberInvitesFragment newInstance(@NonNull GroupId.V2 groupId) {
PendingMemberInvitesFragment fragment = new PendingMemberInvitesFragment();
Bundle args = new Bundle();

args.putString(GROUP_ID, groupId.toString());
fragment.setArguments(args);

return fragment;
}

@Override
public @Nullable View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.group_pending_member_invites_fragment, container, false);

youInvited = view.findViewById(R.id.members_you_invited);
othersInvited = view.findViewById(R.id.members_others_invited);
youInvitedEmptyState = view.findViewById(R.id.no_pending_from_you);
othersInvitedEmptyState = view.findViewById(R.id.no_pending_from_others);

return view;
}

@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);

GroupId.V2 groupId = GroupId.parse(Objects.requireNonNull(requireArguments().getString(GROUP_ID))).requireV2();

PendingMemberInvitesViewModel.Factory factory = new PendingMemberInvitesViewModel.Factory(requireContext(), groupId);

viewModel = ViewModelProviders.of(requireActivity(), factory).get(PendingMemberInvitesViewModel.class);

viewModel.getWhoYouInvited().observe(getViewLifecycleOwner(), invitees -> {
youInvited.setMembers(invitees);
youInvitedEmptyState.setVisibility(invitees.isEmpty() ? View.VISIBLE : View.GONE);
});

viewModel.getWhoOthersInvited().observe(getViewLifecycleOwner(), invitees -> {
othersInvited.setMembers(invitees);
othersInvitedEmptyState.setVisibility(invitees.isEmpty() ? View.VISIBLE : View.GONE);
});
}
}

0 comments on commit 1290d0e

Please sign in to comment.