mirror of
https://github.com/oxen-io/session-android.git
synced 2025-12-31 04:06:26 +00:00
Recipient bottom sheet.
This commit is contained in:
committed by
Greyson Parrelli
parent
f6f6496c9c
commit
17c5b858b5
@@ -1,43 +1,45 @@
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||
import org.thoughtcrime.securesms.groups.GroupId;
|
||||
import org.thoughtcrime.securesms.groups.ui.GroupMemberEntry;
|
||||
import org.thoughtcrime.securesms.groups.ui.GroupMemberListView;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientExporter;
|
||||
import org.thoughtcrime.securesms.recipients.ui.bottomsheet.RecipientBottomSheetDialogFragment;
|
||||
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public final class GroupMembersDialog {
|
||||
|
||||
private final Context context;
|
||||
private final Recipient groupRecipient;
|
||||
private final Lifecycle lifecycle;
|
||||
private final FragmentActivity fragmentActivity;
|
||||
private final Recipient groupRecipient;
|
||||
private final Lifecycle lifecycle;
|
||||
|
||||
public GroupMembersDialog(@NonNull Context context,
|
||||
public GroupMembersDialog(@NonNull FragmentActivity activity,
|
||||
@NonNull Recipient groupRecipient,
|
||||
@NonNull Lifecycle lifecycle)
|
||||
{
|
||||
this.context = context;
|
||||
this.groupRecipient = groupRecipient;
|
||||
this.lifecycle = lifecycle;
|
||||
this.fragmentActivity = activity;
|
||||
this.groupRecipient = groupRecipient;
|
||||
this.lifecycle = lifecycle;
|
||||
}
|
||||
|
||||
public void display() {
|
||||
SimpleTask.run(
|
||||
lifecycle,
|
||||
() -> DatabaseFactory.getGroupDatabase(context).getGroupMembers(groupRecipient.requireGroupId(), GroupDatabase.MemberSet.FULL_MEMBERS_INCLUDING_SELF),
|
||||
() -> DatabaseFactory.getGroupDatabase(fragmentActivity).getGroupMembers(groupRecipient.requireGroupId(), GroupDatabase.MemberSet.FULL_MEMBERS_INCLUDING_SELF),
|
||||
members -> {
|
||||
AlertDialog dialog = new AlertDialog.Builder(context)
|
||||
AlertDialog dialog = new AlertDialog.Builder(fragmentActivity)
|
||||
.setTitle(R.string.ConversationActivity_group_members)
|
||||
.setIconAttribute(R.attr.group_members_dialog_icon)
|
||||
.setCancelable(true)
|
||||
@@ -70,13 +72,18 @@ public final class GroupMembersDialog {
|
||||
}
|
||||
|
||||
private void contactClick(@NonNull Recipient recipient) {
|
||||
if (recipient.getContactUri() != null) {
|
||||
Intent intent = new Intent(context, RecipientPreferenceActivity.class);
|
||||
intent.putExtra(RecipientPreferenceActivity.RECIPIENT_ID, recipient.getId());
|
||||
GroupId groupId = groupRecipient.requireGroupId();
|
||||
|
||||
context.startActivity(intent);
|
||||
if (groupId.isV2()) {
|
||||
RecipientBottomSheetDialogFragment.create(recipient.getId(), groupId)
|
||||
.show(fragmentActivity.getSupportFragmentManager(), "BOTTOM");
|
||||
} else if (recipient.getContactUri() != null) {
|
||||
Intent intent = new Intent(fragmentActivity, RecipientPreferenceActivity.class);
|
||||
intent.putExtra(RecipientPreferenceActivity.RECIPIENT_ID, recipient.getId());
|
||||
|
||||
fragmentActivity.startActivity(intent);
|
||||
} else {
|
||||
context.startActivity(RecipientExporter.export(recipient).asAddContactIntent());
|
||||
fragmentActivity.startActivity(RecipientExporter.export(recipient).asAddContactIntent());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
package org.thoughtcrime.securesms.recipients.ui.bottomsheet;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.ViewModelProviders;
|
||||
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.components.AvatarImageView;
|
||||
import org.thoughtcrime.securesms.groups.GroupId;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.ThemeUtil;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public final class RecipientBottomSheetDialogFragment extends BottomSheetDialogFragment {
|
||||
|
||||
private static final String ARGS_RECIPIENT_ID = "RECIPIENT_ID";
|
||||
private static final String ARGS_GROUP_ID = "GROUP_ID";
|
||||
|
||||
private RecipientDialogViewModel viewModel;
|
||||
private AvatarImageView avatar;
|
||||
private TextView fullName;
|
||||
private TextView usernameNumber;
|
||||
private Button messageButton;
|
||||
private Button secureCallButton;
|
||||
private Button blockButton;
|
||||
private Button unblockButton;
|
||||
private Button viewSafetyNumberButton;
|
||||
private Button makeGroupAdminButton;
|
||||
private Button removeAdminButton;
|
||||
private Button removeFromGroupButton;
|
||||
|
||||
public static BottomSheetDialogFragment create(@NonNull RecipientId recipientId,
|
||||
@Nullable GroupId groupId)
|
||||
{
|
||||
Bundle args = new Bundle();
|
||||
RecipientBottomSheetDialogFragment fragment = new RecipientBottomSheetDialogFragment();
|
||||
|
||||
args.putString(ARGS_RECIPIENT_ID, recipientId.serialize());
|
||||
if (groupId != null) {
|
||||
args.putString(ARGS_GROUP_ID, groupId.toString());
|
||||
}
|
||||
|
||||
fragment.setArguments(args);
|
||||
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
setStyle(DialogFragment.STYLE_NORMAL,
|
||||
ThemeUtil.isDarkTheme(requireContext()) ? R.style.Signal_RecipientBottomSheet
|
||||
: R.style.Signal_RecipientBottomSheet_Light);
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.recipient_bottom_sheet, container, false);
|
||||
|
||||
avatar = view.findViewById(R.id.recipient_avatar);
|
||||
fullName = view.findViewById(R.id.full_name);
|
||||
usernameNumber = view.findViewById(R.id.username_number);
|
||||
messageButton = view.findViewById(R.id.message_button);
|
||||
secureCallButton = view.findViewById(R.id.secure_call_button);
|
||||
blockButton = view.findViewById(R.id.block_button);
|
||||
unblockButton = view.findViewById(R.id.unblock_button);
|
||||
viewSafetyNumberButton = view.findViewById(R.id.view_safety_number_button);
|
||||
makeGroupAdminButton = view.findViewById(R.id.make_group_admin_button);
|
||||
removeAdminButton = view.findViewById(R.id.remove_group_admin_button);
|
||||
removeFromGroupButton = view.findViewById(R.id.remove_from_group_button);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View fragmentView, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(fragmentView, savedInstanceState);
|
||||
|
||||
Bundle arguments = requireArguments();
|
||||
RecipientId recipientId = RecipientId.from(Objects.requireNonNull(arguments.getString(ARGS_RECIPIENT_ID)));
|
||||
GroupId groupId = GroupId.parseNullableOrThrow(arguments.getString(ARGS_GROUP_ID));
|
||||
|
||||
RecipientDialogViewModel.Factory factory = new RecipientDialogViewModel.Factory(requireContext().getApplicationContext(), recipientId, groupId);
|
||||
|
||||
viewModel = ViewModelProviders.of(this, factory).get(RecipientDialogViewModel.class);
|
||||
|
||||
viewModel.getRecipient().observe(getViewLifecycleOwner(), recipient -> {
|
||||
avatar.setRecipient(recipient);
|
||||
|
||||
String name = recipient.getProfileName().toString();
|
||||
fullName.setText(name);
|
||||
fullName.setVisibility(TextUtils.isEmpty(name) ? View.GONE : View.VISIBLE);
|
||||
|
||||
String usernameNumberString = String.format("%s %s", recipient.getUsername().or(""), recipient.getSmsAddress().or(""))
|
||||
.trim();
|
||||
usernameNumber.setText(usernameNumberString);
|
||||
usernameNumber.setVisibility(TextUtils.isEmpty(usernameNumberString) ? View.GONE : View.VISIBLE);
|
||||
|
||||
boolean blocked = recipient.isBlocked();
|
||||
blockButton.setVisibility(blocked ? View.GONE : View.VISIBLE);
|
||||
unblockButton.setVisibility(blocked ? View.VISIBLE : View.GONE);
|
||||
|
||||
secureCallButton.setVisibility(recipient.isRegistered() ? View.VISIBLE : View.GONE);
|
||||
});
|
||||
|
||||
viewModel.getAdminActionStatus().observe(getViewLifecycleOwner(), adminStatus -> {
|
||||
makeGroupAdminButton.setVisibility(adminStatus.isCanMakeAdmin() ? View.VISIBLE : View.GONE);
|
||||
removeAdminButton.setVisibility(adminStatus.isCanMakeNonAdmin() ? View.VISIBLE : View.GONE);
|
||||
removeFromGroupButton.setVisibility(adminStatus.isCanRemove() ? View.VISIBLE : View.GONE);
|
||||
});
|
||||
|
||||
viewModel.getIdentity().observe(getViewLifecycleOwner(), identityRecord -> {
|
||||
viewSafetyNumberButton.setVisibility(identityRecord != null ? View.VISIBLE : View.GONE);
|
||||
|
||||
if (identityRecord != null) {
|
||||
viewSafetyNumberButton.setOnClickListener(view -> {
|
||||
dismiss();
|
||||
viewModel.onViewSafetyNumberClicked(requireActivity(), identityRecord);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
avatar.setOnClickListener(view -> {
|
||||
dismiss();
|
||||
viewModel.onAvatarClicked(requireActivity());
|
||||
});
|
||||
|
||||
messageButton.setOnClickListener(view -> {
|
||||
dismiss();
|
||||
viewModel.onMessageClicked(requireActivity());
|
||||
});
|
||||
|
||||
secureCallButton.setOnClickListener(view -> {
|
||||
dismiss();
|
||||
viewModel.onSecureCallClicked(requireActivity());
|
||||
});
|
||||
|
||||
blockButton.setOnClickListener(view -> viewModel.onBlockClicked(requireActivity()));
|
||||
unblockButton.setOnClickListener(view -> viewModel.onUnblockClicked(requireActivity()));
|
||||
|
||||
makeGroupAdminButton.setOnClickListener(view -> viewModel.onMakeGroupAdminClicked());
|
||||
removeAdminButton.setOnClickListener(view -> viewModel.onRemoveGroupAdminClicked());
|
||||
removeFromGroupButton.setOnClickListener(view -> viewModel.onRemoveFromGroupClicked());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package org.thoughtcrime.securesms.recipients.ui.bottomsheet;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||
import org.thoughtcrime.securesms.database.IdentityDatabase;
|
||||
import org.thoughtcrime.securesms.groups.GroupId;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;
|
||||
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
|
||||
|
||||
final class RecipientDialogRepository {
|
||||
|
||||
@NonNull private final GroupDatabase groupDatabase;
|
||||
@NonNull private final Context context;
|
||||
@NonNull private final RecipientId recipientId;
|
||||
@Nullable private final GroupId groupId;
|
||||
|
||||
RecipientDialogRepository(@NonNull Context context,
|
||||
@NonNull RecipientId recipientId,
|
||||
@Nullable GroupId groupId)
|
||||
{
|
||||
this.context = context;
|
||||
this.groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
||||
this.recipientId = recipientId;
|
||||
this.groupId = groupId;
|
||||
}
|
||||
|
||||
@NonNull RecipientId getRecipientId() {
|
||||
return recipientId;
|
||||
}
|
||||
|
||||
@Nullable GroupId getGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
|
||||
void isAdminOfGroup(@NonNull RecipientId recipientId, @NonNull AdminCallback callback) {
|
||||
SimpleTask.run(SignalExecutors.BOUNDED,
|
||||
() -> {
|
||||
if (groupId != null) {
|
||||
Recipient recipient = Recipient.resolved(recipientId);
|
||||
return groupDatabase.getGroup(groupId)
|
||||
.transform(g -> g.isAdmin(recipient))
|
||||
.or(false);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
callback::isAdmin);
|
||||
}
|
||||
|
||||
void getIdentity(@NonNull IdentityCallback callback) {
|
||||
SimpleTask.run(SignalExecutors.BOUNDED,
|
||||
() -> DatabaseFactory.getIdentityDatabase(context)
|
||||
.getIdentity(recipientId)
|
||||
.orNull(),
|
||||
callback::remoteIdentity);
|
||||
}
|
||||
|
||||
public void getRecipient(@NonNull RecipientCallback recipientCallback) {
|
||||
SimpleTask.run(SignalExecutors.BOUNDED,
|
||||
() -> Recipient.resolved(recipientId),
|
||||
recipientCallback::onRecipient);
|
||||
}
|
||||
|
||||
interface AdminCallback {
|
||||
void isAdmin(boolean admin);
|
||||
}
|
||||
|
||||
interface IdentityCallback {
|
||||
void remoteIdentity(@Nullable IdentityDatabase.IdentityRecord identityRecord);
|
||||
}
|
||||
|
||||
interface RecipientCallback {
|
||||
void onRecipient(@NonNull Recipient recipient);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
package org.thoughtcrime.securesms.recipients.ui.bottomsheet;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
import androidx.lifecycle.Transformations;
|
||||
import androidx.lifecycle.ViewModel;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
import org.thoughtcrime.securesms.BlockUnblockDialog;
|
||||
import org.thoughtcrime.securesms.RecipientPreferenceActivity;
|
||||
import org.thoughtcrime.securesms.VerifyIdentityActivity;
|
||||
import org.thoughtcrime.securesms.database.IdentityDatabase;
|
||||
import org.thoughtcrime.securesms.groups.GroupId;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientUtil;
|
||||
import org.thoughtcrime.securesms.util.CommunicationActions;
|
||||
import org.thoughtcrime.securesms.util.DefaultValueLiveData;
|
||||
import org.thoughtcrime.securesms.util.livedata.LiveDataPair;
|
||||
|
||||
final class RecipientDialogViewModel extends ViewModel {
|
||||
|
||||
private final Context context;
|
||||
private final RecipientDialogRepository recipientDialogRepository;
|
||||
private final LiveData<Recipient> recipient;
|
||||
private final MutableLiveData<IdentityDatabase.IdentityRecord> identity;
|
||||
private final LiveData<AdminActionStatus> adminActionStatus;
|
||||
|
||||
private RecipientDialogViewModel(@NonNull Context context,
|
||||
@NonNull RecipientDialogRepository recipientDialogRepository)
|
||||
{
|
||||
this.context = context;
|
||||
this.recipientDialogRepository = recipientDialogRepository;
|
||||
this.identity = new MutableLiveData<>();
|
||||
|
||||
MutableLiveData<Boolean> localIsAdmin = new DefaultValueLiveData<>(false);
|
||||
MutableLiveData<Boolean> recipientIsAdmin = new DefaultValueLiveData<>(false);
|
||||
|
||||
if (recipientDialogRepository.getGroupId() != null && recipientDialogRepository.getGroupId().isV2()) {
|
||||
recipientDialogRepository.isAdminOfGroup(Recipient.self().getId(), localIsAdmin::setValue);
|
||||
recipientDialogRepository.isAdminOfGroup(recipientDialogRepository.getRecipientId(), recipientIsAdmin::setValue);
|
||||
}
|
||||
|
||||
adminActionStatus = Transformations.map(new LiveDataPair<>(localIsAdmin, recipientIsAdmin, false, false),
|
||||
pair -> {
|
||||
boolean localAdmin = pair.first();
|
||||
boolean recipientAdmin = pair.second();
|
||||
|
||||
return new AdminActionStatus(localAdmin,
|
||||
localAdmin && !recipientAdmin,
|
||||
localAdmin && recipientAdmin);
|
||||
});
|
||||
|
||||
recipient = Recipient.live(recipientDialogRepository.getRecipientId()).getLiveData();
|
||||
|
||||
recipientDialogRepository.getIdentity(identity::setValue);
|
||||
}
|
||||
|
||||
LiveData<Recipient> getRecipient() {
|
||||
return recipient;
|
||||
}
|
||||
|
||||
LiveData<AdminActionStatus> getAdminActionStatus() {
|
||||
return adminActionStatus;
|
||||
}
|
||||
|
||||
LiveData<IdentityDatabase.IdentityRecord> getIdentity() {
|
||||
return identity;
|
||||
}
|
||||
|
||||
void onMessageClicked(@NonNull Activity activity) {
|
||||
recipientDialogRepository.getRecipient(recipient -> CommunicationActions.startConversation(activity, recipient, null));
|
||||
}
|
||||
|
||||
void onSecureCallClicked(@NonNull Activity activity) {
|
||||
recipientDialogRepository.getRecipient(recipient -> CommunicationActions.startVoiceCall(activity, recipient));
|
||||
}
|
||||
|
||||
void onBlockClicked(@NonNull FragmentActivity activity) {
|
||||
recipientDialogRepository.getRecipient(recipient -> BlockUnblockDialog.showBlockFor(activity, activity.getLifecycle(), recipient, () -> RecipientUtil.block(context, recipient)));
|
||||
}
|
||||
|
||||
void onUnblockClicked(@NonNull FragmentActivity activity) {
|
||||
recipientDialogRepository.getRecipient(recipient -> BlockUnblockDialog.showUnblockFor(activity, activity.getLifecycle(), recipient, () -> RecipientUtil.unblock(context, recipient)));
|
||||
}
|
||||
|
||||
void onViewSafetyNumberClicked(@NonNull Activity activity, @NonNull IdentityDatabase.IdentityRecord identityRecord) {
|
||||
activity.startActivity(VerifyIdentityActivity.newIntent(activity, identityRecord));
|
||||
}
|
||||
|
||||
void onAvatarClicked(@NonNull Activity activity) {
|
||||
activity.startActivity(RecipientPreferenceActivity.getLaunchIntent(activity, recipientDialogRepository.getRecipientId()));
|
||||
}
|
||||
|
||||
void onMakeGroupAdminClicked() {
|
||||
// TODO GV2
|
||||
throw new AssertionError("NYI");
|
||||
}
|
||||
|
||||
void onRemoveGroupAdminClicked() {
|
||||
// TODO GV2
|
||||
throw new AssertionError("NYI");
|
||||
}
|
||||
|
||||
void onRemoveFromGroupClicked() {
|
||||
// TODO GV2
|
||||
throw new AssertionError("NYI");
|
||||
}
|
||||
|
||||
static class AdminActionStatus {
|
||||
private final boolean canRemove;
|
||||
private final boolean canMakeAdmin;
|
||||
private final boolean canMakeNonAdmin;
|
||||
|
||||
AdminActionStatus(boolean canRemove, boolean canMakeAdmin, boolean canMakeNonAdmin) {
|
||||
this.canRemove = canRemove;
|
||||
this.canMakeAdmin = canMakeAdmin;
|
||||
this.canMakeNonAdmin = canMakeNonAdmin;
|
||||
}
|
||||
|
||||
boolean isCanRemove() {
|
||||
return canRemove;
|
||||
}
|
||||
|
||||
boolean isCanMakeAdmin() {
|
||||
return canMakeAdmin;
|
||||
}
|
||||
|
||||
boolean isCanMakeNonAdmin() {
|
||||
return canMakeNonAdmin;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Factory implements ViewModelProvider.Factory {
|
||||
|
||||
private final Context context;
|
||||
private final RecipientId recipientId;
|
||||
private final GroupId groupId;
|
||||
|
||||
Factory(@NonNull Context context, @NonNull RecipientId recipientId, @Nullable GroupId groupId) {
|
||||
this.context = context;
|
||||
this.recipientId = recipientId;
|
||||
this.groupId = groupId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
|
||||
//noinspection unchecked
|
||||
return (T) new RecipientDialogViewModel(context, new RecipientDialogRepository(context, recipientId, groupId));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user