mirror of
https://github.com/nextcloud/android.git
synced 2024-11-26 07:05:49 +03:00
Unified seach: allow querying different providers asynchronously, and get their IDs in the result
First step towards getting "Load more" working for a single provider Signed-off-by: Álvaro Brey Vilas <alvaro.brey@nextcloud.com>
This commit is contained in:
parent
b0b9d3a3e3
commit
6c98b4cb8d
5 changed files with 81 additions and 37 deletions
|
@ -145,10 +145,10 @@ class UnifiedSearchFragment : Fragment(), Injectable, UnifiedSearchListInterface
|
|||
}
|
||||
|
||||
@VisibleForTesting
|
||||
fun onSearchResultChanged(list: MutableList<SearchResult>) {
|
||||
fun onSearchResultChanged(result: MutableMap<String, SearchResult>) {
|
||||
binding.emptyList.emptyListView.visibility = View.GONE
|
||||
|
||||
adapter.setList(list)
|
||||
adapter.setList(result.values.toList())
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
|
|
|
@ -24,10 +24,17 @@ package com.owncloud.android.ui.unifiedsearch
|
|||
|
||||
import com.owncloud.android.lib.common.SearchResult
|
||||
|
||||
data class UnifiedSearchResults(val success: Boolean, val results: List<SearchResult>)
|
||||
typealias ProviderID = String
|
||||
|
||||
data class UnifiedSearchResult(val provider: ProviderID, val success: Boolean, val result: SearchResult)
|
||||
|
||||
interface IUnifiedSearchRepository {
|
||||
fun refresh()
|
||||
fun startLoading()
|
||||
fun loadMore(query: String, onResult: (UnifiedSearchResults) -> Unit, onError: (Throwable) -> Unit)
|
||||
fun queryAll(
|
||||
query: String,
|
||||
onResult: (UnifiedSearchResult) -> Unit,
|
||||
onError: (Throwable) -> Unit,
|
||||
onFinished: (Boolean) -> Unit
|
||||
)
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ package com.owncloud.android.ui.unifiedsearch
|
|||
import com.nextcloud.android.lib.resources.search.UnifiedSearchRemoteOperation
|
||||
import com.nextcloud.common.NextcloudClient
|
||||
import com.owncloud.android.lib.common.SearchResult
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult
|
||||
import com.owncloud.android.lib.common.utils.Log_OC
|
||||
|
||||
class SearchOnProvidersTask(
|
||||
|
@ -34,24 +35,27 @@ class SearchOnProvidersTask(
|
|||
const val TAG = "SearchOnProvidersTask"
|
||||
}
|
||||
|
||||
data class Result(val success: Boolean = false, val searchResults: List<SearchResult> = emptyList())
|
||||
data class Result(val success: Boolean = false, val searchResults: Map<ProviderID, SearchResult> = emptyMap())
|
||||
|
||||
override fun invoke(): Result {
|
||||
|
||||
Log_OC.d(TAG, "Run task")
|
||||
val results = providers
|
||||
val results: List<Pair<String, RemoteOperationResult<SearchResult>>> = providers
|
||||
.map { UnifiedSearchRemoteOperation(it, query) }
|
||||
.map { it.execute(client) }
|
||||
.map { Pair(it.provider, it.execute(client)) }
|
||||
|
||||
val success = results.isNotEmpty() && results.any { it.isSuccess }
|
||||
val success = results.isNotEmpty() && results.any { it.second.isSuccess }
|
||||
Log_OC.d(TAG, "Task finished, success: $success")
|
||||
Log_OC.d(TAG, "Providers successful: ${results.count { it.isSuccess }}")
|
||||
Log_OC.d(TAG, "Providers successful: ${results.count { !it.isSuccess }}")
|
||||
Log_OC.d(TAG, "Providers successful: ${results.count { it.second.isSuccess }}")
|
||||
Log_OC.d(TAG, "Providers successful: ${results.count { !it.second.isSuccess }}")
|
||||
|
||||
return when {
|
||||
success -> Result(
|
||||
success = true,
|
||||
searchResults = results.filter { it.isSuccess }.map { it.resultData }
|
||||
searchResults = results
|
||||
.filter { it.second.isSuccess }
|
||||
.map { Pair(it.first, it.second.resultData) }
|
||||
.toMap()
|
||||
)
|
||||
else -> Result()
|
||||
}
|
||||
|
|
|
@ -43,30 +43,48 @@ class UnifiedSearchRemoteRepository(
|
|||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun loadMore(
|
||||
override fun queryAll(
|
||||
query: String,
|
||||
onResult: (UnifiedSearchResults) -> Unit,
|
||||
onError: (Throwable) -> Unit
|
||||
onResult: (UnifiedSearchResult) -> Unit,
|
||||
onError: (Throwable) -> Unit,
|
||||
onFinished: (Boolean) -> Unit
|
||||
) {
|
||||
Log_OC.d(this, "loadMore")
|
||||
fetchProviders(
|
||||
onResult = { result ->
|
||||
val providerIds = result.providers.map { it.id }
|
||||
var openRequests = providerIds.size
|
||||
var anyError = false
|
||||
val client = clientFactory.createNextcloudClient(currentAccountProvider.user)
|
||||
val task = SearchOnProvidersTask(query, providerIds, client)
|
||||
providerIds
|
||||
.forEach { provider ->
|
||||
val task = SearchOnProviderTask(query, provider, client)
|
||||
asyncRunner.postQuickTask(
|
||||
task = task,
|
||||
onResult = {
|
||||
onResult(UnifiedSearchResults(it.success, it.searchResults))
|
||||
openRequests--
|
||||
anyError = anyError || !it.success
|
||||
onResult(UnifiedSearchResult(provider, it.success, it.searchResult))
|
||||
if (openRequests == 0) {
|
||||
onFinished(!anyError)
|
||||
}
|
||||
},
|
||||
onError = onError
|
||||
onError = {
|
||||
openRequests--
|
||||
anyError = true
|
||||
onError(it)
|
||||
if (openRequests == 0) {
|
||||
onFinished(!anyError)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
},
|
||||
onError = onError
|
||||
)
|
||||
}
|
||||
|
||||
private fun fetchProviders(onResult: (SearchProviders) -> Unit, onError: (Throwable) -> Unit) {
|
||||
fun fetchProviders(onResult: (SearchProviders) -> Unit, onError: (Throwable) -> Unit) {
|
||||
Log_OC.d(this, "fetchProviders")
|
||||
if (this.providers != null) {
|
||||
onResult(this.providers!!)
|
||||
|
|
|
@ -47,10 +47,14 @@ class UnifiedSearchViewModel() : ViewModel() {
|
|||
private var last: Int = -1
|
||||
|
||||
val isLoading: MutableLiveData<Boolean> = MutableLiveData<Boolean>(false)
|
||||
val searchResults = MutableLiveData<MutableList<SearchResult>>(mutableListOf())
|
||||
val searchResults = MutableLiveData<MutableMap<ProviderID, SearchResult>>(mutableMapOf())
|
||||
val error: MutableLiveData<String> = MutableLiveData<String>("")
|
||||
val query: MutableLiveData<String> = MutableLiveData()
|
||||
|
||||
companion object {
|
||||
private const val TAG = "UnifiedSearchViewModel"
|
||||
}
|
||||
|
||||
@Inject
|
||||
constructor(
|
||||
currentAccountProvider: CurrentAccountProvider,
|
||||
|
@ -74,27 +78,31 @@ class UnifiedSearchViewModel() : ViewModel() {
|
|||
|
||||
open fun refresh() {
|
||||
last = -1
|
||||
searchResults.value = mutableListOf()
|
||||
loadMore()
|
||||
searchResults.value = mutableMapOf()
|
||||
startLoading(query.value.orEmpty())
|
||||
}
|
||||
|
||||
open fun startLoading(query: String) {
|
||||
if (!loadingStarted) {
|
||||
loadingStarted = true
|
||||
this.query.value = query
|
||||
loadMore()
|
||||
queryAll()
|
||||
}
|
||||
}
|
||||
|
||||
open fun loadMore() {
|
||||
fun queryAll() {
|
||||
val queryTerm = query.value.orEmpty()
|
||||
|
||||
if (isLoading.value != true && queryTerm.isNotBlank()) {
|
||||
isLoading.value = true
|
||||
repository.loadMore(queryTerm, this::onSearchResult, this::onError)
|
||||
repository.queryAll(queryTerm, this::onSearchResult, this::onError, this::onSearchFinished)
|
||||
}
|
||||
}
|
||||
|
||||
open fun loadMore() {
|
||||
// TODO load more results for a single provider
|
||||
}
|
||||
|
||||
fun openFile(fileUrl: String) {
|
||||
if (isLoading.value == false) {
|
||||
isLoading.value = true
|
||||
|
@ -115,23 +123,30 @@ class UnifiedSearchViewModel() : ViewModel() {
|
|||
}
|
||||
|
||||
fun onError(error: Throwable) {
|
||||
Log_OC.d("Unified Search", "Error: " + error.stackTrace)
|
||||
Log_OC.d(TAG, "Error: " + error.stackTrace)
|
||||
}
|
||||
|
||||
fun onSearchResult(result: UnifiedSearchResults) {
|
||||
@Synchronized
|
||||
fun onSearchResult(result: UnifiedSearchResult) {
|
||||
isLoading.value = false
|
||||
|
||||
if (result.success) {
|
||||
// TODO append if already exists
|
||||
searchResults.value = result.results.toMutableList()
|
||||
} else {
|
||||
error.value = resources.getString(R.string.search_error)
|
||||
val currentValues: MutableMap<ProviderID, SearchResult> = searchResults.value ?: mutableMapOf()
|
||||
currentValues.put(result.provider, result.result)
|
||||
searchResults.value = currentValues
|
||||
}
|
||||
|
||||
Log_OC.d("Unified Search", "Success: " + result.success)
|
||||
Log_OC.d(TAG, "onSearchResult: Provider '${result.provider}', success: ${result.success}")
|
||||
if (result.success) {
|
||||
Log_OC.d("Unified Search", "Got results from ${result.results.size} providers")
|
||||
Log_OC.d("Unified Search", "Total results: " + result.results.sumOf { it.entries.size })
|
||||
Log_OC.d(TAG, "onSearchResult: Provider '${result.provider}', result count: ${result.result.entries.size}")
|
||||
}
|
||||
}
|
||||
|
||||
fun onSearchFinished(success: Boolean) {
|
||||
isLoading.value = false
|
||||
if (!success) {
|
||||
error.value = resources.getString(R.string.search_error)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue