mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-05-10 17:18:31 +00:00
android, desktop: fix presenting large images (#4139)
* android, desktop: fix presenting large images * 4320 px limitation * revert line * onClick * onClick
This commit is contained in:
committed by
GitHub
parent
bc5af35a3e
commit
93a7ddb128
+17
-6
@@ -37,7 +37,7 @@ actual fun ClipboardManager.shareText(text: String) {
|
||||
}
|
||||
}
|
||||
|
||||
actual fun shareFile(text: String, fileSource: CryptoFile) {
|
||||
fun openOrShareFile(text: String, fileSource: CryptoFile, justOpen: Boolean) {
|
||||
val uri = if (fileSource.cryptoArgs != null) {
|
||||
val tmpFile = File(tmpDir, fileSource.filePath)
|
||||
tmpFile.deleteOnExit()
|
||||
@@ -55,20 +55,31 @@ actual fun shareFile(text: String, fileSource: CryptoFile) {
|
||||
}
|
||||
val ext = fileSource.filePath.substringAfterLast(".")
|
||||
val mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(ext) ?: return
|
||||
val sendIntent: Intent = Intent().apply {
|
||||
action = Intent.ACTION_SEND
|
||||
val sendIntent: Intent = Intent(if (justOpen) Intent.ACTION_VIEW else Intent.ACTION_SEND).apply {
|
||||
/*if (text.isNotEmpty()) {
|
||||
putExtra(Intent.EXTRA_TEXT, text)
|
||||
}*/
|
||||
putExtra(Intent.EXTRA_STREAM, uri.toUri())
|
||||
type = mimeType
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
if (justOpen) {
|
||||
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||
setDataAndType(uri.toUri(), mimeType)
|
||||
} else {
|
||||
putExtra(Intent.EXTRA_STREAM, uri.toUri())
|
||||
type = mimeType
|
||||
}
|
||||
}
|
||||
val shareIntent = Intent.createChooser(sendIntent, null)
|
||||
shareIntent.addFlags(FLAG_ACTIVITY_NEW_TASK)
|
||||
androidAppContext.startActivity(shareIntent)
|
||||
}
|
||||
|
||||
actual fun shareFile(text: String, fileSource: CryptoFile) {
|
||||
openOrShareFile(text, fileSource, justOpen = false)
|
||||
}
|
||||
|
||||
actual fun openFile(fileSource: CryptoFile) {
|
||||
openOrShareFile("", fileSource, justOpen = true)
|
||||
}
|
||||
|
||||
actual fun UriHandler.sendEmail(subject: String, body: CharSequence) {
|
||||
val emailIntent = Intent(Intent.ACTION_SENDTO, Uri.parse("mailto:"))
|
||||
emailIntent.putExtra(Intent.EXTRA_SUBJECT, subject)
|
||||
|
||||
@@ -8,3 +8,4 @@ expect fun UriHandler.sendEmail(subject: String, body: CharSequence)
|
||||
|
||||
expect fun ClipboardManager.shareText(text: String)
|
||||
expect fun shareFile(text: String, fileSource: CryptoFile)
|
||||
expect fun openFile(fileSource: CryptoFile)
|
||||
|
||||
+2
-1
@@ -181,7 +181,8 @@ fun CIFileView(
|
||||
}
|
||||
|
||||
Row(
|
||||
Modifier.padding(top = 4.dp, bottom = 6.dp, start = 6.dp, end = 12.dp),
|
||||
Modifier.clickable(onClick = { fileAction() }).padding(top = 4.dp, bottom = 6.dp, start = 6.dp, end = 12.dp),
|
||||
//Modifier.clickable(enabled = file?.fileSource != null) { if (file?.fileSource != null && getLoadedFilePath(file) != null) openFile(file.fileSource) }.padding(top = 4.dp, bottom = 6.dp, start = 6.dp, end = 12.dp),
|
||||
verticalAlignment = Alignment.Bottom,
|
||||
horizontalArrangement = Arrangement.spacedBy(2.dp)
|
||||
) {
|
||||
|
||||
+41
-14
@@ -2,8 +2,7 @@ package chat.simplex.common.views.chat.item
|
||||
|
||||
import androidx.compose.foundation.*
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.CircularProgressIndicator
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
@@ -113,21 +112,49 @@ fun CIImageView(
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ImageView(painter: Painter, onClick: () -> Unit) {
|
||||
Image(
|
||||
painter,
|
||||
contentDescription = stringResource(MR.strings.image_descr),
|
||||
// .width(DEFAULT_MAX_IMAGE_WIDTH) is a hack for image to increase IntrinsicSize of FramedItemView
|
||||
// if text is short and take all available width if text is long
|
||||
modifier = Modifier
|
||||
fun ImageView(painter: Painter, image: String, fileSource: CryptoFile?, onClick: () -> Unit) {
|
||||
// On my Android device Compose fails to display 6000x6000 px WebP image with exception:
|
||||
// IllegalStateException: Recording currently in progress - missing #endRecording() call?
|
||||
// but can display 5000px image. Using even lower value here just to feel safer.
|
||||
// It happens to WebP because it's not compressed while sending since it can be animated.
|
||||
if (painter.intrinsicSize.width <= 4320 && painter.intrinsicSize.height <= 4320) {
|
||||
Image(
|
||||
painter,
|
||||
contentDescription = stringResource(MR.strings.image_descr),
|
||||
// .width(DEFAULT_MAX_IMAGE_WIDTH) is a hack for image to increase IntrinsicSize of FramedItemView
|
||||
// if text is short and take all available width if text is long
|
||||
modifier = Modifier
|
||||
.width(if (painter.intrinsicSize.width * 0.97 <= painter.intrinsicSize.height) imageViewFullWidth() * 0.75f else DEFAULT_MAX_IMAGE_WIDTH)
|
||||
.combinedClickable(
|
||||
onLongClick = { showMenu.value = true },
|
||||
onClick = onClick
|
||||
)
|
||||
.onRightClick { showMenu.value = true },
|
||||
contentScale = ContentScale.FillWidth,
|
||||
)
|
||||
} else {
|
||||
Box(Modifier
|
||||
.width(if (painter.intrinsicSize.width * 0.97 <= painter.intrinsicSize.height) imageViewFullWidth() * 0.75f else DEFAULT_MAX_IMAGE_WIDTH)
|
||||
.combinedClickable(
|
||||
onLongClick = { showMenu.value = true },
|
||||
onClick = onClick
|
||||
onClick = {}
|
||||
)
|
||||
.onRightClick { showMenu.value = true },
|
||||
contentScale = ContentScale.FillWidth,
|
||||
)
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
imageView(base64ToBitmap(image), onClick = {
|
||||
if (fileSource != null) {
|
||||
openFile(fileSource)
|
||||
}
|
||||
})
|
||||
Icon(
|
||||
painterResource(MR.images.ic_open_in_new),
|
||||
contentDescription = stringResource(MR.strings.image_descr),
|
||||
modifier = Modifier.size(30.dp),
|
||||
tint = MaterialTheme.colors.primary,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun fileSizeValid(): Boolean {
|
||||
@@ -172,9 +199,9 @@ fun CIImageView(
|
||||
}
|
||||
}
|
||||
val loaded = res.value
|
||||
if (loaded != null) {
|
||||
if (loaded != null && file != null) {
|
||||
val (imageBitmap, data, _) = loaded
|
||||
SimpleAndAnimatedImageView(data, imageBitmap, file, imageProvider, @Composable { painter, onClick -> ImageView(painter, onClick) })
|
||||
SimpleAndAnimatedImageView(data, imageBitmap, file, imageProvider, @Composable { painter, onClick -> ImageView(painter, image, file.fileSource, onClick) })
|
||||
} else {
|
||||
imageView(base64ToBitmap(image), onClick = {
|
||||
if (file != null) {
|
||||
|
||||
+28
@@ -9,6 +9,7 @@ import java.io.File
|
||||
import java.net.URI
|
||||
import java.net.URLEncoder
|
||||
import chat.simplex.res.MR
|
||||
import java.awt.Desktop
|
||||
|
||||
actual fun UriHandler.sendEmail(subject: String, body: CharSequence) {
|
||||
val subjectEncoded = URLEncoder.encode(subject, "UTF-8").replace("+", "%20")
|
||||
@@ -41,3 +42,30 @@ actual fun shareFile(text: String, fileSource: CryptoFile) {
|
||||
}.launch(fileSource.filePath)
|
||||
}
|
||||
}
|
||||
|
||||
actual fun openFile(fileSource: CryptoFile) {
|
||||
try {
|
||||
val filePath = filePathForShare(fileSource) ?: return
|
||||
Desktop.getDesktop().open(File(filePath))
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Unable to open the file: " + e.stackTraceToString())
|
||||
AlertManager.shared.showAlertMsg(title = generalGetString(MR.strings.error), text = e.stackTraceToString())
|
||||
}
|
||||
}
|
||||
|
||||
fun filePathForShare(fileSource: CryptoFile): String? {
|
||||
return if (fileSource.cryptoArgs != null) {
|
||||
val tmpFile = File(tmpDir, fileSource.filePath)
|
||||
tmpFile.deleteOnExit()
|
||||
try {
|
||||
decryptCryptoFile(getAppFilePath(fileSource.filePath), fileSource.cryptoArgs ?: return null, tmpFile.absolutePath)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Unable to decrypt crypto file: " + e.stackTraceToString())
|
||||
AlertManager.shared.showAlertMsg(title = generalGetString(MR.strings.error), text = e.stackTraceToString())
|
||||
return null
|
||||
}
|
||||
tmpFile.absolutePath
|
||||
} else {
|
||||
getAppFilePath(fileSource.filePath)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-14
@@ -59,20 +59,7 @@ actual fun copyItemToClipboard(cItem: ChatItem, clipboard: ClipboardManager) = w
|
||||
}
|
||||
|
||||
if (fileSource != null) {
|
||||
val filePath: String = if (fileSource.cryptoArgs != null) {
|
||||
val tmpFile = File(tmpDir, fileSource.filePath)
|
||||
tmpFile.deleteOnExit()
|
||||
try {
|
||||
decryptCryptoFile(getAppFilePath(fileSource.filePath), fileSource.cryptoArgs ?: return@withLongRunningApi, tmpFile.absolutePath)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Unable to decrypt crypto file: " + e.stackTraceToString())
|
||||
AlertManager.shared.showAlertMsg(title = generalGetString(MR.strings.error), text = e.stackTraceToString())
|
||||
return@withLongRunningApi
|
||||
}
|
||||
tmpFile.absolutePath
|
||||
} else {
|
||||
getAppFilePath(fileSource.filePath)
|
||||
}
|
||||
val filePath = filePathForShare(fileSource) ?: return@withLongRunningApi
|
||||
when {
|
||||
desktopPlatform.isWindows() -> clipboard.setText(AnnotatedString("\"${File(filePath).absolutePath}\""))
|
||||
else -> clipboard.setText(AnnotatedString(filePath))
|
||||
|
||||
Reference in New Issue
Block a user