From 7c8cd2f1f3ea6dd35d0f0559736e2d6b0d9d8b5b Mon Sep 17 00:00:00 2001 From: tibbi Date: Wed, 28 Oct 2020 18:05:26 +0100 Subject: [PATCH 01/13] removing the prompt about Simple Dialer, SMS Messenger and Voice Recorder --- .../gallery/pro/activities/MainActivity.kt | 6 ------ 1 file changed, 6 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/MainActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/MainActivity.kt index 6d9362de0..cadce60e4 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/MainActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/MainActivity.kt @@ -154,12 +154,6 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener { finish() } } - - // notify some users about the Dialer, SMS Messenger and Voice Recorder apps - if (!config.wasMessengerRecorderShown && config.appRunCount > 35) { - NewAppsIconsDialog(this) - config.wasMessengerRecorderShown = true - } } override fun onStart() { From ba4ba6a3384f0b57f24f5ad09b7eec676902edcf Mon Sep 17 00:00:00 2001 From: tibbi Date: Wed, 28 Oct 2020 18:05:38 +0100 Subject: [PATCH 02/13] make sure to rescan some WhatsApp folders by default --- .../com/simplemobiletools/gallery/pro/helpers/Config.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/helpers/Config.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/helpers/Config.kt index 9d70eb98c..984298a0d 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/helpers/Config.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/helpers/Config.kt @@ -405,8 +405,10 @@ class Config(context: Context) : BaseConfig(context) { Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).absolutePath, Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).absolutePath, "${Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).absolutePath}/Screenshots", - "internalStoragePath/WhatsApp/Media/WhatsApp Images", - "internalStoragePath/WhatsApp/Media/WhatsApp Video" + "$internalStoragePath/WhatsApp/Media/WhatsApp Images", + "$internalStoragePath/WhatsApp/Media/WhatsApp Images/Sent", + "$internalStoragePath/WhatsApp/Media/WhatsApp Video", + "$internalStoragePath/WhatsApp/Media/WhatsApp Video/Sent", ) var showRecycleBinAtFolders: Boolean From 736416c26caa9e9ae856fd2d61d052d33daf6a2a Mon Sep 17 00:00:00 2001 From: tibbi Date: Wed, 28 Oct 2020 18:47:18 +0100 Subject: [PATCH 03/13] fix #1946, properly handle overwriting edited files on an SD card --- .../gallery/pro/activities/NewEditActivity.kt | 83 ++++++++++++------- 1 file changed, 52 insertions(+), 31 deletions(-) diff --git a/app/src/proprietary/kotlin/com/simplemobiletools/gallery/pro/activities/NewEditActivity.kt b/app/src/proprietary/kotlin/com/simplemobiletools/gallery/pro/activities/NewEditActivity.kt index a1c5fa8cd..97a0bc72d 100644 --- a/app/src/proprietary/kotlin/com/simplemobiletools/gallery/pro/activities/NewEditActivity.kt +++ b/app/src/proprietary/kotlin/com/simplemobiletools/gallery/pro/activities/NewEditActivity.kt @@ -13,10 +13,12 @@ import com.simplemobiletools.commons.helpers.PERMISSION_WRITE_STORAGE import com.simplemobiletools.commons.helpers.REAL_FILE_PATH import com.simplemobiletools.commons.helpers.ensureBackgroundThread import com.simplemobiletools.commons.helpers.isNougatPlus +import com.simplemobiletools.commons.models.FileDirItem import com.simplemobiletools.gallery.pro.R import com.simplemobiletools.gallery.pro.dialogs.SaveAsDialog import com.simplemobiletools.gallery.pro.extensions.config import com.simplemobiletools.gallery.pro.extensions.fixDateTaken +import com.simplemobiletools.gallery.pro.extensions.tryDeleteFileDirItem import ly.img.android.pesdk.PhotoEditorSettingsList import ly.img.android.pesdk.assets.filter.basic.FilterPackBasic import ly.img.android.pesdk.assets.font.basic.FontPackBasic @@ -134,42 +136,44 @@ class NewEditActivity : SimpleActivity() { storeOldExif(source) sourceFileLastModified = File(source).lastModified() - var inputStream: InputStream? = null - var outputStream: OutputStream? = null - try { - inputStream = contentResolver.openInputStream(Uri.parse(resultPath)) - outputStream = getFileOutputStreamSync(destinationFilePath, destinationFilePath.getMimeType()) - inputStream!!.copyTo(outputStream!!) - outputStream.flush() - inputStream.close() - outputStream.close() - + handleFileOverwriting(destinationFilePath) { + var inputStream: InputStream? = null + var outputStream: OutputStream? = null try { - if (isNougatPlus()) { - val newExif = ExifInterface(destinationFilePath) - oldExif?.copyTo(newExif, false) + inputStream = contentResolver.openInputStream(Uri.parse(resultPath)) + outputStream = getFileOutputStreamSync(destinationFilePath, destinationFilePath.getMimeType()) + inputStream!!.copyTo(outputStream!!) + outputStream.flush() + inputStream.close() + outputStream.close() + + try { + if (isNougatPlus()) { + val newExif = ExifInterface(destinationFilePath) + oldExif?.copyTo(newExif, false) + } + } catch (ignored: Exception) { } - } catch (ignored: Exception) { - } - if (config.keepLastModified) { - // add 1 s to the last modified time to properly update the thumbnail - updateLastModified(destinationFilePath, sourceFileLastModified + 1000) - } + if (config.keepLastModified) { + // add 1 s to the last modified time to properly update the thumbnail + updateLastModified(destinationFilePath, sourceFileLastModified + 1000) + } - val paths = arrayListOf(destinationFilePath) - rescanPaths(arrayListOf(destinationFilePath)) { - fixDateTaken(paths, false) - } + val paths = arrayListOf(destinationFilePath) + rescanPaths(arrayListOf(destinationFilePath)) { + fixDateTaken(paths, false) + } - setResult(Activity.RESULT_OK, intent) - toast(R.string.file_edited_successfully) - finish() - } catch (e: Exception) { - showErrorToast(e) - } finally { - inputStream?.close() - outputStream?.close() + setResult(Activity.RESULT_OK, intent) + toast(R.string.file_edited_successfully) + finish() + } catch (e: Exception) { + showErrorToast(e) + } finally { + inputStream?.close() + outputStream?.close() + } } } } else { @@ -197,6 +201,23 @@ class NewEditActivity : SimpleActivity() { } } + // in case the user wants to overwrite the original file and it is on an SD card, delete it manually. Else the system just appends (1) + private fun handleFileOverwriting(path: String, callback: () -> Unit) { + if (getDoesFilePathExist(path) && isPathOnSD(path)) { + val fileDirItem = FileDirItem(path, path.getFilenameFromPath()) + tryDeleteFileDirItem(fileDirItem, false, true) { success -> + if (success) { + callback() + } else { + toast(R.string.unknown_error_occurred) + finish() + } + } + } else { + callback() + } + } + private fun openEditor(inputImage: Uri) { val settingsList = createPesdkSettingsList() From a4c590ddd3edfc3080a72505cd22ef3fecb73911 Mon Sep 17 00:00:00 2001 From: tibbi Date: Wed, 28 Oct 2020 20:06:34 +0100 Subject: [PATCH 04/13] insert created nomedia files into MediaStore manually --- .../gallery/pro/extensions/Activity.kt | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/extensions/Activity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/extensions/Activity.kt index 2c9b54f0c..1fcd09510 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/extensions/Activity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/extensions/Activity.kt @@ -3,6 +3,7 @@ package com.simplemobiletools.gallery.pro.extensions import android.annotation.TargetApi import android.app.Activity import android.content.ContentProviderOperation +import android.content.ContentValues import android.content.Intent import android.graphics.Bitmap import android.graphics.BitmapFactory @@ -13,6 +14,7 @@ import android.media.ExifInterface import android.net.Uri import android.os.Build import android.provider.MediaStore +import android.provider.MediaStore.Files import android.provider.MediaStore.Images import android.util.DisplayMetrics import android.view.View @@ -147,9 +149,8 @@ fun BaseSimpleActivity.addNoMedia(path: String, callback: () -> Unit) { val fileDocument = getDocumentFile(path) if (fileDocument?.exists() == true && fileDocument.isDirectory) { fileDocument.createFile("", NOMEDIA) - applicationContext.scanPathRecursively(file.absolutePath) { - callback() - } + addNoMediaIntoMediaStore(file.absolutePath) + callback() } else { toast(R.string.unknown_error_occurred) callback() @@ -158,7 +159,7 @@ fun BaseSimpleActivity.addNoMedia(path: String, callback: () -> Unit) { } else { try { if (file.createNewFile()) { - rescanFolderMedia(file.absolutePath) + addNoMediaIntoMediaStore(file.absolutePath) } else { toast(R.string.unknown_error_occurred) } @@ -169,6 +170,19 @@ fun BaseSimpleActivity.addNoMedia(path: String, callback: () -> Unit) { } } +fun BaseSimpleActivity.addNoMediaIntoMediaStore(path: String) { + try { + val content = ContentValues().apply { + put(Files.FileColumns.TITLE, NOMEDIA) + put(Files.FileColumns.DATA, path) + put(Files.FileColumns.MEDIA_TYPE, Files.FileColumns.MEDIA_TYPE_NONE) + } + contentResolver.insert(Files.getContentUri("external"), content) + } catch (e: Exception) { + showErrorToast(e) + } +} + fun BaseSimpleActivity.removeNoMedia(path: String, callback: (() -> Unit)? = null) { val file = File(path, NOMEDIA) if (!getDoesFilePathExist(file.absolutePath)) { From eb9ca5df77a265cbcc28c96cae9ad6d16c0c120b Mon Sep 17 00:00:00 2001 From: tibbi Date: Wed, 28 Oct 2020 20:34:30 +0100 Subject: [PATCH 05/13] fetch nomedia files from MediaStore, use them for quick check --- .../gallery/pro/extensions/Context.kt | 59 ++++++++++--------- .../gallery/pro/extensions/String.kt | 7 ++- .../gallery/pro/helpers/MediaFetcher.kt | 3 +- 3 files changed, 38 insertions(+), 31 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/extensions/Context.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/extensions/Context.kt index ba073f07c..10ecf9b34 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/extensions/Context.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/extensions/Context.kt @@ -304,35 +304,39 @@ fun Context.updateSubfolderCounts(children: ArrayList, parentDirs: Ar fun Context.getNoMediaFolders(callback: (folders: ArrayList) -> Unit) { ensureBackgroundThread { - val folders = ArrayList() - - val uri = Files.getContentUri("external") - val projection = arrayOf(Files.FileColumns.DATA) - val selection = "${Files.FileColumns.MEDIA_TYPE} = ? AND ${Files.FileColumns.TITLE} LIKE ?" - val selectionArgs = arrayOf(Files.FileColumns.MEDIA_TYPE_NONE.toString(), "%$NOMEDIA%") - val sortOrder = "${Files.FileColumns.DATE_MODIFIED} DESC" - val OTGPath = config.OTGPath - - var cursor: Cursor? = null - try { - cursor = contentResolver.query(uri, projection, selection, selectionArgs, sortOrder) - if (cursor?.moveToFirst() == true) { - do { - val path = cursor.getStringValue(Files.FileColumns.DATA) ?: continue - val noMediaFile = File(path) - if (getDoesFilePathExist(noMediaFile.absolutePath, OTGPath) && noMediaFile.name == NOMEDIA) { - folders.add("${noMediaFile.parent}/") - } - } while (cursor.moveToNext()) - } - } finally { - cursor?.close() - } - - callback(folders) + callback(getNoMediaFoldersSync()) } } +fun Context.getNoMediaFoldersSync(): ArrayList { + val folders = ArrayList() + + val uri = Files.getContentUri("external") + val projection = arrayOf(Files.FileColumns.DATA) + val selection = "${Files.FileColumns.MEDIA_TYPE} = ? AND ${Files.FileColumns.TITLE} LIKE ?" + val selectionArgs = arrayOf(Files.FileColumns.MEDIA_TYPE_NONE.toString(), "%$NOMEDIA%") + val sortOrder = "${Files.FileColumns.DATE_MODIFIED} DESC" + val OTGPath = config.OTGPath + + var cursor: Cursor? = null + try { + cursor = contentResolver.query(uri, projection, selection, selectionArgs, sortOrder) + if (cursor?.moveToFirst() == true) { + do { + val path = cursor.getStringValue(Files.FileColumns.DATA) ?: continue + val noMediaFile = File(path) + if (getDoesFilePathExist(noMediaFile.absolutePath, OTGPath) && noMediaFile.name == NOMEDIA) { + folders.add("${noMediaFile.parent}") + } + } while (cursor.moveToNext()) + } + } finally { + cursor?.close() + } + + return folders +} + fun Context.rescanFolderMedia(path: String) { ensureBackgroundThread { rescanFolderMediaSync(path) @@ -519,9 +523,10 @@ fun Context.getCachedDirectories(getVideosOnly: Boolean = false, getImagesOnly: val excludedPaths = config.excludedFolders val includedPaths = config.includedFolders + val noMediaFolders = getNoMediaFoldersSync() val folderNomediaStatuses = HashMap() var filteredDirectories = directories.filter { - it.path.shouldFolderBeVisible(excludedPaths, includedPaths, shouldShowHidden, folderNomediaStatuses) { path, hasNoMedia -> + it.path.shouldFolderBeVisible(excludedPaths, includedPaths, shouldShowHidden, folderNomediaStatuses, noMediaFolders) { path, hasNoMedia -> folderNomediaStatuses[path] = hasNoMedia } } as ArrayList diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/extensions/String.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/extensions/String.kt index e8e19edcb..87e92ec37 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/extensions/String.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/extensions/String.kt @@ -11,7 +11,8 @@ fun String.isThisOrParentExcluded(excludedPaths: MutableSet) = excludedP // cache which folders contain .nomedia files to avoid checking them over and over again fun String.shouldFolderBeVisible(excludedPaths: MutableSet, includedPaths: MutableSet, showHidden: Boolean, - folderNomediaStatuses: HashMap, callback: (path: String, hasNoMedia: Boolean) -> Unit): Boolean { + folderNomediaStatuses: HashMap, noMediaFolders: ArrayList = ArrayList(), + callback: (path: String, hasNoMedia: Boolean) -> Unit): Boolean { if (isEmpty()) { return false } @@ -36,7 +37,7 @@ fun String.shouldFolderBeVisible(excludedPaths: MutableSet, includedPath val containsNoMedia = if (showHidden) { false } else { - File(this, NOMEDIA).exists() + noMediaFolders.contains(this) || File(this, NOMEDIA).exists() } return if (!showHidden && containsNoMedia) { @@ -60,7 +61,7 @@ fun String.shouldFolderBeVisible(excludedPaths: MutableSet, includedPath break } } else { - val noMediaExists = File(pathToCheck).exists() + val noMediaExists = noMediaFolders.contains(pathToCheck) || File(pathToCheck).exists() callback(pathToCheck, noMediaExists) if (noMediaExists) { containsNoMediaOrDot = true diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/helpers/MediaFetcher.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/helpers/MediaFetcher.kt index ef2a6c52a..bd229721d 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/helpers/MediaFetcher.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/helpers/MediaFetcher.kt @@ -82,8 +82,9 @@ class MediaFetcher(val context: Context) { } } + val noMediaFolders = context.getNoMediaFoldersSync() distinctPaths.filter { - it.shouldFolderBeVisible(excludedPaths, includedPaths, shouldShowHidden, folderNomediaStatuses) { path, hasNoMedia -> + it.shouldFolderBeVisible(excludedPaths, includedPaths, shouldShowHidden, folderNomediaStatuses, noMediaFolders) { path, hasNoMedia -> folderNomediaStatuses[path] = hasNoMedia } }.toMutableList() as ArrayList From 4ef159e9122cd2290029c905181eb49e321c35e1 Mon Sep 17 00:00:00 2001 From: tibbi Date: Wed, 28 Oct 2020 21:01:51 +0100 Subject: [PATCH 06/13] rely on noMedia files from MediaStore on a couple more places --- app/build.gradle | 2 +- .../gallery/pro/activities/MainActivity.kt | 6 +++--- .../gallery/pro/adapters/DirectoryAdapter.kt | 10 +++++----- .../gallery/pro/extensions/Context.kt | 19 ++++++++++--------- .../gallery/pro/extensions/String.kt | 6 +++--- 5 files changed, 22 insertions(+), 21 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 0e1e1782d..0401e45ef 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -77,7 +77,7 @@ android { } dependencies { - implementation 'com.simplemobiletools:commons:5.31.8' + implementation 'com.simplemobiletools:commons:5.31.13' implementation 'com.theartofdev.edmodo:android-image-cropper:2.8.0' implementation 'it.sephiroth.android.exif:library:1.0.1' implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.19' diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/MainActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/MainActivity.kt index cadce60e4..ea9d72707 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/MainActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/activities/MainActivity.kt @@ -23,7 +23,6 @@ import androidx.recyclerview.widget.RecyclerView import com.simplemobiletools.commons.dialogs.ConfirmationDialog import com.simplemobiletools.commons.dialogs.CreateNewFolderDialog import com.simplemobiletools.commons.dialogs.FilePickerDialog -import com.simplemobiletools.commons.dialogs.NewAppsIconsDialog import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.helpers.* import com.simplemobiletools.commons.models.FileDirItem @@ -903,6 +902,7 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener { val hiddenString = getString(R.string.hidden) val albumCovers = config.parseAlbumCovers() val includedFolders = config.includedFolders + val noMediaFolders = getNoMediaFoldersSync() val tempFolderPath = config.tempFolderPath val getProperFileSize = config.directorySorting and SORT_BY_SIZE != 0 val favoritePaths = getFavoritePaths() @@ -937,7 +937,7 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener { } directory } else { - createDirectoryFromMedia(directory.path, curMedia, albumCovers, hiddenString, includedFolders, getProperFileSize) + createDirectoryFromMedia(directory.path, curMedia, albumCovers, hiddenString, includedFolders, getProperFileSize, noMediaFolders) } // we are looping through the already displayed folders looking for changes, do not do anything if nothing changed @@ -1043,7 +1043,7 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener { } } - val newDir = createDirectoryFromMedia(folder, newMedia, albumCovers, hiddenString, includedFolders, getProperFileSize) + val newDir = createDirectoryFromMedia(folder, newMedia, albumCovers, hiddenString, includedFolders, getProperFileSize, noMediaFolders) dirs.add(newDir) setupAdapter(dirs) diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/adapters/DirectoryAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/adapters/DirectoryAdapter.kt index 75a7146d7..fbbbe7db0 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/pro/adapters/DirectoryAdapter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/pro/adapters/DirectoryAdapter.kt @@ -305,7 +305,7 @@ class DirectoryAdapter(activity: BaseSimpleActivity, var dirs: ArrayList