From ceb81aa2bfd0caeeeb008e8d6ce920d591db0fbb Mon Sep 17 00:00:00 2001 From: greenart7c3 <115044884+greenart7c3@users.noreply.github.com> Date: Mon, 3 Jul 2023 08:20:15 -0300 Subject: [PATCH 01/29] created button to load images] --- .../ui/components/ZoomableContentView.kt | 50 +++++++++++++------ 1 file changed, 36 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt index 9af8a664a..0d5d3a21b 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt @@ -11,6 +11,7 @@ import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.BoxWithConstraints +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.Row @@ -27,6 +28,7 @@ import androidx.compose.foundation.pager.PagerState import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.foundation.text.InlineTextContent import androidx.compose.foundation.text.appendInlineContent +import androidx.compose.material.Button import androidx.compose.material.Icon import androidx.compose.material.IconButton import androidx.compose.material.LocalTextStyle @@ -175,6 +177,10 @@ fun ZoomableContentView(content: ZoomableContent, images: ImmutableList UrlImageView(content, mainImageModifier) + is ZoomableUrlImage -> UrlImageView(content, mainImageModifier, showImage) is ZoomableUrlVideo -> VideoView(content.url, content.description) { dialogOpen = true } is ZoomableLocalImage -> LocalImageView(content, mainImageModifier) is ZoomableLocalVideo -> @@ -256,7 +262,8 @@ private fun LocalImageView( @Composable private fun UrlImageView( content: ZoomableUrlImage, - mainImageModifier: Modifier + mainImageModifier: Modifier, + showImage: MutableState ) { BoxWithConstraints(contentAlignment = Alignment.Center) { val myModifier = remember { @@ -280,17 +287,19 @@ private fun UrlImageView( mutableStateOf(null) } - AsyncImage( - model = content.url, - contentDescription = content.description, - contentScale = contentScale, - modifier = myModifier, - onState = { - painterState.value = it - } - ) + if (showImage.value) { + AsyncImage( + model = content.url, + contentDescription = content.description, + contentScale = contentScale, + modifier = myModifier, + onState = { + painterState.value = it + } + ) + } - AddedImageFeatures(painterState, content, contentScale, myModifier, verifierModifier) + AddedImageFeatures(painterState, content, contentScale, myModifier, verifierModifier, showImage) } } @@ -336,8 +345,18 @@ private fun AddedImageFeatures( content: ZoomableUrlImage, contentScale: ContentScale, myModifier: Modifier, - verifiedModifier: Modifier + verifiedModifier: Modifier, + showImage: MutableState ) { + if (!showImage.value) { + return Column(horizontalAlignment = Alignment.CenterHorizontally) { + ClickableUrl(urlText = "${content.url} ", url = content.url) + Button(onClick = { showImage.value = true }) { + Text("Load image") + } + } + } + var verifiedHash by remember { mutableStateOf(null) } @@ -548,9 +567,12 @@ fun RenderImageOrVideo(content: ZoomableContent) { val mainModifier = Modifier .fillMaxSize() .zoomable(rememberZoomState()) + val showImage = remember { + mutableStateOf(true) + } if (content is ZoomableUrlImage) { - UrlImageView(content = content, mainImageModifier = mainModifier) + UrlImageView(content = content, mainImageModifier = mainModifier, showImage) } else if (content is ZoomableUrlVideo) { Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxSize(1f)) { VideoView(content.url, content.description) From 7c3d9aad1d63caab4e7bcc3227a6d60619c39b2c Mon Sep 17 00:00:00 2001 From: greenart7c3 <115044884+greenart7c3@users.noreply.github.com> Date: Mon, 3 Jul 2023 09:20:50 -0300 Subject: [PATCH 02/29] add ConnectivityStatus singleton --- .../connectivitystatus/ConnectivityStatus.kt | 17 +++++++++++++++++ .../vitorpamplona/amethyst/ui/MainActivity.kt | 10 +++++++++- .../ui/components/ZoomableContentView.kt | 5 ++++- 3 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/com/vitorpamplona/amethyst/service/connectivitystatus/ConnectivityStatus.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/connectivitystatus/ConnectivityStatus.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/connectivitystatus/ConnectivityStatus.kt new file mode 100644 index 000000000..c119001bb --- /dev/null +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/connectivitystatus/ConnectivityStatus.kt @@ -0,0 +1,17 @@ +package com.vitorpamplona.amethyst.service.connectivitystatus + +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.mutableStateOf + +object ConnectivityStatus { + private val onMobileData = mutableStateOf(false) + val isOnMobileData: MutableState = onMobileData + + private val onWifi = mutableStateOf(false) + val isOnWifi: MutableState = onWifi + + fun updateConnectivityStatus(isOnMobileData: Boolean, isOnWifi: Boolean) { + onMobileData.value = isOnMobileData + onWifi.value = isOnWifi + } +} diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt index 52c21b937..6f299b350 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt @@ -19,6 +19,7 @@ import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.BuildConfig import com.vitorpamplona.amethyst.LocalPreferences import com.vitorpamplona.amethyst.ServiceManager +import com.vitorpamplona.amethyst.service.connectivitystatus.ConnectivityStatus import com.vitorpamplona.amethyst.service.model.ChannelCreateEvent import com.vitorpamplona.amethyst.service.model.ChannelMessageEvent import com.vitorpamplona.amethyst.service.model.ChannelMetadataEvent @@ -41,7 +42,6 @@ import java.net.URLEncoder import java.nio.charset.StandardCharsets class MainActivity : FragmentActivity() { - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -130,6 +130,14 @@ class MainActivity : FragmentActivity() { networkCapabilities: NetworkCapabilities ) { super.onCapabilitiesChanged(network, networkCapabilities) + val hasMobileData = networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) + val hasWifi = networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) + Log.d("NETWORKCALLBACK", "onCapabilitiesChanged: hasMobileData $hasMobileData") + Log.d("NETWORKCALLBACK", "onCapabilitiesChanged: hasWifi $hasWifi") + ConnectivityStatus.updateConnectivityStatus( + networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR), + networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) + ) } // lost network connection diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt index 0d5d3a21b..7a259c1be 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt @@ -72,6 +72,7 @@ import coil.imageLoader import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.toHexKey import com.vitorpamplona.amethyst.service.BlurHashRequester +import com.vitorpamplona.amethyst.service.connectivitystatus.ConnectivityStatus import com.vitorpamplona.amethyst.ui.actions.CloseButton import com.vitorpamplona.amethyst.ui.actions.LoadingAnimation import com.vitorpamplona.amethyst.ui.actions.SaveToGallery @@ -177,8 +178,10 @@ fun ZoomableContentView(content: ZoomableContent, images: ImmutableList Date: Mon, 3 Jul 2023 10:32:08 -0300 Subject: [PATCH 03/29] do not autoplay videos when on mobile data --- .../amethyst/ui/actions/NewMediaView.kt | 5 ++- .../amethyst/ui/actions/NewPostView.kt | 4 +-- .../amethyst/ui/components/VideoView.kt | 36 +++++++++++++------ .../ui/components/ZoomableContentView.kt | 8 ++--- .../amethyst/ui/note/NoteCompose.kt | 9 +++-- 5 files changed, 41 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaView.kt index dd3750337..e0203b0d7 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaView.kt @@ -179,8 +179,11 @@ fun ImageVideoPost(postViewModel: NewMediaModel, acc: Account) { ) } } else { + val showVideo = remember { + mutableStateOf(true) + } postViewModel.galleryUri?.let { - VideoView(it.toString()) + VideoView(it.toString(), showVideo = showVideo) } } } 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 89bb3d5a5..34c096888 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 @@ -330,7 +330,7 @@ fun NewPostView(onClose: () -> Unit, baseReplyTo: Note? = null, quote: Note? = n ) ) } else if (videoExtensions.any { removedParamsFromUrl.endsWith(it) }) { - VideoView(myUrlPreview) + VideoView(myUrlPreview, showVideo = remember { mutableStateOf(true) }) } else { UrlPreview(myUrlPreview, myUrlPreview) } @@ -966,7 +966,7 @@ fun ImageVideoDescription( ) } } else { - VideoView(uri.toString()) + VideoView(uri.toString(), showVideo = remember { mutableStateOf(true) }) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/VideoView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/VideoView.kt index 8859a32b9..25f44f746 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/VideoView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/VideoView.kt @@ -25,6 +25,7 @@ import androidx.compose.material.icons.filled.VolumeUp import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.MutableState import androidx.compose.runtime.Stable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -68,7 +69,13 @@ import kotlin.time.measureTimedValue public var DefaultMutedSetting = mutableStateOf(true) @Composable -fun LoadThumbAndThenVideoView(videoUri: String, description: String? = null, thumbUri: String, onDialog: ((Boolean) -> Unit)? = null) { +fun LoadThumbAndThenVideoView( + videoUri: String, + description: String? = null, + thumbUri: String, + showVideo: MutableState, + onDialog: ((Boolean) -> Unit)? = null +) { var loadingFinished by remember { mutableStateOf>(Pair(false, null)) } val context = LocalContext.current @@ -92,9 +99,9 @@ fun LoadThumbAndThenVideoView(videoUri: String, description: String? = null, thu if (loadingFinished.first) { if (loadingFinished.second != null) { - VideoView(videoUri, description, VideoThumb(loadingFinished.second), onDialog) + VideoView(videoUri, description, VideoThumb(loadingFinished.second), showVideo, onDialog) } else { - VideoView(videoUri, description, null, onDialog) + VideoView(videoUri, description, null, showVideo, onDialog) } } } @@ -105,10 +112,11 @@ fun VideoView( videoUri: String, description: String? = null, thumb: VideoThumb? = null, + showVideo: MutableState, onDialog: ((Boolean) -> Unit)? = null ) { val (value, elapsed) = measureTimedValue { - VideoView1(videoUri, description, thumb, onDialog) + VideoView1(videoUri, description, thumb, onDialog, showVideo) } Log.d("Rendering Metrics", "VideoView $elapsed $videoUri") } @@ -118,7 +126,8 @@ fun VideoView1( videoUri: String, description: String? = null, thumb: VideoThumb? = null, - onDialog: ((Boolean) -> Unit)? = null + onDialog: ((Boolean) -> Unit)? = null, + showVideo: MutableState ) { var exoPlayerData by remember { mutableStateOf(null) } val defaultToStart by remember { mutableStateOf(DefaultMutedSetting.value) } @@ -133,7 +142,7 @@ fun VideoView1( } exoPlayerData?.let { - VideoView(videoUri, description, it, defaultToStart, thumb, onDialog) + VideoView(videoUri, description, it, defaultToStart, thumb, onDialog, showVideo = showVideo) } DisposableEffect(Unit) { @@ -151,10 +160,11 @@ fun VideoView( exoPlayerData: VideoPlayer, defaultToStart: Boolean = false, thumb: VideoThumb? = null, - onDialog: ((Boolean) -> Unit)? = null + onDialog: ((Boolean) -> Unit)? = null, + showVideo: MutableState ) { val (value, elapsed) = measureTimedValue { - VideoView1(videoUri, description, exoPlayerData, defaultToStart, thumb, onDialog) + VideoView1(videoUri, description, exoPlayerData, defaultToStart, thumb, onDialog, showVideo) } Log.d("Rendering Metrics", "VideoView $elapsed $videoUri") } @@ -166,7 +176,8 @@ fun VideoView1( exoPlayerData: VideoPlayer, defaultToStart: Boolean = false, thumb: VideoThumb? = null, - onDialog: ((Boolean) -> Unit)? = null + onDialog: ((Boolean) -> Unit)? = null, + showVideo: MutableState ) { val lifecycleOwner = rememberUpdatedState(LocalLifecycleOwner.current) @@ -196,7 +207,7 @@ fun VideoView1( prepare() } - RenderVideoPlayer(exoPlayerData, thumb, onDialog) + RenderVideoPlayer(exoPlayerData, thumb, showVideo, onDialog) DisposableEffect(Unit) { val observer = LifecycleEventObserver { _, event -> @@ -230,6 +241,7 @@ data class VideoThumb( private fun RenderVideoPlayer( playerData: VideoPlayer, thumbData: VideoThumb?, + showVideo: MutableState, onDialog: ((Boolean) -> Unit)? ) { val context = LocalContext.current @@ -241,7 +253,9 @@ private fun RenderVideoPlayer( .defaultMinSize(minHeight = 70.dp) .align(Alignment.Center) .onVisibilityChanges { visible -> - if (visible && !playerData.exoPlayer.isPlaying) { + if (!showVideo.value && visible && !playerData.exoPlayer.isPlaying) { + playerData.exoPlayer.pause() + } else if (visible && !playerData.exoPlayer.isPlaying) { playerData.exoPlayer.play() } else if (!visible && playerData.exoPlayer.isPlaying) { playerData.exoPlayer.pause() diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt index 7a259c1be..c5a1d3087 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt @@ -204,11 +204,11 @@ fun ZoomableContentView(content: ZoomableContent, images: ImmutableList UrlImageView(content, mainImageModifier, showImage) - is ZoomableUrlVideo -> VideoView(content.url, content.description) { dialogOpen = true } + is ZoomableUrlVideo -> VideoView(content.url, content.description, showVideo = showImage) { dialogOpen = true } is ZoomableLocalImage -> LocalImageView(content, mainImageModifier) is ZoomableLocalVideo -> content.localFile?.let { - VideoView(it.toUri().toString(), content.description) { dialogOpen = true } + VideoView(it.toUri().toString(), content.description, showVideo = showImage) { dialogOpen = true } } } @@ -578,14 +578,14 @@ fun RenderImageOrVideo(content: ZoomableContent) { UrlImageView(content = content, mainImageModifier = mainModifier, showImage) } else if (content is ZoomableUrlVideo) { Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxSize(1f)) { - VideoView(content.url, content.description) + VideoView(content.url, content.description, showVideo = showImage) } } else if (content is ZoomableLocalImage) { LocalImageView(content = content, mainImageModifier = mainModifier) } else if (content is ZoomableLocalVideo) { Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxSize(1f)) { content.localFile?.let { - VideoView(it.toUri().toString(), content.description) + VideoView(it.toUri().toString(), content.description, showVideo = showImage) } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt index 5d1f51c25..a669c4b91 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt @@ -3043,12 +3043,14 @@ fun AudioTrackHeader(noteEvent: AudioTrackEvent, accountViewModel: AccountViewMo LoadThumbAndThenVideoView( videoUri = media, description = noteEvent.subject(), - thumbUri = cover + thumbUri = cover, + showVideo = remember { mutableStateOf(true) } ) } ?: VideoView( videoUri = media, - noteEvent.subject() + description = noteEvent.subject(), + showVideo = remember { mutableStateOf(true) } ) } } @@ -3172,7 +3174,8 @@ fun RenderLiveActivityEventInner(baseNote: Note, accountViewModel: AccountViewMo ) { VideoView( videoUri = media, - description = subject + description = subject, + showVideo = remember { mutableStateOf(true) } ) } } else { From a5f10fef60a1bcd29d1cdd0a21ebefb95ce67a18 Mon Sep 17 00:00:00 2001 From: greenart7c3 <115044884+greenart7c3@users.noreply.github.com> Date: Mon, 3 Jul 2023 14:00:16 -0300 Subject: [PATCH 04/29] created settings screen --- .../amethyst/ui/navigation/AppNavigation.kt | 10 ++ .../amethyst/ui/navigation/DrawerContent.kt | 9 ++ .../amethyst/ui/navigation/Routes.kt | 5 + .../ui/screen/loggedIn/SettingsScreen.kt | 104 ++++++++++++++++++ app/src/main/res/values/strings.xml | 1 + 5 files changed, 129 insertions(+) create mode 100644 app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SettingsScreen.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt index 6e3f5bcf1..0278f3646 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt @@ -34,6 +34,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.LoadRedirectScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.NotificationScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.ProfileScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.SearchScreen +import com.vitorpamplona.amethyst.ui.screen.loggedIn.SettingsScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.ThreadScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.VideoScreen import kotlinx.coroutines.delay @@ -219,6 +220,15 @@ fun AppNavigation( ) }) } + + Route.Settings.let { route -> + composable(route.route, route.arguments, content = { + SettingsScreen( + accountViewModel = accountViewModel, + nav = nav + ) + }) + } } actionableNextPage?.let { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt index b115e5b56..b69c5d5c3 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt @@ -355,6 +355,15 @@ fun ListContent( route = Route.BlockedUsers.route ) + NavigationRow( + title = stringResource(R.string.settings), + icon = Route.Settings.icon, + tint = MaterialTheme.colors.onBackground, + nav = nav, + scaffoldState = scaffoldState, + route = Route.Settings.route + ) + IconRow( title = stringResource(R.string.backup_keys), icon = R.drawable.ic_key, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/Routes.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/Routes.kt index eec35833e..008cc0e10 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/Routes.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/Routes.kt @@ -128,6 +128,11 @@ sealed class Route( icon = R.drawable.ic_moments, arguments = listOf(navArgument("id") { type = NavType.StringType }).toImmutableList() ) + + object Settings : Route( + route = "Settings", + icon = com.google.android.exoplayer2.R.drawable.exo_ic_settings + ) } // ** 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 new file mode 100644 index 000000000..5c8c7b1f1 --- /dev/null +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SettingsScreen.kt @@ -0,0 +1,104 @@ +package com.vitorpamplona.amethyst.ui.screen.loggedIn + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.material.DropdownMenuItem +import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.material.ExposedDropdownMenuBox +import androidx.compose.material.ExposedDropdownMenuDefaults +import androidx.compose.material.Text +import androidx.compose.material.TextField +import androidx.compose.runtime.Composable +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp +import com.vitorpamplona.amethyst.ui.theme.DoubleVertSpacer +import com.vitorpamplona.amethyst.ui.theme.StdPadding + +@Composable +fun SettingsScreen( + accountViewModel: AccountViewModel, + nav: (String) -> Unit +) { + val listItems = arrayOf("Always", "Wifi-only", "Never") + val selectedItem = remember { + mutableStateOf(listItems[0]) + } + + val context = LocalContext.current + Column( + StdPadding + ) { + Section("Account preferences") + + Section("Application preferences") + Text( + "Media", + fontWeight = FontWeight.Bold + ) + DropDownSettings( + selectedItem = selectedItem, + listItems = listItems + ) + } +} + +@OptIn(ExperimentalMaterialApi::class) +@Composable +fun DropDownSettings( + selectedItem: MutableState, + listItems: Array +) { + var expanded by remember { + mutableStateOf(false) + } + ExposedDropdownMenuBox( + expanded = expanded, + onExpandedChange = { + expanded = !expanded + } + ) { + TextField( + value = selectedItem.value, + onValueChange = {}, + readOnly = true, + label = { Text(text = "Automatically load images/gifs") }, + trailingIcon = { + ExposedDropdownMenuDefaults.TrailingIcon( + expanded = expanded + ) + }, + colors = ExposedDropdownMenuDefaults.textFieldColors() + ) + + ExposedDropdownMenu( + expanded = expanded, + onDismissRequest = { expanded = false } + ) { + listItems.forEach { selectedOption -> + DropdownMenuItem(onClick = { + selectedItem.value = selectedOption + expanded = false + }) { + Text(text = selectedOption) + } + } + } + } +} + +@Composable +fun Section(text: String) { + Spacer(modifier = DoubleVertSpacer) + Text( + text = text, + fontWeight = FontWeight.Bold, + fontSize = 20.sp + ) + Spacer(modifier = DoubleVertSpacer) +} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 748189d02..8babaa30f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -483,4 +483,5 @@ Sensitive Content Adds sensitive content warning before showing this content + Settings From a639c3f36dbbad7084a139b70bc6edfbeb16be7e Mon Sep 17 00:00:00 2001 From: greenart7c3 <115044884+greenart7c3@users.noreply.github.com> Date: Mon, 3 Jul 2023 18:10:25 -0300 Subject: [PATCH 05/29] add media settings --- .../main/java/com/vitorpamplona/amethyst/model/Settings.kt | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 app/src/main/java/com/vitorpamplona/amethyst/model/Settings.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/Settings.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/Settings.kt new file mode 100644 index 000000000..dc8ccdf41 --- /dev/null +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/Settings.kt @@ -0,0 +1,4 @@ +package com.vitorpamplona.amethyst.model + +class Settings { +} \ No newline at end of file From 68e8a13f73b5d951a41738743fc0db7b7ee821c7 Mon Sep 17 00:00:00 2001 From: greenart7c3 <115044884+greenart7c3@users.noreply.github.com> Date: Wed, 5 Jul 2023 07:37:06 -0300 Subject: [PATCH 06/29] add options to disable auto playback e show images in the settings screen --- .../amethyst/LocalPreferences.kt | 36 +++++++- .../vitorpamplona/amethyst/model/Account.kt | 10 ++- .../vitorpamplona/amethyst/model/Settings.kt | 9 +- .../ui/screen/loggedIn/AccountViewModel.kt | 4 + .../ui/screen/loggedIn/SettingsScreen.kt | 89 ++++++++++++++++--- 5 files changed, 132 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt b/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt index 43124fee9..baa47ed90 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt @@ -10,6 +10,7 @@ import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.GLOBAL_FOLLOWS import com.vitorpamplona.amethyst.model.KIND3_FOLLOWS import com.vitorpamplona.amethyst.model.RelaySetupInfo +import com.vitorpamplona.amethyst.model.Settings import com.vitorpamplona.amethyst.model.hexToByteArray import com.vitorpamplona.amethyst.service.HttpClient import com.vitorpamplona.amethyst.service.model.ContactListEvent @@ -67,6 +68,8 @@ private object PrefKeys { const val WARN_ABOUT_REPORTS = "warn_about_reports" const val FILTER_SPAM_FROM_STRANGERS = "filter_spam_from_strangers" const val LAST_READ_PER_ROUTE = "last_read_route_per_route" + const val AUTOMATICALLY_SHOW_IMAGES = "automatically_show_images" + const val AUTOMATICALLY_START_PLAYBACK = "automatically_start_playback" val LAST_READ: (String) -> String = { route -> "last_read_route_$route" } } @@ -236,6 +239,21 @@ object LocalPreferences { putBoolean(PrefKeys.SHOW_SENSITIVE_CONTENT, account.showSensitiveContent!!) } }.apply() + + val globalPrefs = encryptedPreferences() + globalPrefs.edit().apply { + if (account.settings.automaticallyShowImages == null) { + remove(PrefKeys.AUTOMATICALLY_SHOW_IMAGES) + } else { + putBoolean(PrefKeys.AUTOMATICALLY_SHOW_IMAGES, account.settings.automaticallyShowImages!!) + } + + if (account.settings.automaticallyStartPlayback == null) { + remove(PrefKeys.AUTOMATICALLY_START_PLAYBACK) + } else { + putBoolean(PrefKeys.AUTOMATICALLY_START_PLAYBACK, account.settings.automaticallyStartPlayback!!) + } + }.apply() } fun loadFromEncryptedStorage(): Account? { @@ -340,6 +358,21 @@ object LocalPreferences { mapOf() } + val settings = Settings(null, null) + encryptedPreferences().apply { + settings.automaticallyShowImages = if (contains(PrefKeys.AUTOMATICALLY_SHOW_IMAGES)) { + getBoolean(PrefKeys.AUTOMATICALLY_SHOW_IMAGES, false) + } else { + null + } + + settings.automaticallyStartPlayback = if (contains(PrefKeys.AUTOMATICALLY_START_PLAYBACK)) { + getBoolean(PrefKeys.AUTOMATICALLY_START_PLAYBACK, false) + } else { + null + } + } + val a = Account( loggedIn = Persona(privKey = privKey?.hexToByteArray(), pubKey = pubKey.hexToByteArray()), followingChannels = followingChannels, @@ -366,7 +399,8 @@ object LocalPreferences { showSensitiveContent = showSensitiveContent, warnAboutPostsWithReports = warnAboutReports, filterSpamFromStrangers = filterSpam, - lastReadPerRoute = lastReadPerRoute + lastReadPerRoute = lastReadPerRoute, + settings = settings ) return a 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 b1a5c9a7f..4e48823cc 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt @@ -73,7 +73,8 @@ class Account( var showSensitiveContent: Boolean? = null, var warnAboutPostsWithReports: Boolean = true, var filterSpamFromStrangers: Boolean = true, - var lastReadPerRoute: Map = mapOf() + var lastReadPerRoute: Map = mapOf(), + var settings: Settings = Settings(null, null) ) { var transientHiddenUsers: Set = setOf() @@ -85,6 +86,13 @@ class Account( var userProfileCache: User? = null + fun updateGlobalSettings(automaticallyShowImages: Boolean?, automaticallyStartPlayback: Boolean?) { + settings.automaticallyStartPlayback = automaticallyStartPlayback + settings.automaticallyShowImages = automaticallyShowImages + live.invalidateData() + saveable.invalidateData() + } + fun updateOptOutOptions(warnReports: Boolean, filterSpam: Boolean) { warnAboutPostsWithReports = warnReports filterSpamFromStrangers = filterSpam 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 dc8ccdf41..448afd677 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/Settings.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/Settings.kt @@ -1,4 +1,9 @@ package com.vitorpamplona.amethyst.model -class Settings { -} \ No newline at end of file +import androidx.compose.runtime.Stable + +@Stable +class Settings( + var automaticallyShowImages: Boolean?, + var automaticallyStartPlayback: Boolean? +) 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 6456340a9..91082ac97 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 @@ -40,6 +40,10 @@ class AccountViewModel(val account: Account) : ViewModel() { val userFollows: LiveData = account.userProfile().live().follows.map { it } val userRelays: LiveData = account.userProfile().live().relays.map { it } + fun updateGlobalSettings(automaticallyShowImages: Boolean?, automaticallyStartPlayback: Boolean?) { + account.updateGlobalSettings(automaticallyShowImages, automaticallyStartPlayback) + } + fun isWriteable(): Boolean { return account.isWriteable() } 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 5c8c7b1f1..a0d937843 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 @@ -1,7 +1,11 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.material.Button import androidx.compose.material.DropdownMenuItem import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.ExposedDropdownMenuBox @@ -13,38 +17,95 @@ import androidx.compose.runtime.MutableState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.sp +import com.vitorpamplona.amethyst.LocalPreferences +import com.vitorpamplona.amethyst.ServiceManager import com.vitorpamplona.amethyst.ui.theme.DoubleVertSpacer import com.vitorpamplona.amethyst.ui.theme.StdPadding +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch @Composable fun SettingsScreen( accountViewModel: AccountViewModel, nav: (String) -> Unit ) { - val listItems = arrayOf("Always", "Wifi-only", "Never") - val selectedItem = remember { - mutableStateOf(listItems[0]) + val scope = rememberCoroutineScope() + val selectedItens = arrayOf("Always", "Wifi-only", "Never") + val settings = accountViewModel.account.settings + val index = if (settings.automaticallyShowImages == null) { 0 } else { + if (settings.automaticallyShowImages == true) 1 else 2 + } + val videoIndex = if (settings.automaticallyStartPlayback == null) { 0 } else { + if (settings.automaticallyShowImages == true) 1 else 2 + } + val selectedItem = remember { + mutableStateOf(selectedItens[index]) + } + val selectedVideoItem = remember { + mutableStateOf(selectedItens[videoIndex]) } - val context = LocalContext.current Column( - StdPadding + StdPadding, + horizontalAlignment = Alignment.CenterHorizontally ) { Section("Account preferences") Section("Application preferences") + Text( "Media", fontWeight = FontWeight.Bold ) + DropDownSettings( selectedItem = selectedItem, - listItems = listItems + listItems = selectedItens, + title = "Automatically load images/gifs" ) + + Spacer(modifier = DoubleVertSpacer) + + DropDownSettings( + selectedItem = selectedVideoItem, + listItems = selectedItens, + title = "Automatically play videos" + ) + + Row( + Modifier.fillMaxWidth(), + Arrangement.Center + ) { + Button( + onClick = { + val automaticallyShowImages = when (selectedItens.indexOf(selectedItem.value)) { + 1 -> true + 2 -> false + else -> null + } + val automaticallyStartPlayback = when (selectedItens.indexOf(selectedVideoItem.value)) { + 1 -> true + 2 -> false + else -> null + } + scope.launch(Dispatchers.IO) { + accountViewModel.updateGlobalSettings(automaticallyShowImages, automaticallyStartPlayback) + LocalPreferences.saveToEncryptedStorage(accountViewModel.account) + ServiceManager.pause() + ServiceManager.start(context) + } + } + ) { + Text(text = "Save") + } + } } } @@ -52,7 +113,8 @@ fun SettingsScreen( @Composable fun DropDownSettings( selectedItem: MutableState, - listItems: Array + listItems: Array, + title: String ) { var expanded by remember { mutableStateOf(false) @@ -64,10 +126,11 @@ fun DropDownSettings( } ) { TextField( + modifier = Modifier.fillMaxWidth(), value = selectedItem.value, onValueChange = {}, readOnly = true, - label = { Text(text = "Automatically load images/gifs") }, + label = { Text(text = title) }, trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon( expanded = expanded @@ -81,10 +144,12 @@ fun DropDownSettings( onDismissRequest = { expanded = false } ) { listItems.forEach { selectedOption -> - DropdownMenuItem(onClick = { - selectedItem.value = selectedOption - expanded = false - }) { + DropdownMenuItem( + onClick = { + selectedItem.value = selectedOption + expanded = false + } + ) { Text(text = selectedOption) } } From fee6f19d5ee5a2576ad5b936b32bbd53370908e8 Mon Sep 17 00:00:00 2001 From: greenart7c3 <115044884+greenart7c3@users.noreply.github.com> Date: Wed, 5 Jul 2023 09:21:48 -0300 Subject: [PATCH 07/29] check for load images option --- .../ui/components/ExpandableRichTextViewer.kt | 17 ++++++ .../amethyst/ui/components/RichTextViewer.kt | 12 ++-- .../amethyst/ui/components/VideoView.kt | 3 + .../ui/components/ZoomableContentView.kt | 60 ++++++++++--------- .../amethyst/ui/note/ChannelCardCompose.kt | 33 +++++++++- .../amethyst/ui/note/NoteCompose.kt | 38 +++++++++++- .../amethyst/ui/screen/ThreadFeedView.kt | 18 +++++- .../ui/screen/loggedIn/ChannelScreen.kt | 21 +++++++ .../ui/screen/loggedIn/ProfileScreen.kt | 17 +++++- .../ui/screen/loggedIn/VideoScreen.kt | 18 +++++- 10 files changed, 197 insertions(+), 40 deletions(-) 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 1b715234a..6d8a88ba8 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 @@ -15,6 +15,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue +import androidx.compose.runtime.livedata.observeAsState import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue @@ -24,6 +25,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.R +import com.vitorpamplona.amethyst.service.connectivitystatus.ConnectivityStatus import com.vitorpamplona.amethyst.ui.actions.ImmutableListOfLists import com.vitorpamplona.amethyst.ui.note.getGradient import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel @@ -42,6 +44,20 @@ fun ExpandableRichTextViewer( accountViewModel: AccountViewModel, nav: (String) -> Unit ) { + 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 + } + ) + } + var showFullText by remember { mutableStateOf(false) } val whereToCut = remember(content) { @@ -70,6 +86,7 @@ fun ExpandableRichTextViewer( tags, backgroundColor, accountViewModel, + showImage, 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 a1b02d928..93c0e8a78 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 @@ -108,13 +108,14 @@ fun RichTextViewer( tags: ImmutableListOfLists, backgroundColor: MutableState, accountViewModel: AccountViewModel, + showImage: MutableState, nav: (String) -> Unit ) { Column(modifier = modifier) { if (remember(content) { isMarkdown(content) }) { RenderContentAsMarkdown(content, tags, nav) } else { - RenderRegular(content, tags, canPreview, backgroundColor, accountViewModel, nav) + RenderRegular(content, tags, canPreview, backgroundColor, accountViewModel, showImage, nav) } } } @@ -127,6 +128,7 @@ private fun RenderRegular( canPreview: Boolean, backgroundColor: MutableState, accountViewModel: AccountViewModel, + showImage: MutableState, nav: (String) -> Unit ) { val state by remember(content) { @@ -156,6 +158,7 @@ private fun RenderRegular( backgroundColor, textStyle, accountViewModel, + showImage, nav ) } @@ -235,10 +238,11 @@ private fun RenderWordWithPreview( backgroundColor: MutableState, style: TextStyle, accountViewModel: AccountViewModel, + showImage: MutableState, nav: (String) -> Unit ) { when (word) { - is ImageSegment -> ZoomableContentView(word.segmentText, state) + is ImageSegment -> ZoomableContentView(word.segmentText, state, showImage) is LinkSegment -> UrlPreview(word.segmentText, word.segmentText) is EmojiSegment -> RenderCustomEmoji(word.segmentText, state) is InvoiceSegment -> MayBeInvoicePreview(word.segmentText) @@ -256,9 +260,9 @@ private fun RenderWordWithPreview( } @Composable -private fun ZoomableContentView(word: String, state: RichTextViewerState) { +private fun ZoomableContentView(word: String, state: RichTextViewerState, showImage: MutableState) { state.imagesForPager[word]?.let { - ZoomableContentView(it, state.imageList) + ZoomableContentView(it, state.imageList, showImage) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/VideoView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/VideoView.kt index 25f44f746..62c665e9d 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/VideoView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/VideoView.kt @@ -253,6 +253,9 @@ private fun RenderVideoPlayer( .defaultMinSize(minHeight = 70.dp) .align(Alignment.Center) .onVisibilityChanges { visible -> + if (!showVideo.value) { + playerData.exoPlayer.stop() + } if (!showVideo.value && visible && !playerData.exoPlayer.isPlaying) { playerData.exoPlayer.pause() } else if (visible && !playerData.exoPlayer.isPlaying) { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt index c5a1d3087..d61c9291a 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt @@ -5,7 +5,6 @@ import android.os.Build import android.util.Log import android.widget.Toast import androidx.compose.foundation.ExperimentalFoundationApi -import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.layout.Arrangement @@ -72,7 +71,6 @@ import coil.imageLoader import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.toHexKey import com.vitorpamplona.amethyst.service.BlurHashRequester -import com.vitorpamplona.amethyst.service.connectivitystatus.ConnectivityStatus import com.vitorpamplona.amethyst.ui.actions.CloseButton import com.vitorpamplona.amethyst.ui.actions.LoadingAnimation import com.vitorpamplona.amethyst.ui.actions.SaveToGallery @@ -170,7 +168,7 @@ fun figureOutMimeType(fullUrl: String): ZoomableContent { @Composable @OptIn(ExperimentalFoundationApi::class) -fun ZoomableContentView(content: ZoomableContent, images: ImmutableList = listOf(content).toImmutableList()) { +fun ZoomableContentView(content: ZoomableContent, images: ImmutableList = listOf(content).toImmutableList(), showImage: MutableState) { val clipboardManager = LocalClipboardManager.current // store the dialog open or close state @@ -178,12 +176,6 @@ fun ZoomableContentView(content: ZoomableContent, images: ImmutableList UrlImageView(content, mainImageModifier, showImage) is ZoomableUrlVideo -> VideoView(content.url, content.description, showVideo = showImage) { dialogOpen = true } - is ZoomableLocalImage -> LocalImageView(content, mainImageModifier) + is ZoomableLocalImage -> LocalImageView(content, mainImageModifier, showImage) is ZoomableLocalVideo -> content.localFile?.let { VideoView(it.toUri().toString(), content.description, showVideo = showImage) { dialogOpen = true } @@ -220,7 +212,8 @@ fun ZoomableContentView(content: ZoomableContent, images: ImmutableList ) { if (content.localFile != null && content.localFile.exists()) { BoxWithConstraints(contentAlignment = Alignment.Center) { @@ -245,17 +238,19 @@ private fun LocalImageView( mutableStateOf(null) } - AsyncImage( - model = content.localFile, - contentDescription = content.description, - contentScale = contentScale, - modifier = myModifier, - onState = { - painterState.value = it - } - ) + if (showImage.value) { + AsyncImage( + model = content.localFile, + contentDescription = content.description, + contentScale = contentScale, + modifier = myModifier, + onState = { + painterState.value = it + } + ) + } - AddedImageFeatures(painterState, content, contentScale, myModifier, verifierModifier) + AddedImageFeatures(painterState, content, contentScale, myModifier, verifierModifier, showImage) } } else { BlankNote() @@ -313,8 +308,18 @@ private fun AddedImageFeatures( content: ZoomableLocalImage, contentScale: ContentScale, myModifier: Modifier, - verifiedModifier: Modifier + verifiedModifier: Modifier, + showImage: MutableState ) { + if (!showImage.value) { + return Column(horizontalAlignment = Alignment.CenterHorizontally) { + ClickableUrl(urlText = "${content.uri} ", url = content.uri) + Button(onClick = { showImage.value = true }) { + Text("Load image") + } + } + } + when (painter.value) { null, is AsyncImagePainter.State.Loading -> { if (content.blurhash != null) { @@ -537,11 +542,11 @@ fun ZoomableImageDialog(imageUrl: ZoomableContent, allImages: ImmutableList - RenderImageOrVideo(allImages[index]) + RenderImageOrVideo(allImages[index], remember { mutableStateOf(true) }) } ) } else { - RenderImageOrVideo(imageUrl) + RenderImageOrVideo(imageUrl, remember { mutableStateOf(true) }) } Row( @@ -566,13 +571,10 @@ fun ZoomableImageDialog(imageUrl: ZoomableContent, allImages: ImmutableList) { val mainModifier = Modifier .fillMaxSize() .zoomable(rememberZoomState()) - val showImage = remember { - mutableStateOf(true) - } if (content is ZoomableUrlImage) { UrlImageView(content = content, mainImageModifier = mainModifier, showImage) @@ -581,7 +583,7 @@ fun RenderImageOrVideo(content: ZoomableContent) { VideoView(content.url, content.description, showVideo = showImage) } } else if (content is ZoomableLocalImage) { - LocalImageView(content = content, mainImageModifier = mainModifier) + LocalImageView(content = content, mainImageModifier = mainModifier, showImage) } else if (content is ZoomableLocalVideo) { Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxSize(1f)) { content.localFile?.let { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChannelCardCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChannelCardCompose.kt index b7ff28c60..b22a59fa4 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChannelCardCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChannelCardCompose.kt @@ -52,6 +52,7 @@ import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.service.OnlineChecker import com.vitorpamplona.amethyst.service.model.ChannelCreateEvent import com.vitorpamplona.amethyst.service.model.CommunityDefinitionEvent +import com.vitorpamplona.amethyst.service.connectivitystatus.ConnectivityStatus import com.vitorpamplona.amethyst.service.model.LiveActivitiesEvent import com.vitorpamplona.amethyst.service.model.LiveActivitiesEvent.Companion.STATUS_ENDED import com.vitorpamplona.amethyst.service.model.LiveActivitiesEvent.Companion.STATUS_LIVE @@ -93,6 +94,20 @@ fun ChannelCardCompose( it.note.event == null }.distinctUntilChanged().observeAsState(baseNote.event == null) + 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 + } + ) + } + Crossfade(targetState = isBlank) { if (it) { LongPressToQuickAction(baseNote = baseNote, accountViewModel = accountViewModel) { showPopup -> @@ -113,6 +128,7 @@ fun ChannelCardCompose( modifier, parentBackgroundColor, accountViewModel, + showImage, nav ) } @@ -126,6 +142,7 @@ fun CheckHiddenChannelCardCompose( modifier: Modifier = Modifier, parentBackgroundColor: MutableState? = null, accountViewModel: AccountViewModel, + showImage: MutableState, nav: (String) -> Unit ) { val isHidden by accountViewModel.accountLiveData.map { @@ -140,6 +157,7 @@ fun CheckHiddenChannelCardCompose( modifier, parentBackgroundColor, accountViewModel, + showImage, nav ) } @@ -153,6 +171,7 @@ fun LoadedChannelCardCompose( modifier: Modifier = Modifier, parentBackgroundColor: MutableState? = null, accountViewModel: AccountViewModel, + showImage: MutableState, nav: (String) -> Unit ) { var state by remember { @@ -184,6 +203,7 @@ fun LoadedChannelCardCompose( modifier, parentBackgroundColor, accountViewModel, + showImage, nav ) } @@ -197,6 +217,7 @@ fun RenderChannelCardReportState( modifier: Modifier = Modifier, parentBackgroundColor: MutableState? = null, accountViewModel: AccountViewModel, + showImage: MutableState, nav: (String) -> Unit ) { var showReportedNote by remember { mutableStateOf(false) } @@ -218,6 +239,7 @@ fun RenderChannelCardReportState( modifier, parentBackgroundColor, accountViewModel, + showImage, nav ) } @@ -231,6 +253,7 @@ fun NormalChannelCard( modifier: Modifier = Modifier, parentBackgroundColor: MutableState? = null, accountViewModel: AccountViewModel, + showImage: MutableState, nav: (String) -> Unit ) { LongPressToQuickAction(baseNote = baseNote, accountViewModel = accountViewModel) { showPopup -> @@ -240,6 +263,7 @@ fun NormalChannelCard( modifier, parentBackgroundColor, accountViewModel, + showImage, showPopup, nav ) @@ -253,6 +277,7 @@ private fun CheckNewAndRenderChannelCard( modifier: Modifier = Modifier, parentBackgroundColor: MutableState? = null, accountViewModel: AccountViewModel, + showImage: MutableState, showPopup: () -> Unit, nav: (String) -> Unit ) { @@ -310,6 +335,7 @@ private fun CheckNewAndRenderChannelCard( InnerChannelCardWithReactions( baseNote = baseNote, accountViewModel = accountViewModel, + showImage, nav = nav ) } @@ -319,6 +345,7 @@ private fun CheckNewAndRenderChannelCard( fun InnerChannelCardWithReactions( baseNote: Note, accountViewModel: AccountViewModel, + showImage: MutableState, nav: (String) -> Unit ) { Column(StdPadding) { @@ -339,11 +366,12 @@ fun InnerChannelCardWithReactions( private fun RenderNoteRow( baseNote: Note, accountViewModel: AccountViewModel, + showImage: MutableState, nav: (String) -> Unit ) { when (remember { baseNote.event }) { is LiveActivitiesEvent -> { - RenderLiveActivityThumb(baseNote, accountViewModel, nav) + RenderLiveActivityThumb(baseNote, accountViewModel, showImage, nav) } is CommunityDefinitionEvent -> { RenderCommunitiesThumb(baseNote, accountViewModel, nav) @@ -355,7 +383,7 @@ private fun RenderNoteRow( } @Composable -fun RenderLiveActivityThumb(baseNote: Note, accountViewModel: AccountViewModel, nav: (String) -> Unit) { +fun RenderLiveActivityThumb(baseNote: Note, accountViewModel: AccountViewModel, showImage: MutableState, nav: (String) -> Unit) { val noteEvent = baseNote.event as? LiveActivitiesEvent ?: return val eventUpdates by baseNote.live().metadata.observeAsState() @@ -492,6 +520,7 @@ fun RenderLiveActivityThumb(baseNote: Note, accountViewModel: AccountViewModel, Modifier.padding(start = 0.dp, end = 0.dp, top = 5.dp, bottom = 5.dp) }, accountViewModel = accountViewModel, + showImage = showImage, nav = nav ) } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt index a669c4b91..e8f0893fc 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt @@ -86,6 +86,7 @@ import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.model.UserMetadata import com.vitorpamplona.amethyst.service.OnlineChecker import com.vitorpamplona.amethyst.service.model.ATag +import com.vitorpamplona.amethyst.service.connectivitystatus.ConnectivityStatus import com.vitorpamplona.amethyst.service.model.AppDefinitionEvent import com.vitorpamplona.amethyst.service.model.AudioTrackEvent import com.vitorpamplona.amethyst.service.model.BadgeAwardEvent @@ -210,6 +211,20 @@ fun NoteCompose( it.note.event == null }.distinctUntilChanged().observeAsState(baseNote.event == null) + 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 + } + ) + } + Crossfade(targetState = isBlank) { if (it) { LongPressToQuickAction(baseNote = baseNote, accountViewModel = accountViewModel) { showPopup -> @@ -235,6 +250,7 @@ fun NoteCompose( addMarginTop, parentBackgroundColor, accountViewModel, + showImage, nav ) } @@ -253,6 +269,7 @@ fun CheckHiddenNoteCompose( addMarginTop: Boolean = true, parentBackgroundColor: MutableState? = null, accountViewModel: AccountViewModel, + showImage: MutableState, nav: (String) -> Unit ) { val isHidden by accountViewModel.accountLiveData.map { @@ -272,6 +289,7 @@ fun CheckHiddenNoteCompose( addMarginTop, parentBackgroundColor, accountViewModel, + showImage, nav ) } @@ -297,6 +315,7 @@ fun LoadedNoteCompose( addMarginTop: Boolean = true, parentBackgroundColor: MutableState? = null, accountViewModel: AccountViewModel, + showImage: MutableState, nav: (String) -> Unit ) { var state by remember { @@ -333,6 +352,7 @@ fun LoadedNoteCompose( addMarginTop, parentBackgroundColor, accountViewModel, + showImage, nav ) } @@ -351,6 +371,7 @@ fun RenderReportState( addMarginTop: Boolean = true, parentBackgroundColor: MutableState? = null, accountViewModel: AccountViewModel, + showImage: MutableState, nav: (String) -> Unit ) { var showReportedNote by remember { mutableStateOf(false) } @@ -380,6 +401,7 @@ fun RenderReportState( canPreview, parentBackgroundColor, accountViewModel, + showImage, nav ) } @@ -415,6 +437,7 @@ fun NormalNote( canPreview: Boolean = true, parentBackgroundColor: MutableState? = null, accountViewModel: AccountViewModel, + showImage: MutableState, nav: (String) -> Unit ) { when (baseNote.event) { @@ -423,6 +446,7 @@ fun NormalNote( showVideo = !makeItShort, showBottomDiviser = true, accountViewModel = accountViewModel, + showImage = showImage, nav = nav ) is CommunityDefinitionEvent -> CommunityHeader( @@ -448,6 +472,7 @@ fun NormalNote( canPreview, parentBackgroundColor, accountViewModel, + showImage, showPopup, nav ) @@ -745,6 +770,7 @@ private fun CheckNewAndRenderNote( canPreview: Boolean = true, parentBackgroundColor: MutableState? = null, accountViewModel: AccountViewModel, + showImage: MutableState, showPopup: () -> Unit, nav: (String) -> Unit ) { @@ -809,6 +835,7 @@ private fun CheckNewAndRenderNote( makeItShort = makeItShort, canPreview = canPreview, accountViewModel = accountViewModel, + showImage = showImage, nav = nav ) } @@ -859,6 +886,7 @@ fun InnerNoteWithReactions( makeItShort: Boolean, canPreview: Boolean, accountViewModel: AccountViewModel, + showImage: MutableState, nav: (String) -> Unit ) { val notBoostedNorQuote = !isBoostedNote && !isQuotedNote @@ -897,6 +925,7 @@ fun InnerNoteWithReactions( showSecondRow = showSecondRow, backgroundColor = backgroundColor, accountViewModel = accountViewModel, + showImage = showImage, nav = nav ) } @@ -942,6 +971,7 @@ private fun NoteBody( showSecondRow: Boolean, backgroundColor: MutableState, accountViewModel: AccountViewModel, + showImage: MutableState, nav: (String) -> Unit ) { FirstUserInfoRow( @@ -967,6 +997,7 @@ private fun NoteBody( unPackReply, backgroundColor, accountViewModel, + showImage, nav ) } @@ -977,6 +1008,7 @@ private fun NoteBody( makeItShort, canPreview, accountViewModel, + showImage, nav ) } @@ -988,11 +1020,12 @@ private fun RenderNoteRow( makeItShort: Boolean, canPreview: Boolean, accountViewModel: AccountViewModel, + showImage: MutableState, nav: (String) -> Unit ) { when (baseNote.event) { is AppDefinitionEvent -> { - RenderAppDefinition(baseNote, accountViewModel, nav) + RenderAppDefinition(baseNote, accountViewModel, showImage, nav) } is ReactionEvent -> { @@ -1236,6 +1269,7 @@ fun RenderPoll( fun RenderAppDefinition( note: Note, accountViewModel: AccountViewModel, + showImage: MutableState, nav: (String) -> Unit ) { val noteEvent = note.event as? AppDefinitionEvent ?: return @@ -2065,6 +2099,7 @@ private fun ReplyRow( unPackReply: Boolean, backgroundColor: MutableState, accountViewModel: AccountViewModel, + showImage: MutableState, nav: (String) -> Unit ) { val noteEvent = note.event @@ -2100,6 +2135,7 @@ private fun ReplyRow( showBottomDiviser = false, modifier = remember { Modifier.padding(vertical = 5.dp) }, accountViewModel = accountViewModel, + showImage = showImage, nav = nav ) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt index b2c9c26fc..9cfc09bc0 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt @@ -55,6 +55,7 @@ import androidx.compose.ui.unit.sp import coil.compose.AsyncImage import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.Note +import com.vitorpamplona.amethyst.service.connectivitystatus.ConnectivityStatus import com.vitorpamplona.amethyst.service.model.AppDefinitionEvent import com.vitorpamplona.amethyst.service.model.AudioTrackEvent import com.vitorpamplona.amethyst.service.model.BadgeDefinitionEvent @@ -244,6 +245,19 @@ fun NoteMaster( val accountState by accountViewModel.accountLiveData.observeAsState() val account = accountState?.account ?: return + val settings = accountState?.account?.settings + val isMobile = ConnectivityStatus.isOnMobileData.value + + val showImage = remember { + mutableStateOf( + when (settings?.automaticallyShowImages) { + true -> !isMobile + false -> false + else -> true + } + ) + } + var showHiddenNote by remember { mutableStateOf(false) } val context = LocalContext.current @@ -398,7 +412,7 @@ fun NoteMaster( ) { Column() { if ((noteEvent is ChannelCreateEvent || noteEvent is ChannelMetadataEvent) && note.channelHex() != null) { - ChannelHeader(channelHex = note.channelHex()!!, showVideo = true, showBottomDiviser = false, accountViewModel = accountViewModel, nav = nav) + ChannelHeader(channelHex = note.channelHex()!!, showVideo = true, showBottomDiviser = false, accountViewModel = accountViewModel, showImage = showImage, nav = nav) } else if (noteEvent is FileHeaderEvent) { FileHeaderDisplay(baseNote, accountViewModel) } else if (noteEvent is FileStorageHeaderEvent) { @@ -431,7 +445,7 @@ fun NoteMaster( nav ) } else if (noteEvent is AppDefinitionEvent) { - RenderAppDefinition(baseNote, accountViewModel, nav) + RenderAppDefinition(baseNote, accountViewModel, showImage, nav) } else if (noteEvent is HighlightEvent) { DisplayHighlight( noteEvent.quote(), diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt index 68139c1cc..ec2a7b987 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt @@ -87,6 +87,7 @@ import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.PublicChatChannel import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.service.NostrChannelDataSource +import com.vitorpamplona.amethyst.service.connectivitystatus.ConnectivityStatus import com.vitorpamplona.amethyst.service.model.LiveActivitiesEvent.Companion.STATUS_LIVE import com.vitorpamplona.amethyst.service.model.Participant import com.vitorpamplona.amethyst.ui.actions.ImmutableListOfLists @@ -199,6 +200,20 @@ fun ChannelScreen( val lifeCycleOwner = LocalLifecycleOwner.current + 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 + } + ) + } + LaunchedEffect(Unit) { NostrChannelDataSource.start() feedViewModel.invalidateData() @@ -239,6 +254,7 @@ fun ChannelScreen( showVideo = true, showBottomDiviser = true, accountViewModel = accountViewModel, + showImage = showImage, nav = nav ) @@ -518,6 +534,7 @@ fun ChannelHeader( showBottomDiviser: Boolean, modifier: Modifier = StdPadding, accountViewModel: AccountViewModel, + showImage: MutableState, nav: (String) -> Unit ) { val channelHex by remember { @@ -531,6 +548,7 @@ fun ChannelHeader( showVideo = showVideo, showBottomDiviser = showBottomDiviser, accountViewModel = accountViewModel, + showImage = showImage, nav = nav ) } @@ -544,6 +562,7 @@ fun ChannelHeader( showFlag: Boolean = true, modifier: Modifier = StdPadding, accountViewModel: AccountViewModel, + showImage: MutableState, nav: (String) -> Unit ) { var baseChannel by remember { mutableStateOf(LocalCache.channels[channelHex]) } @@ -564,6 +583,7 @@ fun ChannelHeader( showFlag, modifier, accountViewModel, + showImage, nav ) } @@ -577,6 +597,7 @@ fun ChannelHeader( showFlag: Boolean = true, modifier: Modifier = StdPadding, accountViewModel: AccountViewModel, + showImage: MutableState, nav: (String) -> Unit ) { Column(Modifier.fillMaxWidth()) { 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 2c0451cb1..bb9303912 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,6 +57,7 @@ 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 @@ -598,6 +599,20 @@ 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) @@ -1260,7 +1275,7 @@ private fun WatchAndRenderBadgeImage( @OptIn(ExperimentalFoundationApi::class) @Composable -public fun DrawBanner(baseUser: User) { +fun DrawBanner(baseUser: User) { val userState by baseUser.live().metadata.observeAsState() val banner = remember(userState) { userState?.user?.info?.banner } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/VideoScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/VideoScreen.kt index a734b065f..fa072d2ac 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/VideoScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/VideoScreen.kt @@ -62,6 +62,7 @@ import com.google.accompanist.permissions.rememberPermissionState import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.service.NostrVideoDataSource +import com.vitorpamplona.amethyst.service.connectivitystatus.ConnectivityStatus import com.vitorpamplona.amethyst.service.model.FileHeaderEvent import com.vitorpamplona.amethyst.service.model.FileStorageHeaderEvent import com.vitorpamplona.amethyst.ui.actions.GallerySelect @@ -192,7 +193,19 @@ fun RenderPage( nav: (String) -> Unit ) { val feedState by videoFeedView.feedContent.collectAsState() + 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() { Column { Crossfade( @@ -213,6 +226,7 @@ fun RenderPage( state.feed, pagerState, accountViewModel, + showImage, nav ) } @@ -232,6 +246,7 @@ fun SlidingCarousel( feed: MutableState>, pagerState: PagerState, accountViewModel: AccountViewModel, + showImage: MutableState, nav: (String) -> Unit ) { VerticalPager( @@ -244,7 +259,7 @@ fun SlidingCarousel( } ) { index -> feed.value.getOrNull(index)?.let { note -> - RenderVideoOrPictureNote(note, accountViewModel, nav) + RenderVideoOrPictureNote(note, accountViewModel, showImage, nav) } } } @@ -253,6 +268,7 @@ fun SlidingCarousel( private fun RenderVideoOrPictureNote( note: Note, accountViewModel: AccountViewModel, + showImage: MutableState, nav: (String) -> Unit ) { Column(remember { Modifier.fillMaxSize(1f) }) { From 33cc261b6270a3ea78ec9dcc414d3a5b58ec81fb Mon Sep 17 00:00:00 2001 From: greenart7c3 <115044884+greenart7c3@users.noreply.github.com> Date: Wed, 5 Jul 2023 11:30:18 -0300 Subject: [PATCH 08/29] add settings to change theme --- .../amethyst/LocalPreferences.kt | 15 ++++++++++++++ .../vitorpamplona/amethyst/ui/MainActivity.kt | 7 +++++-- .../amethyst/ui/screen/AccountScreen.kt | 6 +++--- .../amethyst/ui/screen/ThemeViewModel.kt | 14 +++++++++++++ .../ui/screen/loggedIn/AccountViewModel.kt | 15 +++++++++++--- .../ui/screen/loggedIn/SettingsScreen.kt | 20 +++++++++++++++++++ .../vitorpamplona/amethyst/ui/theme/Theme.kt | 14 ++++++++----- 7 files changed, 78 insertions(+), 13 deletions(-) create mode 100644 app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThemeViewModel.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt b/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt index baa47ed90..2b3b08e66 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt @@ -70,6 +70,7 @@ private object PrefKeys { const val LAST_READ_PER_ROUTE = "last_read_route_per_route" const val AUTOMATICALLY_SHOW_IMAGES = "automatically_show_images" const val AUTOMATICALLY_START_PLAYBACK = "automatically_start_playback" + const val THEME = "theme" val LAST_READ: (String) -> String = { route -> "last_read_route_$route" } } @@ -256,6 +257,20 @@ object LocalPreferences { }.apply() } + fun updateTheme(theme: String) { + encryptedPreferences().edit().apply { + putString(PrefKeys.THEME, theme) + }.apply() + } + + fun getTheme(): String { + var theme = "System" + encryptedPreferences().apply { + theme = getString(PrefKeys.THEME, "System") ?: "System" + } + return theme + } + fun loadFromEncryptedStorage(): Account? { val acc = loadFromEncryptedStorage(currentAccount()) acc?.registerObservers() diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt index 6f299b350..1e5f10444 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt @@ -33,6 +33,7 @@ import com.vitorpamplona.amethyst.ui.navigation.debugState import com.vitorpamplona.amethyst.ui.note.Nip47 import com.vitorpamplona.amethyst.ui.screen.AccountScreen import com.vitorpamplona.amethyst.ui.screen.AccountStateViewModel +import com.vitorpamplona.amethyst.ui.screen.ThemeViewModel import com.vitorpamplona.amethyst.ui.theme.AmethystTheme import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers @@ -50,16 +51,18 @@ class MainActivity : FragmentActivity() { val startingPage = uriToRoute(uri) LocalPreferences.migrateSingleUserPrefs() + val themeViewModel = ThemeViewModel() + themeViewModel.onChange(LocalPreferences.getTheme()) setContent { - AmethystTheme { + AmethystTheme(themeViewModel) { // A surface container using the 'background' color from the theme Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colors.background) { val accountStateViewModel: AccountStateViewModel = viewModel { AccountStateViewModel(this@MainActivity) } - AccountScreen(accountStateViewModel, startingPage) + AccountScreen(accountStateViewModel, themeViewModel, startingPage) } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountScreen.kt index f3c923a68..6ac35a240 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountScreen.kt @@ -12,7 +12,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.MainScreen import com.vitorpamplona.amethyst.ui.screen.loggedOff.LoginPage @Composable -fun AccountScreen(accountStateViewModel: AccountStateViewModel, startingPage: String?) { +fun AccountScreen(accountStateViewModel: AccountStateViewModel, themeViewModel: ThemeViewModel, startingPage: String?) { val accountState by accountStateViewModel.accountContent.collectAsState() Column() { @@ -24,7 +24,7 @@ fun AccountScreen(accountStateViewModel: AccountStateViewModel, startingPage: St is AccountState.LoggedIn -> { val accountViewModel: AccountViewModel = viewModel( key = state.account.userProfile().pubkeyHex, - factory = AccountViewModel.Factory(state.account) + factory = AccountViewModel.Factory(state.account, themeViewModel) ) MainScreen(accountViewModel, accountStateViewModel, startingPage) @@ -32,7 +32,7 @@ fun AccountScreen(accountStateViewModel: AccountStateViewModel, startingPage: St is AccountState.LoggedInViewOnly -> { val accountViewModel: AccountViewModel = viewModel( key = state.account.userProfile().pubkeyHex, - factory = AccountViewModel.Factory(state.account) + factory = AccountViewModel.Factory(state.account, themeViewModel) ) MainScreen(accountViewModel, accountStateViewModel, startingPage) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThemeViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThemeViewModel.kt new file mode 100644 index 000000000..c64cca42d --- /dev/null +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThemeViewModel.kt @@ -0,0 +1,14 @@ +package com.vitorpamplona.amethyst.ui.screen + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel + +class ThemeViewModel : ViewModel() { + private val _theme = MutableLiveData("System") + val theme: LiveData = _theme + + fun onChange(newValue: String) { + _theme.value = newValue + } +} 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 91082ac97..f55bca325 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 @@ -22,6 +22,7 @@ import com.vitorpamplona.amethyst.service.model.Event import com.vitorpamplona.amethyst.service.model.LnZapEvent import com.vitorpamplona.amethyst.service.model.PayInvoiceErrorResponse import com.vitorpamplona.amethyst.service.model.ReportEvent +import com.vitorpamplona.amethyst.ui.screen.ThemeViewModel import kotlinx.collections.immutable.ImmutableSet import kotlinx.collections.immutable.persistentSetOf import kotlinx.collections.immutable.toImmutableSet @@ -32,7 +33,7 @@ import java.math.BigDecimal import java.util.Locale @Stable -class AccountViewModel(val account: Account) : ViewModel() { +class AccountViewModel(val account: Account, private val themeViewModel: ThemeViewModel) : ViewModel() { val accountLiveData: LiveData = account.live.map { it } val accountLanguagesLiveData: LiveData = account.liveLanguages.map { it } val accountLastReadLiveData: LiveData = account.liveLastRead.map { it } @@ -40,6 +41,14 @@ class AccountViewModel(val account: Account) : ViewModel() { val userFollows: LiveData = account.userProfile().live().follows.map { it } val userRelays: LiveData = account.userProfile().live().relays.map { it } + fun changeTheme(newValue: String) { + themeViewModel.onChange(newValue) + } + + fun currentTheme(): String { + return themeViewModel.theme.value ?: "System" + } + fun updateGlobalSettings(automaticallyShowImages: Boolean?, automaticallyStartPlayback: Boolean?) { account.updateGlobalSettings(automaticallyShowImages, automaticallyStartPlayback) } @@ -303,9 +312,9 @@ class AccountViewModel(val account: Account) : ViewModel() { } } - class Factory(val account: Account) : ViewModelProvider.Factory { + class Factory(val account: Account, private val themeViewModel: ThemeViewModel) : ViewModelProvider.Factory { override fun create(modelClass: Class): AccountViewModel { - return AccountViewModel(account) as AccountViewModel + return AccountViewModel(account, themeViewModel) as AccountViewModel } } } 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 a0d937843..854a16221 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 @@ -51,6 +51,13 @@ fun SettingsScreen( val selectedVideoItem = remember { mutableStateOf(selectedItens[videoIndex]) } + + val themeItens = arrayOf("System", "Light", "Dark") + val themeIndex = themeItens.indexOf(accountViewModel.currentTheme()) + val selectedTheme = remember { + mutableStateOf(themeItens[themeIndex]) + } + val context = LocalContext.current Column( StdPadding, @@ -60,6 +67,17 @@ fun SettingsScreen( Section("Application preferences") + Text( + "Theme", + fontWeight = FontWeight.Bold + ) + + DropDownSettings( + selectedItem = selectedTheme, + listItems = themeItens, + title = "Theme" + ) + Text( "Media", fontWeight = FontWeight.Bold @@ -95,9 +113,11 @@ fun SettingsScreen( 2 -> false else -> null } + accountViewModel.changeTheme(selectedTheme.value) scope.launch(Dispatchers.IO) { accountViewModel.updateGlobalSettings(automaticallyShowImages, automaticallyStartPlayback) LocalPreferences.saveToEncryptedStorage(accountViewModel.account) + LocalPreferences.updateTheme(selectedTheme.value) ServiceManager.pause() ServiceManager.start(context) } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt index 46471728e..88cf6fec2 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt @@ -14,6 +14,7 @@ import androidx.compose.material.darkColors import androidx.compose.material.lightColors import androidx.compose.runtime.Composable import androidx.compose.runtime.SideEffect +import androidx.compose.runtime.livedata.observeAsState import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color @@ -27,6 +28,7 @@ import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.unit.dp import com.halilibo.richtext.ui.RichTextStyle import com.halilibo.richtext.ui.resolveDefaults +import com.vitorpamplona.amethyst.ui.screen.ThemeViewModel private val DarkColorPalette = darkColors( primary = Purple200, @@ -304,12 +306,14 @@ val Colors.innerPostModifier: Modifier get() = if (isLight) LightInnerPostBorderModifier else DarkInnerPostBorderModifier @Composable -fun AmethystTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit) { - val colors = if (darkTheme) { - DarkColorPalette - } else { - LightColorPalette +fun AmethystTheme(themeViewModel: ThemeViewModel, content: @Composable () -> Unit) { + val theme = themeViewModel.theme.observeAsState() + val darkTheme = when (theme.value) { + "Dark" -> true + "Light" -> false + else -> if (isSystemInDarkTheme()) true else false } + val colors = if (darkTheme) DarkColorPalette else LightColorPalette MaterialTheme( colors = colors, From 035ba899ee9d108f8c59a0fca41a5854db52ea8b Mon Sep 17 00:00:00 2001 From: greenart7c3 <115044884+greenart7c3@users.noreply.github.com> Date: Wed, 5 Jul 2023 15:12:24 -0300 Subject: [PATCH 09/29] add language picker --- .../amethyst/LocalPreferences.kt | 14 +++- .../vitorpamplona/amethyst/model/Settings.kt | 5 +- .../vitorpamplona/amethyst/ui/MainActivity.kt | 11 ++- .../ui/screen/loggedIn/SettingsScreen.kt | 71 ++++++++++++++++--- app/src/main/res/values-night/themes.xml | 2 +- app/src/main/res/values/themes.xml | 2 +- app/src/main/res/xml/locales_config.xml | 9 ++- 7 files changed, 92 insertions(+), 22 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt b/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt index 2b3b08e66..83466eed0 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt @@ -71,6 +71,7 @@ private object PrefKeys { const val AUTOMATICALLY_SHOW_IMAGES = "automatically_show_images" const val AUTOMATICALLY_START_PLAYBACK = "automatically_start_playback" const val THEME = "theme" + const val PREFERRED_LANGUAGE = "preferred_Language" val LAST_READ: (String) -> String = { route -> "last_read_route_$route" } } @@ -254,6 +255,7 @@ object LocalPreferences { } else { putBoolean(PrefKeys.AUTOMATICALLY_START_PLAYBACK, account.settings.automaticallyStartPlayback!!) } + putString(PrefKeys.PREFERRED_LANGUAGE, account.settings.preferredLanguage ?: "") }.apply() } @@ -271,6 +273,14 @@ object LocalPreferences { return theme } + fun getPreferredLanguage(): String { + var language = "" + encryptedPreferences().apply { + language = getString(PrefKeys.PREFERRED_LANGUAGE, "") ?: "" + } + return language + } + fun loadFromEncryptedStorage(): Account? { val acc = loadFromEncryptedStorage(currentAccount()) acc?.registerObservers() @@ -373,7 +383,7 @@ object LocalPreferences { mapOf() } - val settings = Settings(null, null) + val settings = Settings() encryptedPreferences().apply { settings.automaticallyShowImages = if (contains(PrefKeys.AUTOMATICALLY_SHOW_IMAGES)) { getBoolean(PrefKeys.AUTOMATICALLY_SHOW_IMAGES, false) @@ -386,6 +396,8 @@ object LocalPreferences { } else { null } + + settings.preferredLanguage = getString(PrefKeys.PREFERRED_LANGUAGE, "") } val a = Account( 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 448afd677..9d539924f 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/Settings.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/Settings.kt @@ -4,6 +4,7 @@ import androidx.compose.runtime.Stable @Stable class Settings( - var automaticallyShowImages: Boolean?, - var automaticallyStartPlayback: Boolean? + var automaticallyShowImages: Boolean? = null, + var automaticallyStartPlayback: Boolean? = null, + var preferredLanguage: String? = null ) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt index 1e5f10444..5af93a12e 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt @@ -10,11 +10,13 @@ import android.os.Bundle import android.util.Log import androidx.activity.compose.setContent import androidx.activity.result.contract.ActivityResultContracts +import androidx.appcompat.app.AppCompatActivity +import androidx.appcompat.app.AppCompatDelegate import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material.MaterialTheme import androidx.compose.material.Surface import androidx.compose.ui.Modifier -import androidx.fragment.app.FragmentActivity +import androidx.core.os.LocaleListCompat import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.BuildConfig import com.vitorpamplona.amethyst.LocalPreferences @@ -42,7 +44,7 @@ import kotlinx.coroutines.launch import java.net.URLEncoder import java.nio.charset.StandardCharsets -class MainActivity : FragmentActivity() { +class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -53,6 +55,11 @@ class MainActivity : FragmentActivity() { LocalPreferences.migrateSingleUserPrefs() val themeViewModel = ThemeViewModel() themeViewModel.onChange(LocalPreferences.getTheme()) + val language = LocalPreferences.getPreferredLanguage() + if (language.isNotBlank()) { + val appLocale: LocaleListCompat = LocaleListCompat.forLanguageTags(language) + AppCompatDelegate.setApplicationLocales(appLocale) + } setContent { AmethystTheme(themeViewModel) { 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 854a16221..9041276f1 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 @@ -1,10 +1,13 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn +import android.content.Context +import androidx.appcompat.app.AppCompatDelegate import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding import androidx.compose.material.Button import androidx.compose.material.DropdownMenuItem import androidx.compose.material.ExperimentalMaterialApi @@ -23,13 +26,53 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.intl.Locale +import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import androidx.core.os.LocaleListCompat import com.vitorpamplona.amethyst.LocalPreferences +import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ServiceManager import com.vitorpamplona.amethyst.ui.theme.DoubleVertSpacer import com.vitorpamplona.amethyst.ui.theme.StdPadding import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import org.xmlpull.v1.XmlPullParser +import org.xmlpull.v1.XmlPullParserException +import java.io.IOException + +fun Context.getLocaleListFromXml(): LocaleListCompat { + val tagsList = mutableListOf() + try { + val xpp: XmlPullParser = resources.getXml(R.xml.locales_config) + while (xpp.eventType != XmlPullParser.END_DOCUMENT) { + if (xpp.eventType == XmlPullParser.START_TAG) { + if (xpp.name == "locale") { + tagsList.add(xpp.getAttributeValue(0)) + } + } + xpp.next() + } + } catch (e: XmlPullParserException) { + e.printStackTrace() + } catch (e: IOException) { + e.printStackTrace() + } + + return LocaleListCompat.forLanguageTags(tagsList.joinToString(",")) +} + +fun Context.getLangPreferenceDropdownEntries(): Map { + val localeList = getLocaleListFromXml() + val map = mutableMapOf() + + for (a in 0 until localeList.size()) { + localeList[a].let { + map.put(it!!.getDisplayName(it).replaceFirstChar { char -> char.uppercase() }, it.toLanguageTag()) + } + } + return map +} @Composable fun SettingsScreen( @@ -59,6 +102,16 @@ fun SettingsScreen( } val context = LocalContext.current + + val languageEntries = context.getLangPreferenceDropdownEntries() + val languageList = languageEntries.keys.toTypedArray() + var languageIndex = languageEntries.values.toTypedArray().indexOf(Locale.current.toLanguageTag()) + if (languageIndex == -1) languageIndex = languageEntries.values.toTypedArray().indexOf(Locale.current.language) + if (languageIndex == -1) languageIndex = languageEntries.values.toTypedArray().indexOf("en") + val selectedLanguage = remember { + mutableStateOf(languageList[languageIndex]) + } + Column( StdPadding, horizontalAlignment = Alignment.CenterHorizontally @@ -67,9 +120,10 @@ fun SettingsScreen( Section("Application preferences") - Text( - "Theme", - fontWeight = FontWeight.Bold + DropDownSettings( + selectedItem = selectedLanguage, + listItems = languageList, + title = "Language" ) DropDownSettings( @@ -78,19 +132,12 @@ fun SettingsScreen( title = "Theme" ) - Text( - "Media", - fontWeight = FontWeight.Bold - ) - DropDownSettings( selectedItem = selectedItem, listItems = selectedItens, title = "Automatically load images/gifs" ) - Spacer(modifier = DoubleVertSpacer) - DropDownSettings( selectedItem = selectedVideoItem, listItems = selectedItens, @@ -114,12 +161,15 @@ fun SettingsScreen( else -> null } accountViewModel.changeTheme(selectedTheme.value) + scope.launch(Dispatchers.IO) { accountViewModel.updateGlobalSettings(automaticallyShowImages, automaticallyStartPlayback) LocalPreferences.saveToEncryptedStorage(accountViewModel.account) LocalPreferences.updateTheme(selectedTheme.value) ServiceManager.pause() ServiceManager.start(context) + val appLocale: LocaleListCompat = LocaleListCompat.forLanguageTags(languageEntries[selectedLanguage.value]) + AppCompatDelegate.setApplicationLocales(appLocale) } } ) { @@ -140,6 +190,7 @@ fun DropDownSettings( mutableStateOf(false) } ExposedDropdownMenuBox( + modifier = Modifier.padding(8.dp), expanded = expanded, onExpandedChange = { expanded = !expanded diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml index 437a0e623..196cb2c3a 100644 --- a/app/src/main/res/values-night/themes.xml +++ b/app/src/main/res/values-night/themes.xml @@ -1,6 +1,6 @@ - diff --git a/app/src/main/res/xml/locales_config.xml b/app/src/main/res/xml/locales_config.xml index 014573af0..b70b87c5e 100644 --- a/app/src/main/res/xml/locales_config.xml +++ b/app/src/main/res/xml/locales_config.xml @@ -7,17 +7,16 @@ - - + - + - - + + \ No newline at end of file From 6c1a4f397117158df6e986a6a40d1834c29611da Mon Sep 17 00:00:00 2001 From: greenart7c3 <115044884+greenart7c3@users.noreply.github.com> Date: Wed, 5 Jul 2023 16:15:47 -0300 Subject: [PATCH 10/29] replace load image button with a rectangle box --- .../ui/components/ZoomableContentView.kt | 38 ++++++++++++------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt index d61c9291a..b3038e79a 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt @@ -5,12 +5,12 @@ import android.os.Build import android.util.Log import android.widget.Toast import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.BoxWithConstraints -import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.Row @@ -25,9 +25,9 @@ import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.pager.PagerState import androidx.compose.foundation.pager.rememberPagerState +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.InlineTextContent import androidx.compose.foundation.text.appendInlineContent -import androidx.compose.material.Button import androidx.compose.material.Icon import androidx.compose.material.IconButton import androidx.compose.material.LocalTextStyle @@ -48,6 +48,7 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalClipboardManager @@ -57,10 +58,12 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.Placeholder import androidx.compose.ui.text.PlaceholderVerticalAlign +import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.withStyle import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.isFinite +import androidx.compose.ui.unit.sp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties import androidx.core.net.toUri @@ -301,6 +304,23 @@ private fun UrlImageView( } } +@Composable +fun LoadImageBox(showImage: MutableState) { + Box( + modifier = Modifier + .size(300.dp) + .clip(RoundedCornerShape(10.dp)) + .background(Color.LightGray) + .clickable { showImage.value = true }, + contentAlignment = Alignment.Center + ) { + Text( + text = "Load Image", + style = TextStyle(color = Color.Black, fontSize = 18.sp) + ) + } +} + @Composable @OptIn(ExperimentalLayoutApi::class) private fun AddedImageFeatures( @@ -312,12 +332,7 @@ private fun AddedImageFeatures( showImage: MutableState ) { if (!showImage.value) { - return Column(horizontalAlignment = Alignment.CenterHorizontally) { - ClickableUrl(urlText = "${content.uri} ", url = content.uri) - Button(onClick = { showImage.value = true }) { - Text("Load image") - } - } + return LoadImageBox(showImage) } when (painter.value) { @@ -357,12 +372,7 @@ private fun AddedImageFeatures( showImage: MutableState ) { if (!showImage.value) { - return Column(horizontalAlignment = Alignment.CenterHorizontally) { - ClickableUrl(urlText = "${content.url} ", url = content.url) - Button(onClick = { showImage.value = true }) { - Text("Load image") - } - } + return LoadImageBox(showImage) } var verifiedHash by remember { From 69c3c411965aa51da08582c852fd795ccec9130c Mon Sep 17 00:00:00 2001 From: greenart7c3 <115044884+greenart7c3@users.noreply.github.com> Date: Wed, 5 Jul 2023 17:32:50 -0300 Subject: [PATCH 11/29] move drawer options to settings screen --- .../amethyst/ui/navigation/DrawerContent.kt | 150 ------------------ .../ui/screen/loggedIn/SettingsScreen.kt | 148 ++++++++++++++++- 2 files changed, 144 insertions(+), 154 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt index b69c5d5c3..7018c4138 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt @@ -1,6 +1,5 @@ package com.vitorpamplona.amethyst.ui.navigation -import android.content.Context import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.Image import androidx.compose.foundation.background @@ -20,7 +19,6 @@ import androidx.compose.foundation.layout.width import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.verticalScroll -import androidx.compose.material.AlertDialog import androidx.compose.material.Divider import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.Icon @@ -30,10 +28,8 @@ import androidx.compose.material.ModalBottomSheetState import androidx.compose.material.ScaffoldState import androidx.compose.material.Surface import androidx.compose.material.Text -import androidx.compose.material.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.MutableState import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState @@ -46,30 +42,21 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import androidx.lifecycle.viewmodel.compose.viewModel import coil.compose.AsyncImage import com.vitorpamplona.amethyst.BuildConfig -import com.vitorpamplona.amethyst.LocalPreferences import com.vitorpamplona.amethyst.R -import com.vitorpamplona.amethyst.ServiceManager -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.User -import com.vitorpamplona.amethyst.service.HttpClient -import com.vitorpamplona.amethyst.ui.actions.NewRelayListView import com.vitorpamplona.amethyst.ui.actions.toImmutableListOfLists import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji import com.vitorpamplona.amethyst.ui.components.RobohashAsyncImageProxy import com.vitorpamplona.amethyst.ui.screen.RelayPoolViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountBackupDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import com.vitorpamplona.amethyst.ui.screen.loggedIn.ConnectOrbotDialog import com.vitorpamplona.amethyst.ui.theme.DoubleHorzSpacer import com.vitorpamplona.amethyst.ui.theme.Size16dp import com.vitorpamplona.amethyst.ui.theme.placeholderText @@ -299,19 +286,7 @@ fun ListContent( ) { val accountState by accountViewModel.accountLiveData.observeAsState() val account = remember(accountState) { accountState?.account } ?: return - val coroutineScope = rememberCoroutineScope() - var backupDialogOpen by remember { mutableStateOf(false) } - var checked by remember { mutableStateOf(account.proxy != null) } - var disconnectTorDialog by remember { mutableStateOf(false) } - var conectOrbotDialogOpen by remember { mutableStateOf(false) } - var proxyPort = remember { mutableStateOf(account.proxyPort.toString()) } - - val relayViewModel: RelayPoolViewModel = viewModel { RelayPoolViewModel() } - - var wantsToEditRelays by remember { - mutableStateOf(false) - } Column( modifier = modifier @@ -336,25 +311,6 @@ fun ListContent( route = Route.Bookmarks.route ) - IconRowRelays( - relayViewModel = relayViewModel, - onClick = { - coroutineScope.launch { - scaffoldState.drawerState.close() - } - wantsToEditRelays = true - } - ) - - NavigationRow( - title = stringResource(R.string.security_filters), - icon = Route.BlockedUsers.icon, - tint = MaterialTheme.colors.onBackground, - nav = nav, - scaffoldState = scaffoldState, - route = Route.BlockedUsers.route - ) - NavigationRow( title = stringResource(R.string.settings), icon = Route.Settings.icon, @@ -364,42 +320,6 @@ fun ListContent( route = Route.Settings.route ) - IconRow( - title = stringResource(R.string.backup_keys), - icon = R.drawable.ic_key, - tint = MaterialTheme.colors.onBackground, - onClick = { - coroutineScope.launch { - scaffoldState.drawerState.close() - } - backupDialogOpen = true - } - ) - - val textTorProxy = if (checked) stringResource(R.string.disconnect_from_your_orbot_setup) else stringResource(R.string.connect_via_tor_short) - - IconRow( - title = textTorProxy, - icon = R.drawable.ic_tor, - tint = MaterialTheme.colors.onBackground, - onLongClick = { - coroutineScope.launch { - scaffoldState.drawerState.close() - } - conectOrbotDialogOpen = true - }, - onClick = { - if (checked) { - disconnectTorDialog = true - } else { - coroutineScope.launch { - scaffoldState.drawerState.close() - } - conectOrbotDialogOpen = true - } - } - ) - Spacer(modifier = Modifier.weight(1f)) IconRow( @@ -409,76 +329,6 @@ fun ListContent( onClick = { coroutineScope.launch { sheetState.show() } } ) } - - if (backupDialogOpen) { - AccountBackupDialog(account, onClose = { backupDialogOpen = false }) - } - - val context = LocalContext.current - - if (conectOrbotDialogOpen) { - ConnectOrbotDialog( - onClose = { conectOrbotDialogOpen = false }, - onPost = { - conectOrbotDialogOpen = false - disconnectTorDialog = false - checked = true - enableTor(account, true, proxyPort, context = context) - }, - proxyPort - ) - } - - if (disconnectTorDialog) { - AlertDialog( - title = { - Text(text = stringResource(R.string.do_you_really_want_to_disable_tor_title)) - }, - text = { - Text(text = stringResource(R.string.do_you_really_want_to_disable_tor_text)) - }, - onDismissRequest = { - disconnectTorDialog = false - }, - confirmButton = { - TextButton( - onClick = { - disconnectTorDialog = false - checked = false - enableTor(account, false, proxyPort, context) - } - ) { - Text(text = stringResource(R.string.yes)) - } - }, - dismissButton = { - TextButton( - onClick = { - disconnectTorDialog = false - } - ) { - Text(text = stringResource(R.string.no)) - } - } - ) - } - - if (wantsToEditRelays) { - NewRelayListView({ wantsToEditRelays = false }, accountViewModel, nav = nav) - } -} - -private fun enableTor( - account: Account, - checked: Boolean, - portNumber: MutableState, - context: Context -) { - account.proxyPort = portNumber.value.toInt() - account.proxy = HttpClient.initProxy(checked, "127.0.0.1", account.proxyPort) - LocalPreferences.saveToEncryptedStorage(account) - ServiceManager.pause() - ServiceManager.start(context) } @Composable 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 9041276f1..218b80464 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 @@ -8,12 +8,17 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.AlertDialog import androidx.compose.material.Button import androidx.compose.material.DropdownMenuItem import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.ExposedDropdownMenuBox import androidx.compose.material.ExposedDropdownMenuDefaults +import androidx.compose.material.MaterialTheme import androidx.compose.material.Text +import androidx.compose.material.TextButton import androidx.compose.material.TextField import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState @@ -25,16 +30,26 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.intl.Locale import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.core.os.LocaleListCompat +import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.LocalPreferences import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ServiceManager +import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.service.HttpClient +import com.vitorpamplona.amethyst.ui.actions.NewRelayListView +import com.vitorpamplona.amethyst.ui.navigation.IconRow +import com.vitorpamplona.amethyst.ui.navigation.IconRowRelays +import com.vitorpamplona.amethyst.ui.navigation.Route +import com.vitorpamplona.amethyst.ui.screen.RelayPoolViewModel import com.vitorpamplona.amethyst.ui.theme.DoubleVertSpacer import com.vitorpamplona.amethyst.ui.theme.StdPadding +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import org.xmlpull.v1.XmlPullParser @@ -74,6 +89,13 @@ fun Context.getLangPreferenceDropdownEntries(): Map { return map } +fun getLanguageIndex(languageEntries: Map): Int { + var languageIndex = languageEntries.values.toTypedArray().indexOf(Locale.current.toLanguageTag()) + if (languageIndex == -1) languageIndex = languageEntries.values.toTypedArray().indexOf(Locale.current.language) + if (languageIndex == -1) languageIndex = languageEntries.values.toTypedArray().indexOf("en") + return languageIndex +} + @Composable fun SettingsScreen( accountViewModel: AccountViewModel, @@ -105,19 +127,69 @@ fun SettingsScreen( val languageEntries = context.getLangPreferenceDropdownEntries() val languageList = languageEntries.keys.toTypedArray() - var languageIndex = languageEntries.values.toTypedArray().indexOf(Locale.current.toLanguageTag()) - if (languageIndex == -1) languageIndex = languageEntries.values.toTypedArray().indexOf(Locale.current.language) - if (languageIndex == -1) languageIndex = languageEntries.values.toTypedArray().indexOf("en") + val languageIndex = getLanguageIndex(languageEntries) val selectedLanguage = remember { mutableStateOf(languageList[languageIndex]) } + val relayViewModel: RelayPoolViewModel = viewModel { RelayPoolViewModel() } + var wantsToEditRelays by remember { + mutableStateOf(false) + } + var backupDialogOpen by remember { mutableStateOf(false) } + var checked by remember { mutableStateOf(accountViewModel.account.proxy != null) } + var disconnectTorDialog by remember { mutableStateOf(false) } + var conectOrbotDialogOpen by remember { mutableStateOf(false) } + val proxyPort = remember { mutableStateOf(accountViewModel.account.proxyPort.toString()) } Column( - StdPadding, + StdPadding + .verticalScroll(rememberScrollState()), horizontalAlignment = Alignment.CenterHorizontally ) { Section("Account preferences") + IconRowRelays( + relayViewModel = relayViewModel, + onClick = { + wantsToEditRelays = true + } + ) + + IconRow( + title = stringResource(R.string.security_filters), + icon = Route.BlockedUsers.icon, + tint = MaterialTheme.colors.onBackground, + onClick = { + nav(Route.BlockedUsers.route) + } + ) + + IconRow( + title = stringResource(R.string.backup_keys), + icon = R.drawable.ic_key, + tint = MaterialTheme.colors.onBackground, + onClick = { + backupDialogOpen = true + } + ) + + val textTorProxy = if (checked) stringResource(R.string.disconnect_from_your_orbot_setup) else stringResource(R.string.connect_via_tor_short) + IconRow( + title = textTorProxy, + icon = R.drawable.ic_tor, + tint = MaterialTheme.colors.onBackground, + onLongClick = { + conectOrbotDialogOpen = true + }, + onClick = { + if (checked) { + disconnectTorDialog = true + } else { + conectOrbotDialogOpen = true + } + } + ) + Section("Application preferences") DropDownSettings( @@ -177,6 +249,74 @@ fun SettingsScreen( } } } + if (wantsToEditRelays) { + NewRelayListView({ wantsToEditRelays = false }, accountViewModel, nav = nav) + } + if (backupDialogOpen) { + AccountBackupDialog(accountViewModel.account, onClose = { backupDialogOpen = false }) + } + if (conectOrbotDialogOpen) { + ConnectOrbotDialog( + onClose = { conectOrbotDialogOpen = false }, + onPost = { + conectOrbotDialogOpen = false + disconnectTorDialog = false + checked = true + enableTor(accountViewModel.account, true, proxyPort, context, scope) + }, + proxyPort + ) + } + + if (disconnectTorDialog) { + AlertDialog( + title = { + Text(text = stringResource(R.string.do_you_really_want_to_disable_tor_title)) + }, + text = { + Text(text = stringResource(R.string.do_you_really_want_to_disable_tor_text)) + }, + onDismissRequest = { + disconnectTorDialog = false + }, + confirmButton = { + TextButton( + onClick = { + disconnectTorDialog = false + checked = false + enableTor(accountViewModel.account, false, proxyPort, context, scope) + } + ) { + Text(text = stringResource(R.string.yes)) + } + }, + dismissButton = { + TextButton( + onClick = { + disconnectTorDialog = false + } + ) { + Text(text = stringResource(R.string.no)) + } + } + ) + } +} + +private fun enableTor( + account: Account, + checked: Boolean, + portNumber: MutableState, + context: Context, + scope: CoroutineScope +) { + account.proxyPort = portNumber.value.toInt() + account.proxy = HttpClient.initProxy(checked, "127.0.0.1", account.proxyPort) + scope.launch(Dispatchers.IO) { + LocalPreferences.saveToEncryptedStorage(account) + ServiceManager.pause() + ServiceManager.start(context) + } } @OptIn(ExperimentalMaterialApi::class) From f83a19260fb98ff17b9fc97bb7e7ba870752392b Mon Sep 17 00:00:00 2001 From: greenart7c3 <115044884+greenart7c3@users.noreply.github.com> Date: Fri, 7 Jul 2023 05:18:12 -0300 Subject: [PATCH 12/29] fix build after rebase --- .../com/vitorpamplona/amethyst/ui/note/ChannelCardCompose.kt | 2 +- .../main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChannelCardCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChannelCardCompose.kt index b22a59fa4..7478e0a36 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChannelCardCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChannelCardCompose.kt @@ -50,9 +50,9 @@ import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.ParticipantListBuilder import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.service.OnlineChecker +import com.vitorpamplona.amethyst.service.connectivitystatus.ConnectivityStatus import com.vitorpamplona.amethyst.service.model.ChannelCreateEvent import com.vitorpamplona.amethyst.service.model.CommunityDefinitionEvent -import com.vitorpamplona.amethyst.service.connectivitystatus.ConnectivityStatus import com.vitorpamplona.amethyst.service.model.LiveActivitiesEvent import com.vitorpamplona.amethyst.service.model.LiveActivitiesEvent.Companion.STATUS_ENDED import com.vitorpamplona.amethyst.service.model.LiveActivitiesEvent.Companion.STATUS_LIVE diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt index e8f0893fc..c49ddbdd8 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt @@ -85,8 +85,8 @@ import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.model.UserMetadata import com.vitorpamplona.amethyst.service.OnlineChecker -import com.vitorpamplona.amethyst.service.model.ATag import com.vitorpamplona.amethyst.service.connectivitystatus.ConnectivityStatus +import com.vitorpamplona.amethyst.service.model.ATag import com.vitorpamplona.amethyst.service.model.AppDefinitionEvent import com.vitorpamplona.amethyst.service.model.AudioTrackEvent import com.vitorpamplona.amethyst.service.model.BadgeAwardEvent From 3e615bb152bfcb2f4237f665c6da3da5998ec42d Mon Sep 17 00:00:00 2001 From: greenart7c3 <115044884+greenart7c3@users.noreply.github.com> Date: Fri, 7 Jul 2023 05:55:33 -0300 Subject: [PATCH 13/29] check for automaticallyStartPlayback setting --- .../amethyst/ui/actions/NewMediaView.kt | 4 +-- .../amethyst/ui/actions/NewPostView.kt | 4 +-- .../ui/components/ExpandableRichTextViewer.kt | 11 ++++++ .../amethyst/ui/components/RichTextViewer.kt | 17 +++++++--- .../amethyst/ui/components/VideoView.kt | 22 ++++++------ .../ui/components/ZoomableContentView.kt | 21 +++++++----- .../amethyst/ui/note/ChannelCardCompose.kt | 34 +++++++++++++++++-- .../amethyst/ui/note/NoteCompose.kt | 32 +++++++++++++++-- .../amethyst/ui/screen/ThreadFeedView.kt | 20 ++++++++++- .../ui/screen/loggedIn/ChannelScreen.kt | 16 +++++++++ .../ui/screen/loggedIn/VideoScreen.kt | 16 ++++++++- 11 files changed, 164 insertions(+), 33 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaView.kt index e0203b0d7..11c20598b 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaView.kt @@ -179,11 +179,11 @@ fun ImageVideoPost(postViewModel: NewMediaModel, acc: Account) { ) } } else { - val showVideo = remember { + val automaticallyStartPlayback = remember { mutableStateOf(true) } postViewModel.galleryUri?.let { - VideoView(it.toString(), showVideo = showVideo) + VideoView(it.toString(), automaticallyStartPlayback = automaticallyStartPlayback) } } } 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 34c096888..8a15cadb1 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 @@ -330,7 +330,7 @@ fun NewPostView(onClose: () -> Unit, baseReplyTo: Note? = null, quote: Note? = n ) ) } else if (videoExtensions.any { removedParamsFromUrl.endsWith(it) }) { - VideoView(myUrlPreview, showVideo = remember { mutableStateOf(true) }) + VideoView(myUrlPreview, automaticallyStartPlayback = remember { mutableStateOf(true) }) } else { UrlPreview(myUrlPreview, myUrlPreview) } @@ -966,7 +966,7 @@ fun ImageVideoDescription( ) } } else { - VideoView(uri.toString(), showVideo = remember { mutableStateOf(true) }) + VideoView(uri.toString(), automaticallyStartPlayback = 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 6d8a88ba8..9a55840dc 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 @@ -58,6 +58,16 @@ fun ExpandableRichTextViewer( ) } + val automaticallyStartPlayback = remember { + mutableStateOf( + when (settings?.automaticallyStartPlayback) { + true -> !isMobile + false -> false + else -> true + } + ) + } + var showFullText by remember { mutableStateOf(false) } val whereToCut = remember(content) { @@ -87,6 +97,7 @@ fun ExpandableRichTextViewer( backgroundColor, accountViewModel, showImage, + automaticallyStartPlayback, 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 93c0e8a78..658549f2b 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 @@ -109,13 +109,14 @@ fun RichTextViewer( backgroundColor: MutableState, accountViewModel: AccountViewModel, showImage: MutableState, + automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { Column(modifier = modifier) { if (remember(content) { isMarkdown(content) }) { RenderContentAsMarkdown(content, tags, nav) } else { - RenderRegular(content, tags, canPreview, backgroundColor, accountViewModel, showImage, nav) + RenderRegular(content, tags, canPreview, backgroundColor, accountViewModel, showImage, automaticallyStartPlayback, nav) } } } @@ -129,6 +130,7 @@ private fun RenderRegular( backgroundColor: MutableState, accountViewModel: AccountViewModel, showImage: MutableState, + automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { val state by remember(content) { @@ -159,6 +161,7 @@ private fun RenderRegular( textStyle, accountViewModel, showImage, + automaticallyStartPlayback, nav ) } @@ -239,10 +242,11 @@ private fun RenderWordWithPreview( style: TextStyle, accountViewModel: AccountViewModel, showImage: MutableState, + automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { when (word) { - is ImageSegment -> ZoomableContentView(word.segmentText, state, showImage) + is ImageSegment -> ZoomableContentView(word.segmentText, state, showImage, automaticallyStartPlayback) is LinkSegment -> UrlPreview(word.segmentText, word.segmentText) is EmojiSegment -> RenderCustomEmoji(word.segmentText, state) is InvoiceSegment -> MayBeInvoicePreview(word.segmentText) @@ -260,9 +264,14 @@ private fun RenderWordWithPreview( } @Composable -private fun ZoomableContentView(word: String, state: RichTextViewerState, showImage: MutableState) { +private fun ZoomableContentView( + word: String, + state: RichTextViewerState, + showImage: MutableState, + automaticallyStartPlayback: MutableState +) { state.imagesForPager[word]?.let { - ZoomableContentView(it, state.imageList, showImage) + ZoomableContentView(it, state.imageList, showImage, automaticallyStartPlayback) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/VideoView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/VideoView.kt index 62c665e9d..ff20af82e 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/VideoView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/VideoView.kt @@ -112,11 +112,11 @@ fun VideoView( videoUri: String, description: String? = null, thumb: VideoThumb? = null, - showVideo: MutableState, + automaticallyStartPlayback: MutableState, onDialog: ((Boolean) -> Unit)? = null ) { val (value, elapsed) = measureTimedValue { - VideoView1(videoUri, description, thumb, onDialog, showVideo) + VideoView1(videoUri, description, thumb, onDialog, automaticallyStartPlayback) } Log.d("Rendering Metrics", "VideoView $elapsed $videoUri") } @@ -127,7 +127,7 @@ fun VideoView1( description: String? = null, thumb: VideoThumb? = null, onDialog: ((Boolean) -> Unit)? = null, - showVideo: MutableState + automaticallyStartPlayback: MutableState ) { var exoPlayerData by remember { mutableStateOf(null) } val defaultToStart by remember { mutableStateOf(DefaultMutedSetting.value) } @@ -142,7 +142,7 @@ fun VideoView1( } exoPlayerData?.let { - VideoView(videoUri, description, it, defaultToStart, thumb, onDialog, showVideo = showVideo) + VideoView(videoUri, description, it, defaultToStart, thumb, onDialog, automaticallyStartPlayback = automaticallyStartPlayback) } DisposableEffect(Unit) { @@ -161,10 +161,10 @@ fun VideoView( defaultToStart: Boolean = false, thumb: VideoThumb? = null, onDialog: ((Boolean) -> Unit)? = null, - showVideo: MutableState + automaticallyStartPlayback: MutableState ) { val (value, elapsed) = measureTimedValue { - VideoView1(videoUri, description, exoPlayerData, defaultToStart, thumb, onDialog, showVideo) + VideoView1(videoUri, description, exoPlayerData, defaultToStart, thumb, onDialog, automaticallyStartPlayback) } Log.d("Rendering Metrics", "VideoView $elapsed $videoUri") } @@ -177,7 +177,7 @@ fun VideoView1( defaultToStart: Boolean = false, thumb: VideoThumb? = null, onDialog: ((Boolean) -> Unit)? = null, - showVideo: MutableState + automaticallyStartPlayback: MutableState ) { val lifecycleOwner = rememberUpdatedState(LocalLifecycleOwner.current) @@ -207,7 +207,7 @@ fun VideoView1( prepare() } - RenderVideoPlayer(exoPlayerData, thumb, showVideo, onDialog) + RenderVideoPlayer(exoPlayerData, thumb, automaticallyStartPlayback, onDialog) DisposableEffect(Unit) { val observer = LifecycleEventObserver { _, event -> @@ -241,7 +241,7 @@ data class VideoThumb( private fun RenderVideoPlayer( playerData: VideoPlayer, thumbData: VideoThumb?, - showVideo: MutableState, + automaticallyStartPlayback: MutableState, onDialog: ((Boolean) -> Unit)? ) { val context = LocalContext.current @@ -253,10 +253,10 @@ private fun RenderVideoPlayer( .defaultMinSize(minHeight = 70.dp) .align(Alignment.Center) .onVisibilityChanges { visible -> - if (!showVideo.value) { + if (!automaticallyStartPlayback.value) { playerData.exoPlayer.stop() } - if (!showVideo.value && visible && !playerData.exoPlayer.isPlaying) { + if (!automaticallyStartPlayback.value && visible && !playerData.exoPlayer.isPlaying) { playerData.exoPlayer.pause() } else if (visible && !playerData.exoPlayer.isPlaying) { playerData.exoPlayer.play() diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt index b3038e79a..e8e5a7f09 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt @@ -171,7 +171,12 @@ fun figureOutMimeType(fullUrl: String): ZoomableContent { @Composable @OptIn(ExperimentalFoundationApi::class) -fun ZoomableContentView(content: ZoomableContent, images: ImmutableList = listOf(content).toImmutableList(), showImage: MutableState) { +fun ZoomableContentView( + content: ZoomableContent, + images: ImmutableList = listOf(content).toImmutableList(), + showImage: MutableState, + automaticallyStartPlayback: MutableState +) { val clipboardManager = LocalClipboardManager.current // store the dialog open or close state @@ -199,11 +204,11 @@ fun ZoomableContentView(content: ZoomableContent, images: ImmutableList UrlImageView(content, mainImageModifier, showImage) - is ZoomableUrlVideo -> VideoView(content.url, content.description, showVideo = showImage) { dialogOpen = true } + is ZoomableUrlVideo -> VideoView(content.url, content.description, automaticallyStartPlayback = automaticallyStartPlayback) { dialogOpen = true } is ZoomableLocalImage -> LocalImageView(content, mainImageModifier, showImage) is ZoomableLocalVideo -> content.localFile?.let { - VideoView(it.toUri().toString(), content.description, showVideo = showImage) { dialogOpen = true } + VideoView(it.toUri().toString(), content.description, automaticallyStartPlayback = automaticallyStartPlayback) { dialogOpen = true } } } @@ -552,11 +557,11 @@ fun ZoomableImageDialog(imageUrl: ZoomableContent, allImages: ImmutableList - RenderImageOrVideo(allImages[index], remember { mutableStateOf(true) }) + RenderImageOrVideo(allImages[index], remember { mutableStateOf(true) }, remember { mutableStateOf(true) }) } ) } else { - RenderImageOrVideo(imageUrl, remember { mutableStateOf(true) }) + RenderImageOrVideo(imageUrl, remember { mutableStateOf(true) }, remember { mutableStateOf(true) }) } Row( @@ -581,7 +586,7 @@ fun ZoomableImageDialog(imageUrl: ZoomableContent, allImages: ImmutableList) { +fun RenderImageOrVideo(content: ZoomableContent, showImage: MutableState, automaticallyStartPlayback: MutableState) { val mainModifier = Modifier .fillMaxSize() .zoomable(rememberZoomState()) @@ -590,14 +595,14 @@ fun RenderImageOrVideo(content: ZoomableContent, showImage: MutableState !isMobile + false -> false + else -> true + } + ) + } + Crossfade(targetState = isBlank) { if (it) { LongPressToQuickAction(baseNote = baseNote, accountViewModel = accountViewModel) { showPopup -> @@ -129,6 +139,7 @@ fun ChannelCardCompose( parentBackgroundColor, accountViewModel, showImage, + automaticallyStartPlayback, nav ) } @@ -143,6 +154,7 @@ fun CheckHiddenChannelCardCompose( parentBackgroundColor: MutableState? = null, accountViewModel: AccountViewModel, showImage: MutableState, + automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { val isHidden by accountViewModel.accountLiveData.map { @@ -158,6 +170,7 @@ fun CheckHiddenChannelCardCompose( parentBackgroundColor, accountViewModel, showImage, + automaticallyStartPlayback, nav ) } @@ -172,6 +185,7 @@ fun LoadedChannelCardCompose( parentBackgroundColor: MutableState? = null, accountViewModel: AccountViewModel, showImage: MutableState, + automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { var state by remember { @@ -204,6 +218,7 @@ fun LoadedChannelCardCompose( parentBackgroundColor, accountViewModel, showImage, + automaticallyStartPlayback, nav ) } @@ -218,6 +233,7 @@ fun RenderChannelCardReportState( parentBackgroundColor: MutableState? = null, accountViewModel: AccountViewModel, showImage: MutableState, + automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { var showReportedNote by remember { mutableStateOf(false) } @@ -240,6 +256,7 @@ fun RenderChannelCardReportState( parentBackgroundColor, accountViewModel, showImage, + automaticallyStartPlayback, nav ) } @@ -254,6 +271,7 @@ fun NormalChannelCard( parentBackgroundColor: MutableState? = null, accountViewModel: AccountViewModel, showImage: MutableState, + automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { LongPressToQuickAction(baseNote = baseNote, accountViewModel = accountViewModel) { showPopup -> @@ -264,6 +282,7 @@ fun NormalChannelCard( parentBackgroundColor, accountViewModel, showImage, + automaticallyStartPlayback, showPopup, nav ) @@ -278,6 +297,7 @@ private fun CheckNewAndRenderChannelCard( parentBackgroundColor: MutableState? = null, accountViewModel: AccountViewModel, showImage: MutableState, + automaticallyStartPlayback: MutableState, showPopup: () -> Unit, nav: (String) -> Unit ) { @@ -336,6 +356,7 @@ private fun CheckNewAndRenderChannelCard( baseNote = baseNote, accountViewModel = accountViewModel, showImage, + automaticallyStartPlayback, nav = nav ) } @@ -346,6 +367,7 @@ fun InnerChannelCardWithReactions( baseNote: Note, accountViewModel: AccountViewModel, showImage: MutableState, + automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { Column(StdPadding) { @@ -367,11 +389,12 @@ private fun RenderNoteRow( baseNote: Note, accountViewModel: AccountViewModel, showImage: MutableState, + automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { when (remember { baseNote.event }) { is LiveActivitiesEvent -> { - RenderLiveActivityThumb(baseNote, accountViewModel, showImage, nav) + RenderLiveActivityThumb(baseNote, accountViewModel, showImage, automaticallyStartPlayback, nav) } is CommunityDefinitionEvent -> { RenderCommunitiesThumb(baseNote, accountViewModel, nav) @@ -383,7 +406,13 @@ private fun RenderNoteRow( } @Composable -fun RenderLiveActivityThumb(baseNote: Note, accountViewModel: AccountViewModel, showImage: MutableState, nav: (String) -> Unit) { +fun RenderLiveActivityThumb( + baseNote: Note, + accountViewModel: AccountViewModel, + showImage: MutableState, + automaticallyStartPlayback: MutableState, + nav: (String) -> Unit +) { val noteEvent = baseNote.event as? LiveActivitiesEvent ?: return val eventUpdates by baseNote.live().metadata.observeAsState() @@ -521,6 +550,7 @@ fun RenderLiveActivityThumb(baseNote: Note, accountViewModel: AccountViewModel, }, accountViewModel = accountViewModel, showImage = showImage, + automaticallyStartPlayback = automaticallyStartPlayback, nav = nav ) } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt index c49ddbdd8..d7ee35a64 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt @@ -225,6 +225,16 @@ fun NoteCompose( ) } + val automaticallyStartPlayback = remember { + mutableStateOf( + when (settings?.automaticallyStartPlayback) { + true -> !isMobile + false -> false + else -> true + } + ) + } + Crossfade(targetState = isBlank) { if (it) { LongPressToQuickAction(baseNote = baseNote, accountViewModel = accountViewModel) { showPopup -> @@ -251,6 +261,7 @@ fun NoteCompose( parentBackgroundColor, accountViewModel, showImage, + automaticallyStartPlayback, nav ) } @@ -270,6 +281,7 @@ fun CheckHiddenNoteCompose( parentBackgroundColor: MutableState? = null, accountViewModel: AccountViewModel, showImage: MutableState, + automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { val isHidden by accountViewModel.accountLiveData.map { @@ -290,6 +302,7 @@ fun CheckHiddenNoteCompose( parentBackgroundColor, accountViewModel, showImage, + automaticallyStartPlayback, nav ) } @@ -316,6 +329,7 @@ fun LoadedNoteCompose( parentBackgroundColor: MutableState? = null, accountViewModel: AccountViewModel, showImage: MutableState, + automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { var state by remember { @@ -353,6 +367,7 @@ fun LoadedNoteCompose( parentBackgroundColor, accountViewModel, showImage, + automaticallyStartPlayback, nav ) } @@ -372,6 +387,7 @@ fun RenderReportState( parentBackgroundColor: MutableState? = null, accountViewModel: AccountViewModel, showImage: MutableState, + automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { var showReportedNote by remember { mutableStateOf(false) } @@ -402,6 +418,7 @@ fun RenderReportState( parentBackgroundColor, accountViewModel, showImage, + automaticallyStartPlayback, nav ) } @@ -438,6 +455,7 @@ fun NormalNote( parentBackgroundColor: MutableState? = null, accountViewModel: AccountViewModel, showImage: MutableState, + automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { when (baseNote.event) { @@ -447,6 +465,7 @@ fun NormalNote( showBottomDiviser = true, accountViewModel = accountViewModel, showImage = showImage, + automaticallyStartPlayback = automaticallyStartPlayback, nav = nav ) is CommunityDefinitionEvent -> CommunityHeader( @@ -473,6 +492,7 @@ fun NormalNote( parentBackgroundColor, accountViewModel, showImage, + automaticallyStartPlayback, showPopup, nav ) @@ -771,6 +791,7 @@ private fun CheckNewAndRenderNote( parentBackgroundColor: MutableState? = null, accountViewModel: AccountViewModel, showImage: MutableState, + automaticallyStartPlayback: MutableState, showPopup: () -> Unit, nav: (String) -> Unit ) { @@ -836,6 +857,7 @@ private fun CheckNewAndRenderNote( canPreview = canPreview, accountViewModel = accountViewModel, showImage = showImage, + automaticallyStartPlayback = automaticallyStartPlayback, nav = nav ) } @@ -887,6 +909,7 @@ fun InnerNoteWithReactions( canPreview: Boolean, accountViewModel: AccountViewModel, showImage: MutableState, + automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { val notBoostedNorQuote = !isBoostedNote && !isQuotedNote @@ -926,6 +949,7 @@ fun InnerNoteWithReactions( backgroundColor = backgroundColor, accountViewModel = accountViewModel, showImage = showImage, + automaticallyStartPlayback = automaticallyStartPlayback, nav = nav ) } @@ -972,6 +996,7 @@ private fun NoteBody( backgroundColor: MutableState, accountViewModel: AccountViewModel, showImage: MutableState, + automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { FirstUserInfoRow( @@ -998,6 +1023,7 @@ private fun NoteBody( backgroundColor, accountViewModel, showImage, + automaticallyStartPlayback, nav ) } @@ -2100,6 +2126,7 @@ private fun ReplyRow( backgroundColor: MutableState, accountViewModel: AccountViewModel, showImage: MutableState, + automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { val noteEvent = note.event @@ -2136,6 +2163,7 @@ private fun ReplyRow( modifier = remember { Modifier.padding(vertical = 5.dp) }, accountViewModel = accountViewModel, showImage = showImage, + automaticallyStartPlayback = automaticallyStartPlayback, nav = nav ) @@ -3086,7 +3114,7 @@ fun AudioTrackHeader(noteEvent: AudioTrackEvent, accountViewModel: AccountViewMo ?: VideoView( videoUri = media, description = noteEvent.subject(), - showVideo = remember { mutableStateOf(true) } + automaticallyStartPlayback = remember { mutableStateOf(true) } ) } } @@ -3211,7 +3239,7 @@ fun RenderLiveActivityEventInner(baseNote: Note, accountViewModel: AccountViewMo VideoView( videoUri = media, description = subject, - showVideo = remember { mutableStateOf(true) } + automaticallyStartPlayback = remember { mutableStateOf(true) } ) } } else { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt index 9cfc09bc0..73f46076a 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt @@ -258,6 +258,16 @@ fun NoteMaster( ) } + val automaticallyStartPlayback = remember { + mutableStateOf( + when (settings?.automaticallyStartPlayback) { + true -> !isMobile + false -> false + else -> true + } + ) + } + var showHiddenNote by remember { mutableStateOf(false) } val context = LocalContext.current @@ -412,7 +422,15 @@ fun NoteMaster( ) { Column() { if ((noteEvent is ChannelCreateEvent || noteEvent is ChannelMetadataEvent) && note.channelHex() != null) { - ChannelHeader(channelHex = note.channelHex()!!, showVideo = true, showBottomDiviser = false, accountViewModel = accountViewModel, showImage = showImage, nav = nav) + ChannelHeader( + channelHex = note.channelHex()!!, + showVideo = true, + showBottomDiviser = false, + accountViewModel = accountViewModel, + showImage = showImage, + automaticallyStartPlayback = automaticallyStartPlayback, + nav = nav + ) } else if (noteEvent is FileHeaderEvent) { FileHeaderDisplay(baseNote, accountViewModel) } else if (noteEvent is FileStorageHeaderEvent) { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt index ec2a7b987..edea6280c 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt @@ -214,6 +214,16 @@ fun ChannelScreen( ) } + val automaticallyStartPlayback = remember { + mutableStateOf( + when (settings?.automaticallyStartPlayback) { + true -> !isMobile + false -> false + else -> true + } + ) + } + LaunchedEffect(Unit) { NostrChannelDataSource.start() feedViewModel.invalidateData() @@ -255,6 +265,7 @@ fun ChannelScreen( showBottomDiviser = true, accountViewModel = accountViewModel, showImage = showImage, + automaticallyStartPlayback = automaticallyStartPlayback, nav = nav ) @@ -535,6 +546,7 @@ fun ChannelHeader( modifier: Modifier = StdPadding, accountViewModel: AccountViewModel, showImage: MutableState, + automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { val channelHex by remember { @@ -549,6 +561,7 @@ fun ChannelHeader( showBottomDiviser = showBottomDiviser, accountViewModel = accountViewModel, showImage = showImage, + automaticallyStartPlayback = automaticallyStartPlayback, nav = nav ) } @@ -563,6 +576,7 @@ fun ChannelHeader( modifier: Modifier = StdPadding, accountViewModel: AccountViewModel, showImage: MutableState, + automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { var baseChannel by remember { mutableStateOf(LocalCache.channels[channelHex]) } @@ -584,6 +598,7 @@ fun ChannelHeader( modifier, accountViewModel, showImage, + automaticallyStartPlayback, nav ) } @@ -598,6 +613,7 @@ fun ChannelHeader( modifier: Modifier = StdPadding, accountViewModel: AccountViewModel, showImage: MutableState, + automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { Column(Modifier.fillMaxWidth()) { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/VideoScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/VideoScreen.kt index fa072d2ac..caadbdb2f 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/VideoScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/VideoScreen.kt @@ -206,6 +206,17 @@ fun RenderPage( } ) } + + val automaticallyStartPlayback = remember { + mutableStateOf( + when (settings?.automaticallyStartPlayback) { + true -> !isMobile + false -> false + else -> true + } + ) + } + Box() { Column { Crossfade( @@ -227,6 +238,7 @@ fun RenderPage( pagerState, accountViewModel, showImage, + automaticallyStartPlayback, nav ) } @@ -247,6 +259,7 @@ fun SlidingCarousel( pagerState: PagerState, accountViewModel: AccountViewModel, showImage: MutableState, + automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { VerticalPager( @@ -259,7 +272,7 @@ fun SlidingCarousel( } ) { index -> feed.value.getOrNull(index)?.let { note -> - RenderVideoOrPictureNote(note, accountViewModel, showImage, nav) + RenderVideoOrPictureNote(note, accountViewModel, showImage, automaticallyStartPlayback, nav) } } } @@ -269,6 +282,7 @@ private fun RenderVideoOrPictureNote( note: Note, accountViewModel: AccountViewModel, showImage: MutableState, + automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { Column(remember { Modifier.fillMaxSize(1f) }) { From 38bb9f457d528b9d3c65d5dd267361e47bc462d3 Mon Sep 17 00:00:00 2001 From: greenart7c3 <115044884+greenart7c3@users.noreply.github.com> Date: Fri, 7 Jul 2023 06:09:18 -0300 Subject: [PATCH 14/29] fix statusbar color when changing theme --- .../java/com/vitorpamplona/amethyst/ui/theme/Theme.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt index 88cf6fec2..a1966e8a6 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt @@ -323,10 +323,14 @@ fun AmethystTheme(themeViewModel: ThemeViewModel, content: @Composable () -> Uni ) val view = LocalView.current - if (!view.isInEditMode && darkTheme) { + if (!view.isInEditMode) { SideEffect { val window = (view.context as Activity).window - window.statusBarColor = colors.background.toArgb() + if (darkTheme) { + window.statusBarColor = colors.background.toArgb() + } else { + window.statusBarColor = colors.primary.toArgb() + } } } } From 66952c921296f3f3e857359ca027117db0f616fc Mon Sep 17 00:00:00 2001 From: greenart7c3 <115044884+greenart7c3@users.noreply.github.com> Date: Fri, 7 Jul 2023 06:39:28 -0300 Subject: [PATCH 15/29] add url preview settings --- .../amethyst/LocalPreferences.kt | 11 ++++ .../vitorpamplona/amethyst/model/Account.kt | 7 ++- .../vitorpamplona/amethyst/model/Settings.kt | 3 +- .../amethyst/ui/actions/NewPostView.kt | 4 +- .../ui/components/ExpandableRichTextViewer.kt | 11 ++++ .../amethyst/ui/components/RichTextViewer.kt | 8 ++- .../amethyst/ui/components/UrlPreview.kt | 51 +++++++++++-------- .../amethyst/ui/components/UrlPreviewCard.kt | 7 ++- .../ui/screen/loggedIn/AccountViewModel.kt | 8 ++- .../ui/screen/loggedIn/ProfileScreen.kt | 15 ------ .../ui/screen/loggedIn/SettingsScreen.kt | 19 ++++++- 11 files changed, 98 insertions(+), 46 deletions(-) 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() From 0fead83279d8dbf7ce8d77456b866d06c61c481e Mon Sep 17 00:00:00 2001 From: greenart7c3 <115044884+greenart7c3@users.noreply.github.com> Date: Fri, 7 Jul 2023 07:29:48 -0300 Subject: [PATCH 16/29] fix load image box size --- .../ui/components/ZoomableContentView.kt | 109 +++++++++--------- 1 file changed, 55 insertions(+), 54 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt index e8e5a7f09..a423b1853 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt @@ -313,7 +313,8 @@ private fun UrlImageView( fun LoadImageBox(showImage: MutableState) { Box( modifier = Modifier - .size(300.dp) + .height(300.dp) + .fillMaxWidth() .clip(RoundedCornerShape(10.dp)) .background(Color.LightGray) .clickable { showImage.value = true }, @@ -337,31 +338,31 @@ private fun AddedImageFeatures( showImage: MutableState ) { if (!showImage.value) { - return LoadImageBox(showImage) - } - - when (painter.value) { - null, is AsyncImagePainter.State.Loading -> { - if (content.blurhash != null) { - DisplayBlurHash(content.blurhash, content.description, contentScale, myModifier) - } else { - FlowRow() { - DisplayUrlWithLoadingSymbol(content) + LoadImageBox(showImage) + } else { + when (painter.value) { + null, is AsyncImagePainter.State.Loading -> { + if (content.blurhash != null) { + DisplayBlurHash(content.blurhash, content.description, contentScale, myModifier) + } else { + FlowRow() { + DisplayUrlWithLoadingSymbol(content) + } } } - } - is AsyncImagePainter.State.Error -> { - BlankNote() - } - - is AsyncImagePainter.State.Success -> { - if (content.isVerified != null) { - HashVerificationSymbol(content.isVerified, verifiedModifier) + is AsyncImagePainter.State.Error -> { + BlankNote() } - } - else -> { + is AsyncImagePainter.State.Success -> { + if (content.isVerified != null) { + HashVerificationSymbol(content.isVerified, verifiedModifier) + } + } + + else -> { + } } } } @@ -377,47 +378,47 @@ private fun AddedImageFeatures( showImage: MutableState ) { if (!showImage.value) { - return LoadImageBox(showImage) - } - - var verifiedHash by remember { - mutableStateOf(null) - } - - when (painter.value) { - null, is AsyncImagePainter.State.Loading -> { - if (content.blurhash != null) { - DisplayBlurHash(content.blurhash, content.description, contentScale, myModifier) - } else { - FlowRow() { - DisplayUrlWithLoadingSymbol(content) - } - } + LoadImageBox(showImage) + } else { + var verifiedHash by remember { + mutableStateOf(null) } - is AsyncImagePainter.State.Error -> { - ClickableUrl(urlText = "${content.url} ", url = content.url) - } - - is AsyncImagePainter.State.Success -> { - if (content.hash != null) { - val context = LocalContext.current - LaunchedEffect(key1 = content.url) { - launch(Dispatchers.IO) { - val newVerifiedHash = verifyHash(content, context) - if (newVerifiedHash != verifiedHash) { - verifiedHash = newVerifiedHash - } + when (painter.value) { + null, is AsyncImagePainter.State.Loading -> { + if (content.blurhash != null) { + DisplayBlurHash(content.blurhash, content.description, contentScale, myModifier) + } else { + FlowRow() { + DisplayUrlWithLoadingSymbol(content) } } } - verifiedHash?.let { - HashVerificationSymbol(it, verifiedModifier) + is AsyncImagePainter.State.Error -> { + ClickableUrl(urlText = "${content.url} ", url = content.url) } - } - else -> { + is AsyncImagePainter.State.Success -> { + if (content.hash != null) { + val context = LocalContext.current + LaunchedEffect(key1 = content.url) { + launch(Dispatchers.IO) { + val newVerifiedHash = verifyHash(content, context) + if (newVerifiedHash != verifiedHash) { + verifiedHash = newVerifiedHash + } + } + } + } + + verifiedHash?.let { + HashVerificationSymbol(it, verifiedModifier) + } + } + + else -> { + } } } } From 1e6ee67932b6c49a1c860aa86e3988a0c080fcad Mon Sep 17 00:00:00 2001 From: greenart7c3 <115044884+greenart7c3@users.noreply.github.com> Date: Fri, 7 Jul 2023 11:47:28 -0300 Subject: [PATCH 17/29] move back settings to drawer --- .../amethyst/ui/navigation/DrawerContent.kt | 148 ++++++++++++++++++ .../ui/screen/loggedIn/SettingsScreen.kt | 134 ---------------- 2 files changed, 148 insertions(+), 134 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt index 7018c4138..c6ead6f6d 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt @@ -1,5 +1,6 @@ package com.vitorpamplona.amethyst.ui.navigation +import android.content.Context import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.Image import androidx.compose.foundation.background @@ -19,6 +20,7 @@ import androidx.compose.foundation.layout.width import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.verticalScroll +import androidx.compose.material.AlertDialog import androidx.compose.material.Divider import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.Icon @@ -28,8 +30,10 @@ import androidx.compose.material.ModalBottomSheetState import androidx.compose.material.ScaffoldState import androidx.compose.material.Surface import androidx.compose.material.Text +import androidx.compose.material.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.MutableState import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState @@ -42,24 +46,34 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import androidx.lifecycle.viewmodel.compose.viewModel import coil.compose.AsyncImage import com.vitorpamplona.amethyst.BuildConfig +import com.vitorpamplona.amethyst.LocalPreferences import com.vitorpamplona.amethyst.R +import com.vitorpamplona.amethyst.ServiceManager +import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.User +import com.vitorpamplona.amethyst.service.HttpClient +import com.vitorpamplona.amethyst.ui.actions.NewRelayListView import com.vitorpamplona.amethyst.ui.actions.toImmutableListOfLists import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji import com.vitorpamplona.amethyst.ui.components.RobohashAsyncImageProxy import com.vitorpamplona.amethyst.ui.screen.RelayPoolViewModel +import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountBackupDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.screen.loggedIn.ConnectOrbotDialog import com.vitorpamplona.amethyst.ui.theme.DoubleHorzSpacer import com.vitorpamplona.amethyst.ui.theme.Size16dp import com.vitorpamplona.amethyst.ui.theme.placeholderText +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -287,6 +301,17 @@ fun ListContent( val accountState by accountViewModel.accountLiveData.observeAsState() val account = remember(accountState) { accountState?.account } ?: return val coroutineScope = rememberCoroutineScope() + val relayViewModel: RelayPoolViewModel = viewModel { RelayPoolViewModel() } + var wantsToEditRelays by remember { + mutableStateOf(false) + } + + var backupDialogOpen by remember { mutableStateOf(false) } + var checked by remember { mutableStateOf(accountViewModel.account.proxy != null) } + var disconnectTorDialog by remember { mutableStateOf(false) } + var conectOrbotDialogOpen by remember { mutableStateOf(false) } + val proxyPort = remember { mutableStateOf(accountViewModel.account.proxyPort.toString()) } + val context = LocalContext.current Column( modifier = modifier @@ -311,6 +336,60 @@ fun ListContent( route = Route.Bookmarks.route ) + IconRowRelays( + relayViewModel = relayViewModel, + onClick = { + coroutineScope.launch { + scaffoldState.drawerState.close() + } + wantsToEditRelays = true + } + ) + + NavigationRow( + title = stringResource(R.string.security_filters), + icon = Route.BlockedUsers.icon, + tint = MaterialTheme.colors.onBackground, + nav = nav, + scaffoldState = scaffoldState, + route = Route.BlockedUsers.route + ) + + IconRow( + title = stringResource(R.string.backup_keys), + icon = R.drawable.ic_key, + tint = MaterialTheme.colors.onBackground, + onClick = { + coroutineScope.launch { + scaffoldState.drawerState.close() + } + backupDialogOpen = true + } + ) + + val textTorProxy = if (checked) stringResource(R.string.disconnect_from_your_orbot_setup) else stringResource(R.string.connect_via_tor_short) + IconRow( + title = textTorProxy, + icon = R.drawable.ic_tor, + tint = MaterialTheme.colors.onBackground, + onLongClick = { + coroutineScope.launch { + scaffoldState.drawerState.close() + } + conectOrbotDialogOpen = true + }, + onClick = { + if (checked) { + disconnectTorDialog = true + } else { + coroutineScope.launch { + scaffoldState.drawerState.close() + } + conectOrbotDialogOpen = true + } + } + ) + NavigationRow( title = stringResource(R.string.settings), icon = Route.Settings.icon, @@ -329,6 +408,75 @@ fun ListContent( onClick = { coroutineScope.launch { sheetState.show() } } ) } + + if (wantsToEditRelays) { + NewRelayListView({ wantsToEditRelays = false }, accountViewModel, nav = nav) + } + if (backupDialogOpen) { + AccountBackupDialog(accountViewModel.account, onClose = { backupDialogOpen = false }) + } + if (conectOrbotDialogOpen) { + ConnectOrbotDialog( + onClose = { conectOrbotDialogOpen = false }, + onPost = { + conectOrbotDialogOpen = false + disconnectTorDialog = false + checked = true + enableTor(accountViewModel.account, true, proxyPort, context, coroutineScope) + }, + proxyPort + ) + } + + if (disconnectTorDialog) { + AlertDialog( + title = { + Text(text = stringResource(R.string.do_you_really_want_to_disable_tor_title)) + }, + text = { + Text(text = stringResource(R.string.do_you_really_want_to_disable_tor_text)) + }, + onDismissRequest = { + disconnectTorDialog = false + }, + confirmButton = { + TextButton( + onClick = { + disconnectTorDialog = false + checked = false + enableTor(accountViewModel.account, false, proxyPort, context, coroutineScope) + } + ) { + Text(text = stringResource(R.string.yes)) + } + }, + dismissButton = { + TextButton( + onClick = { + disconnectTorDialog = false + } + ) { + Text(text = stringResource(R.string.no)) + } + } + ) + } +} + +private fun enableTor( + account: Account, + checked: Boolean, + portNumber: MutableState, + context: Context, + scope: CoroutineScope +) { + account.proxyPort = portNumber.value.toInt() + account.proxy = HttpClient.initProxy(checked, "127.0.0.1", account.proxyPort) + scope.launch(Dispatchers.IO) { + LocalPreferences.saveToEncryptedStorage(account) + ServiceManager.pause() + ServiceManager.start(context) + } } @Composable 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 b98079007..29a34963a 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 @@ -10,15 +10,12 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll -import androidx.compose.material.AlertDialog import androidx.compose.material.Button import androidx.compose.material.DropdownMenuItem import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.ExposedDropdownMenuBox import androidx.compose.material.ExposedDropdownMenuDefaults -import androidx.compose.material.MaterialTheme import androidx.compose.material.Text -import androidx.compose.material.TextButton import androidx.compose.material.TextField import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState @@ -30,26 +27,16 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.intl.Locale import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.core.os.LocaleListCompat -import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.LocalPreferences import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ServiceManager -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.service.HttpClient -import com.vitorpamplona.amethyst.ui.actions.NewRelayListView -import com.vitorpamplona.amethyst.ui.navigation.IconRow -import com.vitorpamplona.amethyst.ui.navigation.IconRowRelays -import com.vitorpamplona.amethyst.ui.navigation.Route -import com.vitorpamplona.amethyst.ui.screen.RelayPoolViewModel import com.vitorpamplona.amethyst.ui.theme.DoubleVertSpacer import com.vitorpamplona.amethyst.ui.theme.StdPadding -import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import org.xmlpull.v1.XmlPullParser @@ -137,65 +124,12 @@ fun SettingsScreen( val selectedLanguage = remember { mutableStateOf(languageList[languageIndex]) } - val relayViewModel: RelayPoolViewModel = viewModel { RelayPoolViewModel() } - var wantsToEditRelays by remember { - mutableStateOf(false) - } - var backupDialogOpen by remember { mutableStateOf(false) } - var checked by remember { mutableStateOf(accountViewModel.account.proxy != null) } - var disconnectTorDialog by remember { mutableStateOf(false) } - var conectOrbotDialogOpen by remember { mutableStateOf(false) } - val proxyPort = remember { mutableStateOf(accountViewModel.account.proxyPort.toString()) } Column( StdPadding .verticalScroll(rememberScrollState()), horizontalAlignment = Alignment.CenterHorizontally ) { - Section("Account preferences") - - IconRowRelays( - relayViewModel = relayViewModel, - onClick = { - wantsToEditRelays = true - } - ) - - IconRow( - title = stringResource(R.string.security_filters), - icon = Route.BlockedUsers.icon, - tint = MaterialTheme.colors.onBackground, - onClick = { - nav(Route.BlockedUsers.route) - } - ) - - IconRow( - title = stringResource(R.string.backup_keys), - icon = R.drawable.ic_key, - tint = MaterialTheme.colors.onBackground, - onClick = { - backupDialogOpen = true - } - ) - - val textTorProxy = if (checked) stringResource(R.string.disconnect_from_your_orbot_setup) else stringResource(R.string.connect_via_tor_short) - IconRow( - title = textTorProxy, - icon = R.drawable.ic_tor, - tint = MaterialTheme.colors.onBackground, - onLongClick = { - conectOrbotDialogOpen = true - }, - onClick = { - if (checked) { - disconnectTorDialog = true - } else { - conectOrbotDialogOpen = true - } - } - ) - Section("Application preferences") DropDownSettings( @@ -266,74 +200,6 @@ fun SettingsScreen( } } } - if (wantsToEditRelays) { - NewRelayListView({ wantsToEditRelays = false }, accountViewModel, nav = nav) - } - if (backupDialogOpen) { - AccountBackupDialog(accountViewModel.account, onClose = { backupDialogOpen = false }) - } - if (conectOrbotDialogOpen) { - ConnectOrbotDialog( - onClose = { conectOrbotDialogOpen = false }, - onPost = { - conectOrbotDialogOpen = false - disconnectTorDialog = false - checked = true - enableTor(accountViewModel.account, true, proxyPort, context, scope) - }, - proxyPort - ) - } - - if (disconnectTorDialog) { - AlertDialog( - title = { - Text(text = stringResource(R.string.do_you_really_want_to_disable_tor_title)) - }, - text = { - Text(text = stringResource(R.string.do_you_really_want_to_disable_tor_text)) - }, - onDismissRequest = { - disconnectTorDialog = false - }, - confirmButton = { - TextButton( - onClick = { - disconnectTorDialog = false - checked = false - enableTor(accountViewModel.account, false, proxyPort, context, scope) - } - ) { - Text(text = stringResource(R.string.yes)) - } - }, - dismissButton = { - TextButton( - onClick = { - disconnectTorDialog = false - } - ) { - Text(text = stringResource(R.string.no)) - } - } - ) - } -} - -private fun enableTor( - account: Account, - checked: Boolean, - portNumber: MutableState, - context: Context, - scope: CoroutineScope -) { - account.proxyPort = portNumber.value.toInt() - account.proxy = HttpClient.initProxy(checked, "127.0.0.1", account.proxyPort) - scope.launch(Dispatchers.IO) { - LocalPreferences.saveToEncryptedStorage(account) - ServiceManager.pause() - ServiceManager.start(context) - } } @OptIn(ExperimentalMaterialApi::class) From 6e89e69fb6ac0787d40e373946696b619e38168b Mon Sep 17 00:00:00 2001 From: greenart7c3 <115044884+greenart7c3@users.noreply.github.com> Date: Fri, 7 Jul 2023 13:02:39 -0300 Subject: [PATCH 18/29] refactor settings to use TextSpinner and save settings when selecting an option --- .../amethyst/LocalPreferences.kt | 10 +- .../vitorpamplona/amethyst/model/Account.kt | 22 +- .../amethyst/ui/screen/ThemeViewModel.kt | 6 +- .../ui/screen/loggedIn/AccountViewModel.kt | 24 ++- .../ui/screen/loggedIn/SettingsScreen.kt | 203 +++++++++++------- .../vitorpamplona/amethyst/ui/theme/Theme.kt | 6 +- 6 files changed, 165 insertions(+), 106 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt b/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt index 2a6929735..3ea15b1a8 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt @@ -265,18 +265,16 @@ object LocalPreferences { }.apply() } - fun updateTheme(theme: String) { + fun updateTheme(theme: Int) { encryptedPreferences().edit().apply { - putString(PrefKeys.THEME, theme) + putInt(PrefKeys.THEME, theme) }.apply() } - fun getTheme(): String { - var theme = "System" + fun getTheme(): Int { encryptedPreferences().apply { - theme = getString(PrefKeys.THEME, "System") ?: "System" + return getInt(PrefKeys.THEME, 0) } - return theme } fun getPreferredLanguage(): String { 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 cefa8bf11..9adf54c5f 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt @@ -85,19 +85,31 @@ class Account( val saveable: AccountLiveData = AccountLiveData(this) var userProfileCache: User? = null - - fun updateGlobalSettings( - automaticallyShowImages: Boolean?, + fun updateAutomaticallyStartPlayback( automaticallyStartPlayback: Boolean?, - automaticallyShowUrlPreview: Boolean? ) { settings.automaticallyStartPlayback = automaticallyStartPlayback - settings.automaticallyShowImages = automaticallyShowImages + live.invalidateData() + saveable.invalidateData() + } + + fun updateAutomaticallyShowUrlPreview( + automaticallyShowUrlPreview: Boolean?, + ) { settings.automaticallyShowUrlPreview = automaticallyShowUrlPreview live.invalidateData() saveable.invalidateData() } + fun updateAutomaticallyShowImages( + automaticallyShowImages: Boolean?, + ) { + settings.automaticallyShowImages = automaticallyShowImages + live.invalidateData() + saveable.invalidateData() + } + + fun updateOptOutOptions(warnReports: Boolean, filterSpam: Boolean) { warnAboutPostsWithReports = warnReports filterSpamFromStrangers = filterSpam diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThemeViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThemeViewModel.kt index c64cca42d..661d8672d 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThemeViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThemeViewModel.kt @@ -5,10 +5,10 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel class ThemeViewModel : ViewModel() { - private val _theme = MutableLiveData("System") - val theme: LiveData = _theme + private val _theme = MutableLiveData(0) + val theme: LiveData = _theme - fun onChange(newValue: String) { + fun onChange(newValue: Int) { _theme.value = newValue } } 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 003f7c926..ab743e3d2 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 @@ -41,20 +41,30 @@ class AccountViewModel(val account: Account, private val themeViewModel: ThemeVi val userFollows: LiveData = account.userProfile().live().follows.map { it } val userRelays: LiveData = account.userProfile().live().relays.map { it } - fun changeTheme(newValue: String) { + fun changeTheme(newValue: Int) { themeViewModel.onChange(newValue) } - fun currentTheme(): String { - return themeViewModel.theme.value ?: "System" + fun currentTheme(): Int { + return themeViewModel.theme.value ?: 0 } - fun updateGlobalSettings( - automaticallyShowImages: Boolean?, + fun updateAutomaticallyStartPlayback( automaticallyStartPlayback: Boolean?, - automaticallyShowUrlPreview: Boolean? ) { - account.updateGlobalSettings(automaticallyShowImages, automaticallyStartPlayback, automaticallyShowUrlPreview) + account.updateAutomaticallyStartPlayback(automaticallyStartPlayback) + } + + fun updateAutomaticallyShowUrlPreview( + automaticallyShowUrlPreview: Boolean?, + ) { + account.updateAutomaticallyShowUrlPreview(automaticallyShowUrlPreview) + } + + fun updateAutomaticallyShowImages( + automaticallyShowImages: Boolean?, + ) { + account.updateAutomaticallyShowImages(automaticallyShowImages) } fun isWriteable(): Boolean { 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 29a34963a..a26087ebe 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 @@ -2,15 +2,15 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn import android.content.Context import androidx.appcompat.app.AppCompatDelegate -import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll -import androidx.compose.material.Button import androidx.compose.material.DropdownMenuItem import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.ExposedDropdownMenuBox @@ -34,9 +34,10 @@ import androidx.compose.ui.unit.sp import androidx.core.os.LocaleListCompat import com.vitorpamplona.amethyst.LocalPreferences import com.vitorpamplona.amethyst.R -import com.vitorpamplona.amethyst.ServiceManager import com.vitorpamplona.amethyst.ui.theme.DoubleVertSpacer import com.vitorpamplona.amethyst.ui.theme.StdPadding +import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import org.xmlpull.v1.XmlPullParser @@ -89,7 +90,7 @@ fun SettingsScreen( nav: (String) -> Unit ) { val scope = rememberCoroutineScope() - val selectedItens = arrayOf("Always", "Wifi-only", "Never") + val selectedItens = persistentListOf("Always", "Wifi-only", "Never") val settings = accountViewModel.account.settings val index = if (settings.automaticallyShowImages == null) { 0 } else { if (settings.automaticallyShowImages == true) 1 else 2 @@ -97,33 +98,18 @@ fun SettingsScreen( val videoIndex = if (settings.automaticallyStartPlayback == null) { 0 } else { if (settings.automaticallyShowImages == true) 1 else 2 } - val selectedItem = remember { - mutableStateOf(selectedItens[index]) - } - 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()) - val selectedTheme = remember { - mutableStateOf(themeItens[themeIndex]) - } + val themeItens = persistentListOf("System", "Light", "Dark") + val themeIndex = accountViewModel.currentTheme() val context = LocalContext.current val languageEntries = context.getLangPreferenceDropdownEntries() - val languageList = languageEntries.keys.toTypedArray() + val languageList = languageEntries.keys.toImmutableList() val languageIndex = getLanguageIndex(languageEntries) - val selectedLanguage = remember { - mutableStateOf(languageList[languageIndex]) - } Column( StdPadding @@ -132,72 +118,125 @@ fun SettingsScreen( ) { Section("Application preferences") - DropDownSettings( - selectedItem = selectedLanguage, - listItems = languageList, - title = "Language" - ) - - DropDownSettings( - selectedItem = selectedTheme, - listItems = themeItens, - title = "Theme" - ) - - DropDownSettings( - selectedItem = selectedItem, - listItems = selectedItens, - title = "Automatically load images/gifs" - ) - - DropDownSettings( - selectedItem = selectedVideoItem, - listItems = selectedItens, - title = "Automatically play videos" - ) - - DropDownSettings( - selectedItem = selectedLinkItem, - listItems = selectedItens, - title = "Automatically show url preview" - ) - Row( - Modifier.fillMaxWidth(), - Arrangement.Center + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.fillMaxWidth() ) { - Button( - onClick = { - val automaticallyShowImages = when (selectedItens.indexOf(selectedItem.value)) { - 1 -> true - 2 -> false - else -> null - } - val automaticallyStartPlayback = when (selectedItens.indexOf(selectedVideoItem.value)) { - 1 -> true - 2 -> false - else -> null - } - val automaticallyShowUrlPreview = when (selectedItens.indexOf(selectedLinkItem.value)) { - 1 -> true - 2 -> false - else -> null - } - accountViewModel.changeTheme(selectedTheme.value) - + TextSpinner( + label = "Language", + placeholder = languageList[languageIndex], + options = languageList, + onSelect = { scope.launch(Dispatchers.IO) { - accountViewModel.updateGlobalSettings(automaticallyShowImages, automaticallyStartPlayback, automaticallyShowUrlPreview) + val locale = languageEntries[languageList[it]] + accountViewModel.account.settings.preferredLanguage = locale LocalPreferences.saveToEncryptedStorage(accountViewModel.account) - LocalPreferences.updateTheme(selectedTheme.value) - ServiceManager.pause() - ServiceManager.start(context) - val appLocale: LocaleListCompat = LocaleListCompat.forLanguageTags(languageEntries[selectedLanguage.value]) + val appLocale: LocaleListCompat = LocaleListCompat.forLanguageTags(languageEntries[languageList[it]]) AppCompatDelegate.setApplicationLocales(appLocale) } - } - ) { - Text(text = "Save") - } + }, + modifier = Modifier + .windowInsetsPadding(WindowInsets(0.dp, 0.dp, 0.dp, 0.dp)) + .weight(1f) + ) + } + + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.fillMaxWidth() + ) { + TextSpinner( + label = "Theme", + placeholder = themeItens[themeIndex], + options = themeItens, + onSelect = { + accountViewModel.changeTheme(it) + scope.launch(Dispatchers.IO) { + LocalPreferences.updateTheme(it) + } + }, + modifier = Modifier + .windowInsetsPadding(WindowInsets(0.dp, 0.dp, 0.dp, 0.dp)) + .weight(1f) + ) + } + + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.fillMaxWidth() + ) { + TextSpinner( + label = "Automatically load images/gifs", + placeholder = selectedItens[index], + options = selectedItens, + onSelect = { + val automaticallyShowImages = when (it) { + 1 -> true + 2 -> false + else -> null + } + + scope.launch(Dispatchers.IO) { + accountViewModel.updateAutomaticallyShowImages(automaticallyShowImages) + LocalPreferences.saveToEncryptedStorage(accountViewModel.account) + } + }, + modifier = Modifier + .windowInsetsPadding(WindowInsets(0.dp, 0.dp, 0.dp, 0.dp)) + .weight(1f) + ) + } + + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.fillMaxWidth() + ) { + TextSpinner( + label = "Automatically play videos", + placeholder = selectedItens[videoIndex], + options = selectedItens, + onSelect = { + val automaticallyStartPlayback = when (it) { + 1 -> true + 2 -> false + else -> null + } + + scope.launch(Dispatchers.IO) { + accountViewModel.updateAutomaticallyStartPlayback(automaticallyStartPlayback) + LocalPreferences.saveToEncryptedStorage(accountViewModel.account) + } + }, + modifier = Modifier + .windowInsetsPadding(WindowInsets(0.dp, 0.dp, 0.dp, 0.dp)) + .weight(1f) + ) + } + + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.fillMaxWidth() + ) { + TextSpinner( + label = "Automatically show url preview", + placeholder = selectedItens[linkIndex], + options = selectedItens, + onSelect = { + val automaticallyShowUrlPreview = when (it) { + 1 -> true + 2 -> false + else -> null + } + + scope.launch(Dispatchers.IO) { + accountViewModel.updateAutomaticallyStartPlayback(automaticallyShowUrlPreview) + LocalPreferences.saveToEncryptedStorage(accountViewModel.account) + } + }, + modifier = Modifier + .windowInsetsPadding(WindowInsets(0.dp, 0.dp, 0.dp, 0.dp)) + .weight(1f) + ) } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt index a1966e8a6..cb4f37191 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Theme.kt @@ -309,9 +309,9 @@ val Colors.innerPostModifier: Modifier fun AmethystTheme(themeViewModel: ThemeViewModel, content: @Composable () -> Unit) { val theme = themeViewModel.theme.observeAsState() val darkTheme = when (theme.value) { - "Dark" -> true - "Light" -> false - else -> if (isSystemInDarkTheme()) true else false + 2 -> true + 1 -> false + else -> isSystemInDarkTheme() } val colors = if (darkTheme) DarkColorPalette else LightColorPalette From e2ef7cfd70390376ec61b826faefc88377dae9bd Mon Sep 17 00:00:00 2001 From: greenart7c3 <115044884+greenart7c3@users.noreply.github.com> Date: Fri, 7 Jul 2023 13:17:38 -0300 Subject: [PATCH 19/29] add string resources --- .../vitorpamplona/amethyst/model/Account.kt | 7 ++--- .../ui/components/ZoomableContentView.kt | 3 +- .../ui/screen/loggedIn/AccountViewModel.kt | 6 ++-- .../ui/screen/loggedIn/SettingsScreen.kt | 29 +++++++++++++------ app/src/main/res/values/strings.xml | 12 ++++++++ 5 files changed, 40 insertions(+), 17 deletions(-) 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 9adf54c5f..b703d162a 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt @@ -86,7 +86,7 @@ class Account( var userProfileCache: User? = null fun updateAutomaticallyStartPlayback( - automaticallyStartPlayback: Boolean?, + automaticallyStartPlayback: Boolean? ) { settings.automaticallyStartPlayback = automaticallyStartPlayback live.invalidateData() @@ -94,7 +94,7 @@ class Account( } fun updateAutomaticallyShowUrlPreview( - automaticallyShowUrlPreview: Boolean?, + automaticallyShowUrlPreview: Boolean? ) { settings.automaticallyShowUrlPreview = automaticallyShowUrlPreview live.invalidateData() @@ -102,14 +102,13 @@ class Account( } fun updateAutomaticallyShowImages( - automaticallyShowImages: Boolean?, + automaticallyShowImages: Boolean? ) { settings.automaticallyShowImages = automaticallyShowImages live.invalidateData() saveable.invalidateData() } - fun updateOptOutOptions(warnReports: Boolean, filterSpam: Boolean) { warnAboutPostsWithReports = warnReports filterSpamFromStrangers = filterSpam diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt index a423b1853..4c1f6ce08 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt @@ -55,6 +55,7 @@ import androidx.compose.ui.platform.LocalClipboardManager import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalView import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.Placeholder import androidx.compose.ui.text.PlaceholderVerticalAlign @@ -321,7 +322,7 @@ fun LoadImageBox(showImage: MutableState) { contentAlignment = Alignment.Center ) { Text( - text = "Load Image", + text = stringResource(R.string.load_image), style = TextStyle(color = Color.Black, fontSize = 18.sp) ) } 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 ab743e3d2..fedfa79bf 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 @@ -50,19 +50,19 @@ class AccountViewModel(val account: Account, private val themeViewModel: ThemeVi } fun updateAutomaticallyStartPlayback( - automaticallyStartPlayback: Boolean?, + automaticallyStartPlayback: Boolean? ) { account.updateAutomaticallyStartPlayback(automaticallyStartPlayback) } fun updateAutomaticallyShowUrlPreview( - automaticallyShowUrlPreview: Boolean?, + automaticallyShowUrlPreview: Boolean? ) { account.updateAutomaticallyShowUrlPreview(automaticallyShowUrlPreview) } fun updateAutomaticallyShowImages( - automaticallyShowImages: Boolean?, + automaticallyShowImages: Boolean? ) { account.updateAutomaticallyShowImages(automaticallyShowImages) } 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 a26087ebe..11cdb5464 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 @@ -27,6 +27,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.intl.Locale import androidx.compose.ui.unit.dp @@ -90,7 +91,13 @@ fun SettingsScreen( nav: (String) -> Unit ) { val scope = rememberCoroutineScope() - val selectedItens = persistentListOf("Always", "Wifi-only", "Never") + val selectedItens = persistentListOf( + stringResource(R.string.always), + stringResource(R.string.wifi_only), + stringResource(R.string.never).replaceFirstChar { + it.uppercase() + } + ) val settings = accountViewModel.account.settings val index = if (settings.automaticallyShowImages == null) { 0 } else { if (settings.automaticallyShowImages == true) 1 else 2 @@ -102,7 +109,11 @@ fun SettingsScreen( if (settings.automaticallyShowUrlPreview == true) 1 else 2 } - val themeItens = persistentListOf("System", "Light", "Dark") + val themeItens = persistentListOf( + stringResource(R.string.system), + stringResource(R.string.light), + stringResource(R.string.dark) + ) val themeIndex = accountViewModel.currentTheme() val context = LocalContext.current @@ -116,14 +127,14 @@ fun SettingsScreen( .verticalScroll(rememberScrollState()), horizontalAlignment = Alignment.CenterHorizontally ) { - Section("Application preferences") + Section(stringResource(R.string.application_preferences)) Row( verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth() ) { TextSpinner( - label = "Language", + label = stringResource(R.string.language), placeholder = languageList[languageIndex], options = languageList, onSelect = { @@ -146,7 +157,7 @@ fun SettingsScreen( modifier = Modifier.fillMaxWidth() ) { TextSpinner( - label = "Theme", + label = stringResource(R.string.theme), placeholder = themeItens[themeIndex], options = themeItens, onSelect = { @@ -166,7 +177,7 @@ fun SettingsScreen( modifier = Modifier.fillMaxWidth() ) { TextSpinner( - label = "Automatically load images/gifs", + label = stringResource(R.string.automatically_load_images_gifs), placeholder = selectedItens[index], options = selectedItens, onSelect = { @@ -192,7 +203,7 @@ fun SettingsScreen( modifier = Modifier.fillMaxWidth() ) { TextSpinner( - label = "Automatically play videos", + label = stringResource(R.string.automatically_play_videos), placeholder = selectedItens[videoIndex], options = selectedItens, onSelect = { @@ -218,7 +229,7 @@ fun SettingsScreen( modifier = Modifier.fillMaxWidth() ) { TextSpinner( - label = "Automatically show url preview", + label = stringResource(R.string.automatically_show_url_preview), placeholder = selectedItens[linkIndex], options = selectedItens, onSelect = { @@ -229,7 +240,7 @@ fun SettingsScreen( } scope.launch(Dispatchers.IO) { - accountViewModel.updateAutomaticallyStartPlayback(automaticallyShowUrlPreview) + accountViewModel.updateAutomaticallyShowUrlPreview(automaticallyShowUrlPreview) LocalPreferences.saveToEncryptedStorage(accountViewModel.account) } }, diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8babaa30f..eac5f1dee 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -484,4 +484,16 @@ Sensitive Content Adds sensitive content warning before showing this content Settings + Always + Wifi-only + System + Light + Dark + Application preferences + Language + Theme + Automatically load images/gifs + Automatically play videos + Automatically show url preview + Load Image From b5229f5fe1655bab01ebabfc3cb32c29d893affd Mon Sep 17 00:00:00 2001 From: greenart7c3 <115044884+greenart7c3@users.noreply.github.com> Date: Fri, 7 Jul 2023 17:58:56 -0300 Subject: [PATCH 20/29] only load one image when theres multiple images in the note --- .../vitorpamplona/amethyst/model/Account.kt | 2 +- .../amethyst/ui/components/RichTextViewer.kt | 8 ++-- .../ui/components/ZoomableContentView.kt | 48 +++++++++++++++---- 3 files changed, 42 insertions(+), 16 deletions(-) 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 b703d162a..ea32d6d74 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt @@ -74,7 +74,7 @@ class Account( var warnAboutPostsWithReports: Boolean = true, var filterSpamFromStrangers: Boolean = true, var lastReadPerRoute: Map = mapOf(), - var settings: Settings = Settings(null, null) + var settings: Settings = Settings() ) { var transientHiddenUsers: Set = setOf() 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 5c063e4a2..8e66b165b 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 @@ -162,7 +162,6 @@ private fun RenderRegular( backgroundColor, textStyle, accountViewModel, - showImage, automaticallyStartPlayback, automaticallyShowUrlPreview, nav @@ -244,13 +243,12 @@ private fun RenderWordWithPreview( backgroundColor: MutableState, style: TextStyle, accountViewModel: AccountViewModel, - showImage: MutableState, automaticallyStartPlayback: MutableState, automaticallyShowUrlPreview: MutableState, nav: (String) -> Unit ) { when (word) { - is ImageSegment -> ZoomableContentView(word.segmentText, state, showImage, automaticallyStartPlayback) + is ImageSegment -> ZoomableContentView(word.segmentText, state, accountViewModel, automaticallyStartPlayback) is LinkSegment -> UrlPreview(word.segmentText, word.segmentText, automaticallyShowUrlPreview) is EmojiSegment -> RenderCustomEmoji(word.segmentText, state) is InvoiceSegment -> MayBeInvoicePreview(word.segmentText) @@ -271,11 +269,11 @@ private fun RenderWordWithPreview( private fun ZoomableContentView( word: String, state: RichTextViewerState, - showImage: MutableState, + accountViewModel: AccountViewModel, automaticallyStartPlayback: MutableState ) { state.imagesForPager[word]?.let { - ZoomableContentView(it, state.imageList, showImage, automaticallyStartPlayback) + ZoomableContentView(it, state.imageList, accountViewModel, automaticallyStartPlayback) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt index 4c1f6ce08..e15e58e63 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt @@ -75,10 +75,12 @@ import coil.imageLoader import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.toHexKey import com.vitorpamplona.amethyst.service.BlurHashRequester +import com.vitorpamplona.amethyst.service.connectivitystatus.ConnectivityStatus import com.vitorpamplona.amethyst.ui.actions.CloseButton import com.vitorpamplona.amethyst.ui.actions.LoadingAnimation import com.vitorpamplona.amethyst.ui.actions.SaveToGallery import com.vitorpamplona.amethyst.ui.note.BlankNote +import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.theme.Font17SP import com.vitorpamplona.amethyst.ui.theme.imageModifier import kotlinx.collections.immutable.ImmutableList @@ -175,7 +177,7 @@ fun figureOutMimeType(fullUrl: String): ZoomableContent { fun ZoomableContentView( content: ZoomableContent, images: ImmutableList = listOf(content).toImmutableList(), - showImage: MutableState, + accountViewModel: AccountViewModel, automaticallyStartPlayback: MutableState ) { val clipboardManager = LocalClipboardManager.current @@ -204,9 +206,9 @@ fun ZoomableContentView( } when (content) { - is ZoomableUrlImage -> UrlImageView(content, mainImageModifier, showImage) + is ZoomableUrlImage -> UrlImageView(content, mainImageModifier, accountViewModel) is ZoomableUrlVideo -> VideoView(content.url, content.description, automaticallyStartPlayback = automaticallyStartPlayback) { dialogOpen = true } - is ZoomableLocalImage -> LocalImageView(content, mainImageModifier, showImage) + is ZoomableLocalImage -> LocalImageView(content, mainImageModifier, accountViewModel) is ZoomableLocalVideo -> content.localFile?.let { VideoView(it.toUri().toString(), content.description, automaticallyStartPlayback = automaticallyStartPlayback) { dialogOpen = true } @@ -222,10 +224,23 @@ fun ZoomableContentView( private fun LocalImageView( content: ZoomableLocalImage, mainImageModifier: Modifier, - showImage: MutableState + accountViewModel: AccountViewModel? ) { if (content.localFile != null && content.localFile.exists()) { BoxWithConstraints(contentAlignment = Alignment.Center) { + val settings = accountViewModel?.account?.settings + val isMobile = ConnectivityStatus.isOnMobileData.value + + val showImage = remember { + mutableStateOf( + when (settings?.automaticallyShowImages) { + true -> !isMobile + false -> false + else -> true + } + ) + } + val myModifier = remember { mainImageModifier .widthIn(max = maxWidth) @@ -270,9 +285,22 @@ private fun LocalImageView( private fun UrlImageView( content: ZoomableUrlImage, mainImageModifier: Modifier, - showImage: MutableState + accountViewModel: AccountViewModel? ) { BoxWithConstraints(contentAlignment = Alignment.Center) { + val settings = accountViewModel?.account?.settings + val isMobile = ConnectivityStatus.isOnMobileData.value + + val showImage = remember { + mutableStateOf( + when (settings?.automaticallyShowImages) { + true -> !isMobile + false -> false + else -> true + } + ) + } + val myModifier = remember { mainImageModifier .widthIn(max = maxWidth) @@ -559,11 +587,11 @@ fun ZoomableImageDialog(imageUrl: ZoomableContent, allImages: ImmutableList - RenderImageOrVideo(allImages[index], remember { mutableStateOf(true) }, remember { mutableStateOf(true) }) + RenderImageOrVideo(allImages[index], null, remember { mutableStateOf(true) }) } ) } else { - RenderImageOrVideo(imageUrl, remember { mutableStateOf(true) }, remember { mutableStateOf(true) }) + RenderImageOrVideo(imageUrl, null, remember { mutableStateOf(true) }) } Row( @@ -588,19 +616,19 @@ fun ZoomableImageDialog(imageUrl: ZoomableContent, allImages: ImmutableList, automaticallyStartPlayback: MutableState) { +fun RenderImageOrVideo(content: ZoomableContent, accountViewModel: AccountViewModel?, automaticallyStartPlayback: MutableState) { val mainModifier = Modifier .fillMaxSize() .zoomable(rememberZoomState()) if (content is ZoomableUrlImage) { - UrlImageView(content = content, mainImageModifier = mainModifier, showImage) + UrlImageView(content = content, mainImageModifier = mainModifier, accountViewModel) } else if (content is ZoomableUrlVideo) { Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxSize(1f)) { VideoView(content.url, content.description, automaticallyStartPlayback = automaticallyStartPlayback) } } else if (content is ZoomableLocalImage) { - LocalImageView(content = content, mainImageModifier = mainModifier, showImage) + LocalImageView(content = content, mainImageModifier = mainModifier, accountViewModel) } else if (content is ZoomableLocalVideo) { Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxSize(1f)) { content.localFile?.let { From e69c1cf3a94651a6ba1ce8b7302eb4bc255e0e78 Mon Sep 17 00:00:00 2001 From: greenart7c3 <115044884+greenart7c3@users.noreply.github.com> Date: Fri, 7 Jul 2023 18:15:36 -0300 Subject: [PATCH 21/29] remove unused showImage parameters --- .../ui/components/ExpandableRichTextViewer.kt | 11 -------- .../amethyst/ui/components/RichTextViewer.kt | 4 +-- .../amethyst/ui/note/ChannelCardCompose.kt | 27 +------------------ .../amethyst/ui/note/NoteCompose.kt | 11 +------- .../amethyst/ui/screen/ThreadFeedView.kt | 13 +-------- .../ui/screen/loggedIn/ChannelScreen.kt | 16 ----------- 6 files changed, 4 insertions(+), 78 deletions(-) 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 a640e5c07..93d67549c 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 @@ -48,16 +48,6 @@ fun ExpandableRichTextViewer( val settings = accountState?.account?.settings val isMobile = ConnectivityStatus.isOnMobileData.value - val showImage = remember { - mutableStateOf( - when (settings?.automaticallyShowImages) { - true -> !isMobile - false -> false - else -> true - } - ) - } - val automaticallyStartPlayback = remember { mutableStateOf( when (settings?.automaticallyStartPlayback) { @@ -106,7 +96,6 @@ fun ExpandableRichTextViewer( tags, backgroundColor, 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 8e66b165b..991829086 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 @@ -108,7 +108,6 @@ fun RichTextViewer( tags: ImmutableListOfLists, backgroundColor: MutableState, accountViewModel: AccountViewModel, - showImage: MutableState, automaticallyStartPlayback: MutableState, automaticallyShowUrlPreview: MutableState, nav: (String) -> Unit @@ -117,7 +116,7 @@ fun RichTextViewer( if (remember(content) { isMarkdown(content) }) { RenderContentAsMarkdown(content, tags, nav) } else { - RenderRegular(content, tags, canPreview, backgroundColor, accountViewModel, showImage, automaticallyStartPlayback, automaticallyShowUrlPreview, nav) + RenderRegular(content, tags, canPreview, backgroundColor, accountViewModel, automaticallyStartPlayback, automaticallyShowUrlPreview, nav) } } } @@ -130,7 +129,6 @@ private fun RenderRegular( canPreview: Boolean, backgroundColor: MutableState, accountViewModel: AccountViewModel, - showImage: MutableState, automaticallyStartPlayback: MutableState, automaticallyShowUrlPreview: MutableState, nav: (String) -> Unit diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChannelCardCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChannelCardCompose.kt index d4f850b00..2d2836a60 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChannelCardCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChannelCardCompose.kt @@ -98,16 +98,6 @@ fun ChannelCardCompose( val settings = accountState?.account?.settings val isMobile = ConnectivityStatus.isOnMobileData.value - val showImage = remember { - mutableStateOf( - when (settings?.automaticallyShowImages) { - true -> !isMobile - false -> false - else -> true - } - ) - } - val automaticallyStartPlayback = remember { mutableStateOf( when (settings?.automaticallyStartPlayback) { @@ -138,7 +128,6 @@ fun ChannelCardCompose( modifier, parentBackgroundColor, accountViewModel, - showImage, automaticallyStartPlayback, nav ) @@ -153,7 +142,6 @@ fun CheckHiddenChannelCardCompose( modifier: Modifier = Modifier, parentBackgroundColor: MutableState? = null, accountViewModel: AccountViewModel, - showImage: MutableState, automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { @@ -169,7 +157,6 @@ fun CheckHiddenChannelCardCompose( modifier, parentBackgroundColor, accountViewModel, - showImage, automaticallyStartPlayback, nav ) @@ -184,7 +171,6 @@ fun LoadedChannelCardCompose( modifier: Modifier = Modifier, parentBackgroundColor: MutableState? = null, accountViewModel: AccountViewModel, - showImage: MutableState, automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { @@ -217,7 +203,6 @@ fun LoadedChannelCardCompose( modifier, parentBackgroundColor, accountViewModel, - showImage, automaticallyStartPlayback, nav ) @@ -232,7 +217,6 @@ fun RenderChannelCardReportState( modifier: Modifier = Modifier, parentBackgroundColor: MutableState? = null, accountViewModel: AccountViewModel, - showImage: MutableState, automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { @@ -255,7 +239,6 @@ fun RenderChannelCardReportState( modifier, parentBackgroundColor, accountViewModel, - showImage, automaticallyStartPlayback, nav ) @@ -270,7 +253,6 @@ fun NormalChannelCard( modifier: Modifier = Modifier, parentBackgroundColor: MutableState? = null, accountViewModel: AccountViewModel, - showImage: MutableState, automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { @@ -281,7 +263,6 @@ fun NormalChannelCard( modifier, parentBackgroundColor, accountViewModel, - showImage, automaticallyStartPlayback, showPopup, nav @@ -296,7 +277,6 @@ private fun CheckNewAndRenderChannelCard( modifier: Modifier = Modifier, parentBackgroundColor: MutableState? = null, accountViewModel: AccountViewModel, - showImage: MutableState, automaticallyStartPlayback: MutableState, showPopup: () -> Unit, nav: (String) -> Unit @@ -355,7 +335,6 @@ private fun CheckNewAndRenderChannelCard( InnerChannelCardWithReactions( baseNote = baseNote, accountViewModel = accountViewModel, - showImage, automaticallyStartPlayback, nav = nav ) @@ -366,7 +345,6 @@ private fun CheckNewAndRenderChannelCard( fun InnerChannelCardWithReactions( baseNote: Note, accountViewModel: AccountViewModel, - showImage: MutableState, automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { @@ -388,13 +366,12 @@ fun InnerChannelCardWithReactions( private fun RenderNoteRow( baseNote: Note, accountViewModel: AccountViewModel, - showImage: MutableState, automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { when (remember { baseNote.event }) { is LiveActivitiesEvent -> { - RenderLiveActivityThumb(baseNote, accountViewModel, showImage, automaticallyStartPlayback, nav) + RenderLiveActivityThumb(baseNote, accountViewModel, automaticallyStartPlayback, nav) } is CommunityDefinitionEvent -> { RenderCommunitiesThumb(baseNote, accountViewModel, nav) @@ -409,7 +386,6 @@ private fun RenderNoteRow( fun RenderLiveActivityThumb( baseNote: Note, accountViewModel: AccountViewModel, - showImage: MutableState, automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { @@ -549,7 +525,6 @@ fun RenderLiveActivityThumb( Modifier.padding(start = 0.dp, end = 0.dp, top = 5.dp, bottom = 5.dp) }, accountViewModel = accountViewModel, - showImage = showImage, automaticallyStartPlayback = automaticallyStartPlayback, nav = nav ) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt index d7ee35a64..830aee1a3 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt @@ -464,7 +464,6 @@ fun NormalNote( showVideo = !makeItShort, showBottomDiviser = true, accountViewModel = accountViewModel, - showImage = showImage, automaticallyStartPlayback = automaticallyStartPlayback, nav = nav ) @@ -948,7 +947,6 @@ fun InnerNoteWithReactions( showSecondRow = showSecondRow, backgroundColor = backgroundColor, accountViewModel = accountViewModel, - showImage = showImage, automaticallyStartPlayback = automaticallyStartPlayback, nav = nav ) @@ -995,7 +993,6 @@ private fun NoteBody( showSecondRow: Boolean, backgroundColor: MutableState, accountViewModel: AccountViewModel, - showImage: MutableState, automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { @@ -1022,7 +1019,6 @@ private fun NoteBody( unPackReply, backgroundColor, accountViewModel, - showImage, automaticallyStartPlayback, nav ) @@ -1034,7 +1030,6 @@ private fun NoteBody( makeItShort, canPreview, accountViewModel, - showImage, nav ) } @@ -1046,12 +1041,11 @@ private fun RenderNoteRow( makeItShort: Boolean, canPreview: Boolean, accountViewModel: AccountViewModel, - showImage: MutableState, nav: (String) -> Unit ) { when (baseNote.event) { is AppDefinitionEvent -> { - RenderAppDefinition(baseNote, accountViewModel, showImage, nav) + RenderAppDefinition(baseNote, accountViewModel, nav) } is ReactionEvent -> { @@ -1295,7 +1289,6 @@ fun RenderPoll( fun RenderAppDefinition( note: Note, accountViewModel: AccountViewModel, - showImage: MutableState, nav: (String) -> Unit ) { val noteEvent = note.event as? AppDefinitionEvent ?: return @@ -2125,7 +2118,6 @@ private fun ReplyRow( unPackReply: Boolean, backgroundColor: MutableState, accountViewModel: AccountViewModel, - showImage: MutableState, automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { @@ -2162,7 +2154,6 @@ private fun ReplyRow( showBottomDiviser = false, modifier = remember { Modifier.padding(vertical = 5.dp) }, accountViewModel = accountViewModel, - showImage = showImage, automaticallyStartPlayback = automaticallyStartPlayback, nav = nav ) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt index 73f46076a..12ed909bb 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt @@ -248,16 +248,6 @@ fun NoteMaster( val settings = accountState?.account?.settings val isMobile = ConnectivityStatus.isOnMobileData.value - val showImage = remember { - mutableStateOf( - when (settings?.automaticallyShowImages) { - true -> !isMobile - false -> false - else -> true - } - ) - } - val automaticallyStartPlayback = remember { mutableStateOf( when (settings?.automaticallyStartPlayback) { @@ -427,7 +417,6 @@ fun NoteMaster( showVideo = true, showBottomDiviser = false, accountViewModel = accountViewModel, - showImage = showImage, automaticallyStartPlayback = automaticallyStartPlayback, nav = nav ) @@ -463,7 +452,7 @@ fun NoteMaster( nav ) } else if (noteEvent is AppDefinitionEvent) { - RenderAppDefinition(baseNote, accountViewModel, showImage, nav) + RenderAppDefinition(baseNote, accountViewModel, nav) } else if (noteEvent is HighlightEvent) { DisplayHighlight( noteEvent.quote(), diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt index edea6280c..755db6458 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt @@ -204,16 +204,6 @@ fun ChannelScreen( val settings = accountState?.account?.settings val isMobile = ConnectivityStatus.isOnMobileData.value - val showImage = remember { - mutableStateOf( - when (settings?.automaticallyShowImages) { - true -> !isMobile - false -> false - else -> true - } - ) - } - val automaticallyStartPlayback = remember { mutableStateOf( when (settings?.automaticallyStartPlayback) { @@ -264,7 +254,6 @@ fun ChannelScreen( showVideo = true, showBottomDiviser = true, accountViewModel = accountViewModel, - showImage = showImage, automaticallyStartPlayback = automaticallyStartPlayback, nav = nav ) @@ -545,7 +534,6 @@ fun ChannelHeader( showBottomDiviser: Boolean, modifier: Modifier = StdPadding, accountViewModel: AccountViewModel, - showImage: MutableState, automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { @@ -560,7 +548,6 @@ fun ChannelHeader( showVideo = showVideo, showBottomDiviser = showBottomDiviser, accountViewModel = accountViewModel, - showImage = showImage, automaticallyStartPlayback = automaticallyStartPlayback, nav = nav ) @@ -575,7 +562,6 @@ fun ChannelHeader( showFlag: Boolean = true, modifier: Modifier = StdPadding, accountViewModel: AccountViewModel, - showImage: MutableState, automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { @@ -597,7 +583,6 @@ fun ChannelHeader( showFlag, modifier, accountViewModel, - showImage, automaticallyStartPlayback, nav ) @@ -612,7 +597,6 @@ fun ChannelHeader( showFlag: Boolean = true, modifier: Modifier = StdPadding, accountViewModel: AccountViewModel, - showImage: MutableState, automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { From f95023f59dd1b331c2316b212eb3932455105f69 Mon Sep 17 00:00:00 2001 From: greenart7c3 <115044884+greenart7c3@users.noreply.github.com> Date: Fri, 7 Jul 2023 18:39:27 -0300 Subject: [PATCH 22/29] replace imageBox with url link with download button --- .../ui/components/ZoomableContentView.kt | 40 +++++++++---------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt index e15e58e63..64bdaac8d 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt @@ -5,7 +5,6 @@ import android.os.Build import android.util.Log import android.widget.Toast import androidx.compose.foundation.ExperimentalFoundationApi -import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.layout.Arrangement @@ -25,7 +24,6 @@ import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.pager.PagerState import androidx.compose.foundation.pager.rememberPagerState -import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.InlineTextContent import androidx.compose.foundation.text.appendInlineContent import androidx.compose.material.Icon @@ -35,6 +33,7 @@ import androidx.compose.material.MaterialTheme import androidx.compose.material.Surface import androidx.compose.material.Text import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.DownloadForOffline import androidx.compose.material.icons.filled.Report import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect @@ -48,23 +47,19 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalClipboardManager import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalView import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.Placeholder import androidx.compose.ui.text.PlaceholderVerticalAlign -import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.withStyle import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.isFinite -import androidx.compose.ui.unit.sp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties import androidx.core.net.toUri @@ -338,21 +333,22 @@ private fun UrlImageView( } } +@OptIn(ExperimentalLayoutApi::class) @Composable -fun LoadImageBox(showImage: MutableState) { - Box( - modifier = Modifier - .height(300.dp) - .fillMaxWidth() - .clip(RoundedCornerShape(10.dp)) - .background(Color.LightGray) - .clickable { showImage.value = true }, - contentAlignment = Alignment.Center - ) { - Text( - text = stringResource(R.string.load_image), - style = TextStyle(color = Color.Black, fontSize = 18.sp) - ) +fun ImageUrlWithDownloadButton(url: String, showImage: MutableState) { + FlowRow() { + ClickableUrl(urlText = url, url = url) + IconButton( + modifier = Modifier.size(20.dp), + onClick = { showImage.value = true } + ) { + Icon( + imageVector = Icons.Default.DownloadForOffline, + null, + modifier = Modifier.size(24.dp), + tint = MaterialTheme.colors.primary + ) + } } } @@ -367,7 +363,7 @@ private fun AddedImageFeatures( showImage: MutableState ) { if (!showImage.value) { - LoadImageBox(showImage) + ImageUrlWithDownloadButton(content.uri, showImage) } else { when (painter.value) { null, is AsyncImagePainter.State.Loading -> { @@ -407,7 +403,7 @@ private fun AddedImageFeatures( showImage: MutableState ) { if (!showImage.value) { - LoadImageBox(showImage) + ImageUrlWithDownloadButton(content.url, showImage) } else { var verifiedHash by remember { mutableStateOf(null) From 6d4a887d002b92f9568ed6da13b466cbe8772052 Mon Sep 17 00:00:00 2001 From: greenart7c3 <115044884+greenart7c3@users.noreply.github.com> Date: Mon, 10 Jul 2023 08:01:16 -0300 Subject: [PATCH 23/29] use accountviewmodel as parameter instead of MutableState --- .../amethyst/ui/actions/NewMediaView.kt | 29 +++-- .../amethyst/ui/actions/NewPostView.kt | 14 ++- .../ui/components/ExpandableRichTextViewer.kt | 28 ----- .../amethyst/ui/components/RichTextViewer.kt | 19 +-- .../amethyst/ui/components/UrlPreview.kt | 18 ++- .../amethyst/ui/components/UrlPreviewCard.kt | 112 ++++++++++-------- .../amethyst/ui/components/VideoView.kt | 37 ++++-- .../ui/components/ZoomableContentView.kt | 21 ++-- .../amethyst/ui/note/ChannelCardCompose.kt | 31 +---- .../amethyst/ui/note/NoteCompose.kt | 68 ++--------- .../amethyst/ui/screen/ThreadFeedView.kt | 29 ----- .../ui/screen/loggedIn/ChannelScreen.kt | 24 +--- .../ui/screen/loggedIn/ProfileScreen.kt | 8 +- .../ui/screen/loggedIn/VideoScreen.kt | 32 +---- 14 files changed, 158 insertions(+), 312 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaView.kt index 11c20598b..ff3fa7e63 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaView.kt @@ -6,11 +6,22 @@ import android.os.Build import android.util.Size import android.widget.Toast import androidx.compose.foundation.Image -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.imePadding +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.verticalScroll -import androidx.compose.material.* +import androidx.compose.material.MaterialTheme +import androidx.compose.material.OutlinedTextField +import androidx.compose.material.Surface +import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -29,8 +40,7 @@ import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties import coil.compose.AsyncImage import com.vitorpamplona.amethyst.R -import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.ui.components.* +import com.vitorpamplona.amethyst.ui.components.VideoView import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.TextSpinner import com.vitorpamplona.amethyst.ui.theme.placeholderText @@ -107,7 +117,7 @@ fun NewMediaView(uri: Uri, onClose: () -> Unit, postViewModel: NewMediaModel, ac .fillMaxWidth() .verticalScroll(scroolState) ) { - ImageVideoPost(postViewModel, account) + ImageVideoPost(postViewModel, accountViewModel) } } } @@ -123,7 +133,7 @@ fun isNIP94Server(selectedServer: ServersAvailable?): Boolean { } @Composable -fun ImageVideoPost(postViewModel: NewMediaModel, acc: Account) { +fun ImageVideoPost(postViewModel: NewMediaModel, accountViewModel: AccountViewModel) { val fileServers = listOf( // Triple(ServersAvailable.IMGUR_NIP_94, stringResource(id = R.string.upload_server_imgur_nip94), stringResource(id = R.string.upload_server_imgur_nip94_explainer)), Triple(ServersAvailable.NOSTRIMG_NIP_94, stringResource(id = R.string.upload_server_nostrimg_nip94), stringResource(id = R.string.upload_server_nostrimg_nip94_explainer)), @@ -179,11 +189,8 @@ fun ImageVideoPost(postViewModel: NewMediaModel, acc: Account) { ) } } else { - val automaticallyStartPlayback = remember { - mutableStateOf(true) - } postViewModel.galleryUri?.let { - VideoView(it.toString(), automaticallyStartPlayback = automaticallyStartPlayback) + VideoView(it.toString(), accountViewModel = accountViewModel) } } } @@ -194,7 +201,7 @@ fun ImageVideoPost(postViewModel: NewMediaModel, acc: Account) { ) { TextSpinner( label = stringResource(id = R.string.file_server), - placeholder = fileServers.firstOrNull { it.first == acc.defaultFileServer }?.second ?: fileServers[0].second, + placeholder = fileServers.firstOrNull { it.first == accountViewModel.account.defaultFileServer }?.second ?: fileServers[0].second, options = fileServerOptions, explainers = fileServerExplainers, onSelect = { 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 f0011813b..97b7263e8 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 @@ -272,7 +272,8 @@ fun NewPostView(onClose: () -> Unit, baseReplyTo: Note? = null, quote: Note? = n scope.launch { postViewModel.imageUploadingError.emit(it) } - } + }, + accountViewModel = accountViewModel ) } } @@ -330,9 +331,9 @@ fun NewPostView(onClose: () -> Unit, baseReplyTo: Note? = null, quote: Note? = n ) ) } else if (videoExtensions.any { removedParamsFromUrl.endsWith(it) }) { - VideoView(myUrlPreview, automaticallyStartPlayback = remember { mutableStateOf(true) }) + VideoView(myUrlPreview, accountViewModel = accountViewModel) } else { - UrlPreview(myUrlPreview, myUrlPreview, remember { mutableStateOf(true) }) + UrlPreview(myUrlPreview, myUrlPreview, accountViewModel) } } else if (startsWithNIP19Scheme(myUrlPreview)) { val bgColor = MaterialTheme.colors.background @@ -348,7 +349,7 @@ fun NewPostView(onClose: () -> Unit, baseReplyTo: Note? = null, quote: Note? = n nav ) } else if (noProtocolUrlValidator.matcher(myUrlPreview).matches()) { - UrlPreview("https://$myUrlPreview", myUrlPreview, remember { mutableStateOf(true) }) + UrlPreview("https://$myUrlPreview", myUrlPreview, accountViewModel) } } } @@ -836,7 +837,8 @@ fun ImageVideoDescription( defaultServer: ServersAvailable, onAdd: (String, ServersAvailable, Boolean) -> Unit, onCancel: () -> Unit, - onError: (String) -> Unit + onError: (String) -> Unit, + accountViewModel: AccountViewModel ) { val resolver = LocalContext.current.contentResolver val mediaType = resolver.getType(uri) ?: "" @@ -966,7 +968,7 @@ fun ImageVideoDescription( ) } } else { - VideoView(uri.toString(), automaticallyStartPlayback = remember { mutableStateOf(true) }) + VideoView(uri.toString(), accountViewModel = accountViewModel) } } 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 93d67549c..1b715234a 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 @@ -15,7 +15,6 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue -import androidx.compose.runtime.livedata.observeAsState import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue @@ -25,7 +24,6 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.R -import com.vitorpamplona.amethyst.service.connectivitystatus.ConnectivityStatus import com.vitorpamplona.amethyst.ui.actions.ImmutableListOfLists import com.vitorpamplona.amethyst.ui.note.getGradient import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel @@ -44,30 +42,6 @@ fun ExpandableRichTextViewer( accountViewModel: AccountViewModel, nav: (String) -> Unit ) { - val accountState by accountViewModel.accountLiveData.observeAsState() - val settings = accountState?.account?.settings - val isMobile = ConnectivityStatus.isOnMobileData.value - - val automaticallyStartPlayback = remember { - mutableStateOf( - when (settings?.automaticallyStartPlayback) { - true -> !isMobile - false -> false - else -> true - } - ) - } - - val automaticallyShowUrlPreview = remember { - mutableStateOf( - when (settings?.automaticallyShowUrlPreview) { - true -> !isMobile - false -> false - else -> true - } - ) - } - var showFullText by remember { mutableStateOf(false) } val whereToCut = remember(content) { @@ -96,8 +70,6 @@ fun ExpandableRichTextViewer( tags, backgroundColor, accountViewModel, - 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 991829086..953bc2deb 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 @@ -108,15 +108,13 @@ fun RichTextViewer( tags: ImmutableListOfLists, backgroundColor: MutableState, accountViewModel: AccountViewModel, - 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, automaticallyStartPlayback, automaticallyShowUrlPreview, nav) + RenderRegular(content, tags, canPreview, backgroundColor, accountViewModel, nav) } } } @@ -129,8 +127,6 @@ private fun RenderRegular( canPreview: Boolean, backgroundColor: MutableState, accountViewModel: AccountViewModel, - automaticallyStartPlayback: MutableState, - automaticallyShowUrlPreview: MutableState, nav: (String) -> Unit ) { val state by remember(content) { @@ -160,8 +156,6 @@ private fun RenderRegular( backgroundColor, textStyle, accountViewModel, - automaticallyStartPlayback, - automaticallyShowUrlPreview, nav ) } @@ -241,13 +235,11 @@ private fun RenderWordWithPreview( backgroundColor: MutableState, style: TextStyle, accountViewModel: AccountViewModel, - automaticallyStartPlayback: MutableState, - automaticallyShowUrlPreview: MutableState, nav: (String) -> Unit ) { when (word) { - is ImageSegment -> ZoomableContentView(word.segmentText, state, accountViewModel, automaticallyStartPlayback) - is LinkSegment -> UrlPreview(word.segmentText, word.segmentText, automaticallyShowUrlPreview) + is ImageSegment -> ZoomableContentView(word.segmentText, state, accountViewModel) + is LinkSegment -> UrlPreview(word.segmentText, word.segmentText, accountViewModel) is EmojiSegment -> RenderCustomEmoji(word.segmentText, state) is InvoiceSegment -> MayBeInvoicePreview(word.segmentText) is WithdrawSegment -> MayBeWithdrawal(word.segmentText) @@ -267,11 +259,10 @@ private fun RenderWordWithPreview( private fun ZoomableContentView( word: String, state: RichTextViewerState, - accountViewModel: AccountViewModel, - automaticallyStartPlayback: MutableState + accountViewModel: AccountViewModel ) { state.imagesForPager[word]?.let { - ZoomableContentView(it, state.imageList, accountViewModel, automaticallyStartPlayback) + ZoomableContentView(it, state.imageList, accountViewModel) } } 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 6c9e5449a..85b09ef1b 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,18 +4,28 @@ 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 import androidx.compose.runtime.setValue import com.vitorpamplona.amethyst.model.UrlCachedPreviewer +import com.vitorpamplona.amethyst.service.connectivitystatus.ConnectivityStatus +import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @Composable -fun UrlPreview(url: String, urlText: String, automaticallyShowUrlPreview: MutableState) { - if (!automaticallyShowUrlPreview.value) { +fun UrlPreview(url: String, urlText: String, accountViewModel: AccountViewModel) { + val settings = accountViewModel.account.settings + val isMobile = ConnectivityStatus.isOnMobileData.value + + val automaticallyShowUrlPreview = when (settings.automaticallyShowUrlPreview) { + true -> !isMobile + false -> false + else -> true + } + + if (!automaticallyShowUrlPreview) { ClickableUrl(urlText, url) } else { var urlPreviewState by remember(url) { @@ -43,7 +53,7 @@ fun UrlPreview(url: String, urlText: String, automaticallyShowUrlPreview: Mutabl ) { state -> when (state) { is UrlPreviewState.Loaded -> { - UrlPreviewCard(url, state.previewInfo, automaticallyShowUrlPreview) + UrlPreviewCard(url, state.previewInfo, accountViewModel) } else -> { 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 13e78a92a..e2eb88ce7 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 @@ -20,7 +20,9 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import coil.compose.AsyncImage import com.vitorpamplona.amethyst.R +import com.vitorpamplona.amethyst.service.connectivitystatus.ConnectivityStatus import com.vitorpamplona.amethyst.service.previews.UrlInfoItem +import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.theme.QuoteBorder import com.vitorpamplona.amethyst.ui.theme.subtleBorder @@ -28,62 +30,72 @@ import com.vitorpamplona.amethyst.ui.theme.subtleBorder fun UrlPreviewCard( url: String, previewInfo: UrlInfoItem, - automaticallyShowUrlPreview: MutableState + accountViewModel: AccountViewModel ) { - if (!automaticallyShowUrlPreview.value) { - return ClickableUrl(url, url) + val settings = accountViewModel.account.settings + val isMobile = ConnectivityStatus.isOnMobileData.value + + val automaticallyShowUrlPreview = when (settings.automaticallyShowUrlPreview) { + true -> !isMobile + false -> false + else -> true } - val uri = LocalUriHandler.current - Row( - modifier = Modifier - .clickable { runCatching { uri.openUri(url) } } - .clip(shape = QuoteBorder) - .border( - 1.dp, - MaterialTheme.colors.subtleBorder, - QuoteBorder - ) - ) { - Column { - AsyncImage( - model = previewInfo.imageUrlFullPath, - contentDescription = stringResource(R.string.preview_card_image_for, previewInfo.url), - contentScale = ContentScale.FillWidth, - modifier = Modifier.fillMaxWidth() - ) + if (!automaticallyShowUrlPreview) { + ClickableUrl(url, url) + } else { + val uri = LocalUriHandler.current - Text( - text = previewInfo.verifiedUrl?.host ?: previewInfo.url, - style = MaterialTheme.typography.caption, - modifier = Modifier - .fillMaxWidth() - .padding(start = 10.dp, end = 10.dp, top = 10.dp), - color = Color.Gray, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) + Row( + modifier = Modifier + .clickable { runCatching { uri.openUri(url) } } + .clip(shape = QuoteBorder) + .border( + 1.dp, + MaterialTheme.colors.subtleBorder, + QuoteBorder + ) + ) { + Column { + AsyncImage( + model = previewInfo.imageUrlFullPath, + contentDescription = stringResource(R.string.preview_card_image_for, previewInfo.url), + contentScale = ContentScale.FillWidth, + modifier = Modifier.fillMaxWidth() + ) - Text( - text = previewInfo.title, - style = MaterialTheme.typography.body2, - modifier = Modifier - .fillMaxWidth() - .padding(start = 10.dp, end = 10.dp), - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) + Text( + text = previewInfo.verifiedUrl?.host ?: previewInfo.url, + style = MaterialTheme.typography.caption, + modifier = Modifier + .fillMaxWidth() + .padding(start = 10.dp, end = 10.dp, top = 10.dp), + color = Color.Gray, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) - Text( - text = previewInfo.description, - style = MaterialTheme.typography.caption, - modifier = Modifier - .fillMaxWidth() - .padding(start = 10.dp, end = 10.dp, bottom = 10.dp), - color = Color.Gray, - maxLines = 3, - overflow = TextOverflow.Ellipsis - ) + Text( + text = previewInfo.title, + style = MaterialTheme.typography.body2, + modifier = Modifier + .fillMaxWidth() + .padding(start = 10.dp, end = 10.dp), + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + + Text( + text = previewInfo.description, + style = MaterialTheme.typography.caption, + modifier = Modifier + .fillMaxWidth() + .padding(start = 10.dp, end = 10.dp, bottom = 10.dp), + color = Color.Gray, + maxLines = 3, + overflow = TextOverflow.Ellipsis + ) + } } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/VideoView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/VideoView.kt index ff20af82e..7fb068148 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/VideoView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/VideoView.kt @@ -61,6 +61,8 @@ import com.google.android.exoplayer2.ui.StyledPlayerView import com.google.android.exoplayer2.upstream.DataSource import com.vitorpamplona.amethyst.VideoCache import com.vitorpamplona.amethyst.service.HttpClient +import com.vitorpamplona.amethyst.service.connectivitystatus.ConnectivityStatus +import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlin.time.ExperimentalTime @@ -73,7 +75,7 @@ fun LoadThumbAndThenVideoView( videoUri: String, description: String? = null, thumbUri: String, - showVideo: MutableState, + accountViewModel: AccountViewModel, onDialog: ((Boolean) -> Unit)? = null ) { var loadingFinished by remember { mutableStateOf>(Pair(false, null)) } @@ -99,9 +101,9 @@ fun LoadThumbAndThenVideoView( if (loadingFinished.first) { if (loadingFinished.second != null) { - VideoView(videoUri, description, VideoThumb(loadingFinished.second), showVideo, onDialog) + VideoView(videoUri, description, VideoThumb(loadingFinished.second), accountViewModel, onDialog) } else { - VideoView(videoUri, description, null, showVideo, onDialog) + VideoView(videoUri, description, null, accountViewModel, onDialog) } } } @@ -112,11 +114,11 @@ fun VideoView( videoUri: String, description: String? = null, thumb: VideoThumb? = null, - automaticallyStartPlayback: MutableState, + accountViewModel: AccountViewModel, onDialog: ((Boolean) -> Unit)? = null ) { val (value, elapsed) = measureTimedValue { - VideoView1(videoUri, description, thumb, onDialog, automaticallyStartPlayback) + VideoView1(videoUri, description, thumb, onDialog, accountViewModel) } Log.d("Rendering Metrics", "VideoView $elapsed $videoUri") } @@ -127,7 +129,7 @@ fun VideoView1( description: String? = null, thumb: VideoThumb? = null, onDialog: ((Boolean) -> Unit)? = null, - automaticallyStartPlayback: MutableState + accountViewModel: AccountViewModel ) { var exoPlayerData by remember { mutableStateOf(null) } val defaultToStart by remember { mutableStateOf(DefaultMutedSetting.value) } @@ -142,7 +144,7 @@ fun VideoView1( } exoPlayerData?.let { - VideoView(videoUri, description, it, defaultToStart, thumb, onDialog, automaticallyStartPlayback = automaticallyStartPlayback) + VideoView(videoUri, description, it, defaultToStart, thumb, onDialog, accountViewModel) } DisposableEffect(Unit) { @@ -161,10 +163,10 @@ fun VideoView( defaultToStart: Boolean = false, thumb: VideoThumb? = null, onDialog: ((Boolean) -> Unit)? = null, - automaticallyStartPlayback: MutableState + accountViewModel: AccountViewModel ) { - val (value, elapsed) = measureTimedValue { - VideoView1(videoUri, description, exoPlayerData, defaultToStart, thumb, onDialog, automaticallyStartPlayback) + val (_, elapsed) = measureTimedValue { + VideoView1(videoUri, description, exoPlayerData, defaultToStart, thumb, onDialog, accountViewModel) } Log.d("Rendering Metrics", "VideoView $elapsed $videoUri") } @@ -177,12 +179,25 @@ fun VideoView1( defaultToStart: Boolean = false, thumb: VideoThumb? = null, onDialog: ((Boolean) -> Unit)? = null, - automaticallyStartPlayback: MutableState + accountViewModel: AccountViewModel ) { val lifecycleOwner = rememberUpdatedState(LocalLifecycleOwner.current) val media = remember { MediaItem.Builder().setUri(videoUri).build() } + val settings = accountViewModel.account.settings + val isMobile = ConnectivityStatus.isOnMobileData.value + + val automaticallyStartPlayback = remember { + mutableStateOf( + when (settings.automaticallyStartPlayback) { + true -> !isMobile + false -> false + else -> true + } + ) + } + exoPlayerData.exoPlayer.apply { repeatMode = Player.REPEAT_MODE_ALL videoScalingMode = C.VIDEO_SCALING_MODE_SCALE_TO_FIT diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt index 64bdaac8d..21affa985 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt @@ -172,8 +172,7 @@ fun figureOutMimeType(fullUrl: String): ZoomableContent { fun ZoomableContentView( content: ZoomableContent, images: ImmutableList = listOf(content).toImmutableList(), - accountViewModel: AccountViewModel, - automaticallyStartPlayback: MutableState + accountViewModel: AccountViewModel ) { val clipboardManager = LocalClipboardManager.current @@ -202,16 +201,16 @@ fun ZoomableContentView( when (content) { is ZoomableUrlImage -> UrlImageView(content, mainImageModifier, accountViewModel) - is ZoomableUrlVideo -> VideoView(content.url, content.description, automaticallyStartPlayback = automaticallyStartPlayback) { dialogOpen = true } + is ZoomableUrlVideo -> VideoView(content.url, content.description, accountViewModel = accountViewModel) { dialogOpen = true } is ZoomableLocalImage -> LocalImageView(content, mainImageModifier, accountViewModel) is ZoomableLocalVideo -> content.localFile?.let { - VideoView(it.toUri().toString(), content.description, automaticallyStartPlayback = automaticallyStartPlayback) { dialogOpen = true } + VideoView(it.toUri().toString(), content.description, accountViewModel = accountViewModel) { dialogOpen = true } } } if (dialogOpen) { - ZoomableImageDialog(content, images, onDismiss = { dialogOpen = false }) + ZoomableImageDialog(content, images, onDismiss = { dialogOpen = false }, accountViewModel) } } @@ -541,7 +540,7 @@ private fun DisplayBlurHash( @OptIn(ExperimentalFoundationApi::class) @Composable -fun ZoomableImageDialog(imageUrl: ZoomableContent, allImages: ImmutableList = listOf(imageUrl).toImmutableList(), onDismiss: () -> Unit) { +fun ZoomableImageDialog(imageUrl: ZoomableContent, allImages: ImmutableList = listOf(imageUrl).toImmutableList(), onDismiss: () -> Unit, accountViewModel: AccountViewModel) { val view = LocalView.current DisposableEffect(key1 = Unit) { @@ -583,11 +582,11 @@ fun ZoomableImageDialog(imageUrl: ZoomableContent, allImages: ImmutableList - RenderImageOrVideo(allImages[index], null, remember { mutableStateOf(true) }) + RenderImageOrVideo(allImages[index], accountViewModel) } ) } else { - RenderImageOrVideo(imageUrl, null, remember { mutableStateOf(true) }) + RenderImageOrVideo(imageUrl, accountViewModel) } Row( @@ -612,7 +611,7 @@ fun ZoomableImageDialog(imageUrl: ZoomableContent, allImages: ImmutableList) { +fun RenderImageOrVideo(content: ZoomableContent, accountViewModel: AccountViewModel) { val mainModifier = Modifier .fillMaxSize() .zoomable(rememberZoomState()) @@ -621,14 +620,14 @@ fun RenderImageOrVideo(content: ZoomableContent, accountViewModel: AccountViewMo UrlImageView(content = content, mainImageModifier = mainModifier, accountViewModel) } else if (content is ZoomableUrlVideo) { Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxSize(1f)) { - VideoView(content.url, content.description, automaticallyStartPlayback = automaticallyStartPlayback) + VideoView(content.url, content.description, accountViewModel = accountViewModel) } } else if (content is ZoomableLocalImage) { LocalImageView(content = content, mainImageModifier = mainModifier, accountViewModel) } else if (content is ZoomableLocalVideo) { Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxSize(1f)) { content.localFile?.let { - VideoView(it.toUri().toString(), content.description, automaticallyStartPlayback = automaticallyStartPlayback) + VideoView(it.toUri().toString(), content.description, accountViewModel = accountViewModel) } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChannelCardCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChannelCardCompose.kt index 2d2836a60..60343f94c 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChannelCardCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChannelCardCompose.kt @@ -94,20 +94,6 @@ fun ChannelCardCompose( it.note.event == null }.distinctUntilChanged().observeAsState(baseNote.event == null) - val accountState by accountViewModel.accountLiveData.observeAsState() - val settings = accountState?.account?.settings - val isMobile = ConnectivityStatus.isOnMobileData.value - - val automaticallyStartPlayback = remember { - mutableStateOf( - when (settings?.automaticallyStartPlayback) { - true -> !isMobile - false -> false - else -> true - } - ) - } - Crossfade(targetState = isBlank) { if (it) { LongPressToQuickAction(baseNote = baseNote, accountViewModel = accountViewModel) { showPopup -> @@ -128,7 +114,6 @@ fun ChannelCardCompose( modifier, parentBackgroundColor, accountViewModel, - automaticallyStartPlayback, nav ) } @@ -142,7 +127,6 @@ fun CheckHiddenChannelCardCompose( modifier: Modifier = Modifier, parentBackgroundColor: MutableState? = null, accountViewModel: AccountViewModel, - automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { val isHidden by accountViewModel.accountLiveData.map { @@ -157,7 +141,6 @@ fun CheckHiddenChannelCardCompose( modifier, parentBackgroundColor, accountViewModel, - automaticallyStartPlayback, nav ) } @@ -171,7 +154,6 @@ fun LoadedChannelCardCompose( modifier: Modifier = Modifier, parentBackgroundColor: MutableState? = null, accountViewModel: AccountViewModel, - automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { var state by remember { @@ -203,7 +185,6 @@ fun LoadedChannelCardCompose( modifier, parentBackgroundColor, accountViewModel, - automaticallyStartPlayback, nav ) } @@ -217,7 +198,6 @@ fun RenderChannelCardReportState( modifier: Modifier = Modifier, parentBackgroundColor: MutableState? = null, accountViewModel: AccountViewModel, - automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { var showReportedNote by remember { mutableStateOf(false) } @@ -239,7 +219,6 @@ fun RenderChannelCardReportState( modifier, parentBackgroundColor, accountViewModel, - automaticallyStartPlayback, nav ) } @@ -253,7 +232,6 @@ fun NormalChannelCard( modifier: Modifier = Modifier, parentBackgroundColor: MutableState? = null, accountViewModel: AccountViewModel, - automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { LongPressToQuickAction(baseNote = baseNote, accountViewModel = accountViewModel) { showPopup -> @@ -263,7 +241,6 @@ fun NormalChannelCard( modifier, parentBackgroundColor, accountViewModel, - automaticallyStartPlayback, showPopup, nav ) @@ -277,7 +254,6 @@ private fun CheckNewAndRenderChannelCard( modifier: Modifier = Modifier, parentBackgroundColor: MutableState? = null, accountViewModel: AccountViewModel, - automaticallyStartPlayback: MutableState, showPopup: () -> Unit, nav: (String) -> Unit ) { @@ -335,7 +311,6 @@ private fun CheckNewAndRenderChannelCard( InnerChannelCardWithReactions( baseNote = baseNote, accountViewModel = accountViewModel, - automaticallyStartPlayback, nav = nav ) } @@ -345,7 +320,6 @@ private fun CheckNewAndRenderChannelCard( fun InnerChannelCardWithReactions( baseNote: Note, accountViewModel: AccountViewModel, - automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { Column(StdPadding) { @@ -366,12 +340,11 @@ fun InnerChannelCardWithReactions( private fun RenderNoteRow( baseNote: Note, accountViewModel: AccountViewModel, - automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { when (remember { baseNote.event }) { is LiveActivitiesEvent -> { - RenderLiveActivityThumb(baseNote, accountViewModel, automaticallyStartPlayback, nav) + RenderLiveActivityThumb(baseNote, accountViewModel, nav) } is CommunityDefinitionEvent -> { RenderCommunitiesThumb(baseNote, accountViewModel, nav) @@ -386,7 +359,6 @@ private fun RenderNoteRow( fun RenderLiveActivityThumb( baseNote: Note, accountViewModel: AccountViewModel, - automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { val noteEvent = baseNote.event as? LiveActivitiesEvent ?: return @@ -525,7 +497,6 @@ fun RenderLiveActivityThumb( Modifier.padding(start = 0.dp, end = 0.dp, top = 5.dp, bottom = 5.dp) }, accountViewModel = accountViewModel, - automaticallyStartPlayback = automaticallyStartPlayback, nav = nav ) } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt index 830aee1a3..78a2de461 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt @@ -211,30 +211,6 @@ fun NoteCompose( it.note.event == null }.distinctUntilChanged().observeAsState(baseNote.event == null) - 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 - } - ) - } - - val automaticallyStartPlayback = remember { - mutableStateOf( - when (settings?.automaticallyStartPlayback) { - true -> !isMobile - false -> false - else -> true - } - ) - } - Crossfade(targetState = isBlank) { if (it) { LongPressToQuickAction(baseNote = baseNote, accountViewModel = accountViewModel) { showPopup -> @@ -260,8 +236,6 @@ fun NoteCompose( addMarginTop, parentBackgroundColor, accountViewModel, - showImage, - automaticallyStartPlayback, nav ) } @@ -280,8 +254,6 @@ fun CheckHiddenNoteCompose( addMarginTop: Boolean = true, parentBackgroundColor: MutableState? = null, accountViewModel: AccountViewModel, - showImage: MutableState, - automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { val isHidden by accountViewModel.accountLiveData.map { @@ -301,8 +273,6 @@ fun CheckHiddenNoteCompose( addMarginTop, parentBackgroundColor, accountViewModel, - showImage, - automaticallyStartPlayback, nav ) } @@ -328,8 +298,6 @@ fun LoadedNoteCompose( addMarginTop: Boolean = true, parentBackgroundColor: MutableState? = null, accountViewModel: AccountViewModel, - showImage: MutableState, - automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { var state by remember { @@ -366,8 +334,6 @@ fun LoadedNoteCompose( addMarginTop, parentBackgroundColor, accountViewModel, - showImage, - automaticallyStartPlayback, nav ) } @@ -386,8 +352,6 @@ fun RenderReportState( addMarginTop: Boolean = true, parentBackgroundColor: MutableState? = null, accountViewModel: AccountViewModel, - showImage: MutableState, - automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { var showReportedNote by remember { mutableStateOf(false) } @@ -417,8 +381,6 @@ fun RenderReportState( canPreview, parentBackgroundColor, accountViewModel, - showImage, - automaticallyStartPlayback, nav ) } @@ -454,8 +416,6 @@ fun NormalNote( canPreview: Boolean = true, parentBackgroundColor: MutableState? = null, accountViewModel: AccountViewModel, - showImage: MutableState, - automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { when (baseNote.event) { @@ -464,7 +424,6 @@ fun NormalNote( showVideo = !makeItShort, showBottomDiviser = true, accountViewModel = accountViewModel, - automaticallyStartPlayback = automaticallyStartPlayback, nav = nav ) is CommunityDefinitionEvent -> CommunityHeader( @@ -490,8 +449,6 @@ fun NormalNote( canPreview, parentBackgroundColor, accountViewModel, - showImage, - automaticallyStartPlayback, showPopup, nav ) @@ -789,8 +746,6 @@ private fun CheckNewAndRenderNote( canPreview: Boolean = true, parentBackgroundColor: MutableState? = null, accountViewModel: AccountViewModel, - showImage: MutableState, - automaticallyStartPlayback: MutableState, showPopup: () -> Unit, nav: (String) -> Unit ) { @@ -855,8 +810,6 @@ private fun CheckNewAndRenderNote( makeItShort = makeItShort, canPreview = canPreview, accountViewModel = accountViewModel, - showImage = showImage, - automaticallyStartPlayback = automaticallyStartPlayback, nav = nav ) } @@ -907,8 +860,6 @@ fun InnerNoteWithReactions( makeItShort: Boolean, canPreview: Boolean, accountViewModel: AccountViewModel, - showImage: MutableState, - automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { val notBoostedNorQuote = !isBoostedNote && !isQuotedNote @@ -947,7 +898,6 @@ fun InnerNoteWithReactions( showSecondRow = showSecondRow, backgroundColor = backgroundColor, accountViewModel = accountViewModel, - automaticallyStartPlayback = automaticallyStartPlayback, nav = nav ) } @@ -993,7 +943,6 @@ private fun NoteBody( showSecondRow: Boolean, backgroundColor: MutableState, accountViewModel: AccountViewModel, - automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { FirstUserInfoRow( @@ -1019,7 +968,6 @@ private fun NoteBody( unPackReply, backgroundColor, accountViewModel, - automaticallyStartPlayback, nav ) } @@ -1327,7 +1275,7 @@ fun RenderAppDefinition( ) if (zoomImageDialogOpen) { - ZoomableImageDialog(imageUrl = figureOutMimeType(it.banner!!), onDismiss = { zoomImageDialogOpen = false }) + ZoomableImageDialog(imageUrl = figureOutMimeType(it.banner!!), onDismiss = { zoomImageDialogOpen = false }, accountViewModel = accountViewModel) } } else { Image( @@ -1378,7 +1326,7 @@ fun RenderAppDefinition( } if (zoomImageDialogOpen) { - ZoomableImageDialog(imageUrl = figureOutMimeType(it.banner!!), onDismiss = { zoomImageDialogOpen = false }) + ZoomableImageDialog(imageUrl = figureOutMimeType(it.banner!!), onDismiss = { zoomImageDialogOpen = false }, accountViewModel = accountViewModel) } Spacer(Modifier.weight(1f)) @@ -2118,7 +2066,6 @@ private fun ReplyRow( unPackReply: Boolean, backgroundColor: MutableState, accountViewModel: AccountViewModel, - automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { val noteEvent = note.event @@ -2154,7 +2101,6 @@ private fun ReplyRow( showBottomDiviser = false, modifier = remember { Modifier.padding(vertical = 5.dp) }, accountViewModel = accountViewModel, - automaticallyStartPlayback = automaticallyStartPlayback, nav = nav ) @@ -2942,7 +2888,7 @@ fun FileHeaderDisplay(note: Note, accountViewModel: AccountViewModel) { Crossfade(targetState = content) { if (it != null) { SensitivityWarning(note = note, accountViewModel = accountViewModel) { - ZoomableContentView(content = it) + ZoomableContentView(content = it, accountViewModel = accountViewModel) } } } @@ -3028,7 +2974,7 @@ private fun RenderNIP95( Crossfade(targetState = content) { if (it != null) { SensitivityWarning(note = header, accountViewModel = accountViewModel) { - ZoomableContentView(content = it) + ZoomableContentView(content = it, accountViewModel = accountViewModel) } } } @@ -3099,13 +3045,13 @@ fun AudioTrackHeader(noteEvent: AudioTrackEvent, accountViewModel: AccountViewMo videoUri = media, description = noteEvent.subject(), thumbUri = cover, - showVideo = remember { mutableStateOf(true) } + accountViewModel = accountViewModel ) } ?: VideoView( videoUri = media, description = noteEvent.subject(), - automaticallyStartPlayback = remember { mutableStateOf(true) } + accountViewModel = accountViewModel ) } } @@ -3230,7 +3176,7 @@ fun RenderLiveActivityEventInner(baseNote: Note, accountViewModel: AccountViewMo VideoView( videoUri = media, description = subject, - automaticallyStartPlayback = remember { mutableStateOf(true) } + accountViewModel = accountViewModel ) } } else { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt index 12ed909bb..b9c48d578 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt @@ -23,7 +23,6 @@ import androidx.compose.material.Icon import androidx.compose.material.IconButton import androidx.compose.material.MaterialTheme import androidx.compose.material.ProvideTextStyle -import androidx.compose.material.SnackbarDefaults.backgroundColor import androidx.compose.material.Text import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.MoreVert @@ -55,7 +54,6 @@ import androidx.compose.ui.unit.sp import coil.compose.AsyncImage import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.Note -import com.vitorpamplona.amethyst.service.connectivitystatus.ConnectivityStatus import com.vitorpamplona.amethyst.service.model.AppDefinitionEvent import com.vitorpamplona.amethyst.service.model.AudioTrackEvent import com.vitorpamplona.amethyst.service.model.BadgeDefinitionEvent @@ -75,19 +73,6 @@ import com.vitorpamplona.amethyst.service.model.RelaySetEvent import com.vitorpamplona.amethyst.service.model.RepostEvent import com.vitorpamplona.amethyst.ui.components.ObserveDisplayNip05Status import com.vitorpamplona.amethyst.ui.note.* -import com.vitorpamplona.amethyst.ui.note.BadgeDisplay -import com.vitorpamplona.amethyst.ui.note.BlankNote -import com.vitorpamplona.amethyst.ui.note.DisplayFollowingHashtagsInPost -import com.vitorpamplona.amethyst.ui.note.DisplayPoW -import com.vitorpamplona.amethyst.ui.note.DisplayReward -import com.vitorpamplona.amethyst.ui.note.HiddenNote -import com.vitorpamplona.amethyst.ui.note.NoteAuthorPicture -import com.vitorpamplona.amethyst.ui.note.NoteCompose -import com.vitorpamplona.amethyst.ui.note.NoteDropDownMenu -import com.vitorpamplona.amethyst.ui.note.NoteQuickActionMenu -import com.vitorpamplona.amethyst.ui.note.NoteUsernameDisplay -import com.vitorpamplona.amethyst.ui.note.ReactionsRow -import com.vitorpamplona.amethyst.ui.note.timeAgo import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.ChannelHeader import com.vitorpamplona.amethyst.ui.theme.lessImportantLink @@ -245,19 +230,6 @@ fun NoteMaster( val accountState by accountViewModel.accountLiveData.observeAsState() val account = accountState?.account ?: return - val settings = accountState?.account?.settings - val isMobile = ConnectivityStatus.isOnMobileData.value - - val automaticallyStartPlayback = remember { - mutableStateOf( - when (settings?.automaticallyStartPlayback) { - true -> !isMobile - false -> false - else -> true - } - ) - } - var showHiddenNote by remember { mutableStateOf(false) } val context = LocalContext.current @@ -417,7 +389,6 @@ fun NoteMaster( showVideo = true, showBottomDiviser = false, accountViewModel = accountViewModel, - automaticallyStartPlayback = automaticallyStartPlayback, nav = nav ) } else if (noteEvent is FileHeaderEvent) { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt index 755db6458..a3f1dcef3 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt @@ -87,7 +87,6 @@ import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.PublicChatChannel import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.service.NostrChannelDataSource -import com.vitorpamplona.amethyst.service.connectivitystatus.ConnectivityStatus import com.vitorpamplona.amethyst.service.model.LiveActivitiesEvent.Companion.STATUS_LIVE import com.vitorpamplona.amethyst.service.model.Participant import com.vitorpamplona.amethyst.ui.actions.ImmutableListOfLists @@ -200,20 +199,6 @@ fun ChannelScreen( val lifeCycleOwner = LocalLifecycleOwner.current - val accountState by accountViewModel.accountLiveData.observeAsState() - val settings = accountState?.account?.settings - val isMobile = ConnectivityStatus.isOnMobileData.value - - val automaticallyStartPlayback = remember { - mutableStateOf( - when (settings?.automaticallyStartPlayback) { - true -> !isMobile - false -> false - else -> true - } - ) - } - LaunchedEffect(Unit) { NostrChannelDataSource.start() feedViewModel.invalidateData() @@ -254,7 +239,6 @@ fun ChannelScreen( showVideo = true, showBottomDiviser = true, accountViewModel = accountViewModel, - automaticallyStartPlayback = automaticallyStartPlayback, nav = nav ) @@ -534,7 +518,6 @@ fun ChannelHeader( showBottomDiviser: Boolean, modifier: Modifier = StdPadding, accountViewModel: AccountViewModel, - automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { val channelHex by remember { @@ -548,7 +531,6 @@ fun ChannelHeader( showVideo = showVideo, showBottomDiviser = showBottomDiviser, accountViewModel = accountViewModel, - automaticallyStartPlayback = automaticallyStartPlayback, nav = nav ) } @@ -562,7 +544,6 @@ fun ChannelHeader( showFlag: Boolean = true, modifier: Modifier = StdPadding, accountViewModel: AccountViewModel, - automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { var baseChannel by remember { mutableStateOf(LocalCache.channels[channelHex]) } @@ -583,7 +564,6 @@ fun ChannelHeader( showFlag, modifier, accountViewModel, - automaticallyStartPlayback, nav ) } @@ -597,7 +577,6 @@ fun ChannelHeader( showFlag: Boolean = true, modifier: Modifier = StdPadding, accountViewModel: AccountViewModel, - automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { Column(Modifier.fillMaxWidth()) { @@ -653,7 +632,8 @@ private fun ShowVideoStreaming( } ZoomableContentView( - content = zoomableUrlVideo + content = zoomableUrlVideo, + accountViewModel = accountViewModel ) } } 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 0a9778caa..3a86967f3 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 @@ -599,7 +599,7 @@ private fun ProfileHeader( var zoomImageDialogOpen by remember { mutableStateOf(false) } Box { - DrawBanner(baseUser) + DrawBanner(baseUser, accountViewModel) Box( modifier = Modifier @@ -688,7 +688,7 @@ private fun ProfileHeader( val profilePic = baseUser.profilePicture() if (zoomImageDialogOpen && profilePic != null) { - ZoomableImageDialog(figureOutMimeType(profilePic), onDismiss = { zoomImageDialogOpen = false }) + ZoomableImageDialog(figureOutMimeType(profilePic), onDismiss = { zoomImageDialogOpen = false }, accountViewModel = accountViewModel) } } @@ -1260,7 +1260,7 @@ private fun WatchAndRenderBadgeImage( @OptIn(ExperimentalFoundationApi::class) @Composable -fun DrawBanner(baseUser: User) { +fun DrawBanner(baseUser: User, accountViewModel: AccountViewModel) { val userState by baseUser.live().metadata.observeAsState() val banner = remember(userState) { userState?.user?.info?.banner } @@ -1284,7 +1284,7 @@ fun DrawBanner(baseUser: User) { ) if (zoomImageDialogOpen) { - ZoomableImageDialog(imageUrl = figureOutMimeType(banner), onDismiss = { zoomImageDialogOpen = false }) + ZoomableImageDialog(imageUrl = figureOutMimeType(banner), onDismiss = { zoomImageDialogOpen = false }, accountViewModel = accountViewModel) } } else { Image( diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/VideoScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/VideoScreen.kt index caadbdb2f..a734b065f 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/VideoScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/VideoScreen.kt @@ -62,7 +62,6 @@ import com.google.accompanist.permissions.rememberPermissionState import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.service.NostrVideoDataSource -import com.vitorpamplona.amethyst.service.connectivitystatus.ConnectivityStatus import com.vitorpamplona.amethyst.service.model.FileHeaderEvent import com.vitorpamplona.amethyst.service.model.FileStorageHeaderEvent import com.vitorpamplona.amethyst.ui.actions.GallerySelect @@ -193,29 +192,6 @@ fun RenderPage( nav: (String) -> Unit ) { val feedState by videoFeedView.feedContent.collectAsState() - 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 - } - ) - } - - val automaticallyStartPlayback = remember { - mutableStateOf( - when (settings?.automaticallyStartPlayback) { - true -> !isMobile - false -> false - else -> true - } - ) - } Box() { Column { @@ -237,8 +213,6 @@ fun RenderPage( state.feed, pagerState, accountViewModel, - showImage, - automaticallyStartPlayback, nav ) } @@ -258,8 +232,6 @@ fun SlidingCarousel( feed: MutableState>, pagerState: PagerState, accountViewModel: AccountViewModel, - showImage: MutableState, - automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { VerticalPager( @@ -272,7 +244,7 @@ fun SlidingCarousel( } ) { index -> feed.value.getOrNull(index)?.let { note -> - RenderVideoOrPictureNote(note, accountViewModel, showImage, automaticallyStartPlayback, nav) + RenderVideoOrPictureNote(note, accountViewModel, nav) } } } @@ -281,8 +253,6 @@ fun SlidingCarousel( private fun RenderVideoOrPictureNote( note: Note, accountViewModel: AccountViewModel, - showImage: MutableState, - automaticallyStartPlayback: MutableState, nav: (String) -> Unit ) { Column(remember { Modifier.fillMaxSize(1f) }) { From 245bd4a44d5617929cd7305d1c8f0f978634c462 Mon Sep 17 00:00:00 2001 From: greenart7c3 <115044884+greenart7c3@users.noreply.github.com> Date: Mon, 10 Jul 2023 08:13:22 -0300 Subject: [PATCH 24/29] fix lint --- .../com/vitorpamplona/amethyst/ui/components/UrlPreviewCard.kt | 1 - .../com/vitorpamplona/amethyst/ui/note/ChannelCardCompose.kt | 1 - .../main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt | 1 - 3 files changed, 3 deletions(-) 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 e2eb88ce7..47b8da1cb 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,7 +9,6 @@ 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 diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChannelCardCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChannelCardCompose.kt index 60343f94c..89c2ecaaf 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChannelCardCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChannelCardCompose.kt @@ -50,7 +50,6 @@ import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.ParticipantListBuilder import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.service.OnlineChecker -import com.vitorpamplona.amethyst.service.connectivitystatus.ConnectivityStatus import com.vitorpamplona.amethyst.service.model.ChannelCreateEvent import com.vitorpamplona.amethyst.service.model.CommunityDefinitionEvent import com.vitorpamplona.amethyst.service.model.LiveActivitiesEvent diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt index 78a2de461..9e9595322 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt @@ -85,7 +85,6 @@ import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.model.UserMetadata import com.vitorpamplona.amethyst.service.OnlineChecker -import com.vitorpamplona.amethyst.service.connectivitystatus.ConnectivityStatus import com.vitorpamplona.amethyst.service.model.ATag import com.vitorpamplona.amethyst.service.model.AppDefinitionEvent import com.vitorpamplona.amethyst.service.model.AudioTrackEvent From b31d2d49d6a88bac235088227c12046145287b1c Mon Sep 17 00:00:00 2001 From: greenart7c3 <115044884+greenart7c3@users.noreply.github.com> Date: Mon, 10 Jul 2023 09:46:25 -0300 Subject: [PATCH 25/29] do not load preview of long form text if automaticallyShowUrlPreview is false --- .../amethyst/ui/note/NoteCompose.kt | 33 ++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt index 9e9595322..6de5da295 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt @@ -85,6 +85,7 @@ import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.model.UserMetadata import com.vitorpamplona.amethyst.service.OnlineChecker +import com.vitorpamplona.amethyst.service.connectivitystatus.ConnectivityStatus import com.vitorpamplona.amethyst.service.model.ATag import com.vitorpamplona.amethyst.service.model.AppDefinitionEvent import com.vitorpamplona.amethyst.service.model.AudioTrackEvent @@ -3225,17 +3226,27 @@ private fun LongFormHeader(noteEvent: LongTextNoteEvent, note: Note, accountView ) ) { Column { - image?.let { - AsyncImage( - model = it, - contentDescription = stringResource( - R.string.preview_card_image_for, - it - ), - contentScale = ContentScale.FillWidth, - modifier = Modifier.fillMaxWidth() - ) - } ?: CreateImageHeader(note, accountViewModel) + val settings = accountViewModel.account.settings + val isMobile = ConnectivityStatus.isOnMobileData.value + + val automaticallyShowUrlPreview = when (settings.automaticallyShowUrlPreview) { + true -> !isMobile + false -> false + else -> true + } + if (automaticallyShowUrlPreview) { + image?.let { + AsyncImage( + model = it, + contentDescription = stringResource( + R.string.preview_card_image_for, + it + ), + contentScale = ContentScale.FillWidth, + modifier = Modifier.fillMaxWidth() + ) + } ?: CreateImageHeader(note, accountViewModel) + } title?.let { Text( From 492b9494ec3af9c7ec1579a35cdb6d6dfcfcd187 Mon Sep 17 00:00:00 2001 From: greenart7c3 <115044884+greenart7c3@users.noreply.github.com> Date: Mon, 10 Jul 2023 15:07:12 -0300 Subject: [PATCH 26/29] fix theme not changing after changing language --- .../com/vitorpamplona/amethyst/ui/MainActivity.kt | 4 ++-- .../amethyst/ui/navigation/AppNavigation.kt | 4 +++- .../amethyst/ui/screen/AccountScreen.kt | 8 ++++---- .../ui/screen/loggedIn/AccountViewModel.kt | 15 +++------------ .../amethyst/ui/screen/loggedIn/MainScreen.kt | 9 ++++++++- .../amethyst/ui/screen/loggedIn/SettingsScreen.kt | 7 ++++--- 6 files changed, 24 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt index 5af93a12e..abeb8dd52 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt @@ -53,13 +53,13 @@ class MainActivity : AppCompatActivity() { val startingPage = uriToRoute(uri) LocalPreferences.migrateSingleUserPrefs() - val themeViewModel = ThemeViewModel() - themeViewModel.onChange(LocalPreferences.getTheme()) val language = LocalPreferences.getPreferredLanguage() if (language.isNotBlank()) { val appLocale: LocaleListCompat = LocaleListCompat.forLanguageTags(language) AppCompatDelegate.setApplicationLocales(appLocale) } + val themeViewModel = ThemeViewModel() + themeViewModel.onChange(LocalPreferences.getTheme()) setContent { AmethystTheme(themeViewModel) { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt index 0278f3646..8901064c4 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt @@ -20,6 +20,7 @@ import com.vitorpamplona.amethyst.ui.screen.NostrHomeFeedViewModel import com.vitorpamplona.amethyst.ui.screen.NostrHomeRepliesFeedViewModel import com.vitorpamplona.amethyst.ui.screen.NostrVideoFeedViewModel import com.vitorpamplona.amethyst.ui.screen.NotificationViewModel +import com.vitorpamplona.amethyst.ui.screen.ThemeViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.BookmarkListScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.ChannelScreen @@ -55,6 +56,7 @@ fun AppNavigation( navController: NavHostController, accountViewModel: AccountViewModel, + themeViewModel: ThemeViewModel, nextPage: String? = null ) { var actionableNextPage by remember { mutableStateOf(nextPage) } @@ -225,7 +227,7 @@ fun AppNavigation( composable(route.route, route.arguments, content = { SettingsScreen( accountViewModel = accountViewModel, - nav = nav + themeViewModel ) }) } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountScreen.kt index 6ac35a240..82b872d7e 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountScreen.kt @@ -24,18 +24,18 @@ fun AccountScreen(accountStateViewModel: AccountStateViewModel, themeViewModel: is AccountState.LoggedIn -> { val accountViewModel: AccountViewModel = viewModel( key = state.account.userProfile().pubkeyHex, - factory = AccountViewModel.Factory(state.account, themeViewModel) + factory = AccountViewModel.Factory(state.account) ) - MainScreen(accountViewModel, accountStateViewModel, startingPage) + MainScreen(accountViewModel, accountStateViewModel, themeViewModel, startingPage) } is AccountState.LoggedInViewOnly -> { val accountViewModel: AccountViewModel = viewModel( key = state.account.userProfile().pubkeyHex, - factory = AccountViewModel.Factory(state.account, themeViewModel) + factory = AccountViewModel.Factory(state.account) ) - MainScreen(accountViewModel, accountStateViewModel, startingPage) + MainScreen(accountViewModel, accountStateViewModel, themeViewModel, startingPage) } } } 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 fedfa79bf..3a297cfe3 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 @@ -22,7 +22,6 @@ import com.vitorpamplona.amethyst.service.model.Event import com.vitorpamplona.amethyst.service.model.LnZapEvent import com.vitorpamplona.amethyst.service.model.PayInvoiceErrorResponse import com.vitorpamplona.amethyst.service.model.ReportEvent -import com.vitorpamplona.amethyst.ui.screen.ThemeViewModel import kotlinx.collections.immutable.ImmutableSet import kotlinx.collections.immutable.persistentSetOf import kotlinx.collections.immutable.toImmutableSet @@ -33,7 +32,7 @@ import java.math.BigDecimal import java.util.Locale @Stable -class AccountViewModel(val account: Account, private val themeViewModel: ThemeViewModel) : ViewModel() { +class AccountViewModel(val account: Account) : ViewModel() { val accountLiveData: LiveData = account.live.map { it } val accountLanguagesLiveData: LiveData = account.liveLanguages.map { it } val accountLastReadLiveData: LiveData = account.liveLastRead.map { it } @@ -41,14 +40,6 @@ class AccountViewModel(val account: Account, private val themeViewModel: ThemeVi val userFollows: LiveData = account.userProfile().live().follows.map { it } val userRelays: LiveData = account.userProfile().live().relays.map { it } - fun changeTheme(newValue: Int) { - themeViewModel.onChange(newValue) - } - - fun currentTheme(): Int { - return themeViewModel.theme.value ?: 0 - } - fun updateAutomaticallyStartPlayback( automaticallyStartPlayback: Boolean? ) { @@ -326,9 +317,9 @@ class AccountViewModel(val account: Account, private val themeViewModel: ThemeVi } } - class Factory(val account: Account, private val themeViewModel: ThemeViewModel) : ViewModelProvider.Factory { + class Factory(val account: Account) : ViewModelProvider.Factory { override fun create(modelClass: Class): AccountViewModel { - return AccountViewModel(account, themeViewModel) as AccountViewModel + return AccountViewModel(account) as AccountViewModel } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/MainScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/MainScreen.kt index 1bffcfed1..b3fef99eb 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/MainScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/MainScreen.kt @@ -51,11 +51,17 @@ import com.vitorpamplona.amethyst.ui.screen.NostrHomeFeedViewModel import com.vitorpamplona.amethyst.ui.screen.NostrHomeRepliesFeedViewModel import com.vitorpamplona.amethyst.ui.screen.NostrVideoFeedViewModel import com.vitorpamplona.amethyst.ui.screen.NotificationViewModel +import com.vitorpamplona.amethyst.ui.screen.ThemeViewModel import kotlinx.coroutines.launch @OptIn(ExperimentalMaterialApi::class) @Composable -fun MainScreen(accountViewModel: AccountViewModel, accountStateViewModel: AccountStateViewModel, startingPage: String? = null) { +fun MainScreen( + accountViewModel: AccountViewModel, + accountStateViewModel: AccountStateViewModel, + themeViewModel: ThemeViewModel, + startingPage: String? = null +) { val scope = rememberCoroutineScope() val navController = rememberNavController() val scaffoldState = rememberScaffoldState(rememberDrawerState(DrawerValue.Closed)) @@ -211,6 +217,7 @@ fun MainScreen(accountViewModel: AccountViewModel, accountStateViewModel: Accoun userReactionsStatsModel = userReactionsStatsModel, navController = navController, accountViewModel = accountViewModel, + themeViewModel = themeViewModel, nextPage = startingPage ) } 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 11cdb5464..69b18e5ef 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 @@ -35,6 +35,7 @@ import androidx.compose.ui.unit.sp import androidx.core.os.LocaleListCompat import com.vitorpamplona.amethyst.LocalPreferences import com.vitorpamplona.amethyst.R +import com.vitorpamplona.amethyst.ui.screen.ThemeViewModel import com.vitorpamplona.amethyst.ui.theme.DoubleVertSpacer import com.vitorpamplona.amethyst.ui.theme.StdPadding import kotlinx.collections.immutable.persistentListOf @@ -88,7 +89,7 @@ fun getLanguageIndex(languageEntries: Map): Int { @Composable fun SettingsScreen( accountViewModel: AccountViewModel, - nav: (String) -> Unit + themeViewModel: ThemeViewModel ) { val scope = rememberCoroutineScope() val selectedItens = persistentListOf( @@ -114,7 +115,7 @@ fun SettingsScreen( stringResource(R.string.light), stringResource(R.string.dark) ) - val themeIndex = accountViewModel.currentTheme() + val themeIndex = themeViewModel.theme.value ?: 0 val context = LocalContext.current @@ -161,7 +162,7 @@ fun SettingsScreen( placeholder = themeItens[themeIndex], options = themeItens, onSelect = { - accountViewModel.changeTheme(it) + themeViewModel.onChange(it) scope.launch(Dispatchers.IO) { LocalPreferences.updateTheme(it) } From 3e48b293b067483a93a33d56d6cf1b6f96e6a30f Mon Sep 17 00:00:00 2001 From: greenart7c3 <115044884+greenart7c3@users.noreply.github.com> Date: Mon, 10 Jul 2023 16:04:06 -0300 Subject: [PATCH 27/29] create ThemeViewModel using viewModel contructor --- .../main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt index abeb8dd52..7a5b04b8f 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt @@ -58,10 +58,9 @@ class MainActivity : AppCompatActivity() { val appLocale: LocaleListCompat = LocaleListCompat.forLanguageTags(language) AppCompatDelegate.setApplicationLocales(appLocale) } - val themeViewModel = ThemeViewModel() - themeViewModel.onChange(LocalPreferences.getTheme()) - setContent { + val themeViewModel: ThemeViewModel = viewModel() + themeViewModel.onChange(LocalPreferences.getTheme()) AmethystTheme(themeViewModel) { // A surface container using the 'background' color from the theme Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colors.background) { From 6cc426643571983e2b0532cc10245818233a6f15 Mon Sep 17 00:00:00 2001 From: greenart7c3 <115044884+greenart7c3@users.noreply.github.com> Date: Wed, 12 Jul 2023 11:27:34 -0300 Subject: [PATCH 28/29] appcompat needed for language picker and theme --- app/build.gradle | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/build.gradle b/app/build.gradle index 21ff25157..08d2f49b4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -173,6 +173,9 @@ dependencies { implementation('com.github.vitorpamplona.compose-richtext:richtext-ui-material:a0954aba63') implementation('com.github.vitorpamplona.compose-richtext:richtext-commonmark:a0954aba63') + // Language picker and Theme chooser + implementation 'androidx.appcompat:appcompat:1.6.1' + // Local model for language identification playImplementation 'com.google.mlkit:language-id:17.0.4' From 3254479ee5b59ddd81301cd2ae459ea18b84ffea Mon Sep 17 00:00:00 2001 From: greenart7c3 <115044884+greenart7c3@users.noreply.github.com> Date: Wed, 12 Jul 2023 11:41:37 -0300 Subject: [PATCH 29/29] add settings icon --- .../com/vitorpamplona/amethyst/ui/navigation/Routes.kt | 2 +- app/src/main/res/drawable/ic_settings.xml | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 app/src/main/res/drawable/ic_settings.xml diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/Routes.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/Routes.kt index 008cc0e10..c2f197b19 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/Routes.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/Routes.kt @@ -131,7 +131,7 @@ sealed class Route( object Settings : Route( route = "Settings", - icon = com.google.android.exoplayer2.R.drawable.exo_ic_settings + icon = R.drawable.ic_settings ) } diff --git a/app/src/main/res/drawable/ic_settings.xml b/app/src/main/res/drawable/ic_settings.xml new file mode 100644 index 000000000..f783dd69b --- /dev/null +++ b/app/src/main/res/drawable/ic_settings.xml @@ -0,0 +1,10 @@ + + +