mirror of
https://github.com/oxen-io/session-android.git
synced 2025-12-08 06:02:13 +00:00
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
This commit is contained in:
@@ -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))
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user