diff --git a/app/src/main/kotlin/org/fossify/gallery/activities/MainActivity.kt b/app/src/main/kotlin/org/fossify/gallery/activities/MainActivity.kt index de2a8bead..344fd163a 100644 --- a/app/src/main/kotlin/org/fossify/gallery/activities/MainActivity.kt +++ b/app/src/main/kotlin/org/fossify/gallery/activities/MainActivity.kt @@ -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) } @@ -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) { - val fileDirItems = - folders.asSequence().filter { it.isDirectory }.map { FileDirItem(it.absolutePath, it.name, true) }.toMutableList() as ArrayList + val fileDirItems = folders + .asSequence() + .filter { it.isDirectory } + .map { FileDirItem(it.absolutePath, it.name, true) } + .toMutableList() as ArrayList + 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, folders: ArrayList) { + private fun deleteFilteredFileDirItems( + fileDirItems: ArrayList, + folders: ArrayList + ) { 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() 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, textToSearch: String = binding.mainMenu.getCurrentQuery(), forceRecreate: Boolean = false) { + private fun setupAdapter( + dirs: ArrayList, + textToSearch: String = binding.mainMenu.getCurrentQuery(), + forceRecreate: Boolean = false + ) { val currAdapter = binding.directoriesGrid.adapter - val distinctDirs = dirs.distinctBy { it.path.getDistinctPath() }.toMutableList() as ArrayList + val distinctDirs = dirs + .distinctBy { it.path.getDistinctPath() } + .toMutableList() as ArrayList + val sortedDirs = getSortedDirectories(distinctDirs) - var dirsToShow = getDirsToShow(sortedDirs, mDirs, mCurrentPathPrefix).clone() as ArrayList + var dirsToShow = getDirsToShow( + dirs = sortedDirs, + allDirs = mDirs, + currentPathPrefix = mCurrentPathPrefix + ).clone() as ArrayList 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() val oftenRepeatedPaths = ArrayList() - val paths = mDirs.map { it.path.removePrefix(internalPath) }.toMutableList() as ArrayList + val paths = mDirs + .map { it.path.removePrefix(internalPath) } + .toMutableList() as ArrayList paths.forEach { val parts = it.split("/") var currentString = "" diff --git a/app/src/main/kotlin/org/fossify/gallery/activities/MediaActivity.kt b/app/src/main/kotlin/org/fossify/gallery/activities/MediaActivity.kt index 4c6602a43..da132e5f9 100644 --- a/app/src/main/kotlin/org/fossify/gallery/activities/MediaActivity.kt +++ b/app/src/main/kotlin/org/fossify/gallery/activities/MediaActivity.kt @@ -17,8 +17,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 +61,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 +172,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() @@ -249,7 +327,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 +340,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 +433,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, mPath) + val grouped = MediaFetcher(applicationContext).groupMedia( + media = filtered as ArrayList, 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 +502,13 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener { if (currAdapter == null) { initZoomListener() MediaAdapter( - this, mMedia.clone() as ArrayList, this, mIsGetImageIntent || mIsGetVideoIntent || mIsGetAnyIntent, - mAllowPickingMultiple, mPath, binding.mediaGrid + activity = this, + media = mMedia.clone() as ArrayList, + listener = this, + isAGetIntent = mIsGetImageIntent || mIsGetVideoIntent || mIsGetAnyIntent, + allowMultiplePicks = mAllowPickingMultiple, + path = mPath, + recyclerView = binding.mediaGrid ) { if (it is Medium && !isFinishing) { itemClicked(it.path) @@ -585,7 +675,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 val newMedia = it @@ -594,14 +690,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 +710,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 +785,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 +814,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 +830,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 +879,14 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener { private fun changeColumnCount() { val items = ArrayList() 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,7 +938,10 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener { .load(File(path)) .apply(options) .into(object : SimpleTarget() { - override fun onResourceReady(resource: Bitmap, transition: Transition?) { + override fun onResourceReady( + resource: Bitmap, + transition: Transition? + ) { try { WallpaperManager.getInstance(applicationContext).setBitmap(resource) setResult(Activity.RESULT_OK) @@ -880,7 +1006,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 +1018,22 @@ class MediaActivity : SimpleActivity(), MediaOperationsListener { } override fun tryDeleteFiles(fileDirItems: ArrayList, 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) { @@ -908,13 +1044,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) { deleteFiles(filtered) { @@ -965,7 +1107,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 } } diff --git a/app/src/main/kotlin/org/fossify/gallery/dialogs/ChangeSortingDialog.kt b/app/src/main/kotlin/org/fossify/gallery/dialogs/ChangeSortingDialog.kt index dffc75fef..99a75238e 100644 --- a/app/src/main/kotlin/org/fossify/gallery/dialogs/ChangeSortingDialog.kt +++ b/app/src/main/kotlin/org/fossify/gallery/dialogs/ChangeSortingDialog.kt @@ -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) } diff --git a/app/src/main/kotlin/org/fossify/gallery/extensions/Context.kt b/app/src/main/kotlin/org/fossify/gallery/extensions/Context.kt index 482c50221..754fc0012 100644 --- a/app/src/main/kotlin/org/fossify/gallery/extensions/Context.kt +++ b/app/src/main/kotlin/org/fossify/gallery/extensions/Context.kt @@ -117,6 +117,7 @@ import java.nio.ByteBuffer import java.nio.channels.FileChannel import java.util.Locale import kotlin.math.max +import kotlin.math.min val Context.audioManager get() = getSystemService(Context.AUDIO_SERVICE) as AudioManager @@ -127,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 @@ -207,11 +212,12 @@ fun Context.getSortedDirectories(source: ArrayList): ArrayList): ArrayList): ArrayList, allDirs: ArrayList, currentPathPrefix: String): ArrayList { +fun Context.getDirsToShow( + dirs: ArrayList, + allDirs: ArrayList, + currentPathPrefix: String +): ArrayList { return if (config.groupDirectSubfolders) { dirs.forEach { it.subfoldersCount = 0 @@ -257,8 +271,12 @@ fun Context.getDirsToShow(dirs: ArrayList, allDirs: ArrayList, 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 @@ -335,7 +353,10 @@ fun Context.fillWithSharedDirectParents(dirs: ArrayList): ArrayList, currentPathPrefix: String): ArrayList { +fun Context.getDirectParentSubfolders( + dirs: ArrayList, + currentPathPrefix: String +): ArrayList { val folders = dirs.map { it.path }.sorted().toMutableSet() as HashSet val currentPaths = LinkedHashSet() val foldersWithoutMediaFiles = ArrayList() @@ -355,15 +376,28 @@ fun Context.getDirectParentSubfolders(dirs: ArrayList, 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) @@ -378,7 +412,11 @@ fun Context.getDirectParentSubfolders(dirs: ArrayList, 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 } } @@ -407,7 +445,10 @@ fun Context.getDirectParentSubfolders(dirs: ArrayList, currentPathPre } } -fun Context.updateSubfolderCounts(children: ArrayList, parentDirs: ArrayList) { +fun Context.updateSubfolderCounts( + children: ArrayList, + parentDirs: ArrayList +) { for (child in children) { var longestSharedPath = "" for (parentDir in parentDirs) { @@ -416,14 +457,21 @@ fun Context.updateSubfolderCounts(children: ArrayList, 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++ } @@ -459,7 +507,10 @@ fun Context.getNoMediaFoldersSync(): ArrayList { 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()) @@ -480,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() as ArrayList try { @@ -507,14 +564,22 @@ fun Context.storeDirectoryItems(items: ArrayList) { } } -fun Context.checkAppendingHidden(path: String, hidden: String, includedFolders: MutableSet, noMediaFolders: ArrayList): String { +fun Context.checkAppendingHidden( + path: String, + hidden: String, + includedFolders: MutableSet, + noMediaFolders: ArrayList +): String { val dirName = getFolderNameFromPath(path) val folderNoMediaStatuses = HashMap() 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 @@ -572,7 +637,19 @@ fun Context.addTempFolderIfNeeded(dirs: ArrayList): ArrayList() - 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 @@ -611,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())) @@ -636,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) + ) ) } @@ -648,7 +731,12 @@ fun Context.loadImageBase( .transition(getOptionalCrossFadeTransition(crossFadeDuration)) builder = builder.listener(object : RequestListener { - override fun onLoadFailed(e: GlideException?, model: Any?, targetBitmap: Target, isFirstResource: Boolean): Boolean { + override fun onLoadFailed( + e: GlideException?, + model: Any?, + targetBitmap: Target, + isFirstResource: Boolean + ): Boolean { if (tryLoadingWithPicasso) { tryLoadingWithPicasso(path, target, cropThumbnails, roundCorners, signature) } else { @@ -678,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) @@ -702,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") @@ -768,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 - 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 @@ -814,10 +917,20 @@ fun Context.getCachedDirectories( } } -fun Context.getCachedMedia(path: String, getVideosOnly: Boolean = false, getImagesOnly: Boolean = false, callback: (ArrayList) -> Unit) { +fun Context.getCachedMedia( + path: String, + getVideosOnly: Boolean = false, + getImagesOnly: Boolean = false, + callback: (ArrayList) -> 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() if (path == FAVORITES) { media.addAll(mediaDB.getFavorites()) @@ -856,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 @@ -902,7 +1015,12 @@ fun Context.getCachedMedia(path: String, getVideosOnly: Boolean = false, getImag fun Context.removeInvalidDBDirectories(dirs: ArrayList? = 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) { @@ -923,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) { } @@ -938,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? { + return getOTGFolderChildren(path)?.map { it.name }?.toMutableList() +} fun Context.getFavoritePaths(): ArrayList { return try { @@ -948,7 +1068,9 @@ fun Context.getFavoritePaths(): ArrayList { } } -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 { @@ -988,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 @@ -1000,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 @@ -1040,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) } @@ -1075,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) @@ -1118,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, path: String, name: String, size: Long, count: Int): String { +fun Context.getDirectorySortingValue( + media: ArrayList, + path: String, + name: String, + size: Long, + count: Int +): String { val sorting = config.directorySorting val sorted = when { sorting and SORT_BY_NAME != 0 -> return name @@ -1165,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) }