diff --git a/app/src/main/java/com/nextcloud/utils/extensions/FileDataStorageManagerExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/FileDataStorageManagerExtensions.kt index 7231ab65cd60..c347da0252a6 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/FileDataStorageManagerExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/FileDataStorageManagerExtensions.kt @@ -98,10 +98,12 @@ suspend fun FileDataStorageManager.getGalleryItemsPageSuspended( return result } -fun FileDataStorageManager.searchFilesByName(file: OCFile, accountName: String, query: String): List = - fileDao.searchFilesInFolder(file.fileId, accountName, query).map { - createFileInstance(it) - } +fun FileDataStorageManager.searchFilesByName(file: OCFile, accountName: String, query: String): List { + val terms = query.toSearchTerms() + return fileDao.searchFilesInFolder(file.fileId, accountName, terms.firstOrNull().orEmpty()) + .filter { it.name.orEmpty().containsAllTerms(terms) } + .map { createFileInstance(it) } +} fun FileDataStorageManager.getDecryptedPath(file: OCFile): String { val paths = mutableListOf() diff --git a/app/src/main/java/com/nextcloud/utils/extensions/StringExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/StringExtensions.kt index ca827301ca76..ab0c13928079 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/StringExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/StringExtensions.kt @@ -55,6 +55,12 @@ fun String.extension(): String { fun String.truncateWithEllipsis(limit: Int) = take(limit) + if (length > limit) StringConstants.THREE_DOT else "" +private val whitespaceRegex = Regex("""\s+""") + +fun String.toSearchTerms(): List = split(whitespaceRegex).filter { it.isNotEmpty() } + +fun String.containsAllTerms(terms: List): Boolean = terms.all { contains(it, ignoreCase = true) } + object StringConstants { const val SLASH = "/" const val DOT = "." diff --git a/app/src/main/java/com/owncloud/android/ui/unifiedsearch/SearchOnProviderTask.kt b/app/src/main/java/com/owncloud/android/ui/unifiedsearch/SearchOnProviderTask.kt index 5cbf6d0b3447..ba6e57423934 100644 --- a/app/src/main/java/com/owncloud/android/ui/unifiedsearch/SearchOnProviderTask.kt +++ b/app/src/main/java/com/owncloud/android/ui/unifiedsearch/SearchOnProviderTask.kt @@ -8,7 +8,10 @@ package com.owncloud.android.ui.unifiedsearch import com.nextcloud.android.lib.resources.search.UnifiedSearchRemoteOperation import com.nextcloud.common.NextcloudClient +import com.nextcloud.utils.extensions.containsAllTerms +import com.nextcloud.utils.extensions.toSearchTerms import com.owncloud.android.lib.common.SearchResult +import com.owncloud.android.lib.common.SearchResultEntry import com.owncloud.android.lib.common.utils.Log_OC class SearchOnProviderTask( @@ -20,22 +23,52 @@ class SearchOnProviderTask( ) : () -> SearchOnProviderTask.Result { companion object { private const val TAG = "SearchOnProviderTask" + private const val FILES_PROVIDER_ID = "files" + private const val MAX_SERVER_PAGE_SIZE = 25 } data class Result(val success: Boolean = false, val searchResult: SearchResult = SearchResult()) override fun invoke(): Result { Log_OC.d(TAG, "Run task") - val result = UnifiedSearchRemoteOperation(provider, query, cursor, limit).execute(client) + val terms = query.toSearchTerms() + val result = if (provider == FILES_PROVIDER_ID && terms.size > 1) { + searchFilesMatchingAllTerms(terms) + } else { + search(query, cursor, limit) + } - Log_OC.d(TAG, "Task finished: " + result.isSuccess) - return if (result.isSuccess && result.resultData != null) { - Result( - success = true, - searchResult = result.resultData as SearchResult - ) + Log_OC.d(TAG, "Task finished: " + result.success) + return result + } + + private fun search(query: String, cursor: Int?, limit: Int): Result { + val result = UnifiedSearchRemoteOperation(provider, query, cursor, limit).execute(client) + val searchResult = result.resultData + return if (result.isSuccess && searchResult != null) { + Result(success = true, searchResult = searchResult) } else { Result() } } + + private fun searchFilesMatchingAllTerms(terms: List): Result { + val serverQuery = terms.maxBy { it.length } + val matches = mutableListOf() + var nextCursor = cursor + var page: SearchResult + + do { + val result = search(serverQuery, nextCursor, MAX_SERVER_PAGE_SIZE) + if (!result.success) { + return result + } + + page = result.searchResult + matches += page.entries.filter { it.title.containsAllTerms(terms) } + nextCursor = page.cursor?.toIntOrNull() + } while (matches.size < limit && page.entries.size == MAX_SERVER_PAGE_SIZE && nextCursor != null) + + return Result(success = true, searchResult = page.copy(entries = matches)) + } }