mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-26 19:56:02 +01:00
Improve message requests, add megaphone.
This commit is contained in:
committed by
Greyson Parrelli
parent
dc689d325b
commit
9e5f64c431
@@ -1,172 +0,0 @@
|
||||
package org.thoughtcrime.securesms.messagerequests;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.text.HtmlCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.ViewModelProviders;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.components.AvatarImageView;
|
||||
import org.thoughtcrime.securesms.conversation.ConversationItem;
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class MessageRequestFragment extends Fragment {
|
||||
|
||||
private AvatarImageView contactAvatar;
|
||||
private TextView contactTitle;
|
||||
private TextView contactSubtitle;
|
||||
private TextView contactDescription;
|
||||
private FrameLayout messageView;
|
||||
private TextView question;
|
||||
private Button accept;
|
||||
private Button block;
|
||||
private Button delete;
|
||||
private ConversationItem conversationItem;
|
||||
|
||||
private MessageRequestFragmentViewModel viewModel;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater,
|
||||
@Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState)
|
||||
{
|
||||
return inflater.inflate(R.layout.message_request_fragment, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
contactAvatar = view.findViewById(R.id.message_request_avatar);
|
||||
contactTitle = view.findViewById(R.id.message_request_title);
|
||||
contactSubtitle = view.findViewById(R.id.message_request_subtitle);
|
||||
contactDescription = view.findViewById(R.id.message_request_description);
|
||||
messageView = view.findViewById(R.id.message_request_message);
|
||||
question = view.findViewById(R.id.message_request_question);
|
||||
accept = view.findViewById(R.id.message_request_accept);
|
||||
block = view.findViewById(R.id.message_request_block);
|
||||
delete = view.findViewById(R.id.message_request_delete);
|
||||
|
||||
initializeViewModel();
|
||||
initializeBottomViewListeners();
|
||||
}
|
||||
|
||||
private void initializeViewModel() {
|
||||
viewModel = ViewModelProviders.of(requireActivity()).get(MessageRequestFragmentViewModel.class);
|
||||
viewModel.getState().observe(getViewLifecycleOwner(), state -> {
|
||||
if (state.messageRecord == null || state.recipient == null) return;
|
||||
|
||||
presentConversationItemTo(state.messageRecord, state.recipient);
|
||||
presentMessageRequestBottomViewTo(state.recipient);
|
||||
presentMessageRequestProfileViewTo(state.recipient, state.groups, state.memberCount);
|
||||
});
|
||||
}
|
||||
|
||||
private void presentConversationItemTo(@NonNull MessageRecord messageRecord, @NonNull Recipient recipient) {
|
||||
if (messageRecord.isGroupAction()) {
|
||||
if (conversationItem != null) {
|
||||
messageView.removeAllViews();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (conversationItem == null) {
|
||||
conversationItem = (ConversationItem) LayoutInflater.from(requireActivity()).inflate(R.layout.conversation_item_received, messageView, false);
|
||||
}
|
||||
|
||||
conversationItem.bind(messageRecord,
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
GlideApp.with(this),
|
||||
Locale.getDefault(),
|
||||
Collections.emptySet(),
|
||||
recipient,
|
||||
null,
|
||||
false);
|
||||
|
||||
if (messageView.getChildCount() == 0 || messageView.getChildAt(0) != conversationItem) {
|
||||
messageView.removeAllViews();
|
||||
messageView.addView(conversationItem);
|
||||
}
|
||||
}
|
||||
|
||||
private void presentMessageRequestProfileViewTo(@Nullable Recipient recipient, @Nullable List<String> groups, int memberCount) {
|
||||
if (recipient != null) {
|
||||
contactAvatar.setAvatar(GlideApp.with(this), recipient, false);
|
||||
|
||||
String title = recipient.getDisplayName(requireContext());
|
||||
contactTitle.setText(title);
|
||||
|
||||
if (recipient.isGroup()) {
|
||||
contactSubtitle.setText(getString(R.string.MessageRequestProfileView_members, memberCount));
|
||||
} else {
|
||||
String subtitle = recipient.getUsername().or(recipient.getE164()).orNull();
|
||||
|
||||
if (subtitle == null || subtitle.equals(title)) {
|
||||
contactSubtitle.setVisibility(View.GONE);
|
||||
} else {
|
||||
contactSubtitle.setText(subtitle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (groups == null || groups.isEmpty()) {
|
||||
contactDescription.setVisibility(View.GONE);
|
||||
} else {
|
||||
final String description;
|
||||
|
||||
switch (groups.size()) {
|
||||
case 1:
|
||||
description = getString(R.string.MessageRequestProfileView_member_of_one_group, bold(groups.get(0)));
|
||||
break;
|
||||
case 2:
|
||||
description = getString(R.string.MessageRequestProfileView_member_of_two_groups, bold(groups.get(0)), bold(groups.get(1)));
|
||||
break;
|
||||
case 3:
|
||||
description = getString(R.string.MessageRequestProfileView_member_of_many_groups, bold(groups.get(0)), bold(groups.get(1)), bold(groups.get(2)));
|
||||
break;
|
||||
default:
|
||||
int others = groups.size() - 2;
|
||||
description = getString(R.string.MessageRequestProfileView_member_of_many_groups,
|
||||
bold(groups.get(0)),
|
||||
bold(groups.get(1)),
|
||||
getResources().getQuantityString(R.plurals.MessageRequestProfileView_member_of_others, others, others));
|
||||
}
|
||||
|
||||
contactDescription.setText(HtmlCompat.fromHtml(description, 0));
|
||||
contactDescription.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
private @NonNull String bold(@NonNull String target) {
|
||||
return "<b>" + target + "</b>";
|
||||
}
|
||||
|
||||
private void presentMessageRequestBottomViewTo(@Nullable Recipient recipient) {
|
||||
if (recipient == null) return;
|
||||
|
||||
question.setText(HtmlCompat.fromHtml(getString(R.string.MessageRequestBottomView_do_you_want_to_let, bold(recipient.getDisplayName(requireContext()))), 0));
|
||||
}
|
||||
|
||||
private void initializeBottomViewListeners() {
|
||||
accept.setOnClickListener(v -> viewModel.accept());
|
||||
delete.setOnClickListener(v -> viewModel.delete());
|
||||
block.setOnClickListener(v -> viewModel.block());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
package org.thoughtcrime.securesms.messagerequests;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class MessageRequestFragmentState {
|
||||
|
||||
public enum MessageRequestState {
|
||||
LOADING,
|
||||
PENDING,
|
||||
BLOCKED,
|
||||
DELETED,
|
||||
ACCEPTED
|
||||
}
|
||||
|
||||
public final @NonNull MessageRequestState messageRequestState;
|
||||
public final @Nullable MessageRecord messageRecord;
|
||||
public final @Nullable Recipient recipient;
|
||||
public final @Nullable List<String> groups;
|
||||
public final int memberCount;
|
||||
|
||||
|
||||
public MessageRequestFragmentState(@NonNull MessageRequestState messageRequestState,
|
||||
@Nullable MessageRecord messageRecord,
|
||||
@Nullable Recipient recipient,
|
||||
@Nullable List<String> groups,
|
||||
int memberCount)
|
||||
{
|
||||
this.messageRequestState = messageRequestState;
|
||||
this.messageRecord = messageRecord;
|
||||
this.recipient = recipient;
|
||||
this.groups = groups;
|
||||
this.memberCount = memberCount;
|
||||
}
|
||||
|
||||
public @NonNull MessageRequestFragmentState updateMessageRequestState(@NonNull MessageRequestState messageRequestState) {
|
||||
return new MessageRequestFragmentState(messageRequestState,
|
||||
this.messageRecord,
|
||||
this.recipient,
|
||||
this.groups,
|
||||
this.memberCount);
|
||||
}
|
||||
|
||||
public @NonNull MessageRequestFragmentState updateMessageRecord(@NonNull MessageRecord messageRecord) {
|
||||
return new MessageRequestFragmentState(this.messageRequestState,
|
||||
messageRecord,
|
||||
this.recipient,
|
||||
this.groups,
|
||||
this.memberCount);
|
||||
}
|
||||
|
||||
public @NonNull MessageRequestFragmentState updateRecipient(@NonNull Recipient recipient) {
|
||||
return new MessageRequestFragmentState(this.messageRequestState,
|
||||
this.messageRecord,
|
||||
recipient,
|
||||
this.groups,
|
||||
this.memberCount);
|
||||
}
|
||||
|
||||
public @NonNull MessageRequestFragmentState updateGroups(@NonNull List<String> groups) {
|
||||
return new MessageRequestFragmentState(this.messageRequestState,
|
||||
this.messageRecord,
|
||||
this.recipient,
|
||||
groups,
|
||||
this.memberCount);
|
||||
}
|
||||
|
||||
public @NonNull MessageRequestFragmentState updateMemberCount(int memberCount) {
|
||||
return new MessageRequestFragmentState(this.messageRequestState,
|
||||
this.messageRecord,
|
||||
this.recipient,
|
||||
this.groups,
|
||||
memberCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull String toString() {
|
||||
return "MessageRequestFragmentState: [" +
|
||||
messageRequestState.name() + "] [" +
|
||||
messageRecord + "] [" +
|
||||
recipient + "] [" +
|
||||
groups + "] [" +
|
||||
memberCount + "]";
|
||||
}
|
||||
}
|
||||
@@ -1,139 +0,0 @@
|
||||
package org.thoughtcrime.securesms.messagerequests;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.MainThread;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.arch.core.util.Function;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
import androidx.lifecycle.ViewModel;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
import org.thoughtcrime.securesms.recipients.RecipientForeverObserver;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
|
||||
public class MessageRequestFragmentViewModel extends ViewModel {
|
||||
|
||||
private static final String TAG = MessageRequestFragmentViewModel.class.getSimpleName();
|
||||
|
||||
private final MutableLiveData<MessageRequestFragmentState> internalState = new MutableLiveData<>();
|
||||
|
||||
private final MessageRequestFragmentRepository repository;
|
||||
|
||||
@SuppressWarnings("CodeBlock2Expr")
|
||||
private final RecipientForeverObserver recipientObserver = recipient -> {
|
||||
updateState(getNewState(s -> s.updateRecipient(recipient)));
|
||||
};
|
||||
|
||||
private MessageRequestFragmentViewModel(@NonNull MessageRequestFragmentRepository repository) {
|
||||
internalState.setValue(new MessageRequestFragmentState(MessageRequestFragmentState.MessageRequestState.LOADING, null, null, null, 0));
|
||||
this.repository = repository;
|
||||
|
||||
loadRecipient();
|
||||
loadMessageRecord();
|
||||
loadGroups();
|
||||
loadMemberCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCleared() {
|
||||
repository.getLiveRecipient().removeForeverObserver(recipientObserver);
|
||||
}
|
||||
|
||||
public @NonNull LiveData<MessageRequestFragmentState> getState() {
|
||||
return internalState;
|
||||
}
|
||||
|
||||
@MainThread
|
||||
public void accept() {
|
||||
repository.acceptMessageRequest(() -> {
|
||||
MessageRequestFragmentState state = internalState.getValue();
|
||||
updateState(state.updateMessageRequestState(MessageRequestFragmentState.MessageRequestState.ACCEPTED));
|
||||
});
|
||||
}
|
||||
|
||||
@MainThread
|
||||
public void delete() {
|
||||
repository.deleteMessageRequest(() -> {
|
||||
MessageRequestFragmentState state = internalState.getValue();
|
||||
updateState(state.updateMessageRequestState(MessageRequestFragmentState.MessageRequestState.DELETED));
|
||||
});
|
||||
}
|
||||
|
||||
@MainThread
|
||||
public void block() {
|
||||
repository.blockMessageRequest(() -> {
|
||||
MessageRequestFragmentState state = internalState.getValue();
|
||||
updateState(state.updateMessageRequestState(MessageRequestFragmentState.MessageRequestState.BLOCKED));
|
||||
});
|
||||
}
|
||||
|
||||
private void updateState(@NonNull MessageRequestFragmentState newState) {
|
||||
Log.i(TAG, "updateState: " + newState);
|
||||
internalState.setValue(newState);
|
||||
}
|
||||
|
||||
private void loadRecipient() {
|
||||
repository.getLiveRecipient().observeForever(recipientObserver);
|
||||
repository.refreshRecipient();
|
||||
}
|
||||
|
||||
private void loadMessageRecord() {
|
||||
repository.getMessageRecord(messageRecord -> {
|
||||
MessageRequestFragmentState newState = getNewState(s -> s.updateMessageRecord(messageRecord));
|
||||
updateState(newState);
|
||||
});
|
||||
}
|
||||
|
||||
private void loadGroups() {
|
||||
repository.getGroups(groups -> {
|
||||
MessageRequestFragmentState newState = getNewState(s -> s.updateGroups(groups));
|
||||
updateState(newState);
|
||||
});
|
||||
}
|
||||
|
||||
private void loadMemberCount() {
|
||||
repository.getMemberCount(memberCount -> {
|
||||
MessageRequestFragmentState newState = getNewState(s -> s.updateMemberCount(memberCount == null ? 0 : memberCount));
|
||||
updateState(newState);
|
||||
});
|
||||
}
|
||||
|
||||
private @NonNull MessageRequestFragmentState getNewState(@NonNull Function<MessageRequestFragmentState, MessageRequestFragmentState> stateTransformer) {
|
||||
MessageRequestFragmentState oldState = internalState.getValue();
|
||||
MessageRequestFragmentState newState = stateTransformer.apply(oldState);
|
||||
return newState.updateMessageRequestState(getUpdatedRequestState(newState));
|
||||
}
|
||||
|
||||
private static @NonNull MessageRequestFragmentState.MessageRequestState getUpdatedRequestState(@NonNull MessageRequestFragmentState state) {
|
||||
if (state.messageRequestState != MessageRequestFragmentState.MessageRequestState.LOADING) {
|
||||
return state.messageRequestState;
|
||||
}
|
||||
|
||||
if (state.messageRecord != null && state.recipient != null && state.groups != null) {
|
||||
return MessageRequestFragmentState.MessageRequestState.PENDING;
|
||||
}
|
||||
|
||||
return MessageRequestFragmentState.MessageRequestState.LOADING;
|
||||
}
|
||||
|
||||
public static class Factory implements ViewModelProvider.Factory {
|
||||
private final Context context;
|
||||
private final long threadId;
|
||||
private final RecipientId recipientId;
|
||||
|
||||
public Factory(@NonNull Context context, long threadId, @NonNull RecipientId recipientId) {
|
||||
this.context = context;
|
||||
this.threadId = threadId;
|
||||
this.recipientId = recipientId;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public @NonNull <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
|
||||
return (T) new MessageRequestFragmentViewModel(new MessageRequestFragmentRepository(context, recipientId, threadId));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package org.thoughtcrime.securesms.messagerequests;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.airbnb.lottie.LottieAnimationView;
|
||||
|
||||
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.megaphone.Megaphones;
|
||||
import org.thoughtcrime.securesms.profiles.ProfileName;
|
||||
import org.thoughtcrime.securesms.profiles.edit.EditProfileActivity;
|
||||
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
|
||||
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
|
||||
public class MessageRequestMegaphoneActivity extends PassphraseRequiredActionBarActivity {
|
||||
|
||||
public static final short EDIT_PROFILE_REQUEST_CODE = 24563;
|
||||
|
||||
private DynamicTheme dynamicTheme = new DynamicNoActionBarTheme();
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState, boolean isReady) {
|
||||
dynamicTheme.onCreate(this);
|
||||
|
||||
setContentView(R.layout.message_requests_megaphone_activity);
|
||||
|
||||
|
||||
LottieAnimationView lottie = findViewById(R.id.message_requests_lottie);
|
||||
TextView profileNameButton = findViewById(R.id.message_requests_confirm_profile_name);
|
||||
|
||||
lottie.setAnimation(R.raw.lottie_message_requests_splash);
|
||||
lottie.playAnimation();
|
||||
|
||||
profileNameButton.setOnClickListener(v -> {
|
||||
final Intent profile = new Intent(this, EditProfileActivity.class);
|
||||
|
||||
profile.putExtra(EditProfileActivity.SHOW_TOOLBAR, false);
|
||||
profile.putExtra(EditProfileActivity.NEXT_BUTTON_TEXT, R.string.save);
|
||||
|
||||
startActivityForResult(profile, EDIT_PROFILE_REQUEST_CODE);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
|
||||
if (requestCode == EDIT_PROFILE_REQUEST_CODE &&
|
||||
resultCode == RESULT_OK &&
|
||||
TextSecurePreferences.getProfileName(this) != ProfileName.EMPTY) {
|
||||
ApplicationDependencies.getMegaphoneRepository().markFinished(Megaphones.Event.MESSAGE_REQUESTS);
|
||||
setResult(RESULT_OK);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
dynamicTheme.onResume(this);
|
||||
}
|
||||
}
|
||||
@@ -25,46 +25,26 @@ import org.whispersystems.libsignal.util.guava.Optional;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class MessageRequestFragmentRepository {
|
||||
public class MessageRequestRepository {
|
||||
|
||||
private final Context context;
|
||||
private final RecipientId recipientId;
|
||||
private final long threadId;
|
||||
private final LiveRecipient liveRecipient;
|
||||
|
||||
public MessageRequestFragmentRepository(@NonNull Context context, @NonNull RecipientId recipientId, long threadId) {
|
||||
public MessageRequestRepository(@NonNull Context context) {
|
||||
this.context = context.getApplicationContext();
|
||||
this.recipientId = recipientId;
|
||||
this.threadId = threadId;
|
||||
this.liveRecipient = Recipient.live(recipientId);
|
||||
}
|
||||
|
||||
public LiveRecipient getLiveRecipient() {
|
||||
return liveRecipient;
|
||||
public LiveRecipient getLiveRecipient(@NonNull RecipientId recipientId) {
|
||||
return Recipient.live(recipientId);
|
||||
}
|
||||
|
||||
public void refreshRecipient() {
|
||||
SignalExecutors.BOUNDED.execute(liveRecipient::refresh);
|
||||
}
|
||||
|
||||
public void getMessageRecord(@NonNull Consumer<MessageRecord> onMessageRecordLoaded) {
|
||||
SimpleTask.run(() -> {
|
||||
MmsSmsDatabase mmsSmsDatabase = DatabaseFactory.getMmsSmsDatabase(context);
|
||||
try (Cursor cursor = mmsSmsDatabase.getConversation(threadId, 0, 1)) {
|
||||
if (!cursor.moveToFirst()) return null;
|
||||
return mmsSmsDatabase.readerFor(cursor).getCurrent();
|
||||
}
|
||||
}, onMessageRecordLoaded::accept);
|
||||
}
|
||||
|
||||
public void getGroups(@NonNull Consumer<List<String>> onGroupsLoaded) {
|
||||
public void getGroups(@NonNull RecipientId recipientId, @NonNull Consumer<List<String>> onGroupsLoaded) {
|
||||
SimpleTask.run(() -> {
|
||||
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
||||
return groupDatabase.getGroupNamesContainingMember(recipientId);
|
||||
}, onGroupsLoaded::accept);
|
||||
}
|
||||
|
||||
public void getMemberCount(@NonNull Consumer<Integer> onMemberCountLoaded) {
|
||||
public void getMemberCount(@NonNull RecipientId recipientId, @NonNull Consumer<Integer> onMemberCountLoaded) {
|
||||
SimpleTask.run(() -> {
|
||||
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
||||
Optional<GroupDatabase.GroupRecord> groupRecord = groupDatabase.getGroup(recipientId);
|
||||
@@ -72,10 +52,15 @@ public class MessageRequestFragmentRepository {
|
||||
}, onMemberCountLoaded::accept);
|
||||
}
|
||||
|
||||
public void acceptMessageRequest(@NonNull Runnable onMessageRequestAccepted) {
|
||||
public void getMessageRequestAccepted(long threadId, @NonNull Consumer<Boolean> recipientRequestAccepted) {
|
||||
SimpleTask.run(() -> RecipientUtil.isThreadMessageRequestAccepted(context, threadId),
|
||||
recipientRequestAccepted::accept);
|
||||
}
|
||||
|
||||
public void acceptMessageRequest(@NonNull LiveRecipient liveRecipient, long threadId, @NonNull Runnable onMessageRequestAccepted) {
|
||||
SimpleTask.run(() -> {
|
||||
RecipientDatabase recipientDatabase = DatabaseFactory.getRecipientDatabase(context);
|
||||
recipientDatabase.setProfileSharing(recipientId, true);
|
||||
recipientDatabase.setProfileSharing(liveRecipient.getId(), true);
|
||||
liveRecipient.refresh();
|
||||
|
||||
List<MessagingDatabase.MarkedMessageInfo> messageIds = DatabaseFactory.getThreadDatabase(context)
|
||||
@@ -87,7 +72,7 @@ public class MessageRequestFragmentRepository {
|
||||
}, v -> onMessageRequestAccepted.run());
|
||||
}
|
||||
|
||||
public void deleteMessageRequest(@NonNull Runnable onMessageRequestDeleted) {
|
||||
public void deleteMessageRequest(long threadId, @NonNull Runnable onMessageRequestDeleted) {
|
||||
SimpleTask.run(() -> {
|
||||
ThreadDatabase threadDatabase = DatabaseFactory.getThreadDatabase(context);
|
||||
threadDatabase.deleteConversation(threadId);
|
||||
@@ -95,7 +80,7 @@ public class MessageRequestFragmentRepository {
|
||||
}, v -> onMessageRequestDeleted.run());
|
||||
}
|
||||
|
||||
public void blockMessageRequest(@NonNull Runnable onMessageRequestBlocked) {
|
||||
public void blockMessageRequest(@NonNull LiveRecipient liveRecipient, @NonNull Runnable onMessageRequestBlocked) {
|
||||
SimpleTask.run(() -> {
|
||||
Recipient recipient = liveRecipient.resolve();
|
||||
RecipientUtil.block(context, recipient);
|
||||
@@ -0,0 +1,177 @@
|
||||
package org.thoughtcrime.securesms.messagerequests;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.MainThread;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
import androidx.lifecycle.Transformations;
|
||||
import androidx.lifecycle.ViewModel;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
import org.thoughtcrime.securesms.recipients.LiveRecipient;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientForeverObserver;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.SingleLiveEvent;
|
||||
import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;
|
||||
import org.thoughtcrime.securesms.util.livedata.LiveDataTriple;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class MessageRequestViewModel extends ViewModel {
|
||||
|
||||
private final SingleLiveEvent<Status> status = new SingleLiveEvent<>();
|
||||
private final MutableLiveData<Recipient> recipient = new MutableLiveData<>();
|
||||
private final MutableLiveData<List<String>> groups = new MutableLiveData<>(Collections.emptyList());
|
||||
private final MutableLiveData<Integer> memberCount = new MutableLiveData<>(0);
|
||||
private final MutableLiveData<Boolean> shouldDisplayMessageRequest = new MutableLiveData<>();
|
||||
private final LiveData<RecipientInfo> recipientInfo = Transformations.map(new LiveDataTriple<>(recipient, memberCount, groups),
|
||||
triple -> new RecipientInfo(triple.first(), triple.second(), triple.third()));
|
||||
|
||||
private final MessageRequestRepository repository;
|
||||
|
||||
private LiveRecipient liveRecipient;
|
||||
private long threadId;
|
||||
|
||||
@SuppressWarnings("CodeBlock2Expr")
|
||||
private final RecipientForeverObserver recipientObserver = recipient -> {
|
||||
if (Recipient.self().equals(recipient) || recipient.isBlocked() || recipient.isForceSmsSelection() || !recipient.isRegistered()) {
|
||||
shouldDisplayMessageRequest.setValue(false);
|
||||
} else {
|
||||
loadMessageRequestAccepted();
|
||||
}
|
||||
this.recipient.setValue(recipient);
|
||||
};
|
||||
|
||||
private MessageRequestViewModel(MessageRequestRepository repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
public void setConversationInfo(@NonNull RecipientId recipientId, long threadId) {
|
||||
if (liveRecipient != null) {
|
||||
liveRecipient.removeForeverObserver(recipientObserver);
|
||||
}
|
||||
|
||||
liveRecipient = Recipient.live(recipientId);
|
||||
this.threadId = threadId;
|
||||
|
||||
loadRecipient();
|
||||
loadGroups();
|
||||
loadMemberCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCleared() {
|
||||
if (liveRecipient != null) {
|
||||
liveRecipient.removeForeverObserver(recipientObserver);
|
||||
}
|
||||
}
|
||||
|
||||
public LiveData<Boolean> getShouldDisplayMessageRequest() {
|
||||
return shouldDisplayMessageRequest;
|
||||
}
|
||||
|
||||
public LiveData<Recipient> getRecipient() {
|
||||
return recipient;
|
||||
}
|
||||
|
||||
public LiveData<RecipientInfo> getRecipientInfo() {
|
||||
return recipientInfo;
|
||||
}
|
||||
|
||||
public LiveData<Status> getMesasgeRequestStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
@MainThread
|
||||
public void accept() {
|
||||
repository.acceptMessageRequest(liveRecipient, threadId, () -> {
|
||||
status.setValue(Status.ACCEPTED);
|
||||
});
|
||||
}
|
||||
|
||||
@MainThread
|
||||
public void delete() {
|
||||
repository.deleteMessageRequest(threadId, () -> {
|
||||
status.setValue(Status.DELETED);
|
||||
});
|
||||
}
|
||||
|
||||
@MainThread
|
||||
public void block() {
|
||||
repository.blockMessageRequest(liveRecipient, () -> {
|
||||
status.setValue(Status.BLOCKED);
|
||||
});
|
||||
}
|
||||
|
||||
private void loadRecipient() {
|
||||
liveRecipient.observeForever(recipientObserver);
|
||||
SignalExecutors.BOUNDED.execute(liveRecipient::refresh);
|
||||
}
|
||||
|
||||
private void loadGroups() {
|
||||
repository.getGroups(liveRecipient.getId(), this.groups::setValue);
|
||||
}
|
||||
|
||||
private void loadMemberCount() {
|
||||
repository.getMemberCount(liveRecipient.getId(), memberCount -> {
|
||||
this.memberCount.setValue(memberCount == null ? 0 : memberCount);
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
private void loadMessageRequestAccepted() {
|
||||
repository.getMessageRequestAccepted(threadId, accepted -> shouldDisplayMessageRequest.setValue(!accepted));
|
||||
}
|
||||
|
||||
public static class Factory implements ViewModelProvider.Factory {
|
||||
|
||||
private final Context context;
|
||||
|
||||
public Factory(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
|
||||
return (T) new MessageRequestViewModel(new MessageRequestRepository(context.getApplicationContext()));
|
||||
}
|
||||
}
|
||||
|
||||
public static class RecipientInfo {
|
||||
private final @Nullable Recipient recipient;
|
||||
private final int groupMemberCount;
|
||||
private final @NonNull List<String> sharedGroups;
|
||||
|
||||
private RecipientInfo(@Nullable Recipient recipient, @Nullable Integer groupMemberCount, @Nullable List<String> sharedGroups) {
|
||||
this.recipient = recipient;
|
||||
this.groupMemberCount = groupMemberCount == null ? 0 : groupMemberCount;
|
||||
this.sharedGroups = sharedGroups == null ? Collections.emptyList() : sharedGroups;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Recipient getRecipient() {
|
||||
return recipient;
|
||||
}
|
||||
|
||||
public int getGroupMemberCount() {
|
||||
return groupMemberCount;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public List<String> getSharedGroups() {
|
||||
return sharedGroups;
|
||||
}
|
||||
}
|
||||
|
||||
public enum Status {
|
||||
BLOCKED,
|
||||
DELETED,
|
||||
ACCEPTED
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package org.thoughtcrime.securesms.messagerequests;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
|
||||
public class MessageRequestsBottomView extends ConstraintLayout {
|
||||
|
||||
private TextView question;
|
||||
private View accept;
|
||||
private View block;
|
||||
private View delete;
|
||||
|
||||
public MessageRequestsBottomView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public MessageRequestsBottomView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public MessageRequestsBottomView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
|
||||
inflate(getContext(), R.layout.message_request_bottom_bar, this);
|
||||
|
||||
question = findViewById(R.id.message_request_question);
|
||||
accept = findViewById(R.id.message_request_accept);
|
||||
block = findViewById(R.id.message_request_block);
|
||||
delete = findViewById(R.id.message_request_delete);
|
||||
}
|
||||
|
||||
public void setQuestionText(CharSequence questionText) {
|
||||
question.setText(questionText);
|
||||
}
|
||||
|
||||
public void setAcceptOnClickListener(OnClickListener acceptOnClickListener) {
|
||||
accept.setOnClickListener(acceptOnClickListener);
|
||||
}
|
||||
|
||||
public void setDeleteOnClickListener(OnClickListener deleteOnClickListener) {
|
||||
delete.setOnClickListener(deleteOnClickListener);
|
||||
}
|
||||
|
||||
public void setBlockOnClickListener(OnClickListener blockOnClickListener) {
|
||||
block.setOnClickListener(blockOnClickListener);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user