diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 85395342a..da9c7ea86 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -32,6 +32,14 @@
android:name=".activities.MainActivity"
android:resizeableActivity="true">
+
+
+
+
+
+
diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/MainActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/MainActivity.kt
index ac11c3169..2609148ae 100644
--- a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/MainActivity.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/MainActivity.kt
@@ -1,7 +1,9 @@
package com.simplemobiletools.gallery.activities
import android.app.Activity
+import android.app.SearchManager
import android.content.ClipData
+import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Bundle
@@ -12,6 +14,8 @@ import android.view.MenuItem
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.Toast
+import androidx.appcompat.widget.SearchView
+import androidx.core.view.MenuItemCompat
import androidx.recyclerview.widget.RecyclerView
import com.simplemobiletools.commons.dialogs.CreateNewFolderDialog
import com.simplemobiletools.commons.dialogs.FilePickerDialog
@@ -60,11 +64,14 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
private var mIsPasswordProtectionPending = false
private var mWasProtectionHandled = false
private var mShouldStopFetching = false
+ private var mIsSearchOpen = false
private var mLatestMediaId = 0L
private var mLatestMediaDateId = 0L
private var mLastMediaHandler = Handler()
private var mTempShowHiddenHandler = Handler()
private var mZoomListener: MyRecyclerView.MyZoomListener? = null
+ private var mSearchMenuItem: MenuItem? = null
+ private var mDirs = ArrayList()
private var mStoredAnimateGifs = true
private var mStoredCropThumbnails = true
@@ -213,6 +220,8 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
override fun onStop() {
super.onStop()
+ mSearchMenuItem?.collapseActionView()
+
if (config.temporarilyShowHidden || config.tempSkipDeleteConfirmation) {
mTempShowHiddenHandler.postDelayed({
config.temporarilyShowHidden = false
@@ -244,8 +253,10 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
findItem(R.id.reduce_column_count).isVisible = config.viewTypeFolders == VIEW_TYPE_GRID && config.dirColumnCnt > 1
}
}
+
menu.findItem(R.id.temporarily_show_hidden).isVisible = !config.shouldShowHidden
menu.findItem(R.id.stop_showing_hidden).isVisible = config.temporarilyShowHidden
+ setupSearch(menu)
return true
}
@@ -292,6 +303,55 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
}
}
+ private fun setupSearch(menu: Menu) {
+ val searchManager = getSystemService(Context.SEARCH_SERVICE) as SearchManager
+ mSearchMenuItem = menu.findItem(R.id.search)
+ (mSearchMenuItem?.actionView as? SearchView)?.apply {
+ setSearchableInfo(searchManager.getSearchableInfo(componentName))
+ isSubmitButtonEnabled = false
+ setOnQueryTextListener(object : SearchView.OnQueryTextListener {
+ override fun onQueryTextSubmit(query: String) = false
+
+ override fun onQueryTextChange(newText: String): Boolean {
+ if (mIsSearchOpen) {
+ searchQueryChanged(newText)
+ }
+ return true
+ }
+ })
+ }
+
+ MenuItemCompat.setOnActionExpandListener(mSearchMenuItem, object : MenuItemCompat.OnActionExpandListener {
+ override fun onMenuItemActionExpand(item: MenuItem?): Boolean {
+ mIsSearchOpen = true
+ directories_refresh_layout.isEnabled = false
+ return true
+ }
+
+ // this triggers on device rotation too, avoid doing anything
+ override fun onMenuItemActionCollapse(item: MenuItem?): Boolean {
+ if (mIsSearchOpen) {
+ mIsSearchOpen = false
+ directories_refresh_layout.isEnabled = config.enablePullToRefresh
+ searchQueryChanged("")
+ }
+ return true
+ }
+ })
+ }
+
+ private fun searchQueryChanged(text: String) {
+ Thread {
+ val filtered = getUniqueSortedDirs(mDirs).filter { it.name.contains(text, true) } as ArrayList
+ filtered.sortBy { !it.name.startsWith(text, true) }
+
+ runOnUiThread {
+ getRecyclerAdapter()?.updateDirs(filtered)
+ measureRecyclerViewContent(filtered)
+ }
+ }.start()
+ }
+
private fun removeTempFolder() {
if (config.tempFolderPath.isNotEmpty()) {
val newFolder = File(config.tempFolderPath)
@@ -824,6 +884,7 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
} catch (e: Exception) {
config.everShownFolders = HashSet()
}
+ mDirs = dirs
}
private fun checkPlaceholderVisibility(dirs: ArrayList) {
@@ -833,14 +894,17 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
}
private fun showSortedDirs(dirs: ArrayList) {
- var sortedDirs = dirs.distinctBy { it.path.getDistinctPath() } as ArrayList
- sortedDirs = getSortedDirectories(sortedDirs)
-
+ val updatedDirs = getUniqueSortedDirs(dirs)
runOnUiThread {
- (directories_grid.adapter as? DirectoryAdapter)?.updateDirs(sortedDirs)
+ (directories_grid.adapter as? DirectoryAdapter)?.updateDirs(updatedDirs)
}
}
+ private fun getUniqueSortedDirs(dirs: ArrayList): ArrayList {
+ val sortedDirs = dirs.distinctBy { it.path.getDistinctPath() } as ArrayList
+ return getSortedDirectories(sortedDirs)
+ }
+
private fun createDirectoryFromMedia(path: String, curMedia: ArrayList, albumCovers: ArrayList, hiddenString: String,
includedFolders: MutableSet, isSortingAscending: Boolean): Directory {
var thumbnail = curMedia.firstOrNull { getDoesFilePathExist(it.path) }?.path ?: ""
@@ -884,7 +948,7 @@ class MainActivity : SimpleActivity(), DirectoryOperationsListener {
directories_grid.adapter = this
}
} else {
- (currAdapter as DirectoryAdapter).updateDirs(dirs)
+ showSortedDirs(dirs)
}
getRecyclerAdapter()?.dirs?.apply {
diff --git a/app/src/main/res/menu/menu_main.xml b/app/src/main/res/menu/menu_main.xml
index b1a4035e7..5d6ee89c7 100644
--- a/app/src/main/res/menu/menu_main.xml
+++ b/app/src/main/res/menu/menu_main.xml
@@ -1,6 +1,12 @@