@@ -4,14 +4,23 @@ import android.content.Intent
44import android.net.Uri
55import android.os.Bundle
66import org.fossify.commons.dialogs.FilePickerDialog
7- import org.fossify.commons.extensions.*
7+ import org.fossify.commons.extensions.getDocumentFile
8+ import org.fossify.commons.extensions.getDoesFilePathExist
9+ import org.fossify.commons.extensions.getFileOutputStreamSync
10+ import org.fossify.commons.extensions.getFilenameFromContentUri
11+ import org.fossify.commons.extensions.getFilenameFromPath
12+ import org.fossify.commons.extensions.getMimeType
13+ import org.fossify.commons.extensions.needsStupidWritePermissions
14+ import org.fossify.commons.extensions.rescanPaths
15+ import org.fossify.commons.extensions.showErrorToast
16+ import org.fossify.commons.extensions.toast
17+ import org.fossify.commons.extensions.viewBinding
818import org.fossify.commons.helpers.NavigationIcon
919import org.fossify.commons.helpers.ensureBackgroundThread
1020import org.fossify.filemanager.R
1121import org.fossify.filemanager.databinding.ActivitySaveAsBinding
1222import org.fossify.filemanager.extensions.config
1323import java.io.File
14- import java.io.IOException
1524
1625class SaveAsActivity : SimpleActivity () {
1726 private val binding by viewBinding(ActivitySaveAsBinding ::inflate)
@@ -34,184 +43,50 @@ class SaveAsActivity : SimpleActivity() {
3443 }
3544
3645 private fun saveAsDialog () {
37- when {
38- intent.action == Intent .ACTION_SEND && intent.extras?.containsKey(Intent .EXTRA_STREAM ) == true -> {
39- handleSingleFile()
40- }
41- intent.action == Intent .ACTION_SEND_MULTIPLE && intent.extras?.containsKey(Intent .EXTRA_STREAM ) == true -> {
42- handleMultipleFiles()
43- }
44- else -> {
45- toast(R .string.unknown_error_occurred)
46- finish()
47- }
48- }
49- }
50-
51- private fun handleSingleFile () {
52- FilePickerDialog (this , pickFile = false , showHidden = config.shouldShowHidden(), showFAB = true , showFavoritesButton = true ) {
53- val destination = it
54- handleSAFDialog(destination) {
55- toast(R .string.saving)
56- ensureBackgroundThread {
57- try {
58- createDestinationIfNeeded(destination)
59-
60- val source = intent.getParcelableExtra<Uri >(Intent .EXTRA_STREAM )!!
61- val originalFilename = getFilenameFromContentUri(source)
62- ? : source.toString().getFilenameFromPath()
63- val filename = sanitizeFilename(originalFilename)
64- val mimeType = contentResolver.getType(source)
65- ? : intent.type?.takeIf { it != " */*" }
66- ? : filename.getMimeType()
67- val inputStream = contentResolver.openInputStream(source)
68-
69- val destinationPath = getAvailablePath(" $destination /$filename " )
70- val outputStream = getFileOutputStreamSync(destinationPath, mimeType, null )!!
71- inputStream!! .copyTo(outputStream)
72- rescanPaths(arrayListOf (destinationPath))
73- toast(R .string.file_saved)
74- finish()
75- } catch (e: IOException ) {
76- showErrorToast(e)
77- finish()
78- } catch (e: SecurityException ) {
79- showErrorToast(e)
80- finish()
46+ if (intent.action == Intent .ACTION_SEND && intent.extras?.containsKey(Intent .EXTRA_STREAM ) == true ) {
47+ FilePickerDialog (this , pickFile = false , showHidden = config.shouldShowHidden(), showFAB = true , showFavoritesButton = true ) {
48+ val destination = it
49+ handleSAFDialog(destination) {
50+ toast(R .string.saving)
51+ ensureBackgroundThread {
52+ try {
53+ if (! getDoesFilePathExist(destination)) {
54+ if (needsStupidWritePermissions(destination)) {
55+ val document = getDocumentFile(destination)
56+ document!! .createDirectory(destination.getFilenameFromPath())
57+ } else {
58+ File (destination).mkdirs()
59+ }
60+ }
61+
62+ val source = intent.getParcelableExtra<Uri >(Intent .EXTRA_STREAM )!!
63+ val originalFilename = getFilenameFromContentUri(source)
64+ ? : source.toString().getFilenameFromPath()
65+ val filename = sanitizeFilename(originalFilename)
66+ val mimeType = contentResolver.getType(source)
67+ ? : intent.type?.takeIf { it != " */*" }
68+ ? : filename.getMimeType()
69+ val inputStream = contentResolver.openInputStream(source)
70+
71+ val destinationPath = getAvailablePath(" $destination /$filename " )
72+ val outputStream = getFileOutputStreamSync(destinationPath, mimeType, null )!!
73+ inputStream!! .copyTo(outputStream)
74+ rescanPaths(arrayListOf (destinationPath))
75+ toast(R .string.file_saved)
76+ finish()
77+ } catch (e: Exception ) {
78+ showErrorToast(e)
79+ finish()
80+ }
8181 }
8282 }
8383 }
84- }
85- }
86-
87- private fun handleMultipleFiles () {
88- FilePickerDialog (this , pickFile = false , showHidden = config.shouldShowHidden(), showFAB = true , showFavoritesButton = true ) { destination ->
89- handleSAFDialog(destination) {
90- toast(R .string.saving)
91- ensureBackgroundThread {
92- processMultipleFiles(destination)
93- }
94- }
95- }
96- }
97-
98- private fun processMultipleFiles (destination : String ) {
99- try {
100- createDestinationIfNeeded(destination)
101-
102- val uriList = intent.getParcelableArrayListExtra<Uri >(Intent .EXTRA_STREAM )
103- if (uriList.isNullOrEmpty()) {
104- runOnUiThread {
105- toast(R .string.no_items_found)
106- finish()
107- }
108- return
109- }
110-
111- val result = saveAllFiles(destination, uriList)
112- showFinalResult(result)
113- } catch (e: IOException ) {
114- runOnUiThread {
115- showErrorToast(e)
116- finish()
117- }
118- } catch (e: SecurityException ) {
119- runOnUiThread {
120- showErrorToast(e)
121- finish()
122- }
123- }
124- }
125-
126- private fun saveAllFiles (destination : String , uriList : ArrayList <Uri >): SaveResult {
127- val mimeTypes = intent.getStringArrayListExtra(Intent .EXTRA_MIME_TYPES )
128- val savedPaths = mutableListOf<String >()
129- var successCount = 0
130- var errorCount = 0
131-
132- for ((index, source) in uriList.withIndex()) {
133- if (saveSingleFileItem(destination, source, index, mimeTypes)) {
134- successCount++
135- savedPaths.add(destination)
136- } else {
137- errorCount++
138- }
139- }
140-
141- if (savedPaths.isNotEmpty()) {
142- rescanPaths(ArrayList (savedPaths))
143- }
144-
145- return SaveResult (successCount, errorCount)
146- }
147-
148- private fun saveSingleFileItem (
149- destination : String ,
150- source : Uri ,
151- index : Int ,
152- mimeTypes : ArrayList <String >? ): Boolean {
153- return try {
154- val originalFilename = getFilenameFromContentUri(source)
155- ? : source.toString().getFilenameFromPath()
156- val filename = sanitizeFilename(originalFilename)
157-
158- val mimeType = contentResolver.getType(source)
159- ? : mimeTypes?.getOrNull(index)?.takeIf { it != " */*" }
160- ? : intent.type?.takeIf { it != " */*" }
161- ? : filename.getMimeType()
162-
163- val inputStream = contentResolver.openInputStream(source)
164- ? : throw IOException (getString(R .string.error, source))
165-
166- val destinationPath = getAvailablePath(" $destination /$filename " )
167- val outputStream = getFileOutputStreamSync(destinationPath, mimeType, null )
168- ? : throw IOException (getString(R .string.error, source))
169-
170- inputStream.use { input ->
171- outputStream.use { output ->
172- input.copyTo(output)
173- }
174- }
175- true
176- } catch (e: IOException ) {
177- showErrorToast(e)
178- false
179- } catch (e: SecurityException ) {
180- showErrorToast(e)
181- false
182- }
183- }
184-
185- private fun showFinalResult (result : SaveResult ) {
186- runOnUiThread {
187- when {
188- result.successCount > 0 && result.errorCount == 0 -> {
189- val message = resources.getQuantityString(R .plurals.files_saved,result.successCount)
190- toast(message)
191- }
192- result.successCount > 0 && result.errorCount > 0 -> {
193- toast(getString(R .string.files_saved_partially))
194- }
195- else -> {
196- toast(R .string.error)
197- }
198- }
84+ } else {
85+ toast(R .string.unknown_error_occurred)
19986 finish()
20087 }
20188 }
20289
203- private data class SaveResult (val successCount : Int , val errorCount : Int )
204- private fun createDestinationIfNeeded (destination : String ) {
205- if (! getDoesFilePathExist(destination)) {
206- if (needsStupidWritePermissions(destination)) {
207- val document = getDocumentFile(destination)
208- document!! .createDirectory(destination.getFilenameFromPath())
209- } else {
210- File (destination).mkdirs()
211- }
212- }
213- }
214-
21590 override fun onResume () {
21691 super .onResume()
21792 setupTopAppBar(binding.activitySaveAsAppbar, NavigationIcon .Arrow )
0 commit comments