Align quote behaviour, move the media message outside of text bubble to simplify layouts (#935)

* refactor: remove text from quote model

* refactor: add docs for TODOs where quote text should be refactored

* refactor: remove the references to stored text in the quote and get the quote text from referenced DB lookup

* refactor: drop the quote data from DB

* fix: turns out we can't drop columns using this version of sqlite

* fix: fixing an attachment download bug, fixing up UI issues with quotes and body text

* feat: split off the message attachment UI from message bubble

* refactor: replace media thumbnails with new designs

* refactor: add debug drawing to troubleshoot swipe gesture

* fix: fix the swipe to reply gesture drawing
pull/944/head
Harris 2 years ago committed by GitHub
parent b1e954084c
commit d53752713e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,153 +0,0 @@
package org.thoughtcrime.securesms.components;
import android.content.Context;
import android.util.AttributeSet;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.TextView;
import androidx.annotation.ColorInt;
import androidx.annotation.IdRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.session.libsession.utilities.Stub;
import org.thoughtcrime.securesms.conversation.v2.utilities.KThumbnailView;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.mms.Slide;
import org.thoughtcrime.securesms.mms.SlideClickListener;
import org.thoughtcrime.securesms.mms.SlidesClickedListener;
import java.util.List;
import network.loki.messenger.R;
public class AlbumThumbnailView extends FrameLayout {
private @Nullable SlideClickListener thumbnailClickListener;
private @Nullable SlidesClickedListener downloadClickListener;
private int currentSizeClass;
private ViewGroup albumCellContainer;
private Stub<TransferControlView> transferControls;
private final SlideClickListener defaultThumbnailClickListener = (v, slide) -> {
if (thumbnailClickListener != null) {
thumbnailClickListener.onClick(v, slide);
}
};
private final OnLongClickListener defaultLongClickListener = v -> this.performLongClick();
public AlbumThumbnailView(@NonNull Context context) {
super(context);
initialize();
}
public AlbumThumbnailView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initialize();
}
private void initialize() {
inflate(getContext(), R.layout.album_thumbnail_view, this);
albumCellContainer = findViewById(R.id.albumCellContainer);
transferControls = new Stub<>(findViewById(R.id.albumTransferControlsStub));
}
public void setSlides(@NonNull GlideRequests glideRequests, @NonNull List<Slide> slides, boolean showControls) {
if (slides.size() < 2) {
throw new IllegalStateException("Provided less than two slides.");
}
if (showControls) {
transferControls.get().setShowDownloadText(true);
transferControls.get().setSlides(slides);
transferControls.get().setDownloadClickListener(v -> {
if (downloadClickListener != null) {
downloadClickListener.onClick(v, slides);
}
});
} else {
if (transferControls.resolved()) {
transferControls.get().setVisibility(GONE);
}
}
int sizeClass = Math.min(slides.size(), 6);
if (sizeClass != currentSizeClass) {
inflateLayout(sizeClass);
currentSizeClass = sizeClass;
}
showSlides(glideRequests, slides);
}
public void setCellBackgroundColor(@ColorInt int color) {
ViewGroup cellRoot = findViewById(R.id.album_thumbnail_root);
if (cellRoot != null) {
for (int i = 0; i < cellRoot.getChildCount(); i++) {
cellRoot.getChildAt(i).setBackgroundColor(color);
}
}
}
public void setThumbnailClickListener(@Nullable SlideClickListener listener) {
thumbnailClickListener = listener;
}
public void setDownloadClickListener(@Nullable SlidesClickedListener listener) {
downloadClickListener = listener;
}
private void inflateLayout(int sizeClass) {
albumCellContainer.removeAllViews();
switch (sizeClass) {
case 2:
inflate(getContext(), R.layout.album_thumbnail_2, albumCellContainer);
break;
case 3:
inflate(getContext(), R.layout.album_thumbnail_3, albumCellContainer);
break;
case 4:
inflate(getContext(), R.layout.album_thumbnail_4, albumCellContainer);
break;
case 5:
inflate(getContext(), R.layout.album_thumbnail_5, albumCellContainer);
break;
default:
inflate(getContext(), R.layout.album_thumbnail_many, albumCellContainer);
break;
}
}
private void showSlides(@NonNull GlideRequests glideRequests, @NonNull List<Slide> slides) {
setSlide(glideRequests, slides.get(0), R.id.album_cell_1);
setSlide(glideRequests, slides.get(1), R.id.album_cell_2);
if (slides.size() >= 3) {
setSlide(glideRequests, slides.get(2), R.id.album_cell_3);
}
if (slides.size() >= 4) {
setSlide(glideRequests, slides.get(3), R.id.album_cell_4);
}
if (slides.size() >= 5) {
setSlide(glideRequests, slides.get(4), R.id.album_cell_5);
}
if (slides.size() > 5) {
TextView text = findViewById(R.id.album_cell_overflow_text);
text.setText(getContext().getString(R.string.AlbumThumbnailView_plus, slides.size() - 5));
}
}
private void setSlide(@NonNull GlideRequests glideRequests, @NonNull Slide slide, @IdRes int id) {
}
}

@ -1,158 +0,0 @@
package org.thoughtcrime.securesms.components;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.widget.FrameLayout;
import android.widget.ImageView;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import org.thoughtcrime.securesms.conversation.v2.utilities.ThumbnailView;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.mms.Slide;
import org.thoughtcrime.securesms.mms.SlideClickListener;
import org.thoughtcrime.securesms.mms.SlidesClickedListener;
import org.session.libsession.messaging.sending_receiving.attachments.Attachment;
import org.session.libsession.utilities.ThemeUtil;
import java.util.List;
import network.loki.messenger.R;
public class ConversationItemThumbnail extends FrameLayout {
private ThumbnailView thumbnail;
private AlbumThumbnailView album;
private ImageView shade;
private ConversationItemFooter footer;
private CornerMask cornerMask;
private Outliner outliner;
private boolean borderless;
public ConversationItemThumbnail(Context context) {
super(context);
init(null);
}
public ConversationItemThumbnail(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
public ConversationItemThumbnail(final Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(attrs);
}
private void init(@Nullable AttributeSet attrs) {
inflate(getContext(), R.layout.conversation_item_thumbnail, this);
this.thumbnail = findViewById(R.id.conversation_thumbnail_image);
this.album = findViewById(R.id.conversation_thumbnail_album);
this.shade = findViewById(R.id.conversation_thumbnail_shade);
this.footer = findViewById(R.id.conversation_thumbnail_footer);
this.cornerMask = new CornerMask(this);
this.outliner = new Outliner();
outliner.setColor(ThemeUtil.getThemedColor(getContext(), R.attr.conversation_item_image_outline_color));
if (attrs != null) {
TypedArray typedArray = getContext().getTheme().obtainStyledAttributes(attrs, R.styleable.ConversationItemThumbnail, 0, 0);
typedArray.recycle();
}
}
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
if (!borderless) {
cornerMask.mask(canvas);
if (album.getVisibility() != VISIBLE) {
outliner.draw(canvas);
}
}
}
@Override
public void setFocusable(boolean focusable) {
thumbnail.setFocusable(focusable);
album.setFocusable(focusable);
}
@Override
public void setClickable(boolean clickable) {
thumbnail.setClickable(clickable);
album.setClickable(clickable);
}
@Override
public void setOnLongClickListener(@Nullable OnLongClickListener l) {
thumbnail.setOnLongClickListener(l);
album.setOnLongClickListener(l);
}
public void showShade(boolean show) {
shade.setVisibility(show ? VISIBLE : GONE);
forceLayout();
}
public void setCorners(int topLeft, int topRight, int bottomRight, int bottomLeft) {
cornerMask.setRadii(topLeft, topRight, bottomRight, bottomLeft);
outliner.setRadii(topLeft, topRight, bottomRight, bottomLeft);
}
public void setBorderless(boolean borderless) {
this.borderless = borderless;
}
public ConversationItemFooter getFooter() {
return footer;
}
@UiThread
public void setImageResource(@NonNull GlideRequests glideRequests, @NonNull List<Slide> slides,
boolean showControls, boolean isPreview)
{
if (slides.size() == 1) {
thumbnail.setVisibility(VISIBLE);
album.setVisibility(GONE);
Slide slide = slides.get(0);
Attachment attachment = slide.asAttachment();
thumbnail.setImageResource(glideRequests, slide, showControls, isPreview, attachment.getWidth(), attachment.getHeight());
thumbnail.setLoadIndicatorVisibile(slide.isInProgress());
setTouchDelegate(thumbnail.getTouchDelegate());
} else {
thumbnail.setVisibility(GONE);
album.setVisibility(VISIBLE);
album.setSlides(glideRequests, slides, showControls);
setTouchDelegate(album.getTouchDelegate());
}
}
public void setConversationColor(@ColorInt int color) {
if (album.getVisibility() == VISIBLE) {
album.setCellBackgroundColor(color);
}
}
public void setThumbnailClickListener(SlideClickListener listener) {
thumbnail.setThumbnailClickListener(listener);
album.setThumbnailClickListener(listener);
}
public void setDownloadClickListener(SlidesClickedListener listener) {
thumbnail.setDownloadClickListener(listener);
album.setDownloadClickListener(listener);
}
}

@ -31,7 +31,7 @@ class AlbumThumbnailView : FrameLayout {
private lateinit var binding: AlbumThumbnailViewBinding
companion object {
const val MAX_ALBUM_DISPLAY_SIZE = 5
const val MAX_ALBUM_DISPLAY_SIZE = 3
}
// region Lifecycle
@ -130,18 +130,13 @@ class AlbumThumbnailView : FrameLayout {
fun layoutRes(slideCount: Int) = when (slideCount) {
1 -> R.layout.album_thumbnail_1 // single
2 -> R.layout.album_thumbnail_2// two sidebyside
3 -> R.layout.album_thumbnail_3// three stacked
4 -> R.layout.album_thumbnail_4// four square
5 -> R.layout.album_thumbnail_5//
else -> R.layout.album_thumbnail_many// five or more
else -> R.layout.album_thumbnail_3 // three stacked with additional text
}
fun getThumbnailView(position: Int): KThumbnailView = when (position) {
0 -> binding.albumCellContainer.findViewById<ViewGroup>(R.id.albumCellContainer).findViewById(R.id.album_cell_1)
1 -> binding.albumCellContainer.findViewById<ViewGroup>(R.id.albumCellContainer).findViewById(R.id.album_cell_2)
2 -> binding.albumCellContainer.findViewById<ViewGroup>(R.id.albumCellContainer).findViewById(R.id.album_cell_3)
3 -> binding.albumCellContainer.findViewById<ViewGroup>(R.id.albumCellContainer).findViewById(R.id.album_cell_4)
4 -> binding.albumCellContainer.findViewById<ViewGroup>(R.id.albumCellContainer).findViewById(R.id.album_cell_5)
else -> throw Exception("Can't get thumbnail view for non-existent thumbnail at position: $position")
}

@ -67,18 +67,11 @@ class QuoteView @JvmOverloads constructor(context: Context, attrs: AttributeSet?
fun bind(authorPublicKey: String, body: String?, attachments: SlideDeck?, thread: Recipient,
isOutgoingMessage: Boolean, isOpenGroupInvitation: Boolean, threadID: Long,
isOriginalMissing: Boolean, glide: GlideRequests) {
// Reduce the max body text view line count to 2 if this is a group thread because
// we'll be showing the author text view and we don't want the overall quote view height
// to get too big.
binding.quoteViewBodyTextView.maxLines = if (thread.isGroupRecipient) 2 else 3
// Author
if (thread.isGroupRecipient) {
val author = contactDb.getContactWithSessionID(authorPublicKey)
val authorDisplayName = author?.displayName(Contact.contextForRecipient(thread)) ?: "${authorPublicKey.take(4)}...${authorPublicKey.takeLast(4)}"
binding.quoteViewAuthorTextView.text = authorDisplayName
binding.quoteViewAuthorTextView.setTextColor(getTextColor(isOutgoingMessage))
}
binding.quoteViewAuthorTextView.isVisible = thread.isGroupRecipient
val author = contactDb.getContactWithSessionID(authorPublicKey)
val authorDisplayName = author?.displayName(Contact.contextForRecipient(thread)) ?: "${authorPublicKey.take(4)}...${authorPublicKey.takeLast(4)}"
binding.quoteViewAuthorTextView.text = authorDisplayName
binding.quoteViewAuthorTextView.setTextColor(getTextColor(isOutgoingMessage))
// Body
binding.quoteViewBodyTextView.text = if (isOpenGroupInvitation) resources.getString(R.string.open_group_invitation_view__open_group_invitation) else MentionUtilities.highlightMentions((body ?: "").toSpannable(), threadID, context)
binding.quoteViewBodyTextView.setTextColor(getTextColor(isOutgoingMessage))

@ -13,11 +13,11 @@ import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import androidx.annotation.ColorInt
import androidx.annotation.DrawableRes
import androidx.appcompat.app.AppCompatActivity
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.res.ResourcesCompat
import androidx.core.graphics.BlendModeColorFilterCompat
import androidx.core.graphics.BlendModeCompat
@ -46,7 +46,6 @@ import org.thoughtcrime.securesms.mms.GlideRequests
import org.thoughtcrime.securesms.util.SearchUtil
import org.thoughtcrime.securesms.util.UiModeUtilities
import org.thoughtcrime.securesms.util.getColorWithID
import org.thoughtcrime.securesms.util.toPx
import java.util.Locale
import kotlin.math.roundToInt
@ -76,7 +75,7 @@ class VisibleMessageContentView : LinearLayout {
val color = ThemeUtil.getThemedColor(context, colorID)
val filter = BlendModeColorFilterCompat.createBlendModeColorFilterCompat(color, BlendModeCompat.SRC_IN)
background.colorFilter = filter
setBackground(background)
binding.contentParent.background = background
val onlyBodyMessage = message is SmsMessageRecord
val mediaThumbnailMessage = contactIsTrusted && message is MmsMessageRecord && message.slideDeck.thumbnailSlide != null
@ -94,17 +93,13 @@ class VisibleMessageContentView : LinearLayout {
binding.deletedMessageView.root.isVisible = false
}
// clear the
binding.bodyTextView.text = null
binding.bodyTextView.text = ""
binding.quoteView.root.isVisible = message is MmsMessageRecord && message.quote != null
binding.linkPreviewView.isVisible = message is MmsMessageRecord && message.linkPreviews.isNotEmpty()
val linkPreviewLayout = binding.linkPreviewView.layoutParams
linkPreviewLayout.width = if (mediaThumbnailMessage) 0 else ViewGroup.LayoutParams.WRAP_CONTENT
binding.linkPreviewView.layoutParams = linkPreviewLayout
binding.untrustedView.root.isVisible = !contactIsTrusted && message is MmsMessageRecord && message.quote == null && message.linkPreviews.isEmpty()
binding.voiceMessageView.root.isVisible = contactIsTrusted && message is MmsMessageRecord && message.slideDeck.audioSlide != null
binding.documentView.root.isVisible = contactIsTrusted && message is MmsMessageRecord && message.slideDeck.documentSlide != null
@ -131,9 +126,7 @@ class VisibleMessageContentView : LinearLayout {
delegate?.scrollToMessageIfPossible(quote.id)
}
}
val layoutParams = binding.quoteView.root.layoutParams as MarginLayoutParams
val hasMedia = message.slideDeck.asAttachments().isNotEmpty()
binding.quoteView.root.minWidth = if (hasMedia) 0 else toPx(300,context.resources)
}
if (message is MmsMessageRecord) {
@ -198,6 +191,9 @@ class VisibleMessageContentView : LinearLayout {
isStart = isStartOfMessageCluster,
isEnd = isEndOfMessageCluster
)
val layoutParams = binding.albumThumbnailView.layoutParams as ConstraintLayout.LayoutParams
layoutParams.horizontalBias = if (message.isOutgoing) 1f else 0f
binding.albumThumbnailView.layoutParams = layoutParams
onContentClick.add { event ->
binding.albumThumbnailView.calculateHitObject(event, message, thread)
}
@ -215,11 +211,6 @@ class VisibleMessageContentView : LinearLayout {
binding.bodyTextView.isVisible = message.body.isNotEmpty() && !hideBody
// set it to use constraints if not only a text message, otherwise wrap content to whatever width it wants
val params = binding.bodyTextView.layoutParams
params.width = if (onlyBodyMessage || binding.barrierViewsGone()) ViewGroup.LayoutParams.MATCH_PARENT else 0
binding.bodyTextView.layoutParams = params
if (message.body.isNotEmpty() && !hideBody) {
val color = getTextColor(context, message)
binding.bodyTextView.setTextColor(color)
@ -232,6 +223,9 @@ class VisibleMessageContentView : LinearLayout {
}
}
}
val layoutParams = binding.contentParent.layoutParams as ConstraintLayout.LayoutParams
layoutParams.horizontalBias = if (message.isOutgoing) 1f else 0f
binding.contentParent.layoutParams = layoutParams
}
private fun ViewVisibleMessageContentBinding.barrierViewsGone(): Boolean =

@ -17,7 +17,9 @@ import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import androidx.core.content.res.ResourcesCompat
import androidx.core.os.bundleOf
import androidx.core.view.isInvisible
import androidx.core.view.isVisible
import androidx.core.view.marginBottom
import dagger.hilt.android.AndroidEntryPoint
import network.loki.messenger.R
import network.loki.messenger.databinding.ViewVisibleMessageBinding
@ -41,6 +43,7 @@ import org.thoughtcrime.securesms.util.getColorWithID
import org.thoughtcrime.securesms.util.toDp
import org.thoughtcrime.securesms.util.toPx
import java.util.Date
import java.util.Locale
import javax.inject.Inject
import kotlin.math.abs
import kotlin.math.min
@ -152,18 +155,15 @@ class VisibleMessageView : LinearLayout {
binding.moderatorIconImageView.isVisible = !message.isOutgoing && isModerator
}
}
binding.senderNameTextView.isVisible = isStartOfMessageCluster
val context =
if (thread.isOpenGroupRecipient) ContactContext.OPEN_GROUP else ContactContext.REGULAR
binding.senderNameTextView.text = contact?.displayName(context) ?: senderSessionID
} else {
binding.senderNameTextView.visibility = View.GONE
}
binding.senderNameTextView.isVisible = !message.isOutgoing && (isStartOfMessageCluster && (isGroupThread || snIsSelected))
val contactContext =
if (thread.isOpenGroupRecipient) ContactContext.OPEN_GROUP else ContactContext.REGULAR
binding.senderNameTextView.text = contact?.displayName(contactContext) ?: senderSessionID
// Date break
binding.dateBreakTextView.showDateBreak(message, previous)
// Timestamp
// binding.messageTimestampTextView.text = DateUtils.getDisplayFormattedTimeSpanString(context, Locale.getDefault(), message.timestamp)
// Set inter-message spacing
val showDateBreak = isStartOfMessageCluster || snIsSelected
binding.dateBreakTextView.text = if (showDateBreak) DateUtils.getDisplayFormattedTimeSpanString(context, Locale.getDefault(), message.timestamp) else null
binding.dateBreakTextView.isVisible = showDateBreak
// Message status indicator
val (iconID, iconColor) = getMessageStatusImage(message)
if (iconID != null) {
@ -242,7 +242,7 @@ class VisibleMessageView : LinearLayout {
container.layoutParams = containerParams
if (message.expiresIn > 0 && !message.isPending) {
binding.expirationTimerView.setColorFilter(ResourcesCompat.getColor(resources, R.color.text, context.theme))
binding.expirationTimerView.isVisible = true
binding.expirationTimerView.isInvisible = false
binding.expirationTimerView.setPercentComplete(0.0f)
if (message.expireStarted > 0) {
binding.expirationTimerView.setExpirationTime(message.expireStarted, message.expiresIn)
@ -265,7 +265,7 @@ class VisibleMessageView : LinearLayout {
binding.expirationTimerView.setPercentComplete(0.0f)
}
} else {
binding.expirationTimerView.isVisible = false
binding.expirationTimerView.isInvisible = true
}
container.requestLayout()
}
@ -279,15 +279,19 @@ class VisibleMessageView : LinearLayout {
}
override fun onDraw(canvas: Canvas) {
val spacing = context.resources.getDimensionPixelSize(R.dimen.small_spacing)
val iconSize = toPx(24, context.resources)
val left = binding.expirationTimerViewContainer.left + binding.messageContentView.right + spacing
val top = height - (binding.expirationTimerViewContainer.height / 2) - binding.profilePictureView.root.marginBottom - (iconSize / 2)
val right = left + iconSize
val bottom = top + iconSize
swipeToReplyIconRect.left = left
swipeToReplyIconRect.top = top
swipeToReplyIconRect.right = right
swipeToReplyIconRect.bottom = bottom
if (translationX < 0 && !binding.expirationTimerView.isVisible) {
val spacing = context.resources.getDimensionPixelSize(R.dimen.small_spacing)
val threshold = swipeToReplyThreshold
val iconSize = toPx(24, context.resources)
val bottomVOffset = paddingBottom + binding.messageStatusImageView.height + (binding.messageContentView.height - iconSize) / 2
swipeToReplyIconRect.left = binding.messageContentView.right - binding.messageContentView.paddingEnd + spacing
swipeToReplyIconRect.top = height - bottomVOffset - iconSize
swipeToReplyIconRect.right = binding.messageContentView.right - binding.messageContentView.paddingEnd + iconSize + spacing
swipeToReplyIconRect.bottom = height - bottomVOffset
swipeToReplyIcon.bounds = swipeToReplyIconRect
swipeToReplyIcon.alpha = (255.0f * (min(abs(translationX), threshold) / threshold)).roundToInt()
} else {

@ -62,7 +62,6 @@ import org.thoughtcrime.securesms.database.SmsDatabase.InsertListener
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper
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.NotificationMmsMessageRecord
import org.thoughtcrime.securesms.database.model.Quote
import org.thoughtcrime.securesms.dependencies.DatabaseComponent.Companion.get
@ -479,7 +478,7 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa
)
val quoteId = cursor.getLong(cursor.getColumnIndexOrThrow(QUOTE_ID))
val quoteAuthor = cursor.getString(cursor.getColumnIndexOrThrow(QUOTE_AUTHOR))
val quoteText = cursor.getString(cursor.getColumnIndexOrThrow(QUOTE_BODY))
val quoteText = cursor.getString(cursor.getColumnIndexOrThrow(QUOTE_BODY)) // TODO: this should be the referenced quote
val quoteMissing = cursor.getInt(cursor.getColumnIndexOrThrow(QUOTE_MISSING)) == 1
val quoteAttachments = associatedAttachments
.filter { obj: DatabaseAttachment -> obj.isQuote }
@ -502,7 +501,7 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa
quote = QuoteModel(
quoteId,
fromSerialized(quoteAuthor),
quoteText,
quoteText, // TODO: refactor this to use referenced quote
quoteMissing,
quoteAttachments
)
@ -669,7 +668,6 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa
var quoteAttachments: List<Attachment?>? = LinkedList()
if (retrieved.quote != null) {
contentValues.put(QUOTE_ID, retrieved.quote.id)
contentValues.put(QUOTE_BODY, retrieved.quote.text)
contentValues.put(QUOTE_AUTHOR, retrieved.quote.author.serialize())
contentValues.put(QUOTE_MISSING, if (retrieved.quote.missing) 1 else 0)
quoteAttachments = retrieved.quote.attachments
@ -816,7 +814,6 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa
if (message.outgoingQuote != null) {
contentValues.put(QUOTE_ID, message.outgoingQuote!!.id)
contentValues.put(QUOTE_AUTHOR, message.outgoingQuote!!.author.serialize())
contentValues.put(QUOTE_BODY, message.outgoingQuote!!.text)
contentValues.put(QUOTE_MISSING, if (message.outgoingQuote!!.missing) 1 else 0)
quoteAttachments.addAll(message.outgoingQuote!!.attachments!!)
}
@ -949,31 +946,12 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa
}
val query = queryBuilder.toString()
val db = databaseHelper.writableDatabase
val values = ContentValues(3)
val values = ContentValues(2)
values.put(QUOTE_MISSING, 1)
values.put(QUOTE_BODY, "")
values.put(QUOTE_AUTHOR, "")
db!!.update(TABLE_NAME, values, query, null)
}
fun deleteQuotedFromMessages(toDeleteRecord: MessageRecord?) {
if (toDeleteRecord == null) {
return
}
val query = "$THREAD_ID = ?"
rawQuery(query, arrayOf(toDeleteRecord.threadId.toString())).use { threadMmsCursor ->
val reader = readerFor(threadMmsCursor)
var messageRecord: MmsMessageRecord? = reader.next as MmsMessageRecord?
while (messageRecord != null) {
if (messageRecord.quote != null && toDeleteRecord.dateSent == messageRecord.quote?.id) {
setQuoteMissing(messageRecord.id)
}
messageRecord = reader.next as MmsMessageRecord?
}
reader.close()
}
}
/**
* Delete all the messages in single queries where possible
* @param messageIds a String array representation of regularly Long types representing message IDs
@ -997,13 +975,6 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa
queue(Runnable { attachmentDatabase.deleteAttachmentsForMessages(messageIds) })
val groupReceiptDatabase = get(context).groupReceiptDatabase()
groupReceiptDatabase.deleteRowsForMessages(messageIds)
val toDeleteList: MutableList<MessageRecord> = ArrayList()
getMessages(idsAsString).use { messageCursor ->
while (messageCursor.moveToNext()) {
toDeleteList.add(readerFor(messageCursor).current)
}
}
deleteQuotedFromMessages(toDeleteList)
val database = databaseHelper.writableDatabase
database.delete(TABLE_NAME, idsAsString, null)
notifyConversationListListeners()
@ -1017,13 +988,8 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa
queue(Runnable { attachmentDatabase.deleteAttachmentsForMessage(messageId) })
val groupReceiptDatabase = get(context).groupReceiptDatabase()
groupReceiptDatabase.deleteRowsForMessage(messageId)
var toDelete: MessageRecord?
getMessage(messageId).use { messageCursor ->
toDelete = readerFor(messageCursor).next
}
deleteQuotedFromMessages(toDelete)
val database = databaseHelper.writableDatabase
database!!.delete(TABLE_NAME, ID_WHERE, arrayOf<String>(messageId.toString()))
database!!.delete(TABLE_NAME, ID_WHERE, arrayOf(messageId.toString()))
val threadDeleted = get(context).threadDatabase().update(threadId, false)
notifyConversationListeners(threadId)
notifyStickerListeners()
@ -1287,7 +1253,7 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa
if (message.outgoingQuote != null) Quote(
message.outgoingQuote!!.id,
message.outgoingQuote!!.author,
message.outgoingQuote!!.text,
message.outgoingQuote!!.text, // TODO: use the referenced message's content
message.outgoingQuote!!.missing,
SlideDeck(context, message.outgoingQuote!!.attachments!!)
) else null,
@ -1466,8 +1432,9 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa
private fun getQuote(cursor: Cursor): Quote? {
val quoteId = cursor.getLong(cursor.getColumnIndexOrThrow(QUOTE_ID))
val quoteAuthor = cursor.getString(cursor.getColumnIndexOrThrow(QUOTE_AUTHOR))
val quoteText = cursor.getString(cursor.getColumnIndexOrThrow(QUOTE_BODY))
val quoteMissing = cursor.getInt(cursor.getColumnIndexOrThrow(QUOTE_MISSING)) == 1
val retrievedQuote = get(context).mmsSmsDatabase().getMessageFor(quoteId, quoteAuthor)
val quoteText = retrievedQuote?.body
val quoteMissing = retrievedQuote == null
val attachments = get(context).attachmentDatabase().getAttachment(cursor)
val quoteAttachments: List<Attachment?>? =
Stream.of(attachments).filter { obj: DatabaseAttachment? -> obj!!.isQuote }
@ -1601,7 +1568,6 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa
")) AS " + AttachmentDatabase.ATTACHMENT_JSON_ALIAS
)
private const val RAW_ID_WHERE: String = "$TABLE_NAME._id = ?"
private const val RAW_ID_IN: String = "$TABLE_NAME._id IN (?)"
const val createMessageRequestResponseCommand: String = "ALTER TABLE $TABLE_NAME ADD COLUMN $MESSAGE_REQUEST_RESPONSE INTEGER DEFAULT 0;"
}
}

@ -563,12 +563,6 @@ public class SmsDatabase extends MessagingDatabase {
Log.i("MessageDatabase", "Deleting: " + messageId);
SQLiteDatabase db = databaseHelper.getWritableDatabase();
long threadId = getThreadIdForMessage(messageId);
try {
SmsMessageRecord toDelete = getMessage(messageId);
DatabaseComponent.get(context).mmsDatabase().deleteQuotedFromMessages(toDelete);
} catch (NoSuchMessageException e) {
Log.e(TAG, "Couldn't find message record for messageId "+messageId, e);
}
db.delete(TABLE_NAME, ID_WHERE, new String[] {messageId+""});
boolean threadDeleted = DatabaseComponent.get(context).threadDatabase().update(threadId, false);
notifyConversationListeners(threadId);

@ -258,7 +258,7 @@ public class DefaultMessageNotifier implements MessageNotifier {
Cursor pushCursor = null;
try {
telcoCursor = DatabaseComponent.get(context).mmsSmsDatabase().getUnread();
telcoCursor = DatabaseComponent.get(context).mmsSmsDatabase().getUnread(); // TODO: add a notification specific lighter query here
if ((telcoCursor == null || telcoCursor.isAfterLast()) || !TextSecurePreferences.hasSeenWelcomeScreen(context))
{

@ -17,7 +17,7 @@
android:id="@+id/album_cell_2"
android:layout_width="@dimen/album_2_cell_width"
android:layout_height="@dimen/album_2_total_height"
android:layout_gravity="right|end"
android:layout_gravity="end"
app:thumbnail_radius="0dp"/>
</FrameLayout>

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/album_thumbnail_root"
android:layout_width="@dimen/album_total_width"
android:layout_height="@dimen/album_3_total_height">
@ -16,14 +16,34 @@
android:id="@+id/album_cell_2"
android:layout_width="@dimen/album_3_cell_size_small"
android:layout_height="@dimen/album_3_cell_size_small"
android:layout_gravity="right|end|top"
android:layout_gravity="end|top"
app:thumbnail_radius="0dp"/>
<org.thoughtcrime.securesms.conversation.v2.utilities.KThumbnailView
android:id="@+id/album_cell_3"
android:layout_width="@dimen/album_3_cell_size_small"
android:layout_height="@dimen/album_3_cell_size_small"
android:layout_gravity="right|end|bottom"
app:thumbnail_radius="0dp"/>
<FrameLayout
android:layout_width="@dimen/album_5_cell_size_small"
android:layout_height="@dimen/album_5_cell_size_small"
android:layout_gravity="end|bottom">
<org.thoughtcrime.securesms.conversation.v2.utilities.KThumbnailView
android:id="@+id/album_cell_3"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:layout_gravity="center_horizontal|bottom"
app:thumbnail_radius="0dp"/>
<TextView
tools:visibility="visible"
android:visibility="gone"
android:id="@+id/album_cell_overflow_text"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:gravity="center"
android:textSize="@dimen/text_size"
android:textColor="@color/core_white"
android:background="@color/transparent_black_70"
tools:text="+2" />
</FrameLayout>
</FrameLayout>

@ -1,36 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/album_thumbnail_root"
android:layout_width="@dimen/album_total_width"
android:layout_height="@dimen/album_4_total_height">
<org.thoughtcrime.securesms.conversation.v2.utilities.KThumbnailView
android:id="@+id/album_cell_1"
android:layout_width="@dimen/album_4_cell_size"
android:layout_height="@dimen/album_4_cell_size"
app:thumbnail_radius="0dp"/>
<org.thoughtcrime.securesms.conversation.v2.utilities.KThumbnailView
android:id="@+id/album_cell_2"
android:layout_width="@dimen/album_4_cell_size"
android:layout_height="@dimen/album_4_cell_size"
android:layout_gravity="right|end|top"
app:thumbnail_radius="0dp"/>
<org.thoughtcrime.securesms.conversation.v2.utilities.KThumbnailView
android:id="@+id/album_cell_3"
android:layout_width="@dimen/album_4_cell_size"
android:layout_height="@dimen/album_4_cell_size"
android:layout_gravity="left|start|bottom"
app:thumbnail_radius="0dp"/>
<org.thoughtcrime.securesms.conversation.v2.utilities.KThumbnailView
android:id="@+id/album_cell_4"
android:layout_width="@dimen/album_4_cell_size"
android:layout_height="@dimen/album_4_cell_size"
android:layout_gravity="right|end|bottom"
app:thumbnail_radius="0dp"/>
</FrameLayout>

@ -1,43 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/album_thumbnail_root"
android:layout_width="@dimen/album_total_width"
android:layout_height="@dimen/album_5_total_height">
<org.thoughtcrime.securesms.conversation.v2.utilities.KThumbnailView
android:id="@+id/album_cell_1"
android:layout_width="@dimen/album_5_cell_size_big"
android:layout_height="@dimen/album_5_cell_size_big"
app:thumbnail_radius="0dp"/>
<org.thoughtcrime.securesms.conversation.v2.utilities.KThumbnailView
android:id="@+id/album_cell_2"
android:layout_width="@dimen/album_5_cell_size_big"
android:layout_height="@dimen/album_5_cell_size_big"
android:layout_gravity="right|end|top"
app:thumbnail_radius="0dp"/>
<org.thoughtcrime.securesms.conversation.v2.utilities.KThumbnailView
android:id="@+id/album_cell_3"
android:layout_width="@dimen/album_5_cell_size_small"
android:layout_height="@dimen/album_5_cell_size_small"
android:layout_gravity="left|start|bottom"
app:thumbnail_radius="0dp"/>
<org.thoughtcrime.securesms.conversation.v2.utilities.KThumbnailView
android:id="@+id/album_cell_4"
android:layout_width="@dimen/album_5_cell_size_small"
android:layout_height="@dimen/album_5_cell_size_small"
android:layout_gravity="center_horizontal|bottom"
app:thumbnail_radius="0dp"/>
<org.thoughtcrime.securesms.conversation.v2.utilities.KThumbnailView
android:id="@+id/album_cell_5"
android:layout_width="@dimen/album_5_cell_size_small"
android:layout_height="@dimen/album_5_cell_size_small"
android:layout_gravity="right|end|bottom"
app:thumbnail_radius="0dp"/>
</FrameLayout>

@ -1,61 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/album_thumbnail_root"
android:layout_width="@dimen/album_total_width"
android:layout_height="@dimen/album_5_total_height">
<org.thoughtcrime.securesms.conversation.v2.utilities.KThumbnailView
android:id="@+id/album_cell_1"
android:layout_width="@dimen/album_5_cell_size_big"
android:layout_height="@dimen/album_5_cell_size_big"
app:thumbnail_radius="0dp"/>
<org.thoughtcrime.securesms.conversation.v2.utilities.KThumbnailView
android:id="@+id/album_cell_2"
android:layout_width="@dimen/album_5_cell_size_big"
android:layout_height="@dimen/album_5_cell_size_big"
android:layout_gravity="right|end|top"
app:thumbnail_radius="0dp"/>
<org.thoughtcrime.securesms.conversation.v2.utilities.KThumbnailView
android:id="@+id/album_cell_3"
android:layout_width="@dimen/album_5_cell_size_small"
android:layout_height="@dimen/album_5_cell_size_small"
android:layout_gravity="left|start|bottom"
app:thumbnail_radius="0dp"/>
<org.thoughtcrime.securesms.conversation.v2.utilities.KThumbnailView
android:id="@+id/album_cell_4"
android:layout_width="@dimen/album_5_cell_size_small"
android:layout_height="@dimen/album_5_cell_size_small"
android:layout_gravity="center_horizontal|bottom"
app:thumbnail_radius="0dp"/>
<FrameLayout
android:layout_width="@dimen/album_5_cell_size_small"
android:layout_height="@dimen/album_5_cell_size_small"
android:layout_gravity="right|end|bottom">
<org.thoughtcrime.securesms.conversation.v2.utilities.KThumbnailView
android:id="@+id/album_cell_5"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:layout_gravity="center_horizontal|bottom"
app:thumbnail_radius="0dp"/>
<TextView
android:id="@+id/album_cell_overflow_text"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:gravity="center"
android:textSize="@dimen/text_size"
android:textColor="@color/core_white"
android:background="@color/transparent_black_40"
tools:text="+2" />
</FrameLayout>
</FrameLayout>

@ -1,48 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<merge
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<org.thoughtcrime.securesms.conversation.v2.utilities.ThumbnailView
android:id="@+id/conversation_thumbnail_image"
android:layout_width="@dimen/media_bubble_default_dimens"
android:layout_height="@dimen/media_bubble_default_dimens"
android:adjustViewBounds="true"
android:clickable="false"
android:longClickable="false"
android:scaleType="fitCenter"
android:contentDescription="@string/conversation_item__mms_image_description"
android:visibility="gone"
tools:visibility="visible"
app:thumbnail_radius="1dp"/>
<org.thoughtcrime.securesms.components.AlbumThumbnailView
android:id="@+id/conversation_thumbnail_album"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="false"
android:longClickable="false"
android:contentDescription="@string/conversation_item__mms_image_description"
android:visibility="gone"/>
<ImageView
android:id="@+id/conversation_thumbnail_shade"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_gravity="bottom"
android:visibility="gone"
android:src="@drawable/image_shade" />
<org.thoughtcrime.securesms.components.ConversationItemFooter
android:id="@+id/conversation_thumbnail_footer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layout_marginStart="@dimen/message_bubble_horizontal_padding"
android:layout_marginEnd="@dimen/message_bubble_horizontal_padding"
android:layout_marginBottom="@dimen/message_bubble_bottom_padding"
app:footer_text_color="@android:color/white"
app:footer_icon_color="@android:color/white"/>
</merge>

@ -6,7 +6,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/input_bar_background"
android:minWidth="300dp"
android:minHeight="52dp"
android:paddingVertical="12dp"
android:paddingHorizontal="12dp"
@ -24,6 +23,7 @@
app:layout_constraintTop_toTopOf="parent" />
<RelativeLayout
tools:visibility="visible"
android:id="@+id/quoteViewAttachmentPreviewContainer"
android:layout_width="40dp"
android:layout_height="40dp"
@ -71,30 +71,27 @@
android:textColor="@color/text"
android:textSize="@dimen/small_font_size"
android:textStyle="bold"
android:visibility="gone"
android:maxWidth="240dp"
app:layout_constraintBottom_toTopOf="@+id/quoteViewBodyTextView"
app:layout_constraintEnd_toEndOf="@+id/quoteViewBodyTextView"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintStart_toEndOf="@+id/quoteStartBarrier"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed"
tools:text="Spiderman" />
tools:text="@tools:sample/full_names" />
<TextView
android:id="@+id/quoteViewBodyTextView"
android:layout_width="0dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/medium_spacing"
android:ellipsize="end"
android:maxLines="3"
android:maxLines="1"
android:textColor="@color/text"
android:textSize="@dimen/small_font_size"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/quoteStartBarrier"
app:layout_constraintTop_toBottomOf="@+id/quoteViewAuthorTextView"
app:layout_constraintVertical_chainStyle="packed"
android:maxWidth="240dp"
tools:maxLines="1"
tools:text="@tools:sample/lorem/random" />

@ -31,7 +31,7 @@
android:layout_height="1dp"/>
<include
tools:visibility="gone"
tools:visibility="visible"
android:id="@+id/profilePictureView"
layout="@layout/view_profile_picture"
android:layout_marginBottom="@dimen/small_spacing"
@ -44,6 +44,7 @@
android:layout_gravity="center" />
<ImageView
tools:visibility="visible"
android:visibility="gone"
android:id="@+id/moderatorIconImageView"
android:layout_width="16dp"
@ -87,7 +88,7 @@
<org.thoughtcrime.securesms.conversation.v2.components.ExpirationTimerView
tools:visibility="visible"
android:visibility="gone"
android:visibility="invisible"
android:id="@+id/expirationTimerView"
android:layout_width="12dp"
android:layout_height="12dp"

@ -7,104 +7,120 @@
android:id="@+id/mainContainerConstraint"
xmlns:app="http://schemas.android.com/apk/res-auto">
<!-- Content that will only show on its own -->
<include layout="@layout/view_deleted_message"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:visibility="gone"
android:id="@+id/deletedMessageView"
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/contentParent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<include layout="@layout/view_untrusted_attachment"
tools:visibility="gone"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintEnd_toEndOf="parent"
android:visibility="gone"
android:id="@+id/untrustedView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
>
<!-- Content that will only show on its own -->
<include layout="@layout/view_deleted_message"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:visibility="gone"
android:id="@+id/deletedMessageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<include layout="@layout/view_voice_message"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:visibility="gone"
android:id="@+id/voiceMessageView"
android:layout_width="160dp"
android:layout_height="36dp"/>
<include layout="@layout/view_untrusted_attachment"
tools:visibility="gone"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:visibility="gone"
android:id="@+id/untrustedView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<include layout="@layout/view_open_group_invitation"
tools:visibility="gone"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:visibility="gone"
android:id="@+id/openGroupInvitationView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<include layout="@layout/view_voice_message"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:visibility="gone"
android:id="@+id/voiceMessageView"
android:layout_width="160dp"
android:layout_height="36dp"/>
<include layout="@layout/view_document"
tools:visibility="gone"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:visibility="gone"
android:id="@+id/documentView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<include layout="@layout/view_open_group_invitation"
tools:visibility="gone"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:visibility="gone"
android:id="@+id/openGroupInvitationView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<!-- Content that will show with other elements -->
<include layout="@layout/view_document"
tools:visibility="gone"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:visibility="gone"
android:id="@+id/documentView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<include layout="@layout/view_quote"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:visibility="visible"
android:visibility="gone"
android:id="@+id/quoteView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<org.thoughtcrime.securesms.conversation.v2.messages.LinkPreviewView
app:layout_constraintTop_toBottomOf="@+id/quoteView"
app:layout_constraintStart_toStartOf="parent"
android:visibility="gone"
android:id="@+id/linkPreviewView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<androidx.constraintlayout.widget.Barrier
app:barrierAllowsGoneWidgets="true"
android:id="@+id/bodyBarrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="end"
app:constraint_referenced_ids="albumThumbnailView,linkPreviewView,quoteView,voiceMessageView"/>
<!-- Content that will show with other elements -->
<include layout="@layout/view_quote"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:visibility="visible"
android:visibility="gone"
android:id="@+id/quoteView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<org.thoughtcrime.securesms.conversation.v2.messages.LinkPreviewView
app:layout_constraintTop_toBottomOf="@+id/quoteView"
app:layout_constraintStart_toStartOf="parent"
android:visibility="gone"
android:id="@+id/linkPreviewView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<androidx.constraintlayout.widget.Barrier
app:barrierAllowsGoneWidgets="true"
android:id="@+id/bodyBarrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="end"
app:constraint_referenced_ids="linkPreviewView,quoteView,voiceMessageView"/>
<androidx.constraintlayout.widget.Barrier
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/bodyTopBarrier"
app:constraint_referenced_ids="linkPreviewView,quoteView"
app:barrierDirection="bottom"/>
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
app:layout_constraintHorizontal_bias="0"
tools:visibility="visible"
android:visibility="gone"
app:layout_constraintTop_toBottomOf="@+id/bodyTopBarrier"
app:layout_constraintStart_toStartOf="parent"
android:maxWidth="300dp"
android:paddingHorizontal="12dp"
android:paddingVertical="@dimen/small_spacing"
android:id="@+id/bodyTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<org.thoughtcrime.securesms.conversation.v2.components.AlbumThumbnailView
app:layout_constraintTop_toBottomOf="@+id/linkPreviewView"
app:layout_constraintHorizontal_bias="1"
android:visibility="visible"
android:id="@+id/albumThumbnailView"
android:layout_marginTop="4dp"
app:layout_constraintTop_toBottomOf="@+id/contentParent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:visibility="gone"
android:id="@+id/albumThumbnailView"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
app:layout_constraintHorizontal_bias="0"
android:visibility="gone"
app:layout_constraintTop_toBottomOf="@+id/albumThumbnailView"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="@+id/bodyBarrier"
android:paddingHorizontal="12dp"
android:paddingVertical="@dimen/small_spacing"
android:id="@+id/bodyTextView"
android:layout_width="0dp"
android:maxWidth="300dp"
android:layout_height="wrap_content"/>
</androidx.constraintlayout.widget.ConstraintLayout>

@ -60,6 +60,15 @@ class AttachmentDownloadJob(val attachmentID: Long, val databaseMessageID: Long)
messageDataProvider.setAttachmentState(AttachmentState.FAILED, AttachmentId(attachmentID,0), databaseMessageID)
}
this.handlePermanentFailure(exception)
} else if (exception == Error.DuplicateData) {
attachment?.let { id ->
Log.d("AttachmentDownloadJob", "Setting attachment state = done from duplicate data")
messageDataProvider.setAttachmentState(AttachmentState.DONE, id, databaseMessageID)
} ?: run {
Log.d("AttachmentDownloadJob", "Setting attachment state = done from duplicate data")
messageDataProvider.setAttachmentState(AttachmentState.DONE, AttachmentId(attachmentID,0), databaseMessageID)
}
this.handleSuccess()
} else {
if (failureCount + 1 >= maxFailureCount) {
attachment?.let { id ->

@ -30,7 +30,7 @@ class Quote() {
fun from(signalQuote: SignalQuote?): Quote? {
if (signalQuote == null) { return null }
val attachmentID = (signalQuote.attachments?.firstOrNull() as? DatabaseAttachment)?.attachmentId?.rowId
return Quote(signalQuote.id, signalQuote.author.serialize(), signalQuote.text, attachmentID)
return Quote(signalQuote.id, signalQuote.author.serialize(), "", attachmentID) // TODO: re-add this
}
}

@ -254,9 +254,9 @@ fun MessageReceiver.handleVisibleMessage(message: VisibleMessage,
val messageInfo = messageDataProvider.getMessageForQuote(quote.id, author)
if (messageInfo != null) {
val attachments = if (messageInfo.second) messageDataProvider.getAttachmentsAndLinkPreviewFor(messageInfo.first) else ArrayList()
quoteModel = QuoteModel(quote.id, author, messageDataProvider.getMessageBodyFor(quote.id, quote.author), false, attachments)
quoteModel = QuoteModel(quote.id, author,null,false, attachments)
} else {
quoteModel = QuoteModel(quote.id, author, quote.text, true, PointerAttachment.forPointers(proto.dataMessage.quote.attachmentsList))
quoteModel = QuoteModel(quote.id, author,null, true, PointerAttachment.forPointers(proto.dataMessage.quote.attachmentsList))
}
}
// Parse link preview if needed

@ -4,7 +4,7 @@ import org.session.libsession.messaging.sending_receiving.attachments.Attachment
import org.session.libsession.utilities.Address
class QuoteModel(val id: Long,
val author: Address,
val text: String,
val missing: Boolean,
val attachments: List<Attachment>?)
val author: Address,
val text: String?,
val missing: Boolean,
val attachments: List<Attachment>?)

Loading…
Cancel
Save