mirror of
https://github.com/element-hq/element-android
synced 2024-11-27 11:59:12 +03:00
Update url preview when the event is edited.
This commit is contained in:
parent
618d1f5de6
commit
5eeb545ae2
6 changed files with 37 additions and 23 deletions
|
@ -10,6 +10,7 @@ Improvements 🙌:
|
|||
Bugfix 🐛:
|
||||
- Fix clear cache issue: sometimes, after a clear cache, there is still a token, so the init sync service is not started.
|
||||
- Sidebar too large in horizontal orientation or tablets (#475)
|
||||
- UrlPreview should be updated when the url is edited and changed (#2678)
|
||||
|
||||
Translations 🗣:
|
||||
-
|
||||
|
|
|
@ -17,15 +17,17 @@
|
|||
package org.matrix.android.sdk.api.session.media
|
||||
|
||||
import org.matrix.android.sdk.api.cache.CacheStrategy
|
||||
import org.matrix.android.sdk.api.session.events.model.Event
|
||||
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
||||
import org.matrix.android.sdk.api.util.JsonDict
|
||||
|
||||
interface MediaService {
|
||||
/**
|
||||
* Extract URLs from an Event.
|
||||
* @return the list of URLs contains in the body of the Event. It does not mean that URLs in this list have UrlPreview data
|
||||
* Extract URLs from a TimelineEvent.
|
||||
* @param event TimelineEvent to extract the URL from.
|
||||
* @param forceExtract Should be used for edited events. If true, URL will be extracted again even it is already in the cache.
|
||||
* @return the list of URLs contains in the body of the TimelineEvent. It does not mean that URLs in this list have UrlPreview data
|
||||
*/
|
||||
fun extractUrls(event: Event): List<String>
|
||||
fun extractUrls(event: TimelineEvent, forceExtract: Boolean = false): List<String>
|
||||
|
||||
/**
|
||||
* Get Raw Url Preview data from the homeserver. There is no cache management for this request
|
||||
|
|
|
@ -21,6 +21,7 @@ import org.matrix.android.sdk.api.cache.CacheStrategy
|
|||
import org.matrix.android.sdk.api.session.events.model.Event
|
||||
import org.matrix.android.sdk.api.session.media.MediaService
|
||||
import org.matrix.android.sdk.api.session.media.PreviewUrlData
|
||||
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
||||
import org.matrix.android.sdk.api.util.JsonDict
|
||||
import org.matrix.android.sdk.internal.util.getOrPut
|
||||
import javax.inject.Inject
|
||||
|
@ -34,8 +35,9 @@ internal class DefaultMediaService @Inject constructor(
|
|||
// Cache of extracted URLs
|
||||
private val extractedUrlsCache = LruCache<String, List<String>>(1_000)
|
||||
|
||||
override fun extractUrls(event: Event): List<String> {
|
||||
return extractedUrlsCache.getOrPut(event.cacheKey()) { urlsExtractor.extract(event) }
|
||||
override fun extractUrls(event: TimelineEvent, forceExtract: Boolean): List<String> {
|
||||
if (forceExtract) extractedUrlsCache.remove(event.root.cacheKey())
|
||||
return extractedUrlsCache.getOrPut(event.root.cacheKey()) { urlsExtractor.extract(event) }
|
||||
}
|
||||
|
||||
private fun Event.cacheKey() = "${eventId ?: ""}-${roomId ?: ""}"
|
||||
|
|
|
@ -17,21 +17,19 @@
|
|||
package org.matrix.android.sdk.internal.session.media
|
||||
|
||||
import android.util.Patterns
|
||||
import org.matrix.android.sdk.api.session.events.model.Event
|
||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageContent
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageType
|
||||
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
||||
import org.matrix.android.sdk.api.session.room.timeline.getLastMessageContent
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class UrlsExtractor @Inject constructor() {
|
||||
// Sadly Patterns.WEB_URL_WITH_PROTOCOL is not public so filter the protocol later
|
||||
private val urlRegex = Patterns.WEB_URL.toRegex()
|
||||
|
||||
fun extract(event: Event): List<String> {
|
||||
return event.takeIf { it.getClearType() == EventType.MESSAGE }
|
||||
?.getClearContent()
|
||||
?.toModel<MessageContent>()
|
||||
fun extract(event: TimelineEvent): List<String> {
|
||||
return event.takeIf { it.root.getClearType() == EventType.MESSAGE }
|
||||
?.getLastMessageContent()
|
||||
?.takeIf {
|
||||
it.msgType == MessageType.MSGTYPE_TEXT
|
||||
|| it.msgType == MessageType.MSGTYPE_NOTICE
|
||||
|
|
|
@ -1396,7 +1396,7 @@ class RoomDetailViewModel @AssistedInject constructor(
|
|||
snapshot
|
||||
.takeIf { state.asyncRoomSummary.invoke()?.isEncrypted == false }
|
||||
?.forEach {
|
||||
previewUrlRetriever.getPreviewUrl(it.root, viewModelScope)
|
||||
previewUrlRetriever.getPreviewUrl(it, viewModelScope)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,37 +16,46 @@
|
|||
|
||||
package im.vector.app.features.home.room.detail.timeline.url
|
||||
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import im.vector.app.BuildConfig
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.android.sdk.api.cache.CacheStrategy
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.api.session.events.model.Event
|
||||
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
||||
import org.matrix.android.sdk.api.session.room.timeline.hasBeenEdited
|
||||
|
||||
class PreviewUrlRetriever(session: Session) {
|
||||
private val mediaService = session.mediaService()
|
||||
|
||||
private val data = mutableMapOf<String, PreviewUrlUiState>()
|
||||
private val listeners = mutableMapOf<String, MutableSet<PreviewUrlRetrieverListener>>()
|
||||
private val uiHandler = Handler(Looper.getMainLooper())
|
||||
|
||||
// In memory list
|
||||
private val blockedUrl = mutableSetOf<String>()
|
||||
|
||||
fun getPreviewUrl(event: Event, coroutineScope: CoroutineScope) {
|
||||
val eventId = event.eventId ?: return
|
||||
fun getPreviewUrl(event: TimelineEvent, coroutineScope: CoroutineScope) {
|
||||
val eventId = event.root.eventId ?: return
|
||||
|
||||
synchronized(data) {
|
||||
if (data[eventId] == null) {
|
||||
val isEditedEvent = event.hasBeenEdited()
|
||||
if (data[eventId] == null || isEditedEvent) {
|
||||
// Keep only the first URL for the moment
|
||||
val url = mediaService.extractUrls(event)
|
||||
val url = mediaService.extractUrls(event, forceExtract = isEditedEvent)
|
||||
.firstOrNull()
|
||||
?.takeIf { it !in blockedUrl }
|
||||
if (url == null) {
|
||||
updateState(eventId, PreviewUrlUiState.NoUrl)
|
||||
} else {
|
||||
url
|
||||
} else if (url != (data[eventId] as? PreviewUrlUiState.Data)?.url) {
|
||||
updateState(eventId, PreviewUrlUiState.Loading)
|
||||
url
|
||||
} else {
|
||||
// Already handled
|
||||
null
|
||||
}
|
||||
url
|
||||
} else {
|
||||
// Already handled
|
||||
null
|
||||
|
@ -96,8 +105,10 @@ class PreviewUrlRetriever(session: Session) {
|
|||
private fun updateState(eventId: String, state: PreviewUrlUiState) {
|
||||
data[eventId] = state
|
||||
// Notify the listener
|
||||
listeners[eventId].orEmpty().forEach {
|
||||
it.onStateUpdated(state)
|
||||
uiHandler.post {
|
||||
listeners[eventId].orEmpty().forEach {
|
||||
it.onStateUpdated(state)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue