66 * SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
77 */
88package com.owncloud.android.ui.fragment
9-
109import android.Manifest
1110import android.content.Context
1211import android.content.Intent
@@ -27,25 +26,33 @@ import androidx.appcompat.widget.SearchView
2726import androidx.core.view.updatePadding
2827import androidx.fragment.app.Fragment
2928import androidx.lifecycle.ViewModelProvider
29+ import androidx.lifecycle.lifecycleScope
3030import androidx.recyclerview.widget.GridLayoutManager
3131import com.nextcloud.client.account.CurrentAccountProvider
3232import com.nextcloud.client.account.UserAccountManager
3333import com.nextcloud.client.core.AsyncRunner
34+ import com.nextcloud.client.core.Clock
3435import com.nextcloud.client.di.Injectable
3536import com.nextcloud.client.di.ViewModelFactory
3637import 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
3741import com.nextcloud.utils.extensions.typedActivity
3842import com.owncloud.android.R
3943import com.owncloud.android.databinding.ListFragmentBinding
4044import com.owncloud.android.datamodel.FileDataStorageManager
4145import com.owncloud.android.datamodel.OCFile
46+ import com.owncloud.android.datamodel.SyncedFolderProvider
4247import com.owncloud.android.lib.common.SearchResultEntry
4348import com.owncloud.android.lib.common.utils.Log_OC
4449import com.owncloud.android.lib.resources.status.NextcloudVersion
50+ import com.owncloud.android.ui.activity.FileActivity
4551import com.owncloud.android.ui.activity.FileDisplayActivity
4652import com.owncloud.android.ui.adapter.UnifiedSearchItemViewHolder
4753import com.owncloud.android.ui.adapter.UnifiedSearchListAdapter
4854import com.owncloud.android.ui.fragment.util.PairMediatorLiveData
55+ import com.owncloud.android.ui.interfaces.UnifiedSearchCurrentDirItemAction
4956import com.owncloud.android.ui.interfaces.UnifiedSearchListInterface
5057import com.owncloud.android.ui.unifiedsearch.IUnifiedSearchViewModel
5158import com.owncloud.android.ui.unifiedsearch.ProviderID
@@ -55,6 +62,9 @@ import com.owncloud.android.ui.unifiedsearch.filterOutHiddenFiles
5562import com.owncloud.android.utils.DisplayUtils
5663import com.owncloud.android.utils.PermissionUtil
5764import com.owncloud.android.utils.theme.ViewThemeUtils
65+ import kotlinx.coroutines.Dispatchers
66+ import kotlinx.coroutines.launch
67+ import kotlinx.coroutines.withContext
5868import javax.inject.Inject
5969
6070/* *
@@ -67,7 +77,8 @@ class UnifiedSearchFragment :
6777 Injectable ,
6878 UnifiedSearchListInterface ,
6979 SearchView .OnQueryTextListener ,
70- UnifiedSearchItemViewHolder .FilesAction {
80+ UnifiedSearchItemViewHolder .FilesAction ,
81+ UnifiedSearchCurrentDirItemAction {
7182 private lateinit var adapter: UnifiedSearchListAdapter
7283 private var _binding : ListFragmentBinding ? = null
7384 val binding get() = _binding !!
@@ -77,16 +88,20 @@ class UnifiedSearchFragment :
7788 companion object {
7889 private const val TAG = " UnifiedSearchFragment"
7990
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+ }
90105 }
91106 }
92107
@@ -111,23 +126,26 @@ class UnifiedSearchFragment :
111126 @Inject
112127 lateinit var accountManager: UserAccountManager
113128
129+ @Inject
130+ lateinit var appPreferences: AppPreferences
131+
132+ @Inject
133+ lateinit var clock: Clock
134+
114135 private var listOfHiddenFiles = ArrayList <String >()
115136 private var showMoreActions = false
137+ private var currentDir: OCFile ? = null
138+ private var initialQuery: String? = null
116139
117140 override fun onCreate (savedInstanceState : Bundle ? ) {
118141 super .onCreate(savedInstanceState)
119142 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 )
123146 listOfHiddenFiles =
124147 savedInstanceState?.getStringArrayList(ARG_HIDDEN_FILES ) ? : arguments?.getStringArrayList(ARG_HIDDEN_FILES )
125148 ? : ArrayList ()
126-
127- if (! query.isNullOrEmpty()) {
128- vm.setQuery(query)
129- vm.initialQuery()
130- }
131149 }
132150
133151 @Suppress(" DEPRECATION" )
@@ -149,6 +167,15 @@ class UnifiedSearchFragment :
149167 }
150168 }
151169
170+ override fun onResume () {
171+ super .onResume()
172+ typedActivity<FileDisplayActivity >()?.run {
173+ setupToolbar()
174+ setMainFabVisible(false )
175+ updateActionBarTitleAndHomeButtonByString(null )
176+ }
177+ }
178+
152179 private fun supportsOpeningCalendarContactsLocally (): Boolean = storageManager
153180 .getCapability(accountManager.user)
154181 .version
@@ -200,6 +227,7 @@ class UnifiedSearchFragment :
200227
201228 vm.setQuery(" " )
202229 adapter.setData(emptyList())
230+ adapter.setDataCurrentDirItems(listOf ())
203231
204232 showStartYourSearch()
205233 showKeyboard(searchView)
@@ -282,36 +310,41 @@ class UnifiedSearchFragment :
282310 }
283311 }
284312
313+ @Suppress(" ComplexCondition" )
285314 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 ->
288317 binding.swipeContainingList.isRefreshing = loading
289318 }
290319
291- PairMediatorLiveData (vm.searchResults, vm.isLoading).observe(this ) { pair ->
320+ PairMediatorLiveData (vm.searchResults, vm.isLoading).observe(viewLifecycleOwner ) { pair ->
292321 if (pair.second == false ) {
293322 var count = 0
294323
295324 pair.first?.forEach {
296325 count + = it.entries.size
297326 }
298327
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+ ) {
300333 showNoResult()
301334 }
302335 }
303336 }
304337
305- vm.error.observe(this ) { error ->
338+ vm.error.observe(viewLifecycleOwner ) { error ->
306339 if (! error.isNullOrEmpty()) {
307340 DisplayUtils .showSnackMessage(binding.root, error)
308341 }
309342 }
310- vm.browserUri.observe(this ) { uri ->
343+ vm.browserUri.observe(viewLifecycleOwner ) { uri ->
311344 val browserIntent = Intent (Intent .ACTION_VIEW , uri)
312345 startActivity(browserIntent)
313346 }
314- vm.file.observe(this ) {
347+ vm.file.observe(viewLifecycleOwner ) {
315348 showFile(it, showMoreActions)
316349 }
317350 }
@@ -337,30 +370,42 @@ class UnifiedSearchFragment :
337370 }
338371 }
339372
340- override fun onResume () {
341- super .onResume()
342- typedActivity<FileDisplayActivity >()?.run {
343- setupToolbar()
344- setMainFabVisible(false )
345- updateActionBarTitleAndHomeButtonByString(null )
346- }
347- }
348-
349373 private fun setupAdapter () {
374+ val syncedFolderProvider = SyncedFolderProvider (requireContext().contentResolver, appPreferences, clock)
350375 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+ }
364409 }
365410
366411 override fun onSearchResultClicked (searchResultEntry : SearchResultEntry ) {
@@ -394,9 +439,17 @@ class UnifiedSearchFragment :
394439 override fun onQueryTextChange (newText : String? ): Boolean {
395440 val closeButton = searchView?.findViewById<ImageView >(androidx.appcompat.R .id.search_close_btn)
396441 closeButton?.visibility = if (newText?.isEmpty() == true ) View .INVISIBLE else View .VISIBLE
442+ searchInCurrentDirectory(newText ? : " " )
397443 return true
398444 }
399445
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+
400453 override fun onDestroyView () {
401454 super .onDestroyView()
402455 _binding = null
@@ -406,4 +459,9 @@ class UnifiedSearchFragment :
406459 showMoreActions = true
407460 vm.openResult(searchResultEntry)
408461 }
462+
463+ override fun openFile (remotePath : String , showMoreActions : Boolean ) {
464+ this .showMoreActions = showMoreActions
465+ vm.openFile(remotePath)
466+ }
409467}
0 commit comments