diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a95a9baebe..bc9e379d11 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -206,18 +206,6 @@
android:resource="@mipmap/ic_launcher" />
-
-
-
-
-
.
- */
-package org.thoughtcrime.securesms;
-
-import android.annotation.SuppressLint;
-import android.content.ClipData;
-import android.content.ClipboardManager;
-import android.content.Context;
-import android.database.Cursor;
-import android.graphics.drawable.ColorDrawable;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ListView;
-import android.widget.TextView;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.loader.app.LoaderManager.LoaderCallbacks;
-import androidx.loader.content.Loader;
-import org.session.libsession.messaging.messages.visible.LinkPreview;
-import org.session.libsession.messaging.messages.visible.OpenGroupInvitation;
-import org.session.libsession.messaging.messages.visible.Quote;
-import org.session.libsession.messaging.messages.visible.VisibleMessage;
-import org.session.libsession.messaging.open_groups.OpenGroupV2;
-import org.session.libsession.messaging.sending_receiving.MessageSender;
-import org.session.libsession.messaging.utilities.UpdateMessageData;
-import org.thoughtcrime.securesms.MessageDetailsRecipientAdapter.RecipientDeliveryStatus;
-import org.session.libsession.utilities.MaterialColor;
-import org.thoughtcrime.securesms.conversation.ConversationItem;
-import org.thoughtcrime.securesms.database.DatabaseFactory;
-import org.thoughtcrime.securesms.database.GroupReceiptDatabase;
-import org.thoughtcrime.securesms.database.GroupReceiptDatabase.GroupReceiptInfo;
-import org.thoughtcrime.securesms.database.MmsDatabase;
-import org.thoughtcrime.securesms.database.MmsSmsDatabase;
-import org.thoughtcrime.securesms.database.SmsDatabase;
-import org.thoughtcrime.securesms.database.loaders.MessageDetailsLoader;
-import org.thoughtcrime.securesms.database.model.MessageRecord;
-import org.session.libsignal.utilities.Log;
-import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
-import org.thoughtcrime.securesms.loki.database.LokiMessageDatabase;
-import org.thoughtcrime.securesms.mms.GlideApp;
-import org.thoughtcrime.securesms.mms.GlideRequests;
-import org.session.libsession.utilities.recipients.Recipient;
-import org.session.libsession.utilities.recipients.RecipientModifiedListener;
-import org.thoughtcrime.securesms.util.DateUtils;
-import org.session.libsession.utilities.ExpirationUtil;
-import org.session.libsession.utilities.Util;
-import org.session.libsignal.utilities.guava.Optional;
-
-import java.lang.ref.WeakReference;
-import java.sql.Date;
-import java.text.SimpleDateFormat;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Locale;
-
-import network.loki.messenger.R;
-
-/**
- * @author Jake McGinty
- */
-public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity implements LoaderCallbacks, RecipientModifiedListener {
- private final static String TAG = MessageDetailsActivity.class.getSimpleName();
-
- public final static String MESSAGE_ID_EXTRA = "message_id";
- public final static String THREAD_ID_EXTRA = "thread_id";
- public final static String IS_PUSH_GROUP_EXTRA = "is_push_group";
- public final static String TYPE_EXTRA = "type";
- public final static String ADDRESS_EXTRA = "address";
-
- private GlideRequests glideRequests;
- private long threadId;
- private boolean isPushGroup;
- private ConversationItem conversationItem;
- private ViewGroup itemParent;
- private View metadataContainer;
- private View expiresContainer;
- private TextView errorText;
- private View resendButton;
- private TextView sentDate;
- private TextView receivedDate;
- private TextView expiresInText;
- private View receivedContainer;
- private TextView transport;
- private TextView toFrom;
- private View separator;
- private ListView recipientsList;
- private LayoutInflater inflater;
-
- private boolean running;
-
- @Override
- public void onCreate(Bundle bundle, boolean ready) {
- super.onCreate(bundle, ready);
- setContentView(R.layout.message_details_activity);
- running = true;
-
- initializeResources();
- initializeActionBar();
- getSupportLoaderManager().initLoader(0, null, this);
- }
-
- @Override
- protected void onResume() {
- super.onResume();
-
- assert getSupportActionBar() != null;
- getSupportActionBar().setTitle("Message Details");
-
- ApplicationContext.getInstance(this).messageNotifier.setVisibleThread(threadId);
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- ApplicationContext.getInstance(this).messageNotifier.setVisibleThread(-1L);
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- running = false;
- }
-
- private void initializeActionBar() {
- assert getSupportActionBar() != null;
-
- Recipient recipient = Recipient.from(this, getIntent().getParcelableExtra(ADDRESS_EXTRA), true);
- recipient.addListener(this);
- }
-
- private void setActionBarColor(MaterialColor color) {
- assert getSupportActionBar() != null;
- getSupportActionBar().setBackgroundDrawable(new ColorDrawable(color.toActionBarColor(this)));
- }
-
- @Override
- public void onModified(final Recipient recipient) {
- Util.runOnMain(() -> setActionBarColor(recipient.getColor()));
- }
-
- private void initializeResources() {
- inflater = LayoutInflater.from(this);
- View header = inflater.inflate(R.layout.message_details_header, recipientsList, false);
-
- threadId = getIntent().getLongExtra(THREAD_ID_EXTRA, -1);
- isPushGroup = getIntent().getBooleanExtra(IS_PUSH_GROUP_EXTRA, false);
- glideRequests = GlideApp.with(this);
- itemParent = header.findViewById(R.id.item_container);
- recipientsList = findViewById(R.id.recipients_list);
- metadataContainer = header.findViewById(R.id.metadata_container);
- errorText = header.findViewById(R.id.error_text);
- resendButton = header.findViewById(R.id.resend_button);
- sentDate = header.findViewById(R.id.sent_time);
- receivedContainer = header.findViewById(R.id.received_container);
- receivedDate = header.findViewById(R.id.received_time);
- transport = header.findViewById(R.id.transport);
- toFrom = header.findViewById(R.id.tofrom);
- separator = header.findViewById(R.id.separator);
- expiresContainer = header.findViewById(R.id.expires_container);
- expiresInText = header.findViewById(R.id.expires_in);
- recipientsList.setHeaderDividersEnabled(false);
- recipientsList.addHeaderView(header, null, false);
- }
-
- private void updateTransport(MessageRecord messageRecord) {
- final String transportText;
- if (messageRecord.isOutgoing() && messageRecord.isFailed()) {
- transportText = "-";
- } else if (messageRecord.isPending()) {
- transportText = getString(R.string.ConversationFragment_pending);
- } else if (messageRecord.isMms()) {
- transportText = getString(R.string.ConversationFragment_mms);
- } else {
- transportText = getString(R.string.ConversationFragment_sms);
- }
-
- transport.setText(transportText);
- }
-
- private void updateTime(MessageRecord messageRecord) {
- sentDate.setOnLongClickListener(null);
- receivedDate.setOnLongClickListener(null);
-
- if (messageRecord.isPending() || messageRecord.isFailed()) {
- sentDate.setText("-");
- receivedContainer.setVisibility(View.GONE);
- } else {
- Locale dateLocale = Locale.getDefault();
- SimpleDateFormat dateFormatter = DateUtils.getDetailedDateFormatter(this, dateLocale);
- sentDate.setText(dateFormatter.format(new Date(messageRecord.getDateSent())));
- sentDate.setOnLongClickListener(v -> {
- copyToClipboard(String.valueOf(messageRecord.getDateSent()));
- return true;
- });
-
- if (messageRecord.getDateReceived() != messageRecord.getDateSent() && !messageRecord.isOutgoing()) {
- receivedDate.setText(dateFormatter.format(new Date(messageRecord.getDateReceived())));
- receivedDate.setOnLongClickListener(v -> {
- copyToClipboard(String.valueOf(messageRecord.getDateReceived()));
- return true;
- });
- receivedContainer.setVisibility(View.VISIBLE);
- } else {
- receivedContainer.setVisibility(View.GONE);
- }
- }
- }
-
- private void updateExpirationTime(final MessageRecord messageRecord) {
- if (messageRecord.getExpiresIn() <= 0 || messageRecord.getExpireStarted() <= 0) {
- expiresContainer.setVisibility(View.GONE);
- return;
- }
-
- expiresContainer.setVisibility(View.VISIBLE);
- Util.runOnMain(new Runnable() {
- @Override
- public void run() {
- long elapsed = System.currentTimeMillis() - messageRecord.getExpireStarted();
- long remaining = messageRecord.getExpiresIn() - elapsed;
-
- String duration = ExpirationUtil.getExpirationDisplayValue(MessageDetailsActivity.this, Math.max((int)(remaining / 1000), 1));
- expiresInText.setText(duration);
-
- if (running) {
- Util.runOnMainDelayed(this, 500);
- }
- }
- });
- }
-
- private void updateRecipients(MessageRecord messageRecord, Recipient recipient, List recipients) {
- final int toFromRes;
- if (messageRecord.isOutgoing()) {
- toFromRes = R.string.message_details_header__to;
- } else {
- toFromRes = R.string.message_details_header__from;
- }
- toFrom.setText(toFromRes);
- long threadID = messageRecord.getThreadId();
- OpenGroupV2 openGroup = DatabaseFactory.getLokiThreadDatabase(this).getOpenGroupChat(threadID);
- if (openGroup != null && messageRecord.isOutgoing()) {
- toFrom.setVisibility(View.GONE);
- separator.setVisibility(View.GONE);
- }
- conversationItem.bind(messageRecord, Optional.absent(), Optional.absent(), glideRequests, Locale.getDefault(), new HashSet<>(), recipient, null, false);
- recipientsList.setAdapter(new MessageDetailsRecipientAdapter(this, glideRequests, messageRecord, recipients, isPushGroup));
- }
-
- private void inflateMessageViewIfAbsent(MessageRecord messageRecord) {
- if (conversationItem == null) {
- if (messageRecord.isOutgoing()) {
- conversationItem = (ConversationItem) inflater.inflate(R.layout.conversation_item_sent, itemParent, false);
- } else {
- conversationItem = (ConversationItem) inflater.inflate(R.layout.conversation_item_received, itemParent, false);
- }
- itemParent.addView(conversationItem);
- }
- }
-
- private @Nullable MessageRecord getMessageRecord(Context context, Cursor cursor, String type) {
- switch (type) {
- case MmsSmsDatabase.SMS_TRANSPORT:
- SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context);
- SmsDatabase.Reader reader = smsDatabase.readerFor(cursor);
- return reader.getNext();
- case MmsSmsDatabase.MMS_TRANSPORT:
- MmsDatabase mmsDatabase = DatabaseFactory.getMmsDatabase(context);
- MmsDatabase.Reader mmsReader = mmsDatabase.readerFor(cursor);
- return mmsReader.getNext();
- default:
- throw new AssertionError("no valid message type specified");
- }
- }
-
- private void copyToClipboard(@NonNull String text) {
- ((ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE)).setPrimaryClip(ClipData.newPlainText("text", text));
- }
-
- @Override
- public @NonNull Loader onCreateLoader(int id, Bundle args) {
- return new MessageDetailsLoader(this, getIntent().getStringExtra(TYPE_EXTRA),
- getIntent().getLongExtra(MESSAGE_ID_EXTRA, -1));
- }
-
- @Override
- public void onLoadFinished(@NonNull Loader loader, Cursor cursor) {
- MessageRecord messageRecord = getMessageRecord(this, cursor, getIntent().getStringExtra(TYPE_EXTRA));
-
- if (messageRecord == null) {
- finish();
- } else {
- new MessageRecipientAsyncTask(this, messageRecord).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- }
- }
-
- @Override
- public void onLoaderReset(@NonNull Loader loader) {
- recipientsList.setAdapter(null);
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- super.onOptionsItemSelected(item);
-
- switch (item.getItemId()) {
- case android.R.id.home: finish(); return true;
- }
-
- return false;
- }
-
- @SuppressLint("StaticFieldLeak")
- private class MessageRecipientAsyncTask extends AsyncTask> {
-
- private final WeakReference weakContext;
- private final MessageRecord messageRecord;
-
- MessageRecipientAsyncTask(@NonNull Context context, @NonNull MessageRecord messageRecord) {
- this.weakContext = new WeakReference<>(context);
- this.messageRecord = messageRecord;
- }
-
- protected Context getContext() {
- return weakContext.get();
- }
-
- @Override
- public List doInBackground(Void... voids) {
- Context context = getContext();
-
- if (context == null) {
- Log.w(TAG, "associated context is destroyed, finishing early");
- return null;
- }
-
- List recipients = new LinkedList<>();
-
- if (!messageRecord.getRecipient().isGroupRecipient()) {
- recipients.add(new RecipientDeliveryStatus(messageRecord.getRecipient(), getStatusFor(messageRecord.getDeliveryReceiptCount(), messageRecord.getReadReceiptCount(), messageRecord.isPending()), true, -1));
- } else {
- List receiptInfoList = DatabaseFactory.getGroupReceiptDatabase(context).getGroupReceiptInfo(messageRecord.getId());
-
- if (receiptInfoList.isEmpty()) {
- List group = DatabaseFactory.getGroupDatabase(context).getGroupMembers(messageRecord.getRecipient().getAddress().toGroupString(), false);
-
- for (Recipient recipient : group) {
- recipients.add(new RecipientDeliveryStatus(recipient, RecipientDeliveryStatus.Status.UNKNOWN, false, -1));
- }
- } else {
- for (GroupReceiptInfo info : receiptInfoList) {
- recipients.add(new RecipientDeliveryStatus(Recipient.from(context, info.getAddress(), true),
- getStatusFor(info.getStatus(), messageRecord.isPending(), messageRecord.isFailed()),
- info.isUnidentified(),
- info.getTimestamp()));
- }
- }
- }
-
- return recipients;
- }
-
- @Override
- public void onPostExecute(List recipients) {
- if (getContext() == null) {
- Log.w(TAG, "AsyncTask finished with a destroyed context, leaving early.");
- return;
- }
-
- inflateMessageViewIfAbsent(messageRecord);
- updateRecipients(messageRecord, messageRecord.getRecipient(), recipients);
-
- boolean isGroupNetworkFailure = messageRecord.isFailed() && !messageRecord.getNetworkFailures().isEmpty();
- boolean isIndividualNetworkFailure = messageRecord.isFailed() && !isPushGroup;
-
- LokiMessageDatabase lokiMessageDatabase = DatabaseFactory.getLokiMessageDatabase(getContext());
- String errorMessage = lokiMessageDatabase.getErrorMessage(messageRecord.id);
- if (errorMessage != null) {
- errorText.setText(errorMessage);
- }
-
- if (isGroupNetworkFailure || isIndividualNetworkFailure) {
- errorText.setVisibility(View.VISIBLE);
- resendButton.setVisibility(View.VISIBLE);
- resendButton.setOnClickListener(this::onResendClicked);
- metadataContainer.setVisibility(View.GONE);
- } else if (messageRecord.isFailed()) {
- errorText.setVisibility(View.VISIBLE);
- resendButton.setVisibility(View.GONE);
- resendButton.setOnClickListener(null);
- metadataContainer.setVisibility(View.GONE);
- } else {
- updateTransport(messageRecord);
- updateTime(messageRecord);
- updateExpirationTime(messageRecord);
- errorText.setVisibility(View.GONE);
- resendButton.setVisibility(View.GONE);
- resendButton.setOnClickListener(null);
- metadataContainer.setVisibility(View.VISIBLE);
- }
- }
-
- private RecipientDeliveryStatus.Status getStatusFor(int deliveryReceiptCount, int readReceiptCount, boolean pending) {
- if (readReceiptCount > 0) return RecipientDeliveryStatus.Status.READ;
- else if (deliveryReceiptCount > 0) return RecipientDeliveryStatus.Status.DELIVERED;
- else if (!pending) return RecipientDeliveryStatus.Status.SENT;
- else return RecipientDeliveryStatus.Status.PENDING;
- }
-
- private RecipientDeliveryStatus.Status getStatusFor(int groupStatus, boolean pending, boolean failed) {
- if (groupStatus == GroupReceiptDatabase.STATUS_READ) return RecipientDeliveryStatus.Status.READ;
- else if (groupStatus == GroupReceiptDatabase.STATUS_DELIVERED) return RecipientDeliveryStatus.Status.DELIVERED;
- else if (groupStatus == GroupReceiptDatabase.STATUS_UNDELIVERED && failed) return RecipientDeliveryStatus.Status.UNKNOWN;
- else if (groupStatus == GroupReceiptDatabase.STATUS_UNDELIVERED && !pending) return RecipientDeliveryStatus.Status.SENT;
- else if (groupStatus == GroupReceiptDatabase.STATUS_UNDELIVERED) return RecipientDeliveryStatus.Status.PENDING;
- else if (groupStatus == GroupReceiptDatabase.STATUS_UNKNOWN) return RecipientDeliveryStatus.Status.UNKNOWN;
- throw new AssertionError();
- }
-
- private void onResendClicked(View v) {
- Recipient recipient = messageRecord.getRecipient();
- VisibleMessage message = new VisibleMessage();
- message.setId(messageRecord.getId());
- if (messageRecord.isOpenGroupInvitation()) {
- OpenGroupInvitation openGroupInvitation = new OpenGroupInvitation();
- UpdateMessageData updateMessageData = UpdateMessageData.Companion.fromJSON(messageRecord.getBody());
- if (updateMessageData.getKind() instanceof UpdateMessageData.Kind.OpenGroupInvitation) {
- UpdateMessageData.Kind.OpenGroupInvitation data = (UpdateMessageData.Kind.OpenGroupInvitation)updateMessageData.getKind();
- openGroupInvitation.setName(data.getGroupName());
- openGroupInvitation.setUrl(data.getGroupUrl());
- }
- message.setOpenGroupInvitation(openGroupInvitation);
- } else {
- message.setText(messageRecord.getBody());
- }
- message.setSentTimestamp(messageRecord.getTimestamp());
- if (recipient.isGroupRecipient()) {
- message.setGroupPublicKey(recipient.getAddress().toGroupString());
- } else {
- message.setRecipient(messageRecord.getRecipient().getAddress().serialize());
- }
- message.setThreadID(messageRecord.getThreadId());
- if (messageRecord.isMms()) {
- MmsMessageRecord mmsMessageRecord = (MmsMessageRecord) messageRecord;
- if (!mmsMessageRecord.getLinkPreviews().isEmpty()) {
- message.setLinkPreview(LinkPreview.Companion.from(mmsMessageRecord.getLinkPreviews().get(0)));
- }
- if (mmsMessageRecord.getQuote() != null) {
- message.setQuote(Quote.Companion.from(mmsMessageRecord.getQuote().getQuoteModel()));
- }
- message.addSignalAttachments(mmsMessageRecord.getSlideDeck().asAttachments());
- }
- MessageSender.send(message, recipient.getAddress());
- resendButton.setVisibility(View.GONE);
- }
- }
-}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/ShareActivity.java b/app/src/main/java/org/thoughtcrime/securesms/ShareActivity.java
index 8f820cba54..ba7e145bf4 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/ShareActivity.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/ShareActivity.java
@@ -37,7 +37,7 @@ import androidx.appcompat.widget.Toolbar;
import org.session.libsession.utilities.DistributionTypes;
import org.thoughtcrime.securesms.components.SearchToolbar;
-import org.thoughtcrime.securesms.conversation.ConversationActivity;
+
import org.session.libsession.utilities.Address;
import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2;
import org.thoughtcrime.securesms.database.DatabaseFactory;
@@ -219,7 +219,6 @@ public class ShareActivity extends PassphraseRequiredActionBarActivity
final Intent intent = getBaseShareIntent(ConversationActivityV2.class);
intent.putExtra(ConversationActivityV2.ADDRESS, address);
intent.putExtra(ConversationActivityV2.THREAD_ID, threadId);
- intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, distributionType);
isPassingAlongMedia = true;
startActivity(intent);
@@ -227,11 +226,6 @@ public class ShareActivity extends PassphraseRequiredActionBarActivity
private Intent getBaseShareIntent(final @NonNull Class> target) {
final Intent intent = new Intent(this, target);
- final String textExtra = getIntent().getStringExtra(Intent.EXTRA_TEXT);
- final ArrayList mediaExtra = getIntent().getParcelableArrayListExtra(ConversationActivity.MEDIA_EXTRA);
-
- intent.putExtra(ConversationActivity.TEXT_EXTRA, textExtra);
- intent.putExtra(ConversationActivity.MEDIA_EXTRA, mediaExtra);
if (resolvedExtra != null) intent.setDataAndType(resolvedExtra, mimeType);
diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/ComposeText.java b/app/src/main/java/org/thoughtcrime/securesms/components/ComposeText.java
index 012086dc94..42825360c0 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/components/ComposeText.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/components/ComposeText.java
@@ -28,166 +28,166 @@ import org.session.libsession.utilities.TextSecurePreferences;
public class ComposeText extends EmojiEditText {
- private CharSequence hint;
- private SpannableString subHint;
+ private CharSequence hint;
+ private SpannableString subHint;
- @Nullable private InputPanel.MediaListener mediaListener;
- @Nullable private CursorPositionChangedListener cursorPositionChangedListener;
+ @Nullable private InputPanel.MediaListener mediaListener;
+ @Nullable private CursorPositionChangedListener cursorPositionChangedListener;
- public ComposeText(Context context) {
- super(context);
- initialize();
- }
-
- public ComposeText(Context context, AttributeSet attrs) {
- super(context, attrs);
- initialize();
- }
-
- public ComposeText(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- initialize();
- }
-
- public String getTextTrimmed(){
- return getText().toString().trim();
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
-
- if (!TextUtils.isEmpty(hint)) {
- if (!TextUtils.isEmpty(subHint)) {
- setHint(new SpannableStringBuilder().append(ellipsizeToWidth(hint))
- .append("\n")
- .append(ellipsizeToWidth(subHint)));
- } else {
- setHint(ellipsizeToWidth(hint));
- }
- }
- }
-
- @Override
- protected void onSelectionChanged(int selStart, int selEnd) {
- super.onSelectionChanged(selStart, selEnd);
-
- if (cursorPositionChangedListener != null) {
- cursorPositionChangedListener.onCursorPositionChanged(selStart, selEnd);
- }
- }
-
- private CharSequence ellipsizeToWidth(CharSequence text) {
- return TextUtils.ellipsize(text,
- getPaint(),
- getWidth() - getPaddingLeft() - getPaddingRight(),
- TruncateAt.END);
- }
-
- public void setHint(@NonNull String hint, @Nullable CharSequence subHint) {
- this.hint = hint;
-
- if (subHint != null) {
- this.subHint = new SpannableString(subHint);
- this.subHint.setSpan(new RelativeSizeSpan(0.5f), 0, subHint.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
- } else {
- this.subHint = null;
+ public ComposeText(Context context) {
+ super(context);
+ initialize();
}
- if (this.subHint != null) {
- super.setHint(new SpannableStringBuilder().append(ellipsizeToWidth(this.hint))
- .append("\n")
- .append(ellipsizeToWidth(this.subHint)));
- } else {
- super.setHint(ellipsizeToWidth(this.hint));
- }
- }
-
- public void setCursorPositionChangedListener(@Nullable CursorPositionChangedListener listener) {
- this.cursorPositionChangedListener = listener;
- }
-
- public void setTransport() {
- final boolean useSystemEmoji = TextSecurePreferences.isSystemEmojiPreferred(getContext());
- final boolean isIncognito = TextSecurePreferences.isIncognitoKeyboardEnabled(getContext());
-
- int imeOptions = (getImeOptions() & ~EditorInfo.IME_MASK_ACTION) | EditorInfo.IME_ACTION_SEND;
- int inputType = getInputType();
-
- setImeActionLabel(null, 0);
-
- if (useSystemEmoji) {
- inputType = (inputType & ~InputType.TYPE_MASK_VARIATION) | InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE;
+ public ComposeText(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ initialize();
}
- setInputType(inputType);
- if (isIncognito) {
- setImeOptions(imeOptions | 16777216);
- } else {
- setImeOptions(imeOptions);
- }
- }
-
- @Override
- public InputConnection onCreateInputConnection(EditorInfo editorInfo) {
- InputConnection inputConnection = super.onCreateInputConnection(editorInfo);
-
- if(TextSecurePreferences.isEnterSendsEnabled(getContext())) {
- editorInfo.imeOptions &= ~EditorInfo.IME_FLAG_NO_ENTER_ACTION;
+ public ComposeText(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ initialize();
}
- if (Build.VERSION.SDK_INT < 21) return inputConnection;
- if (mediaListener == null) return inputConnection;
- if (inputConnection == null) return null;
-
- EditorInfoCompat.setContentMimeTypes(editorInfo, new String[] {"image/jpeg", "image/png", "image/gif"});
- return InputConnectionCompat.createWrapper(inputConnection, editorInfo, new CommitContentListener(mediaListener));
- }
-
- public void setMediaListener(@Nullable InputPanel.MediaListener mediaListener) {
- this.mediaListener = mediaListener;
- }
-
- private void initialize() {
- if (TextSecurePreferences.isIncognitoKeyboardEnabled(getContext())) {
- setImeOptions(getImeOptions() | 16777216);
- }
- }
-
- @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB_MR2)
- private static class CommitContentListener implements InputConnectionCompat.OnCommitContentListener {
-
- private static final String TAG = CommitContentListener.class.getSimpleName();
-
- private final InputPanel.MediaListener mediaListener;
-
- private CommitContentListener(@NonNull InputPanel.MediaListener mediaListener) {
- this.mediaListener = mediaListener;
+ public String getTextTrimmed(){
+ return getText().toString().trim();
}
@Override
- public boolean onCommitContent(InputContentInfoCompat inputContentInfo, int flags, Bundle opts) {
- if (BuildCompat.isAtLeastNMR1() && (flags & InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION) != 0) {
- try {
- inputContentInfo.requestPermission();
- } catch (Exception e) {
- Log.w(TAG, e);
- return false;
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+
+ if (!TextUtils.isEmpty(hint)) {
+ if (!TextUtils.isEmpty(subHint)) {
+ setHint(new SpannableStringBuilder().append(ellipsizeToWidth(hint))
+ .append("\n")
+ .append(ellipsizeToWidth(subHint)));
+ } else {
+ setHint(ellipsizeToWidth(hint));
+ }
}
- }
-
- if (inputContentInfo.getDescription().getMimeTypeCount() > 0) {
- mediaListener.onMediaSelected(inputContentInfo.getContentUri(),
- inputContentInfo.getDescription().getMimeType(0));
-
- return true;
- }
-
- return false;
}
- }
- public interface CursorPositionChangedListener {
- void onCursorPositionChanged(int start, int end);
- }
+ @Override
+ protected void onSelectionChanged(int selStart, int selEnd) {
+ super.onSelectionChanged(selStart, selEnd);
+
+ if (cursorPositionChangedListener != null) {
+ cursorPositionChangedListener.onCursorPositionChanged(selStart, selEnd);
+ }
+ }
+
+ private CharSequence ellipsizeToWidth(CharSequence text) {
+ return TextUtils.ellipsize(text,
+ getPaint(),
+ getWidth() - getPaddingLeft() - getPaddingRight(),
+ TruncateAt.END);
+ }
+
+ public void setHint(@NonNull String hint, @Nullable CharSequence subHint) {
+ this.hint = hint;
+
+ if (subHint != null) {
+ this.subHint = new SpannableString(subHint);
+ this.subHint.setSpan(new RelativeSizeSpan(0.5f), 0, subHint.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
+ } else {
+ this.subHint = null;
+ }
+
+ if (this.subHint != null) {
+ super.setHint(new SpannableStringBuilder().append(ellipsizeToWidth(this.hint))
+ .append("\n")
+ .append(ellipsizeToWidth(this.subHint)));
+ } else {
+ super.setHint(ellipsizeToWidth(this.hint));
+ }
+ }
+
+ public void setCursorPositionChangedListener(@Nullable CursorPositionChangedListener listener) {
+ this.cursorPositionChangedListener = listener;
+ }
+
+ public void setTransport() {
+ final boolean useSystemEmoji = TextSecurePreferences.isSystemEmojiPreferred(getContext());
+ final boolean isIncognito = TextSecurePreferences.isIncognitoKeyboardEnabled(getContext());
+
+ int imeOptions = (getImeOptions() & ~EditorInfo.IME_MASK_ACTION) | EditorInfo.IME_ACTION_SEND;
+ int inputType = getInputType();
+
+ setImeActionLabel(null, 0);
+
+ if (useSystemEmoji) {
+ inputType = (inputType & ~InputType.TYPE_MASK_VARIATION) | InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE;
+ }
+
+ setInputType(inputType);
+ if (isIncognito) {
+ setImeOptions(imeOptions | 16777216);
+ } else {
+ setImeOptions(imeOptions);
+ }
+ }
+
+ @Override
+ public InputConnection onCreateInputConnection(EditorInfo editorInfo) {
+ InputConnection inputConnection = super.onCreateInputConnection(editorInfo);
+
+ if(TextSecurePreferences.isEnterSendsEnabled(getContext())) {
+ editorInfo.imeOptions &= ~EditorInfo.IME_FLAG_NO_ENTER_ACTION;
+ }
+
+ if (Build.VERSION.SDK_INT < 21) return inputConnection;
+ if (mediaListener == null) return inputConnection;
+ if (inputConnection == null) return null;
+
+ EditorInfoCompat.setContentMimeTypes(editorInfo, new String[] {"image/jpeg", "image/png", "image/gif"});
+ return InputConnectionCompat.createWrapper(inputConnection, editorInfo, new CommitContentListener(mediaListener));
+ }
+
+ public void setMediaListener(@Nullable InputPanel.MediaListener mediaListener) {
+ this.mediaListener = mediaListener;
+ }
+
+ private void initialize() {
+ if (TextSecurePreferences.isIncognitoKeyboardEnabled(getContext())) {
+ setImeOptions(getImeOptions() | 16777216);
+ }
+ }
+
+ @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB_MR2)
+ private static class CommitContentListener implements InputConnectionCompat.OnCommitContentListener {
+
+ private static final String TAG = CommitContentListener.class.getSimpleName();
+
+ private final InputPanel.MediaListener mediaListener;
+
+ private CommitContentListener(@NonNull InputPanel.MediaListener mediaListener) {
+ this.mediaListener = mediaListener;
+ }
+
+ @Override
+ public boolean onCommitContent(InputContentInfoCompat inputContentInfo, int flags, Bundle opts) {
+ if (BuildCompat.isAtLeastNMR1() && (flags & InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION) != 0) {
+ try {
+ inputContentInfo.requestPermission();
+ } catch (Exception e) {
+ Log.w(TAG, e);
+ return false;
+ }
+ }
+
+ if (inputContentInfo.getDescription().getMimeTypeCount() > 0) {
+ mediaListener.onMediaSelected(inputContentInfo.getContentUri(),
+ inputContentInfo.getDescription().getMimeType(0));
+
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ public interface CursorPositionChangedListener {
+ void onCursorPositionChanged(int start, int end);
+ }
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/ConversationSearchBottomBar.java b/app/src/main/java/org/thoughtcrime/securesms/components/ConversationSearchBottomBar.java
deleted file mode 100644
index 603c4869a1..0000000000
--- a/app/src/main/java/org/thoughtcrime/securesms/components/ConversationSearchBottomBar.java
+++ /dev/null
@@ -1,88 +0,0 @@
-package org.thoughtcrime.securesms.components;
-
-import android.content.Context;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.constraintlayout.widget.ConstraintLayout;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.TextView;
-
-import network.loki.messenger.R;
-
-/**
- * Bottom navigation bar shown in the {@link org.thoughtcrime.securesms.conversation.ConversationActivity}
- * when the user is searching within a conversation. Shows details about the results and allows the
- * user to move between them.
- */
-public class ConversationSearchBottomBar extends ConstraintLayout {
-
- private View searchDown;
- private View searchUp;
- private TextView searchPositionText;
- private View progressWheel;
-
- private EventListener eventListener;
-
-
- public ConversationSearchBottomBar(Context context) {
- super(context);
- }
-
- public ConversationSearchBottomBar(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
-
- this.searchUp = findViewById(R.id.conversation_search_up);
- this.searchDown = findViewById(R.id.conversation_search_down);
- this.searchPositionText = findViewById(R.id.conversation_search_position);
- this.progressWheel = findViewById(R.id.conversation_search_progress_wheel);
- }
-
- public void setData(int position, int count) {
- progressWheel.setVisibility(GONE);
-
- searchUp.setOnClickListener(v -> {
- if (eventListener != null) {
- eventListener.onSearchMoveUpPressed();
- }
- });
-
- searchDown.setOnClickListener(v -> {
- if (eventListener != null) {
- eventListener.onSearchMoveDownPressed();
- }
- });
-
- if (count > 0) {
- searchPositionText.setText(getResources().getString(R.string.ConversationActivity_search_position, position + 1, count));
- } else {
- searchPositionText.setText(R.string.ConversationActivity_no_results);
- }
-
- setViewEnabled(searchUp, position < (count - 1));
- setViewEnabled(searchDown, position > 0);
- }
-
- public void showLoading() {
- progressWheel.setVisibility(VISIBLE);
- }
-
- private void setViewEnabled(@NonNull View view, boolean enabled) {
- view.setEnabled(enabled);
- view.setAlpha(enabled ? 1f : 0.25f);
- }
-
- public void setEventListener(@Nullable EventListener eventListener) {
- this.eventListener = eventListener;
- }
-
- public interface EventListener {
- void onSearchMoveUpPressed();
- void onSearchMoveDownPressed();
- }
-}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/ConversationTypingView.java b/app/src/main/java/org/thoughtcrime/securesms/components/ConversationTypingView.java
deleted file mode 100644
index ddc782628a..0000000000
--- a/app/src/main/java/org/thoughtcrime/securesms/components/ConversationTypingView.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package org.thoughtcrime.securesms.components;
-
-import android.content.Context;
-import android.graphics.PorterDuff;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.LinearLayout;
-
-import org.thoughtcrime.securesms.conversation.v2.components.TypingIndicatorView;
-import org.thoughtcrime.securesms.mms.GlideRequests;
-import org.session.libsession.utilities.recipients.Recipient;
-import org.session.libsession.utilities.ThemeUtil;
-
-
-import java.util.List;
-
-import network.loki.messenger.R;
-
-public class ConversationTypingView extends LinearLayout {
-
- private AvatarImageView avatar;
- private View bubble;
- private TypingIndicatorView indicator;
-
- public ConversationTypingView(Context context, @Nullable AttributeSet attrs) {
- super(context, attrs);
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
-
- avatar = findViewById(R.id.typing_avatar);
- bubble = findViewById(R.id.typing_bubble);
- indicator = findViewById(R.id.typing_indicator);
- }
-
- public void setTypists(@NonNull GlideRequests glideRequests, @NonNull List typists, boolean isGroupThread) {
- if (typists.isEmpty()) {
- indicator.stopAnimation();
- return;
- }
-
- Recipient typist = typists.get(0);
-
- bubble.getBackground().setColorFilter(
- ThemeUtil.getThemedColor(getContext(), R.attr.message_received_background_color),
- PorterDuff.Mode.MULTIPLY);
-
- if (isGroupThread) {
- avatar.setAvatar(glideRequests, typist, false);
- avatar.setVisibility(VISIBLE);
- } else {
- avatar.setVisibility(GONE);
- }
-
- indicator.startAnimation();
- }
-}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/InputPanel.java b/app/src/main/java/org/thoughtcrime/securesms/components/InputPanel.java
index 9b05c269a4..e81757026c 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/components/InputPanel.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/components/InputPanel.java
@@ -4,443 +4,26 @@ import android.annotation.TargetApi;
import android.content.Context;
import android.net.Uri;
import android.os.Build;
-import androidx.annotation.DimenRes;
-import androidx.annotation.MainThread;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.core.view.ViewCompat;
-import android.text.format.DateUtils;
import android.util.AttributeSet;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.animation.AlphaAnimation;
-import android.view.animation.Animation;
-import android.view.animation.AnimationSet;
-import android.view.animation.Interpolator;
-import android.view.animation.TranslateAnimation;
import android.widget.LinearLayout;
-import android.widget.TextView;
-import android.widget.Toast;
-import org.thoughtcrime.securesms.components.emoji.EmojiKeyboardProvider;
-import org.thoughtcrime.securesms.components.emoji.EmojiToggle;
-import org.thoughtcrime.securesms.components.emoji.MediaKeyboard;
-import org.session.libsignal.utilities.Log;
-import org.thoughtcrime.securesms.loki.utilities.MentionUtilities;
-import org.thoughtcrime.securesms.mms.GlideRequests;
-import org.thoughtcrime.securesms.mms.SlideDeck;
+public class InputPanel extends LinearLayout {
-import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview;
-import org.session.libsession.messaging.sending_receiving.quotes.QuoteModel;
-import org.session.libsession.utilities.recipients.Recipient;
-import org.session.libsession.utilities.TextSecurePreferences;
-import org.session.libsession.utilities.Util;
-import org.session.libsession.utilities.ViewUtil;
-import org.session.libsession.utilities.concurrent.AssertedSuccessListener;
-import org.session.libsignal.utilities.ListenableFuture;
-import org.session.libsignal.utilities.SettableFuture;
-import org.session.libsignal.utilities.guava.Optional;
-
-import java.util.concurrent.TimeUnit;
-
-import network.loki.messenger.R;
-
-public class InputPanel extends LinearLayout
- implements MicrophoneRecorderView.Listener,
- KeyboardAwareLinearLayout.OnKeyboardShownListener,
- EmojiKeyboardProvider.EmojiEventListener
-{
-
- private static final String TAG = InputPanel.class.getSimpleName();
-
- private static final int FADE_TIME = 150;
-
- private QuoteView quoteView;
- private LinkPreviewView linkPreview;
- private EmojiToggle mediaKeyboard;
- public ComposeText composeText;
- private View quickCameraToggle;
- private View quickAudioToggle;
- private View buttonToggle;
- private View recordingContainer;
- private View recordLockCancel;
-
- private MicrophoneRecorderView microphoneRecorderView;
- private SlideToCancel slideToCancel;
- private RecordTime recordTime;
-
- private @Nullable Listener listener;
- private boolean emojiVisible;
-
- public InputPanel(Context context) {
- super(context);
- }
-
- public InputPanel(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- @TargetApi(Build.VERSION_CODES.HONEYCOMB)
- public InputPanel(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
-
- @Override
- public void onFinishInflate() {
- super.onFinishInflate();
-
- View quoteDismiss = findViewById(R.id.quote_dismiss);
-
- this.quoteView = findViewById(R.id.quote_view);
- this.linkPreview = findViewById(R.id.link_preview);
- this.mediaKeyboard = findViewById(R.id.emoji_toggle);
- this.composeText = findViewById(R.id.embedded_text_editor);
- this.quickCameraToggle = findViewById(R.id.quick_camera_toggle);
- this.quickAudioToggle = findViewById(R.id.quick_audio_toggle);
- this.buttonToggle = findViewById(R.id.button_toggle);
- this.recordingContainer = findViewById(R.id.recording_container);
- this.recordLockCancel = findViewById(R.id.record_cancel);
- View slideToCancelView = findViewById(R.id.slide_to_cancel);
- this.slideToCancel = new SlideToCancel(slideToCancelView);
- this.microphoneRecorderView = findViewById(R.id.recorder_view);
- this.microphoneRecorderView.setListener(this);
- this.recordTime = new RecordTime(findViewById(R.id.record_time),
- findViewById(R.id.microphone),
- TimeUnit.HOURS.toSeconds(1),
- () -> microphoneRecorderView.cancelAction());
-
- this.recordLockCancel.setOnClickListener(v -> microphoneRecorderView.cancelAction());
-
- if (TextSecurePreferences.isSystemEmojiPreferred(getContext())) {
- mediaKeyboard.setVisibility(View.GONE);
- emojiVisible = false;
- } else {
- mediaKeyboard.setVisibility(View.VISIBLE);
- emojiVisible = true;
+ public InputPanel(Context context) {
+ super(context);
}
- quoteDismiss.setOnClickListener(v -> clearQuote());
-
- linkPreview.setCloseClickedListener(() -> {
- if (listener != null) {
- listener.onLinkPreviewCanceled();
- }
- });
- }
-
- public void setListener(final @NonNull Listener listener) {
- this.listener = listener;
-
- mediaKeyboard.setOnClickListener(v -> listener.onEmojiToggle());
- }
-
- public void setMediaListener(@NonNull MediaListener listener) {
- composeText.setMediaListener(listener);
- }
-
- public void setQuote(@NonNull GlideRequests glideRequests, long id, @NonNull Recipient author, @NonNull String body, @NonNull SlideDeck attachments, @NonNull Recipient conversationRecipient, long threadID) {
- this.quoteView.setQuote(glideRequests, id, author, MentionUtilities.highlightMentions(body, threadID, getContext()), false, attachments, conversationRecipient);
- this.quoteView.setVisibility(View.VISIBLE);
-
- if (this.linkPreview.getVisibility() == View.VISIBLE) {
- int cornerRadius = readDimen(R.dimen.message_corner_collapse_radius);
- this.linkPreview.setCorners(cornerRadius, cornerRadius);
- }
- }
-
- public void clearQuote() {
- this.quoteView.dismiss();
-
- if (this.linkPreview.getVisibility() == View.VISIBLE) {
- int cornerRadius = readDimen(R.dimen.message_corner_radius);
- this.linkPreview.setCorners(cornerRadius, cornerRadius);
- }
- }
-
- public Optional getQuote() {
- if (quoteView.getQuoteId() > 0 && quoteView.getVisibility() == View.VISIBLE) {
- return Optional.of(new QuoteModel(quoteView.getQuoteId(), quoteView.getAuthor().getAddress(), quoteView.getBody(), false, quoteView.getAttachments()));
- } else {
- return Optional.absent();
- }
- }
-
- public void setLinkPreviewLoading() {
- this.linkPreview.setVisibility(View.VISIBLE);
- this.linkPreview.setLoading();
- }
-
- public void setLinkPreview(@NonNull GlideRequests glideRequests, @NonNull Optional preview) {
- if (preview.isPresent()) {
- this.linkPreview.setVisibility(View.VISIBLE);
- this.linkPreview.setLinkPreview(glideRequests, preview.get(), true);
- } else {
- this.linkPreview.setVisibility(View.GONE);
+ public InputPanel(Context context, AttributeSet attrs) {
+ super(context, attrs);
}
- int largeCornerRadius = (int)(16 * getResources().getDisplayMetrics().density);
- int cornerRadius = quoteView.getVisibility() == VISIBLE ? readDimen(R.dimen.message_corner_collapse_radius) : largeCornerRadius;
-
- this.linkPreview.setCorners(cornerRadius, cornerRadius);
- }
-
- public void setMediaKeyboard(@NonNull MediaKeyboard mediaKeyboard) {
- this.mediaKeyboard.attach(mediaKeyboard);
- }
-
- @Override
- public void onRecordPermissionRequired() {
- if (listener != null) listener.onRecorderPermissionRequired();
- }
-
- @Override
- public void onRecordPressed() {
- if (listener != null) listener.onRecorderStarted();
- recordTime.display();
- slideToCancel.display();
-
- if (emojiVisible) ViewUtil.fadeOut(mediaKeyboard, FADE_TIME, View.INVISIBLE);
- ViewUtil.fadeOut(composeText, FADE_TIME, View.INVISIBLE);
- ViewUtil.fadeOut(quickCameraToggle, FADE_TIME, View.INVISIBLE);
- ViewUtil.fadeOut(quickAudioToggle, FADE_TIME, View.INVISIBLE);
- buttonToggle.animate().alpha(0).setDuration(FADE_TIME).start();
- }
-
- @Override
- public void onRecordReleased() {
- long elapsedTime = onRecordHideEvent();
-
- if (listener != null) {
- Log.d(TAG, "Elapsed time: " + elapsedTime);
- if (elapsedTime > 1000) {
- listener.onRecorderFinished();
- } else {
- Toast.makeText(getContext(), R.string.InputPanel_tap_and_hold_to_record_a_voice_message_release_to_send, Toast.LENGTH_LONG).show();
- listener.onRecorderCanceled();
- }
- }
- }
-
- @Override
- public void onRecordMoved(float offsetX, float absoluteX) {
- slideToCancel.moveTo(offsetX);
-
- int direction = ViewCompat.getLayoutDirection(this);
- float position = absoluteX / recordingContainer.getWidth();
-
- if (direction == ViewCompat.LAYOUT_DIRECTION_LTR && position <= 0.5 ||
- direction == ViewCompat.LAYOUT_DIRECTION_RTL && position >= 0.6)
- {
- this.microphoneRecorderView.cancelAction();
- }
- }
-
- @Override
- public void onRecordCanceled() {
- onRecordHideEvent();
- if (listener != null) listener.onRecorderCanceled();
- }
-
- @Override
- public void onRecordLocked() {
- slideToCancel.hide();
- recordLockCancel.setVisibility(View.VISIBLE);
- buttonToggle.animate().alpha(1).setDuration(FADE_TIME).start();
- if (listener != null) listener.onRecorderLocked();
- }
-
- public void onPause() {
- this.microphoneRecorderView.cancelAction();
- }
-
- public void setEnabled(boolean enabled) {
- composeText.setEnabled(enabled);
- mediaKeyboard.setEnabled(enabled);
- quickAudioToggle.setEnabled(enabled);
- quickCameraToggle.setEnabled(enabled);
- }
-
- public void setHint(@NonNull String hint) {
- composeText.setHint(hint, null);
- }
-
- private long onRecordHideEvent() {
- recordLockCancel.setVisibility(View.GONE);
-
- ListenableFuture future = slideToCancel.hide();
- long elapsedTime = recordTime.hide();
-
- future.addListener(new AssertedSuccessListener() {
- @Override
- public void onSuccess(Void result) {
- if (emojiVisible) ViewUtil.fadeIn(mediaKeyboard, FADE_TIME);
- ViewUtil.fadeIn(composeText, FADE_TIME);
- ViewUtil.fadeIn(quickCameraToggle, FADE_TIME);
- ViewUtil.fadeIn(quickAudioToggle, FADE_TIME);
- buttonToggle.animate().alpha(1).setDuration(FADE_TIME).start();
- }
- });
-
- return elapsedTime;
- }
-
- @Override
- public void onKeyboardShown() {
- mediaKeyboard.setToMedia();
- }
-
- @Override
- public void onKeyEvent(KeyEvent keyEvent) {
- composeText.dispatchKeyEvent(keyEvent);
- }
-
- @Override
- public void onEmojiSelected(String emoji) {
- composeText.insertEmoji(emoji);
- }
-
- private int readDimen(@DimenRes int dimenRes) {
- return getResources().getDimensionPixelSize(dimenRes);
- }
-
- public boolean isRecordingInLockedMode() {
- return microphoneRecorderView.isRecordingLocked();
- }
-
- public void releaseRecordingLock() {
- microphoneRecorderView.unlockAction();
- }
-
- public interface Listener {
- void onRecorderStarted();
- void onRecorderLocked();
- void onRecorderFinished();
- void onRecorderCanceled();
- void onRecorderPermissionRequired();
- void onEmojiToggle();
- void onLinkPreviewCanceled();
- }
-
- private static class SlideToCancel {
-
- private final View slideToCancelView;
-
- SlideToCancel(View slideToCancelView) {
- this.slideToCancelView = slideToCancelView;
+ @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+ public InputPanel(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
}
- public void display() {
- ViewUtil.fadeIn(this.slideToCancelView, FADE_TIME);
+ public interface MediaListener {
+ void onMediaSelected(@NonNull Uri uri, String contentType);
}
-
- public ListenableFuture hide() {
- final SettableFuture future = new SettableFuture<>();
-
- AnimationSet animation = new AnimationSet(true);
- animation.addAnimation(new TranslateAnimation(Animation.ABSOLUTE, slideToCancelView.getTranslationX(),
- Animation.ABSOLUTE, 0,
- Animation.RELATIVE_TO_SELF, 0,
- Animation.RELATIVE_TO_SELF, 0));
- animation.addAnimation(new AlphaAnimation(1, 0));
-
- animation.setDuration(MicrophoneRecorderView.ANIMATION_DURATION);
- animation.setFillBefore(true);
- animation.setFillAfter(false);
-
- slideToCancelView.postDelayed(() -> future.set(null), MicrophoneRecorderView.ANIMATION_DURATION);
- slideToCancelView.setVisibility(View.GONE);
- slideToCancelView.startAnimation(animation);
-
- return future;
- }
-
- void moveTo(float offset) {
- Animation animation = new TranslateAnimation(Animation.ABSOLUTE, offset,
- Animation.ABSOLUTE, offset,
- Animation.RELATIVE_TO_SELF, 0,
- Animation.RELATIVE_TO_SELF, 0);
-
- animation.setDuration(0);
- animation.setFillAfter(true);
- animation.setFillBefore(true);
-
- slideToCancelView.startAnimation(animation);
- }
- }
-
- private static class RecordTime implements Runnable {
-
- private final @NonNull TextView recordTimeView;
- private final @NonNull View microphone;
- private final @NonNull Runnable onLimitHit;
- private final long limitSeconds;
- private long startTime;
-
- private RecordTime(@NonNull TextView recordTimeView, @NonNull View microphone, long limitSeconds, @NonNull Runnable onLimitHit) {
- this.recordTimeView = recordTimeView;
- this.microphone = microphone;
- this.limitSeconds = limitSeconds;
- this.onLimitHit = onLimitHit;
- }
-
- @MainThread
- public void display() {
- this.startTime = System.currentTimeMillis();
- this.recordTimeView.setText(DateUtils.formatElapsedTime(0));
- ViewUtil.fadeIn(this.recordTimeView, FADE_TIME);
- Util.runOnMainDelayed(this, TimeUnit.SECONDS.toMillis(1));
- microphone.setVisibility(View.VISIBLE);
- microphone.startAnimation(pulseAnimation());
- }
-
- @MainThread
- public long hide() {
- long elapsedTime = System.currentTimeMillis() - startTime;
- this.startTime = 0;
- ViewUtil.fadeOut(this.recordTimeView, FADE_TIME, View.INVISIBLE);
- microphone.clearAnimation();
- ViewUtil.fadeOut(this.microphone, FADE_TIME, View.INVISIBLE);
- return elapsedTime;
- }
-
- @Override
- @MainThread
- public void run() {
- long localStartTime = startTime;
- if (localStartTime > 0) {
- long elapsedTime = System.currentTimeMillis() - localStartTime;
- long elapsedSeconds = TimeUnit.MILLISECONDS.toSeconds(elapsedTime);
- if (elapsedSeconds >= limitSeconds) {
- onLimitHit.run();
- } else {
- recordTimeView.setText(DateUtils.formatElapsedTime(elapsedSeconds));
- Util.runOnMainDelayed(this, TimeUnit.SECONDS.toMillis(1));
- }
- }
- }
-
- private static Animation pulseAnimation() {
- AlphaAnimation animation = new AlphaAnimation(0, 1);
-
- animation.setInterpolator(pulseInterpolator());
- animation.setRepeatCount(Animation.INFINITE);
- animation.setDuration(1000);
-
- return animation;
- }
-
- private static Interpolator pulseInterpolator() {
- return input -> {
- input *= 5;
- if (input > 1) {
- input = 4 - input;
- }
- return Math.max(0, Math.min(1, input));
- };
- }
- }
-
- public interface MediaListener {
- void onMediaSelected(@NonNull Uri uri, String contentType);
- }
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/MicrophoneRecorderView.java b/app/src/main/java/org/thoughtcrime/securesms/components/MicrophoneRecorderView.java
deleted file mode 100644
index 26b3d4f62f..0000000000
--- a/app/src/main/java/org/thoughtcrime/securesms/components/MicrophoneRecorderView.java
+++ /dev/null
@@ -1,272 +0,0 @@
-package org.thoughtcrime.securesms.components;
-
-import android.Manifest;
-import android.content.Context;
-import android.graphics.PorterDuff;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.core.view.ViewCompat;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.animation.Animation;
-import android.view.animation.AnimationSet;
-import android.view.animation.AnticipateOvershootInterpolator;
-import android.view.animation.DecelerateInterpolator;
-import android.view.animation.LinearInterpolator;
-import android.view.animation.OvershootInterpolator;
-import android.view.animation.ScaleAnimation;
-import android.view.animation.TranslateAnimation;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-
-import org.thoughtcrime.securesms.permissions.Permissions;
-
-import org.session.libsession.utilities.ViewUtil;
-
-import network.loki.messenger.R;
-
-public final class MicrophoneRecorderView extends FrameLayout implements View.OnTouchListener {
-
- enum State {
- NOT_RUNNING,
- RUNNING_HELD,
- RUNNING_LOCKED
- }
-
- public static final int ANIMATION_DURATION = 200;
-
- private FloatingRecordButton floatingRecordButton;
- private LockDropTarget lockDropTarget;
- private @Nullable Listener listener;
- private @NonNull State state = State.NOT_RUNNING;
-
- public MicrophoneRecorderView(Context context) {
- super(context);
- }
-
- public MicrophoneRecorderView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- @Override
- public void onFinishInflate() {
- super.onFinishInflate();
-
- floatingRecordButton = new FloatingRecordButton(getContext(), findViewById(R.id.quick_audio_fab));
- lockDropTarget = new LockDropTarget (getContext(), findViewById(R.id.lock_drop_target));
-
- View recordButton = ViewUtil.findById(this, R.id.quick_audio_toggle);
- recordButton.setOnTouchListener(this);
- }
-
- public void cancelAction() {
- if (state != State.NOT_RUNNING) {
- state = State.NOT_RUNNING;
- hideUi();
-
- if (listener != null) listener.onRecordCanceled();
- }
- }
-
- public boolean isRecordingLocked() {
- return state == State.RUNNING_LOCKED;
- }
-
- private void lockAction() {
- if (state == State.RUNNING_HELD) {
- state = State.RUNNING_LOCKED;
- hideUi();
-
- if (listener != null) listener.onRecordLocked();
- }
- }
-
- public void unlockAction() {
- if (state == State.RUNNING_LOCKED) {
- state = State.NOT_RUNNING;
- hideUi();
-
- if (listener != null) listener.onRecordReleased();
- }
- }
-
- private void hideUi() {
- floatingRecordButton.hide();
- lockDropTarget.hide();
- }
-
- @Override
- public boolean onTouch(View v, final MotionEvent event) {
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- if (!Permissions.hasAll(getContext(), Manifest.permission.RECORD_AUDIO)) {
- if (listener != null) listener.onRecordPermissionRequired();
- } else {
- state = State.RUNNING_HELD;
- floatingRecordButton.display(event.getX(), event.getY());
- lockDropTarget.display();
- if (listener != null) listener.onRecordPressed();
- }
- break;
- case MotionEvent.ACTION_CANCEL:
- case MotionEvent.ACTION_UP:
- if (this.state == State.RUNNING_HELD) {
- state = State.NOT_RUNNING;
- hideUi();
- if (listener != null) listener.onRecordReleased();
- }
- break;
- case MotionEvent.ACTION_MOVE:
- if (this.state == State.RUNNING_HELD) {
- this.floatingRecordButton.moveTo(event.getX(), event.getY());
- if (listener != null) listener.onRecordMoved(floatingRecordButton.lastOffsetX, event.getRawX());
-
- int dimensionPixelSize = getResources().getDimensionPixelSize(R.dimen.recording_voice_lock_target);
- if (floatingRecordButton.lastOffsetY <= dimensionPixelSize) {
- lockAction();
- }
- }
- break;
- }
-
- return false;
- }
-
- public void setListener(@Nullable Listener listener) {
- this.listener = listener;
- }
-
- public interface Listener {
- void onRecordPressed();
- void onRecordReleased();
- void onRecordCanceled();
- void onRecordLocked();
- void onRecordMoved(float offsetX, float absoluteX);
- void onRecordPermissionRequired();
- }
-
- private static class FloatingRecordButton {
-
- private final ImageView recordButtonFab;
-
- private float startPositionX;
- private float startPositionY;
- private float lastOffsetX;
- private float lastOffsetY;
-
- FloatingRecordButton(Context context, ImageView recordButtonFab) {
- this.recordButtonFab = recordButtonFab;
- this.recordButtonFab.getBackground().setColorFilter(context.getResources()
- .getColor(R.color.destructive),
- PorterDuff.Mode.SRC_IN);
- }
-
- void display(float x, float y) {
- this.startPositionX = x;
- this.startPositionY = y;
-
- recordButtonFab.setVisibility(View.VISIBLE);
-
- AnimationSet animation = new AnimationSet(true);
- animation.addAnimation(new TranslateAnimation(Animation.ABSOLUTE, 0,
- Animation.ABSOLUTE, 0,
- Animation.ABSOLUTE, 0,
- Animation.ABSOLUTE, 0));
-
- animation.addAnimation(new ScaleAnimation(.5f, 1f, .5f, 1f,
- Animation.RELATIVE_TO_SELF, .5f,
- Animation.RELATIVE_TO_SELF, .5f));
-
- animation.setDuration(ANIMATION_DURATION);
- animation.setInterpolator(new OvershootInterpolator());
-
- recordButtonFab.startAnimation(animation);
- }
-
- void moveTo(float x, float y) {
- lastOffsetX = getXOffset(x);
- lastOffsetY = getYOffset(y);
-
- if (Math.abs(lastOffsetX) > Math.abs(lastOffsetY)) {
- lastOffsetY = 0;
- } else {
- lastOffsetX = 0;
- }
-
- recordButtonFab.setTranslationX(lastOffsetX);
- recordButtonFab.setTranslationY(lastOffsetY);
- }
-
- void hide() {
- recordButtonFab.setTranslationX(0);
- recordButtonFab.setTranslationY(0);
- if (recordButtonFab.getVisibility() != VISIBLE) return;
-
- AnimationSet animation = new AnimationSet(false);
- Animation scaleAnimation = new ScaleAnimation(1, 0.5f, 1, 0.5f,
- Animation.RELATIVE_TO_SELF, 0.5f,
- Animation.RELATIVE_TO_SELF, 0.5f);
-
- Animation translateAnimation = new TranslateAnimation(Animation.ABSOLUTE, lastOffsetX,
- Animation.ABSOLUTE, 0,
- Animation.ABSOLUTE, lastOffsetY,
- Animation.ABSOLUTE, 0);
-
- scaleAnimation.setInterpolator(new AnticipateOvershootInterpolator(1.5f));
- translateAnimation.setInterpolator(new DecelerateInterpolator());
- animation.addAnimation(scaleAnimation);
- animation.addAnimation(translateAnimation);
- animation.setDuration(ANIMATION_DURATION);
- animation.setInterpolator(new AnticipateOvershootInterpolator(1.5f));
-
- recordButtonFab.setVisibility(View.GONE);
- recordButtonFab.clearAnimation();
- recordButtonFab.startAnimation(animation);
- }
-
- private float getXOffset(float x) {
- return ViewCompat.getLayoutDirection(recordButtonFab) == ViewCompat.LAYOUT_DIRECTION_LTR ?
- -Math.max(0, this.startPositionX - x) : Math.max(0, x - this.startPositionX);
- }
-
- private float getYOffset(float y) {
- return Math.min(0, y - this.startPositionY);
- }
- }
-
- private static class LockDropTarget {
-
- private final View lockDropTarget;
- private final int dropTargetPosition;
-
- LockDropTarget(Context context, View lockDropTarget) {
- this.lockDropTarget = lockDropTarget;
- this.dropTargetPosition = context.getResources().getDimensionPixelSize(R.dimen.recording_voice_lock_target);
- }
-
- void display() {
- lockDropTarget.setScaleX(1);
- lockDropTarget.setScaleY(1);
- lockDropTarget.setAlpha(0);
- lockDropTarget.setTranslationY(0);
- lockDropTarget.setVisibility(VISIBLE);
- lockDropTarget.animate()
- .setStartDelay(ANIMATION_DURATION * 2)
- .setDuration(ANIMATION_DURATION)
- .setInterpolator(new DecelerateInterpolator())
- .translationY(dropTargetPosition)
- .alpha(1)
- .start();
- }
-
- void hide() {
- lockDropTarget.animate()
- .setStartDelay(0)
- .setDuration(ANIMATION_DURATION)
- .setInterpolator(new LinearInterpolator())
- .scaleX(0).scaleY(0)
- .start();
- }
- }
-}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java
deleted file mode 100644
index d6db6ec16d..0000000000
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java
+++ /dev/null
@@ -1,2440 +0,0 @@
-/*
- * Copyright (C) 2011 Whisper Systems
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.thoughtcrime.securesms.conversation;
-
-import android.Manifest;
-import android.annotation.SuppressLint;
-import android.annotation.TargetApi;
-import android.content.ActivityNotFoundException;
-import android.content.BroadcastReceiver;
-import android.content.ClipData;
-import android.content.ClipboardManager;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.content.res.Configuration;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffColorFilter;
-import android.hardware.Camera;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Vibrator;
-import android.provider.Browser;
-import android.provider.Telephony;
-import android.text.Editable;
-import android.text.TextUtils;
-import android.text.TextWatcher;
-import android.util.Pair;
-import android.util.TypedValue;
-import android.view.KeyEvent;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.View.OnFocusChangeListener;
-import android.view.View.OnKeyListener;
-import android.view.WindowManager;
-import android.view.inputmethod.EditorInfo;
-import android.widget.Button;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-import android.widget.ProgressBar;
-import android.widget.TextView;
-import android.widget.Toast;
-import androidx.annotation.ColorInt;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.appcompat.app.ActionBar;
-import androidx.appcompat.app.AlertDialog;
-import androidx.appcompat.widget.SearchView;
-import androidx.appcompat.widget.Toolbar;
-import androidx.core.content.pm.ShortcutInfoCompat;
-import androidx.core.content.pm.ShortcutManagerCompat;
-import androidx.core.graphics.drawable.IconCompat;
-import androidx.core.view.MenuItemCompat;
-import androidx.lifecycle.ViewModelProviders;
-import androidx.loader.app.LoaderManager;
-import androidx.localbroadcastmanager.content.LocalBroadcastManager;
-import com.annimon.stream.Stream;
-import org.greenrobot.eventbus.EventBus;
-import org.greenrobot.eventbus.Subscribe;
-import org.greenrobot.eventbus.ThreadMode;
-import org.session.libsession.messaging.mentions.MentionsManager;
-import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate;
-import org.session.libsession.messaging.messages.signal.OutgoingMediaMessage;
-import org.session.libsession.messaging.messages.signal.OutgoingSecureMediaMessage;
-import org.session.libsession.messaging.messages.signal.OutgoingTextMessage;
-import org.session.libsession.messaging.messages.visible.OpenGroupInvitation;
-import org.session.libsession.messaging.messages.visible.VisibleMessage;
-import org.session.libsession.messaging.open_groups.OpenGroupV2;
-import org.session.libsession.messaging.sending_receiving.MessageSender;
-import org.session.libsession.messaging.sending_receiving.attachments.Attachment;
-import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview;
-import org.session.libsession.messaging.sending_receiving.quotes.QuoteModel;
-import org.session.libsession.utilities.Contact;
-import org.session.libsession.utilities.Address;
-import org.session.libsession.utilities.DistributionTypes;
-import org.session.libsession.utilities.GroupRecord;
-import org.session.libsession.utilities.recipients.Recipient;
-import org.session.libsession.utilities.recipients.RecipientFormattingException;
-import org.session.libsession.utilities.recipients.RecipientModifiedListener;
-import org.session.libsession.utilities.ExpirationUtil;
-import org.session.libsession.utilities.GroupUtil;
-import org.session.libsession.utilities.MediaTypes;
-import org.session.libsession.utilities.ServiceUtil;
-import org.session.libsession.utilities.TextSecurePreferences;
-import org.session.libsession.utilities.Util;
-import org.session.libsession.utilities.ViewUtil;
-import org.session.libsession.utilities.concurrent.AssertedSuccessListener;
-import org.session.libsession.utilities.Stub;
-import org.session.libsignal.exceptions.InvalidMessageException;
-import org.session.libsignal.utilities.guava.Optional;
-import org.session.libsession.messaging.mentions.Mention;
-import org.session.libsignal.utilities.HexEncodingKt;
-import org.session.libsignal.utilities.PublicKeyValidation;
-import org.session.libsignal.utilities.ListenableFuture;
-import org.session.libsignal.utilities.SettableFuture;
-import org.session.libsignal.utilities.Log;
-import org.thoughtcrime.securesms.ApplicationContext;
-import org.thoughtcrime.securesms.ExpirationDialog;
-import org.thoughtcrime.securesms.MediaOverviewActivity;
-import org.thoughtcrime.securesms.MuteDialog;
-import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity;
-import org.thoughtcrime.securesms.ShortcutLauncherActivity;
-import org.thoughtcrime.securesms.audio.AudioRecorder;
-import org.thoughtcrime.securesms.audio.AudioSlidePlayer;
-import org.thoughtcrime.securesms.components.AnimatingToggle;
-import org.thoughtcrime.securesms.components.AttachmentTypeSelector;
-import org.thoughtcrime.securesms.components.ComposeText;
-import org.thoughtcrime.securesms.components.ConversationSearchBottomBar;
-import org.thoughtcrime.securesms.components.HidingLinearLayout;
-import org.thoughtcrime.securesms.components.InputAwareLayout;
-import org.thoughtcrime.securesms.components.InputPanel;
-import org.thoughtcrime.securesms.components.KeyboardAwareLinearLayout.OnKeyboardShownListener;
-import org.thoughtcrime.securesms.components.emoji.EmojiKeyboardProvider;
-import org.thoughtcrime.securesms.components.emoji.EmojiStrings;
-import org.thoughtcrime.securesms.components.emoji.MediaKeyboard;
-import org.thoughtcrime.securesms.contacts.ContactAccessor;
-import org.thoughtcrime.securesms.contacts.ContactAccessor.ContactData;
-import org.thoughtcrime.securesms.contactshare.ContactUtil;
-import org.thoughtcrime.securesms.contactshare.SimpleTextWatcher;
-import org.thoughtcrime.securesms.database.DatabaseFactory;
-import org.thoughtcrime.securesms.database.DraftDatabase;
-import org.thoughtcrime.securesms.database.DraftDatabase.Draft;
-import org.thoughtcrime.securesms.database.DraftDatabase.Drafts;
-import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo;
-import org.thoughtcrime.securesms.database.MmsSmsColumns.Types;
-import org.thoughtcrime.securesms.database.ThreadDatabase;
-import org.thoughtcrime.securesms.database.model.MessageRecord;
-import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
-import org.thoughtcrime.securesms.giph.ui.GiphyActivity;
-import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository;
-import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil;
-import org.thoughtcrime.securesms.linkpreview.LinkPreviewViewModel;
-import org.thoughtcrime.securesms.loki.activities.EditClosedGroupActivity;
-import org.thoughtcrime.securesms.loki.activities.HomeActivity;
-import org.thoughtcrime.securesms.loki.activities.SelectContactsActivity;
-import org.thoughtcrime.securesms.loki.api.PublicChatInfoUpdateWorker;
-import org.thoughtcrime.securesms.loki.protocol.SessionMetaProtocol;
-import org.thoughtcrime.securesms.loki.utilities.GeneralUtilitiesKt;
-import org.thoughtcrime.securesms.loki.utilities.MentionManagerUtilities;
-import org.thoughtcrime.securesms.loki.utilities.OpenGroupUtilities;
-import org.thoughtcrime.securesms.loki.views.MentionCandidateSelectionView;
-import org.thoughtcrime.securesms.loki.views.ProfilePictureView;
-import org.thoughtcrime.securesms.mediasend.Media;
-import org.thoughtcrime.securesms.mediasend.MediaSendActivity;
-import org.thoughtcrime.securesms.conversation.v2.utilities.AttachmentManager;
-import org.thoughtcrime.securesms.conversation.v2.utilities.AttachmentManager.MediaType;
-import org.thoughtcrime.securesms.mms.AudioSlide;
-import org.thoughtcrime.securesms.mms.GifSlide;
-import org.thoughtcrime.securesms.mms.GlideApp;
-import org.thoughtcrime.securesms.mms.GlideRequests;
-import org.thoughtcrime.securesms.mms.ImageSlide;
-import org.thoughtcrime.securesms.mms.MediaConstraints;
-import org.thoughtcrime.securesms.mms.MmsException;
-import org.thoughtcrime.securesms.mms.QuoteId;
-import org.thoughtcrime.securesms.mms.Slide;
-import org.thoughtcrime.securesms.mms.SlideDeck;
-import org.thoughtcrime.securesms.mms.TextSlide;
-import org.thoughtcrime.securesms.mms.VideoSlide;
-import org.thoughtcrime.securesms.notifications.MarkReadReceiver;
-import org.thoughtcrime.securesms.permissions.Permissions;
-import org.thoughtcrime.securesms.providers.BlobProvider;
-import org.thoughtcrime.securesms.search.model.MessageResult;
-import org.thoughtcrime.securesms.service.ExpiringMessageManager;
-import org.thoughtcrime.securesms.util.BitmapUtil;
-import org.thoughtcrime.securesms.util.DateUtils;
-import org.thoughtcrime.securesms.util.MediaUtil;
-import org.thoughtcrime.securesms.util.PushCharacterCalculator;
-import java.io.IOException;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-import java.util.Locale;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-import kotlin.Unit;
-import network.loki.messenger.R;
-
-/**
- * Activity for displaying a message thread, as well as
- * composing/sending a new message into that thread.
- *
- * @author Moxie Marlinspike
- *
- */
-@SuppressLint("StaticFieldLeak")
-public class ConversationActivity extends PassphraseRequiredActionBarActivity
- implements ConversationFragment.ConversationFragmentListener,
- AttachmentManager.AttachmentListener,
- RecipientModifiedListener,
- OnKeyboardShownListener,
- InputPanel.Listener,
- InputPanel.MediaListener,
- ComposeText.CursorPositionChangedListener,
- ConversationSearchBottomBar.EventListener
-{
- private static final String TAG = ConversationActivity.class.getSimpleName();
-
- public static final String ADDRESS_EXTRA = "address";
- public static final String THREAD_ID_EXTRA = "thread_id";
- public static final String IS_ARCHIVED_EXTRA = "is_archived";
- public static final String TEXT_EXTRA = "draft_text";
- public static final String MEDIA_EXTRA = "media_list";
- public static final String STICKER_EXTRA = "media_list";
- public static final String DISTRIBUTION_TYPE_EXTRA = "distribution_type";
- public static final String TIMING_EXTRA = "timing";
- public static final String LAST_SEEN_EXTRA = "last_seen";
- public static final String STARTING_POSITION_EXTRA = "starting_position";
-
- // private static final int PICK_GALLERY = 1;
- private static final int PICK_DOCUMENT = 2;
- private static final int PICK_AUDIO = 3;
- private static final int PICK_CONTACT = 4;
- // private static final int GET_CONTACT_DETAILS = 5;
-// private static final int GROUP_EDIT = 6;
- private static final int TAKE_PHOTO = 7;
- private static final int ADD_CONTACT = 8;
- private static final int PICK_LOCATION = 9;
- private static final int PICK_GIF = 10;
- private static final int SMS_DEFAULT = 11;
- private static final int MEDIA_SENDER = 12;
- private static final int INVITE_CONTACTS = 124;
-
- private GlideRequests glideRequests;
- protected ComposeText composeText;
- private AnimatingToggle buttonToggle;
- private ImageButton sendButton;
- private ImageButton attachButton;
- private ProfilePictureView profilePictureView;
- private TextView titleTextView;
- private ConversationFragment fragment;
- private Button unblockButton;
- private Button makeDefaultSmsButton;
- private InputAwareLayout container;
- private TypingStatusTextWatcher typingTextWatcher;
- private MentionTextWatcher mentionTextWatcher;
- private ConversationSearchBottomBar searchNav;
- private MenuItem searchViewItem;
- private ProgressBar messageStatusProgressBar;
- private ImageView muteIndicatorImageView;
- private TextView subtitleTextView;
- private View homeButtonContainer;
-
- private AttachmentTypeSelector attachmentTypeSelector;
- private AttachmentManager attachmentManager;
- private AudioRecorder audioRecorder;
- private Handler audioHandler;
- private Runnable stopRecordingTask;
- private Stub emojiDrawerStub;
- protected HidingLinearLayout quickAttachmentToggle;
- protected HidingLinearLayout inlineAttachmentToggle;
- private InputPanel inputPanel;
-
- private LinkPreviewViewModel linkPreviewViewModel;
- private ConversationSearchViewModel searchViewModel;
-
- private Recipient recipient;
- private long threadId;
- private int distributionType;
- private boolean isDefaultSms = false;
- private boolean isSecurityInitialized = false;
- private int expandedKeyboardHeight = 0;
- private int collapsedKeyboardHeight = Integer.MAX_VALUE;
- private int keyboardHeight = 0;
-
- // Message status bar
- private ArrayList broadcastReceivers = new ArrayList<>();
- private String messageStatus = null;
-
- // Mentions
- private View mentionCandidateSelectionViewContainer;
- private MentionCandidateSelectionView mentionCandidateSelectionView;
- private int currentMentionStartIndex = -1;
- private ArrayList mentions = new ArrayList<>();
- private String oldText = "";
-
- private final PushCharacterCalculator characterCalculator = new PushCharacterCalculator();
-
- @Override
- protected void onCreate(Bundle state, boolean ready) {
- Log.i(TAG, "onCreate()");
-
- setContentView(R.layout.conversation_activity);
-
- fragment = initFragment(R.id.fragment_content, new ConversationFragment(), Locale.getDefault());
-
- registerMessageStatusObserver("calculatingPoW");
- registerMessageStatusObserver("contactingNetwork");
- registerMessageStatusObserver("sendingMessage");
- registerMessageStatusObserver("messageSent");
- registerMessageStatusObserver("messageFailed");
- BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
-
- @Override
- public void onReceive(Context context, Intent intent) {
- Toast.makeText(ConversationActivity.this, "Your clock is out of sync with the service node network.", Toast.LENGTH_LONG).show();
- }
- };
- broadcastReceivers.add(broadcastReceiver);
- LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, new IntentFilter("clockOutOfSync"));
-
- initializeActionBar();
- initializeViews();
- initializeResources();
- initializeLinkPreviewObserver();
- initializeSearchObserver();
- initializeSecurity(false, isDefaultSms).addListener(new AssertedSuccessListener() {
- @Override
- public void onSuccess(Boolean result) {
- initializeDraft().addListener(new AssertedSuccessListener() {
- @Override
- public void onSuccess(Boolean loadedDraft) {
- if (loadedDraft != null && loadedDraft) {
- Log.i(TAG, "Finished loading draft");
- Util.runOnMain(() -> {
- if (fragment != null && fragment.isResumed()) {
- fragment.moveToLastSeen();
- } else {
- Log.w(TAG, "Wanted to move to the last seen position, but the fragment was in an invalid state");
- }
- });
- }
-
- if (TextSecurePreferences.isTypingIndicatorsEnabled(ConversationActivity.this)) {
- composeText.addTextChangedListener(typingTextWatcher);
- }
- composeText.setSelection(composeText.length(), composeText.length());
- composeText.addTextChangedListener(mentionTextWatcher);
- mentionCandidateSelectionView.setGlide(glideRequests);
- mentionCandidateSelectionView.setOnMentionCandidateSelected( mentionCandidate -> {
- mentions.add(mentionCandidate);
- String oldText = composeText.getText().toString();
- String newText = oldText.substring(0, currentMentionStartIndex) + "@" + mentionCandidate.getDisplayName() + " ";
- composeText.setText(newText);
- composeText.setSelection(newText.length());
- currentMentionStartIndex = -1;
- mentionCandidateSelectionView.hide();
- ConversationActivity.this.oldText = newText;
- return Unit.INSTANCE;
- });
- }
- });
- }
- });
-
- MentionManagerUtilities.INSTANCE.populateUserPublicKeyCacheIfNeeded(threadId, this);
-
- OpenGroupV2 openGroupV2 = DatabaseFactory.getLokiThreadDatabase(this).getOpenGroupChat(threadId);
- if (openGroupV2 != null) {
- PublicChatInfoUpdateWorker.scheduleInstant(this, openGroupV2.getServer(), openGroupV2.getRoom());
- if (openGroupV2.getRoom().equals("session") || openGroupV2.getRoom().equals("oxen")
- || openGroupV2.getRoom().equals("lokinet") || openGroupV2.getRoom().equals("crypto")) {
- View openGroupGuidelinesView = findViewById(R.id.open_group_guidelines_view);
- openGroupGuidelinesView.setVisibility(View.VISIBLE);
- }
- }
-
- View rootView = findViewById(R.id.rootView);
- rootView.getViewTreeObserver().addOnGlobalLayoutListener(() -> {
- int height = rootView.getRootView().getHeight() - rootView.getHeight();
- int thresholdInDP = 120;
- float scale = getResources().getDisplayMetrics().density;
- int thresholdInPX = (int)(thresholdInDP * scale);
- if (expandedKeyboardHeight == 0 || height > thresholdInPX) {
- expandedKeyboardHeight = height;
- }
- collapsedKeyboardHeight = Math.min(collapsedKeyboardHeight, height);
- keyboardHeight = expandedKeyboardHeight - collapsedKeyboardHeight;
-
- // Use 300dp if the keyboard wasn't opened yet.
- if (keyboardHeight == 0) {
- keyboardHeight = (int)(300f * getResources().getDisplayMetrics().density);
- }
- });
- }
-
- private void registerMessageStatusObserver(String status) {
- BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
-
- @Override
- public void onReceive(Context context, Intent intent) {
- long timestamp = intent.getLongExtra("long", 0);
- handleMessageStatusChanged(status, timestamp);
- }
- };
- broadcastReceivers.add(broadcastReceiver);
- LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, new IntentFilter(status));
- }
-
- @Override
- protected void onNewIntent(Intent intent) {
- super.onNewIntent(intent);
- Log.i(TAG, "onNewIntent()");
-
- if (isFinishing()) {
- Log.w(TAG, "Activity is finishing...");
- return;
- }
-
- if (!org.thoughtcrime.securesms.util.Util.isEmpty(composeText)) {
- saveDraft();
- attachmentManager.clear();
- silentlySetComposeText("");
- }
-
- setIntent(intent);
- initializeResources();
- initializeSecurity(false, isDefaultSms).addListener(new AssertedSuccessListener() {
- @Override
- public void onSuccess(Boolean result) {
- initializeDraft();
- }
- });
-
- if (fragment != null) {
- fragment.onNewIntent();
- }
-
- searchNav.setVisibility(View.GONE);
- }
-
- @Override
- protected void onResume() {
- super.onResume();
-
- EventBus.getDefault().register(this);
- initializeEnabledCheck();
- composeText.setTransport();
-
- updateTitleTextView(recipient);
- updateProfilePicture();
- updateSubtitleTextView();
- updateInputUI(recipient);
-
- ApplicationContext.getInstance(this).messageNotifier.setVisibleThread(threadId);
- markThreadAsRead();
-
- inputPanel.setHint(getResources().getString(R.string.ConversationActivity_message));
-
- Log.i(TAG, "onResume() Finished: " + (System.currentTimeMillis() - getIntent().getLongExtra(TIMING_EXTRA, 0)));
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- ApplicationContext.getInstance(this).messageNotifier.setVisibleThread(-1L);
- if (isFinishing()) overridePendingTransition(R.anim.fade_scale_in, R.anim.slide_to_right);
- inputPanel.onPause();
-
- fragment.setLastSeen(System.currentTimeMillis());
- markLastSeen();
- AudioSlidePlayer.stopAll();
- EventBus.getDefault().unregister(this);
- }
-
- @Override
- protected void onStop() {
- super.onStop();
- EventBus.getDefault().unregister(this);
- }
-
- @Override
- public void onConfigurationChanged(Configuration newConfig) {
- Log.i(TAG, "onConfigurationChanged(" + newConfig.orientation + ")");
- super.onConfigurationChanged(newConfig);
- composeText.setTransport();
-
- if (emojiDrawerStub.resolved() && container.getCurrentInput() == emojiDrawerStub.get()) {
- container.hideAttachedInput(true);
- }
- }
-
- @Override
- protected void onDestroy() {
- saveDraft();
- if (recipient != null) recipient.removeListener(this);
- for (BroadcastReceiver broadcastReceiver : broadcastReceivers) {
- LocalBroadcastManager.getInstance(this).unregisterReceiver(broadcastReceiver);
- }
- super.onDestroy();
- }
-
- @Override
- public void onActivityResult(final int reqCode, int resultCode, Intent data) {
- Log.i(TAG, "onActivityResult called: " + reqCode + ", " + resultCode + " , " + data);
- super.onActivityResult(reqCode, resultCode, data);
-
- if ((data == null && reqCode != TAKE_PHOTO && reqCode != SMS_DEFAULT) ||
- (resultCode != RESULT_OK && reqCode != SMS_DEFAULT))
- {
- updateLinkPreviewState();
- return;
- }
-
- switch (reqCode) {
- case PICK_DOCUMENT:
- setMedia(data.getData(), MediaType.DOCUMENT);
- break;
- case PICK_AUDIO:
- setMedia(data.getData(), MediaType.AUDIO);
- break;
- case TAKE_PHOTO:
- if (attachmentManager.getCaptureUri() != null) {
- setMedia(attachmentManager.getCaptureUri(), MediaType.IMAGE);
- }
- break;
- case ADD_CONTACT:
- recipient = Recipient.from(this, recipient.getAddress(), true);
- recipient.addListener(this);
- fragment.reloadList();
- break;
- /*
- case PICK_LOCATION:
- SignalPlace place = new SignalPlace(PlacePicker.getPlace(data, this));
- attachmentManager.setLocation(place, getCurrentMediaConstraints());
- break;
- */
- case PICK_GIF:
- setMedia(data.getData(),
- MediaType.GIF,
- data.getIntExtra(GiphyActivity.EXTRA_WIDTH, 0),
- data.getIntExtra(GiphyActivity.EXTRA_HEIGHT, 0));
- break;
- case SMS_DEFAULT:
- initializeSecurity(true, isDefaultSms);
- break;
- case MEDIA_SENDER:
- long expiresIn = recipient.getExpireMessages() * 1000L;
- int subscriptionId = -1;
- boolean initiating = threadId == -1;
- String message = data.getStringExtra(MediaSendActivity.EXTRA_MESSAGE);
- SlideDeck slideDeck = new SlideDeck();
-
- List mediaList = data.getParcelableArrayListExtra(MediaSendActivity.EXTRA_MEDIA);
-
- for (Media mediaItem : mediaList) {
- if (MediaUtil.isVideoType(mediaItem.getMimeType())) {
- slideDeck.addSlide(new VideoSlide(this, mediaItem.getUri(), 0, mediaItem.getCaption().orNull()));
- } else if (MediaUtil.isGif(mediaItem.getMimeType())) {
- slideDeck.addSlide(new GifSlide(this, mediaItem.getUri(), 0, mediaItem.getWidth(), mediaItem.getHeight(), mediaItem.getCaption().orNull()));
- } else if (MediaUtil.isImageType(mediaItem.getMimeType())) {
- slideDeck.addSlide(new ImageSlide(this, mediaItem.getUri(), 0, mediaItem.getWidth(), mediaItem.getHeight(), mediaItem.getCaption().orNull()));
- } else {
- Log.w(TAG, "Asked to send an unexpected mimeType: '" + mediaItem.getMimeType() + "'. Skipping.");
- }
- }
-
- final Context context = ConversationActivity.this.getApplicationContext();
-
- sendMediaMessage(message,
- slideDeck,
- inputPanel.getQuote().orNull(),
- Optional.absent(),
- initiating).addListener(new AssertedSuccessListener() {
- @Override
- public void onSuccess(Void result) {
- AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
- Stream.of(slideDeck.getSlides())
- .map(Slide::getUri)
- .withoutNulls()
- .filter(BlobProvider::isAuthority)
- .forEach(uri -> BlobProvider.getInstance().delete(context, uri));
- });
- }
- });
- break;
- case INVITE_CONTACTS:
- if (data.getExtras() == null || !data.hasExtra(SelectContactsActivity.Companion.getSelectedContactsKey())) return;
- String[] selectedContacts = data.getExtras().getStringArray(SelectContactsActivity.Companion.getSelectedContactsKey());
- sendOpenGroupInvitations(selectedContacts);
- break;
- }
- }
-
- @Override
- public void startActivity(Intent intent) {
- if (intent.getStringExtra(Browser.EXTRA_APPLICATION_ID) != null) {
- intent.removeExtra(Browser.EXTRA_APPLICATION_ID);
- }
-
- try {
- super.startActivity(intent);
- } catch (ActivityNotFoundException e) {
- Log.w(TAG, e);
- Toast.makeText(this, R.string.ConversationActivity_there_is_no_app_available_to_handle_this_link_on_your_device, Toast.LENGTH_LONG).show();
- }
- }
-
- @Override
- public boolean onPrepareOptionsMenu(Menu menu) {
- MenuInflater inflater = this.getMenuInflater();
- menu.clear();
-
- boolean isOpenGroupOrRSSFeed = recipient.getAddress().isOpenGroup();
-
- if (!isOpenGroupOrRSSFeed) {
- if (recipient.getExpireMessages() > 0) {
- inflater.inflate(R.menu.conversation_expiring_on, menu);
-
- final MenuItem item = menu.findItem(R.id.menu_expiring_messages);
- final View actionView = MenuItemCompat.getActionView(item);
- final ImageView iconView = actionView.findViewById(R.id.menu_badge_icon);
- final TextView badgeView = actionView.findViewById(R.id.expiration_badge);
-
- @ColorInt int color = GeneralUtilitiesKt.getColorWithID(getResources(), R.color.text, getTheme());
- iconView.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.MULTIPLY));
- badgeView.setText(ExpirationUtil.getExpirationAbbreviatedDisplayValue(this, recipient.getExpireMessages()));
- actionView.setOnClickListener(v -> onOptionsItemSelected(item));
- } else {
- inflater.inflate(R.menu.conversation_expiring_off, menu);
- }
- }
-
- if (isSingleConversation()) {
- if (recipient.isBlocked()) {
- inflater.inflate(R.menu.conversation_unblock, menu);
- } else {
- inflater.inflate(R.menu.conversation_block, menu);
- }
- inflater.inflate(R.menu.conversation_copy_session_id, menu);
- } else if (isGroupConversation() && !isOpenGroupOrRSSFeed) {
-// inflater.inflate(R.menu.conversation_group_options, menu);
-
- if (!isPushGroupConversation()) {
- inflater.inflate(R.menu.conversation_mms_group_options, menu);
- if (distributionType == DistributionTypes.BROADCAST) {
- menu.findItem(R.id.menu_distribution_broadcast).setChecked(true);
- } else {
- menu.findItem(R.id.menu_distribution_conversation).setChecked(true);
- }
- } else if (isActiveGroup()) {
- inflater.inflate(R.menu.conversation_push_group_options, menu);
- }
- } else if (isOpenGroupOrRSSFeed) {
- inflater.inflate(R.menu.conversation_invite_open_group, menu);
- }
-
- inflater.inflate(R.menu.conversation, menu);
-
-// if (isSingleConversation()) {
-// inflater.inflate(R.menu.conversation_secure, menu);
-// }
-
- if (recipient != null && recipient.isMuted()) inflater.inflate(R.menu.conversation_muted, menu);
- else inflater.inflate(R.menu.conversation_unmuted, menu);
-
- /*
- if (isSingleConversation() && getRecipient().getContactUri() == null) {
- inflater.inflate(R.menu.conversation_add_to_contacts, menu);
- }
- if (recipient != null && recipient.isLocalNumber()) {
- if (isSecureText) menu.findItem(R.id.menu_call_secure).setVisible(false);
- else menu.findItem(R.id.menu_call_insecure).setVisible(false);
- MenuItem muteItem = menu.findItem(R.id.menu_mute_notifications);
- if (muteItem != null) {
- muteItem.setVisible(false);
- }
- }
- */
-
- searchViewItem = menu.findItem(R.id.menu_search);
-
- SearchView searchView = (SearchView)searchViewItem.getActionView();
- SearchView.OnQueryTextListener queryListener = new SearchView.OnQueryTextListener() {
- @Override
- public boolean onQueryTextSubmit(String query) {
- searchViewModel.onQueryUpdated(query, threadId);
- searchNav.showLoading();
- fragment.onSearchQueryUpdated(query);
- return true;
- }
-
- @Override
- public boolean onQueryTextChange(String query) {
- searchViewModel.onQueryUpdated(query, threadId);
- searchNav.showLoading();
- fragment.onSearchQueryUpdated(query);
- return true;
- }
- };
-
- searchViewItem.setOnActionExpandListener(new MenuItem.OnActionExpandListener() {
- @Override
- public boolean onMenuItemActionExpand(MenuItem item) {
- searchView.setOnQueryTextListener(queryListener);
- searchViewModel.onSearchOpened();
- searchNav.setVisibility(View.VISIBLE);
- searchNav.setData(0, 0);
- inputPanel.setVisibility(View.GONE);
-
- for (int i = 0; i < menu.size(); i++) {
- if (!menu.getItem(i).equals(searchViewItem)) {
- menu.getItem(i).setVisible(false);
- }
- }
- return true;
- }
-
- @Override
- public boolean onMenuItemActionCollapse(MenuItem item) {
- searchView.setOnQueryTextListener(null);
- searchViewModel.onSearchClosed();
- searchNav.setVisibility(View.GONE);
- inputPanel.setVisibility(View.VISIBLE);
- updateInputUI(recipient);
- fragment.onSearchQueryUpdated(null);
- invalidateOptionsMenu();
- return true;
- }
- });
-
- super.onPrepareOptionsMenu(menu);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- super.onOptionsItemSelected(item);
- switch (item.getItemId()) {
-// case R.id.menu_call_secure: handleDial(getRecipient(), true); return true;
-// case R.id.menu_call_insecure: handleDial(getRecipient(), false); return true;
- case R.id.menu_unblock: handleUnblock(); return true;
- case R.id.menu_block: handleBlock(); return true;
- case R.id.menu_copy_session_id: handleCopySessionID(); return true;
- case R.id.menu_view_media: handleViewMedia(); return true;
- case R.id.menu_add_shortcut: handleAddShortcut(); return true;
- case R.id.menu_search: handleSearch(); return true;
-// case R.id.menu_add_to_contacts: handleAddToContacts(); return true;
-// case R.id.menu_reset_secure_session: handleResetSecureSession(); return true;
-// case R.id.menu_group_recipients: handleDisplayGroupRecipients(); return true;
- 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_leave: handleLeavePushGroup(); return true;
- case R.id.menu_mute_notifications: handleMuteNotifications(); return true;
- case R.id.menu_unmute_notifications: handleUnmuteNotifications(); return true;
-// case R.id.menu_conversation_settings: handleConversationSettings(); return true;
- case R.id.menu_expiring_messages_off:
- case R.id.menu_expiring_messages: handleSelectMessageExpiration(); return true;
- case R.id.menu_invite_to_open_group: handleInviteToOpenGroup(); return true;
- case android.R.id.home: handleReturnToConversationList(); return true;
- }
-
- return false;
- }
-
- @Override
- public void onBackPressed() {
- Log.d(TAG, "onBackPressed()");
- if (container.isInputOpen()) container.hideCurrentInput(composeText);
- else super.onBackPressed();
- }
-
- @Override
- public void onKeyboardShown() {
- inputPanel.onKeyboardShown();
- }
-
- @Override
- public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
- super.onRequestPermissionsResult(requestCode, permissions, grantResults);
- Permissions.onRequestPermissionsResult(this, requestCode, permissions, grantResults);
- }
-
- //////// Event Handlers
-
- private void handleReturnToConversationList() {
- Intent intent = new Intent(this, HomeActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- startActivity(intent);
- finish();
- }
-
- private void handleSelectMessageExpiration() {
- if (isPushGroupConversation() && !isActiveGroup()) {
- return;
- }
-
- //noinspection CodeBlock2Expr
- ExpirationDialog.show(this, recipient.getExpireMessages(), expirationTime -> {
- new AsyncTask() {
- @Override
- protected Void doInBackground(Void... params) {
- DatabaseFactory.getRecipientDatabase(ConversationActivity.this).setExpireMessages(recipient, expirationTime);
- ExpirationTimerUpdate message = new ExpirationTimerUpdate(expirationTime);
- message.setRecipient(recipient.getAddress().serialize()); // we need the recipient in ExpiringMessageManager.insertOutgoingExpirationTimerMessage
- message.setSentTimestamp(System.currentTimeMillis());
- ExpiringMessageManager expiringMessageManager = ApplicationContext.getInstance(getApplicationContext()).getExpiringMessageManager();
- expiringMessageManager.setExpirationTimer(message);
- MessageSender.send(message, recipient.getAddress());
-
- return null;
- }
-
- @Override
- protected void onPostExecute(Void result) {
- invalidateOptionsMenu();
- if (fragment != null) fragment.setLastSeen(0);
- }
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- });
- }
-
- private void handleMuteNotifications() {
- MuteDialog.show(this, until -> {
- recipient.setMuted(until);
-
- new AsyncTask() {
- @Override
- protected Void doInBackground(Void... params) {
- DatabaseFactory.getRecipientDatabase(ConversationActivity.this)
- .setMuted(recipient, until);
-
- return null;
- }
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- });
- }
-
- private void handleUnmuteNotifications() {
- recipient.setMuted(0);
-
- new AsyncTask() {
- @Override
- protected Void doInBackground(Void... params) {
- DatabaseFactory.getRecipientDatabase(ConversationActivity.this)
- .setMuted(recipient, 0);
-
- return null;
- }
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- }
-
- private void handleUnblock() {
- int titleRes = R.string.ConversationActivity_unblock_this_contact_question;
- int bodyRes = R.string.ConversationActivity_you_will_once_again_be_able_to_receive_messages_and_calls_from_this_contact;
-
- new AlertDialog.Builder(this)
- .setTitle(titleRes)
- .setMessage(bodyRes)
- .setNegativeButton(android.R.string.cancel, null)
- .setPositiveButton(R.string.ConversationActivity_unblock, (dialog, which) -> {
- new AsyncTask() {
- @Override
- protected Void doInBackground(Void... params) {
- DatabaseFactory.getRecipientDatabase(ConversationActivity.this)
- .setBlocked(recipient, false);
-
- return null;
- }
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- }).show();
- }
-
- @TargetApi(Build.VERSION_CODES.KITKAT)
- private void handleMakeDefaultSms() {
- Intent intent = new Intent(Telephony.Sms.Intents.ACTION_CHANGE_DEFAULT);
- intent.putExtra(Telephony.Sms.Intents.EXTRA_PACKAGE_NAME, getPackageName());
- startActivityForResult(intent, SMS_DEFAULT);
- }
-
- private void handleBlock() {
- int titleRes = R.string.RecipientPreferenceActivity_block_this_contact_question;
- int bodyRes = R.string.RecipientPreferenceActivity_you_will_no_longer_receive_messages_and_calls_from_this_contact;
-
- new AlertDialog.Builder(this)
- .setTitle(titleRes)
- .setMessage(bodyRes)
- .setNegativeButton(android.R.string.cancel, null)
- .setPositiveButton(R.string.RecipientPreferenceActivity_block, (dialog, which) -> {
- new AsyncTask() {
- @Override
- protected Void doInBackground(Void... params) {
- DatabaseFactory.getRecipientDatabase(ConversationActivity.this)
- .setBlocked(recipient, true);
-
- Util.runOnMain(() -> finish());
-
- return null;
- }
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- }).show();
- }
-
- private void handleCopySessionID() {
- if (recipient.isGroupRecipient()) { return; }
- String sessionID = recipient.getAddress().toString();
- ClipboardManager clipboard = (ClipboardManager)getSystemService(Context.CLIPBOARD_SERVICE);
- ClipData clip = ClipData.newPlainText("Session ID", sessionID);
- clipboard.setPrimaryClip(clip);
- Toast.makeText(this, R.string.copied_to_clipboard, Toast.LENGTH_SHORT).show();
- }
-
- private void handleViewMedia() {
- Intent intent = new Intent(this, MediaOverviewActivity.class);
- intent.putExtra(MediaOverviewActivity.ADDRESS_EXTRA, recipient.getAddress());
- startActivity(intent);
- }
-
- private void handleAddShortcut() {
- Log.i(TAG, "Creating home screen shortcut for recipient " + recipient.getAddress());
-
- new AsyncTask() {
-
- @Override
- protected IconCompat doInBackground(Void... voids) {
- Context context = getApplicationContext();
- IconCompat icon = null;
-
- if (recipient.getContactPhoto() != null) {
- try {
- Bitmap bitmap = BitmapFactory.decodeStream(recipient.getContactPhoto().openInputStream(context));
- bitmap = BitmapUtil.createScaledBitmap(bitmap, 300, 300);
- icon = IconCompat.createWithAdaptiveBitmap(bitmap);
- } catch (IOException e) {
- Log.w(TAG, "Failed to decode contact photo during shortcut creation. Falling back to generic icon.", e);
- }
- }
-
- if (icon == null) {
- icon = IconCompat.createWithResource(context, recipient.isGroupRecipient() ? R.mipmap.ic_group_shortcut
- : R.mipmap.ic_person_shortcut);
- }
-
- return icon;
- }
-
- @Override
- protected void onPostExecute(IconCompat icon) {
- Context context = getApplicationContext();
- String name = Optional.fromNullable(recipient.getName())
- .or(Optional.fromNullable(recipient.getProfileName()))
- .or(recipient.toShortString());
-
- ShortcutInfoCompat shortcutInfo = new ShortcutInfoCompat.Builder(context, recipient.getAddress().serialize() + '-' + System.currentTimeMillis())
- .setShortLabel(name)
- .setIcon(icon)
- .setIntent(ShortcutLauncherActivity.createIntent(context, recipient.getAddress()))
- .build();
-
- if (ShortcutManagerCompat.requestPinShortcut(context, shortcutInfo, null)) {
- Toast.makeText(context, getString(R.string.ConversationActivity_added_to_home_screen), Toast.LENGTH_LONG).show();
- }
- }
- }.execute();
- }
-
- private void handleSearch() {
- searchViewModel.onSearchOpened();
- }
-
- private void handleLeavePushGroup() {
- if (getRecipient() == null) {
- Toast.makeText(this, getString(R.string.ConversationActivity_invalid_recipient),
- Toast.LENGTH_LONG).show();
- return;
- }
-
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setTitle(getString(R.string.ConversationActivity_leave_group));
- builder.setIconAttribute(R.attr.dialog_info_icon);
- builder.setCancelable(true);
-
- GroupRecord group = DatabaseFactory.getGroupDatabase(this).getGroup(getRecipient().getAddress().toGroupString()).orNull();
- List admins = group.getAdmins();
- String userPublicKey = TextSecurePreferences.getLocalNumber(this);
- String message = getString(R.string.ConversationActivity_are_you_sure_you_want_to_leave_this_group);
- for (Address admin : admins) {
- if (admin.toString().equals(userPublicKey)) {
- message = "Because you are the creator of this group it will be deleted for everyone. This cannot be undone.";
- }
- }
-
- builder.setMessage(message);
- builder.setPositiveButton(R.string.yes, (dialog, which) -> {
- Recipient groupRecipient = getRecipient();
- String groupPublicKey;
- boolean isClosedGroup;
- try {
- groupPublicKey = HexEncodingKt.toHexString(GroupUtil.doubleDecodeGroupID(groupRecipient.getAddress().toString()));
- isClosedGroup = DatabaseFactory.getLokiAPIDatabase(this).isClosedGroup(groupPublicKey);
- } catch (IOException e) {
- groupPublicKey = null;
- isClosedGroup = false;
- }
- try {
- if (isClosedGroup) {
- MessageSender.explicitLeave(groupPublicKey, true);
- initializeEnabledCheck();
- } else {
- Toast.makeText(this, R.string.ConversationActivity_error_leaving_group, Toast.LENGTH_LONG).show();
- }
- } catch (Exception e) {
- Toast.makeText(this, R.string.ConversationActivity_error_leaving_group, Toast.LENGTH_LONG).show();
- }
- });
-
- builder.setNegativeButton(R.string.no, null);
- builder.show();
- }
-
- private void handleEditPushGroup() {
- Intent intent = new Intent(this, EditClosedGroupActivity.class);
- String groupID = this.recipient.getAddress().toGroupString();
- intent.putExtra(EditClosedGroupActivity.Companion.getGroupIDKey(), groupID);
- startActivity(intent);
- }
-
- private void handleInviteToOpenGroup() {
- Intent intent = new Intent(this, SelectContactsActivity.class);
- startActivityForResult(intent, INVITE_CONTACTS);
- }
-
- private void handleDistributionBroadcastEnabled(MenuItem item) {
- distributionType = DistributionTypes.BROADCAST;
- item.setChecked(true);
-
- if (threadId != -1) {
- new AsyncTask() {
- @Override
- protected Void doInBackground(Void... params) {
- DatabaseFactory.getThreadDatabase(ConversationActivity.this)
- .setDistributionType(threadId, DistributionTypes.BROADCAST);
- return null;
- }
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- }
- }
-
- private void handleDistributionConversationEnabled(MenuItem item) {
- distributionType = DistributionTypes.CONVERSATION;
- item.setChecked(true);
-
- if (threadId != -1) {
- new AsyncTask() {
- @Override
- protected Void doInBackground(Void... params) {
- DatabaseFactory.getThreadDatabase(ConversationActivity.this)
- .setDistributionType(threadId, DistributionTypes.CONVERSATION);
- return null;
- }
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- }
- }
-
- private void handleAddAttachment() {
- if (attachmentTypeSelector == null) {
- attachmentTypeSelector = new AttachmentTypeSelector(
- this,
- LoaderManager.getInstance(this),
- new AttachmentTypeListener(),
- keyboardHeight);
- }
- attachmentTypeSelector.show(this, attachButton);
- }
-
- private void handleSecurityChange(boolean isSecureText, boolean isDefaultSms) {
- Log.i(TAG, "handleSecurityChange(" + isSecureText + ", " + isDefaultSms + ")");
- if (isSecurityInitialized && isSecureText == true && isDefaultSms == this.isDefaultSms) {
- return;
- }
-
- this.isDefaultSms = isDefaultSms;
- this.isSecurityInitialized = true;
-
- if (recipient == null || attachmentManager == null) { return; }
-
- /* Loki - We don't support SMS
- if (!isSecureText && !isPushGroupConversation()) sendButton.disableTransport(Type.TEXTSECURE);
- if (recipient.isPushGroupRecipient()) sendButton.disableTransport(Type.SMS);
- if (!recipient.isPushGroupRecipient() && recipient.isForceSmsSelection()) {
- sendButton.setDefaultTransport(Type.SMS);
- } else {
- if (isSecureText || isPushGroupConversation()) sendButton.setDefaultTransport(Type.TEXTSECURE);
- else sendButton.setDefaultTransport(Type.SMS);
- }
- */
-
- supportInvalidateOptionsMenu();
- updateInputUI(recipient);
- }
-
- ///// Initializers
-
- private ListenableFuture initializeDraft() {
- final SettableFuture result = new SettableFuture<>();
-
- final String draftText = getIntent().getStringExtra(TEXT_EXTRA);
- final Uri draftMedia = getIntent().getData();
- final MediaType draftMediaType = MediaType.from(getIntent().getType());
- final List mediaList = getIntent().getParcelableArrayListExtra(MEDIA_EXTRA);
-
- if (!Util.isEmpty(mediaList)) {
- Intent sendIntent = MediaSendActivity.buildEditorIntent(this, mediaList, recipient, draftText);
- startActivityForResult(sendIntent, MEDIA_SENDER);
- return new SettableFuture<>(false);
- }
-
- if (draftText != null) {
- composeText.setText("");
- composeText.append(draftText);
- result.set(true);
- }
-
- if (draftMedia != null && draftMediaType != null) {
- return setMedia(draftMedia, draftMediaType);
- }
-
- if (draftText == null && draftMedia == null && draftMediaType == null) {
- return initializeDraftFromDatabase();
- } else {
- updateToggleButtonState();
- result.set(false);
- }
-
- return result;
- }
-
- private void initializeEnabledCheck() {
- boolean enabled = !(isPushGroupConversation() && !isActiveGroup());
- inputPanel.setEnabled(enabled);
- sendButton.setEnabled(enabled);
- attachButton.setEnabled(enabled);
- }
-
- private ListenableFuture initializeDraftFromDatabase() {
- SettableFuture future = new SettableFuture<>();
-
- new AsyncTask>() {
- @Override
- protected List doInBackground(Void... params) {
- DraftDatabase draftDatabase = DatabaseFactory.getDraftDatabase(ConversationActivity.this);
- List results = draftDatabase.getDrafts(threadId);
-
- draftDatabase.clearDrafts(threadId);
-
- return results;
- }
-
- @Override
- protected void onPostExecute(List drafts) {
- if (drafts.isEmpty()) {
- future.set(false);
- updateToggleButtonState();
- return;
- }
-
- AtomicInteger draftsRemaining = new AtomicInteger(drafts.size());
- AtomicBoolean success = new AtomicBoolean(false);
- ListenableFuture.Listener listener = new AssertedSuccessListener() {
- @Override
- public void onSuccess(Boolean result) {
- success.compareAndSet(false, result);
-
- if (draftsRemaining.decrementAndGet() <= 0) {
- future.set(success.get());
- }
- }
- };
-
- for (Draft draft : drafts) {
- switch (draft.getType()) {
- case Draft.TEXT:
- composeText.setText(draft.getValue());
- listener.onSuccess(true);
- break;
- case Draft.IMAGE:
- setMedia(Uri.parse(draft.getValue()), MediaType.IMAGE).addListener(listener);
- break;
- case Draft.AUDIO:
- setMedia(Uri.parse(draft.getValue()), MediaType.AUDIO).addListener(listener);
- break;
- case Draft.VIDEO:
- setMedia(Uri.parse(draft.getValue()), MediaType.VIDEO).addListener(listener);
- break;
- case Draft.QUOTE:
- SettableFuture quoteResult = new SettableFuture<>();
- new QuoteRestorationTask(draft.getValue(), quoteResult).execute();
- quoteResult.addListener(listener);
- break;
- }
- }
-
- updateToggleButtonState();
- }
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
-
- return future;
- }
-
- private ListenableFuture initializeSecurity(final boolean currentSecureText,
- final boolean currentIsDefaultSms)
- {
- final SettableFuture future = new SettableFuture<>();
-
- handleSecurityChange(currentSecureText || isPushGroupConversation(), currentIsDefaultSms);
-
- new AsyncTask() {
- @Override
- protected boolean[] doInBackground(Recipient... params) {
- // Loki - Override the flag below
- boolean signalEnabled = true; // TextSecurePreferences.isPushRegistered(context);
-
-
- return new boolean[] { signalEnabled, false};
- }
-
- @Override
- protected void onPostExecute(boolean[] result) {
- if (result[0] != currentSecureText || result[1] != currentIsDefaultSms) {
- Log.i(TAG, "onPostExecute() handleSecurityChange: " + result[0] + " , " + result[1]);
- handleSecurityChange(result[0], result[1]);
- }
- future.set(true);
- }
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, recipient);
-
- return future;
- }
-
- private void initializeViews() {
- profilePictureView = findViewById(R.id.profilePictureView);
- titleTextView = findViewById(R.id.titleTextView);
- buttonToggle = ViewUtil.findById(this, R.id.button_toggle);
- sendButton = ViewUtil.findById(this, R.id.send_button);
- attachButton = ViewUtil.findById(this, R.id.attach_button);
- composeText = ViewUtil.findById(this, R.id.embedded_text_editor);
- emojiDrawerStub = ViewUtil.findStubById(this, R.id.emoji_drawer_stub);
- unblockButton = ViewUtil.findById(this, R.id.unblock_button);
- makeDefaultSmsButton = ViewUtil.findById(this, R.id.make_default_sms_button);
- container = ViewUtil.findById(this, R.id.layout_container);
- quickAttachmentToggle = ViewUtil.findById(this, R.id.quick_attachment_toggle);
- inlineAttachmentToggle = ViewUtil.findById(this, R.id.inline_attachment_container);
- inputPanel = ViewUtil.findById(this, R.id.bottom_panel);
- searchNav = ViewUtil.findById(this, R.id.conversation_search_nav);
- mentionCandidateSelectionViewContainer = ViewUtil.findById(this, R.id.mentionCandidateSelectionViewContainer);
- mentionCandidateSelectionView = ViewUtil.findById(this, R.id.userSelectionView);
- messageStatusProgressBar = ViewUtil.findById(this, R.id.messageStatusProgressBar);
- muteIndicatorImageView = ViewUtil.findById(this, R.id.muteIndicatorImageView);
- subtitleTextView = ViewUtil.findById(this, R.id.subtitleTextView);
- homeButtonContainer = ViewUtil.findById(this, R.id.homeButtonContainer);
-
- ImageButton quickCameraToggle = ViewUtil.findById(this, R.id.quick_camera_toggle);
- ImageButton inlineAttachmentButton = ViewUtil.findById(this, R.id.inline_attachment_button);
-
- container.addOnKeyboardShownListener(this);
- inputPanel.setListener(this);
- inputPanel.setMediaListener(this);
-
- attachmentTypeSelector = null;
- attachmentManager = new AttachmentManager(this, this);
- audioRecorder = new AudioRecorder(this);
- typingTextWatcher = new TypingStatusTextWatcher();
- mentionTextWatcher = new MentionTextWatcher();
-
- SendButtonListener sendButtonListener = new SendButtonListener();
- ComposeKeyPressedListener composeKeyPressedListener = new ComposeKeyPressedListener();
-
- composeText.setOnEditorActionListener(sendButtonListener);
- composeText.setCursorPositionChangedListener(this);
- attachButton.setOnClickListener(new AttachButtonListener());
- attachButton.setOnLongClickListener(new AttachButtonLongClickListener());
- sendButton.setOnClickListener(sendButtonListener);
- sendButton.setEnabled(true);
-
- unblockButton.setOnClickListener(v -> handleUnblock());
- makeDefaultSmsButton.setOnClickListener(v -> handleMakeDefaultSms());
-
- composeText.setOnKeyListener(composeKeyPressedListener);
- composeText.addTextChangedListener(composeKeyPressedListener);
- composeText.setOnEditorActionListener(sendButtonListener);
- composeText.setOnClickListener(composeKeyPressedListener);
- composeText.setOnFocusChangeListener(composeKeyPressedListener);
-
- if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA) && Camera.getNumberOfCameras() > 0) {
- quickCameraToggle.setVisibility(View.VISIBLE);
- quickCameraToggle.setOnClickListener(new QuickCameraToggleListener());
- } else {
- quickCameraToggle.setVisibility(View.GONE);
- }
-
- searchNav.setEventListener(this);
-
- inlineAttachmentButton.setOnClickListener(v -> handleAddAttachment());
-
- homeButtonContainer.setOnClickListener(v -> onSupportNavigateUp());
- }
-
- protected void initializeActionBar() {
- Toolbar toolbar = findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- ActionBar supportActionBar = getSupportActionBar();
- if (supportActionBar == null) throw new AssertionError();
-
-// supportActionBar.setDisplayHomeAsUpEnabled(true);
- supportActionBar.setDisplayShowTitleEnabled(false);
- }
-
- private void initializeResources() {
- if (recipient != null) recipient.removeListener(this);
-
- Address address = getIntent().getParcelableExtra(ADDRESS_EXTRA);
- if (address == null) { finish(); return; }
- recipient = Recipient.from(this, address, true);
- threadId = getIntent().getLongExtra(THREAD_ID_EXTRA, -1);
- distributionType = getIntent().getIntExtra(DISTRIBUTION_TYPE_EXTRA, DistributionTypes.DEFAULT);
- glideRequests = GlideApp.with(this);
-
- recipient.addListener(this);
- }
-
- private void initializeLinkPreviewObserver() {
- linkPreviewViewModel = ViewModelProviders.of(this, new LinkPreviewViewModel.Factory(new LinkPreviewRepository(this))).get(LinkPreviewViewModel.class);
-
- if (!TextSecurePreferences.isLinkPreviewsEnabled(this)) {
- linkPreviewViewModel.onUserCancel();
- return;
- }
-
- linkPreviewViewModel.getLinkPreviewState().observe(this, previewState -> {
- if (previewState == null) return;
-
- if (previewState.isLoading()) {
- Log.d(TAG, "Loading link preview.");
- inputPanel.setLinkPreviewLoading();
- } else {
- Log.d(TAG, "Setting link preview: " + previewState.getLinkPreview().isPresent());
- inputPanel.setLinkPreview(glideRequests, previewState.getLinkPreview());
- }
-
- updateToggleButtonState();
- });
- }
-
- private void initializeSearchObserver() {
- searchViewModel = ViewModelProviders.of(this).get(ConversationSearchViewModel.class);
-
- searchViewModel.getSearchResults().observe(this, result -> {
- if (result == null) return;
-
- if (!result.getResults().isEmpty()) {
- MessageResult messageResult = result.getResults().get(result.getPosition());
- fragment.jumpToMessage(messageResult.messageRecipient.getAddress(), messageResult.receivedTimestampMs, searchViewModel::onMissingResult);
- }
-
- searchNav.setData(result.getPosition(), result.getResults().size());
- });
- }
-
- @Override
- public void onSearchMoveUpPressed() {
- searchViewModel.onMoveUp();
- }
-
- @Override
- public void onSearchMoveDownPressed() {
- searchViewModel.onMoveDown();
- }
-
- @Override
- public void onModified(final Recipient recipient) {
- Log.i(TAG, "onModified(" + recipient.getAddress().serialize() + ")");
- Util.runOnMain(() -> {
- Log.i(TAG, "onModifiedRun(): " + recipient.getRegistered());
- updateTitleTextView(recipient);
- updateProfilePicture();
- updateSubtitleTextView();
- updateInputUI(recipient);
- initializeSecurity(true, isDefaultSms);
-
- if (searchViewItem == null || !searchViewItem.isActionViewExpanded()) {
- invalidateOptionsMenu();
- }
- });
- }
-
- @Subscribe(threadMode = ThreadMode.MAIN)
- public void onOpenGroupInfoUpdated(OpenGroupUtilities.GroupInfoUpdatedEvent event) {
- OpenGroupV2 openGroup = DatabaseFactory.getLokiThreadDatabase(this).getOpenGroupChat(threadId);
- if (openGroup != null &&
- openGroup.getRoom().equals(event.getRoom()) &&
- openGroup.getServer().equals(event.getUrl())) {
- this.updateSubtitleTextView();
- }
- }
-
- //////// Helper Methods
-
- private void addAttachment(int type) {
- linkPreviewViewModel.onUserCancel();
-
- Log.i(TAG, "Selected: " + type);
- switch (type) {
- case AttachmentTypeSelector.ADD_GALLERY:
- AttachmentManager.selectGallery(this, MEDIA_SENDER, recipient, composeText.getTextTrimmed()); break;
- case AttachmentTypeSelector.ADD_DOCUMENT:
- AttachmentManager.selectDocument(this, PICK_DOCUMENT); break;
- case AttachmentTypeSelector.ADD_SOUND:
- AttachmentManager.selectAudio(this, PICK_AUDIO); break;
- case AttachmentTypeSelector.ADD_CONTACT_INFO:
- break;
- case AttachmentTypeSelector.ADD_LOCATION:
- break;
- case AttachmentTypeSelector.TAKE_PHOTO:
- attachmentManager.capturePhoto(this, TAKE_PHOTO); break;
- case AttachmentTypeSelector.ADD_GIF:
- boolean hasSeenGIFMetaDataWarning = TextSecurePreferences.hasSeenGIFMetaDataWarning(this);
- if (!hasSeenGIFMetaDataWarning) {
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setTitle("Search GIFs?");
- builder.setMessage("You will not have full metadata protection when sending GIFs.");
- builder.setPositiveButton("OK", (dialog, which) -> {
- AttachmentManager.selectGif(this, PICK_GIF);
- dialog.dismiss();
- });
- builder.setNegativeButton("Cancel", (dialog, which) -> dialog.dismiss());
- builder.create().show();
- TextSecurePreferences.setHasSeenGIFMetaDataWarning(this);
- } else {
- AttachmentManager.selectGif(this, PICK_GIF);
- }
- break;
- }
- }
-
- private ListenableFuture setMedia(@Nullable Uri uri, @NonNull MediaType mediaType) {
- return setMedia(uri, mediaType, 0, 0);
- }
-
- private ListenableFuture setMedia(@Nullable Uri uri, @NonNull MediaType mediaType, int width, int height) {
- if (uri == null) {
- return new SettableFuture<>(false);
- }
-
- if (MediaType.VCARD.equals(mediaType)) {
- return new SettableFuture<>(false);
- } else if (MediaType.IMAGE.equals(mediaType) || MediaType.GIF.equals(mediaType) || MediaType.VIDEO.equals(mediaType)) {
- Media media = new Media(uri, MediaUtil.getMimeType(this, uri), 0, width, height, 0, Optional.absent(), Optional.absent());
- startActivityForResult(MediaSendActivity.buildEditorIntent(ConversationActivity.this, Collections.singletonList(media), recipient, composeText.getTextTrimmed()), MEDIA_SENDER);
- return new SettableFuture<>(false);
- } else {
- return attachmentManager.setMedia(glideRequests, uri, mediaType, MediaConstraints.getPushMediaConstraints(), width, height);
- }
- }
-
- private void addAttachmentContactInfo(Uri contactUri) {
- ContactAccessor contactDataList = ContactAccessor.getInstance();
- ContactData contactData = contactDataList.getContactData(this, contactUri);
-
- if (contactData.numbers.size() == 1) composeText.append(contactData.numbers.get(0).number);
- else if (contactData.numbers.size() > 1) selectContactInfo(contactData);
- }
-
- private void selectContactInfo(ContactData contactData) {
- final CharSequence[] numbers = new CharSequence[contactData.numbers.size()];
- final CharSequence[] numberItems = new CharSequence[contactData.numbers.size()];
-
- for (int i = 0; i < contactData.numbers.size(); i++) {
- numbers[i] = contactData.numbers.get(i).number;
- numberItems[i] = contactData.numbers.get(i).type + ": " + contactData.numbers.get(i).number;
- }
-
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setIconAttribute(R.attr.conversation_attach_contact_info);
- builder.setTitle(R.string.ConversationActivity_select_contact_info);
-
- builder.setItems(numberItems, (dialog, which) -> composeText.append(numbers[which]));
- builder.show();
- }
-
- private Drafts getDraftsForCurrentState() {
- Drafts drafts = new Drafts();
-
- if (!org.thoughtcrime.securesms.util.Util.isEmpty(composeText)) {
- drafts.add(new Draft(Draft.TEXT, composeText.getTextTrimmed()));
- }
-
- for (Slide slide : attachmentManager.buildSlideDeck().getSlides()) {
- if (slide.hasAudio() && slide.getUri() != null) drafts.add(new Draft(Draft.AUDIO, slide.getUri().toString()));
- else if (slide.hasVideo() && slide.getUri() != null) drafts.add(new Draft(Draft.VIDEO, slide.getUri().toString()));
- else if (slide.hasImage() && slide.getUri() != null) drafts.add(new Draft(Draft.IMAGE, slide.getUri().toString()));
- }
-
- Optional quote = inputPanel.getQuote();
-
- if (quote.isPresent()) {
- drafts.add(new Draft(Draft.QUOTE, new QuoteId(quote.get().getId(), quote.get().getAuthor()).serialize()));
- }
-
- return drafts;
- }
-
- protected ListenableFuture saveDraft() {
- final SettableFuture future = new SettableFuture<>();
-
- if (this.recipient == null) {
- future.set(threadId);
- return future;
- }
-
- final Drafts drafts = getDraftsForCurrentState();
- final long thisThreadId = this.threadId;
- final int thisDistributionType = this.distributionType;
-
- new AsyncTask() {
- @Override
- protected Long doInBackground(Long... params) {
- ThreadDatabase threadDatabase = DatabaseFactory.getThreadDatabase(ConversationActivity.this);
- DraftDatabase draftDatabase = DatabaseFactory.getDraftDatabase(ConversationActivity.this);
- long threadId = params[0];
-
- if (drafts.size() > 0) {
- if (threadId == -1) threadId = threadDatabase.getOrCreateThreadIdFor(getRecipient(), thisDistributionType);
-
- draftDatabase.insertDrafts(threadId, drafts);
- threadDatabase.updateSnippet(threadId, drafts.getSnippet(ConversationActivity.this),
- drafts.getUriSnippet(),
- System.currentTimeMillis(), Types.BASE_DRAFT_TYPE, true);
- } else if (threadId > 0) {
- threadDatabase.update(threadId, false);
- }
-
- return threadId;
- }
-
- @Override
- protected void onPostExecute(Long result) {
- future.set(result);
- }
-
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, thisThreadId);
-
- return future;
- }
-
- private void updateInputUI(Recipient recipient) {
- if (recipient.isGroupRecipient() && !isActiveGroup()) {
- unblockButton.setVisibility(View.GONE);
- inputPanel.setVisibility(View.GONE);
- makeDefaultSmsButton.setVisibility(View.GONE);
- } else if (recipient.isBlocked()) {
- unblockButton.setVisibility(View.VISIBLE);
- inputPanel.setVisibility(View.GONE);
- makeDefaultSmsButton.setVisibility(View.GONE);
- } else {
- inputPanel.setVisibility(View.VISIBLE);
- unblockButton.setVisibility(View.GONE);
- makeDefaultSmsButton.setVisibility(View.GONE);
- }
- }
-
- private void initializeMediaKeyboardProviders(@NonNull MediaKeyboard mediaKeyboard) {
- boolean isSystemEmojiPreferred = TextSecurePreferences.isSystemEmojiPreferred(this);
- if (!isSystemEmojiPreferred) {
- mediaKeyboard.setProviders(0, new EmojiKeyboardProvider(this, inputPanel));
- }
- }
-
-
- private boolean isSingleConversation() {
- return getRecipient() != null && !getRecipient().isGroupRecipient();
- }
-
- private boolean isActiveGroup() {
- if (!isGroupConversation()) return false;
-
- Optional record = DatabaseFactory.getGroupDatabase(this).getGroup(getRecipient().getAddress().toGroupString());
- return record.isPresent() && record.get().isActive();
- }
-
- @SuppressWarnings("SimplifiableIfStatement")
- private boolean isSelfConversation() {
- if (!TextSecurePreferences.isPushRegistered(this)) return false;
- if (recipient.isGroupRecipient()) return false;
-
- return Util.isOwnNumber(this, recipient.getAddress().serialize());
- }
-
- private boolean isGroupConversation() {
- return getRecipient() != null && getRecipient().isGroupRecipient();
- }
-
- private boolean isPushGroupConversation() {
- return getRecipient() != null && getRecipient().isPushGroupRecipient();
- }
-
- protected Recipient getRecipient() {
- return this.recipient;
- }
-
- protected long getThreadId() {
- return this.threadId;
- }
-
- private String getMessage() throws InvalidMessageException {
- String result = composeText.getTextTrimmed();
- if (result.length() < 1) throw new InvalidMessageException();
- for (Mention mention : mentions) {
- try {
- int startIndex = result.indexOf("@" + mention.getDisplayName());
- int endIndex = startIndex + mention.getDisplayName().length() + 1; // + 1 to include the @
- result = result.substring(0, startIndex) + "@" + mention.getPublicKey() + result.substring(endIndex);
- } catch (Exception exception) {
- Log.d("Loki", "Couldn't process mention due to error: " + exception.toString() + ".");
- }
- }
- return result;
- }
-
- private Pair> getSplitMessage(String rawText, int maxPrimaryMessageSize) {
- String bodyText = rawText;
- Optional textSlide = Optional.absent();
-
- if (bodyText.length() > maxPrimaryMessageSize) {
- bodyText = rawText.substring(0, maxPrimaryMessageSize);
-
- byte[] textData = rawText.getBytes();
- String timestamp = new SimpleDateFormat("yyyy-MM-dd-HHmmss", Locale.US).format(new Date());
- String filename = String.format("signal-%s.txt", timestamp);
- Uri textUri = BlobProvider.getInstance()
- .forData(textData)
- .withMimeType(MediaTypes.LONG_TEXT)
- .withFileName(filename)
- .createForSingleSessionInMemory();
-
- textSlide = Optional.of(new TextSlide(this, textUri, filename, textData.length));
- }
-
- return new Pair<>(bodyText, textSlide);
- }
-
- private void markThreadAsRead() {
- Recipient recipient = this.recipient;
- new AsyncTask() {
- @Override
- protected Void doInBackground(Long... params) {
- Context context = ConversationActivity.this;
- List messageIds = DatabaseFactory.getThreadDatabase(context).setRead(params[0], false);
-
- if (!SessionMetaProtocol.shouldSendReadReceipt(recipient.getAddress())) {
- for (MarkedMessageInfo messageInfo : messageIds) {
- MarkReadReceiver.scheduleDeletion(context, messageInfo.getExpirationInfo());
- }
- } else {
- MarkReadReceiver.process(context, messageIds);
- }
- ApplicationContext.getInstance(context).messageNotifier.updateNotification(context);
- return null;
- }
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, threadId);
- }
-
- private void markLastSeen() {
- new AsyncTask() {
- @Override
- protected Void doInBackground(Long... params) {
- DatabaseFactory.getThreadDatabase(ConversationActivity.this).setLastSeen(params[0]);
- return null;
- }
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, threadId);
- }
-
- protected void sendComplete(long threadId) {
- boolean refreshFragment = (threadId != this.threadId);
- this.threadId = threadId;
-
- if (fragment == null || !fragment.isVisible() || isFinishing()) {
- return;
- }
-
- fragment.setLastSeen(0);
-
- if (refreshFragment) {
- fragment.reload(recipient, threadId);
- ApplicationContext.getInstance(this).messageNotifier.setVisibleThread(threadId);
- }
-
- fragment.scrollToBottom();
- attachmentManager.cleanup();
-
- updateLinkPreviewState();
- }
-
- private void sendMessage() {
- if (inputPanel.isRecordingInLockedMode()) {
- inputPanel.releaseRecordingLock();
- return;
- }
-
- try {
- Recipient recipient = getRecipient();
-
- if (recipient == null) {
- throw new RecipientFormattingException("Badly formatted");
- }
-
- String message = getMessage();
- boolean initiating = threadId == -1;
- boolean needsSplit = message.length() > characterCalculator.calculateCharacters(message).maxPrimaryMessageSize;
- boolean isMediaMessage = false ||
-// recipient.isGroupRecipient() ||
- inputPanel.getQuote().isPresent() ||
- linkPreviewViewModel.hasLinkPreview() ||
- LinkPreviewUtil.isValidMediaUrl(message) || // Loki - Send GIFs as media messages
- needsSplit;
-
- if (isMediaMessage) {
- sendMediaMessage(initiating);
- } else {
- sendTextMessage(initiating);
- }
- } catch (RecipientFormattingException ex) {
- Log.w(TAG, ex);
- } catch (InvalidMessageException ex) {
- Log.w(TAG, ex);
- }
-
- if (messageStatus == null && !isGroupConversation() && !(TextSecurePreferences.getLocalNumber(this).equals(recipient.getAddress().serialize()))) {
- messageStatus = "calculatingPoW";
- updateSubtitleTextView();
- updateMessageStatusProgressBar();
- }
- }
-
- private void sendMediaMessage(boolean initiating)
- throws InvalidMessageException
- {
- Log.i(TAG, "Sending media message...");
- sendMediaMessage(getMessage(), attachmentManager.buildSlideDeck(), inputPanel.getQuote().orNull(), linkPreviewViewModel.getActiveLinkPreview(), initiating);
- }
-
- private ListenableFuture sendMediaMessage(String body,
- SlideDeck slideDeck,
- QuoteModel quote,
- Optional linkPreview,
- final boolean initiating)
- {
-
- Pair> splitMessage = getSplitMessage(body, characterCalculator.calculateCharacters(body).maxPrimaryMessageSize);
- body = splitMessage.first;
-
- if (splitMessage.second.isPresent()) {
- slideDeck.addSlide(splitMessage.second.get());
- }
-
- List attachments = slideDeck.asAttachments();
-
- VisibleMessage message = new VisibleMessage();
- message.setSentTimestamp(System.currentTimeMillis());
- message.setText(body);
- OutgoingMediaMessage outgoingMessageCandidate = OutgoingMediaMessage.from(message, recipient, attachments, quote, linkPreview.orNull());
-
- final SettableFuture future = new SettableFuture<>();
- final Context context = getApplicationContext();
-
- final OutgoingMediaMessage outgoingMessage;
-
- outgoingMessage = new OutgoingSecureMediaMessage(outgoingMessageCandidate);
- ApplicationContext.getInstance(context).getTypingStatusSender().onTypingStopped(threadId);
-
- inputPanel.clearQuote();
- attachmentManager.clear();
- silentlySetComposeText("");
-
- final long id = fragment.stageOutgoingMessage(outgoingMessage);
-
- if (initiating) {
- DatabaseFactory.getRecipientDatabase(context).setProfileSharing(recipient, true);
- }
-
- try {
- long allocatedThreadId = getAllocatedThreadId(context);
- message.setId(DatabaseFactory.getMmsDatabase(context).insertMessageOutbox(outgoingMessage, allocatedThreadId, false, ()->fragment.releaseOutgoingMessage(id)));
- MessageSender.send(message, recipient.getAddress(), attachments, quote, linkPreview.orNull());
- sendComplete(allocatedThreadId);
- } catch (MmsException e) {
- Log.w(TAG, e);
- sendComplete(threadId);
- }
- future.set(null);
-
- return future;
- }
-
- private void sendTextMessage(final boolean initiating)
- throws InvalidMessageException
- {
- final Context context = getApplicationContext();
- final String messageBody = getMessage();
-
- VisibleMessage message = new VisibleMessage();
- message.setSentTimestamp(System.currentTimeMillis());
- message.setText(messageBody);
- OutgoingTextMessage outgoingTextMessage = OutgoingTextMessage.from(message, recipient);
- ApplicationContext.getInstance(context).getTypingStatusSender().onTypingStopped(threadId);
-
- silentlySetComposeText("");
- final long id = fragment.stageOutgoingMessage(outgoingTextMessage);
-
- if (initiating) {
- DatabaseFactory.getRecipientDatabase(context).setProfileSharing(recipient, true);
- }
-
- long allocatedThreadId = getAllocatedThreadId(context);
- message.setId(DatabaseFactory.getSmsDatabase(context).insertMessageOutbox(allocatedThreadId, outgoingTextMessage, false, message.getSentTimestamp(), ()->fragment.releaseOutgoingMessage(id)));
- MessageSender.send(message, recipient.getAddress());
-
- sendComplete(allocatedThreadId);
- }
-
- private void sendOpenGroupInvitations(String[] contactIDs) {
- final Context context = getApplicationContext();
- OpenGroupV2 openGroup = DatabaseFactory.getLokiThreadDatabase(context).getOpenGroupChat(threadId);
- for (String contactID : contactIDs) {
- Recipient recipient = Recipient.from(context, Address.fromSerialized(contactID), true);
- VisibleMessage message = new VisibleMessage();
- message.setSentTimestamp(System.currentTimeMillis());
- OpenGroupInvitation openGroupInvitationMessage = new OpenGroupInvitation();
- openGroupInvitationMessage.setName(openGroup.getName());
- openGroupInvitationMessage.setUrl(openGroup.getJoinURL());
- message.setOpenGroupInvitation(openGroupInvitationMessage);
- OutgoingTextMessage outgoingTextMessage = OutgoingTextMessage.fromOpenGroupInvitation(openGroupInvitationMessage, recipient, message.getSentTimestamp());
- DatabaseFactory.getSmsDatabase(context).insertMessageOutbox(-1, outgoingTextMessage, message.getSentTimestamp());
- MessageSender.send(message, recipient.getAddress());
- }
- }
-
- private void updateToggleButtonState() {
- if (inputPanel.isRecordingInLockedMode()) {
- buttonToggle.display(sendButton);
- quickAttachmentToggle.show();
- inlineAttachmentToggle.hide();
- return;
- }
-
- if (composeText.getText().length() == 0) {
- buttonToggle.display(attachButton);
- quickAttachmentToggle.show();
- inlineAttachmentToggle.hide();
- } else {
- buttonToggle.display(sendButton);
- quickAttachmentToggle.hide();
-
- if (!linkPreviewViewModel.hasLinkPreview()) {
- inlineAttachmentToggle.show();
- } else {
- inlineAttachmentToggle.hide();
- }
- }
- }
-
- private void updateLinkPreviewState() {
- if (TextSecurePreferences.isLinkPreviewsEnabled(this)) {
- linkPreviewViewModel.onEnabled();
- linkPreviewViewModel.onTextChanged(this, composeText.getTextTrimmed(), composeText.getSelectionStart(), composeText.getSelectionEnd());
- } else {
- linkPreviewViewModel.onUserCancel();
- }
- }
-
- @Override
- public void onRecorderPermissionRequired() {
- Permissions.with(this)
- .request(Manifest.permission.RECORD_AUDIO)
- .withRationaleDialog(getString(R.string.ConversationActivity_to_send_audio_messages_allow_signal_access_to_your_microphone), R.drawable.ic_baseline_mic_48)
- .withPermanentDenialDialog(getString(R.string.ConversationActivity_signal_requires_the_microphone_permission_in_order_to_send_audio_messages))
- .execute();
- }
-
- @Override
- public void onRecorderStarted() {
- Vibrator vibrator = ServiceUtil.getVibrator(this);
- vibrator.vibrate(20);
-
- getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
-
- audioRecorder.startRecording();
-
- audioHandler = new Handler();
- stopRecordingTask = () -> inputPanel.onRecordReleased();
- audioHandler.postDelayed(stopRecordingTask, 60000);
- }
-
- @Override
- public void onRecorderLocked() {
- updateToggleButtonState();
- }
-
- @Override
- public void onRecorderFinished() {
- if (audioHandler != null && stopRecordingTask != null) {
- audioHandler.removeCallbacks(stopRecordingTask);
- }
- updateToggleButtonState();
- Vibrator vibrator = ServiceUtil.getVibrator(this);
- vibrator.vibrate(20);
-
- getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
-
- ListenableFuture> future = audioRecorder.stopRecording();
- future.addListener(new ListenableFuture.Listener>() {
- @Override
- public void onSuccess(final @NonNull Pair result) {
- int subscriptionId = -1;
- long expiresIn = recipient.getExpireMessages() * 1000L;
- boolean initiating = threadId == -1;
- AudioSlide audioSlide = new AudioSlide(ConversationActivity.this, result.first, result.second, MediaTypes.AUDIO_AAC, true);
- SlideDeck slideDeck = new SlideDeck();
- slideDeck.addSlide(audioSlide);
-
- sendMediaMessage("", slideDeck, inputPanel.getQuote().orNull(), Optional.absent(), initiating).addListener(new AssertedSuccessListener() {
- @Override
- public void onSuccess(Void nothing) {
- new AsyncTask() {
- @Override
- protected Void doInBackground(Void... params) {
- BlobProvider.getInstance().delete(ConversationActivity.this, result.first);
- return null;
- }
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- }
- });
- }
-
- @Override
- public void onFailure(ExecutionException e) {
- Toast.makeText(ConversationActivity.this, R.string.ConversationActivity_unable_to_record_audio, Toast.LENGTH_LONG).show();
- }
- });
- }
-
- @Override
- public void onRecorderCanceled() {
- if (audioHandler != null && stopRecordingTask != null) {
- audioHandler.removeCallbacks(stopRecordingTask);
- }
- updateToggleButtonState();
- Vibrator vibrator = ServiceUtil.getVibrator(this);
- vibrator.vibrate(50);
-
- getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
-
- ListenableFuture> future = audioRecorder.stopRecording();
- future.addListener(new ListenableFuture.Listener>() {
- @Override
- public void onSuccess(final Pair result) {
- new AsyncTask() {
- @Override
- protected Void doInBackground(Void... params) {
- BlobProvider.getInstance().delete(ConversationActivity.this, result.first);
- return null;
- }
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- }
-
- @Override
- public void onFailure(ExecutionException e) {}
- });
- }
-
- @Override
- public void onEmojiToggle() {
- if (!emojiDrawerStub.resolved()) {
- initializeMediaKeyboardProviders(emojiDrawerStub.get());
-
- inputPanel.setMediaKeyboard(emojiDrawerStub.get());
- }
-
- if (container.getCurrentInput() == emojiDrawerStub.get()) {
- container.showSoftkey(composeText);
- } else {
- container.show(composeText, emojiDrawerStub.get());
- }
- }
-
- @Override
- public void onLinkPreviewCanceled() {
- linkPreviewViewModel.onUserCancel();
- }
-
- @Override
- public void onMediaSelected(@NonNull Uri uri, String contentType) {
- if (!TextUtils.isEmpty(contentType) && contentType.trim().equals("image/gif")) {
- setMedia(uri, MediaType.GIF);
- } else if (MediaUtil.isImageType(contentType)) {
- setMedia(uri, MediaType.IMAGE);
- } else if (MediaUtil.isVideoType(contentType)) {
- setMedia(uri, MediaType.VIDEO);
- } else if (MediaUtil.isAudioType(contentType)) {
- setMedia(uri, MediaType.AUDIO);
- }
- }
-
- @Override
- public void onCursorPositionChanged(int start, int end) {
- linkPreviewViewModel.onTextChanged(this, composeText.getTextTrimmed(), start, end);
- }
-
- private void silentlySetComposeText(String text) {
- typingTextWatcher.setEnabled(false);
- composeText.setText(text);
- if (text.isEmpty()) { resetMentions(); }
- typingTextWatcher.setEnabled(true);
- }
-
- // Listeners
-
- private class AttachmentTypeListener implements AttachmentTypeSelector.AttachmentClickedListener {
- @Override
- public void onClick(int type) {
- addAttachment(type);
- }
-
- @Override
- public void onQuickAttachment(Uri uri, String mimeType, String bucketId, long dateTaken, int width, int height, long size) {
- linkPreviewViewModel.onUserCancel();
- Media media = new Media(uri, mimeType, dateTaken, width, height, size, Optional.of(Media.ALL_MEDIA_BUCKET_ID), Optional.absent());
- startActivityForResult(MediaSendActivity.buildEditorIntent(ConversationActivity.this, Collections.singletonList(media), recipient, composeText.getTextTrimmed()), MEDIA_SENDER);
- }
- }
-
- private class QuickCameraToggleListener implements OnClickListener {
- @Override
- public void onClick(View v) {
- Permissions.with(ConversationActivity.this)
- .request(Manifest.permission.CAMERA)
- .withRationaleDialog(getString(R.string.ConversationActivity_to_capture_photos_and_video_allow_signal_access_to_the_camera), R.drawable.ic_baseline_photo_camera_48)
- .withPermanentDenialDialog(getString(R.string.ConversationActivity_signal_needs_the_camera_permission_to_take_photos_or_video))
- .onAllGranted(() -> {
- composeText.clearFocus();
- startActivityForResult(MediaSendActivity.buildCameraIntent(ConversationActivity.this, recipient), MEDIA_SENDER);
- overridePendingTransition(R.anim.camera_slide_from_bottom, R.anim.stationary);
- })
- .onAnyDenied(() -> Toast.makeText(ConversationActivity.this, R.string.ConversationActivity_signal_needs_camera_permissions_to_take_photos_or_video, Toast.LENGTH_LONG).show())
- .execute();
- }
- }
-
- private class SendButtonListener implements OnClickListener, TextView.OnEditorActionListener {
- @Override
- public void onClick(View v) {
- sendMessage();
- }
-
- @Override
- public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
- if (actionId == EditorInfo.IME_ACTION_SEND) {
- sendButton.performClick();
- return true;
- }
- return false;
- }
- }
-
- private class AttachButtonListener implements OnClickListener {
- @Override
- public void onClick(View v) {
- handleAddAttachment();
- }
- }
-
- private class AttachButtonLongClickListener implements View.OnLongClickListener {
- @Override
- public boolean onLongClick(View v) {
- return sendButton.performLongClick();
- }
- }
-
- private class ComposeKeyPressedListener implements OnKeyListener, OnClickListener, TextWatcher, OnFocusChangeListener {
-
- int beforeLength;
-
- @Override
- public boolean onKey(View v, int keyCode, KeyEvent event) {
- if (event.getAction() == KeyEvent.ACTION_DOWN) {
- if (keyCode == KeyEvent.KEYCODE_ENTER) {
- if (TextSecurePreferences.isEnterSendsEnabled(ConversationActivity.this)) {
- sendButton.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER));
- sendButton.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER));
- return true;
- }
- }
- }
- return false;
- }
-
- @Override
- public void onClick(View v) {
- container.showSoftkey(composeText);
- }
-
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count,int after) {
- beforeLength = composeText.getTextTrimmed().length();
- }
-
- @Override
- public void afterTextChanged(Editable s) {
- if (composeText.getTextTrimmed().length() == 0 || beforeLength == 0) {
- composeText.postDelayed(ConversationActivity.this::updateToggleButtonState, 50);
- }
- }
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before,int count) {}
-
- @Override
- public void onFocusChange(View v, boolean hasFocus) {}
- }
-
- private class TypingStatusTextWatcher extends SimpleTextWatcher {
- private boolean enabled = true;
-
- @Override
- public void onTextChanged(String text) {
- if (enabled && threadId > 0) {
- ApplicationContext.getInstance(ConversationActivity.this).getTypingStatusSender().onTypingStarted(threadId);
- }
- }
-
- public void setEnabled(boolean enabled) {
- this.enabled = enabled;
- }
- }
-
- private class MentionTextWatcher extends SimpleTextWatcher {
-
- @Override
- public void onTextChanged(String text) {
- boolean isBackspace = text.length() < oldText.length();
- if (isBackspace) {
- currentMentionStartIndex = -1;
- mentionCandidateSelectionView.hide();
- mentionCandidateSelectionViewContainer.setVisibility(View.GONE);
- ArrayList mentionsToRemove = new ArrayList<>();
- for (Mention mention : mentions) {
- if (!text.contains(mention.getDisplayName())) {
- mentionsToRemove.add(mention);
- }
- }
- mentions.removeAll(mentionsToRemove);
- }
- if (text.length() > 0) {
- if (currentMentionStartIndex > text.length()) {
- resetMentions(); // Should never occur
- }
- int lastCharacterIndex = text.length() - 1;
- char lastCharacter = text.charAt(lastCharacterIndex);
- char secondToLastCharacter = ' ';
- if (lastCharacterIndex > 0) {
- secondToLastCharacter = text.charAt(lastCharacterIndex - 1);
- }
- if (lastCharacter == '@' && Character.isWhitespace(secondToLastCharacter)) {
- List mentionCandidates = MentionsManager.INSTANCE.getMentionCandidates("", threadId, recipient.isOpenGroupRecipient());
- currentMentionStartIndex = lastCharacterIndex;
- mentionCandidateSelectionViewContainer.setVisibility(View.VISIBLE);
- mentionCandidateSelectionView.show(mentionCandidates, threadId);
- } else if (Character.isWhitespace(lastCharacter)) {
- currentMentionStartIndex = -1;
- mentionCandidateSelectionView.hide();
- mentionCandidateSelectionViewContainer.setVisibility(View.GONE);
- } else {
- if (currentMentionStartIndex != -1) {
- String query = text.substring(currentMentionStartIndex + 1); // + 1 to get rid of the @
- List mentionCandidates = MentionsManager.INSTANCE.getMentionCandidates(query, threadId, recipient.isOpenGroupRecipient());
- mentionCandidateSelectionViewContainer.setVisibility(View.VISIBLE);
- mentionCandidateSelectionView.show(mentionCandidates, threadId);
- }
- }
- }
- ConversationActivity.this.oldText = text;
- }
- }
-
- private void resetMentions() {
- oldText = "";
- currentMentionStartIndex = -1;
- mentions.clear();
- }
-
- @Override
- public void setThreadId(long threadId) {
- this.threadId = threadId;
- }
-
- @Override
- public void handleReplyMessage(MessageRecord messageRecord) {
- if (recipient.isGroupRecipient() && !isActiveGroup()) { return; }
-
- Recipient author;
-
- if (messageRecord.isOutgoing()) {
- author = Recipient.from(this, Address.fromSerialized(TextSecurePreferences.getLocalNumber(this)), true);
- } else {
- author = messageRecord.getIndividualRecipient();
- }
-
- if (messageRecord.isMms() && !((MmsMessageRecord) messageRecord).getSharedContacts().isEmpty()) {
- Contact contact = ((MmsMessageRecord) messageRecord).getSharedContacts().get(0);
- String displayName = ContactUtil.getDisplayName(contact);
- String body = getString(R.string.ConversationActivity_quoted_contact_message, EmojiStrings.BUST_IN_SILHOUETTE, displayName);
- SlideDeck slideDeck = new SlideDeck();
-
- if (contact.getAvatarAttachment() != null) {
- slideDeck.addSlide(MediaUtil.getSlideForAttachment(this, contact.getAvatarAttachment()));
- }
-
- inputPanel.setQuote(GlideApp.with(this),
- messageRecord.getDateSent(),
- author,
- body,
- slideDeck,
- recipient,
- threadId);
-
- } else if (messageRecord.isMms() && !((MmsMessageRecord) messageRecord).getLinkPreviews().isEmpty()) {
- LinkPreview linkPreview = ((MmsMessageRecord) messageRecord).getLinkPreviews().get(0);
- SlideDeck slideDeck = new SlideDeck();
-
- if (linkPreview.getThumbnail().isPresent()) {
- slideDeck.addSlide(MediaUtil.getSlideForAttachment(this, linkPreview.getThumbnail().get()));
- }
-
- inputPanel.setQuote(GlideApp.with(this),
- messageRecord.getDateSent(),
- author,
- messageRecord.getBody(),
- slideDeck,
- recipient,
- threadId);
- } else {
- inputPanel.setQuote(GlideApp.with(this),
- messageRecord.getDateSent(),
- author,
- messageRecord.getBody(),
- messageRecord.isMms() ? ((MmsMessageRecord) messageRecord).getSlideDeck() : new SlideDeck(),
- recipient,
- threadId);
- }
- }
-
- @Override
- public void onMessageActionToolbarOpened() {
- searchViewItem.collapseActionView();
- }
-
- @Override
- public void onForwardClicked() {
- inputPanel.clearQuote();
- }
-
- @Override
- public void onAttachmentChanged() {
- handleSecurityChange(true, isDefaultSms);
- updateToggleButtonState();
- updateLinkPreviewState();
- }
-
- private class QuoteRestorationTask extends AsyncTask {
-
- private final String serialized;
- private final SettableFuture future;
-
- QuoteRestorationTask(@NonNull String serialized, @NonNull SettableFuture future) {
- this.serialized = serialized;
- this.future = future;
- }
-
- @Override
- protected MessageRecord doInBackground(Void... voids) {
- QuoteId quoteId = QuoteId.deserialize(serialized);
-
- if (quoteId != null) {
- return DatabaseFactory.getMmsSmsDatabase(getApplicationContext()).getMessageFor(quoteId.getId(), quoteId.getAuthor());
- }
-
- return null;
- }
-
- @Override
- protected void onPostExecute(MessageRecord messageRecord) {
- if (messageRecord != null) {
- handleReplyMessage(messageRecord);
- future.set(true);
- } else {
- Log.e(TAG, "Failed to restore a quote from a draft. No matching message record.");
- future.set(false);
- }
- }
- }
-
- // region Loki
- private long getAllocatedThreadId(Context context) {
- long allocatedThreadId;
- if (threadId == -1) {
- allocatedThreadId = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(recipient);
- } else {
- allocatedThreadId = threadId;
- }
- return allocatedThreadId;
- }
-
- private void updateTitleTextView(Recipient recipient) {
- String userPublicKey = TextSecurePreferences.getLocalNumber(this);
- if (recipient == null) {
- titleTextView.setText(R.string.ConversationActivity_compose);
- } else if (recipient.getAddress().toString().toLowerCase().equals(userPublicKey)) {
- titleTextView.setText(R.string.note_to_self);
- } else {
- String displayName = recipient.getName(); // Uses the Contact API internally
- boolean hasName = (displayName != null);
- titleTextView.setText(hasName ? displayName : recipient.getAddress().toString());
- }
- }
-
- private void updateProfilePicture() {
- try {
- profilePictureView.glide = GlideApp.with(this);
- profilePictureView.update(recipient, threadId);
- } catch (Exception exception) {
- // Do nothing
- }
- }
-
- private void updateSubtitleTextView() {
- muteIndicatorImageView.setVisibility(View.GONE);
- subtitleTextView.setVisibility(View.VISIBLE);
- if (recipient.isMuted()) {
- muteIndicatorImageView.setVisibility(View.VISIBLE);
- subtitleTextView.setText(getString(R.string.ConversationActivity_muted_until_date,DateUtils.getFormattedDateTime(recipient.mutedUntil, "EEE, MMM d, yyyy HH:mm", Locale.getDefault())));
- } else if (recipient.isGroupRecipient() && recipient.getName() != null && !recipient.getName().equals("Session Updates") && !recipient.getName().equals("Loki News")) {
- OpenGroupV2 openGroup = DatabaseFactory.getLokiThreadDatabase(this).getOpenGroupChat(threadId);
- if (openGroup != null) {
- Integer userCount = DatabaseFactory.getLokiAPIDatabase(this).getUserCount(openGroup.getRoom(),openGroup.getServer());
- if (userCount == null) { userCount = 0; }
- subtitleTextView.setText(getString(R.string.ConversationActivity_member_count,userCount));
- } else if (PublicKeyValidation.isValid(recipient.getAddress().toString())) {
- subtitleTextView.setText(recipient.getAddress().toString());
- } else {
- subtitleTextView.setVisibility(View.GONE);
- }
- } else {
- subtitleTextView.setVisibility(View.GONE);
- }
- titleTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, getResources().getDimension((subtitleTextView.getVisibility() == View.GONE) ? R.dimen.very_large_font_size : R.dimen.large_font_size));
- }
-
- private void setMessageStatusProgressAnimatedIfPossible(int progress) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- messageStatusProgressBar.setProgress(progress, true);
- } else {
- messageStatusProgressBar.setProgress(progress);
- }
- }
-
- private void updateMessageStatusProgressBar() {
- if (messageStatus != null) {
- messageStatusProgressBar.setAlpha(1.0f);
- switch (messageStatus) {
- case "calculatingPoW": setMessageStatusProgressAnimatedIfPossible(25); break;
- case "contactingNetwork": setMessageStatusProgressAnimatedIfPossible(50); break;
- case "sendingMessage": setMessageStatusProgressAnimatedIfPossible(75); break;
- case "messageSent":
- setMessageStatusProgressAnimatedIfPossible(100);
- new Handler().postDelayed(() -> messageStatusProgressBar.animate().alpha(0).setDuration(250).start(), 250);
- new Handler().postDelayed(() -> messageStatusProgressBar.setProgress(0), 500);
- break;
- case "messageFailed":
- messageStatusProgressBar.animate().alpha(0).setDuration(250).start();
- new Handler().postDelayed(() -> messageStatusProgressBar.setProgress(0), 250);
- break;
- }
- }
- }
-
- private void handleMessageStatusChanged(String newMessageStatus, long timestamp) {
- if (timestamp == 0 || (TextSecurePreferences.getLocalNumber(this).equals(recipient.getAddress().serialize())) ) { return; }
- updateForNewMessageStatusIfNeeded(newMessageStatus, timestamp);
- if (newMessageStatus.equals("messageFailed") || newMessageStatus.equals("messageSent")) {
- new Handler().postDelayed(() -> clearMessageStatusIfNeeded(timestamp), 1000);
- }
- }
-
- private int precedence(String messageStatus) {
- if (messageStatus != null) {
- switch (messageStatus) {
- case "calculatingPoW": return 0;
- case "contactingNetwork": return 1;
- case "sendingMessage": return 2;
- case "messageSent": return 3;
- case "messageFailed": return 4;
- default: return -1;
- }
- } else {
- return -1;
- }
- }
-
- private void updateForNewMessageStatusIfNeeded(String newMessageStatus, long timestamp) {
- if (!DatabaseFactory.getSmsDatabase(this).isOutgoingMessage(timestamp) && !DatabaseFactory.getMmsDatabase(this).isOutgoingMessage(timestamp)) { return; }
- if (precedence(newMessageStatus) > precedence(messageStatus)) {
- messageStatus = newMessageStatus;
- updateSubtitleTextView();
- updateMessageStatusProgressBar();
- }
- }
-
- private void clearMessageStatusIfNeeded(long timestamp) {
- if (!DatabaseFactory.getSmsDatabase(this).isOutgoingMessage(timestamp) && !DatabaseFactory.getMmsDatabase(this).isOutgoingMessage(timestamp)) { return; }
- messageStatus = null;
- updateSubtitleTextView();
- updateMessageStatusProgressBar();
- }
- // endregion
-}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationAdapter.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationAdapter.java
deleted file mode 100644
index 8c7522a3f0..0000000000
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationAdapter.java
+++ /dev/null
@@ -1,532 +0,0 @@
-/*
- * Copyright (C) 2011 Whisper Systems
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.thoughtcrime.securesms.conversation;
-
-import android.content.Context;
-import android.database.Cursor;
-import androidx.annotation.LayoutRes;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.VisibleForTesting;
-import androidx.recyclerview.widget.RecyclerView;
-
-import android.util.SparseArray;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.TextView;
-
-import com.annimon.stream.Stream;
-
-import org.thoughtcrime.securesms.BindableConversationItem;
-import org.thoughtcrime.securesms.conversation.ConversationAdapter.HeaderViewHolder;
-import org.thoughtcrime.securesms.database.DatabaseFactory;
-import org.thoughtcrime.securesms.database.FastCursorRecyclerViewAdapter;
-import org.thoughtcrime.securesms.database.MmsSmsColumns;
-import org.thoughtcrime.securesms.database.MmsSmsDatabase;
-import org.thoughtcrime.securesms.database.model.MessageRecord;
-import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
-import org.session.libsignal.utilities.Log;
-import org.thoughtcrime.securesms.mms.GlideRequests;
-import org.thoughtcrime.securesms.mms.SlideDeck;
-import org.session.libsession.utilities.recipients.Recipient;
-import org.thoughtcrime.securesms.util.DateUtils;
-import org.thoughtcrime.securesms.util.LRUCache;
-import org.thoughtcrime.securesms.util.StickyHeaderDecoration;
-import org.session.libsignal.utilities.guava.Optional;
-
-import org.session.libsession.messaging.sending_receiving.attachments.DatabaseAttachment;
-import org.session.libsession.utilities.Conversions;
-import org.session.libsession.utilities.ViewUtil;
-import org.session.libsession.utilities.Util;
-
-import java.lang.ref.SoftReference;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.Calendar;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-
-import network.loki.messenger.R;
-
-/**
- * A cursor adapter for a conversation thread. Ultimately
- * used by ComposeMessageActivity to display a conversation
- * thread in a ListActivity.
- *
- * @author Moxie Marlinspike
- *
- */
-public class ConversationAdapter
- extends FastCursorRecyclerViewAdapter
- implements StickyHeaderDecoration.StickyHeaderAdapter
-{
-
- private static final int MAX_CACHE_SIZE = 1000;
- private static final String TAG = ConversationAdapter.class.getSimpleName();
- private final Map> messageRecordCache =
- Collections.synchronizedMap(new LRUCache>(MAX_CACHE_SIZE));
- private final SparseArray positionToCacheRef = new SparseArray<>();
-
- private static final int MESSAGE_TYPE_OUTGOING = 0;
- private static final int MESSAGE_TYPE_INCOMING = 1;
- private static final int MESSAGE_TYPE_UPDATE = 2;
- private static final int MESSAGE_TYPE_AUDIO_OUTGOING = 3;
- private static final int MESSAGE_TYPE_AUDIO_INCOMING = 4;
- private static final int MESSAGE_TYPE_THUMBNAIL_OUTGOING = 5;
- private static final int MESSAGE_TYPE_THUMBNAIL_INCOMING = 6;
- private static final int MESSAGE_TYPE_DOCUMENT_OUTGOING = 7;
- private static final int MESSAGE_TYPE_DOCUMENT_INCOMING = 8;
- private static final int MESSAGE_TYPE_INVITATION_OUTGOING = 9;
- private static final int MESSAGE_TYPE_INVITATION_INCOMING = 10;
-
- private final Set batchSelected = Collections.synchronizedSet(new HashSet());
-
- private final @Nullable ItemClickListener clickListener;
- private final @NonNull
- GlideRequests glideRequests;
- private final @NonNull Locale locale;
- private final @NonNull Recipient recipient;
- private final @NonNull MmsSmsDatabase db;
- private final @NonNull LayoutInflater inflater;
- private final @NonNull Calendar calendar;
- private final @NonNull MessageDigest digest;
-
- private MessageRecord recordToPulseHighlight;
- private String searchQuery;
-
- protected static class ViewHolder extends RecyclerView.ViewHolder {
- public ViewHolder(final @NonNull V itemView) {
- super(itemView);
- }
-
- @SuppressWarnings("unchecked")
- public V getView() {
- return (V)itemView;
- }
- }
-
-
- static class HeaderViewHolder extends RecyclerView.ViewHolder {
- TextView textView;
-
- HeaderViewHolder(View itemView) {
- super(itemView);
- textView = ViewUtil.findById(itemView, R.id.text);
- }
-
- HeaderViewHolder(TextView textView) {
- super(textView);
- this.textView = textView;
- }
-
- public void setText(CharSequence text) {
- textView.setText(text);
- }
- }
-
-
- interface ItemClickListener extends BindableConversationItem.EventListener {
- void onItemClick(MessageRecord item);
- void onItemLongClick(MessageRecord item);
- }
-
- @SuppressWarnings("ConstantConditions")
- @VisibleForTesting
- ConversationAdapter(Context context, Cursor cursor) {
- super(context, cursor);
- try {
- this.glideRequests = null;
- this.locale = null;
- this.clickListener = null;
- this.recipient = null;
- this.inflater = null;
- this.db = null;
- this.calendar = null;
- this.digest = MessageDigest.getInstance("SHA1");
- } catch (NoSuchAlgorithmException nsae) {
- throw new AssertionError("SHA1 isn't supported!");
- }
- }
-
- public ConversationAdapter(@NonNull Context context,
- @NonNull GlideRequests glideRequests,
- @NonNull Locale locale,
- @Nullable ItemClickListener clickListener,
- @Nullable Cursor cursor,
- @NonNull Recipient recipient)
- {
- super(context, cursor);
-
- try {
- this.glideRequests = glideRequests;
- this.locale = locale;
- this.clickListener = clickListener;
- this.recipient = recipient;
- this.inflater = LayoutInflater.from(context);
- this.db = DatabaseFactory.getMmsSmsDatabase(context);
- this.calendar = Calendar.getInstance();
- this.digest = MessageDigest.getInstance("SHA1");
-
- setHasStableIds(true);
- } catch (NoSuchAlgorithmException nsae) {
- throw new AssertionError("SHA1 isn't supported!");
- }
- }
-
- @Override
- public void changeCursor(Cursor cursor) {
- messageRecordCache.clear();
- positionToCacheRef.clear();
- super.cleanFastRecords();
- super.changeCursor(cursor);
- }
-
- @Override
- protected void onBindItemViewHolder(ViewHolder viewHolder, @NonNull MessageRecord messageRecord) {
- int adapterPosition = viewHolder.getAdapterPosition();
-
- String prevCachedId = positionToCacheRef.get(adapterPosition + 1,null);
- String nextCachedId = positionToCacheRef.get(adapterPosition - 1, null);
-
- MessageRecord previousRecord = null;
- if (adapterPosition < getItemCount() - 1 && !isFooterPosition(adapterPosition + 1)) {
- if (prevCachedId != null && messageRecordCache.containsKey(prevCachedId)) {
- SoftReference prevSoftRecord = messageRecordCache.get(prevCachedId);
- MessageRecord prevCachedRecord = prevSoftRecord.get();
- if (prevCachedRecord != null) {
- previousRecord = prevCachedRecord;
- } else {
- previousRecord = getRecordForPositionOrThrow(adapterPosition + 1);
- }
- } else {
- previousRecord = getRecordForPositionOrThrow(adapterPosition + 1);
- }
- }
-
- MessageRecord nextRecord = null;
- if (adapterPosition > 0 && !isHeaderPosition(adapterPosition - 1)) {
- if (nextCachedId != null && messageRecordCache.containsKey(nextCachedId)) {
- SoftReference nextSoftRecord = messageRecordCache.get(nextCachedId);
- MessageRecord nextCachedRecord = nextSoftRecord.get();
- if (nextCachedRecord != null) {
- nextRecord = nextCachedRecord;
- } else {
- nextRecord = getRecordForPositionOrThrow(adapterPosition - 1);
- }
- } else {
- nextRecord = getRecordForPositionOrThrow(adapterPosition - 1);
- }
- }
-
- viewHolder.getView().bind(messageRecord,
- Optional.fromNullable(previousRecord),
- Optional.fromNullable(nextRecord),
- glideRequests,
- locale,
- batchSelected,
- recipient,
- searchQuery,
- messageRecord == recordToPulseHighlight);
-
- if (messageRecord == recordToPulseHighlight) {
- recordToPulseHighlight = null;
- }
- }
-
- @Override
- public ViewHolder onCreateItemViewHolder(ViewGroup parent, int viewType) {
- long start = System.currentTimeMillis();
- final V itemView = ViewUtil.inflate(inflater, parent, getLayoutForViewType(viewType));
- itemView.setOnClickListener(view -> {
- if (clickListener != null) {
- clickListener.onItemClick(itemView.getMessageRecord());
- }
- });
- itemView.setOnLongClickListener(view -> {
- if (clickListener != null) {
- clickListener.onItemLongClick(itemView.getMessageRecord());
- }
- return true;
- });
- itemView.setEventListener(clickListener);
- Log.d(TAG, "Inflate time: " + (System.currentTimeMillis() - start));
- return new ViewHolder(itemView);
- }
-
- @Override
- public void onItemViewRecycled(ViewHolder holder) {
- holder.getView().unbind();
- }
-
- private @LayoutRes int getLayoutForViewType(int viewType) {
- switch (viewType) {
- case MESSAGE_TYPE_AUDIO_OUTGOING:
- case MESSAGE_TYPE_THUMBNAIL_OUTGOING:
- case MESSAGE_TYPE_DOCUMENT_OUTGOING:
- case MESSAGE_TYPE_INVITATION_OUTGOING:
- case MESSAGE_TYPE_OUTGOING: return R.layout.conversation_item_sent;
- case MESSAGE_TYPE_AUDIO_INCOMING:
- case MESSAGE_TYPE_THUMBNAIL_INCOMING:
- case MESSAGE_TYPE_DOCUMENT_INCOMING:
- case MESSAGE_TYPE_INVITATION_INCOMING:
- case MESSAGE_TYPE_INCOMING: return R.layout.conversation_item_received;
- case MESSAGE_TYPE_UPDATE: return R.layout.conversation_item_update;
- default: throw new IllegalArgumentException("unsupported item view type given to ConversationAdapter");
- }
- }
-
- @Override
- public int getItemViewType(@NonNull MessageRecord messageRecord) {
- if (messageRecord.isUpdate()) {
- return MESSAGE_TYPE_UPDATE;
- } else if (messageRecord.isOpenGroupInvitation()) {
- if (messageRecord.isOutgoing()) return MESSAGE_TYPE_INVITATION_OUTGOING;
- else return MESSAGE_TYPE_INVITATION_INCOMING;
- } else if (hasAudio(messageRecord)) {
- if (messageRecord.isOutgoing()) return MESSAGE_TYPE_AUDIO_OUTGOING;
- else return MESSAGE_TYPE_AUDIO_INCOMING;
- } else if (hasDocument(messageRecord)) {
- if (messageRecord.isOutgoing()) return MESSAGE_TYPE_DOCUMENT_OUTGOING;
- else return MESSAGE_TYPE_DOCUMENT_INCOMING;
- } else if (hasThumbnail(messageRecord)) {
- if (messageRecord.isOutgoing()) return MESSAGE_TYPE_THUMBNAIL_OUTGOING;
- else return MESSAGE_TYPE_THUMBNAIL_INCOMING;
- } else if (messageRecord.isOutgoing()) {
- return MESSAGE_TYPE_OUTGOING;
- } else {
- return MESSAGE_TYPE_INCOMING;
- }
- }
-
- @Override
- protected boolean isRecordForId(@NonNull MessageRecord record, long id) {
- return record.getId() == id;
- }
-
- @Override
- public long getItemId(@NonNull Cursor cursor) {
- List attachments = DatabaseFactory.getAttachmentDatabase(getContext()).getAttachment(cursor);
- List messageAttachments = Stream.of(attachments).filterNot(DatabaseAttachment::isQuote).toList();
-
- if (messageAttachments.size() > 0 && messageAttachments.get(0).getFastPreflightId() != null) {
- return Long.valueOf(messageAttachments.get(0).getFastPreflightId());
- }
-
- final String unique = cursor.getString(cursor.getColumnIndexOrThrow(MmsSmsColumns.UNIQUE_ROW_ID));
- final byte[] bytes = digest.digest(unique.getBytes());
- return Conversions.byteArrayToLong(bytes);
- }
-
- @Override
- protected long getItemId(@NonNull MessageRecord record) {
- if (record.isOutgoing() && record.isMms()) {
- MmsMessageRecord mmsRecord = (MmsMessageRecord) record;
- SlideDeck slideDeck = mmsRecord.getSlideDeck();
-
- if (slideDeck.getThumbnailSlide() != null && slideDeck.getThumbnailSlide().getFastPreflightId() != null) {
- return Long.valueOf(slideDeck.getThumbnailSlide().getFastPreflightId());
- }
- }
-
- return record.getId();
- }
-
- @Override
- protected MessageRecord getRecordFromCursor(@NonNull Cursor cursor) {
- long messageId = cursor.getLong(cursor.getColumnIndexOrThrow(MmsSmsColumns.ID));
- String type = cursor.getString(cursor.getColumnIndexOrThrow(MmsSmsDatabase.TRANSPORT));
-
- final SoftReference reference = messageRecordCache.get(type + messageId);
- if (reference != null) {
- final MessageRecord record = reference.get();
- if (record != null) return record;
- }
-
- final MessageRecord messageRecord = db.readerFor(cursor).getCurrent();
- messageRecordCache.put(type + messageId, new SoftReference<>(messageRecord));
-
- return messageRecord;
- }
-
- public void close() {
- getCursor().close();
- }
-
- public int findLastSeenPosition(long lastSeen) {
- if (lastSeen <= 0) return -1;
- if (!isActiveCursor()) return -1;
-
- int count = getItemCount() - (hasFooterView() ? 1 : 0);
-
- for (int i=(hasHeaderView() ? 1 : 0);i getSelectedItems() {
- return Collections.unmodifiableSet(new HashSet<>(batchSelected));
- }
-
- public void pulseHighlightItem(int position) {
- if (position < getItemCount()) {
- recordToPulseHighlight = getRecordForPositionOrThrow(position);
- notifyItemChanged(position);
- }
- }
-
- public void onSearchQueryUpdated(@Nullable String query) {
- this.searchQuery = query;
- notifyDataSetChanged();
- }
-
- private boolean hasAudio(MessageRecord messageRecord) {
- return messageRecord.isMms() && ((MmsMessageRecord)messageRecord).getSlideDeck().getAudioSlide() != null;
- }
-
- private boolean hasDocument(MessageRecord messageRecord) {
- return messageRecord.isMms() && ((MmsMessageRecord)messageRecord).getSlideDeck().getDocumentSlide() != null;
- }
-
- private boolean hasThumbnail(MessageRecord messageRecord) {
- return messageRecord.isMms() && ((MmsMessageRecord)messageRecord).getSlideDeck().getThumbnailSlide() != null;
- }
-
- @Override
- public long getHeaderId(int position) {
- if (!isActiveCursor()) return -1;
- if (isHeaderPosition(position)) return -1;
- if (isFooterPosition(position)) return -1;
- if (position >= getItemCount()) return -1;
- if (position < 0) return -1;
-
- MessageRecord record = getRecordForPositionOrThrow(position);
- if (record.getRecipient().getAddress().isOpenGroup()) {
- calendar.setTime(new Date(record.getDateReceived()));
- } else {
- calendar.setTime(new Date(record.getDateSent()));
- }
- return Util.hashCode(calendar.get(Calendar.YEAR), calendar.get(Calendar.DAY_OF_YEAR));
- }
-
- public long getReceivedTimestamp(int position) {
- if (!isActiveCursor()) return 0;
- if (isHeaderPosition(position)) return 0;
- if (isFooterPosition(position)) return 0;
- if (position >= getItemCount()) return 0;
- if (position < 0) return 0;
-
- MessageRecord messageRecord = getRecordForPositionOrThrow(position);
-
- if (messageRecord.isOutgoing()) return 0;
- else return messageRecord.getDateReceived();
- }
-
- @Override
- public HeaderViewHolder onCreateHeaderViewHolder(ViewGroup parent) {
- return new HeaderViewHolder(LayoutInflater.from(getContext()).inflate(R.layout.conversation_item_header, parent, false));
- }
-
- public HeaderViewHolder onCreateLastSeenViewHolder(ViewGroup parent) {
- return new HeaderViewHolder(LayoutInflater.from(getContext()).inflate(R.layout.conversation_item_last_seen, parent, false));
- }
-
- @Override
- public void onBindHeaderViewHolder(HeaderViewHolder viewHolder, int position) {
- MessageRecord messageRecord = getRecordForPositionOrThrow(position);
- long timestamp = messageRecord.getDateReceived();
- if (recipient.getAddress().isOpenGroup()) { timestamp = messageRecord.getTimestamp(); }
- viewHolder.setText(DateUtils.getRelativeDate(getContext(), locale, timestamp));
- }
-
- public void onBindLastSeenViewHolder(HeaderViewHolder viewHolder, int position) {
- viewHolder.setText(getContext().getResources().getQuantityString(R.plurals.ConversationAdapter_n_unread_messages, (position + 1), (position + 1)));
- }
-
- static class LastSeenHeader extends StickyHeaderDecoration {
-
- private final ConversationAdapter adapter;
- private final long lastSeenTimestamp;
-
- LastSeenHeader(ConversationAdapter adapter, long lastSeenTimestamp) {
- super(adapter, false, false);
- this.adapter = adapter;
- this.lastSeenTimestamp = lastSeenTimestamp;
- }
-
- @Override
- protected boolean hasHeader(RecyclerView parent, StickyHeaderAdapter stickyAdapter, int position) {
- if (!adapter.isActiveCursor()) {
- return false;
- }
-
- if (lastSeenTimestamp <= 0) {
- return false;
- }
-
- long currentRecordTimestamp = adapter.getReceivedTimestamp(position);
- long previousRecordTimestamp = adapter.getReceivedTimestamp(position + 1);
-
- return currentRecordTimestamp > lastSeenTimestamp && previousRecordTimestamp < lastSeenTimestamp;
- }
-
- @Override
- protected int getHeaderTop(RecyclerView parent, View child, View header, int adapterPos, int layoutPos) {
- return parent.getLayoutManager().getDecoratedTop(child);
- }
-
- @Override
- protected HeaderViewHolder getHeader(RecyclerView parent, StickyHeaderAdapter stickyAdapter, int position) {
- HeaderViewHolder viewHolder = adapter.onCreateLastSeenViewHolder(parent);
- adapter.onBindLastSeenViewHolder(viewHolder, position);
-
- int widthSpec = View.MeasureSpec.makeMeasureSpec(parent.getWidth(), View.MeasureSpec.EXACTLY);
- int heightSpec = View.MeasureSpec.makeMeasureSpec(parent.getHeight(), View.MeasureSpec.UNSPECIFIED);
-
- int childWidth = ViewGroup.getChildMeasureSpec(widthSpec, parent.getPaddingLeft() + parent.getPaddingRight(), viewHolder.itemView.getLayoutParams().width);
- int childHeight = ViewGroup.getChildMeasureSpec(heightSpec, parent.getPaddingTop() + parent.getPaddingBottom(), viewHolder.itemView.getLayoutParams().height);
-
- viewHolder.itemView.measure(childWidth, childHeight);
- viewHolder.itemView.layout(0, 0, viewHolder.itemView.getMeasuredWidth(), viewHolder.itemView.getMeasuredHeight());
-
- return viewHolder;
- }
- }
-
-}
-
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java
deleted file mode 100644
index 74a3b5eddb..0000000000
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java
+++ /dev/null
@@ -1,1220 +0,0 @@
-/*
- * Copyright (C) 2015 Open Whisper Systems
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.thoughtcrime.securesms.conversation;
-
-import android.annotation.SuppressLint;
-import android.app.Activity;
-import android.content.ClipData;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Build;
-import android.os.Bundle;
-import android.text.ClipboardManager;
-import android.text.TextUtils;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewParent;
-import android.view.Window;
-import android.view.animation.Animation;
-import android.view.animation.AnimationUtils;
-import android.widget.TextView;
-import android.widget.Toast;
-import android.widget.ViewSwitcher;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.appcompat.app.AlertDialog;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.appcompat.view.ActionMode;
-import androidx.fragment.app.Fragment;
-import androidx.loader.app.LoaderManager;
-import androidx.loader.content.Loader;
-import androidx.recyclerview.widget.LinearLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
-import androidx.recyclerview.widget.RecyclerView.OnScrollListener;
-import com.annimon.stream.Stream;
-import org.session.libsession.messaging.MessagingModuleConfiguration;
-import org.session.libsession.messaging.messages.control.DataExtractionNotification;
-import org.session.libsession.messaging.messages.signal.OutgoingMediaMessage;
-import org.session.libsession.messaging.messages.signal.OutgoingTextMessage;
-import org.session.libsession.messaging.messages.visible.Quote;
-import org.session.libsession.messaging.messages.visible.VisibleMessage;
-import org.session.libsession.messaging.open_groups.OpenGroupAPIV2;
-import org.session.libsession.messaging.open_groups.OpenGroupV2;
-import org.session.libsession.messaging.sending_receiving.MessageSender;
-import org.session.libsession.messaging.sending_receiving.attachments.Attachment;
-import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview;
-import org.session.libsession.utilities.Address;
-import org.session.libsession.utilities.recipients.Recipient;
-import org.session.libsession.utilities.TextSecurePreferences;
-import org.session.libsession.utilities.Util;
-import org.session.libsession.utilities.ViewUtil;
-import org.session.libsession.utilities.concurrent.SimpleTask;
-import org.session.libsession.utilities.task.ProgressDialogAsyncTask;
-import org.session.libsignal.utilities.guava.Optional;
-import org.session.libsignal.utilities.Log;
-import org.thoughtcrime.securesms.ApplicationContext;
-import org.thoughtcrime.securesms.MessageDetailsActivity;
-import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity;
-import org.thoughtcrime.securesms.ShareActivity;
-import org.thoughtcrime.securesms.components.ConversationTypingView;
-import org.thoughtcrime.securesms.components.recyclerview.SmoothScrollingLinearLayoutManager;
-import org.thoughtcrime.securesms.conversation.ConversationAdapter.HeaderViewHolder;
-import org.thoughtcrime.securesms.conversation.ConversationAdapter.ItemClickListener;
-import org.thoughtcrime.securesms.database.DatabaseFactory;
-import org.thoughtcrime.securesms.database.MmsSmsDatabase;
-import org.thoughtcrime.securesms.database.loaders.ConversationLoader;
-import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord;
-import org.thoughtcrime.securesms.database.model.MessageRecord;
-import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
-import org.thoughtcrime.securesms.longmessage.LongMessageActivity;
-import org.thoughtcrime.securesms.mediasend.Media;
-import org.thoughtcrime.securesms.mms.GlideApp;
-import org.thoughtcrime.securesms.mms.PartAuthority;
-import org.thoughtcrime.securesms.mms.Slide;
-import org.thoughtcrime.securesms.permissions.Permissions;
-import org.thoughtcrime.securesms.util.CommunicationActions;
-import org.thoughtcrime.securesms.util.SaveAttachmentTask;
-import org.thoughtcrime.securesms.util.StickyHeaderDecoration;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Locale;
-import java.util.Set;
-
-import kotlin.Unit;
-import network.loki.messenger.R;
-
-@SuppressLint("StaticFieldLeak")
-public class ConversationFragment extends Fragment
- implements LoaderManager.LoaderCallbacks
-{
- private static final String TAG = ConversationFragment.class.getSimpleName();
- private static final String KEY_LIMIT = "limit";
-
- private static final int PARTIAL_CONVERSATION_LIMIT = 500;
- private static final int SCROLL_ANIMATION_THRESHOLD = 50;
- private static final int CODE_ADD_EDIT_CONTACT = 77;
-
- private final ActionModeCallback actionModeCallback = new ActionModeCallback();
- private final ItemClickListener selectionClickListener = new ConversationFragmentItemClickListener();
-
- private ConversationFragmentListener listener;
-
- private Recipient recipient;
- private long threadId;
- private long lastSeen;
- private int startingPosition;
- private int previousOffset;
- private int activeOffset;
- private boolean firstLoad;
- private long loaderStartTime;
- private ActionMode actionMode;
- private Locale locale;
- private RecyclerView list;
- private RecyclerView.ItemDecoration lastSeenDecoration;
- private ViewSwitcher topLoadMoreView;
- private ViewSwitcher bottomLoadMoreView;
- private ConversationTypingView typingView;
- private View composeDivider;
- private View scrollToBottomButton;
- private TextView scrollDateHeader;
-
- @Override
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
- this.locale = (Locale) getArguments().getSerializable(PassphraseRequiredActionBarActivity.LOCALE_EXTRA);
- }
-
- @Override
- public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle bundle) {
- final View view = inflater.inflate(R.layout.conversation_fragment, container, false);
- list = ViewUtil.findById(view, android.R.id.list);
- composeDivider = ViewUtil.findById(view, R.id.compose_divider);
- scrollToBottomButton = ViewUtil.findById(view, R.id.scroll_to_bottom_button);
- scrollDateHeader = ViewUtil.findById(view, R.id.scroll_date_header);
-
- scrollToBottomButton.setOnClickListener(v -> scrollToBottom());
-
- final LinearLayoutManager layoutManager = new SmoothScrollingLinearLayoutManager(getActivity(), true);
- list.setHasFixedSize(false);
- list.setLayoutManager(layoutManager);
- list.setItemAnimator(null);
-
- topLoadMoreView = (ViewSwitcher) inflater.inflate(R.layout.load_more_header, container, false);
- bottomLoadMoreView = (ViewSwitcher) inflater.inflate(R.layout.load_more_header, container, false);
- initializeLoadMoreView(topLoadMoreView);
- initializeLoadMoreView(bottomLoadMoreView);
-
- typingView = (ConversationTypingView) inflater.inflate(R.layout.conversation_typing_view, container, false);
-
- return view;
- }
-
- @Override
- public void onActivityCreated(Bundle bundle) {
- super.onActivityCreated(bundle);
-
- initializeResources();
- initializeListAdapter();
- }
-
- @Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
- this.listener = (ConversationFragmentListener)activity;
- }
-
- @Override
- public void onStart() {
- super.onStart();
- initializeTypingObserver();
- }
-
- @Override
- public void onResume() {
- super.onResume();
-
- if (list.getAdapter() != null) {
- list.getAdapter().notifyDataSetChanged();
- }
- }
-
- @Override
- public void onStop() {
- super.onStop();
- ApplicationContext.getInstance(requireContext()).getTypingStatusRepository().getTypists(threadId).removeObservers(this);
- }
-
- public void onNewIntent() {
- if (actionMode != null) {
- actionMode.finish();
- }
-
- initializeResources();
- initializeListAdapter();
-
- if (threadId == -1) {
- getLoaderManager().restartLoader(0, Bundle.EMPTY, this);
- }
- }
-
- public void reloadList() {
- getLoaderManager().restartLoader(0, Bundle.EMPTY, this);
- }
-
- public void moveToLastSeen() {
- if (lastSeen <= 0) {
- Log.i(TAG, "No need to move to last seen.");
- return;
- }
-
- if (list == null || getListAdapter() == null) {
- Log.w(TAG, "Tried to move to last seen position, but we hadn't initialized the view yet.");
- return;
- }
-
- int position = getListAdapter().findLastSeenPosition(lastSeen);
- scrollToLastSeenPosition(position);
- }
-
- private void initializeResources() {
- this.recipient = Recipient.from(getActivity(), getActivity().getIntent().getParcelableExtra(ConversationActivity.ADDRESS_EXTRA), true);
- this.threadId = this.getActivity().getIntent().getLongExtra(ConversationActivity.THREAD_ID_EXTRA, -1);
- this.lastSeen = this.getActivity().getIntent().getLongExtra(ConversationActivity.LAST_SEEN_EXTRA, -1);
- this.startingPosition = this.getActivity().getIntent().getIntExtra(ConversationActivity.STARTING_POSITION_EXTRA, -1);
- this.firstLoad = true;
-
- OnScrollListener scrollListener = new ConversationScrollListener(getActivity());
- list.addOnScrollListener(scrollListener);
- }
-
- private void initializeListAdapter() {
- if (this.recipient != null && this.threadId != -1) {
- ConversationAdapter adapter = new ConversationAdapter(getActivity(), GlideApp.with(this), locale, selectionClickListener, null, this.recipient);
- list.setAdapter(adapter);
- list.addItemDecoration(new StickyHeaderDecoration(adapter, false, false));
-
- setLastSeen(lastSeen);
- getLoaderManager().restartLoader(0, Bundle.EMPTY, this);
- }
- }
-
- private void initializeLoadMoreView(ViewSwitcher loadMoreView) {
- loadMoreView.setOnClickListener(v -> {
- Bundle args = new Bundle();
- args.putInt(KEY_LIMIT, 0);
- getLoaderManager().restartLoader(0, args, ConversationFragment.this);
- loadMoreView.showNext();
- loadMoreView.setOnClickListener(null);
- });
- }
-
- private void initializeTypingObserver() {
- if (!TextSecurePreferences.isTypingIndicatorsEnabled(requireContext())) {
- return;
- }
-
- ApplicationContext.getInstance(requireContext()).getTypingStatusRepository().getTypists(threadId).observe(this, typingState -> {
- List recipients;
- boolean replacedByIncomingMessage;
-
- if (typingState != null) {
- recipients = typingState.getTypists();
- replacedByIncomingMessage = typingState.isReplacedByIncomingMessage();
- } else {
- recipients = Collections.emptyList();
- replacedByIncomingMessage = false;
- }
-
- typingView.setTypists(GlideApp.with(ConversationFragment.this), recipients, recipient.isGroupRecipient());
-
- ConversationAdapter adapter = getListAdapter();
-
- if (adapter.getHeaderView() != null && adapter.getHeaderView() != typingView) {
- Log.i(TAG, "Skipping typing indicator -- the header slot is occupied.");
- return;
- }
-
- if (recipients.size() > 0) {
- if (adapter.getHeaderView() == null && isAtBottom()) {
- list.setVerticalScrollBarEnabled(false);
- list.post(() -> getListLayoutManager().smoothScrollToPosition(requireContext(), 0, 250));
- list.postDelayed(() -> list.setVerticalScrollBarEnabled(true), 300);
- adapter.setHeaderView(typingView);
- adapter.notifyItemInserted(0);
- } else {
- if (adapter.getHeaderView() == null) {
- adapter.setHeaderView(typingView);
- adapter.notifyItemInserted(0);
- } else {
- adapter.setHeaderView(typingView);
- adapter.notifyItemChanged(0);
- }
- }
- } else {
- if (getListLayoutManager().findFirstCompletelyVisibleItemPosition() == 0 && getListLayoutManager().getItemCount() > 1 && !replacedByIncomingMessage) {
- getListLayoutManager().smoothScrollToPosition(requireContext(), 1, 250);
- list.setVerticalScrollBarEnabled(false);
- list.postDelayed(() -> {
- adapter.setHeaderView(null);
- adapter.notifyItemRemoved(0);
- list.post(() -> list.setVerticalScrollBarEnabled(true));
- }, 200);
- } else if (!replacedByIncomingMessage) {
- adapter.setHeaderView(null);
- adapter.notifyItemRemoved(0);
- } else {
- adapter.setHeaderView(null);
- }
- }
- });
- }
-
- private void setCorrectMenuVisibility(Menu menu) {
- Set messageRecords = getListAdapter().getSelectedItems();
- boolean actionMessage = false;
- boolean hasText = false;
- boolean sharedContact = false;
-
- if (actionMode != null && messageRecords.size() == 0) {
- actionMode.finish();
- return;
- }
-
- for (MessageRecord messageRecord : messageRecords) {
- if (messageRecord.isCallLog() || messageRecord.isExpirationTimerUpdate())
- {
- actionMessage = true;
- }
-
- if (messageRecord.getBody().length() > 0) {
- hasText = true;
- }
-
- if (messageRecord.isMms() && !((MmsMessageRecord) messageRecord).getSharedContacts().isEmpty()) {
- sharedContact = true;
- }
- }
-
- if (messageRecords.size() > 1) {
- menu.findItem(R.id.menu_context_details).setVisible(false);
- menu.findItem(R.id.menu_context_reply).setVisible(false);
- menu.findItem(R.id.menu_context_save_attachment).setVisible(false);
- menu.findItem(R.id.menu_context_resend).setVisible(false);
- } else {
- MessageRecord messageRecord = messageRecords.iterator().next();
-
- menu.findItem(R.id.menu_context_details).setVisible(true);
- menu.findItem(R.id.menu_context_resend).setVisible(messageRecord.isFailed());
- menu.findItem(R.id.menu_context_save_attachment).setVisible(!actionMessage &&
- messageRecord.isMms() &&
- !messageRecord.isMmsNotification() &&
- ((MediaMmsMessageRecord)messageRecord).containsMediaSlide());
-
- menu.findItem(R.id.menu_context_reply).setVisible(!actionMessage &&
- !messageRecord.isPending() &&
- !messageRecord.isFailed());
- }
-
- menu.findItem(R.id.menu_context_copy).setVisible(!actionMessage && hasText);
-
- boolean isGroupChat = recipient.isGroupRecipient();
-
- if (isGroupChat) {
- OpenGroupV2 openGroupChat = DatabaseFactory.getLokiThreadDatabase(getContext()).getOpenGroupChat(threadId);
- boolean isPublicChat = (openGroupChat != null);
- int selectedMessageCount = messageRecords.size();
- boolean areAllSentByUser = true;
- Set uniqueUserSet = new HashSet<>();
- for (MessageRecord message : messageRecords) {
- if (!message.isOutgoing()) { areAllSentByUser = false; }
- uniqueUserSet.add(message.getRecipient().getAddress().toString());
- }
- menu.findItem(R.id.menu_context_copy_public_key).setVisible(selectedMessageCount == 1 && !areAllSentByUser);
- menu.findItem(R.id.menu_context_reply).setVisible(selectedMessageCount == 1);
- String userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(requireContext());
- boolean userCanModerate =
- (isPublicChat && (OpenGroupAPIV2.isUserModerator(userHexEncodedPublicKey, openGroupChat.getRoom(), openGroupChat.getServer())));
- boolean isDeleteOptionVisible = !isPublicChat || (areAllSentByUser || userCanModerate);
- // allow banning if moderating a public chat and only one user's messages are selected
- boolean isBanOptionVisible = isPublicChat && userCanModerate && !areAllSentByUser && uniqueUserSet.size() == 1;
- menu.findItem(R.id.menu_context_delete_message).setVisible(isDeleteOptionVisible);
- menu.findItem(R.id.menu_context_ban_user).setVisible(isBanOptionVisible);
- } else {
- menu.findItem(R.id.menu_context_copy_public_key).setVisible(false);
- menu.findItem(R.id.menu_context_delete_message).setVisible(true);
- menu.findItem(R.id.menu_context_ban_user).setVisible(false);
- }
- }
-
- private ConversationAdapter getListAdapter() {
- return (ConversationAdapter) list.getAdapter();
- }
-
- private SmoothScrollingLinearLayoutManager getListLayoutManager() {
- return (SmoothScrollingLinearLayoutManager) list.getLayoutManager();
- }
-
- private MessageRecord getSelectedMessageRecord() {
- Set messageRecords = getListAdapter().getSelectedItems();
- return messageRecords.iterator().next();
- }
-
- public void reload(Recipient recipient, long threadId) {
- this.recipient = recipient;
-
- if (this.threadId != threadId) {
- this.threadId = threadId;
- initializeListAdapter();
- }
- }
-
- public void scrollToBottom() {
- if (getListLayoutManager().findFirstVisibleItemPosition() < SCROLL_ANIMATION_THRESHOLD) {
- list.smoothScrollToPosition(0);
- } else {
- list.scrollToPosition(0);
- }
- }
-
- public void setLastSeen(long lastSeen) {
- this.lastSeen = lastSeen;
- if (lastSeenDecoration != null) {
- list.removeItemDecoration(lastSeenDecoration);
- }
-
- lastSeenDecoration = new ConversationAdapter.LastSeenHeader(getListAdapter(), lastSeen);
- list.addItemDecoration(lastSeenDecoration);
- }
-
- private void handleCopyMessage(final Set messageRecords) {
- List messageList = new LinkedList<>(messageRecords);
- Collections.sort(messageList, new Comparator() {
- @Override
- public int compare(MessageRecord lhs, MessageRecord rhs) {
- if (lhs.getDateReceived() < rhs.getDateReceived()) return -1;
- else if (lhs.getDateReceived() == rhs.getDateReceived()) return 0;
- else return 1;
- }
- });
-
- StringBuilder bodyBuilder = new StringBuilder();
- ClipboardManager clipboard = (ClipboardManager) getActivity().getSystemService(Context.CLIPBOARD_SERVICE);
-
- for (MessageRecord messageRecord : messageList) {
- String body = messageRecord.getDisplayBody(requireContext()).toString();
- if (!TextUtils.isEmpty(body)) {
- bodyBuilder.append(body).append('\n');
- }
- }
- if (bodyBuilder.length() > 0 && bodyBuilder.charAt(bodyBuilder.length() - 1) == '\n') {
- bodyBuilder.deleteCharAt(bodyBuilder.length() - 1);
- }
-
- String result = bodyBuilder.toString();
-
- if (!TextUtils.isEmpty(result))
- clipboard.setText(result);
- }
-
- private void handleCopyPublicKey(MessageRecord messageRecord) {
- String sessionID = messageRecord.getRecipient().getAddress().toString();
- android.content.ClipboardManager clipboard = (android.content.ClipboardManager)requireActivity().getSystemService(Context.CLIPBOARD_SERVICE);
- ClipData clip = ClipData.newPlainText("Session ID", sessionID);
- clipboard.setPrimaryClip(clip);
- Toast.makeText(getContext(), R.string.copied_to_clipboard, Toast.LENGTH_SHORT).show();
- }
-
- private void handleDeleteMessages(final Set messageRecords) {
- int messagesCount = messageRecords.size();
- AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
-
- builder.setIconAttribute(R.attr.dialog_alert_icon);
- builder.setTitle(getActivity().getResources().getQuantityString(R.plurals.ConversationFragment_delete_selected_messages, messagesCount, messagesCount));
- builder.setMessage(getActivity().getResources().getQuantityString(R.plurals.ConversationFragment_this_will_permanently_delete_all_n_selected_messages, messagesCount, messagesCount));
- builder.setCancelable(true);
-
- OpenGroupV2 openGroupChat = DatabaseFactory.getLokiThreadDatabase(getContext()).getOpenGroupChat(threadId);
-
- builder.setPositiveButton(R.string.delete, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- new ProgressDialogAsyncTask(getActivity(),
- R.string.ConversationFragment_deleting,
- R.string.ConversationFragment_deleting_messages)
- {
- @Override
- protected Void doInBackground(MessageRecord... messageRecords) {
- if (openGroupChat != null) {
- ArrayList serverIDs = new ArrayList<>();
- ArrayList ignoredMessages = new ArrayList<>();
- ArrayList failedMessages = new ArrayList<>();
- boolean isSentByUser = true;
- for (MessageRecord messageRecord : messageRecords) {
- isSentByUser = isSentByUser && messageRecord.isOutgoing();
- Long serverID = DatabaseFactory.getLokiMessageDatabase(getContext()).getServerID(messageRecord.id, !messageRecord.isMms());
- if (serverID != null) {
- serverIDs.add(serverID);
- } else {
- ignoredMessages.add(messageRecord.getId());
- }
- }
- if (openGroupChat != null) {
- for (Long serverId : serverIDs) {
- OpenGroupAPIV2
- .deleteMessage(serverId, openGroupChat.getRoom(), openGroupChat.getServer())
- .success(l -> {
- for (MessageRecord messageRecord : messageRecords) {
- Long serverID = DatabaseFactory.getLokiMessageDatabase(getContext()).getServerID(messageRecord.id, !messageRecord.isMms());
- if (serverID != null && serverID.equals(serverId)) {
- MessagingModuleConfiguration.shared.getMessageDataProvider().deleteMessage(messageRecord.id, !messageRecord.isMms());
- break;
- }
- }
- return null;
- }).fail(e->{
- Log.e("Loki", "Couldn't delete message due to error",e);
- return null;
- });
- }
- }
- } else {
- for (MessageRecord messageRecord : messageRecords) {
- if (messageRecord.isMms()) {
- DatabaseFactory.getMmsDatabase(getActivity()).delete(messageRecord.getId());
- } else {
- DatabaseFactory.getSmsDatabase(getActivity()).deleteMessage(messageRecord.getId());
- }
- }
- }
- return null;
- }
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, messageRecords.toArray(new MessageRecord[messageRecords.size()]));
- }
- });
-
- builder.setNegativeButton(android.R.string.cancel, null);
- builder.show();
- }
-
- private void handleBanUser(Set messageRecords) {
- AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
-
- String userPublicKey = null;
- for (MessageRecord record: messageRecords) {
- String currentPublicKey = record.getRecipient().getAddress().toString();
- if (userPublicKey == null) {
- userPublicKey = currentPublicKey;
- }
- }
- final String finalPublicKey = userPublicKey;
-
- builder.setIconAttribute(R.attr.dialog_alert_icon);
- builder.setTitle(R.string.ConversationFragment_ban_selected_user);
- builder.setCancelable(true);
-
- final OpenGroupV2 openGroupChat = DatabaseFactory.getLokiThreadDatabase(getContext()).getOpenGroupChat(threadId);
-
- builder.setPositiveButton(R.string.ban, (dialog, which) -> {
- ConversationAdapter chatAdapter = getListAdapter();
- chatAdapter.clearSelection();
- chatAdapter.notifyDataSetChanged();
- new ProgressDialogAsyncTask(getActivity(),
- R.string.ConversationFragment_banning,
- R.string.ConversationFragment_banning_user) {
- @Override
- protected Void doInBackground(String... userPublicKeyParam) {
- String userPublicKey = userPublicKeyParam[0];
- if (openGroupChat != null) {
- OpenGroupAPIV2
- .ban(userPublicKey, openGroupChat.getRoom(), openGroupChat.getServer())
- .success(l -> {
- Log.d("Loki", "User banned");
- return Unit.INSTANCE;
- }).fail(e -> {
- Log.e("Loki", "Failed to ban user",e);
- return null;
- });
- } else {
- Log.d("Loki", "Tried to ban user from a non-public chat");
- }
- return null;
- }
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, finalPublicKey);
- });
-
- builder.setNegativeButton(android.R.string.cancel, null);
- builder.show();
- }
-
- private void handleDisplayDetails(MessageRecord message) {
- Intent intent = new Intent(getActivity(), MessageDetailsActivity.class);
- intent.putExtra(MessageDetailsActivity.MESSAGE_ID_EXTRA, message.getId());
- intent.putExtra(MessageDetailsActivity.THREAD_ID_EXTRA, threadId);
- intent.putExtra(MessageDetailsActivity.TYPE_EXTRA, message.isMms() ? MmsSmsDatabase.MMS_TRANSPORT : MmsSmsDatabase.SMS_TRANSPORT);
- intent.putExtra(MessageDetailsActivity.ADDRESS_EXTRA, recipient.getAddress());
- intent.putExtra(MessageDetailsActivity.IS_PUSH_GROUP_EXTRA, recipient.isGroupRecipient());
- startActivity(intent);
- }
-
- private void handleForwardMessage(MessageRecord message) {
- listener.onForwardClicked();
-
- SimpleTask.run(getLifecycle(), () -> {
- Intent composeIntent = new Intent(getActivity(), ShareActivity.class);
- composeIntent.putExtra(Intent.EXTRA_TEXT, message.getDisplayBody(requireContext()).toString());
-
- if (message.isMms()) {
- MmsMessageRecord mediaMessage = (MmsMessageRecord) message;
- boolean isAlbum = mediaMessage.containsMediaSlide() &&
- mediaMessage.getSlideDeck().getSlides().size() > 1 &&
- mediaMessage.getSlideDeck().getAudioSlide() == null &&
- mediaMessage.getSlideDeck().getDocumentSlide() == null;
-
- if (isAlbum) {
- ArrayList mediaList = new ArrayList<>(mediaMessage.getSlideDeck().getSlides().size());
- List attachments = Stream.of(mediaMessage.getSlideDeck().getSlides())
- .filter(s -> s.hasImage() || s.hasVideo())
- .map(Slide::asAttachment)
- .toList();
-
- for (Attachment attachment : attachments) {
- Uri uri = attachment.getDataUri() != null ? attachment.getDataUri() : attachment.getThumbnailUri();
-
- if (uri != null) {
- mediaList.add(new Media(uri,
- attachment.getContentType(),
- System.currentTimeMillis(),
- attachment.getWidth(),
- attachment.getHeight(),
- attachment.getSize(),
- Optional.absent(),
- Optional.fromNullable(attachment.getCaption())));
- }
- };
-
- if (!mediaList.isEmpty()) {
- composeIntent.putExtra(ConversationActivity.MEDIA_EXTRA, mediaList);
- }
- } else if (mediaMessage.containsMediaSlide()) {
- Slide slide = mediaMessage.getSlideDeck().getSlides().get(0);
- composeIntent.putExtra(Intent.EXTRA_STREAM, slide.getUri());
- composeIntent.setType(slide.getContentType());
- }
-
- if (mediaMessage.getSlideDeck().getTextSlide() != null && mediaMessage.getSlideDeck().getTextSlide().getUri() != null) {
- try (InputStream stream = PartAuthority.getAttachmentStream(requireContext(), mediaMessage.getSlideDeck().getTextSlide().getUri())) {
- String fullBody = Util.readFullyAsString(stream);
- composeIntent.putExtra(Intent.EXTRA_TEXT, fullBody);
- } catch (IOException e) {
- Log.w(TAG, "Failed to read long message text when forwarding.");
- }
- }
- }
-
- return composeIntent;
- }, this::startActivity);
- }
-
- private void handleResendMessage(final MessageRecord message) {
- new AsyncTask() {
- @Override
- protected Void doInBackground(MessageRecord... messageRecords) {
- MessageRecord messageRecord = messageRecords[0];
- Recipient recipient = messageRecord.getRecipient();
- VisibleMessage message = new VisibleMessage();
- message.setId(messageRecord.getId());
- message.setText(messageRecord.getBody());
- message.setSentTimestamp(messageRecord.getTimestamp());
- if (recipient.isGroupRecipient()) {
- message.setGroupPublicKey(recipient.getAddress().toGroupString());
- } else {
- message.setRecipient(messageRecord.getRecipient().getAddress().serialize());
- }
- message.setThreadID(messageRecord.getThreadId());
- if (messageRecord.isMms()) {
- MmsMessageRecord mmsMessageRecord = (MmsMessageRecord) messageRecord;
- if (!mmsMessageRecord.getLinkPreviews().isEmpty()) {
- message.setLinkPreview(org.session.libsession.messaging.messages.visible.LinkPreview.Companion.from(mmsMessageRecord.getLinkPreviews().get(0)));
- }
- if (mmsMessageRecord.getQuote() != null) {
- message.setQuote(Quote.Companion.from(mmsMessageRecord.getQuote().getQuoteModel()));
- }
- message.addSignalAttachments(mmsMessageRecord.getSlideDeck().asAttachments());
- }
- MessageSender.send(message, recipient.getAddress());
- return null;
- }
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, message);
- }
-
- private void handleReplyMessage(final MessageRecord message) {
- listener.handleReplyMessage(message);
- }
-
- private void handleSaveAttachment(final MediaMmsMessageRecord message) {
- SaveAttachmentTask.showWarningDialog(getActivity(), (dialog, which) -> {
- Permissions.with(this)
- .request(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
- .maxSdkVersion(Build.VERSION_CODES.P)
- .withPermanentDenialDialog(getString(R.string.MediaPreviewActivity_signal_needs_the_storage_permission_in_order_to_write_to_external_storage_but_it_has_been_permanently_denied))
- .onAnyDenied(() -> Toast.makeText(getContext(), R.string.MediaPreviewActivity_unable_to_write_to_external_storage_without_permission, Toast.LENGTH_LONG).show())
- .onAllGranted(() -> {
- List attachments =
- Stream.of(message.getSlideDeck().getSlides())
- .filter(s -> s.getUri() != null && (s.hasImage() || s.hasVideo() || s.hasAudio() || s.hasDocument()))
- .map(s -> new SaveAttachmentTask.Attachment(s.getUri(), s.getContentType(), message.getDateReceived(), s.getFileName().orNull()))
- .toList();
- if (!Util.isEmpty(attachments)) {
- SaveAttachmentTask saveTask = new SaveAttachmentTask(getActivity());
- saveTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, attachments.toArray(new SaveAttachmentTask.Attachment[0]));
- if (!message.isOutgoing()) {
- sendMediaSavedNotificationIfNeeded();
- }
- return;
- }
-
- Log.w(TAG, "No slide with attachable media found, failing nicely.");
- Toast.makeText(getActivity(),
- getResources().getQuantityString(R.plurals.ConversationFragment_error_while_saving_attachments_to_sd_card, 1),
- Toast.LENGTH_LONG).show();
- })
- .execute();
- });
- }
-
- private void sendMediaSavedNotificationIfNeeded() {
- if (recipient.isGroupRecipient()) return;
- DataExtractionNotification message = new DataExtractionNotification(new DataExtractionNotification.Kind.MediaSaved(System.currentTimeMillis()));
- MessageSender.send(message, recipient.getAddress());
- }
-
- @Override
- public @NonNull Loader onCreateLoader(int id, Bundle args) {
- Log.i(TAG, "onCreateLoader");
- loaderStartTime = System.currentTimeMillis();
-
- int limit = args.getInt(KEY_LIMIT, PARTIAL_CONVERSATION_LIMIT);
- int offset = 0;
- if (limit != 0 && startingPosition >= limit) {
- offset = Math.max(startingPosition - (limit / 2) + 1, 0);
- startingPosition -= offset - 1;
- }
-
- return new ConversationLoader(getActivity(), threadId, offset, limit, lastSeen);
- }
-
- @Override
- public void onLoadFinished(@NonNull Loader cursorLoader, Cursor cursor) {
- long loadTime = System.currentTimeMillis() - loaderStartTime;
- int count = cursor.getCount();
- Log.i(TAG, "onLoadFinished - took " + loadTime + " ms to load a cursor of size " + count);
- ConversationLoader loader = (ConversationLoader)cursorLoader;
-
- ConversationAdapter adapter = getListAdapter();
- if (adapter == null) {
- return;
- }
-
- if (cursor.getCount() >= PARTIAL_CONVERSATION_LIMIT && loader.hasLimit()) {
- adapter.setFooterView(topLoadMoreView);
- } else {
- adapter.setFooterView(null);
- }
-
- if (lastSeen == -1) {
- setLastSeen(loader.getLastSeen());
- }
-
- if (!loader.hasSent() && !recipient.isSystemContact() && !recipient.isGroupRecipient() && recipient.getRegistered() == Recipient.RegisteredState.REGISTERED) {
-// adapter.setHeaderView(unknownSenderView);
- } else {
- clearHeaderIfNotTyping(adapter);
- }
-
- if (loader.hasOffset()) {
- adapter.setHeaderView(bottomLoadMoreView);
- }
-
- if (firstLoad || loader.hasOffset()) {
- previousOffset = loader.getOffset();
- }
-
- activeOffset = loader.getOffset();
-
- adapter.changeCursor(cursor);
-
- int lastSeenPosition = adapter.findLastSeenPosition(lastSeen);
-
- if (adapter.getHeaderView() == typingView) {
- lastSeenPosition = Math.max(lastSeenPosition - 1, 0);
- }
-
- if (firstLoad) {
- if (startingPosition >= 0) {
- scrollToStartingPosition(startingPosition);
- } else {
- scrollToLastSeenPosition(lastSeenPosition);
- }
- firstLoad = false;
- } else if (previousOffset > 0) {
- int scrollPosition = previousOffset + getListLayoutManager().findFirstVisibleItemPosition();
- scrollPosition = Math.min(scrollPosition, count - 1);
-
- View firstView = list.getLayoutManager().getChildAt(scrollPosition);
- int pixelOffset = (firstView == null) ? 0 : (firstView.getBottom() - list.getPaddingBottom());
-
- getListLayoutManager().scrollToPositionWithOffset(scrollPosition, pixelOffset);
- previousOffset = 0;
- }
-
- if (lastSeenPosition <= 0) {
- setLastSeen(0);
- }
- }
-
- private void clearHeaderIfNotTyping(ConversationAdapter adapter) {
- if (adapter.getHeaderView() != typingView) {
- adapter.setHeaderView(null);
- }
- }
-
- @Override
- public void onLoaderReset(@NonNull Loader arg0) {
- if (list.getAdapter() != null) {
- getListAdapter().changeCursor(null);
- }
- }
-
- public long stageOutgoingMessage(OutgoingMediaMessage message) {
- MessageRecord messageRecord = DatabaseFactory.getMmsDatabase(getContext()).readerFor(message, threadId).getCurrent();
-
- if (getListAdapter() != null) {
- clearHeaderIfNotTyping(getListAdapter());
- setLastSeen(0);
- getListAdapter().addFastRecord(messageRecord);
- }
-
- return messageRecord.getId();
- }
-
- public long stageOutgoingMessage(OutgoingTextMessage message) {
- MessageRecord messageRecord = DatabaseFactory.getSmsDatabase(getContext()).readerFor(message, threadId).getCurrent();
-
- if (getListAdapter() != null) {
- clearHeaderIfNotTyping(getListAdapter());
- setLastSeen(0);
- getListAdapter().addFastRecord(messageRecord);
- }
-
- return messageRecord.getId();
- }
-
- public void releaseOutgoingMessage(long id) {
- if (getListAdapter() != null) {
- getListAdapter().releaseFastRecord(id);
- }
- }
-
- private void scrollToStartingPosition(final int startingPosition) {
- list.post(() -> {
- list.getLayoutManager().scrollToPosition(startingPosition);
- getListAdapter().pulseHighlightItem(startingPosition);
- });
- }
-
- private void scrollToLastSeenPosition(final int lastSeenPosition) {
- if (lastSeenPosition > 0) {
- list.post(() -> getListLayoutManager().scrollToPositionWithOffset(lastSeenPosition, list.getHeight()));
- }
- }
-
- private boolean isAtBottom() {
- if (list.getChildCount() == 0) return true;
-
- int firstVisiblePosition = getListLayoutManager().findFirstVisibleItemPosition();
-
- if (getListAdapter().getHeaderView() == typingView) {
- RecyclerView.ViewHolder item1 = list.findViewHolderForAdapterPosition(1);
- return firstVisiblePosition <= 1 && item1 != null && item1.itemView.getBottom() <= list.getHeight();
- }
-
- return firstVisiblePosition == 0 && list.getChildAt(0).getBottom() <= list.getHeight();
- }
-
- public void onSearchQueryUpdated(@Nullable String query) {
- if (getListAdapter() != null) {
- getListAdapter().onSearchQueryUpdated(query);
- }
- }
-
- public void jumpToMessage(@NonNull Address author, long timestamp, @Nullable Runnable onMessageNotFound) {
- SimpleTask.run(getLifecycle(), () -> {
- return DatabaseFactory.getMmsSmsDatabase(getContext())
- .getMessagePositionInConversation(threadId, timestamp, author);
- }, p -> moveToMessagePosition(p, onMessageNotFound));
- }
-
- private void moveToMessagePosition(int position, @Nullable Runnable onMessageNotFound) {
- Log.d(TAG, "Moving to message position: " + position + " activeOffset: " + activeOffset + " cursorCount: " + getListAdapter().getCursorCount());
-
- if (position >= activeOffset && position >= 0 && position < getListAdapter().getCursorCount()) {
- int offset = activeOffset > 0 ? activeOffset - 1 : 0;
- list.scrollToPosition(position - offset);
- getListAdapter().pulseHighlightItem(position - offset);
- } else if (position < 0) {
- Log.w(TAG, "Tried to navigate to message, but it wasn't found.");
- if (onMessageNotFound != null) {
- onMessageNotFound.run();
- }
- } else {
- Log.i(TAG, "Message was outside of the loaded range. Need to restart the loader.");
-
- firstLoad = true;
- startingPosition = position;
- getLoaderManager().restartLoader(0, Bundle.EMPTY, ConversationFragment.this);
- }
- }
-
- public interface ConversationFragmentListener {
- void setThreadId(long threadId);
- void handleReplyMessage(MessageRecord messageRecord);
- void onMessageActionToolbarOpened();
- void onForwardClicked();
- }
-
- private class ConversationScrollListener extends OnScrollListener {
-
- private final Animation scrollButtonInAnimation;
- private final Animation scrollButtonOutAnimation;
- private final ConversationDateHeader conversationDateHeader;
-
- private boolean wasAtBottom = true;
- private boolean wasAtZoomScrollHeight = false;
- private long lastPositionId = -1;
-
- ConversationScrollListener(@NonNull Context context) {
- this.scrollButtonInAnimation = AnimationUtils.loadAnimation(context, R.anim.fade_scale_in);
- this.scrollButtonOutAnimation = AnimationUtils.loadAnimation(context, R.anim.fade_scale_out);
- this.conversationDateHeader = new ConversationDateHeader(context, scrollDateHeader);
-
- this.scrollButtonInAnimation.setDuration(100);
- this.scrollButtonOutAnimation.setDuration(50);
- }
-
- @Override
- public void onScrolled(@NonNull final RecyclerView rv, final int dx, final int dy) {
- boolean currentlyAtBottom = isAtBottom();
- boolean currentlyAtZoomScrollHeight = isAtZoomScrollHeight();
- int positionId = getHeaderPositionId();
-
- if (currentlyAtBottom && !wasAtBottom) {
- ViewUtil.fadeOut(composeDivider, 50, View.INVISIBLE);
- ViewUtil.animateOut(scrollToBottomButton, scrollButtonOutAnimation, View.INVISIBLE);
- } else if (!currentlyAtBottom && wasAtBottom) {
- ViewUtil.fadeIn(composeDivider, 500);
- }
-
- if (currentlyAtZoomScrollHeight && !wasAtZoomScrollHeight) {
- ViewUtil.animateIn(scrollToBottomButton, scrollButtonInAnimation);
- }
-
- if (positionId != lastPositionId) {
- bindScrollHeader(conversationDateHeader, positionId);
- }
-
- wasAtBottom = currentlyAtBottom;
- wasAtZoomScrollHeight = currentlyAtZoomScrollHeight;
- lastPositionId = positionId;
- }
-
- @Override
- public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
- if (newState == RecyclerView.SCROLL_STATE_DRAGGING) {
- conversationDateHeader.show();
- } else if (newState == RecyclerView.SCROLL_STATE_IDLE) {
- conversationDateHeader.hide();
- }
- }
-
- private boolean isAtZoomScrollHeight() {
- return getListLayoutManager().findFirstCompletelyVisibleItemPosition() > 4;
- }
-
- private int getHeaderPositionId() {
- return getListLayoutManager().findLastVisibleItemPosition();
- }
-
- private void bindScrollHeader(HeaderViewHolder headerViewHolder, int positionId) {
- if (((ConversationAdapter)list.getAdapter()).getHeaderId(positionId) != -1) {
- ((ConversationAdapter) list.getAdapter()).onBindHeaderViewHolder(headerViewHolder, positionId);
- }
- }
- }
-
- private class ConversationFragmentItemClickListener implements ItemClickListener {
-
- @Override
- public void onItemClick(MessageRecord messageRecord) {
- if (messageRecord.isUpdate()) return;
- if (actionMode != null) {
- ((ConversationAdapter) list.getAdapter()).toggleSelection(messageRecord);
- list.getAdapter().notifyDataSetChanged();
-
- if (getListAdapter().getSelectedItems().size() == 0) {
- actionMode.finish();
- } else {
- setCorrectMenuVisibility(actionMode.getMenu());
- actionMode.setTitle(String.valueOf(getListAdapter().getSelectedItems().size()));
- }
- }
- }
-
- @Override
- public void onItemLongClick(MessageRecord messageRecord) {
- if (messageRecord.isUpdate()) return;
- if (actionMode == null) {
- ((ConversationAdapter) list.getAdapter()).toggleSelection(messageRecord);
- list.getAdapter().notifyDataSetChanged();
-
- actionMode = ((AppCompatActivity)getActivity()).startSupportActionMode(actionModeCallback);
-
- View titleTextView = (getActivity().findViewById(R.id.action_bar_title));
- if (titleTextView != null) {
- titleTextView.setBackgroundColor(getResources().getColor(R.color.transparent));
- ViewParent titleTextViewContainerView = titleTextView.getParent();
- if (titleTextViewContainerView != null) {
- ((View)titleTextViewContainerView).setBackgroundColor(getResources().getColor(R.color.transparent));
- }
- }
- }
- }
-
- @Override
- public void onQuoteClicked(MmsMessageRecord messageRecord) {
- if (messageRecord.getQuote() == null) {
- Log.w(TAG, "Received a 'quote clicked' event, but there's no quote...");
- return;
- }
-
- if (messageRecord.getQuote().isOriginalMissing()) {
- Log.i(TAG, "Clicked on a quote whose original message we never had.");
- Toast.makeText(getContext(), R.string.ConversationFragment_quoted_message_not_found, Toast.LENGTH_SHORT).show();
- return;
- }
-
- SimpleTask.run(getLifecycle(), () -> {
- return DatabaseFactory.getMmsSmsDatabase(getContext())
- .getQuotedMessagePosition(threadId,
- messageRecord.getQuote().getId(),
- messageRecord.getQuote().getAuthor());
- }, p -> moveToMessagePosition(p, () -> {
- Toast.makeText(getContext(), R.string.ConversationFragment_quoted_message_no_longer_available, Toast.LENGTH_SHORT).show();
- }));
- }
-
- @Override
- public void onLinkPreviewClicked(@NonNull LinkPreview linkPreview) {
- if (getContext() != null && getActivity() != null) {
- CommunicationActions.openBrowserLink(getActivity(), linkPreview.getUrl());
- }
- }
-
- @Override
- public void onMoreTextClicked(@NonNull Address conversationAddress, long messageId, boolean isMms) {
- if (getContext() != null && getActivity() != null) {
- startActivity(LongMessageActivity.getIntent(getContext(), conversationAddress, messageId, isMms));
- }
- }
- }
-
- private class ActionModeCallback implements ActionMode.Callback {
-
- private int statusBarColor;
-
- @Override
- public boolean onCreateActionMode(ActionMode mode, Menu menu) {
- MenuInflater inflater = mode.getMenuInflater();
- inflater.inflate(R.menu.conversation_context, menu);
-
- mode.setTitle("1");
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- Window window = getActivity().getWindow();
- statusBarColor = window.getStatusBarColor();
- }
-
- setCorrectMenuVisibility(menu);
- listener.onMessageActionToolbarOpened();
- return true;
- }
-
- @Override
- public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
- return false;
- }
-
- @Override
- public void onDestroyActionMode(ActionMode mode) {
- ((ConversationAdapter)list.getAdapter()).clearSelection();
- list.getAdapter().notifyDataSetChanged();
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- getActivity().getWindow().setStatusBarColor(statusBarColor);
- }
-
- actionMode = null;
- }
-
- @Override
- public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
- switch(item.getItemId()) {
- case R.id.menu_context_copy:
- handleCopyMessage(getListAdapter().getSelectedItems());
- actionMode.finish();
- return true;
- case R.id.menu_context_copy_public_key:
- handleCopyPublicKey((MessageRecord) getListAdapter().getSelectedItems().toArray()[0]);
- actionMode.finish();
- return true;
- case R.id.menu_context_delete_message:
- handleDeleteMessages(getListAdapter().getSelectedItems());
- actionMode.finish();
- return true;
- case R.id.menu_context_ban_user:
- handleBanUser(getListAdapter().getSelectedItems());
- return true;
- case R.id.menu_context_details:
- handleDisplayDetails(getSelectedMessageRecord());
- actionMode.finish();
- return true;
-// case R.id.menu_context_forward:
-// handleForwardMessage(getSelectedMessageRecord());
-// actionMode.finish();
-// return true;
- case R.id.menu_context_resend:
- handleResendMessage(getSelectedMessageRecord());
- actionMode.finish();
- return true;
- case R.id.menu_context_save_attachment:
- handleSaveAttachment((MediaMmsMessageRecord)getSelectedMessageRecord());
- actionMode.finish();
- return true;
- case R.id.menu_context_reply:
- handleReplyMessage(getSelectedMessageRecord());
- actionMode.finish();
- return true;
- }
-
- return false;
- }
- }
-
- private static class ConversationDateHeader extends HeaderViewHolder {
-
- private final Animation animateIn;
- private final Animation animateOut;
-
- private boolean pendingHide = false;
-
- private ConversationDateHeader(Context context, TextView textView) {
- super(textView);
- this.animateIn = AnimationUtils.loadAnimation(context, R.anim.slide_from_top);
- this.animateOut = AnimationUtils.loadAnimation(context, R.anim.slide_to_top);
-
- this.animateIn.setDuration(100);
- this.animateOut.setDuration(100);
- }
-
- public void show() {
- if (pendingHide) {
- pendingHide = false;
- } else {
- ViewUtil.animateIn(textView, animateIn);
- }
- }
-
- public void hide() {
- pendingHide = true;
-
- textView.postDelayed(new Runnable() {
- @Override
- public void run() {
- if (pendingHide) {
- pendingHide = false;
- ViewUtil.animateOut(textView, animateOut, View.GONE);
- }
- }
- }, 400);
- }
- }
-}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java
deleted file mode 100644
index aa60603074..0000000000
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java
+++ /dev/null
@@ -1,1203 +0,0 @@
-/*
- * Copyright (C) 2011 Whisper Systems
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.thoughtcrime.securesms.conversation;
-
-import android.annotation.SuppressLint;
-import android.content.ActivityNotFoundException;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.TypedArray;
-import android.graphics.Color;
-import android.graphics.PorterDuff;
-import android.graphics.Typeface;
-import android.net.Uri;
-import android.text.Spannable;
-import android.text.SpannableString;
-import android.text.SpannableStringBuilder;
-import android.text.Spanned;
-import android.text.TextPaint;
-import android.text.TextUtils;
-import android.text.style.BackgroundColorSpan;
-import android.text.style.CharacterStyle;
-import android.text.style.ClickableSpan;
-import android.text.style.ForegroundColorSpan;
-import android.text.style.URLSpan;
-import android.text.util.Linkify;
-import android.util.AttributeSet;
-import android.util.TypedValue;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import androidx.annotation.DimenRes;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.annimon.stream.Stream;
-
-import org.session.libsession.messaging.contacts.Contact;
-import org.session.libsession.messaging.jobs.AttachmentDownloadJob;
-import org.session.libsession.messaging.jobs.JobQueue;
-import org.session.libsession.messaging.open_groups.OpenGroupAPIV2;
-import org.session.libsession.messaging.open_groups.OpenGroupV2;
-import org.session.libsession.messaging.sending_receiving.attachments.AttachmentTransferProgress;
-import org.session.libsession.messaging.sending_receiving.attachments.DatabaseAttachment;
-import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview;
-import org.session.libsession.messaging.utilities.UpdateMessageData;
-import org.session.libsession.utilities.Stub;
-import org.session.libsession.utilities.TextSecurePreferences;
-import org.session.libsession.utilities.ThemeUtil;
-import org.session.libsession.utilities.Util;
-import org.session.libsession.utilities.ViewUtil;
-import org.session.libsession.utilities.recipients.Recipient;
-import org.session.libsession.utilities.recipients.RecipientModifiedListener;
-import org.session.libsignal.utilities.Log;
-import org.session.libsignal.utilities.guava.Optional;
-import org.thoughtcrime.securesms.BindableConversationItem;
-import org.thoughtcrime.securesms.MediaPreviewActivity;
-import org.thoughtcrime.securesms.MessageDetailsActivity;
-import org.thoughtcrime.securesms.components.ConversationItemAlertView;
-import org.thoughtcrime.securesms.components.ConversationItemFooter;
-import org.thoughtcrime.securesms.components.ConversationItemThumbnail;
-import org.thoughtcrime.securesms.components.DocumentView;
-import org.thoughtcrime.securesms.components.LinkPreviewView;
-import org.thoughtcrime.securesms.components.QuoteView;
-import org.thoughtcrime.securesms.components.StickerView;
-import org.thoughtcrime.securesms.components.emoji.EmojiTextView;
-import org.thoughtcrime.securesms.database.DatabaseFactory;
-import org.thoughtcrime.securesms.database.MmsSmsDatabase;
-import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord;
-import org.thoughtcrime.securesms.database.model.MessageRecord;
-import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
-import org.thoughtcrime.securesms.database.model.Quote;
-import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil;
-import org.thoughtcrime.securesms.loki.utilities.MentionUtilities;
-import org.thoughtcrime.securesms.loki.views.MessageAudioView;
-import org.thoughtcrime.securesms.loki.views.OpenGroupInvitationView;
-import org.thoughtcrime.securesms.loki.views.ProfilePictureView;
-import org.thoughtcrime.securesms.mms.GlideRequests;
-import org.thoughtcrime.securesms.mms.ImageSlide;
-import org.thoughtcrime.securesms.mms.PartAuthority;
-import org.thoughtcrime.securesms.mms.Slide;
-import org.thoughtcrime.securesms.mms.SlideClickListener;
-import org.thoughtcrime.securesms.mms.SlidesClickedListener;
-import org.thoughtcrime.securesms.mms.TextSlide;
-import org.thoughtcrime.securesms.util.DateUtils;
-import org.thoughtcrime.securesms.util.LongClickCopySpan;
-import org.thoughtcrime.securesms.util.LongClickMovementMethod;
-import org.thoughtcrime.securesms.util.SearchUtil;
-
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Locale;
-import java.util.Set;
-
-import network.loki.messenger.R;
-
-/**
- * A view that displays an individual conversation item within a conversation
- * thread. Used by ComposeMessageActivity's ListActivity via a ConversationAdapter.
- *
- * @author Moxie Marlinspike
- *
- */
-
-public class ConversationItem extends LinearLayout
- implements RecipientModifiedListener, BindableConversationItem
-{
- private static final String TAG = ConversationItem.class.getSimpleName();
-
- private static final int MAX_MEASURE_CALLS = 3;
- private static final int MAX_BODY_DISPLAY_LENGTH = 1000;
-
- private MessageRecord messageRecord;
- private Locale locale;
- private boolean groupThread;
- private Recipient recipient;
- private GlideRequests glideRequests;
-
- protected ViewGroup bodyBubble;
- private QuoteView quoteView;
- private EmojiTextView bodyText;
- private ConversationItemFooter footer;
- private ConversationItemFooter stickerFooter;
- private TextView groupSender;
- private TextView groupSenderProfileName;
- private View groupSenderHolder;
- private ProfilePictureView profilePictureView;
- private ImageView moderatorIconImageView;
- private ViewGroup contactPhotoHolder;
- private ConversationItemAlertView alertView;
- private ViewGroup container;
-
- private @NonNull Set batchSelected = new HashSet<>();
- private Recipient conversationRecipient;
- private Stub mediaThumbnailStub;
- private Stub audioViewStub;
- private Stub documentViewStub;
- private Stub linkPreviewStub;
- private Stub stickerStub;
- private Stub openGroupInvitationViewStub;
- private @Nullable EventListener eventListener;
-
- private int defaultBubbleColor;
- private int measureCalls;
-
- private final PassthroughClickListener passthroughClickListener = new PassthroughClickListener();
- private final AttachmentDownloadClickListener downloadClickListener = new AttachmentDownloadClickListener();
- private final SlideClickPassthroughListener singleDownloadClickListener = new SlideClickPassthroughListener(downloadClickListener);
- private final LinkPreviewClickListener linkPreviewClickListener = new LinkPreviewClickListener();
-
- private final Context context;
-
- public ConversationItem(Context context) {
- this(context, null);
- }
-
- public ConversationItem(Context context, AttributeSet attrs) {
- super(context, attrs);
- this.context = context;
- }
-
- @Override
- public void setOnClickListener(OnClickListener l) {
- super.setOnClickListener(new ClickListener(l));
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
-
- initializeAttributes();
-
- this.bodyText = findViewById(R.id.conversation_item_body);
- this.footer = findViewById(R.id.conversation_item_footer);
- this.stickerFooter = findViewById(R.id.conversation_item_sticker_footer);
- this.groupSender = findViewById(R.id.group_message_sender);
- this.groupSenderProfileName = findViewById(R.id.group_message_sender_profile);
- this.alertView = findViewById(R.id.indicators_parent);
- this.profilePictureView = findViewById(R.id.profilePictureView);
- this.moderatorIconImageView = findViewById(R.id.moderator_icon_image_view);
- this.contactPhotoHolder = findViewById(R.id.contact_photo_container);
- this.bodyBubble = findViewById(R.id.body_bubble);
- this.mediaThumbnailStub = new Stub<>(findViewById(R.id.image_view_stub));
- this.audioViewStub = new Stub<>(findViewById(R.id.audio_view_stub));
- this.documentViewStub = new Stub<>(findViewById(R.id.document_view_stub));
- this.linkPreviewStub = new Stub<>(findViewById(R.id.link_preview_stub));
- this.stickerStub = new Stub<>(findViewById(R.id.sticker_view_stub));
- this.openGroupInvitationViewStub = new Stub<>(findViewById(R.id.open_group_invitation_stub));
- this.groupSenderHolder = findViewById(R.id.group_sender_holder);
- this.quoteView = findViewById(R.id.quote_view);
- this.container = findViewById(R.id.container);
-
- setOnClickListener(new ClickListener(null));
-
- bodyText.setOnLongClickListener(passthroughClickListener);
- bodyText.setOnClickListener(passthroughClickListener);
-
- bodyText.setMovementMethod(LongClickMovementMethod.getInstance(getContext()));
- }
-
- @Override
- public void bind(@NonNull MessageRecord messageRecord,
- @NonNull Optional previousMessageRecord,
- @NonNull Optional nextMessageRecord,
- @NonNull GlideRequests glideRequests,
- @NonNull Locale locale,
- @NonNull Set batchSelected,
- @NonNull Recipient conversationRecipient,
- @Nullable String searchQuery,
- boolean pulseHighlight)
- {
- this.messageRecord = messageRecord;
- this.locale = locale;
- this.glideRequests = glideRequests;
- this.batchSelected = batchSelected;
- this.conversationRecipient = conversationRecipient;
- this.groupThread = conversationRecipient.isGroupRecipient();
- this.recipient = messageRecord.getIndividualRecipient();
-
- this.recipient.addListener(this);
- this.conversationRecipient.addListener(this);
-
- setGutterSizes(messageRecord, groupThread);
- setMessageShape(messageRecord, previousMessageRecord, nextMessageRecord, groupThread);
- setMediaAttributes(messageRecord, previousMessageRecord, nextMessageRecord, conversationRecipient, groupThread);
- setInteractionState(messageRecord, pulseHighlight);
- setBodyText(messageRecord, searchQuery, groupThread);
- setBubbleState(messageRecord);
- setStatusIcons(messageRecord);
- setContactPhoto(recipient);
- setGroupMessageStatus(messageRecord, recipient);
- setGroupAuthorColor(messageRecord);
- setAuthor(messageRecord, previousMessageRecord, nextMessageRecord, groupThread);
- setQuote(messageRecord, previousMessageRecord, nextMessageRecord, groupThread);
- setMessageSpacing(context, messageRecord, previousMessageRecord, nextMessageRecord, groupThread);
- setFooter(messageRecord, nextMessageRecord, locale, groupThread);
- adjustMarginsIfNeeded(messageRecord);
- }
-
- @Override
- public void setEventListener(@Nullable EventListener eventListener) {
- this.eventListener = eventListener;
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-
- if (isInEditMode()) {
- return;
- }
-
- boolean needsMeasure = false;
-
- if (hasQuote(messageRecord)) {
- int quoteWidth = quoteView.getMeasuredWidth();
- int availableWidth = getAvailableMessageBubbleWidth(quoteView);
-
- if (quoteWidth != availableWidth) {
- quoteView.getLayoutParams().width = availableWidth;
- needsMeasure = true;
- }
- }
-
- if (hasThumbnail(messageRecord) && messageRecord.getDisplayBody(context).length() > 0) {
- ViewUtil.updateLayoutParams(bodyText, getAvailableMessageBubbleWidth(bodyText), ViewGroup.LayoutParams.WRAP_CONTENT);
- }
-
- ConversationItemFooter activeFooter = getActiveFooter(messageRecord);
- int availableWidth = getAvailableMessageBubbleWidth(footer);
-
- if (activeFooter.getVisibility() != GONE && activeFooter.getMeasuredWidth() != availableWidth) {
- activeFooter.getLayoutParams().width = availableWidth;
- needsMeasure = true;
- }
-
- if (needsMeasure) {
- if (measureCalls < MAX_MEASURE_CALLS) {
- measureCalls++;
- measure(widthMeasureSpec, heightMeasureSpec);
- } else {
- Log.w(TAG, "Hit measure() cap of " + MAX_MEASURE_CALLS);
- }
- } else {
- measureCalls = 0;
- }
- }
-
- private int getAvailableMessageBubbleWidth(@NonNull View forView) {
- int availableWidth;
- if (hasAudio(messageRecord)) {
- availableWidth = audioViewStub.get().getMeasuredWidth() + ViewUtil.getLeftMargin(audioViewStub.get()) + ViewUtil.getRightMargin(audioViewStub.get());
- } else if (hasThumbnail(messageRecord) || hasBigImageLinkPreview(messageRecord)) {
- availableWidth = mediaThumbnailStub.get().getMeasuredWidth();
- } else {
- availableWidth = bodyBubble.getMeasuredWidth() - bodyBubble.getPaddingLeft() - bodyBubble.getPaddingRight();
- }
-
- availableWidth -= ViewUtil.getLeftMargin(forView) + ViewUtil.getRightMargin(forView);
-
- return availableWidth;
- }
-
- private void initializeAttributes() {
- final int[] attributes = new int[] {R.attr.conversation_item_bubble_background};
- final TypedArray attrs = context.obtainStyledAttributes(attributes);
-
- defaultBubbleColor = attrs.getColor(0, Color.WHITE);
- attrs.recycle();
- }
-
- @Override
- public void unbind() {
- if (recipient != null) {
- recipient.removeListener(this);
- }
- if (profilePictureView != null) {
- profilePictureView.recycle();
- }
- }
-
- public MessageRecord getMessageRecord() {
- return messageRecord;
- }
-
- /// MessageRecord Attribute Parsers
-
- private void setBubbleState(MessageRecord messageRecord) {
- int bubbleColor = ThemeUtil.getThemedColor(getContext(), messageRecord.isOutgoing() ?
- R.attr.message_sent_background_color :
- R.attr.message_received_background_color);
- bodyBubble.getBackground().setColorFilter(bubbleColor, PorterDuff.Mode.MULTIPLY);
-
- if (audioViewStub.resolved()) {
- setAudioViewTint(messageRecord, this.conversationRecipient);
- }
- }
-
- private void setAudioViewTint(MessageRecord messageRecord, Recipient recipient) {
-// audioViewStub.get().setTint(Color.WHITE, getResources().getColor(R.color.action_bar_background));
- }
-
- private void setInteractionState(MessageRecord messageRecord, boolean pulseHighlight) {
- if (batchSelected.contains(messageRecord)) {
- setBackgroundResource(R.drawable.conversation_item_background);
- setSelected(true);
- } else if (pulseHighlight) {
- setBackgroundResource(R.drawable.conversation_item_background_animated);
- setSelected(true);
- postDelayed(() -> setSelected(false), 500);
- } else {
- setSelected(false);
- }
-
- if (mediaThumbnailStub.resolved()) {
- mediaThumbnailStub.get().setFocusable(!shouldInterceptClicks(messageRecord) && batchSelected.isEmpty());
- mediaThumbnailStub.get().setClickable(!shouldInterceptClicks(messageRecord) && batchSelected.isEmpty());
- mediaThumbnailStub.get().setLongClickable(batchSelected.isEmpty());
- }
-
- if (audioViewStub.resolved()) {
- audioViewStub.get().setFocusable(!shouldInterceptClicks(messageRecord) && batchSelected.isEmpty());
- audioViewStub.get().setClickable(batchSelected.isEmpty());
- audioViewStub.get().setEnabled(batchSelected.isEmpty());
- }
-
- if (documentViewStub.resolved()) {
- documentViewStub.get().setFocusable(!shouldInterceptClicks(messageRecord) && batchSelected.isEmpty());
- documentViewStub.get().setClickable(batchSelected.isEmpty());
- }
- }
-
- private boolean isCaptionlessMms(MessageRecord messageRecord) {
- return TextUtils.isEmpty(messageRecord.getDisplayBody(getContext())) && messageRecord.isMms() && ((MmsMessageRecord) messageRecord).getSlideDeck().getTextSlide() == null;
- }
-
- private boolean hasAudio(MessageRecord messageRecord) {
- return messageRecord.isMms() && ((MmsMessageRecord)messageRecord).getSlideDeck().getAudioSlide() != null;
- }
-
- private boolean hasThumbnail(MessageRecord messageRecord) {
- return messageRecord.isMms() && ((MmsMessageRecord)messageRecord).getSlideDeck().getThumbnailSlide() != null;
- }
-
- private boolean hasOnlyThumbnail(MessageRecord messageRecord) {
- return hasThumbnail(messageRecord) &&
- !hasAudio(messageRecord) &&
- !hasDocument(messageRecord);
- }
-
- private boolean hasOnlyDocument(MessageRecord messageRecord) {
- return messageRecord.getBody().length() == 0 &&
- !hasThumbnail(messageRecord) &&
- !hasAudio(messageRecord) &&
- hasDocument(messageRecord) &&
- !hasQuote(messageRecord);
- }
-
- private boolean hasOnlyText(MessageRecord messageRecord) {
- return messageRecord.getBody().length() != 0 &&
- !hasThumbnail(messageRecord) &&
- !hasAudio(messageRecord) &&
- !hasDocument(messageRecord) &&
- !hasQuote(messageRecord);
- }
-
- private boolean hasDocument(MessageRecord messageRecord) {
- return messageRecord.isMms() && ((MmsMessageRecord)messageRecord).getSlideDeck().getDocumentSlide() != null;
- }
-
- private boolean hasExtraText(MessageRecord messageRecord) {
- boolean hasTextSlide = messageRecord.isMms() && ((MmsMessageRecord)messageRecord).getSlideDeck().getTextSlide() != null;
- boolean hasOverflowText = messageRecord.getBody().length() > MAX_BODY_DISPLAY_LENGTH;
-
- return hasTextSlide || hasOverflowText;
- }
-
- private boolean hasQuote(MessageRecord messageRecord) {
- return messageRecord.isMms() && ((MmsMessageRecord)messageRecord).getQuote() != null;
- }
-
- private boolean hasLinkPreview(MessageRecord messageRecord) {
- return messageRecord.isMms() && !((MmsMessageRecord)messageRecord).getLinkPreviews().isEmpty();
- }
-
- private boolean hasBigImageLinkPreview(MessageRecord messageRecord) {
- if (!hasLinkPreview(messageRecord)) return false;
-
- LinkPreview linkPreview = ((MmsMessageRecord) messageRecord).getLinkPreviews().get(0);
- int minWidth = getResources().getDimensionPixelSize(R.dimen.media_bubble_min_width);
-
- return linkPreview.getThumbnail().isPresent() &&
- linkPreview.getThumbnail().get().getWidth() >= minWidth;
- }
-
- private void setBodyText(MessageRecord messageRecord, @Nullable String searchQuery, boolean isGroupThread) {
- bodyText.setClickable(false);
- bodyText.setFocusable(false);
- bodyText.setTextSize(TypedValue.COMPLEX_UNIT_SP, TextSecurePreferences.getMessageBodyTextSize(context));
- if (isCaptionlessMms(messageRecord)) {
- bodyText.setVisibility(View.GONE);
- } else {
- Spannable text = MentionUtilities.highlightMentions(linkifyMessageBody(messageRecord.getDisplayBody(context), batchSelected.isEmpty()), messageRecord.isOutgoing(), messageRecord.getThreadId(), context);
- text = SearchUtil.getHighlightedSpan(locale, () -> new BackgroundColorSpan(Color.WHITE), text, searchQuery);
- text = SearchUtil.getHighlightedSpan(locale, () -> new ForegroundColorSpan(Color.BLACK), text, searchQuery);
-
- if (hasExtraText(messageRecord)) {
- bodyText.setOverflowText(getLongMessageSpan(messageRecord));
- } else {
- bodyText.setOverflowText(null);
- }
-
- if (!messageRecord.isOpenGroupInvitation())
- bodyText.setText(text);
-
- bodyText.setVisibility(View.VISIBLE);
- }
- }
-
- private void adjustMarginsIfNeeded(MessageRecord messageRecord) {
- LinearLayout.LayoutParams bodyTextLayoutParams = (LinearLayout.LayoutParams)bodyText.getLayoutParams();
- bodyTextLayoutParams.topMargin = 0;
- if (hasOnlyThumbnail(messageRecord) || hasLinkPreview(messageRecord)) {
- int topPadding = 0;
- if (groupSenderHolder.getVisibility() == VISIBLE) {
- topPadding = (int)getResources().getDimension(R.dimen.medium_spacing);
- }
- int bottomPadding = 0;
- if (messageRecord.getBody().length() > 0) {
- bodyTextLayoutParams.topMargin = (int)getResources().getDimension(R.dimen.medium_spacing);
- bottomPadding = (int)getResources().getDimension(R.dimen.medium_spacing);
- }
- bodyBubble.setPadding(0, topPadding, 0, bottomPadding);
- } else {
- bodyBubble.setPadding(0, (int)getResources().getDimension(R.dimen.medium_spacing), 0, (int)getResources().getDimension(R.dimen.medium_spacing));
- }
- bodyText.setLayoutParams(bodyTextLayoutParams);
- LinearLayout.LayoutParams senderHolderLayoutParams = (LinearLayout.LayoutParams)groupSenderHolder.getLayoutParams();
- if (groupSenderHolder.getVisibility() == VISIBLE && hasOnlyText(messageRecord)) {
- senderHolderLayoutParams.bottomMargin = (int)(getResources().getDisplayMetrics().density * 4);
- } else {
- senderHolderLayoutParams.bottomMargin = (int)getResources().getDimension(R.dimen.medium_spacing);
- }
- groupSenderHolder.setLayoutParams(senderHolderLayoutParams);
- if (documentViewStub.resolved()) {
- LinearLayout.LayoutParams documentViewLayoutParams = (LinearLayout.LayoutParams)documentViewStub.get().getLayoutParams();
- int bottomMargin = 0;
- if (hasOnlyDocument(messageRecord)) {
- if (footer.getVisibility() == VISIBLE) {
- bottomMargin = (int)(4 * getResources().getDisplayMetrics().density);
- } else {
- bottomMargin = (int)(-4 * getResources().getDisplayMetrics().density);
- }
- } else {
- bottomMargin = (int)(4 * getResources().getDisplayMetrics().density);
- }
- documentViewLayoutParams.bottomMargin = bottomMargin;
- documentViewStub.get().setLayoutParams(documentViewLayoutParams);
- }
- }
-
- private void setMediaAttributes(@NonNull MessageRecord messageRecord,
- @NonNull Optional previousRecord,
- @NonNull Optional nextRecord,
- @NonNull Recipient conversationRecipient,
- boolean isGroupThread)
- {
- boolean showControls = !messageRecord.isFailed();
-
- if (hasLinkPreview(messageRecord)) {
- linkPreviewStub.get().setVisibility(View.VISIBLE);
- if (audioViewStub.resolved()) audioViewStub.get().setVisibility(View.GONE);
- if (mediaThumbnailStub.resolved()) mediaThumbnailStub.get().setVisibility(View.GONE);
- if (documentViewStub.resolved()) documentViewStub.get().setVisibility(View.GONE);
- if (stickerStub.resolved()) stickerStub.get().setVisibility(View.GONE);
- if (openGroupInvitationViewStub.resolved()) openGroupInvitationViewStub.get().setVisibility(View.GONE);
-
- //noinspection ConstantConditions
- LinkPreview linkPreview = ((MmsMessageRecord) messageRecord).getLinkPreviews().get(0);
-
- if (hasBigImageLinkPreview(messageRecord)) {
- mediaThumbnailStub.get().setVisibility(VISIBLE);
- mediaThumbnailStub.get().setImageResource(glideRequests, Collections.singletonList(new ImageSlide(context, linkPreview.getThumbnail().get())), showControls, false);
- mediaThumbnailStub.get().setThumbnailClickListener(new LinkPreviewThumbnailClickListener());
- mediaThumbnailStub.get().setDownloadClickListener(downloadClickListener);
- mediaThumbnailStub.get().setOnLongClickListener(passthroughClickListener);
-
- linkPreviewStub.get().setLinkPreview(glideRequests, linkPreview, false, false);
-
- setThumbnailCorners(messageRecord, previousRecord, nextRecord, isGroupThread);
- setLinkPreviewCorners(messageRecord, previousRecord, nextRecord, isGroupThread, true);
-
- ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
- ViewUtil.updateLayoutParams(groupSenderHolder, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
- } else {
- linkPreviewStub.get().setLinkPreview(glideRequests, linkPreview, true, false);
- linkPreviewStub.get().setDownloadClickedListener(downloadClickListener);
- setLinkPreviewCorners(messageRecord, previousRecord, nextRecord, isGroupThread, false);
- ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
- ViewUtil.updateLayoutParams(groupSenderHolder, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
- }
-
- linkPreviewStub.get().setOnClickListener(linkPreviewClickListener);
- linkPreviewStub.get().setOnLongClickListener(passthroughClickListener);
-
- footer.setVisibility(VISIBLE);
- } else if (hasAudio(messageRecord)) {
- audioViewStub.get().setVisibility(View.VISIBLE);
- if (mediaThumbnailStub.resolved()) mediaThumbnailStub.get().setVisibility(View.GONE);
- if (documentViewStub.resolved()) documentViewStub.get().setVisibility(View.GONE);
- if (linkPreviewStub.resolved()) linkPreviewStub.get().setVisibility(GONE);
- if (stickerStub.resolved()) stickerStub.get().setVisibility(View.GONE);
- if (openGroupInvitationViewStub.resolved()) openGroupInvitationViewStub.get().setVisibility(View.GONE);
-
- //noinspection ConstantConditions
- audioViewStub.get().setAudio(((MediaMmsMessageRecord) messageRecord).getSlideDeck().getAudioSlide(), showControls);
- audioViewStub.get().setDownloadClickListener(singleDownloadClickListener);
- audioViewStub.get().setOnLongClickListener(passthroughClickListener);
-
- ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
- ViewUtil.updateLayoutParams(groupSenderHolder, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
-
- footer.setVisibility(VISIBLE);
- } else if (hasDocument(messageRecord)) {
- documentViewStub.get().setVisibility(View.VISIBLE);
- if (mediaThumbnailStub.resolved()) mediaThumbnailStub.get().setVisibility(View.GONE);
- if (audioViewStub.resolved()) audioViewStub.get().setVisibility(View.GONE);
- if (linkPreviewStub.resolved()) linkPreviewStub.get().setVisibility(GONE);
- if (stickerStub.resolved()) stickerStub.get().setVisibility(View.GONE);
- if (openGroupInvitationViewStub.resolved()) openGroupInvitationViewStub.get().setVisibility(View.GONE);
-
- //noinspection ConstantConditions
- documentViewStub.get().setDocument(((MediaMmsMessageRecord) messageRecord).getSlideDeck().getDocumentSlide(), showControls);
- documentViewStub.get().setDocumentClickListener(new ThumbnailClickListener());
- documentViewStub.get().setDownloadClickListener(singleDownloadClickListener);
- documentViewStub.get().setOnLongClickListener(passthroughClickListener);
-
- ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
- ViewUtil.updateLayoutParams(groupSenderHolder, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
-
- footer.setVisibility(VISIBLE);
- } else if (hasThumbnail(messageRecord)) {
- mediaThumbnailStub.get().setVisibility(View.VISIBLE);
- if (audioViewStub.resolved()) audioViewStub.get().setVisibility(View.GONE);
- if (documentViewStub.resolved()) documentViewStub.get().setVisibility(View.GONE);
- if (linkPreviewStub.resolved()) linkPreviewStub.get().setVisibility(GONE);
- if (stickerStub.resolved()) stickerStub.get().setVisibility(View.GONE);
- if (openGroupInvitationViewStub.resolved()) openGroupInvitationViewStub.get().setVisibility(View.GONE);
-
- //noinspection ConstantConditions
- List thumbnailSlides = ((MmsMessageRecord) messageRecord).getSlideDeck().getThumbnailSlides();
- mediaThumbnailStub.get().setImageResource(glideRequests,
- thumbnailSlides,
- showControls,
- false);
- mediaThumbnailStub.get().setThumbnailClickListener(new ThumbnailClickListener());
- mediaThumbnailStub.get().setDownloadClickListener(downloadClickListener);
- mediaThumbnailStub.get().setOnLongClickListener(passthroughClickListener);
- mediaThumbnailStub.get().setOnClickListener(passthroughClickListener);
- mediaThumbnailStub.get().showShade(TextUtils.isEmpty(messageRecord.getDisplayBody(getContext())) && !hasExtraText(messageRecord));
- mediaThumbnailStub.get().setConversationColor(messageRecord.isOutgoing() ? defaultBubbleColor
- : messageRecord.getRecipient().getColor().toConversationColor(context));
- mediaThumbnailStub.get().setBorderless(false);
-
- setThumbnailCorners(messageRecord, previousRecord, nextRecord, isGroupThread);
-
- ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
- ViewUtil.updateLayoutParams(groupSenderHolder, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
-
- footer.setVisibility(VISIBLE);
- } else if (messageRecord.isOpenGroupInvitation()) {
- openGroupInvitationViewStub.get().setVisibility(View.VISIBLE);
- if (mediaThumbnailStub.resolved()) mediaThumbnailStub.get().setVisibility(View.GONE);
- if (audioViewStub.resolved()) audioViewStub.get().setVisibility(View.GONE);
- if (documentViewStub.resolved()) documentViewStub.get().setVisibility(View.GONE);
- if (linkPreviewStub.resolved()) linkPreviewStub.get().setVisibility(GONE);
- if (stickerStub.resolved()) stickerStub.get().setVisibility(View.GONE);
-
- UpdateMessageData updateMessageData = UpdateMessageData.Companion.fromJSON(messageRecord.getBody());
- String name = null, url = null;
- if (updateMessageData.getKind() instanceof UpdateMessageData.Kind.OpenGroupInvitation) {
- UpdateMessageData.Kind.OpenGroupInvitation data = (UpdateMessageData.Kind.OpenGroupInvitation)updateMessageData.getKind();
- name = data.getGroupName();
- url = data.getGroupUrl();
- }
-
- openGroupInvitationViewStub.get().setOpenGroup(name, url, messageRecord.isOutgoing());
- openGroupInvitationViewStub.get().setOnLongClickListener(passthroughClickListener);
-
- bodyText.setVisibility(View.GONE);
-
- ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
- ViewUtil.updateLayoutParams(groupSenderHolder, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
- } else {
- if (mediaThumbnailStub.resolved()) mediaThumbnailStub.get().setVisibility(View.GONE);
- if (audioViewStub.resolved()) audioViewStub.get().setVisibility(View.GONE);
- if (documentViewStub.resolved()) documentViewStub.get().setVisibility(View.GONE);
- if (linkPreviewStub.resolved()) linkPreviewStub.get().setVisibility(GONE);
- if (stickerStub.resolved()) stickerStub.get().setVisibility(View.GONE);
-
- ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
- ViewUtil.updateLayoutParams(groupSenderHolder, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
-
- footer.setVisibility(VISIBLE);
- }
- }
-
- private void setThumbnailCorners(@NonNull MessageRecord current,
- @NonNull Optional previous,
- @NonNull Optional next,
- boolean isGroupThread)
- {
- int defaultRadius = readDimen(R.dimen.message_corner_radius);
- int collapseRadius = readDimen(R.dimen.message_corner_collapse_radius);
-
- int topLeft = defaultRadius;
- int topRight = defaultRadius;
- int bottomLeft = defaultRadius;
- int bottomRight = defaultRadius;
-
- if (isSingularMessage(current, previous, next, isGroupThread)) {
- topLeft = defaultRadius;
- topRight = defaultRadius;
- bottomLeft = defaultRadius;
- bottomRight = defaultRadius;
- } else if (isStartOfMessageCluster(current, previous, isGroupThread)) {
- if (current.isOutgoing()) {
- bottomRight = collapseRadius;
- } else {
- bottomLeft = collapseRadius;
- }
- } else if (isEndOfMessageCluster(current, next, isGroupThread)) {
- if (current.isOutgoing()) {
- topRight = collapseRadius;
- } else {
- topLeft = collapseRadius;
- }
- } else {
- if (current.isOutgoing()) {
- topRight = collapseRadius;
- bottomRight = collapseRadius;
- } else {
- topLeft = collapseRadius;
- bottomLeft = collapseRadius;
- }
- }
-
- if (!TextUtils.isEmpty(current.getDisplayBody(getContext()))) {
- bottomLeft = 0;
- bottomRight = 0;
- }
-
- if (isStartOfMessageCluster(current, previous, isGroupThread) && !current.isOutgoing() && isGroupThread) {
- topLeft = 0;
- topRight = 0;
- }
-
- if (hasQuote(messageRecord)) {
- topLeft = 0;
- topRight = 0;
- }
-
- if (hasLinkPreview(messageRecord) || hasExtraText(messageRecord)) {
- bottomLeft = 0;
- bottomRight = 0;
- }
-
- mediaThumbnailStub.get().setCorners(topLeft, topRight, bottomRight, bottomLeft);
- }
- private void setLinkPreviewCorners(@NonNull MessageRecord current, @NonNull Optional previous, @NonNull Optional next, boolean isGroupThread, boolean bigImage) {
- int defaultRadius = readDimen(R.dimen.message_corner_radius);
- int collapseRadius = readDimen(R.dimen.message_corner_collapse_radius);
-
- if (bigImage) {
- linkPreviewStub.get().setCorners(0, 0);
- } else if (isStartOfMessageCluster(current, previous, isGroupThread) && !current.isOutgoing() && isGroupThread) {
- linkPreviewStub.get().setCorners(0, 0);
- } else if (isSingularMessage(current, previous, next, isGroupThread) || isStartOfMessageCluster(current, previous, isGroupThread)) {
- linkPreviewStub.get().setCorners(defaultRadius, defaultRadius);
- } else if (current.isOutgoing()) {
- linkPreviewStub.get().setCorners(defaultRadius, collapseRadius);
- } else {
- linkPreviewStub.get().setCorners(collapseRadius, defaultRadius);
- }
- }
-
- private void setContactPhoto(@NonNull Recipient recipient) {
- if (messageRecord == null) { return; } // TODO: Figure out how this happens
- LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams)bodyBubble.getLayoutParams();
- int groupThreadMargin = (int)((12 * getResources().getDisplayMetrics().density) + getResources().getDimension(R.dimen.small_profile_picture_size));
- int defaultMargin = 0;
- long threadID = messageRecord.getThreadId();
- Recipient r = DatabaseFactory.getThreadDatabase(context).getRecipientForThreadId(threadID);
- String threadName = r != null ? r.getName() : "";
- boolean isRSSFeed = threadName != null && (threadName.equals("Loki News") || threadName.equals("Session Updates"));
- layoutParams.setMarginStart((groupThread && !isRSSFeed) ? groupThreadMargin : defaultMargin);
- bodyBubble.setLayoutParams(layoutParams);
- if (profilePictureView == null) { return; }
- String publicKey = recipient.getAddress().toString();
- profilePictureView.setPublicKey(publicKey);
- String displayName = recipient.getName();
- profilePictureView.setDisplayName(displayName);
- profilePictureView.setAdditionalPublicKey(null);
- profilePictureView.setGlide(glideRequests);
- profilePictureView.update();
- }
-
- private SpannableString linkifyMessageBody(SpannableString messageBody, boolean shouldLinkifyAllLinks) {
- int linkPattern = Linkify.WEB_URLS | Linkify.EMAIL_ADDRESSES | Linkify.PHONE_NUMBERS;
- boolean hasLinks = Linkify.addLinks(messageBody, shouldLinkifyAllLinks ? linkPattern : 0);
-
- if (hasLinks) {
- Stream.of(messageBody.getSpans(0, messageBody.length(), URLSpan.class))
- .filterNot(url -> LinkPreviewUtil.isLegalUrl(url.getURL()))
- .forEach(messageBody::removeSpan);
-
- URLSpan[] urlSpans = messageBody.getSpans(0, messageBody.length(), URLSpan.class);
-
- for (URLSpan urlSpan : urlSpans) {
- int start = messageBody.getSpanStart(urlSpan);
- int end = messageBody.getSpanEnd(urlSpan);
- messageBody.setSpan(new LongClickCopySpan(urlSpan.getURL()), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
- }
- }
- return messageBody;
- }
-
- private void setStatusIcons(MessageRecord messageRecord) {
- bodyText.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
-
- if (messageRecord.isFailed()) {
- alertView.setFailed();
- } else {
- alertView.setNone();
- }
- }
-
- private void setQuote(@NonNull MessageRecord current, @NonNull Optional previous, @NonNull Optional next, boolean isGroupThread) {
- if (current.isMms() && !current.isMmsNotification() && ((MediaMmsMessageRecord)current).getQuote() != null) {
- Quote quote = ((MediaMmsMessageRecord)current).getQuote();
- //noinspection ConstantConditions
- String quoteBody = MentionUtilities.highlightMentions(quote.getText(), current.getThreadId(), context);
- quoteView.setQuote(glideRequests, quote.getId(), Recipient.from(context, quote.getAuthor(), true), quoteBody, quote.isOriginalMissing(), quote.getAttachment(), conversationRecipient);
- quoteView.setVisibility(View.VISIBLE);
- quoteView.getLayoutParams().width = ViewGroup.LayoutParams.WRAP_CONTENT;
-
- quoteView.setOnClickListener(view -> {
- if (eventListener != null && batchSelected.isEmpty()) {
- eventListener.onQuoteClicked((MmsMessageRecord) current);
- } else {
- passthroughClickListener.onClick(view);
- }
- });
-
- quoteView.setOnLongClickListener(passthroughClickListener);
-
- if (isStartOfMessageCluster(current, previous, isGroupThread)) {
- if (current.isOutgoing()) {
- quoteView.setTopCornerSizes(true, true);
- } else if (isGroupThread) {
- quoteView.setTopCornerSizes(false, false);
- } else {
- quoteView.setTopCornerSizes(true, true);
- }
- } else if (!isSingularMessage(current, previous, next, isGroupThread)) {
- if (current.isOutgoing()) {
- quoteView.setTopCornerSizes(true, false);
- } else {
- quoteView.setTopCornerSizes(false, true);
- }
- }
-
- if (mediaThumbnailStub.resolved()) {
- ViewUtil.setTopMargin(mediaThumbnailStub.get(), readDimen(R.dimen.message_bubble_top_padding));
- }
- } else {
- quoteView.dismiss();
-
- if (mediaThumbnailStub.resolved()) {
- ViewUtil.setTopMargin(mediaThumbnailStub.get(), 0);
- }
- }
- }
-
- private void setGutterSizes(@NonNull MessageRecord current, boolean isGroupThread) {
- if (isGroupThread && current.isOutgoing()) {
- ViewUtil.setLeftMargin(container, readDimen(R.dimen.conversation_group_left_gutter));
- } else if (current.isOutgoing()) {
- ViewUtil.setLeftMargin(container, readDimen(R.dimen.conversation_individual_left_gutter));
- }
- }
-
- private void setFooter(@NonNull MessageRecord current, @NonNull Optional next, @NonNull Locale locale, boolean isGroupThread) {
- ViewUtil.updateLayoutParams(footer, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
-
- footer.setVisibility(GONE);
- stickerFooter.setVisibility(GONE);
- if (mediaThumbnailStub.resolved()) mediaThumbnailStub.get().getFooter().setVisibility(GONE);
-
- boolean differentTimestamps = next.isPresent() && !DateUtils.isSameExtendedRelativeTimestamp(context, locale, next.get().getTimestamp(), current.getTimestamp());
-
- if (current.getExpiresIn() > 0 || current.isPending() ||
- current.isFailed() || differentTimestamps || isEndOfMessageCluster(current, next, isGroupThread))
- {
- ConversationItemFooter activeFooter = getActiveFooter(current);
- activeFooter.setVisibility(VISIBLE);
- activeFooter.setMessageRecord(current, locale);
- }
- }
-
- private ConversationItemFooter getActiveFooter(@NonNull MessageRecord messageRecord) {
- if (hasOnlyThumbnail(messageRecord) && TextUtils.isEmpty(messageRecord.getDisplayBody(getContext()))) {
- return mediaThumbnailStub.get().getFooter();
- } else {
- return footer;
- }
- }
-
- private int readDimen(@DimenRes int dimenId) {
- return context.getResources().getDimensionPixelOffset(dimenId);
- }
-
- private boolean shouldInterceptClicks(MessageRecord messageRecord) {
- return batchSelected.isEmpty() && (messageRecord.isFailed() && !messageRecord.isMmsNotification());
- }
-
- @SuppressLint("SetTextI18n")
- private void setGroupMessageStatus(MessageRecord messageRecord, Recipient recipient) {
- if (groupThread && !messageRecord.isOutgoing()) {
- String sessionID = recipient.getAddress().serialize();
- Contact contact = DatabaseFactory.getSessionContactDatabase(context).getContactWithSessionID(sessionID);
- String displayName;
- if (contact != null) {
- Contact.ContactContext context = (this.conversationRecipient.isOpenGroupRecipient()) ? Contact.ContactContext.OPEN_GROUP : Contact.ContactContext.REGULAR;
- displayName = contact.displayName(context);
- } else {
- displayName = sessionID;
- }
-
- this.groupSender.setText(displayName);
-
- if (recipient.getName() == null && !TextUtils.isEmpty(recipient.getProfileName())) {
- this.groupSenderProfileName.setText("~" + recipient.getProfileName());
- this.groupSenderProfileName.setVisibility(View.VISIBLE);
- } else {
- this.groupSenderProfileName.setText(null);
- this.groupSenderProfileName.setVisibility(View.GONE);
- }
- }
- }
-
- private void setGroupAuthorColor(@NonNull MessageRecord messageRecord) {
- groupSender.setTextColor(ThemeUtil.getThemedColor(context, R.attr.conversation_item_received_text_primary_color));
- groupSenderProfileName.setTextColor(ThemeUtil.getThemedColor(context, R.attr.conversation_item_received_text_primary_color));
- }
-
- private void setAuthor(@NonNull MessageRecord current, @NonNull Optional previous, @NonNull Optional next, boolean isGroupThread) {
- Recipient recipient = DatabaseFactory.getThreadDatabase(context).getRecipientForThreadId(current.getThreadId());
- String threadName = null;
- if (recipient != null) {
- threadName = recipient.getName();
- }
- boolean isRSSFeed = threadName != null && (threadName.equals("Loki News") || threadName.equals("Session Updates"));
- if (isGroupThread && !isRSSFeed && !current.isOutgoing()) {
- contactPhotoHolder.setVisibility(VISIBLE);
-
- if (!previous.isPresent() || previous.get().isUpdate() || !current.getRecipient().getAddress().equals(previous.get().getRecipient().getAddress()) ||
- !DateUtils.isSameDay(previous.get().getTimestamp(), current.getTimestamp()))
- {
- groupSenderHolder.setVisibility(VISIBLE);
- } else {
- groupSenderHolder.setVisibility(GONE);
- }
-
- if (!previous.isPresent() || previous.get().isUpdate() || !current.getRecipient().getAddress().equals(previous.get().getRecipient().getAddress())) {
- profilePictureView.setVisibility(VISIBLE);
- int visibility = View.GONE;
-
- OpenGroupV2 openGroupV2 = DatabaseFactory.getLokiThreadDatabase(context).getOpenGroupChat(messageRecord.getThreadId());
- if (openGroupV2 != null) {
- boolean isModerator = OpenGroupAPIV2.isUserModerator(current.getRecipient().getAddress().toString(), openGroupV2.getRoom(), openGroupV2.getServer());
- visibility = isModerator ? View.VISIBLE : View.GONE;
- }
-
- moderatorIconImageView.setVisibility(visibility);
- } else {
- profilePictureView.setVisibility(GONE);
- moderatorIconImageView.setVisibility(GONE);
-
- }
- } else {
- groupSenderHolder.setVisibility(GONE);
-
- if (contactPhotoHolder != null) {
- contactPhotoHolder.setVisibility(GONE);
- moderatorIconImageView.setVisibility(GONE);
- }
- }
- }
-
- private void setMessageShape(@NonNull MessageRecord current, @NonNull Optional previous, @NonNull Optional next, boolean isGroupThread) {
- int background;
- if (isSingularMessage(current, previous, next, isGroupThread)) {
- background = current.isOutgoing() ? R.drawable.message_bubble_background_sent_alone : R.drawable.message_bubble_background_received_alone;
- } else if (isStartOfMessageCluster(current, previous, isGroupThread)) {
- background = current.isOutgoing() ? R.drawable.message_bubble_background_sent_start : R.drawable.message_bubble_background_received_start;
- } else if (isEndOfMessageCluster(current, next, isGroupThread)) {
- background = current.isOutgoing() ? R.drawable.message_bubble_background_sent_end : R.drawable.message_bubble_background_received_end;
- } else {
- background = current.isOutgoing() ? R.drawable.message_bubble_background_sent_middle : R.drawable.message_bubble_background_received_middle;
- }
-
- bodyBubble.setBackgroundResource(background);
- }
-
- private boolean isStartOfMessageCluster(@NonNull MessageRecord current, @NonNull Optional previous, boolean isGroupThread) {
- if (isGroupThread) {
- return !previous.isPresent() || previous.get().isUpdate() || !DateUtils.isSameDay(current.getTimestamp(), previous.get().getTimestamp()) ||
- !current.getRecipient().getAddress().equals(previous.get().getRecipient().getAddress());
- } else {
- return !previous.isPresent() || previous.get().isUpdate() || !DateUtils.isSameDay(current.getTimestamp(), previous.get().getTimestamp()) ||
- current.isOutgoing() != previous.get().isOutgoing();
- }
- }
-
- private boolean isEndOfMessageCluster(@NonNull MessageRecord current, @NonNull Optional next, boolean isGroupThread) {
- if (isGroupThread) {
- return !next.isPresent() || next.get().isUpdate() || !DateUtils.isSameDay(current.getTimestamp(), next.get().getTimestamp()) ||
- !current.getRecipient().getAddress().equals(next.get().getRecipient().getAddress());
- } else {
- return !next.isPresent() || next.get().isUpdate() || !DateUtils.isSameDay(current.getTimestamp(), next.get().getTimestamp()) ||
- current.isOutgoing() != next.get().isOutgoing();
- }
- }
-
- private boolean isSingularMessage(@NonNull MessageRecord current, @NonNull Optional previous, @NonNull Optional next, boolean isGroupThread) {
- return isStartOfMessageCluster(current, previous, isGroupThread) && isEndOfMessageCluster(current, next, isGroupThread);
- }
-
- private void setMessageSpacing(@NonNull Context context, @NonNull MessageRecord current, @NonNull Optional previous, @NonNull Optional next, boolean isGroupThread) {
- int spacingTop = readDimen(context, R.dimen.conversation_vertical_message_spacing_collapse);
- int spacingBottom = spacingTop;
-
- if (isStartOfMessageCluster(current, previous, isGroupThread)) {
- spacingTop = readDimen(context, R.dimen.conversation_vertical_message_spacing_default);
- }
-
- if (isEndOfMessageCluster(current, next, isGroupThread)) {
- spacingBottom = readDimen(context, R.dimen.conversation_vertical_message_spacing_default);
- }
-
- ViewUtil.setPaddingTop(this, spacingTop);
- ViewUtil.setPaddingBottom(this, spacingBottom);
- }
-
- private int readDimen(@NonNull Context context, @DimenRes int dimenId) {
- return context.getResources().getDimensionPixelOffset(dimenId);
- }
-
- /// Event handlers
-
- private Spannable getLongMessageSpan(@NonNull MessageRecord messageRecord) {
- String message;
- Runnable action;
-
- if (messageRecord.isMms()) {
- TextSlide slide = ((MmsMessageRecord) messageRecord).getSlideDeck().getTextSlide();
-
- if (slide != null && slide.asAttachment().getTransferState() == AttachmentTransferProgress.TRANSFER_PROGRESS_DONE) {
- message = getResources().getString(R.string.ConversationItem_read_more);
- action = () -> eventListener.onMoreTextClicked(conversationRecipient.getAddress(), messageRecord.getId(), messageRecord.isMms());
- } else if (slide != null && slide.asAttachment().getTransferState() == AttachmentTransferProgress.TRANSFER_PROGRESS_STARTED) {
- message = getResources().getString(R.string.ConversationItem_pending);
- action = () -> {};
- } else if (slide != null) {
- message = getResources().getString(R.string.ConversationItem_download_more);
- action = () -> singleDownloadClickListener.onClick(bodyText, slide);
- } else {
- message = getResources().getString(R.string.ConversationItem_read_more);
- action = () -> eventListener.onMoreTextClicked(conversationRecipient.getAddress(), messageRecord.getId(), messageRecord.isMms());
- }
- } else {
- message = getResources().getString(R.string.ConversationItem_read_more);
- action = () -> eventListener.onMoreTextClicked(conversationRecipient.getAddress(), messageRecord.getId(), messageRecord.isMms());
- }
-
- SpannableStringBuilder span = new SpannableStringBuilder(message);
- CharacterStyle style = new ClickableSpan() {
- @Override
- public void onClick(@NonNull View widget) {
- if (eventListener != null && batchSelected.isEmpty()) {
- action.run();
- }
- }
-
- @Override
- public void updateDrawState(@NonNull TextPaint ds) {
- ds.setTypeface(Typeface.DEFAULT_BOLD);
- }
- };
- span.setSpan(style, 0, span.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
- return span;
- }
-
- @Override
- public void onModified(final Recipient modified) {
- Util.runOnMain(() -> {
- setBubbleState(messageRecord);
- setContactPhoto(recipient);
- setGroupMessageStatus(messageRecord, recipient);
- setAudioViewTint(messageRecord, conversationRecipient);
- });
- }
-
- private class LinkPreviewClickListener implements View.OnClickListener {
- @Override
- public void onClick(View view) {
- if (eventListener != null && batchSelected.isEmpty() && messageRecord.isMms() && !((MmsMessageRecord) messageRecord).getLinkPreviews().isEmpty()) {
- eventListener.onLinkPreviewClicked(((MmsMessageRecord) messageRecord).getLinkPreviews().get(0));
- } else {
- passthroughClickListener.onClick(view);
- }
- }
- }
-
- private class LinkPreviewThumbnailClickListener implements SlideClickListener {
- public void onClick(final View v, final Slide slide) {
- if (eventListener != null && batchSelected.isEmpty() && messageRecord.isMms() && !((MmsMessageRecord) messageRecord).getLinkPreviews().isEmpty()) {
- eventListener.onLinkPreviewClicked(((MmsMessageRecord) messageRecord).getLinkPreviews().get(0));
- } else {
- performClick();
- }
- }
- }
-
- private class AttachmentDownloadClickListener implements SlidesClickedListener {
- @Override
- public void onClick(View v, final List slides) {
- Log.i(TAG, "onClick() for attachment download");
- Log.i(TAG, "Scheduling push attachment downloads for " + slides.size() + " items");
-
- for (Slide slide : slides) {
- JobQueue.getShared().add(
- new AttachmentDownloadJob(messageRecord.getId(),
- ((DatabaseAttachment)slide.asAttachment()).getAttachmentId().getRowId())
- );
- }
- }
- }
-
- private class SlideClickPassthroughListener implements SlideClickListener {
-
- private final SlidesClickedListener original;
-
- private SlideClickPassthroughListener(@NonNull SlidesClickedListener original) {
- this.original = original;
- }
-
- @Override
- public void onClick(View v, Slide slide) {
- original.onClick(v, Collections.singletonList(slide));
- }
- }
-
- private class StickerClickListener implements SlideClickListener {
- @Override
- public void onClick(View v, Slide slide) {
- if (shouldInterceptClicks(messageRecord) || !batchSelected.isEmpty()) {
- performClick();
- }
- }
- }
-
- private class ThumbnailClickListener implements SlideClickListener {
- public void onClick(final View v, final Slide slide) {
- if (shouldInterceptClicks(messageRecord) || !batchSelected.isEmpty()) {
- performClick();
- } else if (MediaPreviewActivity.isContentTypeSupported(slide.getContentType()) && slide.getUri() != null) {
- Intent intent = new Intent(context, MediaPreviewActivity.class);
- intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- intent.setDataAndType(slide.getUri(), slide.getContentType());
- intent.putExtra(MediaPreviewActivity.ADDRESS_EXTRA, conversationRecipient.getAddress());
- intent.putExtra(MediaPreviewActivity.OUTGOING_EXTRA, messageRecord.isOutgoing());
- intent.putExtra(MediaPreviewActivity.DATE_EXTRA, messageRecord.getTimestamp());
- intent.putExtra(MediaPreviewActivity.SIZE_EXTRA, slide.asAttachment().getSize());
- intent.putExtra(MediaPreviewActivity.CAPTION_EXTRA, slide.getCaption().orNull());
- intent.putExtra(MediaPreviewActivity.LEFT_IS_RECENT_EXTRA, false);
-
- context.startActivity(intent);
- } else if (slide.getUri() != null) {
- Log.i(TAG, "Clicked: " + slide.getUri() + " , " + slide.getContentType());
- Uri publicUri = PartAuthority.getAttachmentPublicUri(slide.getUri());
- Log.i(TAG, "Public URI: " + publicUri);
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- intent.setDataAndType(PartAuthority.getAttachmentPublicUri(slide.getUri()), slide.getContentType());
- try {
- context.startActivity(intent);
- } catch (ActivityNotFoundException anfe) {
- Log.w(TAG, "No activity existed to view the media.");
- Toast.makeText(context, R.string.ConversationItem_unable_to_open_media, Toast.LENGTH_LONG).show();
- }
- }
- }
- }
-
- private class PassthroughClickListener implements View.OnLongClickListener, View.OnClickListener {
-
- @Override
- public boolean onLongClick(View v) {
- if (bodyText.hasSelection()) {
- return false;
- }
- performLongClick();
- return true;
- }
-
- @Override
- public void onClick(View v) {
- performClick();
- }
- }
-
- private class ClickListener implements View.OnClickListener {
- private OnClickListener parent;
-
- ClickListener(@Nullable OnClickListener parent) {
- this.parent = parent;
- }
-
- public void onClick(View v) {
- if (!shouldInterceptClicks(messageRecord) && parent != null) {
- parent.onClick(v);
- } else if (messageRecord.isFailed()) {
- Intent intent = new Intent(context, MessageDetailsActivity.class);
- intent.putExtra(MessageDetailsActivity.MESSAGE_ID_EXTRA, messageRecord.getId());
- intent.putExtra(MessageDetailsActivity.THREAD_ID_EXTRA, messageRecord.getThreadId());
- intent.putExtra(MessageDetailsActivity.TYPE_EXTRA, messageRecord.isMms() ? MmsSmsDatabase.MMS_TRANSPORT : MmsSmsDatabase.SMS_TRANSPORT);
- intent.putExtra(MessageDetailsActivity.IS_PUSH_GROUP_EXTRA, groupThread);
- intent.putExtra(MessageDetailsActivity.ADDRESS_EXTRA, conversationRecipient.getAddress());
- context.startActivity(intent);
- }
- }
- }
-}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationPopupActivity.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationPopupActivity.java
deleted file mode 100644
index ece1bb784d..0000000000
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationPopupActivity.java
+++ /dev/null
@@ -1,120 +0,0 @@
-package org.thoughtcrime.securesms.conversation;
-
-import android.content.Intent;
-import android.os.Build.VERSION;
-import android.os.Build.VERSION_CODES;
-import android.os.Bundle;
-import androidx.core.app.ActivityOptionsCompat;
-import android.view.Display;
-import android.view.Gravity;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.WindowManager;
-
-import org.session.libsignal.utilities.Log;
-import org.session.libsignal.utilities.ListenableFuture;
-import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2;
-
-import java.util.concurrent.ExecutionException;
-
-import network.loki.messenger.R;
-
-public class ConversationPopupActivity extends ConversationActivity {
-
- private static final String TAG = ConversationPopupActivity.class.getSimpleName();
-
- @Override
- protected void onPreCreate() {
- super.onPreCreate();
- overridePendingTransition(R.anim.slide_from_top, R.anim.slide_to_top);
- }
-
- @Override
- protected void onCreate(Bundle bundle, boolean ready) {
- getWindow().setFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND,
- WindowManager.LayoutParams.FLAG_DIM_BEHIND);
-
- WindowManager.LayoutParams params = getWindow().getAttributes();
- params.alpha = 1.0f;
- params.dimAmount = 0.1f;
- params.gravity = Gravity.TOP;
- getWindow().setAttributes(params);
-
- Display display = getWindowManager().getDefaultDisplay();
- int width = display.getWidth();
- int height = display.getHeight();
-
- if (height > width) getWindow().setLayout((int) (width * .85), (int) (height * .5));
- else getWindow().setLayout((int) (width * .7), (int) (height * .75));
-
- super.onCreate(bundle, ready);
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- composeText.requestFocus();
- quickAttachmentToggle.disable();
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- if (isFinishing()) overridePendingTransition(R.anim.slide_from_top, R.anim.slide_to_top);
- }
-
- @Override
- public boolean onPrepareOptionsMenu(Menu menu) {
- MenuInflater inflater = this.getMenuInflater();
- menu.clear();
-
- inflater.inflate(R.menu.conversation_popup, menu);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case R.id.menu_expand:
- saveDraft().addListener(new ListenableFuture.Listener() {
- @Override
- public void onSuccess(Long result) {
- ActivityOptionsCompat transition = ActivityOptionsCompat.makeScaleUpAnimation(getWindow().getDecorView(), 0, 0, getWindow().getAttributes().width, getWindow().getAttributes().height);
- Intent intent = new Intent(ConversationPopupActivity.this, ConversationActivityV2.class);
- intent.putExtra(ConversationActivityV2.ADDRESS, getRecipient().getAddress());
- intent.putExtra(ConversationActivityV2.THREAD_ID, result);
-
- if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
- startActivity(intent, transition.toBundle());
- } else {
- startActivity(intent);
- overridePendingTransition(R.anim.fade_scale_in, R.anim.slide_to_right);
- }
-
- finish();
- }
-
- @Override
- public void onFailure(ExecutionException e) {
- Log.w(TAG, e);
- }
- });
- return true;
- }
-
- return false;
- }
-
- @Override
- protected void initializeActionBar() {
- super.initializeActionBar();
- getSupportActionBar().setDisplayHomeAsUpEnabled(false);
- }
-
- @Override
- protected void sendComplete(long threadId) {
- super.sendComplete(threadId);
- finish();
- }
-}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationSearchViewModel.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationSearchViewModel.java
deleted file mode 100644
index d24539982d..0000000000
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationSearchViewModel.java
+++ /dev/null
@@ -1,146 +0,0 @@
-package org.thoughtcrime.securesms.conversation;
-
-import android.app.Application;
-import androidx.lifecycle.AndroidViewModel;
-import androidx.lifecycle.LiveData;
-import android.content.Context;
-import androidx.annotation.NonNull;
-
-import org.thoughtcrime.securesms.contacts.ContactAccessor;
-import org.thoughtcrime.securesms.database.CursorList;
-import org.thoughtcrime.securesms.database.DatabaseFactory;
-import org.thoughtcrime.securesms.search.SearchRepository;
-import org.thoughtcrime.securesms.search.model.MessageResult;
-import org.thoughtcrime.securesms.util.CloseableLiveData;
-import org.session.libsession.utilities.Debouncer;
-import org.session.libsession.utilities.Util;
-import org.session.libsession.utilities.concurrent.SignalExecutors;
-
-import java.io.Closeable;
-import java.util.List;
-
-public class ConversationSearchViewModel extends AndroidViewModel {
-
- private final SearchRepository searchRepository;
- private final CloseableLiveData result;
- private final Debouncer debouncer;
-
- private boolean firstSearch;
- private boolean searchOpen;
- private String activeQuery;
- private long activeThreadId;
-
- public ConversationSearchViewModel(@NonNull Application application) {
- super(application);
- Context context = application.getApplicationContext();
- result = new CloseableLiveData<>();
- debouncer = new Debouncer(500);
- searchRepository = new SearchRepository(context,
- DatabaseFactory.getSearchDatabase(context),
- DatabaseFactory.getThreadDatabase(context),
- ContactAccessor.getInstance(),
- SignalExecutors.SERIAL);
- }
-
- LiveData getSearchResults() {
- return result;
- }
-
- void onQueryUpdated(@NonNull String query, long threadId) {
- if (firstSearch && query.length() < 2) {
- result.postValue(new SearchResult(CursorList.emptyList(), 0));
- return;
- }
-
- if (query.equals(activeQuery)) {
- return;
- }
-
- updateQuery(query, threadId);
- }
-
- void onMissingResult() {
- if (activeQuery != null) {
- updateQuery(activeQuery, activeThreadId);
- }
- }
-
- void onMoveUp() {
- debouncer.clear();
-
- CursorList messages = (CursorList) result.getValue().getResults();
- int position = Math.min(result.getValue().getPosition() + 1, messages.size() - 1);
-
- result.setValue(new SearchResult(messages, position), false);
- }
-
- void onMoveDown() {
- debouncer.clear();
-
- CursorList messages = (CursorList) result.getValue().getResults();
- int position = Math.max(result.getValue().getPosition() - 1, 0);
-
- result.setValue(new SearchResult(messages, position), false);
- }
-
-
- void onSearchOpened() {
- searchOpen = true;
- firstSearch = true;
- }
-
- void onSearchClosed() {
- searchOpen = false;
- debouncer.clear();
- result.close();
- }
-
- @Override
- protected void onCleared() {
- super.onCleared();
- result.close();
- }
-
- private void updateQuery(@NonNull String query, long threadId) {
- activeQuery = query;
- activeThreadId = threadId;
-
- debouncer.publish(() -> {
- firstSearch = false;
-
- searchRepository.query(query, threadId, messages -> {
- Util.runOnMain(() -> {
- if (searchOpen && query.equals(activeQuery)) {
- result.setValue(new SearchResult(messages, 0));
- } else {
- messages.close();
- }
- });
- });
- });
- }
-
- static class SearchResult implements Closeable {
-
- private final CursorList results;
- private final int position;
-
- SearchResult(CursorList results, int position) {
- this.results = results;
- this.position = position;
- }
-
- public List getResults() {
- return results;
- }
-
- public int getPosition() {
- return position;
- }
-
- @Override
- public void close() {
- results.close();
- }
- }
-}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationUpdateItem.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationUpdateItem.java
deleted file mode 100644
index 6dfd2fa887..0000000000
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationUpdateItem.java
+++ /dev/null
@@ -1,198 +0,0 @@
-package org.thoughtcrime.securesms.conversation;
-
-import android.content.Context;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffColorFilter;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import androidx.annotation.ColorInt;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import org.session.libsession.messaging.sending_receiving.data_extraction.DataExtractionNotificationInfoMessage;
-import org.session.libsession.utilities.ExpirationUtil;
-import org.session.libsession.utilities.Util;
-import org.session.libsession.utilities.recipients.Recipient;
-import org.session.libsession.utilities.recipients.RecipientModifiedListener;
-import org.session.libsignal.utilities.guava.Optional;
-import org.thoughtcrime.securesms.BindableConversationItem;
-import org.thoughtcrime.securesms.database.model.MessageRecord;
-import org.thoughtcrime.securesms.loki.utilities.GeneralUtilitiesKt;
-import org.thoughtcrime.securesms.mms.GlideRequests;
-import org.thoughtcrime.securesms.util.DateUtils;
-
-import java.util.Locale;
-import java.util.Set;
-
-import network.loki.messenger.R;
-
-//TODO Remove this class.
-public class ConversationUpdateItem extends LinearLayout
- implements RecipientModifiedListener, BindableConversationItem
-{
- private static final String TAG = ConversationUpdateItem.class.getSimpleName();
-
- private Set batchSelected;
-
- private ImageView icon;
- private TextView title;
- private TextView body;
- private TextView date;
- private Recipient sender;
- private MessageRecord messageRecord;
- private Locale locale;
-
- public ConversationUpdateItem(Context context) {
- super(context);
- }
-
- public ConversationUpdateItem(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- @Override
- public void onFinishInflate() {
- super.onFinishInflate();
-
- this.icon = findViewById(R.id.conversation_update_icon);
- this.title = findViewById(R.id.conversation_update_title);
- this.body = findViewById(R.id.conversation_update_body);
- this.date = findViewById(R.id.conversation_update_date);
-
- this.setOnClickListener(new InternalClickListener(null));
- }
-
- @Override
- public void bind(@NonNull MessageRecord messageRecord,
- @NonNull Optional previousMessageRecord,
- @NonNull Optional nextMessageRecord,
- @NonNull GlideRequests glideRequests,
- @NonNull Locale locale,
- @NonNull Set batchSelected,
- @NonNull Recipient conversationRecipient,
- @Nullable String searchQuery,
- boolean pulseUpdate)
- {
- this.batchSelected = batchSelected;
-
- bind(messageRecord, locale);
- }
-
- @Override
- public void setEventListener(@Nullable EventListener listener) {
- // No events to report yet
- }
-
- @Override
- public MessageRecord getMessageRecord() {
- return messageRecord;
- }
-
- private void bind(@NonNull MessageRecord messageRecord, @NonNull Locale locale) {
- this.messageRecord = messageRecord;
- this.sender = messageRecord.getIndividualRecipient();
- this.locale = locale;
-
- this.sender.addListener(this);
-
- if (messageRecord.isCallLog()) setCallRecord(messageRecord);
- else if (messageRecord.isExpirationTimerUpdate()) setTimerRecord(messageRecord);
- else if (messageRecord.isScreenshotNotification()) setDataExtractionRecord(messageRecord, DataExtractionNotificationInfoMessage.Kind.SCREENSHOT);
- else if (messageRecord.isMediaSavedNotification()) setDataExtractionRecord(messageRecord, DataExtractionNotificationInfoMessage.Kind.MEDIA_SAVED);
- else throw new AssertionError("Neither group nor log nor joined.");
-
- if (batchSelected.contains(messageRecord)) setSelected(true);
- else setSelected(false);
- }
-
- private void setCallRecord(MessageRecord messageRecord) {
- if (messageRecord.isIncomingCall()) icon.setImageResource(R.drawable.ic_call_received_grey600_24dp);
- else if (messageRecord.isOutgoingCall()) icon.setImageResource(R.drawable.ic_call_made_grey600_24dp);
- else icon.setImageResource(R.drawable.ic_call_missed_grey600_24dp);
-
- body.setText(messageRecord.getDisplayBody(getContext()));
- date.setText(DateUtils.getExtendedRelativeTimeSpanString(getContext(), locale, messageRecord.getDateReceived()));
-
- title.setVisibility(GONE);
- body.setVisibility(VISIBLE);
- date.setVisibility(View.VISIBLE);
- }
-
- private void setTimerRecord(final MessageRecord messageRecord) {
- @ColorInt int color = GeneralUtilitiesKt.getColorWithID(getResources(), R.color.text, getContext().getTheme());
- if (messageRecord.getExpiresIn() > 0) {
- icon.setImageResource(R.drawable.ic_timer);
- icon.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.MULTIPLY));
- } else {
- icon.setImageResource(R.drawable.ic_timer_disabled);
- icon.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.MULTIPLY));
- }
-
- title.setText(ExpirationUtil.getExpirationDisplayValue(getContext(), (int)(messageRecord.getExpiresIn() / 1000)));
- body.setText(messageRecord.getDisplayBody(getContext()));
-
- title.setVisibility(VISIBLE);
- body.setVisibility(VISIBLE);
- date.setVisibility(GONE);
- }
-
- private void setDataExtractionRecord(final MessageRecord messageRecord, DataExtractionNotificationInfoMessage.Kind kind) {
- @ColorInt int color = GeneralUtilitiesKt.getColorWithID(getResources(), R.color.text, getContext().getTheme());
- if (kind == DataExtractionNotificationInfoMessage.Kind.SCREENSHOT) {
- icon.setImageResource(R.drawable.quick_camera_dark);
- } else if (kind == DataExtractionNotificationInfoMessage.Kind.MEDIA_SAVED) {
- icon.setImageResource(R.drawable.ic_file_download_white_36dp);
- }
- icon.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.MULTIPLY));
-
- body.setText(messageRecord.getDisplayBody(getContext()));
-
- title.setVisibility(VISIBLE);
- body.setVisibility(VISIBLE);
- date.setVisibility(GONE);
- }
-
- private void setTextMessageRecord(MessageRecord messageRecord) {
- body.setText(messageRecord.getDisplayBody(getContext()));
-
- icon.setVisibility(GONE);
- title.setVisibility(GONE);
- body.setVisibility(VISIBLE);
- date.setVisibility(GONE);
- }
-
- @Override
- public void onModified(Recipient recipient) {
- Util.runOnMain(() -> bind(messageRecord, locale));
- }
-
- @Override
- public void setOnClickListener(View.OnClickListener l) {
- super.setOnClickListener(new InternalClickListener(l));
- }
-
- @Override
- public void unbind() {
- if (sender != null) {
- sender.removeListener(this);
- }
- }
-
- private class InternalClickListener implements View.OnClickListener {
-
- @Nullable private final View.OnClickListener parent;
-
- InternalClickListener(@Nullable View.OnClickListener parent) {
- this.parent = parent;
- }
-
- @Override
- public void onClick(View v) {
-
- }
- }
-}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt
index 075caf5f6e..eeb9deacab 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt
@@ -75,7 +75,7 @@ import org.thoughtcrime.securesms.ApplicationContext
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
import org.thoughtcrime.securesms.audio.AudioRecorder
import org.thoughtcrime.securesms.contactshare.SimpleTextWatcher
-import org.thoughtcrime.securesms.conversation.ConversationActivity
+
import org.thoughtcrime.securesms.conversation.v2.dialogs.*
import org.thoughtcrime.securesms.conversation.v2.input_bar.InputBarButton
import org.thoughtcrime.securesms.conversation.v2.input_bar.InputBarDelegate
diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/CreateClosedGroupActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/CreateClosedGroupActivity.kt
index df4f3ce614..9b40454a2b 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/CreateClosedGroupActivity.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/CreateClosedGroupActivity.kt
@@ -17,7 +17,7 @@ import nl.komponents.kovenant.ui.successUi
import org.session.libsession.messaging.sending_receiving.MessageSender
import org.session.libsession.messaging.sending_receiving.groupSizeLimit
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
-import org.thoughtcrime.securesms.conversation.ConversationActivity
+
import org.session.libsession.utilities.Address
import org.session.libsession.utilities.DistributionTypes
import org.thoughtcrime.securesms.database.DatabaseFactory
@@ -138,7 +138,6 @@ class CreateClosedGroupActivity : PassphraseRequiredActionBarActivity(), LoaderM
private fun openConversationActivity(context: Context, threadId: Long, recipient: Recipient) {
val intent = Intent(context, ConversationActivityV2::class.java)
intent.putExtra(ConversationActivityV2.THREAD_ID, threadId)
- intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, DistributionTypes.DEFAULT)
intent.putExtra(ConversationActivityV2.ADDRESS, recipient.address)
context.startActivity(intent)
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/CreatePrivateChatActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/CreatePrivateChatActivity.kt
index 7d429bf223..6eedd97013 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/CreatePrivateChatActivity.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/CreatePrivateChatActivity.kt
@@ -29,7 +29,7 @@ import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsession.utilities.recipients.Recipient
import org.session.libsignal.utilities.PublicKeyValidation
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
-import org.thoughtcrime.securesms.conversation.ConversationActivity
+
import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2
import org.thoughtcrime.securesms.database.DatabaseFactory
import org.thoughtcrime.securesms.loki.fragments.ScanQRCodeWrapperFragment
@@ -114,11 +114,9 @@ class CreatePrivateChatActivity : PassphraseRequiredActionBarActivity(), ScanQRC
val recipient = Recipient.from(this, Address.fromSerialized(hexEncodedPublicKey), false)
val intent = Intent(this, ConversationActivityV2::class.java)
intent.putExtra(ConversationActivityV2.ADDRESS, recipient.address)
- intent.putExtra(ConversationActivity.TEXT_EXTRA, getIntent().getStringExtra(ConversationActivity.TEXT_EXTRA))
intent.setDataAndType(getIntent().data, getIntent().type)
val existingThread = DatabaseFactory.getThreadDatabase(this).getThreadIdIfExistsFor(recipient)
intent.putExtra(ConversationActivityV2.THREAD_ID, existingThread)
- intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, DistributionTypes.DEFAULT)
startActivity(intent)
finish()
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/HomeActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/HomeActivity.kt
index 474d8036de..58eda3cc91 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/HomeActivity.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/HomeActivity.kt
@@ -37,7 +37,7 @@ import org.session.libsignal.utilities.toHexString
import org.session.libsignal.utilities.ThreadUtils
import org.thoughtcrime.securesms.ApplicationContext
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
-import org.thoughtcrime.securesms.conversation.ConversationActivity
+
import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2
import org.thoughtcrime.securesms.database.DatabaseFactory
import org.thoughtcrime.securesms.database.model.ThreadRecord
diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/JoinPublicChatActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/JoinPublicChatActivity.kt
index dc038cc0cb..4ce8bbde04 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/JoinPublicChatActivity.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/JoinPublicChatActivity.kt
@@ -32,7 +32,7 @@ import org.session.libsignal.utilities.Log
import org.session.libsignal.utilities.PublicKeyValidation
import org.thoughtcrime.securesms.BaseActionBarActivity
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
-import org.thoughtcrime.securesms.conversation.ConversationActivity
+
import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2
import org.thoughtcrime.securesms.groups.GroupManager
import org.thoughtcrime.securesms.loki.api.OpenGroupManager
@@ -130,7 +130,6 @@ class JoinPublicChatActivity : PassphraseRequiredActionBarActivity(), ScanQRCode
private fun openConversationActivity(context: Context, threadId: Long, recipient: Recipient) {
val intent = Intent(context, ConversationActivityV2::class.java)
intent.putExtra(ConversationActivityV2.THREAD_ID, threadId)
- intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, DistributionTypes.DEFAULT)
intent.putExtra(ConversationActivityV2.ADDRESS, recipient.address)
context.startActivity(intent)
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/LinkDeviceActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/LinkDeviceActivity.kt
index ec2a76e760..8cfa9d9e3e 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/LinkDeviceActivity.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/LinkDeviceActivity.kt
@@ -14,7 +14,6 @@ import androidx.fragment.app.FragmentPagerAdapter
import androidx.lifecycle.lifecycleScope
import com.google.android.material.snackbar.Snackbar
import kotlinx.android.synthetic.main.activity_link_device.*
-import kotlinx.android.synthetic.main.conversation_activity.*
import kotlinx.android.synthetic.main.fragment_recovery_phrase.*
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/QRCodeActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/QRCodeActivity.kt
index 96d175ef99..2f5638d952 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/QRCodeActivity.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/QRCodeActivity.kt
@@ -14,7 +14,7 @@ import kotlinx.android.synthetic.main.activity_qr_code.*
import kotlinx.android.synthetic.main.fragment_view_my_qr_code.*
import network.loki.messenger.R
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
-import org.thoughtcrime.securesms.conversation.ConversationActivity
+
import org.session.libsession.utilities.Address
import org.session.libsession.utilities.DistributionTypes
import org.thoughtcrime.securesms.database.DatabaseFactory
@@ -56,11 +56,9 @@ class QRCodeActivity : PassphraseRequiredActionBarActivity(), ScanQRCodeWrapperF
val recipient = Recipient.from(this, Address.fromSerialized(hexEncodedPublicKey), false)
val intent = Intent(this, ConversationActivityV2::class.java)
intent.putExtra(ConversationActivityV2.ADDRESS, recipient.address)
- intent.putExtra(ConversationActivity.TEXT_EXTRA, getIntent().getStringExtra(ConversationActivity.TEXT_EXTRA))
intent.setDataAndType(getIntent().data, getIntent().type)
val existingThread = DatabaseFactory.getThreadDatabase(this).getThreadIdIfExistsFor(recipient)
intent.putExtra(ConversationActivityV2.THREAD_ID, existingThread)
- intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, DistributionTypes.DEFAULT)
startActivity(intent)
finish()
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/MediaSendFragment.java b/app/src/main/java/org/thoughtcrime/securesms/mediasend/MediaSendFragment.java
index 0df65497c8..ce1ccb2bbe 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/MediaSendFragment.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/MediaSendFragment.java
@@ -82,7 +82,7 @@ public class MediaSendFragment extends Fragment implements ViewTreeObserver.OnGl
private InputAwareLayout hud;
private View captionAndRail;
private ImageButton sendButton;
- private ComposeText composeText;
+ private ComposeText composeText;
private ViewGroup composeContainer;
private EmojiEditText captionText;
private EmojiToggle emojiToggle;
diff --git a/app/src/main/java/org/thoughtcrime/securesms/notifications/DefaultMessageNotifier.java b/app/src/main/java/org/thoughtcrime/securesms/notifications/DefaultMessageNotifier.java
index a0c1046e07..c02663843e 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/notifications/DefaultMessageNotifier.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/notifications/DefaultMessageNotifier.java
@@ -48,7 +48,7 @@ import org.session.libsignal.utilities.Util;
import org.session.libsignal.utilities.Log;
import org.thoughtcrime.securesms.ApplicationContext;
import org.thoughtcrime.securesms.contactshare.ContactUtil;
-import org.thoughtcrime.securesms.conversation.ConversationActivity;
+
import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo;
diff --git a/app/src/main/java/org/thoughtcrime/securesms/notifications/NotificationItem.java b/app/src/main/java/org/thoughtcrime/securesms/notifications/NotificationItem.java
index c2041a84fa..991989e8da 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/notifications/NotificationItem.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/notifications/NotificationItem.java
@@ -8,7 +8,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.TaskStackBuilder;
-import org.thoughtcrime.securesms.conversation.ConversationActivity;
+
import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2;
import org.thoughtcrime.securesms.mms.SlideDeck;
import org.session.libsession.utilities.recipients.Recipient;
diff --git a/app/src/main/java/org/thoughtcrime/securesms/notifications/NotificationState.java b/app/src/main/java/org/thoughtcrime/securesms/notifications/NotificationState.java
index 9330ec9e37..fe934e229f 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/notifications/NotificationState.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/notifications/NotificationState.java
@@ -7,11 +7,10 @@ import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import org.thoughtcrime.securesms.conversation.ConversationActivity;
-import org.thoughtcrime.securesms.conversation.ConversationPopupActivity;
import org.session.libsignal.utilities.Log;
import org.session.libsession.utilities.recipients.Recipient;
import org.session.libsession.utilities.recipients.Recipient.*;
+import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2;
import java.util.LinkedHashSet;
import java.util.LinkedList;
@@ -167,9 +166,9 @@ public class NotificationState {
public PendingIntent getQuickReplyIntent(Context context, Recipient recipient) {
if (threads.size() != 1) throw new AssertionError("We only support replies to single thread notifications! " + threads.size());
- Intent intent = new Intent(context, ConversationPopupActivity.class);
- intent.putExtra(ConversationActivity.ADDRESS_EXTRA, recipient.getAddress());
- intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, (long)threads.toArray()[0]);
+ Intent intent = new Intent(context, ConversationActivityV2.class);
+ intent.putExtra(ConversationActivityV2.ADDRESS, recipient.getAddress());
+ intent.putExtra(ConversationActivityV2.THREAD_ID, (long)threads.toArray()[0]);
intent.setData((Uri.parse("custom://"+System.currentTimeMillis())));
return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/CommunicationActions.java b/app/src/main/java/org/thoughtcrime/securesms/util/CommunicationActions.java
index e8dd7cd589..9bb71ad5cc 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/util/CommunicationActions.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/util/CommunicationActions.java
@@ -11,7 +11,7 @@ import androidx.core.app.TaskStackBuilder;
import android.text.TextUtils;
import android.widget.Toast;
-import org.thoughtcrime.securesms.conversation.ConversationActivity;
+
import network.loki.messenger.R;
import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2;
@@ -36,11 +36,6 @@ public class CommunicationActions {
Intent intent = new Intent(context, ConversationActivityV2.class);
intent.putExtra(ConversationActivityV2.ADDRESS, recipient.getAddress());
intent.putExtra(ConversationActivityV2.THREAD_ID, threadId);
- intent.putExtra(ConversationActivity.TIMING_EXTRA, System.currentTimeMillis());
-
- if (!TextUtils.isEmpty(text)) {
- intent.putExtra(ConversationActivity.TEXT_EXTRA, text);
- }
if (backStack != null) {
backStack.addNextIntent(intent);
diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/Util.java b/app/src/main/java/org/thoughtcrime/securesms/util/Util.java
index 2384fe482a..41b18f0247 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/util/Util.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/util/Util.java
@@ -19,7 +19,6 @@ package org.thoughtcrime.securesms.util;
import android.annotation.TargetApi;
import android.app.ActivityManager;
import android.content.Context;
-import android.content.pm.PackageManager;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.text.TextUtils;
diff --git a/app/src/main/res/drawable-hdpi/ic_add_white_24dp.png b/app/src/main/res/drawable-hdpi/ic_add_white_24dp.png
deleted file mode 100644
index b48ba111a3..0000000000
Binary files a/app/src/main/res/drawable-hdpi/ic_add_white_24dp.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_call_made_grey600_24dp.png b/app/src/main/res/drawable-hdpi/ic_call_made_grey600_24dp.png
deleted file mode 100644
index 7d0807b0bf..0000000000
Binary files a/app/src/main/res/drawable-hdpi/ic_call_made_grey600_24dp.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_call_missed_grey600_24dp.png b/app/src/main/res/drawable-hdpi/ic_call_missed_grey600_24dp.png
deleted file mode 100644
index 0241747c68..0000000000
Binary files a/app/src/main/res/drawable-hdpi/ic_call_missed_grey600_24dp.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_call_received_grey600_24dp.png b/app/src/main/res/drawable-hdpi/ic_call_received_grey600_24dp.png
deleted file mode 100644
index 5c9a88d126..0000000000
Binary files a/app/src/main/res/drawable-hdpi/ic_call_received_grey600_24dp.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_check_white_24dp.png b/app/src/main/res/drawable-hdpi/ic_check_white_24dp.png
deleted file mode 100644
index 468ea5acd0..0000000000
Binary files a/app/src/main/res/drawable-hdpi/ic_check_white_24dp.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_favorite_grey600_24dp.png b/app/src/main/res/drawable-hdpi/ic_favorite_grey600_24dp.png
deleted file mode 100644
index 2bdad7d3f1..0000000000
Binary files a/app/src/main/res/drawable-hdpi/ic_favorite_grey600_24dp.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_group_grey600_24dp.png b/app/src/main/res/drawable-hdpi/ic_group_grey600_24dp.png
deleted file mode 100644
index 816fe2053f..0000000000
Binary files a/app/src/main/res/drawable-hdpi/ic_group_grey600_24dp.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_menu_login.png b/app/src/main/res/drawable-hdpi/ic_menu_login.png
deleted file mode 100644
index 163f0aa854..0000000000
Binary files a/app/src/main/res/drawable-hdpi/ic_menu_login.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_refresh_white_24dp.png b/app/src/main/res/drawable-hdpi/ic_refresh_white_24dp.png
deleted file mode 100644
index 38cd52d9d5..0000000000
Binary files a/app/src/main/res/drawable-hdpi/ic_refresh_white_24dp.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_security_white_24dp.png b/app/src/main/res/drawable-hdpi/ic_security_white_24dp.png
deleted file mode 100644
index 262800a4d8..0000000000
Binary files a/app/src/main/res/drawable-hdpi/ic_security_white_24dp.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/ic_timer_disabled.png b/app/src/main/res/drawable-hdpi/ic_timer_disabled.png
deleted file mode 100644
index 9e6127d54f..0000000000
Binary files a/app/src/main/res/drawable-hdpi/ic_timer_disabled.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/quick_camera_dark.png b/app/src/main/res/drawable-hdpi/quick_camera_dark.png
deleted file mode 100644
index aa3a3e5717..0000000000
Binary files a/app/src/main/res/drawable-hdpi/quick_camera_dark.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_add_white_24dp.png b/app/src/main/res/drawable-mdpi/ic_add_white_24dp.png
deleted file mode 100644
index eeba9f6696..0000000000
Binary files a/app/src/main/res/drawable-mdpi/ic_add_white_24dp.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_call_made_grey600_24dp.png b/app/src/main/res/drawable-mdpi/ic_call_made_grey600_24dp.png
deleted file mode 100644
index f275722ffe..0000000000
Binary files a/app/src/main/res/drawable-mdpi/ic_call_made_grey600_24dp.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_call_missed_grey600_24dp.png b/app/src/main/res/drawable-mdpi/ic_call_missed_grey600_24dp.png
deleted file mode 100644
index 609ef52617..0000000000
Binary files a/app/src/main/res/drawable-mdpi/ic_call_missed_grey600_24dp.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_call_received_grey600_24dp.png b/app/src/main/res/drawable-mdpi/ic_call_received_grey600_24dp.png
deleted file mode 100644
index 685982d8e2..0000000000
Binary files a/app/src/main/res/drawable-mdpi/ic_call_received_grey600_24dp.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_check_white_24dp.png b/app/src/main/res/drawable-mdpi/ic_check_white_24dp.png
deleted file mode 100644
index 6a93d69194..0000000000
Binary files a/app/src/main/res/drawable-mdpi/ic_check_white_24dp.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_favorite_grey600_24dp.png b/app/src/main/res/drawable-mdpi/ic_favorite_grey600_24dp.png
deleted file mode 100644
index 63f13a33b4..0000000000
Binary files a/app/src/main/res/drawable-mdpi/ic_favorite_grey600_24dp.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_group_grey600_24dp.png b/app/src/main/res/drawable-mdpi/ic_group_grey600_24dp.png
deleted file mode 100644
index 2c69b7cc14..0000000000
Binary files a/app/src/main/res/drawable-mdpi/ic_group_grey600_24dp.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_menu_login.png b/app/src/main/res/drawable-mdpi/ic_menu_login.png
deleted file mode 100644
index 07dd6a510e..0000000000
Binary files a/app/src/main/res/drawable-mdpi/ic_menu_login.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_refresh_white_24dp.png b/app/src/main/res/drawable-mdpi/ic_refresh_white_24dp.png
deleted file mode 100644
index 48e37b75c4..0000000000
Binary files a/app/src/main/res/drawable-mdpi/ic_refresh_white_24dp.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_security_white_24dp.png b/app/src/main/res/drawable-mdpi/ic_security_white_24dp.png
deleted file mode 100644
index 44ee7346e3..0000000000
Binary files a/app/src/main/res/drawable-mdpi/ic_security_white_24dp.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/ic_timer_disabled.png b/app/src/main/res/drawable-mdpi/ic_timer_disabled.png
deleted file mode 100644
index b2cd951a91..0000000000
Binary files a/app/src/main/res/drawable-mdpi/ic_timer_disabled.png and /dev/null differ
diff --git a/app/src/main/res/drawable-mdpi/quick_camera_dark.png b/app/src/main/res/drawable-mdpi/quick_camera_dark.png
deleted file mode 100644
index 4dbf6c77bc..0000000000
Binary files a/app/src/main/res/drawable-mdpi/quick_camera_dark.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_add_white_24dp.png b/app/src/main/res/drawable-xhdpi/ic_add_white_24dp.png
deleted file mode 100644
index 67bb598e52..0000000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_add_white_24dp.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_call_made_grey600_24dp.png b/app/src/main/res/drawable-xhdpi/ic_call_made_grey600_24dp.png
deleted file mode 100644
index 1e609bb5e6..0000000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_call_made_grey600_24dp.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_call_missed_grey600_24dp.png b/app/src/main/res/drawable-xhdpi/ic_call_missed_grey600_24dp.png
deleted file mode 100644
index fb5e2794f0..0000000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_call_missed_grey600_24dp.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_call_received_grey600_24dp.png b/app/src/main/res/drawable-xhdpi/ic_call_received_grey600_24dp.png
deleted file mode 100644
index 91b5587a8a..0000000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_call_received_grey600_24dp.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_check_white_24dp.png b/app/src/main/res/drawable-xhdpi/ic_check_white_24dp.png
deleted file mode 100644
index 9868d19a42..0000000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_check_white_24dp.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_favorite_grey600_24dp.png b/app/src/main/res/drawable-xhdpi/ic_favorite_grey600_24dp.png
deleted file mode 100644
index c4ad1cb303..0000000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_favorite_grey600_24dp.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_group_grey600_24dp.png b/app/src/main/res/drawable-xhdpi/ic_group_grey600_24dp.png
deleted file mode 100644
index 1865da6942..0000000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_group_grey600_24dp.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_menu_login.png b/app/src/main/res/drawable-xhdpi/ic_menu_login.png
deleted file mode 100644
index 17c2e5c39b..0000000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_menu_login.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_refresh_white_24dp.png b/app/src/main/res/drawable-xhdpi/ic_refresh_white_24dp.png
deleted file mode 100644
index 7e5c6ef194..0000000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_refresh_white_24dp.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_security_white_24dp.png b/app/src/main/res/drawable-xhdpi/ic_security_white_24dp.png
deleted file mode 100644
index 7e306c303c..0000000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_security_white_24dp.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_timer_disabled.png b/app/src/main/res/drawable-xhdpi/ic_timer_disabled.png
deleted file mode 100644
index 45165abecc..0000000000
Binary files a/app/src/main/res/drawable-xhdpi/ic_timer_disabled.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xhdpi/quick_camera_dark.png b/app/src/main/res/drawable-xhdpi/quick_camera_dark.png
deleted file mode 100644
index 753805275b..0000000000
Binary files a/app/src/main/res/drawable-xhdpi/quick_camera_dark.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_add_white_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_add_white_24dp.png
deleted file mode 100644
index 0fdced8fce..0000000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_add_white_24dp.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_call_made_grey600_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_call_made_grey600_24dp.png
deleted file mode 100644
index 66a9ff46e8..0000000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_call_made_grey600_24dp.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_call_missed_grey600_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_call_missed_grey600_24dp.png
deleted file mode 100644
index 84c13861cb..0000000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_call_missed_grey600_24dp.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_call_received_grey600_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_call_received_grey600_24dp.png
deleted file mode 100644
index f4be04c671..0000000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_call_received_grey600_24dp.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_check_white_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_check_white_24dp.png
deleted file mode 100644
index 2a7c32de61..0000000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_check_white_24dp.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_favorite_grey600_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_favorite_grey600_24dp.png
deleted file mode 100644
index 11f108dad1..0000000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_favorite_grey600_24dp.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_group_grey600_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_group_grey600_24dp.png
deleted file mode 100644
index 2aa030e4cf..0000000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_group_grey600_24dp.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_refresh_white_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_refresh_white_24dp.png
deleted file mode 100644
index 72128fe690..0000000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_refresh_white_24dp.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_security_white_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_security_white_24dp.png
deleted file mode 100644
index 7bcb2fd013..0000000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_security_white_24dp.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_timer_disabled.png b/app/src/main/res/drawable-xxhdpi/ic_timer_disabled.png
deleted file mode 100644
index fabf9ffdba..0000000000
Binary files a/app/src/main/res/drawable-xxhdpi/ic_timer_disabled.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxhdpi/quick_camera_dark.png b/app/src/main/res/drawable-xxhdpi/quick_camera_dark.png
deleted file mode 100644
index c1a3549bfc..0000000000
Binary files a/app/src/main/res/drawable-xxhdpi/quick_camera_dark.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_check_white_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_check_white_24dp.png
deleted file mode 100644
index d601ca823c..0000000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_check_white_24dp.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_favorite_grey600_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_favorite_grey600_24dp.png
deleted file mode 100644
index e8ee60e7e6..0000000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_favorite_grey600_24dp.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_security_white_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_security_white_24dp.png
deleted file mode 100644
index b1eddbd6c3..0000000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_security_white_24dp.png and /dev/null differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_timer_disabled.png b/app/src/main/res/drawable-xxxhdpi/ic_timer_disabled.png
deleted file mode 100644
index 6301f7bada..0000000000
Binary files a/app/src/main/res/drawable-xxxhdpi/ic_timer_disabled.png and /dev/null differ
diff --git a/app/src/main/res/drawable/compose_divider_background.xml b/app/src/main/res/drawable/compose_divider_background.xml
deleted file mode 100644
index 0046fe4e43..0000000000
--- a/app/src/main/res/drawable/compose_divider_background.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
diff --git a/app/src/main/res/drawable/contact_photo_background.xml b/app/src/main/res/drawable/contact_photo_background.xml
deleted file mode 100644
index ff1153bf2a..0000000000
--- a/app/src/main/res/drawable/contact_photo_background.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
- -
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/drawable/conversation_back_button_background.xml b/app/src/main/res/drawable/conversation_back_button_background.xml
deleted file mode 100644
index f259e83e74..0000000000
--- a/app/src/main/res/drawable/conversation_back_button_background.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
- -
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/drawable/conversation_home_touch_highlight.xml b/app/src/main/res/drawable/conversation_home_touch_highlight.xml
deleted file mode 100644
index 5fbf5ba7d0..0000000000
--- a/app/src/main/res/drawable/conversation_home_touch_highlight.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
- -
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/drawable/conversation_item_background.xml b/app/src/main/res/drawable/conversation_item_background.xml
deleted file mode 100644
index dfae25e4f8..0000000000
--- a/app/src/main/res/drawable/conversation_item_background.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
diff --git a/app/src/main/res/drawable/conversation_item_background_animated.xml b/app/src/main/res/drawable/conversation_item_background_animated.xml
deleted file mode 100644
index 4206e6a57f..0000000000
--- a/app/src/main/res/drawable/conversation_item_background_animated.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
diff --git a/app/src/main/res/drawable/error_round.xml b/app/src/main/res/drawable/error_round.xml
deleted file mode 100644
index 56cc75291a..0000000000
--- a/app/src/main/res/drawable/error_round.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_baseline_arrow_back_compact_24.xml b/app/src/main/res/drawable/ic_baseline_arrow_back_compact_24.xml
deleted file mode 100644
index f632160152..0000000000
--- a/app/src/main/res/drawable/ic_baseline_arrow_back_compact_24.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/ic_baseline_key_24.xml b/app/src/main/res/drawable/ic_baseline_key_24.xml
deleted file mode 100644
index 2316df207c..0000000000
--- a/app/src/main/res/drawable/ic_baseline_key_24.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/ic_baseline_refresh_24.xml b/app/src/main/res/drawable/ic_baseline_refresh_24.xml
deleted file mode 100644
index f2be45bab5..0000000000
--- a/app/src/main/res/drawable/ic_baseline_refresh_24.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/ic_circle_plus.xml b/app/src/main/res/drawable/ic_circle_plus.xml
deleted file mode 100644
index 5e243e5296..0000000000
--- a/app/src/main/res/drawable/ic_circle_plus.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
-
diff --git a/app/src/main/res/drawable/ic_shield.xml b/app/src/main/res/drawable/ic_shield.xml
deleted file mode 100644
index 67a9845daa..0000000000
--- a/app/src/main/res/drawable/ic_shield.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/info_round.xml b/app/src/main/res/drawable/info_round.xml
deleted file mode 100644
index 668eaf3bee..0000000000
--- a/app/src/main/res/drawable/info_round.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/drawable/message_bubble_background.xml b/app/src/main/res/drawable/message_bubble_background.xml
deleted file mode 100644
index 9c4347ae6e..0000000000
--- a/app/src/main/res/drawable/message_bubble_background.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
- -
-
-
-
-
-
-
diff --git a/app/src/main/res/drawable/profile_picture_view_large_foreground.xml b/app/src/main/res/drawable/profile_picture_view_large_foreground.xml
deleted file mode 100644
index e73b68d168..0000000000
--- a/app/src/main/res/drawable/profile_picture_view_large_foreground.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/drawable/profile_picture_view_medium_foreground.xml b/app/src/main/res/drawable/profile_picture_view_medium_foreground.xml
deleted file mode 100644
index 808be8d0e4..0000000000
--- a/app/src/main/res/drawable/profile_picture_view_medium_foreground.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/drawable/profile_picture_view_rss_medium_background.xml b/app/src/main/res/drawable/profile_picture_view_rss_medium_background.xml
deleted file mode 100644
index a12f21fce5..0000000000
--- a/app/src/main/res/drawable/profile_picture_view_rss_medium_background.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/drawable/profile_picture_view_small_foreground.xml b/app/src/main/res/drawable/profile_picture_view_small_foreground.xml
deleted file mode 100644
index 6a46584bf8..0000000000
--- a/app/src/main/res/drawable/profile_picture_view_small_foreground.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/drawable/prominent_dialog_button_background.xml b/app/src/main/res/drawable/prominent_dialog_button_background.xml
deleted file mode 100644
index de3409d482..0000000000
--- a/app/src/main/res/drawable/prominent_dialog_button_background.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/drawable/scroll_to_bottom_button_background.xml b/app/src/main/res/drawable/scroll_to_bottom_button_background.xml
deleted file mode 100644
index 387c75be90..0000000000
--- a/app/src/main/res/drawable/scroll_to_bottom_button_background.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/drawable/session_logo_white.xml b/app/src/main/res/drawable/session_logo_white.xml
deleted file mode 100644
index 9927e8822f..0000000000
--- a/app/src/main/res/drawable/session_logo_white.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/activity_backup_restore.xml b/app/src/main/res/layout/activity_backup_restore.xml
deleted file mode 100644
index af86967c77..0000000000
--- a/app/src/main/res/layout/activity_backup_restore.xml
+++ /dev/null
@@ -1,125 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/conversation_activity.xml b/app/src/main/res/layout/conversation_activity.xml
deleted file mode 100644
index 814d7d6943..0000000000
--- a/app/src/main/res/layout/conversation_activity.xml
+++ /dev/null
@@ -1,235 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/conversation_activity_attachment_editor_stub.xml b/app/src/main/res/layout/conversation_activity_attachment_editor_stub.xml
deleted file mode 100644
index 389f1e2348..0000000000
--- a/app/src/main/res/layout/conversation_activity_attachment_editor_stub.xml
+++ /dev/null
@@ -1,56 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/conversation_activity_emojidrawer_stub.xml b/app/src/main/res/layout/conversation_activity_emojidrawer_stub.xml
deleted file mode 100644
index c52ae1d333..0000000000
--- a/app/src/main/res/layout/conversation_activity_emojidrawer_stub.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
diff --git a/app/src/main/res/layout/conversation_fragment.xml b/app/src/main/res/layout/conversation_fragment.xml
deleted file mode 100644
index ed9b8f5c86..0000000000
--- a/app/src/main/res/layout/conversation_fragment.xml
+++ /dev/null
@@ -1,60 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/conversation_input_panel.xml b/app/src/main/res/layout/conversation_input_panel.xml
deleted file mode 100644
index e628de7561..0000000000
--- a/app/src/main/res/layout/conversation_input_panel.xml
+++ /dev/null
@@ -1,208 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/conversation_item_header.xml b/app/src/main/res/layout/conversation_item_header.xml
deleted file mode 100644
index 588ddd64ef..0000000000
--- a/app/src/main/res/layout/conversation_item_header.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/conversation_item_last_seen.xml b/app/src/main/res/layout/conversation_item_last_seen.xml
deleted file mode 100644
index ced6a1beed..0000000000
--- a/app/src/main/res/layout/conversation_item_last_seen.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/conversation_item_received.xml b/app/src/main/res/layout/conversation_item_received.xml
deleted file mode 100644
index ade3ea2c78..0000000000
--- a/app/src/main/res/layout/conversation_item_received.xml
+++ /dev/null
@@ -1,221 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/conversation_item_received_audio.xml b/app/src/main/res/layout/conversation_item_received_audio.xml
deleted file mode 100644
index 728135ea5f..0000000000
--- a/app/src/main/res/layout/conversation_item_received_audio.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
diff --git a/app/src/main/res/layout/conversation_item_received_document.xml b/app/src/main/res/layout/conversation_item_received_document.xml
deleted file mode 100644
index ae72a23f0a..0000000000
--- a/app/src/main/res/layout/conversation_item_received_document.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
diff --git a/app/src/main/res/layout/conversation_item_received_link_preview.xml b/app/src/main/res/layout/conversation_item_received_link_preview.xml
deleted file mode 100644
index 3c49d6a421..0000000000
--- a/app/src/main/res/layout/conversation_item_received_link_preview.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
diff --git a/app/src/main/res/layout/conversation_item_received_open_group_invitation.xml b/app/src/main/res/layout/conversation_item_received_open_group_invitation.xml
deleted file mode 100644
index 4ef955f1b2..0000000000
--- a/app/src/main/res/layout/conversation_item_received_open_group_invitation.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/conversation_item_received_sticker.xml b/app/src/main/res/layout/conversation_item_received_sticker.xml
deleted file mode 100644
index b162cece3b..0000000000
--- a/app/src/main/res/layout/conversation_item_received_sticker.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
diff --git a/app/src/main/res/layout/conversation_item_received_thumbnail.xml b/app/src/main/res/layout/conversation_item_received_thumbnail.xml
deleted file mode 100644
index 3d93f459af..0000000000
--- a/app/src/main/res/layout/conversation_item_received_thumbnail.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
diff --git a/app/src/main/res/layout/conversation_item_sent.xml b/app/src/main/res/layout/conversation_item_sent.xml
deleted file mode 100644
index b6a7ff291a..0000000000
--- a/app/src/main/res/layout/conversation_item_sent.xml
+++ /dev/null
@@ -1,176 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/conversation_item_sent_audio.xml b/app/src/main/res/layout/conversation_item_sent_audio.xml
deleted file mode 100644
index cb7889fa1f..0000000000
--- a/app/src/main/res/layout/conversation_item_sent_audio.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
diff --git a/app/src/main/res/layout/conversation_item_sent_document.xml b/app/src/main/res/layout/conversation_item_sent_document.xml
deleted file mode 100644
index 2145cfdbf2..0000000000
--- a/app/src/main/res/layout/conversation_item_sent_document.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
diff --git a/app/src/main/res/layout/conversation_item_sent_link_preview.xml b/app/src/main/res/layout/conversation_item_sent_link_preview.xml
deleted file mode 100644
index 3c49d6a421..0000000000
--- a/app/src/main/res/layout/conversation_item_sent_link_preview.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
diff --git a/app/src/main/res/layout/conversation_item_sent_open_group_invitation.xml b/app/src/main/res/layout/conversation_item_sent_open_group_invitation.xml
deleted file mode 100644
index 4ef955f1b2..0000000000
--- a/app/src/main/res/layout/conversation_item_sent_open_group_invitation.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/conversation_item_sent_sticker.xml b/app/src/main/res/layout/conversation_item_sent_sticker.xml
deleted file mode 100644
index b162cece3b..0000000000
--- a/app/src/main/res/layout/conversation_item_sent_sticker.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
diff --git a/app/src/main/res/layout/conversation_item_sent_thumbnail.xml b/app/src/main/res/layout/conversation_item_sent_thumbnail.xml
deleted file mode 100644
index fc7af1b517..0000000000
--- a/app/src/main/res/layout/conversation_item_sent_thumbnail.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
diff --git a/app/src/main/res/layout/conversation_item_update.xml b/app/src/main/res/layout/conversation_item_update.xml
deleted file mode 100644
index 69a49226e3..0000000000
--- a/app/src/main/res/layout/conversation_item_update.xml
+++ /dev/null
@@ -1,80 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/conversation_search_nav.xml b/app/src/main/res/layout/conversation_search_nav.xml
deleted file mode 100644
index d0f4fb99ce..0000000000
--- a/app/src/main/res/layout/conversation_search_nav.xml
+++ /dev/null
@@ -1,68 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/conversation_typing_view.xml b/app/src/main/res/layout/conversation_typing_view.xml
deleted file mode 100644
index e3ba2a3d92..0000000000
--- a/app/src/main/res/layout/conversation_typing_view.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/load_more_header.xml b/app/src/main/res/layout/load_more_header.xml
deleted file mode 100644
index 7b591b3d48..0000000000
--- a/app/src/main/res/layout/load_more_header.xml
+++ /dev/null
@@ -1,47 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/longmessage_bubble_received.xml b/app/src/main/res/layout/longmessage_bubble_received.xml
deleted file mode 100644
index f13704218b..0000000000
--- a/app/src/main/res/layout/longmessage_bubble_received.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/longmessage_bubble_sent.xml b/app/src/main/res/layout/longmessage_bubble_sent.xml
deleted file mode 100644
index 4b28d5ef78..0000000000
--- a/app/src/main/res/layout/longmessage_bubble_sent.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/message_details_activity.xml b/app/src/main/res/layout/message_details_activity.xml
deleted file mode 100644
index 88cfb1061f..0000000000
--- a/app/src/main/res/layout/message_details_activity.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/message_details_header.xml b/app/src/main/res/layout/message_details_header.xml
deleted file mode 100644
index dbd467499b..0000000000
--- a/app/src/main/res/layout/message_details_header.xml
+++ /dev/null
@@ -1,162 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/microphone_recorder_view.xml b/app/src/main/res/layout/microphone_recorder_view.xml
deleted file mode 100644
index e02cbc4c89..0000000000
--- a/app/src/main/res/layout/microphone_recorder_view.xml
+++ /dev/null
@@ -1,65 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/recording_layout.xml b/app/src/main/res/layout/recording_layout.xml
deleted file mode 100644
index 92e8077983..0000000000
--- a/app/src/main/res/layout/recording_layout.xml
+++ /dev/null
@@ -1,104 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/view_input_bar_button.xml b/app/src/main/res/layout/view_input_bar_button.xml
deleted file mode 100644
index 096c616ab6..0000000000
--- a/app/src/main/res/layout/view_input_bar_button.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/view_mention_candidate_selection.xml b/app/src/main/res/layout/view_mention_candidate_selection.xml
deleted file mode 100644
index 00c1439ed4..0000000000
--- a/app/src/main/res/layout/view_mention_candidate_selection.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
\ No newline at end of file
diff --git a/app/src/main/res/menu/conversation.xml b/app/src/main/res/menu/conversation.xml
deleted file mode 100644
index e1f59e00bb..0000000000
--- a/app/src/main/res/menu/conversation.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
diff --git a/app/src/main/res/menu/conversation_block.xml b/app/src/main/res/menu/conversation_block.xml
deleted file mode 100644
index fb4184d59a..0000000000
--- a/app/src/main/res/menu/conversation_block.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
\ No newline at end of file
diff --git a/app/src/main/res/menu/conversation_context.xml b/app/src/main/res/menu/conversation_context.xml
deleted file mode 100644
index 1204fedb31..0000000000
--- a/app/src/main/res/menu/conversation_context.xml
+++ /dev/null
@@ -1,52 +0,0 @@
-
-
diff --git a/app/src/main/res/menu/conversation_copy_session_id.xml b/app/src/main/res/menu/conversation_copy_session_id.xml
deleted file mode 100644
index e74d0b4c24..0000000000
--- a/app/src/main/res/menu/conversation_copy_session_id.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
\ No newline at end of file
diff --git a/app/src/main/res/menu/conversation_expiring_off.xml b/app/src/main/res/menu/conversation_expiring_off.xml
deleted file mode 100644
index 7b0ad285c6..0000000000
--- a/app/src/main/res/menu/conversation_expiring_off.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
\ No newline at end of file
diff --git a/app/src/main/res/menu/conversation_expiring_on.xml b/app/src/main/res/menu/conversation_expiring_on.xml
deleted file mode 100644
index 5dbf88b001..0000000000
--- a/app/src/main/res/menu/conversation_expiring_on.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
\ No newline at end of file
diff --git a/app/src/main/res/menu/conversation_invite_open_group.xml b/app/src/main/res/menu/conversation_invite_open_group.xml
deleted file mode 100644
index 0cef563b7c..0000000000
--- a/app/src/main/res/menu/conversation_invite_open_group.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
\ No newline at end of file
diff --git a/app/src/main/res/menu/conversation_mms_group_options.xml b/app/src/main/res/menu/conversation_mms_group_options.xml
deleted file mode 100644
index 49c10c3e7d..0000000000
--- a/app/src/main/res/menu/conversation_mms_group_options.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
diff --git a/app/src/main/res/menu/conversation_muted.xml b/app/src/main/res/menu/conversation_muted.xml
deleted file mode 100644
index 3b429c04db..0000000000
--- a/app/src/main/res/menu/conversation_muted.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/menu/conversation_popup.xml b/app/src/main/res/menu/conversation_popup.xml
deleted file mode 100644
index f35e1f1ae3..0000000000
--- a/app/src/main/res/menu/conversation_popup.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
diff --git a/app/src/main/res/menu/conversation_push_group_options.xml b/app/src/main/res/menu/conversation_push_group_options.xml
deleted file mode 100644
index 2a7f2713da..0000000000
--- a/app/src/main/res/menu/conversation_push_group_options.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/menu/conversation_unblock.xml b/app/src/main/res/menu/conversation_unblock.xml
deleted file mode 100644
index 6cf3bcbb27..0000000000
--- a/app/src/main/res/menu/conversation_unblock.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/menu/conversation_unmuted.xml b/app/src/main/res/menu/conversation_unmuted.xml
deleted file mode 100644
index 8474edc5cf..0000000000
--- a/app/src/main/res/menu/conversation_unmuted.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/values-notnight-v21/colors.xml b/app/src/main/res/values-notnight-v21/colors.xml
index 84b91b29dd..e1f6dcef95 100644
--- a/app/src/main/res/values-notnight-v21/colors.xml
+++ b/app/src/main/res/values-notnight-v21/colors.xml
@@ -5,7 +5,6 @@
#000000
#f26f55
#606060
- #23000000
#B0B0B0
#FCFCFC
#DFDFDF
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 5f8fa46a6b..feb1432278 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -5,9 +5,7 @@
#FFFFFF
#FF453A
#D8D8D8
- #23FFFFFF
#353535
- #979797
#1B1B1B
#0C0C0C
#171717
@@ -51,7 +49,6 @@
@color/accent
@color/accent
- #882090ea
@color/signal_primary
@color/signal_primary_dark
@@ -76,8 +73,6 @@
#40ffffff
#aaffffff
- #32000000
-
@color/gray65
#22000000
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index 0afc835242..5e5661c5e2 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -20,7 +20,6 @@
76dp
14dp
1dp
- 1dp
60dp
72dp
36dp
@@ -76,8 +75,6 @@
2dp
1.5dp
@dimen/medium_spacing
- @dimen/medium_spacing
- @dimen/small_spacing
@dimen/medium_spacing
24dp
24dp
@@ -86,7 +83,6 @@
240dp
100dp
320dp
- 128dp
175dp
85dp
@@ -99,18 +95,13 @@
4dp
40dp
- @dimen/large_spacing
- 60dp
8dp
1dp
- 36dp
-
2dp
16dp
3
- 10dp
10dp
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 1b561891f7..b6c72f867d 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -213,11 +213,6 @@
- @dimen/small_font_size
-
-
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
index 110ac1dfe2..3c81efc7ee 100644
--- a/app/src/main/res/values/themes.xml
+++ b/app/src/main/res/values/themes.xml
@@ -280,9 +280,4 @@
- true
-
-
diff --git a/app/src/test/java/org/thoughtcrime/securesms/conversation/ConversationAdapterTest.java b/app/src/test/java/org/thoughtcrime/securesms/conversation/ConversationAdapterTest.java
deleted file mode 100644
index 898ae811c6..0000000000
--- a/app/src/test/java/org/thoughtcrime/securesms/conversation/ConversationAdapterTest.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package org.thoughtcrime.securesms.conversation;
-
-import android.database.Cursor;
-
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.thoughtcrime.securesms.BaseUnitTest;
-import org.thoughtcrime.securesms.conversation.ConversationAdapter;
-
-import static org.junit.Assert.*;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyString;
-import static org.powermock.api.mockito.PowerMockito.mock;
-import static org.powermock.api.mockito.PowerMockito.when;
-
-public class ConversationAdapterTest extends BaseUnitTest {
- private Cursor cursor = mock(Cursor.class);
- private ConversationAdapter adapter;
-
- @Override
- @Before
- public void setUp() throws Exception {
- super.setUp();
- adapter = new ConversationAdapter(context, cursor);
- when(cursor.getColumnIndexOrThrow(anyString())).thenReturn(0);
- }
-
- @Test
- @Ignore("TODO: Fix test")
- public void testGetItemIdEquals() throws Exception {
- when(cursor.getString(anyInt())).thenReturn(null).thenReturn("SMS::1::1");
- long firstId = adapter.getItemId(cursor);
- when(cursor.getString(anyInt())).thenReturn(null).thenReturn("MMS::1::1");
- long secondId = adapter.getItemId(cursor);
- assertNotEquals(firstId, secondId);
- when(cursor.getString(anyInt())).thenReturn(null).thenReturn("MMS::2::1");
- long thirdId = adapter.getItemId(cursor);
- assertNotEquals(secondId, thirdId);
- }
-}
\ No newline at end of file
diff --git a/libsession/src/main/res/drawable/ic_person_large.xml b/libsession/src/main/res/drawable/ic_person_large.xml
deleted file mode 100644
index c3324be1de..0000000000
--- a/libsession/src/main/res/drawable/ic_person_large.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
diff --git a/libsession/src/main/res/values/arrays.xml b/libsession/src/main/res/values/arrays.xml
index 6e75269b4c..385c0711f5 100644
--- a/libsession/src/main/res/values/arrays.xml
+++ b/libsession/src/main/res/values/arrays.xml
@@ -119,17 +119,7 @@
- vi
-
- - @string/preferences__light_theme
- - @string/preferences__dark_theme
-
-
-
- - light
- - dark
-
-
-
+
- @string/preferences__green
- @string/preferences__red
- @string/preferences__blue
@@ -200,19 +190,7 @@
- @string/arrays__mute_for_one_year
-
- - @string/arrays__settings_default
- - @string/arrays__enabled
- - @string/arrays__disabled
-
-
-
- - 0
- - 1
- - 2
-
-
-
+
- @string/arrays__name_and_message
- @string/arrays__name_only
- @string/arrays__no_name_or_message
@@ -225,21 +203,8 @@
-
- - image
- - audio
- - video
- - documents
-
-
- - @string/arrays__images
- - @string/arrays__audio
- - @string/arrays__video
- - @string/arrays__documents
-
-
-
+
- image
- audio
@@ -282,20 +247,6 @@
- #000000
-
- - @string/arrays__small
- - @string/arrays__normal
- - @string/arrays__large
- - @string/arrays__extra_large
-
-
-
- - 13
- - 16
- - 20
- - 30
-
-
- @string/arrays__default
- @string/arrays__high
diff --git a/libsession/src/main/res/values/colors.xml b/libsession/src/main/res/values/colors.xml
index b4d8bc2aae..de9d41f309 100644
--- a/libsession/src/main/res/values/colors.xml
+++ b/libsession/src/main/res/values/colors.xml
@@ -5,20 +5,14 @@
#FFFFFF
#FF453A
#D8D8D8
- #23FFFFFF
#353535
- #979797
#1B1B1B
#0C0C0C
#171717
- #121212
#36383C
#323232
#101011
- #212121
@color/unimportant_button_background
- #3F4146
- #000000
#333132
#0AFFFFFF
#1B1B1B
@@ -37,21 +31,16 @@
- #fcac5a
- #78be20
- #419B41
#0a0a0a
@color/accent
@color/accent
- #882090ea
@color/signal_primary
@color/signal_primary_dark
#ffffffff
#ff000000
- #ffeeeeee
- #ffdddddd
#ffe0e0e0
#ffababab
#ffcccccc
@@ -60,28 +49,16 @@
#ff595959
#ff4d4d4d
#ff383838
- #ff111111
- #05000000
- #10000000
- #20000000
#30000000
#40000000
#70000000
#90000000
- #05ffffff
- #10ffffff
- #20ffffff
#30ffffff
#40ffffff
- #60ffffff
- #70ffffff
#aaffffff
#bbffffff
- #ddffffff
-
- #32000000
@color/gray65
#22000000
@@ -89,24 +66,11 @@
#ffffffff
#ff333333
- #ffeeeeee
- #ff333333
- #ffd5d5d5
- #ff222222
- #400099cc
- #40ffffff
-
- @color/conversation_crimson
- @color/core_blue
-
- #99ffffff
#00FFFFFF
#00000000
#88000000
- #44ff2d00
-
@color/transparent_black_90
#121212
diff --git a/libsession/src/main/res/values/core_colors.xml b/libsession/src/main/res/values/core_colors.xml
index 9622208f1f..e99bedcc97 100644
--- a/libsession/src/main/res/values/core_colors.xml
+++ b/libsession/src/main/res/values/core_colors.xml
@@ -1,9 +1,7 @@
#5bca5b
- #4caf50
#f44336
- #ef5350
#ffffff
#000000
diff --git a/libsession/src/main/res/values/dimens.xml b/libsession/src/main/res/values/dimens.xml
index 0ffa369252..8ca4c0aa43 100644
--- a/libsession/src/main/res/values/dimens.xml
+++ b/libsession/src/main/res/values/dimens.xml
@@ -22,7 +22,6 @@
76dp
14dp
1dp
- 1dp
60dp
72dp
36dp
@@ -55,18 +54,10 @@
220dp
110dp
170dp
- 50dp
- 5dp
- 1.5dp
- 5dp
48dp
16sp
12sp
- 200sp
- 2dp
- 2dp
64dp
- 50dp
210dp
105dp
@@ -85,9 +76,6 @@
2dp
1.5dp
@dimen/medium_spacing
- @dimen/medium_spacing
- @dimen/small_spacing
- 32dp
@dimen/medium_spacing
24dp
24dp
@@ -96,7 +84,6 @@
240dp
100dp
320dp
- 128dp
175dp
85dp
@@ -109,39 +96,17 @@
4dp
40dp
- @dimen/large_spacing
- @dimen/large_spacing
- 60dp
8dp
1dp
- 36dp
-
- 10dp
2dp
16dp
3
- 10dp
- 52dp
-
- 8dp
- 88dp
- 8dp
- 96dp
-
- 16dp
-
- 8dp
-
- 150dp
- 70dp
- 16dp
10dp
13sp
- 26sp
@@ -154,18 +119,10 @@
holding the phone, *before* moving it up to your face and having
the prox sensor kick in.) -->
- 34sp
- 20sp
-
- 2dp
-
- 16dp
-
14dp
-96dp
- 16dp
24dp
16sp
16dp
diff --git a/libsession/src/main/res/values/google-playstore-strings.xml b/libsession/src/main/res/values/google-playstore-strings.xml
index 4057c0298d..9054f40731 100644
--- a/libsession/src/main/res/values/google-playstore-strings.xml
+++ b/libsession/src/main/res/values/google-playstore-strings.xml
@@ -15,22 +15,6 @@
- TextSecure Private Messenger
- TextSecure is a messaging app that allows you to take back your privacy while easily communicating with friends.
-
- Using TextSecure, you can communicate instantly while avoiding SMS fees, create groups so that you can chat in real time with all your friends at once, and share media or attachments all with complete privacy. The server never has access to any of your communication and never stores any of your data.
-
- * Private. TextSecure uses an advanced end to end encryption protocol that provides privacy for every message every time.
- * Open Source. TextSecure is Free and Open Source, enabling anyone to verify its security by auditing the code. TextSecure is the only private messenger that uses open source peer-reviewed cryptographic protocols to keep your messages safe.
- * Group Chat. TextSecure allows you to create encrypted groups so you can have private conversations with all your friends at once. Not only are the messages encrypted, but the TextSecure server never has access to any group metadata such as the membership list, group title, or group icon.
- * Fast. The TextSecure protocol is designed to operate in the most constrained environment possible. Using TextSecure, messages are instantly delivered to friends.
-
- Please file any bugs, issues, or feature requests at:
- https://github.com/signalapp/textsecure/issues
-
- More details:
- http://www.whispersystems.org/#encrypted_texts
-
-
+
diff --git a/libsession/src/main/res/values/material_colors.xml b/libsession/src/main/res/values/material_colors.xml
index 7b674a467d..660f6c1718 100644
--- a/libsession/src/main/res/values/material_colors.xml
+++ b/libsession/src/main/res/values/material_colors.xml
@@ -1,275 +1,30 @@
- #FFEBEE
- #FFCDD2
- #EF9A9A
- #E57373
#EF5350
#F44336
- #E53935
- #D32F2F
- #C62828
- #B71C1C
- #FF8A80
- #FF5252
- #FF1744
- #D50000
- #EDE7F6
- #D1C4E9
- #B39DDB
- #9575CD
- #7E57C2
- #673AB7
- #5E35B1
- #512DA8
- #4527A0
- #311B92
- #B388FF
- #7C4DFF
- #651FFF
- #6200EA
-
- #E1F5FE
- #B3E5FC
- #81D4FA
- #4FC3F7
- #29B6F6
- #03A9F4
- #039BE5
- #0288D1
- #0277BD
- #01579B
- #80D8FF
- #40C4FF
- #00B0FF
- #0091EA
-
- #E8F5E9
- #C8E6C9
- #A5D6A7
- #81C784
#66BB6A
#4CAF50
- #43A047
- #388E3C
- #2E7D32
- #1B5E20
- #B9F6CA
- #69F0AE
- #00E676
- #00C853
- #FFFDE7
- #FFF9C4
- #FFF59D
- #FFF176
- #FFEE58
#FFEB3B
- #FDD835
- #FBC02D
- #F9A825
- #F57F17
- #FFFF8D
- #FFFF00
- #FFEA00
- #FFD600
- #FBE9E7
- #FFCCBC
- #FFAB91
- #FF8A65
- #FF7043
- #FF5722
- #F4511E
- #E64A19
- #D84315
- #BF360C
- #FF9E80
- #FF6E40
- #FF3D00
- #DD2C00
-
- #ECEFF1
- #CFD8DC
- #B0BEC5
- #90A4AE
#78909C
- #607D8B
- #546E7A
- #455A64
- #37474F
- #263238
- #FCE4EC
- #F8BBD0
- #F48FB1
- #F06292
- #EC407A
#E91E63
- #D81B60
- #C2185B
- #AD1457
- #880E4F
- #FF80AB
- #FF4081
- #F50057
- #C51162
- #E8EAF6
- #C5CAE9
- #9FA8DA
- #7986CB
- #5C6BC0
- #3F51B5
- #3949AB
- #303F9F
- #283593
- #1A237E
- #8C9EFF
- #536DFE
- #3D5AFE
- #304FFE
-
- #E0F7FA
- #B2EBF2
- #80DEEA
- #4DD0E1
#26C6DA
#00BCD4
- #00ACC1
- #0097A7
- #00838F
- #006064
- #84FFFF
- #18FFFF
- #00E5FF
- #00B8D4
- #F1F8E9
- #DCEDC8
- #C5E1A5
- #AED581
- #9CCC65
- #8BC34A
- #7CB342
- #689F38
- #558B2F
- #33691E
- #CCFF90
- #B2FF59
- #76FF03
- #64DD17
-
- #FFF8E1
- #FFECB3
- #FFE082
- #FFD54F
- #FFCA28
- #FFC107
- #FFB300
- #FFA000
- #FF8F00
- #FF6F00
- #FFE57F
- #FFD740
- #FFC400
- #FFAB00
-
- #EFEBE9
- #D7CCC8
- #BCAAA4
- #A1887F
- #8D6E63
- #795548
- #6D4C41
- #5D4037
- #4E342E
- #3E2723
-
- #F3E5F5
- #E1BEE7
- #CE93D8
- #BA68C8
#AB47BC
- #9C27B0
- #8E24AA
- #7B1FA2
- #6A1B9A
- #4A148C
- #EA80FC
- #E040FB
- #D500F9
- #AA00FF
- #E3F2FD
- #BBDEFB
- #90CAF9
- #64B5F6
#42A5F5
#2196F3
- #1E88E5
- #1976D2
- #1565C0
- #0D47A1
- #82B1FF
- #448AFF
- #2979FF
- #2962FF
- #E0F2F1
- #B2DFDB
- #80CBC4
- #4DB6AC
- #26A69A
- #009688
- #00897B
- #00796B
- #00695C
- #004D40
- #A7FFEB
- #64FFDA
- #1DE9B6
- #00BFA5
-
- #F9FBE7
- #F0F4C3
- #E6EE9C
- #DCE775
- #D4E157
- #CDDC39
- #C0CA33
- #AFB42B
- #9E9D24
- #827717
- #F4FF81
- #EEFF41
- #C6FF00
- #AEEA00
-
- #FFF3E0
- #FFE0B2
- #FFCC80
- #FFB74D
#FFA726
- #FF9800
- #FB8C00
- #F57C00
- #EF6C00
- #E65100
- #FFD180
- #FFAB40
- #FF9100
- #FF6D00
- #FAFAFA
#F5F5F5
- #EEEEEE
- #E0E0E0
#BDBDBD
- #9E9E9E
#757575
- #616161
#424242
#212121
diff --git a/libsession/src/main/res/values/text_styles.xml b/libsession/src/main/res/values/text_styles.xml
index 544cd22c75..5639c60147 100644
--- a/libsession/src/main/res/values/text_styles.xml
+++ b/libsession/src/main/res/values/text_styles.xml
@@ -1,15 +1,5 @@
-
-
-
-
-
-
-
\ No newline at end of file