diff --git a/app/src/main/java/org/linphone/ui/fileviewer/FileViewerActivity.kt b/app/src/main/java/org/linphone/ui/fileviewer/FileViewerActivity.kt
index 7b856d775..0e95f8a0b 100644
--- a/app/src/main/java/org/linphone/ui/fileviewer/FileViewerActivity.kt
+++ b/app/src/main/java/org/linphone/ui/fileviewer/FileViewerActivity.kt
@@ -84,6 +84,14 @@ class FileViewerActivity : GenericActivity() {
finish()
}
+ viewModel.showRedToastEvent.observe(this) {
+ it.consume { pair ->
+ val message = getString(pair.first)
+ val icon = pair.second
+ showRedToast(message, icon)
+ }
+ }
+
viewModel.fileReadyEvent.observe(this) {
it.consume { done ->
if (!done) {
diff --git a/app/src/main/java/org/linphone/ui/fileviewer/viewmodel/FileViewModel.kt b/app/src/main/java/org/linphone/ui/fileviewer/viewmodel/FileViewModel.kt
index 850679cb9..31e4e6266 100644
--- a/app/src/main/java/org/linphone/ui/fileviewer/viewmodel/FileViewModel.kt
+++ b/app/src/main/java/org/linphone/ui/fileviewer/viewmodel/FileViewModel.kt
@@ -138,6 +138,10 @@ class FileViewModel
Log.d("$TAG File [$file] seems to be plain text")
loadPlainText()
}
+ FileUtils.MimeType.Unknown -> {
+ Log.w("$TAG Unknown MIME type for file at [$file], opening it as plain text")
+ loadPlainText()
+ }
else -> {
Log.e("$TAG Unexpected MIME type [$mimeType] for file at [$file] with extension [$extension]")
fileReadyEvent.value = Event(false)
@@ -333,6 +337,14 @@ class FileViewModel
// TODO FIXME : improve performances !
} catch (e: Exception) {
Log.e("$TAG Exception trying to read file [$filePath] as text: $e")
+ showRedToastEvent.postValue(
+ Event(
+ Pair(
+ R.string.conversation_file_cant_be_opened_error_toast,
+ R.drawable.warning_circle
+ )
+ )
+ )
}
}
}
diff --git a/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationDocumentsListFragment.kt b/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationDocumentsListFragment.kt
index bf6b4cc96..d01a7e959 100644
--- a/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationDocumentsListFragment.kt
+++ b/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationDocumentsListFragment.kt
@@ -31,14 +31,14 @@ import androidx.lifecycle.ViewModelProvider
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
import androidx.recyclerview.widget.LinearLayoutManager
-import org.linphone.R
import org.linphone.core.tools.Log
import org.linphone.databinding.ChatDocumentsFragmentBinding
-import org.linphone.ui.GenericActivity
import org.linphone.ui.main.chat.adapter.ConversationsFilesAdapter
import org.linphone.ui.main.chat.model.FileModel
import org.linphone.ui.main.chat.viewmodel.ConversationDocumentsListViewModel
import org.linphone.ui.main.fragment.SlidingPaneChildFragment
+import org.linphone.utils.ConfirmationDialogModel
+import org.linphone.utils.DialogUtils
import org.linphone.utils.Event
import org.linphone.utils.FileUtils
import org.linphone.utils.RecyclerViewHeaderDecoration
@@ -149,10 +149,10 @@ class ConversationDocumentsListFragment : SlidingPaneChildFragment() {
putBoolean("isEncrypted", fileModel.isEncrypted)
putLong("timestamp", fileModel.fileCreationTimestamp)
putString("originalPath", fileModel.originalPath)
+ putBoolean("isMedia", false)
}
when (FileUtils.getMimeType(mime)) {
FileUtils.MimeType.Pdf, FileUtils.MimeType.PlainText -> {
- bundle.putBoolean("isMedia", false)
sharedViewModel.displayFileEvent.value = Event(bundle)
}
else -> {
@@ -165,13 +165,38 @@ class ConversationDocumentsListFragment : SlidingPaneChildFragment() {
requireContext().startActivity(intent)
} catch (anfe: ActivityNotFoundException) {
Log.e("$TAG Can't open file [$path] in third party app: $anfe")
- val message = getString(
- R.string.conversation_no_app_registered_to_handle_content_type_error_toast
- )
- val icon = R.drawable.file
- (requireActivity() as GenericActivity).showRedToast(message, icon)
+ showOpenAsPlainTextDialog(bundle)
}
}
}
}
+
+ private fun showOpenAsPlainTextDialog(bundle: Bundle) {
+ val model = ConfirmationDialogModel()
+ val dialog = DialogUtils.getOpenAsPlainTextDialog(
+ requireActivity(),
+ model
+ )
+
+ model.dismissEvent.observe(viewLifecycleOwner) {
+ it.consume {
+ dialog.dismiss()
+ }
+ }
+
+ model.cancelEvent.observe(viewLifecycleOwner) {
+ it.consume {
+ dialog.dismiss()
+ }
+ }
+
+ model.confirmEvent.observe(viewLifecycleOwner) {
+ it.consume {
+ sharedViewModel.displayFileEvent.value = Event(bundle)
+ dialog.dismiss()
+ }
+ }
+
+ dialog.show()
+ }
}
diff --git a/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationFragment.kt b/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationFragment.kt
index 4007cf6cc..dc477869f 100644
--- a/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationFragment.kt
+++ b/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationFragment.kt
@@ -69,7 +69,6 @@ import org.linphone.core.tools.Log
import org.linphone.databinding.ChatConversationFragmentBinding
import org.linphone.databinding.ChatConversationPopupMenuBinding
import org.linphone.ui.GenericActivity
-import org.linphone.ui.main.MainActivity
import org.linphone.ui.main.chat.ConversationScrollListener
import org.linphone.ui.main.chat.adapter.ConversationEventAdapter
import org.linphone.ui.main.chat.adapter.MessageBottomSheetAdapter
@@ -1093,7 +1092,11 @@ open class ConversationFragment : SlidingPaneChildFragment() {
val extension = FileUtils.getExtensionFromFileName(path)
val mime = FileUtils.getMimeTypeFromExtension(extension)
val mimeType = FileUtils.getMimeType(mime)
- Log.i("$TAG Extension for file [$path] is [$extension], associated MIME type is [$mimeType]")
+ if (mimeType == FileUtils.MimeType.Unknown && extension.contains("/")) {
+ Log.w("$TAG Slash character found in 'extension' [$extension] deduced from file path [$path]; MIME type will be Unknown")
+ } else {
+ Log.i("$TAG Extension for file [$path] is [$extension], associated MIME type is [$mimeType]")
+ }
val bundle = Bundle()
bundle.apply {
@@ -1114,7 +1117,8 @@ open class ConversationFragment : SlidingPaneChildFragment() {
sharedViewModel.displayFileEvent.value = Event(bundle)
}
else -> {
- showOpenOrExportFileDialog(path, mime)
+ bundle.putBoolean("isMedia", false)
+ showOpenOrExportFileDialog(path, mime, bundle)
}
}
}
@@ -1413,7 +1417,7 @@ open class ConversationFragment : SlidingPaneChildFragment() {
bottomSheetDialog = unsafeConversationDetailsBottomSheet
}
- private fun showOpenOrExportFileDialog(path: String, mime: String) {
+ private fun showOpenOrExportFileDialog(path: String, mime: String, bundle: Bundle) {
val model = ConfirmationDialogModel()
val dialog = DialogUtils.getOpenOrExportFileDialog(
requireActivity(),
@@ -1428,7 +1432,7 @@ open class ConversationFragment : SlidingPaneChildFragment() {
model.cancelEvent.observe(viewLifecycleOwner) {
it.consume {
- openFileInAnotherApp(path, mime)
+ openFileInAnotherApp(path, mime, bundle)
dialog.dismiss()
}
}
@@ -1466,7 +1470,7 @@ open class ConversationFragment : SlidingPaneChildFragment() {
dialog.show()
}
- private fun openFileInAnotherApp(path: String, mime: String) {
+ private fun openFileInAnotherApp(path: String, mime: String, bundle: Bundle) {
val intent = Intent(Intent.ACTION_VIEW)
val contentUri: Uri =
FileUtils.getPublicFilePath(requireContext(), path)
@@ -1477,14 +1481,39 @@ open class ConversationFragment : SlidingPaneChildFragment() {
requireContext().startActivity(intent)
} catch (anfe: ActivityNotFoundException) {
Log.e("$TAG Can't open file [$path] in third party app: $anfe")
- val message = getString(
- R.string.conversation_no_app_registered_to_handle_content_type_error_toast
- )
- val icon = R.drawable.file
- (requireActivity() as MainActivity).showRedToast(message, icon)
+ showOpenAsPlainTextDialog(bundle)
}
}
+ private fun showOpenAsPlainTextDialog(bundle: Bundle) {
+ val model = ConfirmationDialogModel()
+ val dialog = DialogUtils.getOpenAsPlainTextDialog(
+ requireActivity(),
+ model
+ )
+
+ model.dismissEvent.observe(viewLifecycleOwner) {
+ it.consume {
+ dialog.dismiss()
+ }
+ }
+
+ model.cancelEvent.observe(viewLifecycleOwner) {
+ it.consume {
+ dialog.dismiss()
+ }
+ }
+
+ model.confirmEvent.observe(viewLifecycleOwner) {
+ it.consume {
+ sharedViewModel.displayFileEvent.value = Event(bundle)
+ dialog.dismiss()
+ }
+ }
+
+ dialog.show()
+ }
+
private fun exportFile(path: String, mime: String) {
filePathToExport = path
diff --git a/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationMediaListFragment.kt b/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationMediaListFragment.kt
index 4ae642f08..e8d0d1f68 100644
--- a/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationMediaListFragment.kt
+++ b/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationMediaListFragment.kt
@@ -178,10 +178,10 @@ class ConversationMediaListFragment : SlidingPaneChildFragment() {
putBoolean("isEncrypted", fileModel.isEncrypted)
putLong("timestamp", fileModel.fileCreationTimestamp)
putString("originalPath", fileModel.originalPath)
+ putBoolean("isMedia", true)
}
when (FileUtils.getMimeType(mime)) {
FileUtils.MimeType.Image, FileUtils.MimeType.Video, FileUtils.MimeType.Audio -> {
- bundle.putBoolean("isMedia", true)
sharedViewModel.displayFileEvent.value = Event(bundle)
}
else -> {
diff --git a/app/src/main/java/org/linphone/utils/DialogUtils.kt b/app/src/main/java/org/linphone/utils/DialogUtils.kt
index 7e9a751d3..4dc0843cb 100644
--- a/app/src/main/java/org/linphone/utils/DialogUtils.kt
+++ b/app/src/main/java/org/linphone/utils/DialogUtils.kt
@@ -47,6 +47,7 @@ import org.linphone.databinding.DialogKickFromConferenceBinding
import org.linphone.databinding.DialogManageAccountInternationalPrefixHelpBinding
import org.linphone.databinding.DialogMergeCallsIntoConferenceBinding
import org.linphone.databinding.DialogOpenExportFileBinding
+import org.linphone.databinding.DialogOpenPlainTextBinding
import org.linphone.databinding.DialogPickNumberOrAddressBinding
import org.linphone.databinding.DialogRemoveAccountBinding
import org.linphone.databinding.DialogRemoveAllCallLogsBinding
@@ -343,6 +344,22 @@ class DialogUtils {
return getDialog(context, binding)
}
+ @UiThread
+ fun getOpenAsPlainTextDialog(
+ context: Context,
+ viewModel: ConfirmationDialogModel
+ ): Dialog {
+ val binding: DialogOpenPlainTextBinding = DataBindingUtil.inflate(
+ LayoutInflater.from(context),
+ R.layout.dialog_open_plain_text,
+ null,
+ false
+ )
+ binding.viewModel = viewModel
+
+ return getDialog(context, binding)
+ }
+
@UiThread
fun getUpdateAvailableDialog(
context: Context,
diff --git a/app/src/main/java/org/linphone/utils/FileUtils.kt b/app/src/main/java/org/linphone/utils/FileUtils.kt
index 6039aab8f..79c9796ea 100644
--- a/app/src/main/java/org/linphone/utils/FileUtils.kt
+++ b/app/src/main/java/org/linphone/utils/FileUtils.kt
@@ -115,8 +115,9 @@ class FileUtils {
type.endsWith("/log") -> MimeType.PlainText
type.startsWith("video/") -> MimeType.Video
type.startsWith("audio/") -> MimeType.Audio
- type.startsWith("application/pdf") -> MimeType.Pdf
- type.startsWith("application/json") -> MimeType.PlainText
+ type == "application/pdf" -> MimeType.Pdf
+ type == "application/json" -> MimeType.PlainText
+ type == "application/xml" -> MimeType.PlainText
else -> MimeType.Unknown
}
Log.d("$TAG MIME type for [$type] is [$mime]")
diff --git a/app/src/main/res/layout/dialog_open_plain_text.xml b/app/src/main/res/layout/dialog_open_plain_text.xml
new file mode 100644
index 000000000..51d32173d
--- /dev/null
+++ b/app/src/main/res/layout/dialog_open_plain_text.xml
@@ -0,0 +1,103 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
index 2b9baa643..4d08bc087 100644
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -463,6 +463,9 @@
&appName; ne peut ouvrir ce fichier.\n\nVoulez-vous l\'ouvrir dans une autre app (si possible), ou le sauvegarder sur votre appareil ?
Ouvrir le fichier
Sauvegarder le fichier
+ Ouvrir comme texte brut ?
+ Aucune application trouvée pour lire ce fichier.\n\nVoulez-vous essayer de l\'ouvrir en tant que texte brut ?
+ Ouvrir comme texte brut
Impossible de lire le message vocal !
Message supprimé
Échec de création de la conversation !
@@ -483,6 +486,7 @@
Prendre une photo
Ouvrir la gallerie
Choisir un fichier
+ Impossible d\'ouvrir le fichier!
Participants (%s)
Ajouter des participants
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 264693b85..95a788122 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -503,6 +503,9 @@
&appName; can\'t open this file.\n\nDo you want to open it in another app (if possible), or export it on your device?
Open file
Export file
+ Open as plain text?
+ No app found to open this kind of file.\n\nWould you like to try opening it as plain text?
+ Open as plain text
Voice recording cannot be played!
Message has been deleted
Failed to create conversation!
@@ -523,6 +526,7 @@
Take picture
Open gallery
Pick file
+ File can\'t be opened!
Group members (%s)
Add participants