From 7cc1a9ce178e6009b63ef3f854469284895de55b Mon Sep 17 00:00:00 2001 From: tibbi Date: Sat, 30 Sep 2017 22:06:32 +0200 Subject: [PATCH] move the media fetching related functions in a separate class --- .../asynctasks/GetDirectoriesAsynctask.kt | 4 +- .../gallery/asynctasks/GetMediaAsynctask.kt | 7 +- .../gallery/extensions/context.kt | 302 +---------------- .../gallery/helpers/MediaFetcher.kt | 311 ++++++++++++++++++ 4 files changed, 318 insertions(+), 306 deletions(-) create mode 100644 app/src/main/kotlin/com/simplemobiletools/gallery/helpers/MediaFetcher.kt diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/asynctasks/GetDirectoriesAsynctask.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/asynctasks/GetDirectoriesAsynctask.kt index a6450aac1..44a1921dc 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/asynctasks/GetDirectoriesAsynctask.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/asynctasks/GetDirectoriesAsynctask.kt @@ -10,8 +10,8 @@ import com.simplemobiletools.commons.helpers.SORT_DESCENDING import com.simplemobiletools.gallery.R import com.simplemobiletools.gallery.extensions.config import com.simplemobiletools.gallery.extensions.containsNoMedia -import com.simplemobiletools.gallery.extensions.getMediaByDirectories import com.simplemobiletools.gallery.extensions.sumByLong +import com.simplemobiletools.gallery.helpers.MediaFetcher import com.simplemobiletools.gallery.models.Directory import com.simplemobiletools.gallery.models.Medium import java.io.File @@ -24,7 +24,7 @@ class GetDirectoriesAsynctask(val context: Context, val isPickVideo: Boolean, va return ArrayList() val config = context.config - val groupedMedia = context.getMediaByDirectories(isPickVideo, isPickImage) + val groupedMedia = MediaFetcher(context).getMediaByDirectories(isPickVideo, isPickImage) val directories = ArrayList() val hidden = context.resources.getString(R.string.hidden) val albumCovers = config.parseAlbumCovers() diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/asynctasks/GetMediaAsynctask.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/asynctasks/GetMediaAsynctask.kt index 13002eb86..f0016b7f1 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/asynctasks/GetMediaAsynctask.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/asynctasks/GetMediaAsynctask.kt @@ -3,8 +3,7 @@ package com.simplemobiletools.gallery.asynctasks import android.content.Context import android.os.AsyncTask import com.simplemobiletools.gallery.extensions.config -import com.simplemobiletools.gallery.extensions.getFilesFrom -import com.simplemobiletools.gallery.extensions.getMediaByDirectories +import com.simplemobiletools.gallery.helpers.MediaFetcher import com.simplemobiletools.gallery.models.Medium import java.util.* @@ -14,7 +13,7 @@ class GetMediaAsynctask(val context: Context, val mPath: String, val isPickVideo override fun doInBackground(vararg params: Void): ArrayList { return if (showAll) { - val mediaMap = context.getMediaByDirectories(isPickVideo, isPickImage) + val mediaMap = MediaFetcher(context).getMediaByDirectories(isPickVideo, isPickImage) val media = ArrayList() for ((path, curMedia) in mediaMap) { media.addAll(curMedia) @@ -24,7 +23,7 @@ class GetMediaAsynctask(val context: Context, val mPath: String, val isPickVideo media.sort() media } else { - context.getFilesFrom(mPath, isPickImage, isPickVideo) + MediaFetcher(context).getFilesFrom(mPath, isPickImage, isPickVideo) } } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/context.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/context.kt index ac943fe25..c04c3371e 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/context.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/context.kt @@ -10,20 +10,10 @@ import android.net.Uri import android.os.Build import android.provider.MediaStore import android.view.WindowManager -import com.simplemobiletools.commons.extensions.* -import com.simplemobiletools.commons.helpers.SORT_BY_DATE_MODIFIED -import com.simplemobiletools.commons.helpers.SORT_BY_NAME -import com.simplemobiletools.commons.helpers.SORT_BY_SIZE -import com.simplemobiletools.commons.helpers.SORT_DESCENDING +import com.simplemobiletools.commons.extensions.humanizePath import com.simplemobiletools.gallery.activities.SettingsActivity -import com.simplemobiletools.gallery.helpers.* +import com.simplemobiletools.gallery.helpers.Config import com.simplemobiletools.gallery.models.Directory -import com.simplemobiletools.gallery.models.Medium -import java.io.File -import java.util.LinkedHashMap -import kotlin.collections.ArrayList -import kotlin.collections.component1 -import kotlin.collections.component2 val Context.portrait get() = resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT val Context.audioManager get() = getSystemService(Context.AUDIO_SERVICE) as AudioManager @@ -81,225 +71,6 @@ fun Context.launchSettings() { val Context.config: Config get() = Config.newInstance(this) -fun Context.getFilesFrom(curPath: String, isPickImage: Boolean, isPickVideo: Boolean): ArrayList { - val projection = arrayOf(MediaStore.Images.Media._ID, - MediaStore.Images.Media.DISPLAY_NAME, - MediaStore.Images.Media.DATE_TAKEN, - MediaStore.Images.Media.DATE_MODIFIED, - MediaStore.Images.Media.DATA, - MediaStore.Images.Media.SIZE) - val uri = MediaStore.Files.getContentUri("external") - val selection = getSelectionQuery(curPath) - val selectionArgs = getSelectionArgsQuery(curPath) - - return try { - val cur = contentResolver.query(uri, projection, selection, selectionArgs, getSortingForFolder(curPath)) - parseCursor(this, cur, isPickImage, isPickVideo, curPath) - } catch (e: Exception) { - ArrayList() - } -} - -fun Context.getSelectionQuery(path: String): String { - val dataQuery = "${MediaStore.Images.Media.DATA} LIKE ?" - return if (path.isEmpty()) { - var query = "($dataQuery)" - if (hasExternalSDCard()) { - query += " OR ($dataQuery)" - } - query - } else { - "($dataQuery AND ${MediaStore.Images.Media.DATA} NOT LIKE ?)" - } -} - -fun Context.getSelectionArgsQuery(path: String): Array { - return if (path.isEmpty()) { - if (hasExternalSDCard()) arrayOf("$internalStoragePath/%", "$sdCardPath/%") else arrayOf("$internalStoragePath/%") - } else { - arrayOf("$path/%", "$path/%/%") - } -} - -private fun parseCursor(context: Context, cur: Cursor, isPickImage: Boolean, isPickVideo: Boolean, curPath: String): ArrayList { - val curMedia = ArrayList() - val config = context.config - val filterMedia = config.filterMedia - val showHidden = config.shouldShowHidden - val includedFolders = config.includedFolders.map { "${it.trimEnd('/')}/" } - val excludedFolders = config.excludedFolders.map { "${it.trimEnd('/')}/" } - val noMediaFolders = context.getNoMediaFolders() - val isThirdPartyIntent = config.isThirdPartyIntent - - cur.use { - if (cur.moveToFirst()) { - do { - try { - val path = cur.getStringValue(MediaStore.Images.Media.DATA) - - var filename = cur.getStringValue(MediaStore.Images.Media.DISPLAY_NAME) ?: "" - if (filename.isEmpty()) - filename = path.getFilenameFromPath() - - val isImage = filename.isImageFast() - val isVideo = if (isImage) false else filename.isVideoFast() - val isGif = if (isImage || isVideo) false else filename.isGif() - - if (!isImage && !isVideo && !isGif) - continue - - if (isVideo && (isPickImage || filterMedia and VIDEOS == 0)) - continue - - if (isImage && (isPickVideo || filterMedia and IMAGES == 0)) - continue - - if (isGif && filterMedia and GIFS == 0) - continue - - if (!showHidden && filename.startsWith('.')) - continue - - var size = cur.getLongValue(MediaStore.Images.Media.SIZE) - val file = File(path) - if (size == 0L) { - size = file.length() - } - - if (size <= 0L) - continue - - var isExcluded = false - excludedFolders.forEach { - if (path.startsWith(it)) { - isExcluded = true - includedFolders.forEach { - if (path.startsWith(it)) { - isExcluded = false - } - } - } - } - - if (!isExcluded && !showHidden) { - noMediaFolders.forEach { - if (path.startsWith(it)) { - isExcluded = true - } - } - } - - if (!isExcluded && !showHidden && path.contains("/.")) { - isExcluded = true - } - - if (!isExcluded || isThirdPartyIntent) { - if (!file.exists()) - continue - - val dateTaken = cur.getLongValue(MediaStore.Images.Media.DATE_TAKEN) - val dateModified = cur.getIntValue(MediaStore.Images.Media.DATE_MODIFIED) * 1000L - - val medium = Medium(filename, path, isVideo, dateModified, dateTaken, size) - curMedia.add(medium) - } - } catch (e: Exception) { - continue - } - } while (cur.moveToNext()) - } - } - - config.includedFolders.filter { it.isNotEmpty() && (curPath.isEmpty() || it == curPath) }.forEach { - getMediaInFolder(it, curMedia, isPickImage, isPickVideo, filterMedia) - } - - if (isThirdPartyIntent && curPath.isNotEmpty() && curMedia.isEmpty()) { - getMediaInFolder(curPath, curMedia, isPickImage, isPickVideo, filterMedia) - } - - Medium.sorting = config.getFileSorting(curPath) - curMedia.sort() - - return curMedia -} - -private fun getMediaInFolder(folder: String, curMedia: ArrayList, isPickImage: Boolean, isPickVideo: Boolean, filterMedia: Int) { - val files = File(folder).listFiles() ?: return - for (file in files) { - val filename = file.name - val isImage = filename.isImageFast() - val isVideo = if (isImage) false else filename.isVideoFast() - val isGif = if (isImage || isVideo) false else filename.isGif() - - if (!isImage && !isVideo) - continue - - if (isVideo && (isPickImage || filterMedia and VIDEOS == 0)) - continue - - if (isImage && (isPickVideo || filterMedia and IMAGES == 0)) - continue - - if (isGif && filterMedia and GIFS == 0) - continue - - val size = file.length() - if (size <= 0L) - continue - - val dateTaken = file.lastModified() - val dateModified = file.lastModified() - - val medium = Medium(filename, file.absolutePath, isVideo, dateModified, dateTaken, size) - val isAlreadyAdded = curMedia.any { it.path == file.absolutePath } - if (!isAlreadyAdded) - curMedia.add(medium) - } -} - -fun Context.getSortingForFolder(path: String): String { - val sorting = config.getFileSorting(path) - val sortValue = when { - sorting and SORT_BY_NAME > 0 -> MediaStore.Images.Media.DISPLAY_NAME - sorting and SORT_BY_SIZE > 0 -> MediaStore.Images.Media.SIZE - sorting and SORT_BY_DATE_MODIFIED > 0 -> MediaStore.Images.Media.DATE_MODIFIED - else -> MediaStore.Images.Media.DATE_TAKEN - } - - return if (sorting and SORT_DESCENDING > 0) - "$sortValue DESC" - else - "$sortValue ASC" -} - -fun Context.getNoMediaFolders(): ArrayList { - val folders = ArrayList() - val noMediaCondition = "${MediaStore.Files.FileColumns.MEDIA_TYPE} = ${MediaStore.Files.FileColumns.MEDIA_TYPE_NONE}" - - val uri = MediaStore.Files.getContentUri("external") - val columns = arrayOf(MediaStore.Files.FileColumns.DATA) - val where = "$noMediaCondition AND ${MediaStore.Files.FileColumns.TITLE} LIKE ?" - val args = arrayOf("%$NOMEDIA%") - var cursor: Cursor? = null - - try { - cursor = contentResolver.query(uri, columns, where, args, null) - if (cursor?.moveToFirst() == true) { - do { - val path = cursor.getString(cursor.getColumnIndex(MediaStore.Files.FileColumns.DATA)) ?: continue - val noMediaFile = File(path) - if (noMediaFile.exists()) - folders.add("${noMediaFile.parent}/") - } while (cursor.moveToNext()) - } - } finally { - cursor?.close() - } - - return folders -} - fun Context.movePinnedDirectoriesToFront(dirs: ArrayList): ArrayList { val foundFolders = ArrayList() val pinnedFolders = config.pinnedFolders @@ -310,75 +81,6 @@ fun Context.movePinnedDirectoriesToFront(dirs: ArrayList): ArrayList< return dirs } -fun Context.getMediaByDirectories(isPickVideo: Boolean, isPickImage: Boolean): HashMap> { - val media = getFilesFrom("", isPickImage, isPickVideo) - val excludedPaths = config.excludedFolders - val includedPaths = config.includedFolders - val showHidden = config.shouldShowHidden - val directories = groupDirectories(media) - - val removePaths = ArrayList() - for ((path, curMedia) in directories) { - // make sure the path has uppercase letters wherever appropriate - val groupPath = File(curMedia.first().path).parent - if (!File(groupPath).exists() || !shouldFolderBeVisible(groupPath, excludedPaths, includedPaths, showHidden)) { - removePaths.add(groupPath.toLowerCase()) - } - } - - removePaths.forEach { - directories.remove(it) - } - - return directories -} - -private fun groupDirectories(media: ArrayList): HashMap> { - val directories = LinkedHashMap>() - for (medium in media) { - val parentDir = File(medium.path).parent?.toLowerCase() ?: continue - if (directories.containsKey(parentDir)) { - directories[parentDir]!!.add(medium) - } else { - directories.put(parentDir, arrayListOf(medium)) - } - } - return directories -} - -private fun shouldFolderBeVisible(path: String, excludedPaths: MutableSet, includedPaths: MutableSet, showHidden: Boolean): Boolean { - val file = File(path) - return if (includedPaths.contains(path)) { - true - } else if (isThisOrParentExcluded(path, excludedPaths, includedPaths)) { - false - } else if (!showHidden && file.isDirectory && file.canonicalFile == file.absoluteFile) { - var containsNoMediaOrDot = file.containsNoMedia() || path.contains("/.") - if (!containsNoMediaOrDot) { - containsNoMediaOrDot = checkParentHasNoMedia(file.parentFile) - } - !containsNoMediaOrDot - } else { - true - } -} - -private fun checkParentHasNoMedia(file: File): Boolean { - var curFile = file - while (true) { - if (curFile.containsNoMedia()) { - return true - } - curFile = curFile.parentFile - if (curFile.absolutePath == "/") - break - } - return false -} - -private fun isThisOrParentExcluded(path: String, excludedPaths: MutableSet, includedPaths: MutableSet) = - includedPaths.none { path.startsWith(it) } && excludedPaths.any { path.startsWith(it) } - @Suppress("UNCHECKED_CAST") fun Context.getSortedDirectories(source: ArrayList): ArrayList { Directory.sorting = config.directorySorting diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/MediaFetcher.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/MediaFetcher.kt new file mode 100644 index 000000000..7bb0d0e8f --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/MediaFetcher.kt @@ -0,0 +1,311 @@ +package com.simplemobiletools.gallery.helpers + +import android.content.Context +import android.database.Cursor +import android.provider.MediaStore +import android.util.Log +import com.simplemobiletools.commons.extensions.* +import com.simplemobiletools.commons.helpers.SORT_BY_DATE_MODIFIED +import com.simplemobiletools.commons.helpers.SORT_BY_NAME +import com.simplemobiletools.commons.helpers.SORT_BY_SIZE +import com.simplemobiletools.commons.helpers.SORT_DESCENDING +import com.simplemobiletools.gallery.extensions.config +import com.simplemobiletools.gallery.extensions.containsNoMedia +import com.simplemobiletools.gallery.models.Medium +import java.io.File +import java.util.LinkedHashMap +import kotlin.collections.ArrayList +import kotlin.collections.component1 +import kotlin.collections.component2 + +class MediaFetcher(val context: Context) { + fun getMediaByDirectories(isPickVideo: Boolean, isPickImage: Boolean): HashMap> { + val media = getFilesFrom("", isPickImage, isPickVideo) + val excludedPaths = context.config.excludedFolders + val includedPaths = context.config.includedFolders + val showHidden = context.config.shouldShowHidden + val directories = groupDirectories(media) + + val removePaths = ArrayList() + for ((path, curMedia) in directories) { + // make sure the path has uppercase letters wherever appropriate + val groupPath = File(curMedia.first().path).parent + if (!File(groupPath).exists() || !shouldFolderBeVisible(groupPath, excludedPaths, includedPaths, showHidden)) { + removePaths.add(groupPath.toLowerCase()) + } + } + + removePaths.forEach { + directories.remove(it) + } + + return directories + } + + fun getFilesFrom(curPath: String, isPickImage: Boolean, isPickVideo: Boolean): ArrayList { + val projection = arrayOf(MediaStore.Images.Media._ID, + MediaStore.Images.Media.DISPLAY_NAME, + MediaStore.Images.Media.DATE_TAKEN, + MediaStore.Images.Media.DATE_MODIFIED, + MediaStore.Images.Media.DATA, + MediaStore.Images.Media.SIZE) + val uri = MediaStore.Files.getContentUri("external") + val selection = getSelectionQuery(curPath) + val selectionArgs = getSelectionArgsQuery(curPath) + + return try { + val cur = context.contentResolver.query(uri, projection, selection, selectionArgs, getSortingForFolder(curPath)) + parseCursor(context, cur, isPickImage, isPickVideo, curPath) + } catch (e: Exception) { + ArrayList() + } + } + + private fun getSelectionQuery(path: String): String { + val dataQuery = "${MediaStore.Images.Media.DATA} LIKE ?" + return if (path.isEmpty()) { + var query = "($dataQuery)" + if (context.hasExternalSDCard()) { + query += " OR ($dataQuery)" + } + query + } else { + "($dataQuery AND ${MediaStore.Images.Media.DATA} NOT LIKE ?)" + } + } + + private fun getSelectionArgsQuery(path: String): Array { + return if (path.isEmpty()) { + if (context.hasExternalSDCard()) arrayOf("${context.internalStoragePath}/%", "${context.sdCardPath}/%") else arrayOf("${context.internalStoragePath}/%") + } else { + arrayOf("$path/%", "$path/%/%") + } + } + + private fun parseCursor(context: Context, cur: Cursor, isPickImage: Boolean, isPickVideo: Boolean, curPath: String): ArrayList { + val curMedia = ArrayList() + val config = context.config + val filterMedia = config.filterMedia + val showHidden = config.shouldShowHidden + val includedFolders = config.includedFolders.map { "${it.trimEnd('/')}/" } + val excludedFolders = config.excludedFolders.map { "${it.trimEnd('/')}/" } + val noMediaFolders = getNoMediaFolders() + val isThirdPartyIntent = config.isThirdPartyIntent + + cur.use { + if (cur.moveToFirst()) { + do { + try { + val path = cur.getStringValue(MediaStore.Images.Media.DATA) + + Log.e("DEBUG", "checking $path") + var filename = cur.getStringValue(MediaStore.Images.Media.DISPLAY_NAME) ?: "" + if (filename.isEmpty()) + filename = path.getFilenameFromPath() + + val isImage = filename.isImageFast() + val isVideo = if (isImage) false else filename.isVideoFast() + val isGif = if (isImage || isVideo) false else filename.isGif() + + if (!isImage && !isVideo && !isGif) + continue + + if (isVideo && (isPickImage || filterMedia and VIDEOS == 0)) + continue + + if (isImage && (isPickVideo || filterMedia and IMAGES == 0)) + continue + + if (isGif && filterMedia and GIFS == 0) + continue + + if (!showHidden && filename.startsWith('.')) + continue + + var size = cur.getLongValue(MediaStore.Images.Media.SIZE) + val file = File(path) + if (size == 0L) { + size = file.length() + } + + if (size <= 0L) + continue + + var isExcluded = false + excludedFolders.forEach { + if (path.startsWith(it)) { + isExcluded = true + includedFolders.forEach { + if (path.startsWith(it)) { + isExcluded = false + } + } + } + } + + if (!isExcluded && !showHidden) { + noMediaFolders.forEach { + if (path.startsWith(it)) { + isExcluded = true + } + } + } + + if (!isExcluded && !showHidden && path.contains("/.")) { + isExcluded = true + } + + if (!isExcluded || isThirdPartyIntent) { + if (!file.exists()) + continue + + val dateTaken = cur.getLongValue(MediaStore.Images.Media.DATE_TAKEN) + val dateModified = cur.getIntValue(MediaStore.Images.Media.DATE_MODIFIED) * 1000L + + val medium = Medium(filename, path, isVideo, dateModified, dateTaken, size) + curMedia.add(medium) + } + } catch (e: Exception) { + continue + } + } while (cur.moveToNext()) + } + } + + config.includedFolders.filter { it.isNotEmpty() && (curPath.isEmpty() || it == curPath) }.forEach { + getMediaInFolder(it, curMedia, isPickImage, isPickVideo, filterMedia) + } + + if (isThirdPartyIntent && curPath.isNotEmpty() && curMedia.isEmpty()) { + getMediaInFolder(curPath, curMedia, isPickImage, isPickVideo, filterMedia) + } + + Medium.sorting = config.getFileSorting(curPath) + curMedia.sort() + + return curMedia + } + + private fun groupDirectories(media: ArrayList): HashMap> { + val directories = LinkedHashMap>() + for (medium in media) { + val parentDir = File(medium.path).parent?.toLowerCase() ?: continue + if (directories.containsKey(parentDir)) { + directories[parentDir]!!.add(medium) + } else { + directories.put(parentDir, arrayListOf(medium)) + } + } + return directories + } + + private fun shouldFolderBeVisible(path: String, excludedPaths: MutableSet, includedPaths: MutableSet, showHidden: Boolean): Boolean { + val file = File(path) + return if (includedPaths.contains(path)) { + true + } else if (isThisOrParentExcluded(path, excludedPaths, includedPaths)) { + false + } else if (!showHidden && file.isDirectory && file.canonicalFile == file.absoluteFile) { + var containsNoMediaOrDot = file.containsNoMedia() || path.contains("/.") + if (!containsNoMediaOrDot) { + containsNoMediaOrDot = checkParentHasNoMedia(file.parentFile) + } + !containsNoMediaOrDot + } else { + true + } + } + + private fun checkParentHasNoMedia(file: File): Boolean { + var curFile = file + while (true) { + if (curFile.containsNoMedia()) { + return true + } + curFile = curFile.parentFile + if (curFile.absolutePath == "/") + break + } + return false + } + + private fun isThisOrParentExcluded(path: String, excludedPaths: MutableSet, includedPaths: MutableSet) = + includedPaths.none { path.startsWith(it) } && excludedPaths.any { path.startsWith(it) } + + + private fun getMediaInFolder(folder: String, curMedia: ArrayList, isPickImage: Boolean, isPickVideo: Boolean, filterMedia: Int) { + val files = File(folder).listFiles() ?: return + for (file in files) { + val filename = file.name + val isImage = filename.isImageFast() + val isVideo = if (isImage) false else filename.isVideoFast() + val isGif = if (isImage || isVideo) false else filename.isGif() + + if (!isImage && !isVideo) + continue + + if (isVideo && (isPickImage || filterMedia and VIDEOS == 0)) + continue + + if (isImage && (isPickVideo || filterMedia and IMAGES == 0)) + continue + + if (isGif && filterMedia and GIFS == 0) + continue + + val size = file.length() + if (size <= 0L) + continue + + val dateTaken = file.lastModified() + val dateModified = file.lastModified() + + val medium = Medium(filename, file.absolutePath, isVideo, dateModified, dateTaken, size) + val isAlreadyAdded = curMedia.any { it.path == file.absolutePath } + if (!isAlreadyAdded) + curMedia.add(medium) + } + } + + private fun getSortingForFolder(path: String): String { + val sorting = context.config.getFileSorting(path) + val sortValue = when { + sorting and SORT_BY_NAME > 0 -> MediaStore.Images.Media.DISPLAY_NAME + sorting and SORT_BY_SIZE > 0 -> MediaStore.Images.Media.SIZE + sorting and SORT_BY_DATE_MODIFIED > 0 -> MediaStore.Images.Media.DATE_MODIFIED + else -> MediaStore.Images.Media.DATE_TAKEN + } + + return if (sorting and SORT_DESCENDING > 0) + "$sortValue DESC" + else + "$sortValue ASC" + } + + private fun getNoMediaFolders(): ArrayList { + val folders = ArrayList() + val noMediaCondition = "${MediaStore.Files.FileColumns.MEDIA_TYPE} = ${MediaStore.Files.FileColumns.MEDIA_TYPE_NONE}" + + val uri = MediaStore.Files.getContentUri("external") + val columns = arrayOf(MediaStore.Files.FileColumns.DATA) + val where = "$noMediaCondition AND ${MediaStore.Files.FileColumns.TITLE} LIKE ?" + val args = arrayOf("%$NOMEDIA%") + var cursor: Cursor? = null + + try { + cursor = context.contentResolver.query(uri, columns, where, args, null) + if (cursor?.moveToFirst() == true) { + do { + val path = cursor.getString(cursor.getColumnIndex(MediaStore.Files.FileColumns.DATA)) ?: continue + val noMediaFile = File(path) + if (noMediaFile.exists()) + folders.add("${noMediaFile.parent}/") + } while (cursor.moveToNext()) + } + } finally { + cursor?.close() + } + + return folders + } +}