diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/chat/item/FramedItemView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/chat/item/FramedItemView.kt index 8c64a182ee..21c83acfa0 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/chat/item/FramedItemView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/chat/item/FramedItemView.kt @@ -10,6 +10,7 @@ import androidx.compose.material.icons.filled.InsertDriveFile import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clipToBounds import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.asImageBitmap @@ -69,7 +70,10 @@ fun FramedItemView( Modifier .background(if (sent) SentQuoteColorLight else ReceivedQuoteColorLight) .fillMaxWidth() - .clickable { scrollToItem(qi.itemId?: return@clickable) } + .combinedClickable( + onLongClick = { showMenu.value = true }, + onClick = { scrollToItem(qi.itemId?: return@combinedClickable) } + ) ) { when (qi.content) { is MsgContent.MCImage -> { @@ -102,10 +106,16 @@ fun FramedItemView( } } - Surface( - shape = RoundedCornerShape(18.dp), - color = if (sent) SentColorLight else ReceivedColorLight - ) { + val transparentBackground = ci.content.msgContent is MsgContent.MCImage && ci.content.text.isEmpty() + Box(Modifier + .clip(RoundedCornerShape(18.dp)) + .background( + when { + transparentBackground -> Color.Transparent + sent -> SentColorLight + else -> ReceivedColorLight + } + )) { var metaColor = HighOrLowlight Box(contentAlignment = Alignment.BottomEnd) { Column(Modifier.width(IntrinsicSize.Max)) { @@ -131,7 +141,7 @@ fun FramedItemView( is MsgContent.MCImage -> { CIImageView(image = mc.image, file = ci.file, imageProvider ?: return@Box, showMenu, receiveFile) if (mc.text == "") { - metaColor = Color.White + metaColor = HighOrLowlight } else { CIMarkdownText(ci, showMember, uriHandler) } diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/database/DatabaseView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/database/DatabaseView.kt index ae0882b53d..db32719120 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/database/DatabaseView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/database/DatabaseView.kt @@ -58,13 +58,13 @@ fun DatabaseView( val chatLastStart = remember { mutableStateOf(prefs.chatLastStart.get()) } val chatArchiveFile = remember { mutableStateOf(null) } val saveArchiveLauncher = rememberSaveArchiveLauncher(cxt = context, chatArchiveFile) + val appFilesCountAndSize = remember { mutableStateOf(directoryFileCountAndSize(getAppFilesDirectory(context))) } val importArchiveLauncher = rememberGetContentLauncher { uri: Uri? -> if (uri != null) { - importArchiveAlert(m, context, uri, progressIndicator) + importArchiveAlert(m, context, uri, appFilesCountAndSize, progressIndicator) } } val chatDbDeleted = remember { m.chatDbDeleted } - val appFilesCountAndSize = remember { mutableStateOf(directoryFileCountAndSize(getAppFilesDirectory(context))) } LaunchedEffect(m.chatRunning) { runChat.value = m.chatRunning.value ?: true } @@ -507,16 +507,28 @@ private fun rememberSaveArchiveLauncher(cxt: Context, chatArchiveFile: MutableSt } ) -private fun importArchiveAlert(m: ChatModel, context: Context, importedArchiveUri: Uri, progressIndicator: MutableState) { +private fun importArchiveAlert( + m: ChatModel, + context: Context, + importedArchiveUri: Uri, + appFilesCountAndSize: MutableState>, + progressIndicator: MutableState +) { AlertManager.shared.showAlertDialog( title = generalGetString(R.string.import_database_question), text = generalGetString(R.string.your_current_chat_database_will_be_deleted_and_replaced_with_the_imported_one), confirmText = generalGetString(R.string.import_database_confirmation), - onConfirm = { importArchive(m, context, importedArchiveUri, progressIndicator) } + onConfirm = { importArchive(m, context, importedArchiveUri, appFilesCountAndSize, progressIndicator) } ) } -private fun importArchive(m: ChatModel, context: Context, importedArchiveUri: Uri, progressIndicator: MutableState) { +private fun importArchive( + m: ChatModel, + context: Context, + importedArchiveUri: Uri, + appFilesCountAndSize: MutableState>, + progressIndicator: MutableState +) { progressIndicator.value = true val archivePath = saveArchiveFromUri(context, importedArchiveUri) if (archivePath != null) { @@ -527,6 +539,7 @@ private fun importArchive(m: ChatModel, context: Context, importedArchiveUri: Ur val config = ArchiveConfig(archivePath, parentTempDirectory = context.cacheDir.toString()) m.controller.apiImportArchive(config) DatabaseUtils.removeDatabaseKey() + appFilesCountAndSize.value = directoryFileCountAndSize(getAppFilesDirectory(context)) operationEnded(m, progressIndicator) { AlertManager.shared.showAlertMsg(generalGetString(R.string.chat_database_imported), generalGetString(R.string.restart_the_app_to_use_imported_chat_database)) } diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/helpers/GetImageView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/helpers/GetImageView.kt index 75665419e2..cd01e60c7d 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/helpers/GetImageView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/helpers/GetImageView.kt @@ -65,26 +65,26 @@ fun resizeImageToStrSize(image: Bitmap, maxDataSize: Long): String { } private fun compressImageStr(bitmap: Bitmap): String { - return "data:image/jpg;base64," + Base64.encodeToString(compressImageData(bitmap).toByteArray(), Base64.NO_WRAP) + return "data:image/jpg;base64," + Base64.encodeToString(compressImageData(bitmap, false).toByteArray(), Base64.NO_WRAP) } -fun resizeImageToDataSize(image: Bitmap, maxDataSize: Long): ByteArrayOutputStream { +fun resizeImageToDataSize(image: Bitmap, usePng: Boolean, maxDataSize: Long): ByteArrayOutputStream { var img = image - var stream = compressImageData(img) + var stream = compressImageData(img, usePng) while (stream.size() > maxDataSize) { val ratio = sqrt(stream.size().toDouble() / maxDataSize.toDouble()) val clippedRatio = min(ratio, 2.0) val width = (img.width.toDouble() / clippedRatio).toInt() val height = img.height * width / img.width img = Bitmap.createScaledBitmap(img, width, height, true) - stream = compressImageData(img) + stream = compressImageData(img, usePng) } return stream } -private fun compressImageData(bitmap: Bitmap): ByteArrayOutputStream { +private fun compressImageData(bitmap: Bitmap, usePng: Boolean): ByteArrayOutputStream { val stream = ByteArrayOutputStream() - bitmap.compress(Bitmap.CompressFormat.JPEG, 85, stream) + bitmap.compress(if (!usePng) Bitmap.CompressFormat.JPEG else Bitmap.CompressFormat.PNG, 85, stream) return stream } diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/helpers/Util.kt b/apps/android/app/src/main/java/chat/simplex/app/views/helpers/Util.kt index 76b533ed1e..cb6344f28f 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/helpers/Util.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/helpers/Util.kt @@ -308,9 +308,10 @@ fun getFileSize(context: Context, uri: Uri): Long? { fun saveImage(context: Context, image: Bitmap): String? { return try { - val dataResized = resizeImageToDataSize(image, maxDataSize = MAX_IMAGE_SIZE) + val ext = if (image.hasAlpha()) "png" else "jpg" + val dataResized = resizeImageToDataSize(image, ext == "png", maxDataSize = MAX_IMAGE_SIZE) val timestamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(Date()) - val fileToSave = uniqueCombine(context, "IMG_${timestamp}.jpg") + val fileToSave = uniqueCombine(context, "IMG_${timestamp}.$ext") val file = File(getAppFilePath(context, fileToSave)) val output = FileOutputStream(file) dataResized.writeTo(output)