Add initial support for rendering link previews in text story previews.

fork-5.53.8
Alex Hart 2022-03-16 15:21:21 -03:00 zatwierdzone przez Cody Henthorne
rodzic d504bd593a
commit da1ac5358f
7 zmienionych plików z 51 dodań i 23 usunięć

Wyświetl plik

@ -276,7 +276,7 @@ public class QuoteView extends FrameLayout implements RecipientForeverObserver {
if (!TextUtils.isEmpty(body) || !attachments.containsMediaSlide()) {
if (isTextStory && body != null) {
try {
bodyView.setText(StoryTextPostModel.parseFrom(body.toString()).getText());
bodyView.setText(StoryTextPostModel.parseFrom(body.toString(), id, author.getId()).getText());
} catch (Exception e) {
Log.w(TAG, "Could not parse body of text post.", e);
bodyView.setText("");
@ -326,7 +326,7 @@ public class QuoteView extends FrameLayout implements RecipientForeverObserver {
private void setQuoteAttachment(@NonNull GlideRequests glideRequests, @NonNull CharSequence body, @NonNull SlideDeck slideDeck) {
if (!attachments.containsMediaSlide() && isStoryReply()) {
StoryTextPostModel model = StoryTextPostModel.parseFrom(body.toString());
StoryTextPostModel model = StoryTextPostModel.parseFrom(body.toString(), id, author.getId());
attachmentVideoOverlayView.setVisibility(GONE);
attachmentContainerView.setVisibility(GONE);
thumbnailView.setVisibility(VISIBLE);

Wyświetl plik

@ -14,6 +14,8 @@ import org.thoughtcrime.securesms.linkpreview.LinkPreviewViewModel
import org.thoughtcrime.securesms.mms.GlideApp
import org.thoughtcrime.securesms.mms.ImageSlide
import org.thoughtcrime.securesms.util.Util
import org.thoughtcrime.securesms.util.concurrent.ListenableFuture
import org.thoughtcrime.securesms.util.concurrent.SettableFuture
import org.thoughtcrime.securesms.util.visible
import java.text.DateFormat
import java.text.SimpleDateFormat
@ -33,7 +35,9 @@ class StoryLinkPreviewView @JvmOverloads constructor(
private val title: TextView = findViewById(R.id.link_preview_title)
private val url: TextView = findViewById(R.id.link_preview_url)
fun bind(linkPreview: LinkPreview?, hiddenVisibility: Int = View.INVISIBLE) {
fun bind(linkPreview: LinkPreview?, hiddenVisibility: Int = View.INVISIBLE): ListenableFuture<Boolean> {
var listenableFuture: ListenableFuture<Boolean>? = null
if (linkPreview != null) {
visibility = View.VISIBLE
isClickable = true
@ -43,7 +47,7 @@ class StoryLinkPreviewView @JvmOverloads constructor(
val imageSlide: ImageSlide? = linkPreview.thumbnail.map { ImageSlide(image.context, it) }.orElse(null)
if (imageSlide != null) {
image.setImageResource(GlideApp.with(image), imageSlide, false, false)
listenableFuture = image.setImageResource(GlideApp.with(image), imageSlide, false, false)
image.visible = true
} else {
image.visible = false
@ -56,6 +60,8 @@ class StoryLinkPreviewView @JvmOverloads constructor(
visibility = hiddenVisibility
isClickable = false
}
return listenableFuture ?: SettableFuture(false)
}
fun bind(linkPreviewState: LinkPreviewViewModel.LinkPreviewState, hiddenVisibility: Int = View.INVISIBLE) {

Wyświetl plik

@ -9,8 +9,13 @@ import com.bumptech.glide.load.Options
import com.bumptech.glide.load.ResourceDecoder
import com.bumptech.glide.load.engine.Resource
import com.bumptech.glide.load.resource.SimpleResource
import org.thoughtcrime.securesms.database.SignalDatabase
import org.thoughtcrime.securesms.database.model.MessageRecord
import org.thoughtcrime.securesms.database.model.MmsMessageRecord
import org.thoughtcrime.securesms.database.model.databaseprotos.StoryTextPost
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.recipients.RecipientId
import org.thoughtcrime.securesms.util.Base64
import java.security.MessageDigest
@ -18,19 +23,36 @@ import java.security.MessageDigest
* Glide model to render a StoryTextPost as a bitmap
*/
data class StoryTextPostModel(
private val storyTextPost: StoryTextPost
private val storyTextPost: StoryTextPost,
private val storySentAtMillis: Long,
private val storyAuthor: RecipientId
) : Key {
override fun updateDiskCacheKey(messageDigest: MessageDigest) {
messageDigest.update(storyTextPost.toByteArray())
messageDigest.update(storySentAtMillis.toString().toByteArray())
messageDigest.update(storyAuthor.serialize().toByteArray())
}
val text: String = storyTextPost.body
companion object {
fun parseFrom(messageRecord: MessageRecord): StoryTextPostModel {
return parseFrom(
messageRecord.body,
messageRecord.timestamp,
if (messageRecord.isOutgoing) Recipient.self().id else messageRecord.individualRecipient.id
)
}
@JvmStatic
fun parseFrom(body: String): StoryTextPostModel {
return StoryTextPostModel(StoryTextPost.parseFrom(Base64.decode(body)))
fun parseFrom(body: String, storySentAtMillis: Long, storyAuthor: RecipientId): StoryTextPostModel {
return StoryTextPostModel(
storyTextPost = StoryTextPost.parseFrom(Base64.decode(body)),
storySentAtMillis = storySentAtMillis,
storyAuthor = storyAuthor
)
}
}
@ -44,13 +66,13 @@ data class StoryTextPostModel(
override fun handles(source: StoryTextPostModel, options: Options): Boolean = true
override fun decode(source: StoryTextPostModel, width: Int, height: Int, options: Options): Resource<Bitmap> {
val message = SignalDatabase.mmsSms.getMessageFor(source.storySentAtMillis, source.storyAuthor)
val view = StoryTextPostView(ApplicationDependencies.getApplication())
view.measure(View.MeasureSpec.makeMeasureSpec(RENDER_WIDTH, View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(RENDER_HEIGHT, View.MeasureSpec.EXACTLY))
view.layout(0, 0, view.measuredWidth, view.measuredHeight)
view.bindFromStoryTextPost(source.storyTextPost)
view.bindLinkPreview((message as? MmsMessageRecord)?.linkPreviews?.firstOrNull())
view.invalidate()
view.measure(View.MeasureSpec.makeMeasureSpec(RENDER_WIDTH, View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(RENDER_HEIGHT, View.MeasureSpec.EXACTLY))
view.layout(0, 0, view.measuredWidth, view.measuredHeight)

Wyświetl plik

@ -29,6 +29,7 @@ import org.thoughtcrime.securesms.mediasend.v2.text.TextAlignment
import org.thoughtcrime.securesms.mediasend.v2.text.TextStoryPostCreationState
import org.thoughtcrime.securesms.mediasend.v2.text.TextStoryScale
import org.thoughtcrime.securesms.util.ViewUtil
import org.thoughtcrime.securesms.util.concurrent.ListenableFuture
import org.thoughtcrime.securesms.util.visible
import java.util.Locale
@ -160,8 +161,8 @@ class StoryTextPostView @JvmOverloads constructor(
postAdjustLinkPreviewTranslationY()
}
fun bindLinkPreview(linkPreview: LinkPreview?) {
linkPreviewView.bind(linkPreview, View.GONE)
fun bindLinkPreview(linkPreview: LinkPreview?): ListenableFuture<Boolean> {
return linkPreviewView.bind(linkPreview, View.GONE)
}
fun bindLinkPreviewState(linkPreviewState: LinkPreviewViewModel.LinkPreviewState, hiddenVisibility: Int) {

Wyświetl plik

@ -9,12 +9,10 @@ import org.thoughtcrime.securesms.avatar.view.AvatarView
import org.thoughtcrime.securesms.components.ThumbnailView
import org.thoughtcrime.securesms.components.settings.PreferenceModel
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord
import org.thoughtcrime.securesms.database.model.databaseprotos.StoryTextPost
import org.thoughtcrime.securesms.mms.GlideApp
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.stories.StoryTextPostModel
import org.thoughtcrime.securesms.stories.dialogs.StoryContextMenu
import org.thoughtcrime.securesms.util.Base64
import org.thoughtcrime.securesms.util.DateUtils
import org.thoughtcrime.securesms.util.SpanUtil
import org.thoughtcrime.securesms.util.adapter.mapping.LayoutFactory
@ -111,7 +109,7 @@ object StoriesLandingItem {
avatarView.setStoryRingFromState(model.data.storyViewState)
if (record.storyType.isTextStory) {
storyPreview.setImageResource(GlideApp.with(storyPreview), StoryTextPostModel(StoryTextPost.parseFrom(Base64.decode(record.body))), 0, 0)
storyPreview.setImageResource(GlideApp.with(storyPreview), StoryTextPostModel.parseFrom(record), 0, 0)
} else if (record.slideDeck.thumbnailSlide != null) {
storyPreview.setImageResource(GlideApp.with(storyPreview), record.slideDeck.thumbnailSlide!!, false, true)
} else {
@ -122,7 +120,7 @@ object StoriesLandingItem {
val secondaryRecord = model.data.secondaryStory.messageRecord as MediaMmsMessageRecord
if (secondaryRecord.storyType.isTextStory) {
storyMulti.setImageResource(GlideApp.with(storyPreview), StoryTextPostModel(StoryTextPost.parseFrom(Base64.decode(secondaryRecord.body))), 0, 0)
storyMulti.setImageResource(GlideApp.with(storyPreview), StoryTextPostModel.parseFrom(secondaryRecord), 0, 0)
} else {
storyMulti.setImageResource(GlideApp.with(storyPreview), secondaryRecord.slideDeck.thumbnailSlide!!, false, true)
}

Wyświetl plik

@ -11,11 +11,9 @@ import org.thoughtcrime.securesms.components.menu.SignalContextMenu
import org.thoughtcrime.securesms.components.settings.PreferenceModel
import org.thoughtcrime.securesms.conversation.ConversationMessage
import org.thoughtcrime.securesms.database.model.MmsMessageRecord
import org.thoughtcrime.securesms.database.model.databaseprotos.StoryTextPost
import org.thoughtcrime.securesms.mms.GlideApp
import org.thoughtcrime.securesms.mms.Slide
import org.thoughtcrime.securesms.stories.StoryTextPostModel
import org.thoughtcrime.securesms.util.Base64
import org.thoughtcrime.securesms.util.DateUtils
import org.thoughtcrime.securesms.util.SpanUtil
import org.thoughtcrime.securesms.util.adapter.mapping.LayoutFactory
@ -103,7 +101,7 @@ object MyStoriesItem {
@Suppress("CascadeIf")
if (record.storyType.isTextStory) {
storyPreview.setImageResource(GlideApp.with(storyPreview), StoryTextPostModel(StoryTextPost.parseFrom(Base64.decode(record.body))), 0, 0)
storyPreview.setImageResource(GlideApp.with(storyPreview), StoryTextPostModel.parseFrom(record), 0, 0)
} else if (thumbnail != null) {
storyPreview.setImageResource(GlideApp.with(itemView), thumbnail, false, true)
} else {

Wyświetl plik

@ -21,10 +21,13 @@ class StoryViewerActivity : PassphraseRequiredActivity() {
if (savedInstanceState == null) {
supportFragmentManager.beginTransaction()
.replace(R.id.fragment_container, StoryViewerFragment.create(
intent.getParcelableExtra(ARG_START_RECIPIENT_ID)!!,
intent.getLongExtra(ARG_START_STORY_ID, -1L)
))
.replace(
R.id.fragment_container,
StoryViewerFragment.create(
intent.getParcelableExtra(ARG_START_RECIPIENT_ID)!!,
intent.getLongExtra(ARG_START_STORY_ID, -1L)
)
)
.commit()
}
}