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 @@ +