6
6
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
7
7
*/
8
8
package com.owncloud.android.ui.fragment
9
-
10
9
import android.Manifest
11
10
import android.content.Context
12
11
import android.content.Intent
@@ -27,25 +26,33 @@ import androidx.appcompat.widget.SearchView
27
26
import androidx.core.view.updatePadding
28
27
import androidx.fragment.app.Fragment
29
28
import androidx.lifecycle.ViewModelProvider
29
+ import androidx.lifecycle.lifecycleScope
30
30
import androidx.recyclerview.widget.GridLayoutManager
31
31
import com.nextcloud.client.account.CurrentAccountProvider
32
32
import com.nextcloud.client.account.UserAccountManager
33
33
import com.nextcloud.client.core.AsyncRunner
34
+ import com.nextcloud.client.core.Clock
34
35
import com.nextcloud.client.di.Injectable
35
36
import com.nextcloud.client.di.ViewModelFactory
36
37
import com.nextcloud.client.network.ClientFactory
38
+ import com.nextcloud.client.preferences.AppPreferences
39
+ import com.nextcloud.utils.extensions.getTypedActivity
40
+ import com.nextcloud.utils.extensions.searchFilesByName
37
41
import com.nextcloud.utils.extensions.typedActivity
38
42
import com.owncloud.android.R
39
43
import com.owncloud.android.databinding.ListFragmentBinding
40
44
import com.owncloud.android.datamodel.FileDataStorageManager
41
45
import com.owncloud.android.datamodel.OCFile
46
+ import com.owncloud.android.datamodel.SyncedFolderProvider
42
47
import com.owncloud.android.lib.common.SearchResultEntry
43
48
import com.owncloud.android.lib.common.utils.Log_OC
44
49
import com.owncloud.android.lib.resources.status.NextcloudVersion
50
+ import com.owncloud.android.ui.activity.FileActivity
45
51
import com.owncloud.android.ui.activity.FileDisplayActivity
46
52
import com.owncloud.android.ui.adapter.UnifiedSearchItemViewHolder
47
53
import com.owncloud.android.ui.adapter.UnifiedSearchListAdapter
48
54
import com.owncloud.android.ui.fragment.util.PairMediatorLiveData
55
+ import com.owncloud.android.ui.interfaces.UnifiedSearchCurrentDirItemAction
49
56
import com.owncloud.android.ui.interfaces.UnifiedSearchListInterface
50
57
import com.owncloud.android.ui.unifiedsearch.IUnifiedSearchViewModel
51
58
import com.owncloud.android.ui.unifiedsearch.ProviderID
@@ -55,6 +62,9 @@ import com.owncloud.android.ui.unifiedsearch.filterOutHiddenFiles
55
62
import com.owncloud.android.utils.DisplayUtils
56
63
import com.owncloud.android.utils.PermissionUtil
57
64
import com.owncloud.android.utils.theme.ViewThemeUtils
65
+ import kotlinx.coroutines.Dispatchers
66
+ import kotlinx.coroutines.launch
67
+ import kotlinx.coroutines.withContext
58
68
import javax.inject.Inject
59
69
60
70
/* *
@@ -67,7 +77,8 @@ class UnifiedSearchFragment :
67
77
Injectable ,
68
78
UnifiedSearchListInterface ,
69
79
SearchView .OnQueryTextListener ,
70
- UnifiedSearchItemViewHolder .FilesAction {
80
+ UnifiedSearchItemViewHolder .FilesAction ,
81
+ UnifiedSearchCurrentDirItemAction {
71
82
private lateinit var adapter: UnifiedSearchListAdapter
72
83
private var _binding : ListFragmentBinding ? = null
73
84
val binding get() = _binding !!
@@ -77,16 +88,20 @@ class UnifiedSearchFragment :
77
88
companion object {
78
89
private const val TAG = " UnifiedSearchFragment"
79
90
80
- const val ARG_QUERY = " ARG_QUERY"
81
- const val ARG_HIDDEN_FILES = " ARG_HIDDEN_FILES"
82
-
83
- fun newInstance (query : String? , listOfHiddenFiles : ArrayList <String >? ): UnifiedSearchFragment {
84
- val fragment = UnifiedSearchFragment ()
85
- val args = Bundle ()
86
- args.putString(ARG_QUERY , query)
87
- args.putStringArrayList(ARG_HIDDEN_FILES , listOfHiddenFiles)
88
- fragment.arguments = args
89
- return fragment
91
+ private const val ARG_QUERY = " ARG_QUERY"
92
+ private const val ARG_HIDDEN_FILES = " ARG_HIDDEN_FILES"
93
+ private const val CURRENT_DIR_PATH = " CURRENT_DIR"
94
+
95
+ fun newInstance (
96
+ query : String? ,
97
+ listOfHiddenFiles : ArrayList <String >? ,
98
+ currentDirPath : String
99
+ ): UnifiedSearchFragment = UnifiedSearchFragment ().apply {
100
+ arguments = Bundle ().apply {
101
+ putString(ARG_QUERY , query)
102
+ putString(CURRENT_DIR_PATH , currentDirPath)
103
+ putStringArrayList(ARG_HIDDEN_FILES , listOfHiddenFiles)
104
+ }
90
105
}
91
106
}
92
107
@@ -111,23 +126,26 @@ class UnifiedSearchFragment :
111
126
@Inject
112
127
lateinit var accountManager: UserAccountManager
113
128
129
+ @Inject
130
+ lateinit var appPreferences: AppPreferences
131
+
132
+ @Inject
133
+ lateinit var clock: Clock
134
+
114
135
private var listOfHiddenFiles = ArrayList <String >()
115
136
private var showMoreActions = false
137
+ private var currentDir: OCFile ? = null
138
+ private var initialQuery: String? = null
116
139
117
140
override fun onCreate (savedInstanceState : Bundle ? ) {
118
141
super .onCreate(savedInstanceState)
119
142
vm = ViewModelProvider (this , vmFactory)[UnifiedSearchViewModel ::class .java]
120
- setUpViewModel( )
121
-
122
- val query = savedInstanceState?.getString( ARG_QUERY ) ? : arguments?.getString( ARG_QUERY )
143
+ initialQuery = savedInstanceState?.getString( ARG_QUERY ) ? : arguments?.getString( ARG_QUERY )
144
+ val currentDirPath = savedInstanceState?.getString( CURRENT_DIR_PATH ) ? : arguments?.getString( CURRENT_DIR_PATH )
145
+ currentDir = storageManager.getFileByDecryptedRemotePath(currentDirPath )
123
146
listOfHiddenFiles =
124
147
savedInstanceState?.getStringArrayList(ARG_HIDDEN_FILES ) ? : arguments?.getStringArrayList(ARG_HIDDEN_FILES )
125
148
? : ArrayList ()
126
-
127
- if (! query.isNullOrEmpty()) {
128
- vm.setQuery(query)
129
- vm.initialQuery()
130
- }
131
149
}
132
150
133
151
@Suppress(" DEPRECATION" )
@@ -149,6 +167,15 @@ class UnifiedSearchFragment :
149
167
}
150
168
}
151
169
170
+ override fun onResume () {
171
+ super .onResume()
172
+ typedActivity<FileDisplayActivity >()?.run {
173
+ setupToolbar()
174
+ setMainFabVisible(false )
175
+ updateActionBarTitleAndHomeButtonByString(null )
176
+ }
177
+ }
178
+
152
179
private fun supportsOpeningCalendarContactsLocally (): Boolean = storageManager
153
180
.getCapability(accountManager.user)
154
181
.version
@@ -200,6 +227,7 @@ class UnifiedSearchFragment :
200
227
201
228
vm.setQuery(" " )
202
229
adapter.setData(emptyList())
230
+ adapter.setDataCurrentDirItems(listOf ())
203
231
204
232
showStartYourSearch()
205
233
showKeyboard(searchView)
@@ -282,36 +310,41 @@ class UnifiedSearchFragment :
282
310
}
283
311
}
284
312
313
+ @Suppress(" ComplexCondition" )
285
314
private fun setUpViewModel () {
286
- vm.searchResults.observe(this , this ::onSearchResultChanged)
287
- vm.isLoading.observe(this ) { loading ->
315
+ vm.searchResults.observe(viewLifecycleOwner , this ::onSearchResultChanged)
316
+ vm.isLoading.observe(viewLifecycleOwner ) { loading ->
288
317
binding.swipeContainingList.isRefreshing = loading
289
318
}
290
319
291
- PairMediatorLiveData (vm.searchResults, vm.isLoading).observe(this ) { pair ->
320
+ PairMediatorLiveData (vm.searchResults, vm.isLoading).observe(viewLifecycleOwner ) { pair ->
292
321
if (pair.second == false ) {
293
322
var count = 0
294
323
295
324
pair.first?.forEach {
296
325
count + = it.entries.size
297
326
}
298
327
299
- if (count == 0 && pair.first?.isNotEmpty() == true && context != null && ! adapter.isCurrentDirItemsEmpty()) {
328
+ if (count == 0 &&
329
+ pair.first?.isNotEmpty() == true &&
330
+ context != null &&
331
+ ! adapter.isCurrentDirItemsEmpty()
332
+ ) {
300
333
showNoResult()
301
334
}
302
335
}
303
336
}
304
337
305
- vm.error.observe(this ) { error ->
338
+ vm.error.observe(viewLifecycleOwner ) { error ->
306
339
if (! error.isNullOrEmpty()) {
307
340
DisplayUtils .showSnackMessage(binding.root, error)
308
341
}
309
342
}
310
- vm.browserUri.observe(this ) { uri ->
343
+ vm.browserUri.observe(viewLifecycleOwner ) { uri ->
311
344
val browserIntent = Intent (Intent .ACTION_VIEW , uri)
312
345
startActivity(browserIntent)
313
346
}
314
- vm.file.observe(this ) {
347
+ vm.file.observe(viewLifecycleOwner ) {
315
348
showFile(it, showMoreActions)
316
349
}
317
350
}
@@ -337,30 +370,42 @@ class UnifiedSearchFragment :
337
370
}
338
371
}
339
372
340
- override fun onResume () {
341
- super .onResume()
342
- typedActivity<FileDisplayActivity >()?.run {
343
- setupToolbar()
344
- setMainFabVisible(false )
345
- updateActionBarTitleAndHomeButtonByString(null )
346
- }
347
- }
348
-
349
373
private fun setupAdapter () {
374
+ val syncedFolderProvider = SyncedFolderProvider (requireContext().contentResolver, appPreferences, clock)
350
375
val gridLayoutManager = GridLayoutManager (requireContext(), 1 )
351
- adapter = UnifiedSearchListAdapter (
352
- supportsOpeningCalendarContactsLocally(),
353
- storageManager,
354
- this ,
355
- this ,
356
- currentAccountProvider.user,
357
- requireContext(),
358
- viewThemeUtils
359
- )
360
- adapter.shouldShowFooters(true )
361
- adapter.setLayoutManager(gridLayoutManager)
362
- binding.listRoot.layoutManager = gridLayoutManager
363
- binding.listRoot.adapter = adapter
376
+
377
+ lifecycleScope.launch(Dispatchers .IO ) {
378
+ val client =
379
+ getTypedActivity(FileActivity ::class .java)?.clientRepository?.getNextcloudClient() ? : return @launch
380
+
381
+ withContext(Dispatchers .Main ) {
382
+ adapter = UnifiedSearchListAdapter (
383
+ supportsOpeningCalendarContactsLocally(),
384
+ storageManager,
385
+ this @UnifiedSearchFragment,
386
+ this @UnifiedSearchFragment,
387
+ currentAccountProvider.user,
388
+ requireContext(),
389
+ viewThemeUtils,
390
+ appPreferences,
391
+ syncedFolderProvider,
392
+ client,
393
+ this @UnifiedSearchFragment
394
+ )
395
+
396
+ adapter.shouldShowFooters(true )
397
+ adapter.setLayoutManager(gridLayoutManager)
398
+ binding.listRoot.layoutManager = gridLayoutManager
399
+ binding.listRoot.adapter = adapter
400
+ searchInCurrentDirectory(initialQuery ? : " " )
401
+
402
+ setUpViewModel()
403
+ if (! initialQuery.isNullOrEmpty()) {
404
+ vm.setQuery(initialQuery!! )
405
+ vm.initialQuery()
406
+ }
407
+ }
408
+ }
364
409
}
365
410
366
411
override fun onSearchResultClicked (searchResultEntry : SearchResultEntry ) {
@@ -394,9 +439,17 @@ class UnifiedSearchFragment :
394
439
override fun onQueryTextChange (newText : String? ): Boolean {
395
440
val closeButton = searchView?.findViewById<ImageView >(androidx.appcompat.R .id.search_close_btn)
396
441
closeButton?.visibility = if (newText?.isEmpty() == true ) View .INVISIBLE else View .VISIBLE
442
+ searchInCurrentDirectory(newText ? : " " )
397
443
return true
398
444
}
399
445
446
+ private fun searchInCurrentDirectory (query : String ) {
447
+ currentDir?.run {
448
+ val files = storageManager.searchFilesByName(this , accountManager.user.accountName, query)
449
+ adapter.setDataCurrentDirItems(files)
450
+ }
451
+ }
452
+
400
453
override fun onDestroyView () {
401
454
super .onDestroyView()
402
455
_binding = null
@@ -406,4 +459,9 @@ class UnifiedSearchFragment :
406
459
showMoreActions = true
407
460
vm.openResult(searchResultEntry)
408
461
}
462
+
463
+ override fun openFile (remotePath : String , showMoreActions : Boolean ) {
464
+ this .showMoreActions = showMoreActions
465
+ vm.openFile(remotePath)
466
+ }
409
467
}
0 commit comments