diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index f3ab5958c..89f0d25ef 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -152,17 +152,17 @@
android:theme="@style/AppTheme.CallLauncher" />
diff --git a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt
index 22a88a842..a6af87bdd 100644
--- a/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt
+++ b/app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt
@@ -34,7 +34,6 @@ import android.annotation.SuppressLint
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
-import android.content.DialogInterface
import android.content.Intent
import android.content.pm.PackageManager
import android.content.res.AssetFileDescriptor
@@ -157,7 +156,6 @@ import com.nextcloud.talk.events.UserMentionClickEvent
import com.nextcloud.talk.events.WebSocketCommunicationEvent
import com.nextcloud.talk.extensions.loadAvatarOrImagePreview
import com.nextcloud.talk.jobs.DownloadFileToCacheWorker
-import com.nextcloud.talk.jobs.SaveFileToStorageWorker
import com.nextcloud.talk.jobs.ShareOperationWorker
import com.nextcloud.talk.jobs.UploadAndShareFilesWorker
import com.nextcloud.talk.location.LocationPickerActivity
@@ -191,6 +189,7 @@ import com.nextcloud.talk.ui.bottom.sheet.ProfileBottomSheet
import com.nextcloud.talk.ui.dialog.AttachmentDialog
import com.nextcloud.talk.ui.dialog.DateTimePickerFragment
import com.nextcloud.talk.ui.dialog.MessageActionsDialog
+import com.nextcloud.talk.ui.dialog.SaveToStorageDialogFragment
import com.nextcloud.talk.ui.dialog.ShowReactionsDialog
import com.nextcloud.talk.ui.recyclerview.MessageSwipeActions
import com.nextcloud.talk.ui.recyclerview.MessageSwipeCallback
@@ -2020,44 +2019,6 @@ class ChatActivity :
}
}
- @SuppressLint("LongLogTag")
- private fun saveImageToStorage(
- message: ChatMessage
- ) {
- message.openWhenDownloaded = false
- adapter?.update(message)
-
- val fileName = message.selectedIndividualHashMap!!["name"]
- val sourceFilePath = applicationContext.cacheDir.path
- val fileId = message.selectedIndividualHashMap!!["id"]
-
- val workers = WorkManager.getInstance(context).getWorkInfosByTag(fileId!!)
- try {
- for (workInfo in workers.get()) {
- if (workInfo.state == WorkInfo.State.RUNNING || workInfo.state == WorkInfo.State.ENQUEUED) {
- Log.d(TAG, "SaveFileToStorageWorker for $fileId is already running or scheduled")
- return
- }
- }
- } catch (e: ExecutionException) {
- Log.e(TAG, "Error when checking if worker already exists", e)
- } catch (e: InterruptedException) {
- Log.e(TAG, "Error when checking if worker already exists", e)
- }
-
- val data: Data = Data.Builder()
- .putString(SaveFileToStorageWorker.KEY_FILE_NAME, fileName)
- .putString(SaveFileToStorageWorker.KEY_SOURCE_FILE_PATH, "$sourceFilePath/$fileName")
- .build()
-
- val saveWorker: OneTimeWorkRequest = OneTimeWorkRequest.Builder(SaveFileToStorageWorker::class.java)
- .setInputData(data)
- .addTag(fileId)
- .build()
-
- WorkManager.getInstance().enqueue(saveWorker)
- }
-
@SuppressLint("SimpleDateFormat")
private fun setVoiceRecordFileName() {
val simpleDateFormat = SimpleDateFormat(FILE_DATE_PATTERN)
@@ -4147,27 +4108,14 @@ class ChatActivity :
}
}
- private fun saveImage(message: ChatMessage) {
- if (permissionUtil.isFilesPermissionGranted()) {
- saveImageToStorage(message)
- } else {
- UploadAndShareFilesWorker.requestStoragePermission(this@ChatActivity)
- }
- }
-
private fun showSaveToStorageWarning(message: ChatMessage) {
- val builder = AlertDialog.Builder(this)
- builder.setTitle(R.string.nc_dialog_save_to_storage_title)
- builder.setMessage(R.string.nc_dialog_save_to_storage_content)
- builder.setPositiveButton(R.string.nc_dialog_save_to_storage_yes) { dialog: DialogInterface, _: Int ->
- saveImage(message)
- dialog.dismiss()
- }
- builder.setNegativeButton(R.string.nc_dialog_save_to_storage_no) { dialog: DialogInterface, _: Int ->
- dialog.dismiss()
- }
- val dialog = builder.create()
- dialog.show()
+ val saveFragment: DialogFragment = SaveToStorageDialogFragment.newInstance(
+ message.selectedIndividualHashMap!!["name"]!!
+ )
+ saveFragment.show(
+ supportFragmentManager,
+ SaveToStorageDialogFragment.TAG
+ )
}
fun checkIfSaveable(message: ChatMessage) {
@@ -4608,5 +4556,6 @@ class ChatActivity :
private const val TYPING_STOPPED_SIGNALING_MESSAGE_TYPE = "stoppedTyping"
private const val CALL_STARTED_ID = -2
private const val MILISEC_15: Long = 15
+ private const val LINEBREAK = "\n"
}
}
diff --git a/app/src/main/java/com/nextcloud/talk/activities/FullScreenImageActivity.kt b/app/src/main/java/com/nextcloud/talk/fullscreenfile/FullScreenImageActivity.kt
similarity index 75%
rename from app/src/main/java/com/nextcloud/talk/activities/FullScreenImageActivity.kt
rename to app/src/main/java/com/nextcloud/talk/fullscreenfile/FullScreenImageActivity.kt
index 6c6365e63..ccdfec5a9 100644
--- a/app/src/main/java/com/nextcloud/talk/activities/FullScreenImageActivity.kt
+++ b/app/src/main/java/com/nextcloud/talk/fullscreenfile/FullScreenImageActivity.kt
@@ -24,10 +24,8 @@
* along with this program. If not, see .
*/
-package com.nextcloud.talk.activities
+package com.nextcloud.talk.fullscreenfile
-import android.annotation.SuppressLint
-import android.content.DialogInterface
import android.content.Intent
import android.os.Bundle
import android.util.Log
@@ -35,7 +33,6 @@ import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup.MarginLayoutParams
-import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.FileProvider
import androidx.core.view.ViewCompat
@@ -44,28 +41,25 @@ import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat
import androidx.core.view.updateLayoutParams
import androidx.core.view.updatePadding
-import androidx.work.Data
-import androidx.work.OneTimeWorkRequest
-import androidx.work.WorkInfo
-import androidx.work.WorkManager
+import androidx.fragment.app.DialogFragment
+import autodagger.AutoInjector
import com.google.android.material.snackbar.Snackbar
import com.nextcloud.talk.BuildConfig
import com.nextcloud.talk.R
+import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.databinding.ActivityFullScreenImageBinding
-import com.nextcloud.talk.jobs.SaveFileToStorageWorker
-import com.nextcloud.talk.ui.theme.ViewThemeUtils
+import com.nextcloud.talk.ui.dialog.SaveToStorageDialogFragment
import com.nextcloud.talk.utils.BitmapShrinker
import com.nextcloud.talk.utils.Mimetype.IMAGE_PREFIX_GENERIC
import pl.droidsonroids.gif.GifDrawable
import java.io.File
-import java.util.concurrent.ExecutionException
+@AutoInjector(NextcloudTalkApplication::class)
class FullScreenImageActivity : AppCompatActivity() {
lateinit var binding: ActivityFullScreenImageBinding
private lateinit var windowInsetsController: WindowInsetsControllerCompat
private lateinit var path: String
private var showFullscreen = false
- lateinit var viewThemeUtils: ViewThemeUtils
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_preview, menu)
@@ -98,7 +92,13 @@ class FullScreenImageActivity : AppCompatActivity() {
}
R.id.save -> {
- showWarningDialog()
+ val saveFragment: DialogFragment = SaveToStorageDialogFragment.newInstance(
+ intent.getStringExtra("FILE_NAME").toString()
+ )
+ saveFragment.show(
+ supportFragmentManager,
+ SaveToStorageDialogFragment.TAG
+ )
true
}
@@ -108,24 +108,9 @@ class FullScreenImageActivity : AppCompatActivity() {
}
}
- private fun showWarningDialog() {
- val builder = AlertDialog.Builder(this)
- builder.setTitle(R.string.nc_dialog_save_to_storage_title)
- builder.setMessage(R.string.nc_dialog_save_to_storage_content)
- builder.setPositiveButton(R.string.nc_dialog_save_to_storage_yes) { dialog: DialogInterface, which: Int ->
- val fileName = intent.getStringExtra("FILE_NAME").toString()
- saveImageToStorage(fileName)
- dialog.dismiss()
- }
- builder.setNegativeButton(R.string.nc_dialog_save_to_storage_no) { dialog: DialogInterface, which: Int ->
- dialog.dismiss()
- }
- val dialog = builder.create()
- dialog.show()
- }
-
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+ NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
binding = ActivityFullScreenImageBinding.inflate(layoutInflater)
setContentView(binding.root)
@@ -222,38 +207,6 @@ class FullScreenImageActivity : AppCompatActivity() {
}
}
- @SuppressLint("LongLogTag")
- private fun saveImageToStorage(
- fileName: String
- ) {
- val sourceFilePath = applicationContext.cacheDir.path
-
- val workers = WorkManager.getInstance(this).getWorkInfosByTag(fileName)
- try {
- for (workInfo in workers.get()) {
- if (workInfo.state == WorkInfo.State.RUNNING || workInfo.state == WorkInfo.State.ENQUEUED) {
- return
- }
- }
- } catch (e: ExecutionException) {
- Log.e(TAG, "Error when checking if worker already exists", e)
- } catch (e: InterruptedException) {
- Log.e(TAG, "Error when checking if worker already exists", e)
- }
-
- val data: Data = Data.Builder()
- .putString(SaveFileToStorageWorker.KEY_FILE_NAME, fileName)
- .putString(SaveFileToStorageWorker.KEY_SOURCE_FILE_PATH, "$sourceFilePath/$fileName")
- .build()
-
- val saveWorker: OneTimeWorkRequest = OneTimeWorkRequest.Builder(SaveFileToStorageWorker::class.java)
- .setInputData(data)
- .addTag(fileName)
- .build()
-
- WorkManager.getInstance().enqueue(saveWorker)
- }
-
companion object {
private const val TAG = "FullScreenImageActivity"
private const val HUNDRED_MB = 100 * 1024 * 1024
diff --git a/app/src/main/java/com/nextcloud/talk/activities/FullScreenMediaActivity.kt b/app/src/main/java/com/nextcloud/talk/fullscreenfile/FullScreenMediaActivity.kt
similarity index 93%
rename from app/src/main/java/com/nextcloud/talk/activities/FullScreenMediaActivity.kt
rename to app/src/main/java/com/nextcloud/talk/fullscreenfile/FullScreenMediaActivity.kt
index 6d9f9262d..1d6796b52 100644
--- a/app/src/main/java/com/nextcloud/talk/activities/FullScreenMediaActivity.kt
+++ b/app/src/main/java/com/nextcloud/talk/fullscreenfile/FullScreenMediaActivity.kt
@@ -24,7 +24,7 @@
* along with this program. If not, see .
*/
-package com.nextcloud.talk.activities
+package com.nextcloud.talk.fullscreenfile
import android.content.Intent
import android.os.Bundle
@@ -43,6 +43,7 @@ import androidx.core.view.WindowInsetsControllerCompat
import androidx.core.view.marginBottom
import androidx.core.view.updateLayoutParams
import androidx.core.view.updatePadding
+import androidx.fragment.app.DialogFragment
import androidx.media3.common.MediaItem
import androidx.media3.common.util.UnstableApi
import androidx.media3.exoplayer.ExoPlayer
@@ -53,6 +54,7 @@ import com.nextcloud.talk.BuildConfig
import com.nextcloud.talk.R
import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.databinding.ActivityFullScreenMediaBinding
+import com.nextcloud.talk.ui.dialog.SaveToStorageDialogFragment
import com.nextcloud.talk.utils.Mimetype.VIDEO_PREFIX_GENERIC
import java.io.File
@@ -78,6 +80,7 @@ class FullScreenMediaActivity : AppCompatActivity() {
onBackPressedDispatcher.onBackPressed()
true
}
+
R.id.share -> {
val shareUri = FileProvider.getUriForFile(
this,
@@ -95,6 +98,18 @@ class FullScreenMediaActivity : AppCompatActivity() {
true
}
+
+ R.id.save -> {
+ val saveFragment: DialogFragment = SaveToStorageDialogFragment.newInstance(
+ intent.getStringExtra("FILE_NAME").toString()
+ )
+ saveFragment.show(
+ supportFragmentManager,
+ SaveToStorageDialogFragment.TAG
+ )
+ true
+ }
+
else -> {
super.onOptionsItemSelected(item)
}
diff --git a/app/src/main/java/com/nextcloud/talk/activities/FullScreenTextViewerActivity.kt b/app/src/main/java/com/nextcloud/talk/fullscreenfile/FullScreenTextViewerActivity.kt
similarity index 71%
rename from app/src/main/java/com/nextcloud/talk/activities/FullScreenTextViewerActivity.kt
rename to app/src/main/java/com/nextcloud/talk/fullscreenfile/FullScreenTextViewerActivity.kt
index 00d17b7d5..d78ff54c3 100644
--- a/app/src/main/java/com/nextcloud/talk/activities/FullScreenTextViewerActivity.kt
+++ b/app/src/main/java/com/nextcloud/talk/fullscreenfile/FullScreenTextViewerActivity.kt
@@ -22,7 +22,7 @@
* along with this program. If not, see .
*/
-package com.nextcloud.talk.activities
+package com.nextcloud.talk.fullscreenfile
import android.content.Intent
import android.os.Bundle
@@ -31,11 +31,13 @@ import android.view.MenuItem
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.FileProvider
import androidx.core.content.res.ResourcesCompat
+import androidx.fragment.app.DialogFragment
import autodagger.AutoInjector
import com.nextcloud.talk.BuildConfig
import com.nextcloud.talk.R
import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.databinding.ActivityFullScreenTextBinding
+import com.nextcloud.talk.ui.dialog.SaveToStorageDialogFragment
import com.nextcloud.talk.ui.theme.ViewThemeUtils
import com.nextcloud.talk.utils.DisplayUtils
import com.nextcloud.talk.utils.Mimetype.TEXT_PREFIX_GENERIC
@@ -58,27 +60,44 @@ class FullScreenTextViewerActivity : AppCompatActivity() {
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
- return if (item.itemId == android.R.id.home) {
- onBackPressedDispatcher.onBackPressed()
- true
- } else if (item.itemId == R.id.share) {
- val shareUri = FileProvider.getUriForFile(
- this,
- BuildConfig.APPLICATION_ID,
- File(path)
- )
-
- val shareIntent: Intent = Intent().apply {
- action = Intent.ACTION_SEND
- putExtra(Intent.EXTRA_STREAM, shareUri)
- type = TEXT_PREFIX_GENERIC
- addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
+ return when (item.itemId) {
+ android.R.id.home -> {
+ onBackPressedDispatcher.onBackPressed()
+ true
}
- startActivity(Intent.createChooser(shareIntent, resources.getText(R.string.send_to)))
- true
- } else {
- super.onOptionsItemSelected(item)
+ R.id.share -> {
+ val shareUri = FileProvider.getUriForFile(
+ this,
+ BuildConfig.APPLICATION_ID,
+ File(path)
+ )
+
+ val shareIntent: Intent = Intent().apply {
+ action = Intent.ACTION_SEND
+ putExtra(Intent.EXTRA_STREAM, shareUri)
+ type = TEXT_PREFIX_GENERIC
+ addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
+ }
+ startActivity(Intent.createChooser(shareIntent, resources.getText(R.string.send_to)))
+
+ true
+ }
+
+ R.id.save -> {
+ val saveFragment: DialogFragment = SaveToStorageDialogFragment.newInstance(
+ intent.getStringExtra("FILE_NAME").toString()
+ )
+ saveFragment.show(
+ supportFragmentManager,
+ SaveToStorageDialogFragment.TAG
+ )
+ true
+ }
+
+ else -> {
+ super.onOptionsItemSelected(item)
+ }
}
}
diff --git a/app/src/main/java/com/nextcloud/talk/jobs/SaveFileToStorageWorker.kt b/app/src/main/java/com/nextcloud/talk/jobs/SaveFileToStorageWorker.kt
index 29f702955..c2c90c551 100644
--- a/app/src/main/java/com/nextcloud/talk/jobs/SaveFileToStorageWorker.kt
+++ b/app/src/main/java/com/nextcloud/talk/jobs/SaveFileToStorageWorker.kt
@@ -1,10 +1,10 @@
/*
* Nextcloud Talk application
*
- * @author Andy Scherzinger
+ * @author Fariba Khandani
* @author Marcel Hibbe
- * Copyright (C) 2022 Andy Scherzinger
- * Copyright (C) 2021 Marcel Hibbe
+ * Copyright (C) 2023 Fariba Khandani
+ * Copyright (C) 2023 Marcel Hibbe
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -25,14 +25,23 @@ package com.nextcloud.talk.jobs
import android.content.ContentValues
import android.content.Context
import android.media.MediaScannerConnection
+import android.net.Uri
+import android.os.Build
import android.os.Environment
+import android.os.Handler
+import android.os.Looper
import android.provider.MediaStore
import android.provider.MediaStore.Files.FileColumns
import android.util.Log
+import android.widget.Toast
import androidx.work.Worker
import androidx.work.WorkerParameters
import autodagger.AutoInjector
+import com.nextcloud.talk.R
import com.nextcloud.talk.application.NextcloudTalkApplication
+import com.nextcloud.talk.utils.Mimetype.AUDIO_PREFIX
+import com.nextcloud.talk.utils.Mimetype.IMAGE_PREFIX
+import com.nextcloud.talk.utils.Mimetype.VIDEO_PREFIX
import java.io.File
import java.io.IOException
import java.io.OutputStream
@@ -50,16 +59,22 @@ class SaveFileToStorageWorker(val context: Context, workerParameters: WorkerPara
val contentResolver = context.contentResolver
val mimeType = URLConnection.guessContentTypeFromName(cacheFile.name)
+ val appName = applicationContext.resources!!.getString(R.string.nc_app_product_name)
+
val values = ContentValues().apply {
+ if (mimeType.startsWith(IMAGE_PREFIX) || mimeType.startsWith(VIDEO_PREFIX)) {
+ put(FileColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM + "/" + appName)
+ }
put(FileColumns.DISPLAY_NAME, cacheFile.name)
- put(FileColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS)
+
if (mimeType != null) {
- put(FileColumns.MIME_TYPE, URLConnection.guessContentTypeFromName(cacheFile.name))
+ put(FileColumns.MIME_TYPE, mimeType)
}
}
- val collection = MediaStore.Files.getContentUri("external")
- val uri = contentResolver.insert(collection, values)
+ val collectionUri = getUriByType(mimeType)
+
+ val uri = contentResolver.insert(collectionUri, values)
uri?.let { fileUri ->
try {
@@ -79,16 +94,53 @@ class SaveFileToStorageWorker(val context: Context, workerParameters: WorkerPara
// Notify the media scanner about the new file
MediaScannerConnection.scanFile(context, arrayOf(cacheFile.absolutePath), null, null)
+ Handler(Looper.getMainLooper()).post {
+ Toast.makeText(
+ context,
+ context.resources.getString(R.string.nc_save_success),
+ Toast.LENGTH_SHORT
+ ).show()
+ }
+
return Result.success()
} catch (e: IOException) {
Log.e(TAG, "Something went wrong when trying to save file to internal storage", e)
+ Handler(Looper.getMainLooper()).post {
+ Toast.makeText(
+ context,
+ context.resources.getString(R.string.nc_common_error_sorry),
+ Toast.LENGTH_SHORT
+ ).show()
+ }
+
return Result.failure()
} catch (e: NullPointerException) {
Log.e(TAG, "Something went wrong when trying to save file to internal storage", e)
+ Handler(Looper.getMainLooper()).post {
+ Toast.makeText(
+ context,
+ context.resources.getString(R.string.nc_common_error_sorry),
+ Toast.LENGTH_SHORT
+ ).show()
+ }
+
return Result.failure()
}
}
+ private fun getUriByType(mimeType: String): Uri {
+ return when {
+ mimeType.startsWith(VIDEO_PREFIX) -> MediaStore.Video.Media.EXTERNAL_CONTENT_URI
+ mimeType.startsWith(AUDIO_PREFIX) -> MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
+ mimeType.startsWith(IMAGE_PREFIX) -> MediaStore.Images.Media.EXTERNAL_CONTENT_URI
+ else -> if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
+ Uri.fromFile(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS))
+ } else {
+ MediaStore.Downloads.EXTERNAL_CONTENT_URI
+ }
+ }
+ }
+
companion object {
private val TAG = SaveFileToStorageWorker::class.java.simpleName
const val KEY_FILE_NAME = "KEY_FILE_NAME"
diff --git a/app/src/main/java/com/nextcloud/talk/ui/dialog/SaveToStorageDialogFragment.kt b/app/src/main/java/com/nextcloud/talk/ui/dialog/SaveToStorageDialogFragment.kt
new file mode 100644
index 000000000..c429e9466
--- /dev/null
+++ b/app/src/main/java/com/nextcloud/talk/ui/dialog/SaveToStorageDialogFragment.kt
@@ -0,0 +1,155 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Marcel Hibbe
+ * @author Fariba Khandani
+ * Copyright (C) 2023 Marcel Hibbe (dev@mhibbe.de)
+ * Copyright (C) 2023 Fariba Khandani
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.nextcloud.talk.ui.dialog
+
+import android.annotation.SuppressLint
+import android.app.Dialog
+import android.content.DialogInterface
+import android.os.Bundle
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.appcompat.app.AlertDialog
+import androidx.fragment.app.DialogFragment
+import androidx.work.Data
+import androidx.work.OneTimeWorkRequest
+import androidx.work.WorkInfo
+import androidx.work.WorkManager
+import autodagger.AutoInjector
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import com.nextcloud.talk.R
+import com.nextcloud.talk.application.NextcloudTalkApplication
+import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
+import com.nextcloud.talk.databinding.DialogChooseAccountShareToBinding
+import com.nextcloud.talk.jobs.SaveFileToStorageWorker
+import com.nextcloud.talk.ui.theme.ViewThemeUtils
+import java.util.concurrent.ExecutionException
+import javax.inject.Inject
+
+@AutoInjector(NextcloudTalkApplication::class)
+class SaveToStorageDialogFragment : DialogFragment() {
+
+ @Inject
+ lateinit var viewThemeUtils: ViewThemeUtils
+ private var binding: DialogChooseAccountShareToBinding? = null
+ private var dialogView: View? = null
+ lateinit var fileName: String
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ sharedApplication!!.componentApplication.inject(this)
+ fileName = arguments?.getString(KEY_FILE_NAME)!!
+ }
+ override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
+ val dialogText = StringBuilder()
+ dialogText.append(resources.getString(R.string.nc_dialog_save_to_storage_content))
+ dialogText.append("\n")
+ dialogText.append("\n")
+ dialogText.append(resources.getString(R.string.nc_dialog_save_to_storage_continue))
+
+ val dialogBuilder = MaterialAlertDialogBuilder(requireContext())
+ .setTitle(R.string.nc_dialog_save_to_storage_title)
+ .setMessage(dialogText)
+ .setPositiveButton(R.string.nc_dialog_save_to_storage_yes) { _: DialogInterface?, _: Int ->
+ saveImageToStorage(fileName)
+ }
+ .setNegativeButton(R.string.nc_dialog_save_to_storage_no) { _: DialogInterface?, _: Int ->
+ }
+ viewThemeUtils.dialog.colorMaterialAlertDialogBackground(
+ requireContext(),
+ dialogBuilder
+ )
+ val dialog = dialogBuilder.show()
+ viewThemeUtils.platform.colorTextButtons(
+ dialog.getButton(AlertDialog.BUTTON_POSITIVE),
+ dialog.getButton(AlertDialog.BUTTON_NEGATIVE)
+ )
+
+ return dialog
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ themeViews()
+ }
+
+ private fun themeViews() {
+ viewThemeUtils.platform.themeDialog(binding!!.root)
+ }
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
+ return dialogView
+ }
+
+ override fun onDestroyView() {
+ super.onDestroyView()
+ binding = null
+ }
+
+ @SuppressLint("LongLogTag")
+ private fun saveImageToStorage(
+ fileName: String
+ ) {
+ val sourceFilePath = requireContext().cacheDir.path
+ val workerTag = SAVE_TO_STORAGE_WORKER_PREFIX + fileName
+
+ val workers = WorkManager.getInstance(requireContext()).getWorkInfosByTag(workerTag)
+ try {
+ for (workInfo in workers.get()) {
+ if (workInfo.state == WorkInfo.State.RUNNING || workInfo.state == WorkInfo.State.ENQUEUED) {
+ return
+ }
+ }
+ } catch (e: ExecutionException) {
+ Log.e(TAG, "Error when checking if worker already exists", e)
+ } catch (e: InterruptedException) {
+ Log.e(TAG, "Error when checking if worker already exists", e)
+ }
+
+ val data: Data = Data.Builder()
+ .putString(SaveFileToStorageWorker.KEY_FILE_NAME, fileName)
+ .putString(SaveFileToStorageWorker.KEY_SOURCE_FILE_PATH, "$sourceFilePath/$fileName")
+ .build()
+
+ val saveWorker: OneTimeWorkRequest = OneTimeWorkRequest.Builder(SaveFileToStorageWorker::class.java)
+ .setInputData(data)
+ .addTag(workerTag)
+ .build()
+
+ WorkManager.getInstance().enqueue(saveWorker)
+ }
+
+ companion object {
+ val TAG = SaveToStorageDialogFragment::class.java.simpleName
+ private const val KEY_FILE_NAME = "keyFileName"
+ private const val SAVE_TO_STORAGE_WORKER_PREFIX = "saveToStorage_"
+
+ fun newInstance(fileName: String): SaveToStorageDialogFragment {
+ val args = Bundle()
+ args.putString(KEY_FILE_NAME, fileName)
+ val fragment = SaveToStorageDialogFragment()
+ fragment.arguments = args
+ return fragment
+ }
+ }
+}
diff --git a/app/src/main/java/com/nextcloud/talk/utils/FileViewerUtils.kt b/app/src/main/java/com/nextcloud/talk/utils/FileViewerUtils.kt
index af5f636ac..caa66d997 100644
--- a/app/src/main/java/com/nextcloud/talk/utils/FileViewerUtils.kt
+++ b/app/src/main/java/com/nextcloud/talk/utils/FileViewerUtils.kt
@@ -37,9 +37,9 @@ import androidx.work.WorkInfo
import androidx.work.WorkManager
import com.google.android.material.snackbar.Snackbar
import com.nextcloud.talk.R
-import com.nextcloud.talk.activities.FullScreenImageActivity
-import com.nextcloud.talk.activities.FullScreenMediaActivity
-import com.nextcloud.talk.activities.FullScreenTextViewerActivity
+import com.nextcloud.talk.fullscreenfile.FullScreenImageActivity
+import com.nextcloud.talk.fullscreenfile.FullScreenMediaActivity
+import com.nextcloud.talk.fullscreenfile.FullScreenTextViewerActivity
import com.nextcloud.talk.adapters.messages.PreviewMessageViewHolder
import com.nextcloud.talk.data.user.model.User
import com.nextcloud.talk.jobs.DownloadFileToCacheWorker
diff --git a/app/src/main/res/drawable/baseline_download_24.xml b/app/src/main/res/drawable/baseline_download_24.xml
new file mode 100644
index 000000000..e5253209d
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_download_24.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_full_screen_image.xml b/app/src/main/res/layout/activity_full_screen_image.xml
index d7c954011..5e304e925 100644
--- a/app/src/main/res/layout/activity_full_screen_image.xml
+++ b/app/src/main/res/layout/activity_full_screen_image.xml
@@ -28,7 +28,7 @@
android:id="@+id/image_wrapper_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
- tools:context=".activities.FullScreenImageActivity">
+ tools:context=".fullscreenfile.FullScreenImageActivity">
+ tools:context=".fullscreenfile.FullScreenMediaActivity">
+ tools:context=".fullscreenfile.FullScreenTextViewerActivity">
true
- true
- shortEdges
+ - @color/bg_default
-
\ No newline at end of file
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index e673f0da9..dd345ce04 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -51,7 +51,6 @@ How to translate with transifex:
Sorry, something went wrong!
Create
-
Settings
@@ -519,14 +518,14 @@ How to translate with transifex:
Chat via %s
Account not found
- //save feature
+
Save
Save to storage?
- Saving this media to storage will allow any other apps on your device to access it.\nContinue?
+ Saving this media to storage will allow any other apps on your device to access it.
+ Continue?
Yes
No
-
-
+ Saved successfully
Favorite
Status
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 0450185fe..e5aed4879 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -221,6 +221,7 @@
- @color/transparent
- true
- true
+ - @color/bg_default