Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright (C) 2014-2024 Arpit Khurana <arpitkh96@gmail.com>, Vishal Nehra <vishalmeham2@gmail.com>,
* Emmanuel Messulam<emmanuelbendavid@gmail.com>, Raymond Lai <airwave209gt at gmail.com> and Contributors.
*
* This file is part of Amaze File Manager.
*
* Amaze File Manager is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package com.amaze.filemanager.asynchronous.asynctasks.searchfilesystem

import com.amaze.filemanager.adapters.data.LayoutElementParcelable
import kotlinx.coroutines.isActive
import kotlin.coroutines.coroutineContext

class ListElementsSearch(
query: String,
path: String,
searchParameters: SearchParameters,
private val items: List<LayoutElementParcelable>,
) : FileSearch(query, path, searchParameters) {
override suspend fun search(filter: SearchFilter) {
for (item in items) {
if (!coroutineContext.isActive) {
break
}

if (item.isBack || item.header) {
continue
}

val resultRange = filter.searchFilter(item.title)
if (resultRange != null) {
publishProgress(item.generateBaseFile(), resultRange)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ import com.amaze.filemanager.adapters.data.LayoutElementParcelable
import com.amaze.filemanager.application.AppConfig
import com.amaze.filemanager.asynchronous.asynctasks.searchfilesystem.BasicSearch
import com.amaze.filemanager.asynchronous.asynctasks.searchfilesystem.DeepSearch
import com.amaze.filemanager.asynchronous.asynctasks.searchfilesystem.FileSearch
import com.amaze.filemanager.asynchronous.asynctasks.searchfilesystem.IndexedSearch
import com.amaze.filemanager.asynchronous.asynctasks.searchfilesystem.ListElementsSearch
import com.amaze.filemanager.asynchronous.asynctasks.searchfilesystem.SearchParameters
import com.amaze.filemanager.asynchronous.asynctasks.searchfilesystem.SearchResult
import com.amaze.filemanager.asynchronous.asynctasks.searchfilesystem.searchParametersFromBoolean
Expand Down Expand Up @@ -117,18 +119,30 @@ class MainActivityViewModel(val applicationContext: Application) :
query: String,
): LiveData<List<SearchResult>> {
val searchParameters = createSearchParameters(mainActivity)

val path = mainActivity.currentMainFragment?.currentPath ?: ""
val openMode =
mainActivity.currentMainFragment?.mainFragmentViewModel?.openMode ?: OpenMode.FILE

val basicSearch = BasicSearch(query, path, searchParameters, this.applicationContext)
val fileSearch: FileSearch =
if (openMode == OpenMode.CUSTOM || openMode == OpenMode.TRASH_BIN) {
ListElementsSearch(
query,
path,
searchParameters,
mainActivity.currentMainFragment?.mainFragmentViewModel?.listElements
?: emptyList(),
)
} else {
BasicSearch(query, path, searchParameters, this.applicationContext)
}

lastSearchJob =
viewModelScope.launch(Dispatchers.IO) {
basicSearch.search()
fileSearch.search()
}

lastSearchLiveData = basicSearch.foundFilesLiveData
return basicSearch.foundFilesLiveData
lastSearchLiveData = fileSearch.foundFilesLiveData
return fileSearch.foundFilesLiveData
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import com.amaze.filemanager.adapters.SearchRecyclerViewAdapter;
import com.amaze.filemanager.asynchronous.asynctasks.searchfilesystem.SearchResult;
import com.amaze.filemanager.asynchronous.asynctasks.searchfilesystem.SearchResultListSorter;
import com.amaze.filemanager.fileoperations.filesystem.OpenMode;
import com.amaze.filemanager.filesystem.files.sort.DirSortBy;
import com.amaze.filemanager.filesystem.files.sort.SortBy;
import com.amaze.filemanager.filesystem.files.sort.SortOrder;
Expand Down Expand Up @@ -272,9 +273,18 @@ private void basicSearch(String s) {
searchResultsHintTV.setVisibility(View.VISIBLE);
searchResultsSortButton.setVisibility(View.VISIBLE);
searchResultsSortHintTV.setVisibility(View.VISIBLE);
deepSearchContainer.setVisibility(View.VISIBLE);
searchMode = 1;
deepSearchButton.setText(mainActivity.getString(R.string.try_indexed_search));

OpenMode openMode =
mainActivity.getCurrentMainFragment().getMainFragmentViewModel().getOpenMode();

if (openMode == OpenMode.CUSTOM || openMode == OpenMode.TRASH_BIN) {
deepSearchContainer.setVisibility(View.GONE);
searchMode = 0;
} else {
deepSearchContainer.setVisibility(View.VISIBLE);
searchMode = 1;
deepSearchButton.setText(mainActivity.getString(R.string.try_indexed_search));
}

mainActivity
.getCurrentMainFragment()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
/*
* Copyright (C) 2014-2024 Arpit Khurana <arpitkh96@gmail.com>, Vishal Nehra <vishalmeham2@gmail.com>,
* Emmanuel Messulam<emmanuelbendavid@gmail.com>, Raymond Lai <airwave209gt at gmail.com> and Contributors.
*
* This file is part of Amaze File Manager.
*
* Amaze File Manager is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package com.amaze.filemanager.asynchronous.asynctasks.searchfilesystem

import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.amaze.filemanager.adapters.data.LayoutElementParcelable
import com.amaze.filemanager.fileoperations.filesystem.OpenMode
import kotlinx.coroutines.test.runTest
import org.junit.Assert
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import java.util.EnumSet

@RunWith(AndroidJUnit4::class)
class ListElementsSearchTest {
private companion object {
const val QUERY = "report"
}

@get:Rule
val rule = InstantTaskExecutorRule()

/**
* If the visible item title matches the query, the item should be added to
* [FileSearch.foundFilesLiveData]
*/
@Test
fun testSimpleSearchMatch() {
val search =
ListElementsSearch(
QUERY,
"/",
EnumSet.noneOf(SearchParameter::class.java),
listOf(
layoutElement("Annual Report.pdf", "/drawer/Annual Report.pdf"),
layoutElement("Vacation Photo.jpg", "/drawer/Vacation Photo.jpg"),
),
)

search.foundFilesLiveData.observeForever { actualResults ->
Assert.assertNotNull(actualResults)
Assert.assertEquals(listOf("Annual Report.pdf"), actualResults.map { it.file.getName() })
Assert.assertEquals(listOf("/drawer/Annual Report.pdf"), actualResults.map { it.file.getPath() })
Assert.assertEquals(listOf(7..12), actualResults.map { it.matchRange })
}

runTest {
search.search()
}
}

/**
* Back and header items should not be added to
* [FileSearch.foundFilesLiveData]
*/
@Test
fun testSkipsBackAndHeaderItems() {
val search =
ListElementsSearch(
QUERY,
"/",
EnumSet.noneOf(SearchParameter::class.java),
listOf(
layoutElement("Report Back", "/drawer/back", isBack = true),
layoutElement("Report Header", "/drawer/header", header = true),
layoutElement("Report File.txt", "/drawer/Report File.txt"),
),
)

search.foundFilesLiveData.observeForever { actualResults ->
Assert.assertNotNull(actualResults)
Assert.assertEquals(listOf("Report File.txt"), actualResults.map { it.file.getName() })
Assert.assertEquals(listOf("/drawer/Report File.txt"), actualResults.map { it.file.getPath() })
}

runTest {
search.search()
}
}

/**
* If no visible item title matches the query, no results should be published to
* [FileSearch.foundFilesLiveData]
*/
@Test
fun testNoMatchDoesNotPublishResults() {
var observerCalled = false

val search =
ListElementsSearch(
QUERY,
"/",
EnumSet.noneOf(SearchParameter::class.java),
listOf(
layoutElement("Vacation Photo.jpg", "/drawer/Vacation Photo.jpg"),
layoutElement("Budget 2025.xlsx", "/drawer/Budget 2025.xlsx"),
),
)

search.foundFilesLiveData.observeForever {
observerCalled = true
}

runTest {
search.search()
}

Assert.assertFalse(observerCalled)
}

private fun layoutElement(
title: String,
path: String,
isBack: Boolean = false,
header: Boolean = false,
): LayoutElementParcelable =
LayoutElementParcelable(
ApplicationProvider.getApplicationContext(),
isBack,
title,
path,
"",
"",
"",
0,
header,
"",
false,
false,
OpenMode.FILE,
)
}