diff --git a/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt b/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt index 83466eed0..2a6929735 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt @@ -72,6 +72,7 @@ private object PrefKeys { const val AUTOMATICALLY_START_PLAYBACK = "automatically_start_playback" const val THEME = "theme" const val PREFERRED_LANGUAGE = "preferred_Language" + const val AUTOMATICALLY_LOAD_URL_PREVIEW = "automatically_load_url_preview" val LAST_READ: (String) -> String = { route -> "last_read_route_$route" } } @@ -255,6 +256,11 @@ object LocalPreferences { } else { putBoolean(PrefKeys.AUTOMATICALLY_START_PLAYBACK, account.settings.automaticallyStartPlayback!!) } + if (account.settings.automaticallyShowUrlPreview == null) { + remove(PrefKeys.AUTOMATICALLY_LOAD_URL_PREVIEW) + } else { + putBoolean(PrefKeys.AUTOMATICALLY_LOAD_URL_PREVIEW, account.settings.automaticallyShowUrlPreview!!) + } putString(PrefKeys.PREFERRED_LANGUAGE, account.settings.preferredLanguage ?: "") }.apply() } @@ -396,6 +402,11 @@ object LocalPreferences { } else { null } + settings.automaticallyShowUrlPreview = if (contains(PrefKeys.AUTOMATICALLY_LOAD_URL_PREVIEW)) { + getBoolean(PrefKeys.AUTOMATICALLY_LOAD_URL_PREVIEW, false) + } else { + null + } settings.preferredLanguage = getString(PrefKeys.PREFERRED_LANGUAGE, "") } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt index 4e48823cc..cefa8bf11 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt @@ -86,9 +86,14 @@ class Account( var userProfileCache: User? = null - fun updateGlobalSettings(automaticallyShowImages: Boolean?, automaticallyStartPlayback: Boolean?) { + fun updateGlobalSettings( + automaticallyShowImages: Boolean?, + automaticallyStartPlayback: Boolean?, + automaticallyShowUrlPreview: Boolean? + ) { settings.automaticallyStartPlayback = automaticallyStartPlayback settings.automaticallyShowImages = automaticallyShowImages + settings.automaticallyShowUrlPreview = automaticallyShowUrlPreview live.invalidateData() saveable.invalidateData() } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/Settings.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/Settings.kt index 9d539924f..f4fec29d6 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/Settings.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/Settings.kt @@ -6,5 +6,6 @@ import androidx.compose.runtime.Stable class Settings( var automaticallyShowImages: Boolean? = null, var automaticallyStartPlayback: Boolean? = null, - var preferredLanguage: String? = null + var preferredLanguage: String? = null, + var automaticallyShowUrlPreview: Boolean? = null ) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostView.kt index 8a15cadb1..f0011813b 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostView.kt @@ -332,7 +332,7 @@ fun NewPostView(onClose: () -> Unit, baseReplyTo: Note? = null, quote: Note? = n } else if (videoExtensions.any { removedParamsFromUrl.endsWith(it) }) { VideoView(myUrlPreview, automaticallyStartPlayback = remember { mutableStateOf(true) }) } else { - UrlPreview(myUrlPreview, myUrlPreview) + UrlPreview(myUrlPreview, myUrlPreview, remember { mutableStateOf(true) }) } } else if (startsWithNIP19Scheme(myUrlPreview)) { val bgColor = MaterialTheme.colors.background @@ -348,7 +348,7 @@ fun NewPostView(onClose: () -> Unit, baseReplyTo: Note? = null, quote: Note? = n nav ) } else if (noProtocolUrlValidator.matcher(myUrlPreview).matches()) { - UrlPreview("https://$myUrlPreview", myUrlPreview) + UrlPreview("https://$myUrlPreview", myUrlPreview, remember { mutableStateOf(true) }) } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ExpandableRichTextViewer.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ExpandableRichTextViewer.kt index 9a55840dc..a640e5c07 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ExpandableRichTextViewer.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ExpandableRichTextViewer.kt @@ -68,6 +68,16 @@ fun ExpandableRichTextViewer( ) } + val automaticallyShowUrlPreview = remember { + mutableStateOf( + when (settings?.automaticallyShowUrlPreview) { + true -> !isMobile + false -> false + else -> true + } + ) + } + var showFullText by remember { mutableStateOf(false) } val whereToCut = remember(content) { @@ -98,6 +108,7 @@ fun ExpandableRichTextViewer( accountViewModel, showImage, automaticallyStartPlayback, + automaticallyShowUrlPreview, nav ) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt index 658549f2b..5c063e4a2 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt @@ -110,13 +110,14 @@ fun RichTextViewer( accountViewModel: AccountViewModel, showImage: MutableState, automaticallyStartPlayback: MutableState, + automaticallyShowUrlPreview: MutableState, nav: (String) -> Unit ) { Column(modifier = modifier) { if (remember(content) { isMarkdown(content) }) { RenderContentAsMarkdown(content, tags, nav) } else { - RenderRegular(content, tags, canPreview, backgroundColor, accountViewModel, showImage, automaticallyStartPlayback, nav) + RenderRegular(content, tags, canPreview, backgroundColor, accountViewModel, showImage, automaticallyStartPlayback, automaticallyShowUrlPreview, nav) } } } @@ -131,6 +132,7 @@ private fun RenderRegular( accountViewModel: AccountViewModel, showImage: MutableState, automaticallyStartPlayback: MutableState, + automaticallyShowUrlPreview: MutableState, nav: (String) -> Unit ) { val state by remember(content) { @@ -162,6 +164,7 @@ private fun RenderRegular( accountViewModel, showImage, automaticallyStartPlayback, + automaticallyShowUrlPreview, nav ) } @@ -243,11 +246,12 @@ private fun RenderWordWithPreview( accountViewModel: AccountViewModel, showImage: MutableState, automaticallyStartPlayback: MutableState, + automaticallyShowUrlPreview: MutableState, nav: (String) -> Unit ) { when (word) { is ImageSegment -> ZoomableContentView(word.segmentText, state, showImage, automaticallyStartPlayback) - is LinkSegment -> UrlPreview(word.segmentText, word.segmentText) + is LinkSegment -> UrlPreview(word.segmentText, word.segmentText, automaticallyShowUrlPreview) is EmojiSegment -> RenderCustomEmoji(word.segmentText, state) is InvoiceSegment -> MayBeInvoicePreview(word.segmentText) is WithdrawSegment -> MayBeWithdrawal(word.segmentText) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/UrlPreview.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/UrlPreview.kt index 27641a31d..6c9e5449a 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/UrlPreview.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/UrlPreview.kt @@ -4,6 +4,7 @@ import androidx.compose.animation.Crossfade import androidx.compose.animation.core.tween import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.MutableState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -13,33 +14,41 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @Composable -fun UrlPreview(url: String, urlText: String) { - var urlPreviewState by remember(url) { - mutableStateOf( - UrlCachedPreviewer.cache.get(url)?.let { it } ?: UrlPreviewState.Loading - ) - } +fun UrlPreview(url: String, urlText: String, automaticallyShowUrlPreview: MutableState) { + if (!automaticallyShowUrlPreview.value) { + ClickableUrl(urlText, url) + } else { + var urlPreviewState by remember(url) { + mutableStateOf( + UrlCachedPreviewer.cache.get(url)?.let { it } ?: UrlPreviewState.Loading + ) + } - // Doesn't use a viewModel because of viewModel reusing issues (too many UrlPreview are created). - if (urlPreviewState == UrlPreviewState.Loading) { - LaunchedEffect(url) { - launch(Dispatchers.IO) { - UrlCachedPreviewer.previewInfo(url) { - launch(Dispatchers.Main) { - urlPreviewState = it + // Doesn't use a viewModel because of viewModel reusing issues (too many UrlPreview are created). + if (urlPreviewState == UrlPreviewState.Loading) { + LaunchedEffect(url) { + launch(Dispatchers.IO) { + UrlCachedPreviewer.previewInfo(url) { + launch(Dispatchers.Main) { + urlPreviewState = it + } } } } } - } - Crossfade(targetState = urlPreviewState, animationSpec = tween(durationMillis = 100)) { state -> - when (state) { - is UrlPreviewState.Loaded -> { - UrlPreviewCard(url, state.previewInfo) - } - else -> { - ClickableUrl(urlText, url) + Crossfade( + targetState = urlPreviewState, + animationSpec = tween(durationMillis = 100) + ) { state -> + when (state) { + is UrlPreviewState.Loaded -> { + UrlPreviewCard(url, state.previewInfo, automaticallyShowUrlPreview) + } + + else -> { + ClickableUrl(urlText, url) + } } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/UrlPreviewCard.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/UrlPreviewCard.kt index 29edd4a3e..13e78a92a 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/UrlPreviewCard.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/UrlPreviewCard.kt @@ -9,6 +9,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.material.MaterialTheme import androidx.compose.material.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.MutableState import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color @@ -26,8 +27,12 @@ import com.vitorpamplona.amethyst.ui.theme.subtleBorder @Composable fun UrlPreviewCard( url: String, - previewInfo: UrlInfoItem + previewInfo: UrlInfoItem, + automaticallyShowUrlPreview: MutableState ) { + if (!automaticallyShowUrlPreview.value) { + return ClickableUrl(url, url) + } val uri = LocalUriHandler.current Row( diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt index f55bca325..003f7c926 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt @@ -49,8 +49,12 @@ class AccountViewModel(val account: Account, private val themeViewModel: ThemeVi return themeViewModel.theme.value ?: "System" } - fun updateGlobalSettings(automaticallyShowImages: Boolean?, automaticallyStartPlayback: Boolean?) { - account.updateGlobalSettings(automaticallyShowImages, automaticallyStartPlayback) + fun updateGlobalSettings( + automaticallyShowImages: Boolean?, + automaticallyStartPlayback: Boolean?, + automaticallyShowUrlPreview: Boolean? + ) { + account.updateGlobalSettings(automaticallyShowImages, automaticallyStartPlayback, automaticallyShowUrlPreview) } fun isWriteable(): Boolean { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt index bb9303912..0a9778caa 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt @@ -57,7 +57,6 @@ import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.service.NostrUserProfileDataSource -import com.vitorpamplona.amethyst.service.connectivitystatus.ConnectivityStatus import com.vitorpamplona.amethyst.service.model.AppDefinitionEvent import com.vitorpamplona.amethyst.service.model.BadgeDefinitionEvent import com.vitorpamplona.amethyst.service.model.BadgeProfilesEvent @@ -599,20 +598,6 @@ private fun ProfileHeader( var popupExpanded by remember { mutableStateOf(false) } var zoomImageDialogOpen by remember { mutableStateOf(false) } - val accountState by accountViewModel.accountLiveData.observeAsState() - val settings = accountState?.account?.settings - val isMobile = ConnectivityStatus.isOnMobileData.value - - val showImage = remember { - mutableStateOf( - when (settings?.automaticallyShowImages) { - true -> !isMobile - false -> false - else -> true - } - ) - } - Box { DrawBanner(baseUser) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SettingsScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SettingsScreen.kt index 218b80464..b98079007 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SettingsScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SettingsScreen.kt @@ -116,6 +116,12 @@ fun SettingsScreen( val selectedVideoItem = remember { mutableStateOf(selectedItens[videoIndex]) } + val linkIndex = if (settings.automaticallyShowUrlPreview == null) { 0 } else { + if (settings.automaticallyShowUrlPreview == true) 1 else 2 + } + val selectedLinkItem = remember { + mutableStateOf(selectedItens[linkIndex]) + } val themeItens = arrayOf("System", "Light", "Dark") val themeIndex = themeItens.indexOf(accountViewModel.currentTheme()) @@ -216,6 +222,12 @@ fun SettingsScreen( title = "Automatically play videos" ) + DropDownSettings( + selectedItem = selectedLinkItem, + listItems = selectedItens, + title = "Automatically show url preview" + ) + Row( Modifier.fillMaxWidth(), Arrangement.Center @@ -232,10 +244,15 @@ fun SettingsScreen( 2 -> false else -> null } + val automaticallyShowUrlPreview = when (selectedItens.indexOf(selectedLinkItem.value)) { + 1 -> true + 2 -> false + else -> null + } accountViewModel.changeTheme(selectedTheme.value) scope.launch(Dispatchers.IO) { - accountViewModel.updateGlobalSettings(automaticallyShowImages, automaticallyStartPlayback) + accountViewModel.updateGlobalSettings(automaticallyShowImages, automaticallyStartPlayback, automaticallyShowUrlPreview) LocalPreferences.saveToEncryptedStorage(accountViewModel.account) LocalPreferences.updateTheme(selectedTheme.value) ServiceManager.pause()