mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-24 04:58:45 +00:00
Add LinkPreview support to CFV2.
This commit is contained in:
committed by
Nicholas Tinsley
parent
3bdffed8c9
commit
2fbcc23451
@@ -190,6 +190,7 @@ import org.thoughtcrime.securesms.groups.v2.GroupBlockJoinRequestResult
|
||||
import org.thoughtcrime.securesms.invites.InviteActions
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreview
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreviewViewModelV2
|
||||
import org.thoughtcrime.securesms.longmessage.LongMessageFragment
|
||||
import org.thoughtcrime.securesms.mediaoverview.MediaOverviewActivity
|
||||
import org.thoughtcrime.securesms.mediapreview.MediaIntentFactory
|
||||
@@ -302,6 +303,12 @@ class ConversationFragment :
|
||||
)
|
||||
}
|
||||
|
||||
private val linkPreviewViewModel: LinkPreviewViewModelV2 by viewModel {
|
||||
LinkPreviewViewModelV2(
|
||||
enablePlaceholder = false
|
||||
)
|
||||
}
|
||||
|
||||
private val groupCallViewModel: ConversationGroupCallViewModel by viewModels(
|
||||
factoryProducer = {
|
||||
ConversationGroupCallViewModel.Factory(args.threadId, conversationRecipientRepository)
|
||||
@@ -668,6 +675,7 @@ class ConversationFragment :
|
||||
.addTo(disposables)
|
||||
|
||||
initializeSearch()
|
||||
initializeLinkPreviews()
|
||||
|
||||
inputPanel.setListener(InputPanelListener())
|
||||
}
|
||||
@@ -1031,6 +1039,32 @@ class ConversationFragment :
|
||||
}
|
||||
}
|
||||
|
||||
private fun initializeLinkPreviews() {
|
||||
linkPreviewViewModel.linkPreviewState
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeBy { state ->
|
||||
if (state.isLoading) {
|
||||
inputPanel.setLinkPreviewLoading()
|
||||
} else if (state.hasLinks() && !state.linkPreview.isPresent) {
|
||||
inputPanel.setLinkPreviewNoPreview(state.error)
|
||||
} else {
|
||||
inputPanel.setLinkPreview(GlideApp.with(this), state.linkPreview)
|
||||
}
|
||||
|
||||
updateToggleButtonState()
|
||||
}
|
||||
.addTo(disposables)
|
||||
}
|
||||
|
||||
private fun updateLinkPreviewState() {
|
||||
if (/* TODO [cfv2] -- viewModel.isPushAvailable && */ !attachmentManager.isAttachmentPresent && context != null) {
|
||||
linkPreviewViewModel.onEnabled()
|
||||
linkPreviewViewModel.onTextChanged(composeText.textTrimmed.toString(), composeText.selectionStart, composeText.selectionEnd)
|
||||
} else {
|
||||
linkPreviewViewModel.onUserCancel()
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateToggleButtonState() {
|
||||
val buttonToggle: AnimatingToggle = binding.conversationInputPanel.buttonToggle
|
||||
val quickAttachment: HidingLinearLayout = binding.conversationInputPanel.quickAttachmentToggle
|
||||
@@ -1065,7 +1099,7 @@ class ConversationFragment :
|
||||
buttonToggle.display(sendButton)
|
||||
quickAttachment.hide()
|
||||
|
||||
if (!attachmentManager.isAttachmentPresent) { // todo [cfv2] && !linkPreviewViewModel.hasLinkPreviewUi()) {
|
||||
if (!attachmentManager.isAttachmentPresent && !linkPreviewViewModel.hasLinkPreviewUi) {
|
||||
inlineAttachment.show()
|
||||
} else {
|
||||
inlineAttachment.hide()
|
||||
@@ -1103,7 +1137,8 @@ class ConversationFragment :
|
||||
mentions = emptyList(),
|
||||
bodyRanges = null,
|
||||
messageToEdit = null,
|
||||
quote = null
|
||||
quote = null,
|
||||
linkPreviews = emptyList()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1116,7 +1151,8 @@ class ConversationFragment :
|
||||
scheduledDate: Long = -1,
|
||||
slideDeck: SlideDeck? = if (attachmentManager.isAttachmentPresent) attachmentManager.buildSlideDeck() else null,
|
||||
contacts: List<Contact> = emptyList(),
|
||||
clearCompose: Boolean = true
|
||||
clearCompose: Boolean = true,
|
||||
linkPreviews: List<LinkPreview> = linkPreviewViewModel.onSend()
|
||||
) {
|
||||
val metricId = viewModel.recipientSnapshot?.let { if (it.isGroup == true) SignalLocalMetrics.GroupMessageSend.start() else SignalLocalMetrics.IndividualMessageSend.start() }
|
||||
|
||||
@@ -1129,7 +1165,8 @@ class ConversationFragment :
|
||||
quote = quote,
|
||||
mentions = mentions,
|
||||
bodyRanges = bodyRanges,
|
||||
contacts = contacts
|
||||
contacts = contacts,
|
||||
linkPreviews = linkPreviews
|
||||
)
|
||||
|
||||
disposables += send
|
||||
@@ -1164,7 +1201,7 @@ class ConversationFragment :
|
||||
scrollToPositionDelegate.resetScrollPosition()
|
||||
attachmentManager.cleanup()
|
||||
|
||||
// todo [cfv2] updateLinkPreviewState();
|
||||
updateLinkPreviewState()
|
||||
|
||||
draftViewModel.onSendComplete()
|
||||
|
||||
@@ -2712,7 +2749,7 @@ class ConversationFragment :
|
||||
}
|
||||
|
||||
override fun onCursorPositionChanged(start: Int, end: Int) {
|
||||
// todo [cfv2] linkPreviewViewModel.onTextChanged(requireContext(), composeText.getTextTrimmed().toString(), start, end);
|
||||
linkPreviewViewModel.onTextChanged(composeText.textTrimmed.toString(), start, end)
|
||||
}
|
||||
|
||||
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
|
||||
@@ -2809,7 +2846,7 @@ class ConversationFragment :
|
||||
}
|
||||
|
||||
override fun onLinkPreviewCanceled() {
|
||||
// TODO [cfv2] Not yet implemented
|
||||
linkPreviewViewModel.onUserCancel()
|
||||
}
|
||||
|
||||
override fun onStickerSuggestionSelected(sticker: StickerRecord) {
|
||||
@@ -2845,7 +2882,9 @@ class ConversationFragment :
|
||||
|
||||
private inner class AttachmentManagerListener : AttachmentManager.AttachmentListener {
|
||||
override fun onAttachmentChanged() {
|
||||
// TODO [cfv2] implement
|
||||
// TODO [cfv2] handleSecurityChange(viewModel.getConversationStateSnapshot().getSecurityInfo());
|
||||
updateToggleButtonState()
|
||||
updateLinkPreviewState()
|
||||
}
|
||||
|
||||
override fun onLocationRemoved() {
|
||||
|
||||
@@ -72,6 +72,7 @@ import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||
import org.thoughtcrime.securesms.jobs.MultiDeviceViewOnceOpenJob
|
||||
import org.thoughtcrime.securesms.jobs.ServiceOutageDetectionJob
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreview
|
||||
import org.thoughtcrime.securesms.messagerequests.MessageRequestState
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests
|
||||
import org.thoughtcrime.securesms.mms.OutgoingMessage
|
||||
@@ -193,7 +194,8 @@ class ConversationRepository(
|
||||
quote: QuoteModel?,
|
||||
mentions: List<Mention>,
|
||||
bodyRanges: BodyRangeList?,
|
||||
contacts: List<Contact>
|
||||
contacts: List<Contact>,
|
||||
linkPreviews: List<LinkPreview>
|
||||
): Completable {
|
||||
val sendCompletable = Completable.create { emitter ->
|
||||
if (body.isEmpty() && slideDeck?.containsMediaSlide() != true) {
|
||||
@@ -218,7 +220,8 @@ class ConversationRepository(
|
||||
outgoingQuote = quote,
|
||||
messageToEdit = messageToEdit?.id ?: 0,
|
||||
mentions = mentions,
|
||||
sharedContacts = contacts
|
||||
sharedContacts = contacts,
|
||||
linkPreviews = linkPreviews
|
||||
)
|
||||
|
||||
MessageSender.send(
|
||||
|
||||
@@ -46,6 +46,7 @@ import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||
import org.thoughtcrime.securesms.jobs.RetrieveProfileJob
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreview
|
||||
import org.thoughtcrime.securesms.messagerequests.MessageRequestRepository
|
||||
import org.thoughtcrime.securesms.messagerequests.MessageRequestState
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests
|
||||
@@ -297,7 +298,8 @@ class ConversationViewModel(
|
||||
quote: QuoteModel?,
|
||||
mentions: List<Mention>,
|
||||
bodyRanges: BodyRangeList?,
|
||||
contacts: List<Contact>
|
||||
contacts: List<Contact>,
|
||||
linkPreviews: List<LinkPreview>
|
||||
): Completable {
|
||||
return repository.sendMessage(
|
||||
threadId = threadId,
|
||||
@@ -310,7 +312,8 @@ class ConversationViewModel(
|
||||
quote = quote,
|
||||
mentions = mentions,
|
||||
bodyRanges = bodyRanges,
|
||||
contacts = contacts
|
||||
contacts = contacts,
|
||||
linkPreviews = linkPreviews
|
||||
).observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import androidx.core.util.Consumer;
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||
|
||||
import org.signal.core.util.Hex;
|
||||
import org.signal.core.util.Result;
|
||||
import org.signal.core.util.concurrent.SignalExecutors;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.signal.libsignal.protocol.InvalidMessageException;
|
||||
@@ -62,6 +63,8 @@ import java.io.InputStream;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import io.reactivex.rxjava3.core.Single;
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||
import okhttp3.CacheControl;
|
||||
import okhttp3.Call;
|
||||
import okhttp3.OkHttpClient;
|
||||
@@ -86,6 +89,28 @@ public class LinkPreviewRepository {
|
||||
.build();
|
||||
}
|
||||
|
||||
public @NonNull Single<Result<LinkPreview, Error>> getLinkPreview(@NonNull String url) {
|
||||
return Single.<Result<LinkPreview, Error>>create(emitter -> {
|
||||
RequestController controller = getLinkPreview(ApplicationDependencies.getApplication(),
|
||||
url,
|
||||
new Callback() {
|
||||
@Override
|
||||
public void onSuccess(@NonNull LinkPreview linkPreview) {
|
||||
emitter.onSuccess(Result.success(linkPreview));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(@NonNull Error error) {
|
||||
emitter.onSuccess(Result.failure(error));
|
||||
}
|
||||
});
|
||||
|
||||
if (controller != null) {
|
||||
emitter.setCancellable(controller::cancel);
|
||||
}
|
||||
}).subscribeOn(Schedulers.io());
|
||||
}
|
||||
|
||||
@Nullable RequestController getLinkPreview(@NonNull Context context,
|
||||
@NonNull String url,
|
||||
@NonNull Callback callback)
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2023 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.securesms.linkpreview;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class LinkPreviewState {
|
||||
private final String activeUrlForError;
|
||||
private final boolean isLoading;
|
||||
private final boolean hasLinks;
|
||||
private final Optional<LinkPreview> linkPreview;
|
||||
private final LinkPreviewRepository.Error error;
|
||||
|
||||
private LinkPreviewState(@Nullable String activeUrlForError,
|
||||
boolean isLoading,
|
||||
boolean hasLinks,
|
||||
Optional<LinkPreview> linkPreview,
|
||||
@Nullable LinkPreviewRepository.Error error)
|
||||
{
|
||||
this.activeUrlForError = activeUrlForError;
|
||||
this.isLoading = isLoading;
|
||||
this.hasLinks = hasLinks;
|
||||
this.linkPreview = linkPreview;
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
public static LinkPreviewState forLoading() {
|
||||
return new LinkPreviewState(null, true, false, Optional.empty(), null);
|
||||
}
|
||||
|
||||
public static LinkPreviewState forPreview(@NonNull LinkPreview linkPreview) {
|
||||
return new LinkPreviewState(null, false, true, Optional.of(linkPreview), null);
|
||||
}
|
||||
|
||||
public static LinkPreviewState forLinksWithNoPreview(@Nullable String activeUrlForError, @NonNull LinkPreviewRepository.Error error) {
|
||||
return new LinkPreviewState(activeUrlForError, false, true, Optional.empty(), error);
|
||||
}
|
||||
|
||||
public static LinkPreviewState forNoLinks() {
|
||||
return new LinkPreviewState(null, false, false, Optional.empty(), null);
|
||||
}
|
||||
|
||||
public @Nullable String getActiveUrlForError() {
|
||||
return activeUrlForError;
|
||||
}
|
||||
|
||||
public boolean isLoading() {
|
||||
return isLoading;
|
||||
}
|
||||
|
||||
public boolean hasLinks() {
|
||||
return hasLinks;
|
||||
}
|
||||
|
||||
public Optional<LinkPreview> getLinkPreview() {
|
||||
return linkPreview;
|
||||
}
|
||||
|
||||
public @Nullable LinkPreviewRepository.Error getError() {
|
||||
return error;
|
||||
}
|
||||
|
||||
public boolean hasContent() {
|
||||
return isLoading || hasLinks;
|
||||
}
|
||||
}
|
||||
@@ -255,7 +255,7 @@ public class LinkPreviewViewModel extends ViewModel {
|
||||
}
|
||||
|
||||
if (enablePlaceholder) {
|
||||
return state.linkPreview
|
||||
return state.getLinkPreview()
|
||||
.map(linkPreview -> LinkPreviewState.forLinksWithNoPreview(linkPreview.getUrl(), LinkPreviewRepository.Error.PREVIEW_NOT_AVAILABLE))
|
||||
.orElse(state);
|
||||
}
|
||||
@@ -263,67 +263,6 @@ public class LinkPreviewViewModel extends ViewModel {
|
||||
return LinkPreviewState.forNoLinks();
|
||||
}
|
||||
|
||||
public static class LinkPreviewState {
|
||||
private final String activeUrlForError;
|
||||
private final boolean isLoading;
|
||||
private final boolean hasLinks;
|
||||
private final Optional<LinkPreview> linkPreview;
|
||||
private final LinkPreviewRepository.Error error;
|
||||
|
||||
private LinkPreviewState(@Nullable String activeUrlForError,
|
||||
boolean isLoading,
|
||||
boolean hasLinks,
|
||||
Optional<LinkPreview> linkPreview,
|
||||
@Nullable LinkPreviewRepository.Error error)
|
||||
{
|
||||
this.activeUrlForError = activeUrlForError;
|
||||
this.isLoading = isLoading;
|
||||
this.hasLinks = hasLinks;
|
||||
this.linkPreview = linkPreview;
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
private static LinkPreviewState forLoading() {
|
||||
return new LinkPreviewState(null, true, false, Optional.empty(), null);
|
||||
}
|
||||
|
||||
private static LinkPreviewState forPreview(@NonNull LinkPreview linkPreview) {
|
||||
return new LinkPreviewState(null, false, true, Optional.of(linkPreview), null);
|
||||
}
|
||||
|
||||
private static LinkPreviewState forLinksWithNoPreview(@Nullable String activeUrlForError, @NonNull LinkPreviewRepository.Error error) {
|
||||
return new LinkPreviewState(activeUrlForError, false, true, Optional.empty(), error);
|
||||
}
|
||||
|
||||
private static LinkPreviewState forNoLinks() {
|
||||
return new LinkPreviewState(null, false, false, Optional.empty(), null);
|
||||
}
|
||||
|
||||
public @Nullable String getActiveUrlForError() {
|
||||
return activeUrlForError;
|
||||
}
|
||||
|
||||
public boolean isLoading() {
|
||||
return isLoading;
|
||||
}
|
||||
|
||||
public boolean hasLinks() {
|
||||
return hasLinks;
|
||||
}
|
||||
|
||||
public Optional<LinkPreview> getLinkPreview() {
|
||||
return linkPreview;
|
||||
}
|
||||
|
||||
public @Nullable LinkPreviewRepository.Error getError() {
|
||||
return error;
|
||||
}
|
||||
|
||||
boolean hasContent() {
|
||||
return isLoading || hasLinks;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Factory extends ViewModelProvider.NewInstanceFactory {
|
||||
|
||||
private final LinkPreviewRepository repository;
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright 2023 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.securesms.linkpreview
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.core.Flowable
|
||||
import io.reactivex.rxjava3.core.Single
|
||||
import io.reactivex.rxjava3.disposables.Disposable
|
||||
import io.reactivex.rxjava3.kotlin.subscribeBy
|
||||
import org.signal.core.util.Result
|
||||
import org.signal.core.util.isAbsent
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.util.Debouncer
|
||||
import org.thoughtcrime.securesms.util.rx.RxStore
|
||||
import java.util.Optional
|
||||
|
||||
/**
|
||||
* Rewrite of [LinkPreviewViewModel] preferring Rx and Kotlin
|
||||
*/
|
||||
class LinkPreviewViewModelV2(
|
||||
private val linkPreviewRepository: LinkPreviewRepository = LinkPreviewRepository(),
|
||||
private val enablePlaceholder: Boolean
|
||||
) : ViewModel() {
|
||||
private var enabled = SignalStore.settings().isLinkPreviewsEnabled
|
||||
private val linkPreviewStateStore = RxStore<LinkPreviewState>(LinkPreviewState.forNoLinks())
|
||||
|
||||
val linkPreviewState: Flowable<LinkPreviewState> = linkPreviewStateStore.stateFlowable
|
||||
val hasLinkPreview: Boolean = linkPreviewStateStore.state.linkPreview.isPresent
|
||||
val hasLinkPreviewUi: Boolean = linkPreviewStateStore.state.hasContent()
|
||||
|
||||
private var activeUrl: String? = null
|
||||
private var activeRequest: Disposable = Disposable.disposed()
|
||||
private var userCancelled: Boolean = false
|
||||
private val debouncer: Debouncer = Debouncer(250)
|
||||
|
||||
override fun onCleared() {
|
||||
activeRequest.dispose()
|
||||
debouncer.clear()
|
||||
}
|
||||
|
||||
fun onSend(): List<LinkPreview> {
|
||||
val currentState = linkPreviewStateStore.state
|
||||
|
||||
onUserCancel()
|
||||
|
||||
return currentState.linkPreview.map { listOf(it) }.orElse(emptyList())
|
||||
}
|
||||
|
||||
fun onTextChanged(text: String, cursorStart: Int, cursorEnd: Int) {
|
||||
if (!enabled && !enablePlaceholder) {
|
||||
return
|
||||
}
|
||||
|
||||
debouncer.publish {
|
||||
if (text.isEmpty()) {
|
||||
userCancelled = false
|
||||
}
|
||||
|
||||
if (userCancelled) {
|
||||
return@publish
|
||||
}
|
||||
|
||||
val link: Optional<Link> = LinkPreviewUtil.findValidPreviewUrls(text).findFirst()
|
||||
|
||||
activeRequest.dispose()
|
||||
|
||||
if (link.isAbsent() || !isCursorPositionValid(text, link.get(), cursorStart, cursorEnd)) {
|
||||
activeUrl = null
|
||||
setLinkPreviewState(LinkPreviewState.forNoLinks())
|
||||
return@publish
|
||||
}
|
||||
|
||||
setLinkPreviewState(LinkPreviewState.forLoading())
|
||||
|
||||
val activeUrl = link.get().url
|
||||
this.activeUrl = activeUrl
|
||||
activeRequest = if (enabled) {
|
||||
performRequest(activeUrl)
|
||||
} else {
|
||||
createPlaceholder(activeUrl)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun onEnabled() {
|
||||
userCancelled = false
|
||||
enabled = SignalStore.settings().isLinkPreviewsEnabled
|
||||
}
|
||||
|
||||
fun onUserCancel() {
|
||||
activeRequest.dispose()
|
||||
userCancelled = true
|
||||
activeUrl = null
|
||||
debouncer.clear()
|
||||
setLinkPreviewState(LinkPreviewState.forNoLinks())
|
||||
}
|
||||
|
||||
private fun isCursorPositionValid(text: String, link: Link, cursorStart: Int, cursorEnd: Int): Boolean {
|
||||
if (cursorStart != cursorEnd) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (text.endsWith(link.url) && cursorStart == link.position + link.url.length) {
|
||||
return true
|
||||
}
|
||||
|
||||
return cursorStart < link.position || cursorStart > link.position + link.url.length
|
||||
}
|
||||
|
||||
private fun createPlaceholder(url: String): Disposable {
|
||||
return Single.just(url)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeBy {
|
||||
if (!userCancelled) {
|
||||
if (activeUrl != null && activeUrl == url) {
|
||||
setLinkPreviewState(LinkPreviewState.forLinksWithNoPreview(url, LinkPreviewRepository.Error.PREVIEW_NOT_AVAILABLE))
|
||||
} else {
|
||||
setLinkPreviewState(LinkPreviewState.forNoLinks())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun performRequest(url: String): Disposable {
|
||||
return linkPreviewRepository.getLinkPreview(url)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeBy { result ->
|
||||
if (!userCancelled) {
|
||||
val linkPreviewState = when (result) {
|
||||
is Result.Success -> if (activeUrl == result.success.url) LinkPreviewState.forPreview(result.success) else LinkPreviewState.forNoLinks()
|
||||
is Result.Failure -> if (activeUrl != null) LinkPreviewState.forLinksWithNoPreview(activeUrl, result.failure) else LinkPreviewState.forNoLinks()
|
||||
}
|
||||
|
||||
setLinkPreviewState(linkPreviewState)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setLinkPreviewState(linkPreviewState: LinkPreviewState) {
|
||||
linkPreviewStateStore.update { cleanseState(linkPreviewState) }
|
||||
}
|
||||
|
||||
private fun cleanseState(linkPreviewState: LinkPreviewState): LinkPreviewState {
|
||||
if (enabled) {
|
||||
return linkPreviewState
|
||||
}
|
||||
|
||||
if (enablePlaceholder) {
|
||||
return linkPreviewState
|
||||
.linkPreview
|
||||
.map { LinkPreviewState.forLinksWithNoPreview(it.url, LinkPreviewRepository.Error.PREVIEW_NOT_AVAILABLE) }
|
||||
.orElse(linkPreviewState)
|
||||
}
|
||||
|
||||
return LinkPreviewState.forNoLinks()
|
||||
}
|
||||
}
|
||||
@@ -21,8 +21,8 @@ import org.thoughtcrime.securesms.conversation.mutiselect.forward.MultiselectFor
|
||||
import org.thoughtcrime.securesms.databinding.StoriesTextPostCreationFragmentBinding
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreview
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreviewState
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreviewViewModel
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreviewViewModel.LinkPreviewState
|
||||
import org.thoughtcrime.securesms.mediasend.CameraDisplay
|
||||
import org.thoughtcrime.securesms.mediasend.v2.HudCommand
|
||||
import org.thoughtcrime.securesms.mediasend.v2.MediaSelectionViewModel
|
||||
|
||||
@@ -12,8 +12,8 @@ import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.components.ThumbnailView
|
||||
import org.thoughtcrime.securesms.databinding.StoriesTextPostLinkPreviewBinding
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreview
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreviewState
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreviewViewModel
|
||||
import org.thoughtcrime.securesms.mms.GlideApp
|
||||
import org.thoughtcrime.securesms.mms.ImageSlide
|
||||
import org.thoughtcrime.securesms.mms.Slide
|
||||
@@ -73,7 +73,7 @@ class StoryLinkPreviewView @JvmOverloads constructor(
|
||||
return future ?: SettableFuture(false)
|
||||
}
|
||||
|
||||
fun bind(linkPreviewState: LinkPreviewViewModel.LinkPreviewState, hiddenVisibility: Int = View.INVISIBLE, useLargeThumbnail: Boolean) {
|
||||
fun bind(linkPreviewState: LinkPreviewState, hiddenVisibility: Int = View.INVISIBLE, useLargeThumbnail: Boolean) {
|
||||
val linkPreview: LinkPreview? = linkPreviewState.linkPreview.orElseGet {
|
||||
linkPreviewState.activeUrlForError?.let {
|
||||
LinkPreview(it, LinkPreviewUtil.getTopLevelDomain(it) ?: it, null, -1L, null)
|
||||
|
||||
@@ -20,7 +20,7 @@ import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.StoryTextPost
|
||||
import org.thoughtcrime.securesms.fonts.TextFont
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreview
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreviewViewModel
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreviewState
|
||||
import org.thoughtcrime.securesms.mediasend.v2.text.TextStoryPostCreationState
|
||||
import org.thoughtcrime.securesms.mediasend.v2.text.TextStoryScale
|
||||
import org.thoughtcrime.securesms.mediasend.v2.text.TextStoryTextWatcher
|
||||
@@ -157,7 +157,7 @@ class StoryTextPostView @JvmOverloads constructor(
|
||||
linkPreviewView.setThumbnailDrawable(drawable, useLargeThumbnail)
|
||||
}
|
||||
|
||||
fun bindLinkPreviewState(linkPreviewState: LinkPreviewViewModel.LinkPreviewState, hiddenVisibility: Int, useLargeThumbnail: Boolean) {
|
||||
fun bindLinkPreviewState(linkPreviewState: LinkPreviewState, hiddenVisibility: Int, useLargeThumbnail: Boolean) {
|
||||
linkPreviewView.bind(linkPreviewState, hiddenVisibility, useLargeThumbnail)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user