Merge pull request #421 from FossifyOrg/cleanup_code

Cleanup and format some code
This commit is contained in:
Naveen Singh 2025-03-12 00:41:54 +05:30 committed by GitHub
commit 52ca5a0a4d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 872 additions and 259 deletions

View file

@ -1,6 +1,5 @@
package org.fossify.gallery.activities
import android.app.Activity
import android.content.ClipData
import android.content.Intent
import android.net.Uri
@ -173,8 +172,13 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
private var mWasMediaManagementPromptShown = false
private var mLatestMediaId = 0L
private var mLatestMediaDateId = 0L
private var mCurrentPathPrefix = "" // used at "Group direct subfolders" for navigation
private var mOpenedSubfolders = arrayListOf("") // used at "Group direct subfolders" for navigating Up with the back button
// used at "Group direct subfolders" for navigation
private var mCurrentPathPrefix = ""
// used at "Group direct subfolders" for navigating Up with the back button
private var mOpenedSubfolders = arrayListOf("")
private var mDateFormat = ""
private var mTimeFormat = ""
private var mLastMediaHandler = Handler()
@ -215,15 +219,19 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
mIsGetAnyContentIntent = isGetAnyContentIntent(intent)
mIsSetWallpaperIntent = isSetWallpaperIntent(intent)
mAllowPickingMultiple = intent.getBooleanExtra(Intent.EXTRA_ALLOW_MULTIPLE, false)
mIsThirdPartyIntent = mIsPickImageIntent || mIsPickVideoIntent || mIsGetImageContentIntent || mIsGetVideoContentIntent ||
mIsGetAnyContentIntent || mIsSetWallpaperIntent
mIsThirdPartyIntent = mIsPickImageIntent
|| mIsPickVideoIntent
|| mIsGetImageContentIntent
|| mIsGetVideoContentIntent
|| mIsGetAnyContentIntent
|| mIsSetWallpaperIntent
setupOptionsMenu()
refreshMenuItems()
updateMaterialActivityViews(
binding.directoriesCoordinator,
binding.directoriesGrid,
mainCoordinatorLayout = binding.directoriesCoordinator,
nestedView = binding.directoriesGrid,
useTransparentNavigation = !config.scrollHorizontally,
useTopSearchMenu = true
)
@ -314,7 +322,8 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
getRecyclerAdapter()?.updatePrimaryColor()
}
val styleString = "${config.folderStyle}${config.showFolderMediaCount}${config.limitFolderTitle}"
val styleString =
"${config.folderStyle}${config.showFolderMediaCount}${config.limitFolderTitle}"
if (mStoredStyleString != styleString) {
setupAdapter(mDirs, forceRecreate = true)
}
@ -392,7 +401,7 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
if (mCurrentPathPrefix.isEmpty()) {
super.onBackPressed()
} else {
mOpenedSubfolders.removeLast()
mOpenedSubfolders.removeAt(mOpenedSubfolders.lastIndex)
mCurrentPathPrefix = mOpenedSubfolders.last()
setupAdapter(mDirs)
}
@ -403,17 +412,21 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
}
override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
if (resultCode == Activity.RESULT_OK) {
if (resultCode == RESULT_OK) {
if (requestCode == PICK_MEDIA && resultData != null) {
val resultIntent = Intent()
var resultUri: Uri? = null
if (mIsThirdPartyIntent) {
when {
intent.extras?.containsKey(MediaStore.EXTRA_OUTPUT) == true && intent.flags and Intent.FLAG_GRANT_WRITE_URI_PERMISSION != 0 -> {
intent.extras?.containsKey(MediaStore.EXTRA_OUTPUT) == true
&& intent.flags and Intent.FLAG_GRANT_WRITE_URI_PERMISSION != 0 -> {
resultUri = fillExtraOutput(resultData)
}
resultData.extras?.containsKey(PICKED_PATHS) == true -> fillPickedPaths(resultData, resultIntent)
resultData.extras?.containsKey(PICKED_PATHS) == true -> {
fillPickedPaths(resultData, resultIntent)
}
else -> fillIntentPath(resultData, resultIntent)
}
}
@ -423,10 +436,10 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
resultIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
}
setResult(Activity.RESULT_OK, resultIntent)
setResult(RESULT_OK, resultIntent)
finish()
} else if (requestCode == PICK_WALLPAPER) {
setResult(Activity.RESULT_OK)
setResult(RESULT_OK)
finish()
}
}
@ -438,14 +451,17 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
binding.mainMenu.getToolbar().menu.apply {
findItem(R.id.column_count).isVisible = config.viewTypeFolders == VIEW_TYPE_GRID
findItem(R.id.set_as_default_folder).isVisible = !config.defaultFolder.isEmpty()
findItem(R.id.open_recycle_bin).isVisible = config.useRecycleBin && !config.showRecycleBinAtFolders
findItem(R.id.more_apps_from_us).isVisible = !resources.getBoolean(org.fossify.commons.R.bool.hide_google_relations)
findItem(R.id.open_recycle_bin).isVisible =
config.useRecycleBin && !config.showRecycleBinAtFolders
findItem(R.id.more_apps_from_us).isVisible =
!resources.getBoolean(org.fossify.commons.R.bool.hide_google_relations)
}
}
binding.mainMenu.getToolbar().menu.apply {
findItem(R.id.temporarily_show_hidden).isVisible = !config.shouldShowHidden
findItem(R.id.stop_showing_hidden).isVisible = (!isRPlus() || isExternalStorageManager()) && config.temporarilyShowHidden
findItem(R.id.stop_showing_hidden).isVisible =
(!isRPlus() || isExternalStorageManager()) && config.temporarilyShowHidden
findItem(R.id.temporarily_show_excluded).isVisible = !config.temporarilyShowExcluded
findItem(R.id.stop_showing_excluded).isVisible = config.temporarilyShowExcluded
@ -471,7 +487,8 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
binding.mainMenu.onSearchTextChangedListener = { text ->
setupAdapter(mDirsIgnoringSearch, text)
binding.directoriesRefreshLayout.isEnabled = text.isEmpty() && config.enablePullToRefresh
binding.directoriesRefreshLayout.isEnabled =
text.isEmpty() && config.enablePullToRefresh
binding.directoriesSwitchSearching.beVisibleIf(text.isNotEmpty())
}
@ -528,8 +545,17 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
if (config.tempFolderPath.isNotEmpty()) {
val newFolder = File(config.tempFolderPath)
if (getDoesFilePathExist(newFolder.absolutePath) && newFolder.isDirectory) {
if (newFolder.getProperSize(true) == 0L && newFolder.getFileCount(true) == 0 && newFolder.list()?.isEmpty() == true) {
toast(String.format(getString(org.fossify.commons.R.string.deleting_folder), config.tempFolderPath), Toast.LENGTH_LONG)
if (
newFolder.getProperSize(true) == 0L
&& newFolder.getFileCount(true) == 0
&& newFolder.list()?.isEmpty() == true
) {
toast(
String.format(
getString(org.fossify.commons.R.string.deleting_folder),
config.tempFolderPath
), Toast.LENGTH_LONG
)
tryDeleteFileDirItem(newFolder.toFileDirItem(applicationContext), true, true)
}
}
@ -540,7 +566,10 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
private fun checkOTGPath() {
ensureBackgroundThread {
if (!config.wasOTGHandled && hasPermission(getPermissionToRequest()) && hasOTGConnected() && config.OTGPath.isEmpty()) {
getStorageDirectories().firstOrNull { it.trimEnd('/') != internalStoragePath && it.trimEnd('/') != sdCardPath }?.apply {
getStorageDirectories().firstOrNull {
it.trimEnd('/') != internalStoragePath
&& it.trimEnd('/') != sdCardPath
}?.apply {
config.wasOTGHandled = true
val otgPath = trimEnd('/')
config.OTGPath = otgPath
@ -568,7 +597,8 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
private fun tryLoadGallery() {
// avoid calling anything right after granting the permission, it will be called from onResume()
val wasMissingPermission = config.appRunCount == 1 && !hasAllPermissions(getPermissionsToRequest())
val wasMissingPermission =
config.appRunCount == 1 && !hasAllPermissions(getPermissionsToRequest())
handleMediaPermissions {
if (wasMissingPermission) {
return@handleMediaPermissions
@ -707,23 +737,39 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
}
override fun deleteFolders(folders: ArrayList<File>) {
val fileDirItems =
folders.asSequence().filter { it.isDirectory }.map { FileDirItem(it.absolutePath, it.name, true) }.toMutableList() as ArrayList<FileDirItem>
val fileDirItems = folders
.asSequence()
.filter { it.isDirectory }
.map { FileDirItem(it.absolutePath, it.name, true) }
.toMutableList() as ArrayList<FileDirItem>
when {
fileDirItems.isEmpty() -> return
fileDirItems.size == 1 -> {
try {
toast(String.format(getString(org.fossify.commons.R.string.deleting_folder), fileDirItems.first().name))
toast(
String.format(
getString(org.fossify.commons.R.string.deleting_folder),
fileDirItems.first().name
)
)
} catch (e: Exception) {
showErrorToast(e)
}
}
else -> {
val baseString =
if (config.useRecycleBin && !config.tempSkipRecycleBin) org.fossify.commons.R.plurals.moving_items_into_bin else org.fossify.commons.R.plurals.delete_items
val deletingItems = resources.getQuantityString(baseString, fileDirItems.size, fileDirItems.size)
toast(deletingItems)
val baseString = if (config.useRecycleBin && !config.tempSkipRecycleBin) {
org.fossify.commons.R.plurals.moving_items_into_bin
} else {
org.fossify.commons.R.plurals.delete_items
}
toast(
msg = resources.getQuantityString(
baseString, fileDirItems.size, fileDirItems.size
)
)
}
}
@ -733,12 +779,13 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
fileDirItems.filter { it.isDirectory }.forEach {
val files = File(it.path).listFiles()
files?.filter {
it.absolutePath.isMediaFile() && (showHidden || !it.name.startsWith('.')) &&
((it.isImageFast() && filter and TYPE_IMAGES != 0) ||
(it.isVideoFast() && filter and TYPE_VIDEOS != 0) ||
(it.isGif() && filter and TYPE_GIFS != 0) ||
(it.isRawFast() && filter and TYPE_RAWS != 0) ||
(it.isSvg() && filter and TYPE_SVGS != 0))
it.absolutePath.isMediaFile()
&& (showHidden || !it.name.startsWith('.'))
&& ((it.isImageFast() && filter and TYPE_IMAGES != 0)
|| (it.isVideoFast() && filter and TYPE_VIDEOS != 0)
|| (it.isGif() && filter and TYPE_GIFS != 0)
|| (it.isRawFast() && filter and TYPE_RAWS != 0)
|| (it.isSvg() && filter and TYPE_SVGS != 0))
}?.mapTo(itemsToDelete) { it.toFileDirItem(applicationContext) }
}
@ -758,7 +805,10 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
}
}
private fun deleteFilteredFileDirItems(fileDirItems: ArrayList<FileDirItem>, folders: ArrayList<File>) {
private fun deleteFilteredFileDirItems(
fileDirItems: ArrayList<FileDirItem>,
folders: ArrayList<File>
) {
val OTGPath = config.OTGPath
deleteFiles(fileDirItems) {
runOnUiThread {
@ -771,7 +821,11 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
}
if (config.deleteEmptyFolders) {
folders.filter { !it.absolutePath.isDownloadsFolder() && it.isDirectory && it.toFileDirItem(this).getProperFileCount(this, true) == 0 }
folders.filter {
!it.absolutePath.isDownloadsFolder()
&& it.isDirectory
&& it.toFileDirItem(this).getProperFileCount(this, true) == 0
}
.forEach {
tryDeleteFileDirItem(it.toFileDirItem(this), true, true)
}
@ -787,7 +841,8 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
setupListLayoutManager()
}
(binding.directoriesRefreshLayout.layoutParams as RelativeLayout.LayoutParams).addRule(RelativeLayout.BELOW, R.id.directories_switch_searching)
(binding.directoriesRefreshLayout.layoutParams as RelativeLayout.LayoutParams)
.addRule(RelativeLayout.BELOW, R.id.directories_switch_searching)
}
private fun setupGridLayoutManager() {
@ -795,11 +850,17 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
if (config.scrollHorizontally) {
layoutManager.orientation = RecyclerView.HORIZONTAL
binding.directoriesRefreshLayout.layoutParams =
RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT)
RelativeLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
} else {
layoutManager.orientation = RecyclerView.VERTICAL
binding.directoriesRefreshLayout.layoutParams =
RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
RelativeLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
}
layoutManager.spanCount = config.dirColumnCnt
@ -809,7 +870,10 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
val layoutManager = binding.directoriesGrid.layoutManager as MyGridLayoutManager
layoutManager.spanCount = 1
layoutManager.orientation = RecyclerView.VERTICAL
binding.directoriesRefreshLayout.layoutParams = RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
binding.directoriesRefreshLayout.layoutParams = RelativeLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
mZoomListener = null
}
@ -850,10 +914,18 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
private fun changeColumnCount() {
val items = ArrayList<RadioItem>()
for (i in 1..MAX_COLUMN_COUNT) {
items.add(RadioItem(i, resources.getQuantityString(org.fossify.commons.R.plurals.column_counts, i, i)))
items.add(
RadioItem(
id = i,
title = resources.getQuantityString(
org.fossify.commons.R.plurals.column_counts, i, i
)
)
)
}
val currentColumnCount = (binding.directoriesGrid.layoutManager as MyGridLayoutManager).spanCount
val currentColumnCount =
(binding.directoriesGrid.layoutManager as MyGridLayoutManager).spanCount
RadioGroupDialog(this, items, currentColumnCount) {
val newColumnCount = it as Int
if (currentColumnCount != newColumnCount) {
@ -874,40 +946,69 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
}
private fun columnCountChanged() {
(binding.directoriesGrid.layoutManager as MyGridLayoutManager).spanCount = config.dirColumnCnt
(binding.directoriesGrid.layoutManager as MyGridLayoutManager).spanCount =
config.dirColumnCnt
refreshMenuItems()
getRecyclerAdapter()?.apply {
notifyItemRangeChanged(0, dirs.size)
}
}
private fun isPickImageIntent(intent: Intent) = isPickIntent(intent) && (hasImageContentData(intent) || isImageType(intent))
private fun isPickImageIntent(intent: Intent): Boolean {
return isPickIntent(intent) && (hasImageContentData(intent) || isImageType(intent))
}
private fun isPickVideoIntent(intent: Intent) = isPickIntent(intent) && (hasVideoContentData(intent) || isVideoType(intent))
private fun isPickVideoIntent(intent: Intent): Boolean {
return isPickIntent(intent) && (hasVideoContentData(intent) || isVideoType(intent))
}
private fun isPickIntent(intent: Intent) = intent.action == Intent.ACTION_PICK
private fun isPickIntent(intent: Intent): Boolean {
return intent.action == Intent.ACTION_PICK
}
private fun isGetContentIntent(intent: Intent) = intent.action == Intent.ACTION_GET_CONTENT && intent.type != null
private fun isGetContentIntent(intent: Intent): Boolean {
return intent.action == Intent.ACTION_GET_CONTENT && intent.type != null
}
private fun isGetImageContentIntent(intent: Intent) = isGetContentIntent(intent) &&
(intent.type!!.startsWith("image/") || intent.type == Images.Media.CONTENT_TYPE)
private fun isGetImageContentIntent(intent: Intent): Boolean {
return isGetContentIntent(intent)
&& (intent.type!!.startsWith("image/")
|| intent.type == Images.Media.CONTENT_TYPE)
}
private fun isGetVideoContentIntent(intent: Intent) = isGetContentIntent(intent) &&
(intent.type!!.startsWith("video/") || intent.type == Video.Media.CONTENT_TYPE)
private fun isGetVideoContentIntent(intent: Intent): Boolean {
return isGetContentIntent(intent)
&& (intent.type!!.startsWith("video/")
|| intent.type == Video.Media.CONTENT_TYPE)
}
private fun isGetAnyContentIntent(intent: Intent) = isGetContentIntent(intent) && intent.type == "*/*"
private fun isGetAnyContentIntent(intent: Intent): Boolean {
return isGetContentIntent(intent) && intent.type == "*/*"
}
private fun isSetWallpaperIntent(intent: Intent?) = intent?.action == Intent.ACTION_SET_WALLPAPER
private fun isSetWallpaperIntent(intent: Intent?): Boolean {
return intent?.action == Intent.ACTION_SET_WALLPAPER
}
private fun hasImageContentData(intent: Intent) = (intent.data == Images.Media.EXTERNAL_CONTENT_URI ||
intent.data == Images.Media.INTERNAL_CONTENT_URI)
private fun hasImageContentData(intent: Intent): Boolean {
return intent.data == Images.Media.EXTERNAL_CONTENT_URI
|| intent.data == Images.Media.INTERNAL_CONTENT_URI
}
private fun hasVideoContentData(intent: Intent) = (intent.data == Video.Media.EXTERNAL_CONTENT_URI ||
intent.data == Video.Media.INTERNAL_CONTENT_URI)
private fun hasVideoContentData(intent: Intent): Boolean {
return intent.data == Video.Media.EXTERNAL_CONTENT_URI
|| intent.data == Video.Media.INTERNAL_CONTENT_URI
}
private fun isImageType(intent: Intent) = (intent.type?.startsWith("image/") == true || intent.type == Images.Media.CONTENT_TYPE)
private fun isImageType(intent: Intent): Boolean {
return (intent.type?.startsWith("image/") == true
|| intent.type == Images.Media.CONTENT_TYPE)
}
private fun isVideoType(intent: Intent) = (intent.type?.startsWith("video/") == true || intent.type == Video.Media.CONTENT_TYPE)
private fun isVideoType(intent: Intent): Boolean {
return (intent.type?.startsWith("video/") == true
|| intent.type == Video.Media.CONTENT_TYPE)
}
private fun fillExtraOutput(resultData: Intent): Uri? {
val file = File(resultData.data!!.path!!)
@ -932,8 +1033,13 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
private fun fillPickedPaths(resultData: Intent, resultIntent: Intent) {
val paths = resultData.extras!!.getStringArrayList(PICKED_PATHS)
val uris = paths!!.map { getFilePublicUri(File(it), BuildConfig.APPLICATION_ID) } as ArrayList
val clipData = ClipData("Attachment", arrayOf("image/*", "video/*"), ClipData.Item(uris.removeAt(0)))
val uris = paths!!
.map { getFilePublicUri(File(it), BuildConfig.APPLICATION_ID) } as ArrayList
val clipData = ClipData(
"Attachment",
arrayOf("image/*", "video/*"),
ClipData.Item(uris.removeAt(0))
)
uris.forEach {
clipData.addItem(ClipData.Item(it))
@ -987,7 +1093,10 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
// if hidden item showing is disabled but all Favorite items are hidden, hide the Favorites folder
if (!config.shouldShowHidden) {
val favoritesFolder = newDirs.firstOrNull { it.areFavorites() }
if (favoritesFolder != null && favoritesFolder.tmb.getFilenameFromPath().startsWith('.')) {
if (
favoritesFolder != null
&& favoritesFolder.tmb.getFilenameFromPath().startsWith('.')
) {
newDirs.remove(favoritesFolder)
}
}
@ -1020,7 +1129,11 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
val lastModifieds = mLastMediaFetcher!!.getLastModifieds()
val dateTakens = mLastMediaFetcher!!.getDateTakens()
if (config.showRecycleBinAtFolders && !config.showRecycleBinLast && !dirs.map { it.path }.contains(RECYCLE_BIN)) {
if (
config.showRecycleBinAtFolders
&& !config.showRecycleBinLast
&& !dirs.map { it.path }.contains(RECYCLE_BIN)
) {
try {
if (mediaDB.getDeletedMediaCount() > 0) {
val recycleBin = Directory().apply {
@ -1048,7 +1161,14 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
}
// fetch files from MediaStore only, unless the app has the MANAGE_EXTERNAL_STORAGE permission on Android 11+
val android11Files = mLastMediaFetcher?.getAndroid11FolderMedia(getImagesOnly, getVideosOnly, favoritePaths, false, true, dateTakens)
val android11Files = mLastMediaFetcher?.getAndroid11FolderMedia(
isPickImage = getImagesOnly,
isPickVideo = getVideosOnly,
favoritePaths = favoritePaths,
getFavoritePathsOnly = false,
getProperDateTaken = true,
dateTakens = dateTakens
)
try {
for (directory in dirs) {
if (mShouldStopFetching || isDestroyed || isFinishing) {
@ -1057,19 +1177,29 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
val sorting = config.getFolderSorting(directory.path)
val grouping = config.getFolderGrouping(directory.path)
val getProperDateTaken = config.directorySorting and SORT_BY_DATE_TAKEN != 0 ||
sorting and SORT_BY_DATE_TAKEN != 0 ||
grouping and GROUP_BY_DATE_TAKEN_DAILY != 0 ||
grouping and GROUP_BY_DATE_TAKEN_MONTHLY != 0
val getProperDateTaken = config.directorySorting and SORT_BY_DATE_TAKEN != 0
|| sorting and SORT_BY_DATE_TAKEN != 0
|| grouping and GROUP_BY_DATE_TAKEN_DAILY != 0
|| grouping and GROUP_BY_DATE_TAKEN_MONTHLY != 0
val getProperLastModified = config.directorySorting and SORT_BY_DATE_MODIFIED != 0 ||
sorting and SORT_BY_DATE_MODIFIED != 0 ||
grouping and GROUP_BY_LAST_MODIFIED_DAILY != 0 ||
grouping and GROUP_BY_LAST_MODIFIED_MONTHLY != 0
val getProperLastModified =
config.directorySorting and SORT_BY_DATE_MODIFIED != 0
|| sorting and SORT_BY_DATE_MODIFIED != 0
|| grouping and GROUP_BY_LAST_MODIFIED_DAILY != 0
|| grouping and GROUP_BY_LAST_MODIFIED_MONTHLY != 0
val curMedia = mLastMediaFetcher!!.getFilesFrom(
directory.path, getImagesOnly, getVideosOnly, getProperDateTaken, getProperLastModified,
getProperFileSize, favoritePaths, false, lastModifieds, dateTakens, android11Files
curPath = directory.path,
isPickImage = getImagesOnly,
isPickVideo = getVideosOnly,
getProperDateTaken = getProperDateTaken,
getProperLastModified = getProperLastModified,
getProperFileSize = getProperFileSize,
favoritePaths = favoritePaths,
getVideoDurations = false,
lastModifieds = lastModifieds,
dateTakens = dateTakens,
android11Files = android11Files
)
val newDir = if (curMedia.isEmpty()) {
@ -1078,7 +1208,15 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
}
directory
} else {
createDirectoryFromMedia(directory.path, curMedia, albumCovers, hiddenString, includedFolders, getProperFileSize, noMediaFolders)
createDirectoryFromMedia(
path = directory.path,
curMedia = curMedia,
albumCovers = albumCovers,
hiddenString = hiddenString,
includedFolders = includedFolders,
getProperFileSize = getProperFileSize,
noMediaFolders = noMediaFolders
)
}
// we are looping through the already displayed folders looking for changes, do not do anything if nothing changed
@ -1164,19 +1302,28 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
val sorting = config.getFolderSorting(folder)
val grouping = config.getFolderGrouping(folder)
val getProperDateTaken = config.directorySorting and SORT_BY_DATE_TAKEN != 0 ||
sorting and SORT_BY_DATE_TAKEN != 0 ||
grouping and GROUP_BY_DATE_TAKEN_DAILY != 0 ||
grouping and GROUP_BY_DATE_TAKEN_MONTHLY != 0
val getProperDateTaken = config.directorySorting and SORT_BY_DATE_TAKEN != 0
|| sorting and SORT_BY_DATE_TAKEN != 0
|| grouping and GROUP_BY_DATE_TAKEN_DAILY != 0
|| grouping and GROUP_BY_DATE_TAKEN_MONTHLY != 0
val getProperLastModified = config.directorySorting and SORT_BY_DATE_MODIFIED != 0 ||
sorting and SORT_BY_DATE_MODIFIED != 0 ||
grouping and GROUP_BY_LAST_MODIFIED_DAILY != 0 ||
grouping and GROUP_BY_LAST_MODIFIED_MONTHLY != 0
val getProperLastModified = config.directorySorting and SORT_BY_DATE_MODIFIED != 0
|| sorting and SORT_BY_DATE_MODIFIED != 0
|| grouping and GROUP_BY_LAST_MODIFIED_DAILY != 0
|| grouping and GROUP_BY_LAST_MODIFIED_MONTHLY != 0
val newMedia = mLastMediaFetcher!!.getFilesFrom(
folder, getImagesOnly, getVideosOnly, getProperDateTaken, getProperLastModified,
getProperFileSize, favoritePaths, false, lastModifieds, dateTakens, android11Files
curPath = folder,
isPickImage = getImagesOnly,
isPickVideo = getVideosOnly,
getProperDateTaken = getProperDateTaken,
getProperLastModified = getProperLastModified,
getProperFileSize = getProperFileSize,
favoritePaths = favoritePaths,
getVideoDurations = false,
lastModifieds = lastModifieds,
dateTakens = dateTakens,
android11Files = android11Files
)
if (newMedia.isEmpty()) {
@ -1192,7 +1339,15 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
}
}
val newDir = createDirectoryFromMedia(folder, newMedia, albumCovers, hiddenString, includedFolders, getProperFileSize, noMediaFolders)
val newDir = createDirectoryFromMedia(
path = folder,
curMedia = newMedia,
albumCovers = albumCovers,
hiddenString = hiddenString,
includedFolders = includedFolders,
getProperFileSize = getProperFileSize,
noMediaFolders = noMediaFolders
)
dirs.add(newDir)
setupAdapter(dirs)
@ -1274,11 +1429,13 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
binding.directoriesEmptyPlaceholder2.beVisibleIf(dirs.isEmpty() && mLoadedInitialPhotos)
if (binding.mainMenu.isSearchOpen) {
binding.directoriesEmptyPlaceholder.text = getString(org.fossify.commons.R.string.no_items_found)
binding.directoriesEmptyPlaceholder.text =
getString(org.fossify.commons.R.string.no_items_found)
binding.directoriesEmptyPlaceholder2.beGone()
} else if (dirs.isEmpty() && config.filterMedia == getDefaultFileFilter()) {
if (isRPlus() && !isExternalStorageManager()) {
binding.directoriesEmptyPlaceholder.text = getString(org.fossify.commons.R.string.no_items_found)
binding.directoriesEmptyPlaceholder.text =
getString(org.fossify.commons.R.string.no_items_found)
binding.directoriesEmptyPlaceholder2.beGone()
} else {
binding.directoriesEmptyPlaceholder.text = getString(R.string.no_media_add_included)
@ -1292,7 +1449,8 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
}
} else {
binding.directoriesEmptyPlaceholder.text = getString(R.string.no_media_with_filters)
binding.directoriesEmptyPlaceholder2.text = getString(R.string.change_filters_underlined)
binding.directoriesEmptyPlaceholder2.text =
getString(R.string.change_filters_underlined)
binding.directoriesEmptyPlaceholder2.setOnClickListener {
showFilterMediaDialog()
@ -1303,11 +1461,22 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
binding.directoriesFastscroller.beVisibleIf(binding.directoriesEmptyPlaceholder.isGone())
}
private fun setupAdapter(dirs: ArrayList<Directory>, textToSearch: String = binding.mainMenu.getCurrentQuery(), forceRecreate: Boolean = false) {
private fun setupAdapter(
dirs: ArrayList<Directory>,
textToSearch: String = binding.mainMenu.getCurrentQuery(),
forceRecreate: Boolean = false
) {
val currAdapter = binding.directoriesGrid.adapter
val distinctDirs = dirs.distinctBy { it.path.getDistinctPath() }.toMutableList() as ArrayList<Directory>
val distinctDirs = dirs
.distinctBy { it.path.getDistinctPath() }
.toMutableList() as ArrayList<Directory>
val sortedDirs = getSortedDirectories(distinctDirs)
var dirsToShow = getDirsToShow(sortedDirs, mDirs, mCurrentPathPrefix).clone() as ArrayList<Directory>
var dirsToShow = getDirsToShow(
dirs = sortedDirs,
allDirs = mDirs,
currentPathPrefix = mCurrentPathPrefix
).clone() as ArrayList<Directory>
if (currAdapter == null || forceRecreate) {
mDirsIgnoringSearch = dirs
@ -1345,7 +1514,9 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
} else {
runOnUiThread {
if (textToSearch.isNotEmpty()) {
dirsToShow = dirsToShow.filter { it.name.contains(textToSearch, true) }.sortedBy { !it.name.startsWith(textToSearch, true) }
dirsToShow = dirsToShow
.filter { it.name.contains(textToSearch, true) }
.sortedBy { !it.name.startsWith(textToSearch, true) }
.toMutableList() as ArrayList
}
checkPlaceholderVisibility(dirsToShow)
@ -1361,7 +1532,8 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
}
private fun setupScrollDirection() {
val scrollHorizontally = config.scrollHorizontally && config.viewTypeFolders == VIEW_TYPE_GRID
val scrollHorizontally =
config.scrollHorizontally && config.viewTypeFolders == VIEW_TYPE_GRID
binding.directoriesFastscroller.setScrollVertically(!scrollHorizontally)
}
@ -1380,8 +1552,12 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
}
val hasMediaFile = children?.any {
it != null && (it.isMediaFile() || (it.startsWith("img_", true) && File(it).isDirectory))
} ?: false
it != null && (
it.isMediaFile()
|| (it.startsWith("img_", true)
&& File(it).isDirectory)
)
} == true
if (!hasMediaFile) {
invalidDirs.add(it)
@ -1458,7 +1634,9 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
Handler().postDelayed({
ensureBackgroundThread {
try {
val filesToDelete = mediaDB.getOldRecycleBinItems(System.currentTimeMillis() - MONTH_MILLISECONDS)
val filesToDelete = mediaDB.getOldRecycleBinItems(
System.currentTimeMillis() - MONTH_MILLISECONDS
)
filesToDelete.forEach {
if (File(it.path.replaceFirst(RECYCLE_BIN, recycleBinPath)).delete()) {
mediaDB.deleteMediumPath(it.path)
@ -1480,7 +1658,9 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
val internalPath = internalStoragePath
val checkedPaths = ArrayList<String>()
val oftenRepeatedPaths = ArrayList<String>()
val paths = mDirs.map { it.path.removePrefix(internalPath) }.toMutableList() as ArrayList<String>
val paths = mDirs
.map { it.path.removePrefix(internalPath) }
.toMutableList() as ArrayList<String>
paths.forEach {
val parts = it.split("/")
var currentString = ""

View file

@ -1,14 +1,13 @@
package org.fossify.gallery.activities
import android.app.Activity
import android.app.WallpaperManager
import android.content.Intent
import android.graphics.Bitmap
import android.net.Uri
import android.os.Bundle
import android.os.Handler
import android.view.ViewGroup
import android.widget.RelativeLayout
import androidx.core.net.toUri
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
@ -17,8 +16,41 @@ import com.bumptech.glide.request.target.SimpleTarget
import com.bumptech.glide.request.transition.Transition
import org.fossify.commons.dialogs.CreateNewFolderDialog
import org.fossify.commons.dialogs.RadioGroupDialog
import org.fossify.commons.extensions.*
import org.fossify.commons.helpers.*
import org.fossify.commons.extensions.appLockManager
import org.fossify.commons.extensions.areSystemAnimationsEnabled
import org.fossify.commons.extensions.beGone
import org.fossify.commons.extensions.beVisible
import org.fossify.commons.extensions.beVisibleIf
import org.fossify.commons.extensions.deleteFiles
import org.fossify.commons.extensions.getDoesFilePathExist
import org.fossify.commons.extensions.getFilenameFromPath
import org.fossify.commons.extensions.getIsPathDirectory
import org.fossify.commons.extensions.getLatestMediaByDateId
import org.fossify.commons.extensions.getLatestMediaId
import org.fossify.commons.extensions.getProperBackgroundColor
import org.fossify.commons.extensions.getProperPrimaryColor
import org.fossify.commons.extensions.getProperTextColor
import org.fossify.commons.extensions.getTimeFormat
import org.fossify.commons.extensions.handleHiddenFolderPasswordProtection
import org.fossify.commons.extensions.handleLockedFolderOpening
import org.fossify.commons.extensions.hideKeyboard
import org.fossify.commons.extensions.isExternalStorageManager
import org.fossify.commons.extensions.isGone
import org.fossify.commons.extensions.isMediaFile
import org.fossify.commons.extensions.isVideoFast
import org.fossify.commons.extensions.isVisible
import org.fossify.commons.extensions.recycleBinPath
import org.fossify.commons.extensions.showErrorToast
import org.fossify.commons.extensions.toast
import org.fossify.commons.extensions.viewBinding
import org.fossify.commons.helpers.FAVORITES
import org.fossify.commons.helpers.IS_FROM_GALLERY
import org.fossify.commons.helpers.REQUEST_EDIT_IMAGE
import org.fossify.commons.helpers.SORT_BY_RANDOM
import org.fossify.commons.helpers.VIEW_TYPE_GRID
import org.fossify.commons.helpers.VIEW_TYPE_LIST
import org.fossify.commons.helpers.ensureBackgroundThread
import org.fossify.commons.helpers.isRPlus
import org.fossify.commons.models.FileDirItem
import org.fossify.commons.models.RadioItem
import org.fossify.commons.views.MyGridLayoutManager
@ -28,9 +60,49 @@ import org.fossify.gallery.adapters.MediaAdapter
import org.fossify.gallery.asynctasks.GetMediaAsynctask
import org.fossify.gallery.databases.GalleryDatabase
import org.fossify.gallery.databinding.ActivityMediaBinding
import org.fossify.gallery.dialogs.*
import org.fossify.gallery.extensions.*
import org.fossify.gallery.helpers.*
import org.fossify.gallery.dialogs.ChangeGroupingDialog
import org.fossify.gallery.dialogs.ChangeSortingDialog
import org.fossify.gallery.dialogs.ChangeViewTypeDialog
import org.fossify.gallery.dialogs.FilterMediaDialog
import org.fossify.gallery.dialogs.GrantAllFilesDialog
import org.fossify.gallery.extensions.config
import org.fossify.gallery.extensions.deleteDBPath
import org.fossify.gallery.extensions.directoryDB
import org.fossify.gallery.extensions.emptyAndDisableTheRecycleBin
import org.fossify.gallery.extensions.emptyTheRecycleBin
import org.fossify.gallery.extensions.favoritesDB
import org.fossify.gallery.extensions.getCachedMedia
import org.fossify.gallery.extensions.getHumanizedFilename
import org.fossify.gallery.extensions.isDownloadsFolder
import org.fossify.gallery.extensions.launchAbout
import org.fossify.gallery.extensions.launchCamera
import org.fossify.gallery.extensions.launchSettings
import org.fossify.gallery.extensions.mediaDB
import org.fossify.gallery.extensions.movePathsInRecycleBin
import org.fossify.gallery.extensions.openPath
import org.fossify.gallery.extensions.openRecycleBin
import org.fossify.gallery.extensions.restoreRecycleBinPaths
import org.fossify.gallery.extensions.showRecycleBinEmptyingDialog
import org.fossify.gallery.extensions.tryDeleteFileDirItem
import org.fossify.gallery.extensions.updateWidgets
import org.fossify.gallery.helpers.DIRECTORY
import org.fossify.gallery.helpers.GET_ANY_INTENT
import org.fossify.gallery.helpers.GET_IMAGE_INTENT
import org.fossify.gallery.helpers.GET_VIDEO_INTENT
import org.fossify.gallery.helpers.GridSpacingItemDecoration
import org.fossify.gallery.helpers.IS_IN_RECYCLE_BIN
import org.fossify.gallery.helpers.MAX_COLUMN_COUNT
import org.fossify.gallery.helpers.MediaFetcher
import org.fossify.gallery.helpers.PATH
import org.fossify.gallery.helpers.PICKED_PATHS
import org.fossify.gallery.helpers.RECYCLE_BIN
import org.fossify.gallery.helpers.SET_WALLPAPER_INTENT
import org.fossify.gallery.helpers.SHOW_ALL
import org.fossify.gallery.helpers.SHOW_FAVORITES
import org.fossify.gallery.helpers.SHOW_RECYCLE_BIN
import org.fossify.gallery.helpers.SHOW_TEMP_HIDDEN_DURATION
import org.fossify.gallery.helpers.SKIP_AUTHENTICATION
import org.fossify.gallery.helpers.SLIDESHOW_START_ON_ENTER
import org.fossify.gallery.interfaces.MediaOperationsListener
import org.fossify.gallery.models.Medium
import org.fossify.gallery.models.ThumbnailItem
@ -99,7 +171,12 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
setupOptionsMenu()
refreshMenuItems()
storeStateVariables()
updateMaterialActivityViews(binding.mediaCoordinator, binding.mediaGrid, useTransparentNavigation = !config.scrollHorizontally, useTopSearchMenu = true)
updateMaterialActivityViews(
mainCoordinatorLayout = binding.mediaCoordinator,
nestedView = binding.mediaGrid,
useTransparentNavigation = !config.scrollHorizontally,
useTopSearchMenu = true
)
if (mShowAll) {
registerFileUpdateListener()
@ -240,7 +317,7 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
if (requestCode == REQUEST_EDIT_IMAGE) {
if (resultCode == Activity.RESULT_OK && resultData != null) {
if (resultCode == RESULT_OK && resultData != null) {
mMedia.clear()
refreshItems()
}
@ -249,7 +326,8 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
}
private fun refreshMenuItems() {
val isDefaultFolder = !config.defaultFolder.isEmpty() && File(config.defaultFolder).compareTo(File(mPath)) == 0
val isDefaultFolder = !config.defaultFolder.isEmpty()
&& File(config.defaultFolder).compareTo(File(mPath)) == 0
binding.mediaMenu.getToolbar().menu.apply {
findItem(R.id.group).isVisible = !config.scrollHorizontally
@ -261,11 +339,13 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
findItem(R.id.folder_view).isVisible = mShowAll
findItem(R.id.open_camera).isVisible = mShowAll
findItem(R.id.about).isVisible = mShowAll
findItem(R.id.create_new_folder).isVisible = !mShowAll && mPath != RECYCLE_BIN && mPath != FAVORITES
findItem(R.id.create_new_folder).isVisible =
!mShowAll && mPath != RECYCLE_BIN && mPath != FAVORITES
findItem(R.id.open_recycle_bin).isVisible = config.useRecycleBin && mPath != RECYCLE_BIN
findItem(R.id.temporarily_show_hidden).isVisible = !config.shouldShowHidden
findItem(R.id.stop_showing_hidden).isVisible = (!isRPlus() || isExternalStorageManager()) && config.temporarilyShowHidden
findItem(R.id.stop_showing_hidden).isVisible =
(!isRPlus() || isExternalStorageManager()) && config.temporarilyShowHidden
findItem(R.id.set_as_default_folder).isVisible = !isDefaultFolder
findItem(R.id.unset_as_default_folder).isVisible = isDefaultFolder
@ -352,12 +432,16 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
private fun searchQueryChanged(text: String) {
ensureBackgroundThread {
try {
val filtered = mMedia.filter { it is Medium && it.name.contains(text, true) } as ArrayList
val filtered = mMedia
.filter { it is Medium && it.name.contains(text, true) } as ArrayList
filtered.sortBy { it is Medium && !it.name.startsWith(text, true) }
val grouped = MediaFetcher(applicationContext).groupMedia(filtered as ArrayList<Medium>, mPath)
val grouped = MediaFetcher(applicationContext).groupMedia(
media = filtered as ArrayList<Medium>, path = mPath
)
runOnUiThread {
if (grouped.isEmpty()) {
binding.mediaEmptyTextPlaceholder.text = getString(org.fossify.commons.R.string.no_items_found)
binding.mediaEmptyTextPlaceholder.text =
getString(org.fossify.commons.R.string.no_items_found)
binding.mediaEmptyTextPlaceholder.beVisible()
binding.mediaFastscroller.beGone()
} else {
@ -417,8 +501,13 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
if (currAdapter == null) {
initZoomListener()
MediaAdapter(
this, mMedia.clone() as ArrayList<ThumbnailItem>, this, mIsGetImageIntent || mIsGetVideoIntent || mIsGetAnyIntent,
mAllowPickingMultiple, mPath, binding.mediaGrid
activity = this,
media = mMedia.clone() as ArrayList<ThumbnailItem>,
listener = this,
isAGetIntent = mIsGetImageIntent || mIsGetVideoIntent || mIsGetAnyIntent,
allowMultiplePicks = mAllowPickingMultiple,
path = mPath,
recyclerView = binding.mediaGrid
) {
if (it is Medium && !isFinishing) {
itemClicked(it.path)
@ -585,7 +674,13 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
private fun startAsyncTask() {
mCurrAsyncTask?.stopFetching()
mCurrAsyncTask = GetMediaAsynctask(applicationContext, mPath, mIsGetImageIntent, mIsGetVideoIntent, mShowAll) {
mCurrAsyncTask = GetMediaAsynctask(
context = applicationContext,
mPath = mPath,
isPickImage = mIsGetImageIntent,
isPickVideo = mIsGetVideoIntent,
showAll = mShowAll
) {
ensureBackgroundThread {
val oldMedia = mMedia.clone() as ArrayList<ThumbnailItem>
val newMedia = it
@ -594,14 +689,17 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
// remove cached files that are no longer valid for whatever reason
val newPaths = newMedia.mapNotNull { it as? Medium }.map { it.path }
oldMedia.mapNotNull { it as? Medium }.filter { !newPaths.contains(it.path) }.forEach {
if (mPath == FAVORITES && getDoesFilePathExist(it.path)) {
favoritesDB.deleteFavoritePath(it.path)
mediaDB.updateFavorite(it.path, false)
} else {
mediaDB.deleteMediumPath(it.path)
oldMedia
.mapNotNull { it as? Medium }
.filter { !newPaths.contains(it.path) }
.forEach {
if (mPath == FAVORITES && getDoesFilePathExist(it.path)) {
favoritesDB.deleteFavoritePath(it.path)
mediaDB.updateFavorite(it.path, false)
} else {
mediaDB.deleteMediumPath(it.path)
}
}
}
} catch (e: Exception) {
}
}
@ -611,7 +709,7 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
}
private fun isDirEmpty(): Boolean {
return if (mMedia.size <= 0 && config.filterMedia > 0) {
return if (mMedia.isEmpty() && config.filterMedia > 0) {
if (mPath != FAVORITES && mPath != RECYCLE_BIN) {
deleteDirectoryIfEmpty()
deleteDBDirectory()
@ -686,10 +784,16 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
val layoutManager = binding.mediaGrid.layoutManager as MyGridLayoutManager
if (config.scrollHorizontally) {
layoutManager.orientation = RecyclerView.HORIZONTAL
binding.mediaRefreshLayout.layoutParams = RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT)
binding.mediaRefreshLayout.layoutParams = RelativeLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
} else {
layoutManager.orientation = RecyclerView.VERTICAL
binding.mediaRefreshLayout.layoutParams = RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
binding.mediaRefreshLayout.layoutParams = RelativeLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
}
layoutManager.spanCount = config.mediaColumnCnt
@ -709,7 +813,10 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
val layoutManager = binding.mediaGrid.layoutManager as MyGridLayoutManager
layoutManager.spanCount = 1
layoutManager.orientation = RecyclerView.VERTICAL
binding.mediaRefreshLayout.layoutParams = RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
binding.mediaRefreshLayout.layoutParams = RelativeLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
mZoomListener = null
}
@ -722,11 +829,19 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
var currentGridDecoration: GridSpacingItemDecoration? = null
if (binding.mediaGrid.itemDecorationCount > 0) {
currentGridDecoration = binding.mediaGrid.getItemDecorationAt(0) as GridSpacingItemDecoration
currentGridDecoration =
binding.mediaGrid.getItemDecorationAt(0) as GridSpacingItemDecoration
currentGridDecoration.items = media
}
val newGridDecoration = GridSpacingItemDecoration(spanCount, spacing, config.scrollHorizontally, config.fileRoundedCorners, media, useGridPosition)
val newGridDecoration = GridSpacingItemDecoration(
spanCount = spanCount,
spacing = spacing,
isScrollingHorizontally = config.scrollHorizontally,
addSideSpacing = config.fileRoundedCorners,
items = media,
useGridPosition = useGridPosition
)
if (currentGridDecoration.toString() != newGridDecoration.toString()) {
if (currentGridDecoration != null) {
binding.mediaGrid.removeItemDecoration(currentGridDecoration)
@ -763,7 +878,14 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
private fun changeColumnCount() {
val items = ArrayList<RadioItem>()
for (i in 1..MAX_COLUMN_COUNT) {
items.add(RadioItem(i, resources.getQuantityString(org.fossify.commons.R.plurals.column_counts, i, i)))
items.add(
RadioItem(
id = i,
title = resources.getQuantityString(
org.fossify.commons.R.plurals.column_counts, i, i
)
)
)
}
val currentColumnCount = (binding.mediaGrid.layoutManager as MyGridLayoutManager).spanCount
@ -815,10 +937,13 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
.load(File(path))
.apply(options)
.into(object : SimpleTarget<Bitmap>() {
override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
override fun onResourceReady(
resource: Bitmap,
transition: Transition<in Bitmap>?
) {
try {
WallpaperManager.getInstance(applicationContext).setBitmap(resource)
setResult(Activity.RESULT_OK)
setResult(RESULT_OK)
} catch (ignored: IOException) {
}
@ -827,8 +952,8 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
})
} else if (mIsGetImageIntent || mIsGetVideoIntent || mIsGetAnyIntent) {
Intent().apply {
data = Uri.parse(path)
setResult(Activity.RESULT_OK, this)
data = path.toUri()
setResult(RESULT_OK, this)
}
finish()
} else {
@ -880,7 +1005,8 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
mLatestMediaId = getLatestMediaId()
mLatestMediaDateId = getLatestMediaByDateId()
if (!isFromCache) {
val mediaToInsert = (mMedia).filter { it is Medium && it.deletedTS == 0L }.map { it as Medium }
val mediaToInsert = mMedia
.filter { it is Medium && it.deletedTS == 0L }.map { it as Medium }
Thread {
try {
mediaDB.insertAll(mediaToInsert)
@ -891,13 +1017,22 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
}
override fun tryDeleteFiles(fileDirItems: ArrayList<FileDirItem>, skipRecycleBin: Boolean) {
val filtered = fileDirItems.filter { !getIsPathDirectory(it.path) && it.path.isMediaFile() } as ArrayList
val filtered = fileDirItems
.filter { !getIsPathDirectory(it.path) && it.path.isMediaFile() } as ArrayList
if (filtered.isEmpty()) {
return
}
if (config.useRecycleBin && !skipRecycleBin && !filtered.first().path.startsWith(recycleBinPath)) {
val movingItems = resources.getQuantityString(org.fossify.commons.R.plurals.moving_items_into_bin, filtered.size, filtered.size)
if (
config.useRecycleBin
&& !skipRecycleBin
&& !filtered.first().path.startsWith(recycleBinPath)
) {
val movingItems = resources.getQuantityString(
org.fossify.commons.R.plurals.moving_items_into_bin,
filtered.size,
filtered.size
)
toast(movingItems)
movePathsInRecycleBin(filtered.map { it.path } as ArrayList<String>) {
@ -908,13 +1043,19 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
}
}
} else {
val deletingItems = resources.getQuantityString(org.fossify.commons.R.plurals.deleting_items, filtered.size, filtered.size)
val deletingItems = resources.getQuantityString(
org.fossify.commons.R.plurals.deleting_items,
filtered.size,
filtered.size
)
toast(deletingItems)
deleteFilteredFiles(filtered)
}
}
private fun shouldSkipAuthentication() = intent.getBooleanExtra(SKIP_AUTHENTICATION, false)
private fun shouldSkipAuthentication(): Boolean {
return intent.getBooleanExtra(SKIP_AUTHENTICATION, false)
}
private fun deleteFilteredFiles(filtered: ArrayList<FileDirItem>) {
deleteFiles(filtered) {
@ -949,7 +1090,7 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
override fun selectedPaths(paths: ArrayList<String>) {
Intent().apply {
putExtra(PICKED_PATHS, paths)
setResult(Activity.RESULT_OK, this)
setResult(RESULT_OK, this)
}
finish()
}
@ -965,7 +1106,8 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener {
}
if (binding.mediaGrid.itemDecorationCount > 0) {
val currentGridDecoration = binding.mediaGrid.getItemDecorationAt(0) as GridSpacingItemDecoration
val currentGridDecoration =
binding.mediaGrid.getItemDecorationAt(0) as GridSpacingItemDecoration
currentGridDecoration.items = media
}
}

View file

@ -2,16 +2,32 @@ package org.fossify.gallery.dialogs
import android.content.DialogInterface
import org.fossify.commons.activities.BaseSimpleActivity
import org.fossify.commons.extensions.*
import org.fossify.commons.helpers.*
import org.fossify.commons.extensions.beGoneIf
import org.fossify.commons.extensions.beVisibleIf
import org.fossify.commons.extensions.getAlertDialogBuilder
import org.fossify.commons.extensions.isVisible
import org.fossify.commons.extensions.setupDialogStuff
import org.fossify.commons.helpers.SORT_BY_COUNT
import org.fossify.commons.helpers.SORT_BY_CUSTOM
import org.fossify.commons.helpers.SORT_BY_DATE_MODIFIED
import org.fossify.commons.helpers.SORT_BY_DATE_TAKEN
import org.fossify.commons.helpers.SORT_BY_NAME
import org.fossify.commons.helpers.SORT_BY_PATH
import org.fossify.commons.helpers.SORT_BY_RANDOM
import org.fossify.commons.helpers.SORT_BY_SIZE
import org.fossify.commons.helpers.SORT_DESCENDING
import org.fossify.commons.helpers.SORT_USE_NUMERIC_VALUE
import org.fossify.gallery.R
import org.fossify.gallery.databinding.DialogChangeSortingBinding
import org.fossify.gallery.extensions.config
import org.fossify.gallery.helpers.SHOW_ALL
class ChangeSortingDialog(
val activity: BaseSimpleActivity, val isDirectorySorting: Boolean, val showFolderCheckbox: Boolean,
val path: String = "", val callback: () -> Unit
val activity: BaseSimpleActivity,
val isDirectorySorting: Boolean,
val showFolderCheckbox: Boolean,
val path: String = "",
val callback: () -> Unit
) :
DialogInterface.OnClickListener {
private var currSorting = 0
@ -20,12 +36,24 @@ class ChangeSortingDialog(
private val binding: DialogChangeSortingBinding
init {
currSorting = if (isDirectorySorting) config.directorySorting else config.getFolderSorting(pathToUse)
currSorting = if (isDirectorySorting) {
config.directorySorting
} else {
config.getFolderSorting(pathToUse)
}
binding = DialogChangeSortingBinding.inflate(activity.layoutInflater).apply {
sortingDialogRadioNumberOfItems.beVisibleIf(isDirectorySorting)
sortingDialogOrderDivider.beVisibleIf(showFolderCheckbox || (currSorting and SORT_BY_NAME != 0 || currSorting and SORT_BY_PATH != 0))
sortingDialogOrderDivider.beVisibleIf(
beVisible = showFolderCheckbox
|| (currSorting and SORT_BY_NAME != 0 || currSorting and SORT_BY_PATH != 0)
)
sortingDialogNumericSorting.beVisibleIf(
beVisible = showFolderCheckbox
&& (currSorting and SORT_BY_NAME != 0 || currSorting and SORT_BY_PATH != 0)
)
sortingDialogNumericSorting.beVisibleIf(showFolderCheckbox && (currSorting and SORT_BY_NAME != 0 || currSorting and SORT_BY_PATH != 0))
sortingDialogNumericSorting.isChecked = currSorting and SORT_USE_NUMERIC_VALUE != 0
sortingDialogUseForThisFolder.beVisibleIf(showFolderCheckbox)
@ -48,11 +76,20 @@ class ChangeSortingDialog(
private fun setupSortRadio() {
val sortingRadio = binding.sortingDialogRadioSorting
sortingRadio.setOnCheckedChangeListener { _, checkedId ->
val isSortingByNameOrPath = checkedId == binding.sortingDialogRadioName.id || checkedId == binding.sortingDialogRadioPath.id
binding.sortingDialogNumericSorting.beVisibleIf(isSortingByNameOrPath)
binding.sortingDialogOrderDivider.beVisibleIf(binding.sortingDialogNumericSorting.isVisible() || binding.sortingDialogUseForThisFolder.isVisible())
val isSortingByNameOrPath =
checkedId == binding.sortingDialogRadioName.id
|| checkedId == binding.sortingDialogRadioPath.id
binding.sortingDialogNumericSorting.beVisibleIf(isSortingByNameOrPath)
binding.sortingDialogOrderDivider.beVisibleIf(
binding.sortingDialogNumericSorting.isVisible()
|| binding.sortingDialogUseForThisFolder.isVisible()
)
val hideSortOrder =
checkedId == binding.sortingDialogRadioCustom.id
|| checkedId == binding.sortingDialogRadioRandom.id
val hideSortOrder = checkedId == binding.sortingDialogRadioCustom.id || checkedId == binding.sortingDialogRadioRandom.id
binding.sortingDialogRadioOrder.beGoneIf(hideSortOrder)
binding.sortingDialogSortingDivider.beGoneIf(hideSortOrder)
}

View file

@ -33,23 +33,91 @@ import com.bumptech.glide.request.RequestOptions
import com.bumptech.glide.request.target.Target
import com.bumptech.glide.signature.ObjectKey
import com.squareup.picasso.Picasso
import org.fossify.commons.extensions.*
import org.fossify.commons.helpers.*
import org.fossify.commons.extensions.doesThisOrParentHaveNoMedia
import org.fossify.commons.extensions.getDocumentFile
import org.fossify.commons.extensions.getDoesFilePathExist
import org.fossify.commons.extensions.getDuration
import org.fossify.commons.extensions.getFilenameFromPath
import org.fossify.commons.extensions.getLongValue
import org.fossify.commons.extensions.getOTGPublicPath
import org.fossify.commons.extensions.getParentPath
import org.fossify.commons.extensions.getStringValue
import org.fossify.commons.extensions.humanizePath
import org.fossify.commons.extensions.internalStoragePath
import org.fossify.commons.extensions.isGif
import org.fossify.commons.extensions.isPathOnOTG
import org.fossify.commons.extensions.isPathOnSD
import org.fossify.commons.extensions.isPng
import org.fossify.commons.extensions.isPortrait
import org.fossify.commons.extensions.isRawFast
import org.fossify.commons.extensions.isSvg
import org.fossify.commons.extensions.isVideoFast
import org.fossify.commons.extensions.isWebP
import org.fossify.commons.extensions.normalizeString
import org.fossify.commons.extensions.otgPath
import org.fossify.commons.extensions.recycleBinPath
import org.fossify.commons.extensions.sdCardPath
import org.fossify.commons.extensions.toast
import org.fossify.commons.helpers.AlphanumericComparator
import org.fossify.commons.helpers.FAVORITES
import org.fossify.commons.helpers.NOMEDIA
import org.fossify.commons.helpers.SORT_BY_COUNT
import org.fossify.commons.helpers.SORT_BY_CUSTOM
import org.fossify.commons.helpers.SORT_BY_DATE_MODIFIED
import org.fossify.commons.helpers.SORT_BY_DATE_TAKEN
import org.fossify.commons.helpers.SORT_BY_NAME
import org.fossify.commons.helpers.SORT_BY_PATH
import org.fossify.commons.helpers.SORT_BY_RANDOM
import org.fossify.commons.helpers.SORT_BY_SIZE
import org.fossify.commons.helpers.SORT_DESCENDING
import org.fossify.commons.helpers.SORT_USE_NUMERIC_VALUE
import org.fossify.commons.helpers.ensureBackgroundThread
import org.fossify.commons.helpers.sumByLong
import org.fossify.commons.views.MySquareImageView
import org.fossify.gallery.R
import org.fossify.gallery.asynctasks.GetMediaAsynctask
import org.fossify.gallery.databases.GalleryDatabase
import org.fossify.gallery.helpers.*
import org.fossify.gallery.interfaces.*
import org.fossify.gallery.models.*
import org.fossify.gallery.helpers.Config
import org.fossify.gallery.helpers.GROUP_BY_DATE_TAKEN_DAILY
import org.fossify.gallery.helpers.GROUP_BY_DATE_TAKEN_MONTHLY
import org.fossify.gallery.helpers.GROUP_BY_LAST_MODIFIED_DAILY
import org.fossify.gallery.helpers.GROUP_BY_LAST_MODIFIED_MONTHLY
import org.fossify.gallery.helpers.IsoTypeReader
import org.fossify.gallery.helpers.LOCATION_INTERNAL
import org.fossify.gallery.helpers.LOCATION_OTG
import org.fossify.gallery.helpers.LOCATION_SD
import org.fossify.gallery.helpers.MediaFetcher
import org.fossify.gallery.helpers.MyWidgetProvider
import org.fossify.gallery.helpers.PicassoRoundedCornersTransformation
import org.fossify.gallery.helpers.RECYCLE_BIN
import org.fossify.gallery.helpers.ROUNDED_CORNERS_NONE
import org.fossify.gallery.helpers.ROUNDED_CORNERS_SMALL
import org.fossify.gallery.helpers.SHOW_ALL
import org.fossify.gallery.helpers.THUMBNAIL_FADE_DURATION_MS
import org.fossify.gallery.helpers.TYPE_GIFS
import org.fossify.gallery.helpers.TYPE_IMAGES
import org.fossify.gallery.helpers.TYPE_PORTRAITS
import org.fossify.gallery.helpers.TYPE_RAWS
import org.fossify.gallery.helpers.TYPE_SVGS
import org.fossify.gallery.helpers.TYPE_VIDEOS
import org.fossify.gallery.interfaces.DateTakensDao
import org.fossify.gallery.interfaces.DirectoryDao
import org.fossify.gallery.interfaces.FavoritesDao
import org.fossify.gallery.interfaces.MediumDao
import org.fossify.gallery.interfaces.WidgetsDao
import org.fossify.gallery.models.AlbumCover
import org.fossify.gallery.models.Directory
import org.fossify.gallery.models.Favorite
import org.fossify.gallery.models.Medium
import org.fossify.gallery.models.ThumbnailItem
import org.fossify.gallery.svg.SvgSoftwareLayerSetter
import java.io.File
import java.io.FileInputStream
import java.nio.ByteBuffer
import java.nio.channels.FileChannel
import java.util.Locale
import kotlin.collections.set
import kotlin.math.max
import kotlin.math.min
val Context.audioManager get() = getSystemService(Context.AUDIO_SERVICE) as AudioManager
@ -60,15 +128,19 @@ fun Context.getHumanizedFilename(path: String): String {
val Context.config: Config get() = Config.newInstance(applicationContext)
val Context.widgetsDB: WidgetsDao get() = GalleryDatabase.getInstance(applicationContext).WidgetsDao()
val Context.widgetsDB: WidgetsDao
get() = GalleryDatabase.getInstance(applicationContext).WidgetsDao()
val Context.mediaDB: MediumDao get() = GalleryDatabase.getInstance(applicationContext).MediumDao()
val Context.directoryDB: DirectoryDao get() = GalleryDatabase.getInstance(applicationContext).DirectoryDao()
val Context.directoryDB: DirectoryDao
get() = GalleryDatabase.getInstance(applicationContext).DirectoryDao()
val Context.favoritesDB: FavoritesDao get() = GalleryDatabase.getInstance(applicationContext).FavoritesDao()
val Context.favoritesDB: FavoritesDao
get() = GalleryDatabase.getInstance(applicationContext).FavoritesDao()
val Context.dateTakensDB: DateTakensDao get() = GalleryDatabase.getInstance(applicationContext).DateTakensDao()
val Context.dateTakensDB: DateTakensDao
get() = GalleryDatabase.getInstance(applicationContext).DateTakensDao()
val Context.recycleBin: File get() = filesDir
@ -140,11 +212,12 @@ fun Context.getSortedDirectories(source: ArrayList<Directory>): ArrayList<Direct
if (sorting and SORT_USE_NUMERIC_VALUE != 0) {
AlphanumericComparator().compare(
o1.sortValue.normalizeString().lowercase(Locale.getDefault()),
o2.sortValue.normalizeString().lowercase(Locale.getDefault())
string1 = o1.sortValue.normalizeString().lowercase(Locale.getDefault()),
string2 = o2.sortValue.normalizeString().lowercase(Locale.getDefault())
)
} else {
o1.sortValue.normalizeString().lowercase(Locale.getDefault()).compareTo(o2.sortValue.normalizeString().lowercase(Locale.getDefault()))
o1.sortValue.normalizeString().lowercase(Locale.getDefault())
.compareTo(o2.sortValue.normalizeString().lowercase(Locale.getDefault()))
}
}
@ -158,20 +231,17 @@ fun Context.getSortedDirectories(source: ArrayList<Directory>): ArrayList<Direct
}
if (sorting and SORT_USE_NUMERIC_VALUE != 0) {
AlphanumericComparator().compare(o1.sortValue.lowercase(Locale.getDefault()), o2.sortValue.lowercase(Locale.getDefault()))
AlphanumericComparator().compare(
string1 = o1.sortValue.lowercase(Locale.getDefault()),
string2 = o2.sortValue.lowercase(Locale.getDefault())
)
} else {
o1.sortValue.lowercase(Locale.getDefault()).compareTo(o2.sortValue.lowercase(Locale.getDefault()))
o1.sortValue.lowercase(Locale.getDefault())
.compareTo(o2.sortValue.lowercase(Locale.getDefault()))
}
}
sorting and SORT_BY_PATH != 0 -> AlphanumericComparator().compare(
o1.sortValue.lowercase(Locale.getDefault()),
o2.sortValue.lowercase(Locale.getDefault())
)
sorting and SORT_BY_SIZE != 0 -> (o1.sortValue.toLongOrNull() ?: 0).compareTo(o2.sortValue.toLongOrNull() ?: 0)
sorting and SORT_BY_COUNT != 0 -> (o1.sortValue.toLongOrNull() ?: 0).compareTo(o2.sortValue.toLongOrNull() ?: 0)
sorting and SORT_BY_DATE_MODIFIED != 0 -> (o1.sortValue.toLongOrNull() ?: 0).compareTo(o2.sortValue.toLongOrNull() ?: 0)
// SORT_BY_SIZE, SORT_BY_COUNT, SORT_BY_DATE_MODIFIED are numerical
else -> (o1.sortValue.toLongOrNull() ?: 0).compareTo(o2.sortValue.toLongOrNull() ?: 0)
}
@ -184,7 +254,11 @@ fun Context.getSortedDirectories(source: ArrayList<Directory>): ArrayList<Direct
return movePinnedDirectoriesToFront(dirs)
}
fun Context.getDirsToShow(dirs: ArrayList<Directory>, allDirs: ArrayList<Directory>, currentPathPrefix: String): ArrayList<Directory> {
fun Context.getDirsToShow(
dirs: ArrayList<Directory>,
allDirs: ArrayList<Directory>,
currentPathPrefix: String
): ArrayList<Directory> {
return if (config.groupDirectSubfolders) {
dirs.forEach {
it.subfoldersCount = 0
@ -197,8 +271,12 @@ fun Context.getDirsToShow(dirs: ArrayList<Directory>, allDirs: ArrayList<Directo
// show the current folder as an available option too, not just subfolders
if (currentPathPrefix.isNotEmpty()) {
val currentFolder =
allDirs.firstOrNull { parentDirs.firstOrNull { it.path.equals(currentPathPrefix, true) } == null && it.path.equals(currentPathPrefix, true) }
val currentFolder = allDirs.firstOrNull {
parentDirs.firstOrNull {
it.path.equals(currentPathPrefix, true)
} == null && it.path.equals(currentPathPrefix, true)
}
currentFolder?.apply {
subfoldersCount = 1
parentDirs.add(this)
@ -235,17 +313,17 @@ private fun Context.addParentWithoutMediaFiles(into: ArrayList<Directory>, path:
}
val directory = Directory(
newDirId + 1,
path,
subDirs.first().tmb,
getFolderNameFromPath(path),
subDirs.sumOf { it.mediaCnt },
lastModified,
dateTaken,
subDirs.sumByLong { it.size },
getPathLocation(path),
mediaTypes,
""
id = newDirId + 1,
path = path,
tmb = subDirs.first().tmb,
name = getFolderNameFromPath(path),
mediaCnt = subDirs.sumOf { it.mediaCnt },
modified = lastModified,
taken = dateTaken,
size = subDirs.sumByLong { it.size },
location = getPathLocation(path),
types = mediaTypes,
sortValue = ""
)
directory.containsMediaFilesDirectly = false
@ -275,7 +353,10 @@ fun Context.fillWithSharedDirectParents(dirs: ArrayList<Directory>): ArrayList<D
return allDirs
}
fun Context.getDirectParentSubfolders(dirs: ArrayList<Directory>, currentPathPrefix: String): ArrayList<Directory> {
fun Context.getDirectParentSubfolders(
dirs: ArrayList<Directory>,
currentPathPrefix: String
): ArrayList<Directory> {
val folders = dirs.map { it.path }.sorted().toMutableSet() as HashSet<String>
val currentPaths = LinkedHashSet<String>()
val foldersWithoutMediaFiles = ArrayList<String>()
@ -295,15 +376,28 @@ fun Context.getDirectParentSubfolders(dirs: ArrayList<Directory>, currentPathPre
}
}
if (currentPathPrefix.isNotEmpty() && path.equals(currentPathPrefix, true) || File(path).parent.equals(currentPathPrefix, true)) {
if (
currentPathPrefix.isNotEmpty() &&
path.equals(currentPathPrefix, true)
|| File(path).parent.equals(currentPathPrefix, true)
) {
currentPaths.add(path)
} else if (folders.any { !it.equals(path, true) && (File(path).parent.equals(it, true) || File(it).parent.equals(File(path).parent, true)) }) {
} else if (
folders.any {
!it.equals(path, true) && (File(path).parent.equals(it, true)
|| File(it).parent.equals(File(path).parent, true))
}
) {
// if we have folders like
// /storage/emulated/0/Pictures/Images and
// /storage/emulated/0/Pictures/Screenshots,
// but /storage/emulated/0/Pictures is empty, still Pictures with the first folders thumbnails and proper other info
val parent = File(path).parent
if (parent != null && !folders.contains(parent) && dirs.none { it.path.equals(parent, true) }) {
if (
parent != null
&& !folders.contains(parent)
&& dirs.none { it.path.equals(parent, true) }
) {
currentPaths.add(parent)
if (addParentWithoutMediaFiles(dirs, parent)) {
foldersWithoutMediaFiles.add(parent)
@ -318,7 +412,11 @@ fun Context.getDirectParentSubfolders(dirs: ArrayList<Directory>, currentPathPre
currentPaths.forEach {
val path = it
currentPaths.forEach {
if (!foldersWithoutMediaFiles.contains(it) && !it.equals(path, true) && File(it).parent?.equals(path, true) == true) {
if (
!foldersWithoutMediaFiles.contains(it)
&& !it.equals(path, true)
&& File(it).parent?.equals(path, true) == true
) {
areDirectSubfoldersAvailable = true
}
}
@ -347,7 +445,10 @@ fun Context.getDirectParentSubfolders(dirs: ArrayList<Directory>, currentPathPre
}
}
fun Context.updateSubfolderCounts(children: ArrayList<Directory>, parentDirs: ArrayList<Directory>) {
fun Context.updateSubfolderCounts(
children: ArrayList<Directory>,
parentDirs: ArrayList<Directory>
) {
for (child in children) {
var longestSharedPath = ""
for (parentDir in parentDirs) {
@ -356,14 +457,21 @@ fun Context.updateSubfolderCounts(children: ArrayList<Directory>, parentDirs: Ar
continue
}
if (child.path.startsWith(parentDir.path, true) && parentDir.path.length > longestSharedPath.length) {
if (
child.path.startsWith(parentDir.path, true)
&& parentDir.path.length > longestSharedPath.length
) {
longestSharedPath = parentDir.path
}
}
// make sure we count only the proper direct subfolders, grouped the same way as on the main screen
parentDirs.firstOrNull { it.path == longestSharedPath }?.apply {
if (path.equals(child.path, true) || path.equals(File(child.path).parent, true) || children.any { it.path.equals(File(child.path).parent, true) }) {
if (
path.equals(child.path, true)
|| path.equals(File(child.path).parent, true)
|| children.any { it.path.equals(File(child.path).parent, true) }
) {
if (child.containsMediaFilesDirectly) {
subfoldersCount++
}
@ -399,7 +507,10 @@ fun Context.getNoMediaFoldersSync(): ArrayList<String> {
do {
val path = cursor.getStringValue(Files.FileColumns.DATA) ?: continue
val noMediaFile = File(path)
if (getDoesFilePathExist(noMediaFile.absolutePath, OTGPath) && noMediaFile.name == NOMEDIA) {
if (
getDoesFilePathExist(noMediaFile.absolutePath, OTGPath)
&& noMediaFile.name == NOMEDIA
) {
folders.add(noMediaFile.parent)
}
} while (cursor.moveToNext())
@ -420,7 +531,13 @@ fun Context.rescanFolderMedia(path: String) {
fun Context.rescanFolderMediaSync(path: String) {
getCachedMedia(path) { cached ->
GetMediaAsynctask(applicationContext, path, isPickImage = false, isPickVideo = false, showAll = false) { newMedia ->
GetMediaAsynctask(
context = applicationContext,
mPath = path,
isPickImage = false,
isPickVideo = false,
showAll = false
) { newMedia ->
ensureBackgroundThread {
val media = newMedia.filterIsInstance<Medium>() as ArrayList<Medium>
try {
@ -447,14 +564,22 @@ fun Context.storeDirectoryItems(items: ArrayList<Directory>) {
}
}
fun Context.checkAppendingHidden(path: String, hidden: String, includedFolders: MutableSet<String>, noMediaFolders: ArrayList<String>): String {
fun Context.checkAppendingHidden(
path: String,
hidden: String,
includedFolders: MutableSet<String>,
noMediaFolders: ArrayList<String>
): String {
val dirName = getFolderNameFromPath(path)
val folderNoMediaStatuses = HashMap<String, Boolean>()
noMediaFolders.forEach { folder ->
folderNoMediaStatuses["$folder/$NOMEDIA"] = true
}
return if (path.doesThisOrParentHaveNoMedia(folderNoMediaStatuses, null) && !path.isThisOrParentIncluded(includedFolders)) {
return if (
path.doesThisOrParentHaveNoMedia(folderNoMediaStatuses, null)
&& !path.isThisOrParentIncluded(includedFolders)
) {
"$dirName $hidden"
} else {
dirName
@ -512,7 +637,19 @@ fun Context.addTempFolderIfNeeded(dirs: ArrayList<Directory>): ArrayList<Directo
val tempFolderPath = config.tempFolderPath
return if (tempFolderPath.isNotEmpty()) {
val directories = ArrayList<Directory>()
val newFolder = Directory(null, tempFolderPath, "", tempFolderPath.getFilenameFromPath(), 0, 0, 0, 0L, getPathLocation(tempFolderPath), 0, "")
val newFolder = Directory(
id = null,
path = tempFolderPath,
tmb = "",
name = tempFolderPath.getFilenameFromPath(),
mediaCnt = 0,
modified = 0,
taken = 0,
size = 0L,
location = getPathLocation(tempFolderPath),
types = 0,
sortValue = ""
)
directories.add(newFolder)
directories.addAll(dirs)
directories
@ -551,7 +688,10 @@ fun Context.loadImageBase(
if (cropThumbnails) {
options.optionalTransform(CenterCrop())
options.optionalTransform(WebpDrawable::class.java, WebpDrawableTransformation(CenterCrop()))
options.optionalTransform(
WebpDrawable::class.java,
WebpDrawableTransformation(CenterCrop())
)
} else {
options.optionalTransform(FitCenter())
options.optionalTransform(WebpDrawable::class.java, WebpDrawableTransformation(FitCenter()))
@ -576,7 +716,10 @@ fun Context.loadImageBase(
options.optionalTransform(MultiTransformation(CenterCrop(), roundedCornersTransform))
options.optionalTransform(
WebpDrawable::class.java,
MultiTransformation(WebpDrawableTransformation(CenterCrop()), WebpDrawableTransformation(roundedCornersTransform))
MultiTransformation(
WebpDrawableTransformation(CenterCrop()),
WebpDrawableTransformation(roundedCornersTransform)
)
)
}
@ -588,7 +731,12 @@ fun Context.loadImageBase(
.transition(getOptionalCrossFadeTransition(crossFadeDuration))
builder = builder.listener(object : RequestListener<Drawable> {
override fun onLoadFailed(e: GlideException?, model: Any?, targetBitmap: Target<Drawable>, isFirstResource: Boolean): Boolean {
override fun onLoadFailed(
e: GlideException?,
model: Any?,
targetBitmap: Target<Drawable>,
isFirstResource: Boolean
): Boolean {
if (tryLoadingWithPicasso) {
tryLoadingWithPicasso(path, target, cropThumbnails, roundCorners, signature)
} else {
@ -618,7 +766,11 @@ fun Context.loadSVG(
signature: ObjectKey,
crossFadeDuration: Int = THUMBNAIL_FADE_DURATION_MS,
) {
target.scaleType = if (cropThumbnails) ImageView.ScaleType.CENTER_CROP else ImageView.ScaleType.FIT_CENTER
target.scaleType = if (cropThumbnails) {
ImageView.ScaleType.CENTER_CROP
} else {
ImageView.ScaleType.FIT_CENTER
}
val options = RequestOptions().signature(signature)
var builder = Glide.with(applicationContext)
@ -642,7 +794,13 @@ fun Context.loadSVG(
}
// intended mostly for Android 11 issues, that fail loading PNG files bigger than 10 MB
fun Context.tryLoadingWithPicasso(path: String, view: MySquareImageView, cropThumbnails: Boolean, roundCorners: Int, signature: ObjectKey) {
fun Context.tryLoadingWithPicasso(
path: String,
view: MySquareImageView,
cropThumbnails: Boolean,
roundCorners: Int,
signature: ObjectKey
) {
var pathToLoad = "file://$path"
pathToLoad = pathToLoad.replace("%", "%25").replace("#", "%23")
@ -708,22 +866,27 @@ fun Context.getCachedDirectories(
}
var filteredDirectories = directories.filter {
it.path.shouldFolderBeVisible(excludedPaths, includedPaths, shouldShowHidden, folderNoMediaStatuses) { path, hasNoMedia ->
it.path.shouldFolderBeVisible(
excludedPaths = excludedPaths,
includedPaths = includedPaths,
showHidden = shouldShowHidden,
folderNoMediaStatuses = folderNoMediaStatuses
) { path, hasNoMedia ->
folderNoMediaStatuses[path] = hasNoMedia
}
} as ArrayList<Directory>
val filterMedia = config.filterMedia
val filterMedia = config.filterMedia
filteredDirectories = (when {
getVideosOnly -> filteredDirectories.filter { it.types and TYPE_VIDEOS != 0 }
getImagesOnly -> filteredDirectories.filter { it.types and TYPE_IMAGES != 0 }
else -> filteredDirectories.filter {
(filterMedia and TYPE_IMAGES != 0 && it.types and TYPE_IMAGES != 0) ||
(filterMedia and TYPE_VIDEOS != 0 && it.types and TYPE_VIDEOS != 0) ||
(filterMedia and TYPE_GIFS != 0 && it.types and TYPE_GIFS != 0) ||
(filterMedia and TYPE_RAWS != 0 && it.types and TYPE_RAWS != 0) ||
(filterMedia and TYPE_SVGS != 0 && it.types and TYPE_SVGS != 0) ||
(filterMedia and TYPE_PORTRAITS != 0 && it.types and TYPE_PORTRAITS != 0)
(filterMedia and TYPE_IMAGES != 0 && it.types and TYPE_IMAGES != 0)
|| (filterMedia and TYPE_VIDEOS != 0 && it.types and TYPE_VIDEOS != 0)
|| (filterMedia and TYPE_GIFS != 0 && it.types and TYPE_GIFS != 0)
|| (filterMedia and TYPE_RAWS != 0 && it.types and TYPE_RAWS != 0)
|| (filterMedia and TYPE_SVGS != 0 && it.types and TYPE_SVGS != 0)
|| (filterMedia and TYPE_PORTRAITS != 0 && it.types and TYPE_PORTRAITS != 0)
}
}) as ArrayList<Directory>
@ -754,10 +917,20 @@ fun Context.getCachedDirectories(
}
}
fun Context.getCachedMedia(path: String, getVideosOnly: Boolean = false, getImagesOnly: Boolean = false, callback: (ArrayList<ThumbnailItem>) -> Unit) {
fun Context.getCachedMedia(
path: String,
getVideosOnly: Boolean = false,
getImagesOnly: Boolean = false,
callback: (ArrayList<ThumbnailItem>) -> Unit
) {
ensureBackgroundThread {
val mediaFetcher = MediaFetcher(this)
val foldersToScan = if (path.isEmpty()) mediaFetcher.getFoldersToScan() else arrayListOf(path)
val foldersToScan = if (path.isEmpty()) {
mediaFetcher.getFoldersToScan()
} else {
arrayListOf(path)
}
var media = ArrayList<Medium>()
if (path == FAVORITES) {
media.addAll(mediaDB.getFavorites())
@ -796,12 +969,12 @@ fun Context.getCachedMedia(path: String, getVideosOnly: Boolean = false, getImag
getVideosOnly -> media.filter { it.type == TYPE_VIDEOS }
getImagesOnly -> media.filter { it.type == TYPE_IMAGES }
else -> media.filter {
(filterMedia and TYPE_IMAGES != 0 && it.type == TYPE_IMAGES) ||
(filterMedia and TYPE_VIDEOS != 0 && it.type == TYPE_VIDEOS) ||
(filterMedia and TYPE_GIFS != 0 && it.type == TYPE_GIFS) ||
(filterMedia and TYPE_RAWS != 0 && it.type == TYPE_RAWS) ||
(filterMedia and TYPE_SVGS != 0 && it.type == TYPE_SVGS) ||
(filterMedia and TYPE_PORTRAITS != 0 && it.type == TYPE_PORTRAITS)
(filterMedia and TYPE_IMAGES != 0 && it.type == TYPE_IMAGES)
|| (filterMedia and TYPE_VIDEOS != 0 && it.type == TYPE_VIDEOS)
|| (filterMedia and TYPE_GIFS != 0 && it.type == TYPE_GIFS)
|| (filterMedia and TYPE_RAWS != 0 && it.type == TYPE_RAWS)
|| (filterMedia and TYPE_SVGS != 0 && it.type == TYPE_SVGS)
|| (filterMedia and TYPE_PORTRAITS != 0 && it.type == TYPE_PORTRAITS)
}
}) as ArrayList<Medium>
@ -842,7 +1015,12 @@ fun Context.getCachedMedia(path: String, getVideosOnly: Boolean = false, getImag
fun Context.removeInvalidDBDirectories(dirs: ArrayList<Directory>? = null) {
val dirsToCheck = dirs ?: directoryDB.getAll()
val OTGPath = config.OTGPath
dirsToCheck.filter { !it.areFavorites() && !it.isRecycleBin() && !getDoesFilePathExist(it.path, OTGPath) && it.path != config.tempFolderPath }.forEach {
dirsToCheck.filter {
!it.areFavorites()
&& !it.isRecycleBin()
&& !getDoesFilePathExist(it.path, OTGPath)
&& it.path != config.tempFolderPath
}.forEach {
try {
directoryDB.deleteDirPath(it.path)
} catch (ignored: Exception) {
@ -863,14 +1041,14 @@ fun Context.updateDBMediaPath(oldPath: String, newPath: String) {
fun Context.updateDBDirectory(directory: Directory) {
try {
directoryDB.updateDirectory(
directory.path,
directory.tmb,
directory.mediaCnt,
directory.modified,
directory.taken,
directory.size,
directory.types,
directory.sortValue
path = directory.path,
thumbnail = directory.tmb,
mediaCnt = directory.mediaCnt,
lastModified = directory.modified,
dateTaken = directory.taken,
size = directory.size,
mediaTypes = directory.types,
sortValue = directory.sortValue
)
} catch (ignored: Exception) {
}
@ -878,7 +1056,9 @@ fun Context.updateDBDirectory(directory: Directory) {
fun Context.getOTGFolderChildren(path: String) = getDocumentFile(path)?.listFiles()
fun Context.getOTGFolderChildrenNames(path: String) = getOTGFolderChildren(path)?.map { it.name }?.toMutableList()
fun Context.getOTGFolderChildrenNames(path: String): MutableList<String?>? {
return getOTGFolderChildren(path)?.map { it.name }?.toMutableList()
}
fun Context.getFavoritePaths(): ArrayList<String> {
return try {
@ -888,7 +1068,9 @@ fun Context.getFavoritePaths(): ArrayList<String> {
}
}
fun Context.getFavoriteFromPath(path: String) = Favorite(null, path, path.getFilenameFromPath(), path.getParentPath())
fun Context.getFavoriteFromPath(path: String): Favorite {
return Favorite(null, path, path.getFilenameFromPath(), path.getParentPath())
}
fun Context.updateFavorite(path: String, isFavorite: Boolean) {
try {
@ -928,8 +1110,10 @@ fun Context.deleteMediumWithPath(path: String) {
}
fun Context.updateWidgets() {
val widgetIDs = AppWidgetManager.getInstance(applicationContext)?.getAppWidgetIds(ComponentName(applicationContext, MyWidgetProvider::class.java))
val widgetIDs = AppWidgetManager.getInstance(applicationContext)
?.getAppWidgetIds(ComponentName(applicationContext, MyWidgetProvider::class.java))
?: return
if (widgetIDs.isNotEmpty()) {
Intent(applicationContext, MyWidgetProvider::class.java).apply {
action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
@ -940,8 +1124,15 @@ fun Context.updateWidgets() {
}
// based on https://github.com/sannies/mp4parser/blob/master/examples/src/main/java/com/google/code/mp4parser/example/PrintStructure.java
fun Context.parseFileChannel(path: String, fc: FileChannel, level: Int, start: Long, end: Long, callback: () -> Unit) {
val FILE_CHANNEL_CONTAINERS = arrayListOf("moov", "trak", "mdia", "minf", "udta", "stbl")
fun Context.parseFileChannel(
path: String,
fc: FileChannel,
level: Int,
start: Long,
end: Long,
callback: () -> Unit
) {
val fileChannelContainers = arrayListOf("moov", "trak", "mdia", "minf", "udta", "stbl")
try {
var iteration = 0
var currEnd = end
@ -980,13 +1171,16 @@ fun Context.parseFileChannel(path: String, fc: FileChannel, level: Int, start: L
}
val xmlString = sb.toString().lowercase(Locale.getDefault())
if (xmlString.contains("gspherical:projectiontype>equirectangular") || xmlString.contains("gspherical:projectiontype=\"equirectangular\"")) {
if (
xmlString.contains("gspherical:projectiontype>equirectangular")
|| xmlString.contains("gspherical:projectiontype=\"equirectangular\"")
) {
callback.invoke()
}
return
}
if (FILE_CHANNEL_CONTAINERS.contains(type)) {
if (fileChannelContainers.contains(type)) {
parseFileChannel(path, fc, level + 1, begin + 8, newEnd, callback)
}
@ -1015,8 +1209,18 @@ fun Context.addPathToDB(path: String) {
val isFavorite = favoritesDB.isFavorite(path)
val videoDuration = if (type == TYPE_VIDEOS) getDuration(path) ?: 0 else 0
val medium = Medium(
null, path.getFilenameFromPath(), path, path.getParentPath(), System.currentTimeMillis(), System.currentTimeMillis(),
File(path).length(), type, videoDuration, isFavorite, 0L, 0L
id = null,
name = path.getFilenameFromPath(),
path = path,
parentPath = path.getParentPath(),
modified = System.currentTimeMillis(),
taken = System.currentTimeMillis(),
size = File(path).length(),
type = type,
videoDuration = videoDuration,
isFavorite = isFavorite,
deletedTS = 0L,
mediaStoreId = 0L
)
mediaDB.insert(medium)
@ -1058,16 +1262,44 @@ fun Context.createDirectoryFromMedia(
val firstItem = curMedia.firstOrNull() ?: defaultMedium
val lastItem = curMedia.lastOrNull() ?: defaultMedium
val dirName = checkAppendingHidden(path, hiddenString, includedFolders, noMediaFolders)
val lastModified = if (isSortingAscending) Math.min(firstItem.modified, lastItem.modified) else Math.max(firstItem.modified, lastItem.modified)
val dateTaken = if (isSortingAscending) Math.min(firstItem.taken, lastItem.taken) else Math.max(firstItem.taken, lastItem.taken)
val lastModified = if (isSortingAscending) {
min(firstItem.modified, lastItem.modified)
} else {
max(firstItem.modified, lastItem.modified)
}
val dateTaken = if (isSortingAscending) {
min(firstItem.taken, lastItem.taken)
} else {
max(firstItem.taken, lastItem.taken)
}
val size = if (getProperFileSize) curMedia.sumByLong { it.size } else 0L
val mediaTypes = curMedia.getDirMediaTypes()
val count = curMedia.size
val sortValue = getDirectorySortingValue(curMedia, path, dirName, size, count)
return Directory(null, path, thumbnail!!, dirName, curMedia.size, lastModified, dateTaken, size, getPathLocation(path), mediaTypes, sortValue)
return Directory(
id = null,
path = path,
tmb = thumbnail!!,
name = dirName,
mediaCnt = curMedia.size,
modified = lastModified,
taken = dateTaken,
size = size,
location = getPathLocation(path),
types = mediaTypes,
sortValue = sortValue
)
}
fun Context.getDirectorySortingValue(media: ArrayList<Medium>, path: String, name: String, size: Long, count: Int): String {
fun Context.getDirectorySortingValue(
media: ArrayList<Medium>,
path: String,
name: String,
size: Long,
count: Int
): String {
val sorting = config.directorySorting
val sorted = when {
sorting and SORT_BY_NAME != 0 -> return name
@ -1105,26 +1337,48 @@ fun Context.updateDirectoryPath(path: String) {
val sorting = config.getFolderSorting(path)
val grouping = config.getFolderGrouping(path)
val getProperDateTaken = config.directorySorting and SORT_BY_DATE_TAKEN != 0 ||
sorting and SORT_BY_DATE_TAKEN != 0 ||
grouping and GROUP_BY_DATE_TAKEN_DAILY != 0 ||
grouping and GROUP_BY_DATE_TAKEN_MONTHLY != 0
val getProperDateTaken = config.directorySorting and SORT_BY_DATE_TAKEN != 0
|| sorting and SORT_BY_DATE_TAKEN != 0
|| grouping and GROUP_BY_DATE_TAKEN_DAILY != 0
|| grouping and GROUP_BY_DATE_TAKEN_MONTHLY != 0
val getProperLastModified = config.directorySorting and SORT_BY_DATE_MODIFIED != 0 ||
sorting and SORT_BY_DATE_MODIFIED != 0 ||
grouping and GROUP_BY_LAST_MODIFIED_DAILY != 0 ||
grouping and GROUP_BY_LAST_MODIFIED_MONTHLY != 0
val getProperLastModified = config.directorySorting and SORT_BY_DATE_MODIFIED != 0
|| sorting and SORT_BY_DATE_MODIFIED != 0
|| grouping and GROUP_BY_LAST_MODIFIED_DAILY != 0
|| grouping and GROUP_BY_LAST_MODIFIED_MONTHLY != 0
val getProperFileSize = config.directorySorting and SORT_BY_SIZE != 0
val lastModifieds = if (getProperLastModified) mediaFetcher.getFolderLastModifieds(path) else HashMap()
val lastModifieds = if (getProperLastModified) {
mediaFetcher.getFolderLastModifieds(path)
} else {
HashMap()
}
val dateTakens = mediaFetcher.getFolderDateTakens(path)
val favoritePaths = getFavoritePaths()
val curMedia = mediaFetcher.getFilesFrom(
path, getImagesOnly, getVideosOnly, getProperDateTaken, getProperLastModified, getProperFileSize,
favoritePaths, false, lastModifieds, dateTakens, null
curPath = path,
isPickImage = getImagesOnly,
isPickVideo = getVideosOnly,
getProperDateTaken = getProperDateTaken,
getProperLastModified = getProperLastModified,
getProperFileSize = getProperFileSize,
favoritePaths = favoritePaths,
getVideoDurations = false,
lastModifieds = lastModifieds,
dateTakens = dateTakens,
android11Files = null
)
val directory = createDirectoryFromMedia(
path = path,
curMedia = curMedia,
albumCovers = albumCovers,
hiddenString = hiddenString,
includedFolders = includedFolders,
getProperFileSize = getProperFileSize,
noMediaFolders = noMediaFolders
)
val directory = createDirectoryFromMedia(path, curMedia, albumCovers, hiddenString, includedFolders, getProperFileSize, noMediaFolders)
updateDBDirectory(directory)
}