diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/UrlCachedPreviewer.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/UrlCachedPreviewer.kt index 4b49596c9..783b708eb 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/UrlCachedPreviewer.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/UrlCachedPreviewer.kt @@ -34,7 +34,7 @@ object UrlCachedPreviewer { } } - val state = if (urlInfo.allFetchComplete() && urlInfo.url == url) { + val state = if (urlInfo.fetchComplete() && urlInfo.url == url) { UrlPreviewState.Loaded(urlInfo) } else { UrlPreviewState.Empty diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/previews/BahaUrlPreview.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/previews/BahaUrlPreview.kt index 0b394eef0..b7af42bfb 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/previews/BahaUrlPreview.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/previews/BahaUrlPreview.kt @@ -1,13 +1,9 @@ package com.vitorpamplona.amethyst.service.previews -import android.net.Uri import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext -import java.util.Locale class BahaUrlPreview(val url: String, var callback: IUrlPreviewCallback?) { - private val imageExtensionArray = arrayOf(".gif", ".png", ".jpg", ".jpeg", ".bmp", ".webp") - suspend fun fetchUrlPreview(timeOut: Int = 30000) = withContext(Dispatchers.IO) { try { fetch(timeOut) @@ -17,26 +13,7 @@ class BahaUrlPreview(val url: String, var callback: IUrlPreviewCallback?) { } private suspend fun fetch(timeOut: Int = 30000) { - lateinit var urlInfoItem: UrlInfoItem - if (checkIsImageUrl()) { - urlInfoItem = UrlInfoItem(url = url, image = url) - } else { - val document = getDocument(url, timeOut) - urlInfoItem = parseHtml(url, document) - } - callback?.onComplete(urlInfoItem) - } - - private fun checkIsImageUrl(): Boolean { - val uri = Uri.parse(url) - var isImage = false - for (imageExtension in imageExtensionArray) { - if (uri.path != null && uri.path!!.toLowerCase(Locale.getDefault()).endsWith(imageExtension)) { - isImage = true - break - } - } - return isImage + callback?.onComplete(getDocument(url, timeOut)) } fun cleanUp() { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/previews/UrlInfoItem.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/previews/UrlInfoItem.kt index 2547f2d22..f96e5a164 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/previews/UrlInfoItem.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/previews/UrlInfoItem.kt @@ -1,14 +1,16 @@ package com.vitorpamplona.amethyst.service.previews import androidx.compose.runtime.Immutable +import okhttp3.MediaType import java.net.URL @Immutable -data class UrlInfoItem( +class UrlInfoItem( val url: String = "", val title: String = "", val description: String = "", - val image: String = "" + val image: String = "", + val mimeType: MediaType ) { val verifiedUrl = kotlin.runCatching { URL(url) }.getOrNull() val imageUrlFullPath = @@ -18,6 +20,10 @@ data class UrlInfoItem( image } + fun fetchComplete(): Boolean { + return url.isNotEmpty() && image.isNotEmpty() + } + fun allFetchComplete(): Boolean { return title.isNotEmpty() && description.isNotEmpty() && image.isNotEmpty() } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/previews/UrlPreviewUtils.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/previews/UrlPreviewUtils.kt index d8cc1d0c7..fdd4ef681 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/previews/UrlPreviewUtils.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/previews/UrlPreviewUtils.kt @@ -3,6 +3,8 @@ package com.vitorpamplona.amethyst.service.previews import com.vitorpamplona.amethyst.service.HttpClient import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext +import okhttp3.MediaType +import okhttp3.MediaType.Companion.toMediaType import okhttp3.Request import org.jsoup.Jsoup import org.jsoup.nodes.Document @@ -46,21 +48,31 @@ private val META_X_IMAGE = arrayOf( private const val CONTENT = "content" -suspend fun getDocument(url: String, timeOut: Int = 30000): Document = +suspend fun getDocument(url: String, timeOut: Int = 30000): UrlInfoItem = withContext(Dispatchers.IO) { val request: Request = Request.Builder().url(url).get().build() - val html = HttpClient.getHttpClient().newCall(request).execute().use { + HttpClient.getHttpClient().newCall(request).execute().use { if (it.isSuccessful) { - it.body.string() + val mimeType = it.headers.get("Content-Type")?.toMediaType() + ?: throw IllegalArgumentException("Website returned unknown mimetype: ${it.headers.get("Content-Type")}") + + if (mimeType.type == "text" && mimeType.subtype == "html") { + val document = Jsoup.parse(it.body.string()) + parseHtml(url, document, mimeType) + } else if (mimeType.type == "image") { + UrlInfoItem(url, image = url, mimeType = mimeType) + } else if (mimeType.type == "video") { + UrlInfoItem(url, image = url, mimeType = mimeType) + } else { + throw IllegalArgumentException("Website returned unknown encoding for previews: $mimeType") + } } else { throw IllegalArgumentException("Website returned: " + it.code) } } - - Jsoup.parse(html) } -suspend fun parseHtml(url: String, document: Document): UrlInfoItem = +suspend fun parseHtml(url: String, document: Document, type: MediaType): UrlInfoItem = withContext(Dispatchers.IO) { val metaTags = document.getElementsByTag(ELEMENT_TAG_META) @@ -106,8 +118,8 @@ suspend fun parseHtml(url: String, document: Document): UrlInfoItem = } if (title.isNotEmpty() && description.isNotEmpty() && image.isNotEmpty()) { - return@withContext UrlInfoItem(url, title, description, image) + return@withContext UrlInfoItem(url, title, description, image, type) } } - return@withContext UrlInfoItem(url, title, description, image) + return@withContext UrlInfoItem(url, title, description, image, type) } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/LoadUrlPreview.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/LoadUrlPreview.kt index 7ddf771fc..7b6ca9068 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/LoadUrlPreview.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/LoadUrlPreview.kt @@ -2,6 +2,7 @@ package com.vitorpamplona.amethyst.ui.components import androidx.compose.animation.Crossfade import androidx.compose.animation.core.tween +import androidx.compose.foundation.layout.Box import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -10,6 +11,8 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import com.vitorpamplona.amethyst.model.UrlCachedPreviewer import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.theme.HalfVertPadding +import kotlinx.collections.immutable.persistentListOf @Composable fun LoadUrlPreview(url: String, urlText: String, accountViewModel: AccountViewModel) { @@ -42,7 +45,17 @@ fun LoadUrlPreview(url: String, urlText: String, accountViewModel: AccountViewMo ) { state -> when (state) { is UrlPreviewState.Loaded -> { - UrlPreviewCard(url, state.previewInfo) + if (state.previewInfo.mimeType.type == "image") { + Box(modifier = HalfVertPadding) { + ZoomableContentView(ZoomableUrlImage(url), persistentListOf(), roundedCorner = true, accountViewModel) + } + } else if (state.previewInfo.mimeType.type == "video") { + Box(modifier = HalfVertPadding) { + ZoomableContentView(ZoomableUrlVideo(url), persistentListOf(), roundedCorner = true, accountViewModel) + } + } else { + UrlPreviewCard(url, state.previewInfo) + } } else -> {