diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/InformationDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/InformationDialog.kt index 4d47b34ab..df7c256b8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/InformationDialog.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/InformationDialog.kt @@ -20,9 +20,12 @@ */ package com.vitorpamplona.amethyst.ui.actions +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.PaddingValues 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.text.selection.SelectionContainer import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.Done @@ -32,9 +35,14 @@ import androidx.compose.material3.ButtonColors import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.Icon import androidx.compose.material3.Text +import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalClipboardManager +import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.Size16dp @@ -50,15 +58,11 @@ fun InformationDialog( buttonColors: ButtonColors = ButtonDefaults.buttonColors(), onDismiss: () -> Unit, ) { - val stack = stringRes(id = R.string.stack) - val str = + val str = textContent ?: throwable.localizedMessage ?: throwable.message ?: throwable.javaClass.simpleName + + val stack = remember(throwable) { val writer = StringWriter() - textContent?.let { - writer.append(it) - writer.append("\n\n") - } - writer.append(stack) writer.append("\n") throwable.printStackTrace(PrintWriter(writer)) @@ -66,13 +70,14 @@ fun InformationDialog( writer.toString() } - InformationDialog(title = title, textContent = str, buttonColors, onDismiss) + InformationDialog(title = title, textContent = str, moreInfo = stack, buttonColors, onDismiss) } @Composable fun InformationDialog( title: String, textContent: String, + moreInfo: String? = null, buttonColors: ButtonColors = ButtonDefaults.buttonColors(), onDismiss: () -> Unit, ) { @@ -85,20 +90,37 @@ fun InformationDialog( } }, confirmButton = { - Button( - onClick = onDismiss, - colors = buttonColors, - contentPadding = PaddingValues(horizontal = Size16dp), + Row( + modifier = + Modifier + .padding(all = 8.dp) + .fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, ) { - Row( - verticalAlignment = Alignment.CenterVertically, + moreInfo?.let { + val clipboardManager = LocalClipboardManager.current + TextButton(onClick = { + clipboardManager.setText(AnnotatedString(it)) + }) { + Text(stringRes(R.string.copy_stack_to_clipboard)) + } + } + + Button( + onClick = onDismiss, + colors = buttonColors, + contentPadding = PaddingValues(horizontal = Size16dp), ) { - Icon( - imageVector = Icons.Outlined.Done, - contentDescription = null, - ) - Spacer(StdHorzSpacer) - Text(stringRes(R.string.error_dialog_button_ok)) + Row( + verticalAlignment = Alignment.CenterVertically, + ) { + Icon( + imageVector = Icons.Outlined.Done, + contentDescription = null, + ) + Spacer(StdHorzSpacer) + Text(stringRes(R.string.error_dialog_button_ok)) + } } } }, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/VideoView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/VideoView.kt index 9bc1908c0..871d35754 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/VideoView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/VideoView.kt @@ -826,12 +826,18 @@ private fun RenderVideoPlayer( keepPlaying.value = newKeepPlaying } - AnimatedSaveButton(controllerVisible, Modifier.align(Alignment.TopEnd).padding(end = Size110dp)) { context -> - saveImage(videoUri, mimeType, context, accountViewModel) - } + if (!videoUri.endsWith(".m3u8")) { + AnimatedSaveButton(controllerVisible, Modifier.align(Alignment.TopEnd).padding(end = Size110dp)) { context -> + saveImage(videoUri, mimeType, context, accountViewModel) + } - AnimatedShareButton(controllerVisible, Modifier.align(Alignment.TopEnd).padding(end = Size165dp)) { popupExpanded, toggle -> - ShareImageAction(accountViewModel = accountViewModel, popupExpanded, videoUri, nostrUriCallback, null, null, null, mimeType, toggle) + AnimatedShareButton(controllerVisible, Modifier.align(Alignment.TopEnd).padding(end = Size165dp)) { popupExpanded, toggle -> + ShareImageAction(accountViewModel = accountViewModel, popupExpanded, videoUri, nostrUriCallback, null, null, null, mimeType, toggle) + } + } else { + AnimatedShareButton(controllerVisible, Modifier.align(Alignment.TopEnd).padding(end = Size110dp)) { popupExpanded, toggle -> + ShareImageAction(accountViewModel = accountViewModel, popupExpanded, videoUri, nostrUriCallback, null, null, null, mimeType, toggle) + } } } else { controller.volume = 0f diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentDialog.kt index ef948b8be..167adc4ed 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentDialog.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentDialog.kt @@ -255,34 +255,36 @@ private fun DialogContent( ShareImageAction(accountViewModel = accountViewModel, popupExpanded = popupExpanded, myContent, onDismiss = { popupExpanded.value = false }) } - val localContext = LocalContext.current + if (myContent !is MediaUrlContent || !myContent.url.endsWith(".m3u8")) { + val localContext = LocalContext.current - val writeStoragePermissionState = - rememberPermissionState(Manifest.permission.WRITE_EXTERNAL_STORAGE) { isGranted -> - if (isGranted) { - saveImage(myContent, localContext, accountViewModel) + val writeStoragePermissionState = + rememberPermissionState(Manifest.permission.WRITE_EXTERNAL_STORAGE) { isGranted -> + if (isGranted) { + saveImage(myContent, localContext, accountViewModel) + } } + + OutlinedButton( + onClick = { + if ( + Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q || + writeStoragePermissionState.status.isGranted + ) { + saveImage(myContent, localContext, accountViewModel) + } else { + writeStoragePermissionState.launchPermissionRequest() + } + }, + contentPadding = PaddingValues(horizontal = Size5dp), + colors = ButtonDefaults.outlinedButtonColors().copy(containerColor = MaterialTheme.colorScheme.background), + ) { + Icon( + imageVector = Icons.Default.Download, + modifier = Size20Modifier, + contentDescription = stringRes(R.string.save_to_gallery), + ) } - - OutlinedButton( - onClick = { - if ( - Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q || - writeStoragePermissionState.status.isGranted - ) { - saveImage(myContent, localContext, accountViewModel) - } else { - writeStoragePermissionState.launchPermissionRequest() - } - }, - contentPadding = PaddingValues(horizontal = Size5dp), - colors = ButtonDefaults.outlinedButtonColors().copy(containerColor = MaterialTheme.colorScheme.background), - ) { - Icon( - imageVector = Icons.Default.Download, - modifier = Size20Modifier, - contentDescription = stringRes(R.string.save_to_gallery), - ) } } } diff --git a/amethyst/src/main/res/values/strings.xml b/amethyst/src/main/res/values/strings.xml index 588ae1a44..8b84e8990 100644 --- a/amethyst/src/main/res/values/strings.xml +++ b/amethyst/src/main/res/values/strings.xml @@ -602,6 +602,8 @@ Show URL previews When to load images + Copy Stack + Copy to clipboard Copy npub to clipboard Share or Save