diff --git a/core/commonui/lemmyui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/lemmyui/PostCard.kt b/core/commonui/lemmyui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/lemmyui/PostCard.kt index 05e54b72c..398f7bc62 100644 --- a/core/commonui/lemmyui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/lemmyui/PostCard.kt +++ b/core/commonui/lemmyui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/lemmyui/PostCard.kt @@ -45,11 +45,13 @@ import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.rememberCallb import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.rememberCallbackArgs import com.github.diegoberaldin.raccoonforlemmy.core.utils.looksLikeAVideo import com.github.diegoberaldin.raccoonforlemmy.core.utils.looksLikeAnImage +import com.github.diegoberaldin.raccoonforlemmy.core.utils.showInEmbeddedWebView import com.github.diegoberaldin.raccoonforlemmy.core.utils.url.getCustomTabsHelper import com.github.diegoberaldin.raccoonforlemmy.core.utils.url.toUrlOpeningMode import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PostModel import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.UserModel +import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.embeddedUrl import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.imageUrl import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.videoUrl @@ -420,7 +422,11 @@ private fun ExtendedPost( val navigationCoordinator = remember { getNavigationCoordinator() } val optionsMenuOpen = remember { mutableStateOf(false) } val postLinkUrl = post.url.orEmpty().takeIf { - it != post.imageUrl && it != post.videoUrl && !it.looksLikeAnImage && !it.looksLikeAVideo + it != post.imageUrl + && it != post.videoUrl + && !it.looksLikeAnImage + && !it.looksLikeAVideo + && !it.showInEmbeddedWebView }.orEmpty() Column( @@ -483,7 +489,34 @@ private fun ExtendedPost( ) } - if (post.videoUrl.isNotEmpty()) { + if (post.embeddedUrl.isNotEmpty()) { + PostCardEmbeddedWebView( + modifier = Modifier + .padding( + vertical = Spacing.xxs, + horizontal = if (fullWidthImage) 0.dp else Spacing.s, + ), + blurred = blurNsfw && post.nsfw, + autoLoadImages = autoLoadImages, + url = post.embeddedUrl, + onOpen = { + if (postLinkUrl.isNotEmpty()) { + navigationCoordinator.handleUrl( + url = postLinkUrl, + openingMode = settings.urlOpeningMode.toUrlOpeningMode(), + uriHandler = uriHandler, + customTabsHelper = customTabsHelper, + onOpenWeb = onOpenWeb, + onOpenCommunity = onOpenCommunity, + onOpenPost = onOpenPost, + onOpenUser = onOpenCreator, + ) + } else { + onClick?.invoke() + } + }, + ) + } else if (post.videoUrl.isNotEmpty()) { PostCardVideo( modifier = Modifier .padding( @@ -595,7 +628,7 @@ private fun ExtendedPost( } } } - if (postLinkUrl.isNotEmpty() && postLinkUrl != post.imageUrl && postLinkUrl != post.videoUrl) { + if (postLinkUrl.isNotEmpty()) { PostLinkBanner( modifier = Modifier .padding( diff --git a/core/commonui/lemmyui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/lemmyui/PostCardEmbeddedWebView.kt b/core/commonui/lemmyui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/lemmyui/PostCardEmbeddedWebView.kt new file mode 100644 index 000000000..d9ef2ec5f --- /dev/null +++ b/core/commonui/lemmyui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/lemmyui/PostCardEmbeddedWebView.kt @@ -0,0 +1,85 @@ +package com.github.diegoberaldin.raccoonforlemmy.core.commonui.lemmyui + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Button +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.style.TextOverflow +import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing +import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.CustomWebView +import com.github.diegoberaldin.raccoonforlemmy.core.l10n.LocalXmlStrings + +@Composable +fun PostCardEmbeddedWebView( + modifier: Modifier = Modifier, + url: String, + blurred: Boolean = false, + autoLoadImages: Boolean = true, + onOpen: (() -> Unit)? = null, +) { + if (url.isEmpty()) { + return + } + + Box( + modifier = modifier.fillMaxWidth(), + contentAlignment = Alignment.Center, + ) { + if (blurred) { + Column( + modifier = Modifier.padding(vertical = Spacing.s), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(Spacing.s), + ) { + Text( + text = LocalXmlStrings.current.messageVideoNsfw, + style = MaterialTheme.typography.bodyMedium, + ) + Button( + onClick = { + onOpen?.invoke() + }, + ) { + Text( + text = LocalXmlStrings.current.buttonLoad, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + } + } + } else { + var shouldBeRendered by remember(autoLoadImages) { mutableStateOf(autoLoadImages) } + if (shouldBeRendered) { + CustomWebView( + modifier = Modifier.aspectRatio(9f / 16f), + url = url, + ) + } else { + Button( + modifier = Modifier.padding(vertical = Spacing.s), + onClick = { + shouldBeRendered = true + }, + ) { + Text( + text = LocalXmlStrings.current.buttonLoad, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + } + } + } + } +} diff --git a/core/commonui/lemmyui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/lemmyui/PostCardVideo.kt b/core/commonui/lemmyui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/lemmyui/PostCardVideo.kt index 895e8de8e..1028ba194 100644 --- a/core/commonui/lemmyui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/lemmyui/PostCardVideo.kt +++ b/core/commonui/lemmyui/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/commonui/lemmyui/PostCardVideo.kt @@ -1,11 +1,13 @@ package com.github.diegoberaldin.raccoonforlemmy.core.commonui.lemmyui import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.material3.Button import androidx.compose.material3.CircularProgressIndicator @@ -21,9 +23,9 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp +import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.VideoPlayer import com.github.diegoberaldin.raccoonforlemmy.core.l10n.LocalXmlStrings -import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.onClick @Composable fun PostCardVideo( @@ -39,15 +41,14 @@ fun PostCardVideo( } Box( - modifier = modifier - .fillMaxWidth() - .aspectRatio(1.33f) - .onClick(), + modifier = modifier.fillMaxWidth(), contentAlignment = Alignment.Center, ) { if (blurred) { Column( + modifier = Modifier.padding(vertical = Spacing.s), horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(Spacing.s), ) { Text( text = LocalXmlStrings.current.messageVideoNsfw, @@ -70,7 +71,7 @@ fun PostCardVideo( var loading by remember { mutableStateOf(true) } if (shouldBeRendered) { VideoPlayer( - modifier = Modifier.fillMaxSize(), + modifier = Modifier.aspectRatio(4f / 3f), url = url, onPlaybackStarted = { loading = false @@ -89,6 +90,7 @@ fun PostCardVideo( } } else { Button( + modifier = Modifier.padding(vertical = Spacing.s), onClick = { shouldBeRendered = true }, diff --git a/core/utils/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/utils/Extensions.kt b/core/utils/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/utils/Extensions.kt index 809ea08aa..5719e11d4 100644 --- a/core/utils/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/utils/Extensions.kt +++ b/core/utils/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/core/utils/Extensions.kt @@ -157,14 +157,22 @@ fun Boolean.toInboxDefaultType(): Int = if (this) 0 else 1 val String.looksLikeAnImage: Boolean get() { - val imageExtensions = listOf(".jpeg", ".jpg", ".png", ".webp", ".gif") - return imageExtensions.any { this.endsWith(it) } + val extensions = listOf(".jpeg", ".jpg", ".png", ".webp", ".gif") + return extensions.any { this.endsWith(it) } } val String.looksLikeAVideo: Boolean get() { - val imageExtensions = listOf(".mp4", ".mov", ".webm", ".avi") - return imageExtensions.any { this.endsWith(it) } + val extensions = listOf(".mp4", ".mov", ".webm", ".avi") + return extensions.any { this.endsWith(it) } + } + +val String.showInEmbeddedWebView: Boolean + get() { + val patterns = listOf( + ".redgifs.com/", + ) + return patterns.any { this.contains(it) } } diff --git a/domain/lemmy/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/data/PostModel.kt b/domain/lemmy/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/data/PostModel.kt index cf58b1de8..68fe3f35b 100644 --- a/domain/lemmy/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/data/PostModel.kt +++ b/domain/lemmy/data/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/data/PostModel.kt @@ -2,6 +2,7 @@ package com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data import com.github.diegoberaldin.raccoonforlemmy.core.utils.looksLikeAVideo import com.github.diegoberaldin.raccoonforlemmy.core.utils.looksLikeAnImage +import com.github.diegoberaldin.raccoonforlemmy.core.utils.showInEmbeddedWebView data class PostModel( val id: Long = 0, @@ -15,7 +16,6 @@ data class PostModel( val unreadComments: Int? = null, val thumbnailUrl: String? = null, val url: String? = null, - val embedVideoUrl: String? = null, val community: CommunityModel? = null, val creator: UserModel? = null, val saved: Boolean = false, @@ -34,7 +34,11 @@ data class PostModel( ) val PostModel.imageUrl: String - get() = (thumbnailUrl?.takeIf { it.isNotEmpty() } ?: url?.takeIf { it.looksLikeAnImage }).orEmpty() + get() = (thumbnailUrl?.takeIf { it.isNotEmpty() } + ?: url?.takeIf { it.looksLikeAnImage }).orEmpty() val PostModel.videoUrl: String get() = url?.takeIf { it.looksLikeAVideo }?.takeIf { it.isNotEmpty() }.orEmpty() + +val PostModel.embeddedUrl: String + get() = url?.takeIf { it.showInEmbeddedWebView }?.takeIf { it.isNotEmpty() }.orEmpty() \ No newline at end of file diff --git a/domain/lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/utils/Mappings.kt b/domain/lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/utils/Mappings.kt index 95a770939..fad9f7fd3 100644 --- a/domain/lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/utils/Mappings.kt +++ b/domain/lemmy/repository/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/domain/lemmy/repository/utils/Mappings.kt @@ -199,7 +199,6 @@ internal fun Post.toModel() = PostModel( publishDate = published, updateDate = updated, nsfw = nsfw, - embedVideoUrl = embedVideoUrl, featuredCommunity = featuredCommunity, featuredLocal = featuredLocal, removed = removed,