diff --git a/apps/multiplatform/android/src/main/AndroidManifest.xml b/apps/multiplatform/android/src/main/AndroidManifest.xml
index 67bc0d70c8..bb6a6f8f8a 100644
--- a/apps/multiplatform/android/src/main/AndroidManifest.xml
+++ b/apps/multiplatform/android/src/main/AndroidManifest.xml
@@ -27,6 +27,14 @@
+
+
+
+
+
+
+
+
= if (Build.VERSION.SDK_INT >= 33) {
+// pm.queryIntentActivities(openIntent, PackageManager.ResolveInfoFlags.of((PackageManager.MATCH_DEFAULT_ONLY).toLong()))
+// } else {
+// pm.queryIntentActivities(openIntent, PackageManager.MATCH_DEFAULT_ONLY)
+// }.sortedBy { it.priority }
+// val first = resInfoList.firstOrNull { it.isDefault } ?: resInfoList.firstOrNull() ?: return null
+ val act = pm.resolveActivity(openIntent, PackageManager.MATCH_DEFAULT_ONLY) ?: return null
+// Log.d(TAG, "Default launch action ${act} ${act.loadLabel(pm)} ${act.activityInfo?.name}")
+ val label = act.loadLabel(pm).toString()
+ val icon = act.loadIcon(pm).toBitmap().asImageBitmap()
+ val chooser = act.activityInfo?.name?.endsWith("ResolverActivity") == true
+ return OpenDefaultApp(label, icon, chooser)
}
actual fun shareFile(text: String, fileSource: CryptoFile) {
diff --git a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/chat/item/CIFileView.android.kt b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/chat/item/CIFileView.android.kt
new file mode 100644
index 0000000000..b24150ed24
--- /dev/null
+++ b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/chat/item/CIFileView.android.kt
@@ -0,0 +1,57 @@
+package chat.simplex.common.views.chat.item
+
+import androidx.compose.material.MaterialTheme
+import androidx.compose.runtime.*
+import chat.simplex.common.model.CryptoFile
+import chat.simplex.common.platform.*
+import chat.simplex.common.views.helpers.DefaultDropdownMenu
+import chat.simplex.res.MR
+import dev.icerock.moko.resources.compose.painterResource
+import dev.icerock.moko.resources.compose.stringResource
+import java.net.URI
+
+@Composable
+actual fun SaveOrOpenFileMenu(
+ showMenu: MutableState,
+ encrypted: Boolean,
+ ext: String?,
+ encryptedUri: URI,
+ fileSource: CryptoFile,
+ saveFile: () -> Unit
+) {
+ val defaultApp = remember(encryptedUri.toString()) { if (ext != null) queryDefaultAppForExtension(ext, encryptedUri) else null }
+ DefaultDropdownMenu(showMenu) {
+ if (defaultApp != null) {
+ if (!defaultApp.isSystemChooser) {
+ ItemAction(
+ stringResource(MR.strings.open_with_app).format(defaultApp.name),
+ defaultApp.icon,
+ textColor = MaterialTheme.colors.primary,
+ onClick = {
+ openOrShareFile("", fileSource, justOpen = true, useChooser = false)
+ showMenu.value = false
+ }
+ )
+ } else {
+ ItemAction(
+ stringResource(MR.strings.open_with_app).format("…"),
+ painterResource(MR.images.ic_open_in_new),
+ color = MaterialTheme.colors.primary,
+ onClick = {
+ openOrShareFile("", fileSource, justOpen = true, useChooser = false)
+ showMenu.value = false
+ }
+ )
+ }
+ }
+ ItemAction(
+ stringResource(MR.strings.save_verb),
+ painterResource(if (encrypted) MR.images.ic_lock_open_right else MR.images.ic_download),
+ color = MaterialTheme.colors.primary,
+ onClick = {
+ saveFile()
+ showMenu.value = false
+ }
+ )
+ }
+}
diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIFileView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIFileView.kt
index 59643afdf4..2c16de40e9 100644
--- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIFileView.kt
+++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIFileView.kt
@@ -1,12 +1,12 @@
package chat.simplex.common.views.chat.item
-import androidx.compose.foundation.background
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CornerSize
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.*
import androidx.compose.runtime.*
+import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
@@ -184,14 +184,26 @@ fun CIFileView(
}
}
+ val showOpenSaveMenu = rememberSaveable(file?.fileId) { mutableStateOf(false) }
+ val ext = file?.fileSource?.filePath?.substringAfterLast(".")?.takeIf { it.isNotBlank() }
+ val loadedFilePath = if (appPlatform.isAndroid && file?.fileSource != null) getLoadedFilePath(file) else null
+ if (loadedFilePath != null && file?.fileSource != null) {
+ val encrypted = file.fileSource.cryptoArgs != null
+ SaveOrOpenFileMenu(showOpenSaveMenu, encrypted, ext, File(loadedFilePath).toURI(), file.fileSource, saveFile = { fileAction() })
+ }
Row(
Modifier
.combinedClickable(
- onClick = { fileAction() },
+ onClick = {
+ if (appPlatform.isAndroid && loadedFilePath != null) {
+ showOpenSaveMenu.value = true
+ } else {
+ fileAction()
+ }
+ },
onLongClick = { showMenu.value = true }
)
.padding(if (smallView) PaddingValues() else PaddingValues(top = 4.sp.toDp(), bottom = 6.sp.toDp(), start = 6.sp.toDp(), end = 12.sp.toDp())),
- //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.sp.toDp())
) {
@@ -223,6 +235,16 @@ fun CIFileView(
fun fileSizeValid(file: CIFile): Boolean = file.fileSize <= getMaxFileSize(file.fileProtocol)
+@Composable
+expect fun SaveOrOpenFileMenu(
+ showMenu: MutableState,
+ encrypted: Boolean,
+ ext: String?,
+ encryptedUri: URI,
+ fileSource: CryptoFile,
+ saveFile: () -> Unit
+)
+
@Composable
fun rememberSaveFileLauncher(ciFile: CIFile?): FileChooserLauncher =
rememberFileChooserLauncher(false, ciFile) { to: URI? ->
diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/ChatItemView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/ChatItemView.kt
index 22842eb350..647c74da06 100644
--- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/ChatItemView.kt
+++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/ChatItemView.kt
@@ -867,6 +867,32 @@ fun ItemAction(text: String, icon: Painter, color: Color = Color.Unspecified, on
}
}
+@Composable
+fun ItemAction(text: String, icon: ImageBitmap, textColor: Color = Color.Unspecified, iconColor: Color = Color.Unspecified, onClick: () -> Unit) {
+ val finalColor = if (textColor == Color.Unspecified) {
+ MenuTextColor
+ } else textColor
+ DropdownMenuItem(onClick, contentPadding = PaddingValues(horizontal = DEFAULT_PADDING * 1.5f)) {
+ Row(verticalAlignment = Alignment.CenterVertically) {
+ Text(
+ text,
+ modifier = Modifier
+ .fillMaxWidth()
+ .weight(1F)
+ .padding(end = 15.dp),
+ color = finalColor,
+ maxLines = 1,
+ overflow = TextOverflow.Ellipsis
+ )
+ if (iconColor == Color.Unspecified) {
+ Image(icon, text, Modifier.size(22.dp))
+ } else {
+ Icon(icon, text, Modifier.size(22.dp), tint = iconColor)
+ }
+ }
+ }
+}
+
@Composable
fun ItemAction(
text: String,
diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml
index 34788b5bde..b052727ad2 100644
--- a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml
+++ b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml
@@ -482,6 +482,7 @@
Please, wait while the file is being loaded from the linked mobile
File error
Temporary file error
+ Open with %s
Voice message
diff --git a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/chat/item/CIFileView.desktop.kt b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/chat/item/CIFileView.desktop.kt
new file mode 100644
index 0000000000..eceb7de9be
--- /dev/null
+++ b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/chat/item/CIFileView.desktop.kt
@@ -0,0 +1,18 @@
+package chat.simplex.common.views.chat.item
+
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.MutableState
+import chat.simplex.common.model.CryptoFile
+import java.net.URI
+
+@Composable
+actual fun SaveOrOpenFileMenu(
+ showMenu: MutableState,
+ encrypted: Boolean,
+ ext: String?,
+ encryptedUri: URI,
+ fileSource: CryptoFile,
+ saveFile: () -> Unit
+) {
+
+}