tweaking some file related operations

This commit is contained in:
tibbi 2017-03-12 21:27:45 +01:00
parent 8ebdc91649
commit a5bac9311e
12 changed files with 140 additions and 232 deletions

View file

@ -32,7 +32,7 @@ android {
} }
dependencies { dependencies {
compile 'com.simplemobiletools:commons:2.9.9' compile 'com.simplemobiletools:commons:2.10.5'
compile 'com.davemorrissey.labs:subsampling-scale-image-view:3.6.0' compile 'com.davemorrissey.labs:subsampling-scale-image-view:3.6.0'
compile 'com.theartofdev.edmodo:android-image-cropper:2.3.1' compile 'com.theartofdev.edmodo:android-image-cropper:2.3.1'
compile 'com.bignerdranch.android:recyclerview-multiselect:0.2' compile 'com.bignerdranch.android:recyclerview-multiselect:0.2'

View file

@ -122,21 +122,30 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
private fun saveBitmapToFile(bitmap: Bitmap, path: String) { private fun saveBitmapToFile(bitmap: Bitmap, path: String) {
val file = File(path) val file = File(path)
var out: OutputStream? = null
try { try {
if (needsStupidWritePermissions(path)) { if (needsStupidWritePermissions(path)) {
if (isShowingPermDialog(file)) handleSAFDialog(file) {
return var document = getFileDocument(path, config.treeUri) ?: return@handleSAFDialog
var document = getFileDocument(path, config.treeUri) ?: return
if (!file.exists()) { if (!file.exists()) {
document = document.createFile("", file.name) document = document.createFile("", file.name)
} }
out = contentResolver.openOutputStream(document.uri) val out = contentResolver.openOutputStream(document.uri)
saveBitmap(file, bitmap, out)
}
} else { } else {
out = FileOutputStream(file) val out = FileOutputStream(file)
saveBitmap(file, bitmap, out)
}
} catch (e: Exception) {
Log.e(TAG, "Crop compressing failed $path $e")
toast(R.string.image_editing_failed)
finish()
} catch (e: OutOfMemoryError) {
toast(R.string.out_of_memory_error)
}
} }
private fun saveBitmap(file: File, bitmap: Bitmap, out: OutputStream) {
if (resizeWidth > 0 && resizeHeight > 0) { if (resizeWidth > 0 && resizeHeight > 0) {
val resized = Bitmap.createScaledBitmap(bitmap, resizeWidth, resizeHeight, false) val resized = Bitmap.createScaledBitmap(bitmap, resizeWidth, resizeHeight, false)
resized.compress(file.getCompressionFormat(), 90, out) resized.compress(file.getCompressionFormat(), 90, out)
@ -144,16 +153,11 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
bitmap.compress(file.getCompressionFormat(), 90, out) bitmap.compress(file.getCompressionFormat(), 90, out)
} }
setResult(Activity.RESULT_OK, intent) setResult(Activity.RESULT_OK, intent)
} catch (e: Exception) { scanFinalPath(file.absolutePath)
Log.e(TAG, "Crop compressing failed $path $e") out.close()
toast(R.string.image_editing_failed)
finish()
} catch (e: OutOfMemoryError) {
toast(R.string.out_of_memory_error)
} finally {
out?.close()
} }
private fun scanFinalPath(path: String) {
scanPath(path) { scanPath(path) {
setResult(Activity.RESULT_OK, intent) setResult(Activity.RESULT_OK, intent)
runOnUiThread { runOnUiThread {

View file

@ -19,13 +19,15 @@ import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.adapters.DirectoryAdapter import com.simplemobiletools.gallery.adapters.DirectoryAdapter
import com.simplemobiletools.gallery.asynctasks.GetDirectoriesAsynctask import com.simplemobiletools.gallery.asynctasks.GetDirectoriesAsynctask
import com.simplemobiletools.gallery.dialogs.ChangeSortingDialog import com.simplemobiletools.gallery.dialogs.ChangeSortingDialog
import com.simplemobiletools.gallery.extensions.* import com.simplemobiletools.gallery.extensions.config
import com.simplemobiletools.gallery.extensions.launchAbout
import com.simplemobiletools.gallery.extensions.launchCamera
import com.simplemobiletools.gallery.extensions.launchSettings
import com.simplemobiletools.gallery.helpers.* import com.simplemobiletools.gallery.helpers.*
import com.simplemobiletools.gallery.models.Directory import com.simplemobiletools.gallery.models.Directory
import com.simplemobiletools.gallery.views.MyScalableRecyclerView import com.simplemobiletools.gallery.views.MyScalableRecyclerView
import kotlinx.android.synthetic.main.activity_main.* import kotlinx.android.synthetic.main.activity_main.*
import java.io.File import java.io.File
import java.net.URLDecoder
import java.util.* import java.util.*
class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener { class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
@ -181,46 +183,16 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
} }
} }
override fun deleteFiles(paths: ArrayList<String>) { override fun tryDeleteFolders(folders: ArrayList<File>) {
val updatedFiles = ArrayList<File>() for (file in folders) {
for (delPath in paths) { deleteFolders(folders) {
val dir = File(delPath) runOnUiThread {
if (dir.exists()) { refreshItems()
val files = dir.listFiles() ?: continue
files.forEach {
if (it.isFile && it.isImageVideoGif()) {
updatedFiles.add(it)
deleteItem(it)
} }
} }
updatedFiles.add(dir)
if (dir.listFiles().isEmpty())
deleteItem(dir)
} }
} }
scanFiles(updatedFiles) {}
}
private fun deleteItem(file: File) {
if (isShowingPermDialog(file)) {
return
}
Thread({
if (!file.delete()) {
val document = getFileDocument(file.absolutePath, config.treeUri) ?: return@Thread
// double check we have the uri to the proper file path, not some parent folder
val uri = URLDecoder.decode(document.uri.toString(), "UTF-8")
val filename = URLDecoder.decode(file.absolutePath.getFilenameFromPath(), "UTF-8")
if (uri.endsWith(filename)) {
document.delete()
}
}
}).start()
}
private fun handleZooming() { private fun handleZooming() {
val layoutManager = directories_grid.layoutManager as GridLayoutManager val layoutManager = directories_grid.layoutManager as GridLayoutManager
layoutManager.spanCount = config.dirColumnCnt layoutManager.spanCount = config.dirColumnCnt

View file

@ -29,7 +29,6 @@ import com.simplemobiletools.gallery.views.MyScalableRecyclerView
import kotlinx.android.synthetic.main.activity_media.* import kotlinx.android.synthetic.main.activity_media.*
import java.io.File import java.io.File
import java.io.IOException import java.io.IOException
import java.util.*
class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener { class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
private val TAG = MediaActivity::class.java.simpleName private val TAG = MediaActivity::class.java.simpleName
@ -268,34 +267,17 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
} }
override fun deleteFiles(files: ArrayList<File>) { override fun deleteFiles(files: ArrayList<File>) {
if (isShowingPermDialog(files[0])) { val filtered = files.filter { it.exists() && it.isImageVideoGif() } as ArrayList
return deleteFiles(filtered) {
} if (!it) {
Thread({
var hadSuccess = false
files.filter { it.exists() && it.isImageVideoGif() }
.forEach {
if (it.delete() || tryFastDocumentDelete(it)) {
hadSuccess = true
} else {
val document = getFileDocument(it.absolutePath, config.treeUri) ?: return@forEach
if (document.isFile && document.delete()) {
hadSuccess = true
}
}
deleteFromMediaStore(it)
}
if (!hadSuccess)
runOnUiThread { runOnUiThread {
toast(R.string.unknown_error_occurred) toast(R.string.unknown_error_occurred)
} }
}).start() } else if (mMedia.isEmpty()) {
if (mMedia.isEmpty()) {
finish() finish()
} }
} }
}
private fun isSetWallpaperIntent() = intent.getBooleanExtra(SET_WALLPAPER_INTENT, false) private fun isSetWallpaperIntent() = intent.getBooleanExtra(SET_WALLPAPER_INTENT, false)

View file

@ -189,7 +189,6 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
private fun saveImageAs() { private fun saveImageAs() {
val currPath = getCurrentMedium()!!.path val currPath = getCurrentMedium()!!.path
SaveAsDialog(this, currPath) { SaveAsDialog(this, currPath) {
var out: OutputStream? = null
try { try {
val file = File(it) val file = File(it)
if (file.exists()) { if (file.exists()) {
@ -197,36 +196,38 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
return@SaveAsDialog return@SaveAsDialog
} }
var bitmap = BitmapFactory.decodeFile(currPath) val bitmap = BitmapFactory.decodeFile(currPath)
if (needsStupidWritePermissions(it)) { if (needsStupidWritePermissions(it)) {
if (isShowingPermDialog(file)) handleSAFDialog(file) {
return@SaveAsDialog var document = getFileDocument(it, config.treeUri) ?: return@handleSAFDialog
var document = getFileDocument(it, config.treeUri) ?: return@SaveAsDialog
if (!file.exists()) { if (!file.exists()) {
document = document.createFile("", file.name) document = document.createFile("", file.name)
} }
out = contentResolver.openOutputStream(document.uri) val out = contentResolver.openOutputStream(document.uri)
} else { saveFile(file, bitmap, out)
out = FileOutputStream(file) }
} else {
val out = FileOutputStream(file)
saveFile(file, bitmap, out)
} }
val matrix = Matrix()
matrix.postRotate(mRotationDegrees)
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
bitmap.compress(file.getCompressionFormat(), 90, out)
out?.flush()
toast(R.string.file_saved)
} catch (e: OutOfMemoryError) { } catch (e: OutOfMemoryError) {
toast(R.string.out_of_memory_error) toast(R.string.out_of_memory_error)
} catch (e: Exception) { } catch (e: Exception) {
toast(R.string.unknown_error_occurred) toast(R.string.unknown_error_occurred)
} finally {
out?.close()
} }
} }
} }
private fun saveFile(file: File, bitmap: Bitmap, out: OutputStream) {
val matrix = Matrix()
matrix.postRotate(mRotationDegrees)
val bmp = Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
bmp.compress(file.getCompressionFormat(), 90, out)
out.flush()
toast(R.string.file_saved)
out.close()
}
private fun rotateImage(degrees: Float) { private fun rotateImage(degrees: Float) {
mRotationDegrees = (mRotationDegrees + degrees) % 360 mRotationDegrees = (mRotationDegrees + degrees) % 360
getCurrentFragment()?.rotateImageViewBy(mRotationDegrees) getCurrentFragment()?.rotateImageViewBy(mRotationDegrees)
@ -319,36 +320,10 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
private fun askConfirmDelete() { private fun askConfirmDelete() {
ConfirmationDialog(this) { ConfirmationDialog(this) {
deleteFile() deleteFileBg(File(mMedia[mPos].path)) {
}
}
private fun deleteFile() {
val file = File(mMedia[mPos].path)
if (isShowingPermDialog(file)) {
return
}
Thread {
if (!file.delete() && !tryFastDocumentDelete(file)) {
val document = getFileDocument(file.absolutePath, config.treeUri) ?: return@Thread
if (!document.isFile || !document.delete()) {
runOnUiThread {
toast(R.string.unknown_error_occurred)
}
return@Thread
}
}
if (deleteFromMediaStore(file)) {
reloadViewPager()
} else {
scanFile(file) {
reloadViewPager() reloadViewPager()
} }
} }
}.start()
} }
private fun isDirEmpty(): Boolean { private fun isDirEmpty(): Boolean {

View file

@ -273,30 +273,30 @@ class DirectoryAdapter(val activity: SimpleActivity, val dirs: MutableList<Direc
private fun deleteFiles() { private fun deleteFiles() {
val selections = multiSelector.selectedPositions val selections = multiSelector.selectedPositions
val paths = ArrayList<String>(selections.size) val folders = ArrayList<File>(selections.size)
val removeDirs = ArrayList<Directory>(selections.size) val removeFolders = ArrayList<Directory>(selections.size)
var isShowingPermDialog = false var needPermissionForPath = ""
activity.runOnUiThread { selections.forEach {
if (activity.isShowingPermDialog(File(dirs[selections[0]].path))) { val path = dirs[it].path
isShowingPermDialog = true if (activity.needsStupidWritePermissions(path) && activity.config.treeUri.isEmpty()) {
needPermissionForPath = path
} }
} }
if (isShowingPermDialog) activity.handleSAFDialog(File(needPermissionForPath)) {
return
selections.reverse() selections.reverse()
selections.forEach { selections.forEach {
val directory = dirs[it] val directory = dirs[it]
paths.add(directory.path) folders.add(File(directory.path))
removeDirs.add(directory) removeFolders.add(directory)
notifyItemRemoved(it) notifyItemRemoved(it)
} }
dirs.removeAll(removeDirs) dirs.removeAll(removeFolders)
markedItems.clear() markedItems.clear()
listener?.deleteFiles(paths) listener?.tryDeleteFolders(folders)
}
} }
private fun getSelectedPaths(): HashSet<String> { private fun getSelectedPaths(): HashSet<String> {
@ -387,6 +387,6 @@ class DirectoryAdapter(val activity: SimpleActivity, val dirs: MutableList<Direc
interface DirOperationsListener { interface DirOperationsListener {
fun refreshItems() fun refreshItems()
fun deleteFiles(paths: ArrayList<String>) fun tryDeleteFolders(folders: ArrayList<File>)
} }
} }

View file

@ -190,16 +190,7 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList<Medium>,
val files = ArrayList<File>(selections.size) val files = ArrayList<File>(selections.size)
val removeMedia = ArrayList<Medium>(selections.size) val removeMedia = ArrayList<Medium>(selections.size)
var isShowingPermDialog = false activity.handleSAFDialog(File(media[selections[0]].path)) {
activity.runOnUiThread {
if (activity.isShowingPermDialog(File(media[selections[0]].path))) {
isShowingPermDialog = true
}
}
if (isShowingPermDialog)
return
selections.reverse() selections.reverse()
selections.forEach { selections.forEach {
val medium = media[it] val medium = media[it]
@ -212,6 +203,7 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList<Medium>,
markedItems.clear() markedItems.clear()
listener?.deleteFiles(files) listener?.deleteFiles(files)
} }
}
private fun getSelectedMedia(): List<Medium> { private fun getSelectedMedia(): List<Medium> {
val positions = multiSelector.selectedPositions val positions = multiSelector.selectedPositions

View file

@ -59,25 +59,20 @@ class CopyDialog(val activity: SimpleActivity, val files: ArrayList<File>, val c
} }
} }
if (activity.isShowingPermDialog(destinationDir)) { activity.handleSAFDialog(destinationDir) {
return@setOnClickListener
}
if (view.dialog_radio_group.checkedRadioButtonId == R.id.dialog_radio_copy) { if (view.dialog_radio_group.checkedRadioButtonId == R.id.dialog_radio_copy) {
context.toast(R.string.copying) context.toast(R.string.copying)
val pair = Pair<ArrayList<File>, File>(files, destinationDir) val pair = Pair<ArrayList<File>, File>(files, destinationDir)
CopyMoveTask(context, false, context.config.treeUri, true, copyMoveListener).execute(pair) CopyMoveTask(activity, false, context.config.treeUri, true, copyMoveListener).execute(pair)
dismiss() dismiss()
} else { } else {
if (context.isPathOnSD(sourcePath) || context.isPathOnSD(destinationPath)) { if (context.isPathOnSD(sourcePath) || context.isPathOnSD(destinationPath)) {
if (activity.isShowingPermDialog(files[0])) { activity.handleSAFDialog(files[0]) {
return@setOnClickListener
}
context.toast(R.string.moving) context.toast(R.string.moving)
val pair = Pair<ArrayList<File>, File>(files, destinationDir) val pair = Pair<ArrayList<File>, File>(files, destinationDir)
CopyMoveTask(context, true, context.config.treeUri, true, copyMoveListener).execute(pair) CopyMoveTask(activity, true, context.config.treeUri, true, copyMoveListener).execute(pair)
dismiss() dismiss()
}
} else { } else {
val updatedFiles = ArrayList<File>(files.size * 2) val updatedFiles = ArrayList<File>(files.size * 2)
updatedFiles.addAll(files) updatedFiles.addAll(files)
@ -86,6 +81,7 @@ class CopyDialog(val activity: SimpleActivity, val files: ArrayList<File>, val c
if (file.renameTo(destination)) if (file.renameTo(destination))
updatedFiles.add(destination) updatedFiles.add(destination)
} }
context.scanFiles(updatedFiles) { context.scanFiles(updatedFiles) {
activity.runOnUiThread { activity.runOnUiThread {
copyMoveListener.copySucceeded(true, files.size * 2 == updatedFiles.size) copyMoveListener.copySucceeded(true, files.size * 2 == updatedFiles.size)
@ -94,6 +90,7 @@ class CopyDialog(val activity: SimpleActivity, val files: ArrayList<File>, val c
} }
} }
} }
}
}) })
} }

View file

@ -46,14 +46,13 @@ class RenameDirectoryDialog(val activity: SimpleActivity, val dir: File, val cal
} }
if (context.needsStupidWritePermissions(dir.absolutePath)) { if (context.needsStupidWritePermissions(dir.absolutePath)) {
if (activity.isShowingPermDialog(dir)) activity.handleSAFDialog(dir) {
return@setOnClickListener val document = context.getFileDocument(dir.absolutePath, context.config.treeUri) ?: return@handleSAFDialog
val document = context.getFileDocument(dir.absolutePath, context.config.treeUri) ?: return@setOnClickListener
if (document.canWrite()) if (document.canWrite())
document.renameTo(newDirName) document.renameTo(newDirName)
sendSuccess(updatedFiles, newDir) sendSuccess(updatedFiles, newDir)
dismiss() dismiss()
}
} else if (dir.renameTo(newDir)) { } else if (dir.renameTo(newDir)) {
sendSuccess(updatedFiles, newDir) sendSuccess(updatedFiles, newDir)
dismiss() dismiss()

View file

@ -26,7 +26,7 @@ class RenameFileDialog(val activity: SimpleActivity, val file: File, val callbac
} }
view.file_name.setText(name) view.file_name.setText(name)
view.file_path.text = "${activity.humanizePath(file.parent)}/" view.file_path.text = activity.humanizePath(file.parent) + "/"
AlertDialog.Builder(activity) AlertDialog.Builder(activity)
.setPositiveButton(R.string.ok, null) .setPositiveButton(R.string.ok, null)
@ -55,9 +55,7 @@ class RenameFileDialog(val activity: SimpleActivity, val file: File, val callbac
} }
if (context.needsStupidWritePermissions(file.absolutePath)) { if (context.needsStupidWritePermissions(file.absolutePath)) {
if (activity.isShowingPermDialog(file)) activity.handleSAFDialog(file) {
return@setOnClickListener
var document = context.getFastDocument(file) var document = context.getFastDocument(file)
if (document?.isFile == false) { if (document?.isFile == false) {
document = context.getFileDocument(file.absolutePath, context.config.treeUri) document = context.getFileDocument(file.absolutePath, context.config.treeUri)
@ -66,6 +64,7 @@ class RenameFileDialog(val activity: SimpleActivity, val file: File, val callbac
DocumentsContract.renameDocument(context.contentResolver, document!!.uri, newFile.name) DocumentsContract.renameDocument(context.contentResolver, document!!.uri, newFile.name)
sendSuccess(file, newFile) sendSuccess(file, newFile)
dismiss() dismiss()
}
} else if (file.renameTo(newFile)) { } else if (file.renameTo(newFile)) {
sendSuccess(file, newFile) sendSuccess(file, newFile)
dismiss() dismiss()

View file

@ -161,7 +161,7 @@ fun SimpleActivity.addNoMedia(path: String, callback: () -> Unit) {
return return
if (needsStupidWritePermissions(path)) { if (needsStupidWritePermissions(path)) {
if (!isShowingPermDialog(file)) { handleSAFDialog(file) {
getFileDocument(path, config.treeUri)?.createFile("", NOMEDIA) getFileDocument(path, config.treeUri)?.createFile("", NOMEDIA)
} }
} else { } else {
@ -174,21 +174,9 @@ fun SimpleActivity.addNoMedia(path: String, callback: () -> Unit) {
fun SimpleActivity.removeNoMedia(path: String, callback: () -> Unit) { fun SimpleActivity.removeNoMedia(path: String, callback: () -> Unit) {
val file = File(path, NOMEDIA) val file = File(path, NOMEDIA)
if (!file.exists()) deleteFile(file) {
return scanFile(File(path)) {
callback()
if (!file.delete() && !tryFastDocumentDelete(file)) {
if (needsStupidWritePermissions(path)) {
if (!isShowingPermDialog(file)) {
getFileDocument(path, config.treeUri)?.apply {
if (isFile) {
delete()
} }
} }
} }
}
}
scanFile(file) {
callback.invoke()
}
}

View file

@ -70,6 +70,10 @@ fun Context.getParents(): ArrayList<String> {
val noMediaFolders = getNoMediaFolders() val noMediaFolders = getNoMediaFolders()
val parents = ArrayList<String>() val parents = ArrayList<String>()
if (config.showHiddenFolders) {
parentsSet.addAll(noMediaFolders)
}
parentsSet.filterTo(parents, { parentsSet.filterTo(parents, {
if (File(it).isDirectory) { if (File(it).isDirectory) {
if (!config.showHiddenFolders) { if (!config.showHiddenFolders) {
@ -81,10 +85,6 @@ fun Context.getParents(): ArrayList<String> {
} }
}) })
if (config.showHiddenFolders) {
parents.addAll(noMediaFolders)
}
return parents return parents
} }