Fix storage getting full while moving multiple items to the recycle bin at once
This commit is contained in:
parent
07fb21a775
commit
9f152ea01d
|
@ -656,9 +656,10 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
|
||||||
val pathsToDelete = ArrayList<String>()
|
val pathsToDelete = ArrayList<String>()
|
||||||
itemsToDelete.mapTo(pathsToDelete) { it.path }
|
itemsToDelete.mapTo(pathsToDelete) { it.path }
|
||||||
|
|
||||||
movePathsInRecycleBin(pathsToDelete) {
|
movePathsInRecycleBin(pathsToDelete) { wasSuccess, range ->
|
||||||
if (it) {
|
if (wasSuccess) {
|
||||||
deleteFilteredFileDirItems(itemsToDelete, folders)
|
val itemsInRange = itemsToDelete.subList(range.first, range.second)
|
||||||
|
deleteFilteredFileDirItems(ArrayList(itemsInRange), ArrayList())
|
||||||
} else {
|
} else {
|
||||||
toast(R.string.unknown_error_occurred)
|
toast(R.string.unknown_error_occurred)
|
||||||
}
|
}
|
||||||
|
|
|
@ -887,9 +887,10 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
|
||||||
val movingItems = resources.getQuantityString(R.plurals.moving_items_into_bin, filtered.size, filtered.size)
|
val movingItems = resources.getQuantityString(R.plurals.moving_items_into_bin, filtered.size, filtered.size)
|
||||||
toast(movingItems)
|
toast(movingItems)
|
||||||
|
|
||||||
movePathsInRecycleBin(filtered.map { it.path } as ArrayList<String>) {
|
movePathsInRecycleBin(filtered.map { it.path } as ArrayList<String>) { wasSuccess, range ->
|
||||||
if (it) {
|
if (wasSuccess) {
|
||||||
deleteFilteredFiles(filtered)
|
val itemsInRange = filtered.subList(range.first, range.second)
|
||||||
|
deleteFilteredFiles(ArrayList(itemsInRange))
|
||||||
} else {
|
} else {
|
||||||
toast(R.string.unknown_error_occurred)
|
toast(R.string.unknown_error_occurred)
|
||||||
}
|
}
|
||||||
|
|
|
@ -267,9 +267,10 @@ class SearchActivity : SimpleActivity(), MediaOperationsListener {
|
||||||
val movingItems = resources.getQuantityString(R.plurals.moving_items_into_bin, filtered.size, filtered.size)
|
val movingItems = resources.getQuantityString(R.plurals.moving_items_into_bin, filtered.size, filtered.size)
|
||||||
toast(movingItems)
|
toast(movingItems)
|
||||||
|
|
||||||
movePathsInRecycleBin(filtered.map { it.path } as ArrayList<String>) {
|
movePathsInRecycleBin(filtered.map { it.path } as ArrayList<String>) { wasSuccess, range ->
|
||||||
if (it) {
|
if (wasSuccess) {
|
||||||
deleteFilteredFiles(filtered)
|
val itemsInRange = filtered.subList(range.first, range.second)
|
||||||
|
deleteFilteredFiles(ArrayList(itemsInRange))
|
||||||
} else {
|
} else {
|
||||||
toast(R.string.unknown_error_occurred)
|
toast(R.string.unknown_error_occurred)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1161,8 +1161,8 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
|
||||||
onPageSelected(0)
|
onPageSelected(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
movePathsInRecycleBin(arrayListOf(path)) {
|
movePathsInRecycleBin(arrayListOf(path)) { wasSuccess, _ ->
|
||||||
if (it) {
|
if (wasSuccess) {
|
||||||
tryDeleteFileDirItem(fileDirItem, false, false) {
|
tryDeleteFileDirItem(fileDirItem, false, false) {
|
||||||
mIgnoredPaths.remove(fileDirItem.path)
|
mIgnoredPaths.remove(fileDirItem.path)
|
||||||
if (media.isEmpty()) {
|
if (media.isEmpty()) {
|
||||||
|
|
|
@ -44,6 +44,7 @@ import com.squareup.picasso.Picasso
|
||||||
import java.io.*
|
import java.io.*
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
fun Activity.sharePath(path: String) {
|
fun Activity.sharePath(path: String) {
|
||||||
sharePathIntent(path, BuildConfig.APPLICATION_ID)
|
sharePathIntent(path, BuildConfig.APPLICATION_ID)
|
||||||
|
@ -313,18 +314,45 @@ fun BaseSimpleActivity.tryDeleteFileDirItem(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun BaseSimpleActivity.movePathsInRecycleBin(paths: ArrayList<String>, callback: ((wasSuccess: Boolean) -> Unit)?) {
|
fun BaseSimpleActivity.movePathsInRecycleBin(paths: ArrayList<String>, callback: ((wasSuccess: Boolean, movedRange: Pair<Int, Int>) -> Unit)?) {
|
||||||
ensureBackgroundThread {
|
ensureBackgroundThread {
|
||||||
var pathsCnt = paths.size
|
var pathsCnt = paths.size
|
||||||
val OTGPath = config.OTGPath
|
val OTGPath = config.OTGPath
|
||||||
|
|
||||||
for (source in paths) {
|
var availableSize = getAvailableInternalMemorySize().toLong()
|
||||||
|
|
||||||
|
// If available size is more than 200MB, keep a safe distance from
|
||||||
|
// exceeding the remaining size
|
||||||
|
if (availableSize > 1024 * 1024 * 200)
|
||||||
|
availableSize -= 1024 * 1024 * 50
|
||||||
|
var totalCopiedSize = 0L
|
||||||
|
|
||||||
|
var lastDeletedIndex = -1
|
||||||
|
val ensureSizeIsAvailable = { index: Int, size: Long ->
|
||||||
|
// Try to delete already moved files if space if not sufficient
|
||||||
|
if (size <= availableSize && totalCopiedSize > 0 && totalCopiedSize + size > availableSize) {
|
||||||
|
// Return true in wasSuccess for now, callback will be called
|
||||||
|
// at the end of the function with the correct parameter
|
||||||
|
callback?.invoke(true, Pair(lastDeletedIndex + 1, index + 1))
|
||||||
|
availableSize = getAvailableInternalMemorySize()
|
||||||
|
totalCopiedSize = 0L
|
||||||
|
lastDeletedIndex = index
|
||||||
|
}
|
||||||
|
|
||||||
|
size <= availableSize
|
||||||
|
}
|
||||||
|
|
||||||
|
for ((index, source) in paths.withIndex()) {
|
||||||
if (OTGPath.isNotEmpty() && source.startsWith(OTGPath)) {
|
if (OTGPath.isNotEmpty() && source.startsWith(OTGPath)) {
|
||||||
var inputStream: InputStream? = null
|
var inputStream: InputStream? = null
|
||||||
var out: OutputStream? = null
|
var out: OutputStream? = null
|
||||||
try {
|
try {
|
||||||
val destination = "$recycleBinPath/$source"
|
val destination = "$recycleBinPath/$source"
|
||||||
val fileDocument = getSomeDocumentFile(source)
|
val fileDocument = getSomeDocumentFile(source)
|
||||||
|
val originalSize = fileDocument?.getItemSize(true)!!
|
||||||
|
if (!ensureSizeIsAvailable(index, originalSize))
|
||||||
|
continue
|
||||||
|
|
||||||
inputStream = applicationContext.contentResolver.openInputStream(fileDocument?.uri!!)
|
inputStream = applicationContext.contentResolver.openInputStream(fileDocument?.uri!!)
|
||||||
out = getFileOutputStreamSync(destination, source.getMimeType())
|
out = getFileOutputStreamSync(destination, source.getMimeType())
|
||||||
|
|
||||||
|
@ -339,9 +367,11 @@ fun BaseSimpleActivity.movePathsInRecycleBin(paths: ArrayList<String>, callback:
|
||||||
|
|
||||||
out?.flush()
|
out?.flush()
|
||||||
|
|
||||||
if (fileDocument.getItemSize(true) == copiedSize && getDoesFilePathExist(destination)) {
|
if (originalSize == copiedSize && getDoesFilePathExist(destination)) {
|
||||||
mediaDB.updateDeleted("$RECYCLE_BIN$source", System.currentTimeMillis(), source)
|
mediaDB.updateDeleted("$RECYCLE_BIN$source", System.currentTimeMillis(), source)
|
||||||
pathsCnt--
|
pathsCnt--
|
||||||
|
|
||||||
|
totalCopiedSize += copiedSize
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
showErrorToast(e)
|
showErrorToast(e)
|
||||||
|
@ -352,6 +382,10 @@ fun BaseSimpleActivity.movePathsInRecycleBin(paths: ArrayList<String>, callback:
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val file = File(source)
|
val file = File(source)
|
||||||
|
val originalSize = file.length()
|
||||||
|
if (!ensureSizeIsAvailable(index, originalSize))
|
||||||
|
continue
|
||||||
|
|
||||||
val internalFile = File(recycleBinPath, source)
|
val internalFile = File(recycleBinPath, source)
|
||||||
val lastModified = file.lastModified()
|
val lastModified = file.lastModified()
|
||||||
try {
|
try {
|
||||||
|
@ -362,6 +396,8 @@ fun BaseSimpleActivity.movePathsInRecycleBin(paths: ArrayList<String>, callback:
|
||||||
if (config.keepLastModified && lastModified != 0L) {
|
if (config.keepLastModified && lastModified != 0L) {
|
||||||
internalFile.setLastModified(lastModified)
|
internalFile.setLastModified(lastModified)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
totalCopiedSize += originalSize
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
showErrorToast(e)
|
showErrorToast(e)
|
||||||
|
@ -369,7 +405,7 @@ fun BaseSimpleActivity.movePathsInRecycleBin(paths: ArrayList<String>, callback:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
callback?.invoke(pathsCnt == 0)
|
callback?.invoke(pathsCnt == 0, Pair(lastDeletedIndex + 1, paths.size))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,9 @@ import android.database.Cursor
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.graphics.drawable.PictureDrawable
|
import android.graphics.drawable.PictureDrawable
|
||||||
import android.media.AudioManager
|
import android.media.AudioManager
|
||||||
|
import android.os.Environment
|
||||||
import android.os.Process
|
import android.os.Process
|
||||||
|
import android.os.StatFs
|
||||||
import android.provider.MediaStore.Files
|
import android.provider.MediaStore.Files
|
||||||
import android.provider.MediaStore.Images
|
import android.provider.MediaStore.Images
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
|
@ -43,6 +45,7 @@ import java.nio.ByteBuffer
|
||||||
import java.nio.channels.FileChannel
|
import java.nio.channels.FileChannel
|
||||||
import kotlin.collections.set
|
import kotlin.collections.set
|
||||||
|
|
||||||
|
|
||||||
val Context.audioManager get() = getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
val Context.audioManager get() = getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
||||||
|
|
||||||
fun Context.getHumanizedFilename(path: String): String {
|
fun Context.getHumanizedFilename(path: String): String {
|
||||||
|
@ -1103,3 +1106,12 @@ fun Context.getFileDateTaken(path: String): Long {
|
||||||
|
|
||||||
return 0L
|
return 0L
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://stackoverflow.com/questions/8133417/android-get-free-size-of-internal-external-memory
|
||||||
|
fun Context.getAvailableInternalMemorySize(): Long {
|
||||||
|
val path: File = filesDir
|
||||||
|
val stat = StatFs(path.path)
|
||||||
|
val blockSize = stat.blockSizeLong
|
||||||
|
val availableBlocks = stat.availableBlocksLong
|
||||||
|
return availableBlocks * blockSize
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue