From a41d14c33a24c20af8a910c7233185ab084fdcbe Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Tue, 24 May 2022 00:34:51 +0200 Subject: [PATCH 01/29] Reimplement BrowserController with new architecture pattern Signed-off-by: Andy Scherzinger --- app/src/main/AndroidManifest.xml | 6 +- .../MagicPreviewMessageViewHolder.java | 12 +- .../filebrowser/operations/DavListing.java | 12 +- ...ava => LegacyReadFilesystemOperation.java} | 5 +- .../webdav/ReadFilesystemOperation.kt | 184 ++++++++++ .../talk/controllers/ProfileController.kt | 24 +- .../talk/dagger/modules/RepositoryModule.kt | 9 + .../talk/dagger/modules/ViewModelModule.kt | 6 + .../activities/RemoteFileBrowserActivity.kt | 345 ++++++++++++++++++ .../adapters/RemoteFileBrowserItemsAdapter.kt | 86 +++++ .../RemoteFileBrowserItemsListViewHolder.kt | 153 ++++++++ .../RemoteFileBrowserItemsViewHolder.kt | 53 +++ .../model/RemoteFileBrowserItem.kt | 49 +++ .../RemoteFileBrowserItemsRepository.kt | 29 ++ .../RemoteFileBrowserItemsRepositoryImpl.kt | 56 +++ .../RemoteFileBrowserItemsViewModel.kt | 93 +++++ .../nextcloud/talk/utils/DisplayUtils.java | 19 + .../talk/utils/FileSortOrderByDateNew.java | 52 +++ .../talk/utils/FileSortOrderByNameNew.java | 63 ++++ .../talk/utils/FileSortOrderBySizeNew.java | 61 ++++ .../talk/utils/FileSortOrderNew.java | 108 ++++++ .../nextcloud/talk/utils/bundle/BundleKeys.kt | 2 + .../layout/activity_remote_file_browser.xml | 132 +++++++ 23 files changed, 1536 insertions(+), 23 deletions(-) rename app/src/main/java/com/nextcloud/talk/components/filebrowser/webdav/{ReadFilesystemOperation.java => LegacyReadFilesystemOperation.java} (96%) create mode 100644 app/src/main/java/com/nextcloud/talk/components/filebrowser/webdav/ReadFilesystemOperation.kt create mode 100644 app/src/main/java/com/nextcloud/talk/remotefilebrowser/activities/RemoteFileBrowserActivity.kt create mode 100644 app/src/main/java/com/nextcloud/talk/remotefilebrowser/adapters/RemoteFileBrowserItemsAdapter.kt create mode 100644 app/src/main/java/com/nextcloud/talk/remotefilebrowser/adapters/RemoteFileBrowserItemsListViewHolder.kt create mode 100644 app/src/main/java/com/nextcloud/talk/remotefilebrowser/adapters/RemoteFileBrowserItemsViewHolder.kt create mode 100644 app/src/main/java/com/nextcloud/talk/remotefilebrowser/model/RemoteFileBrowserItem.kt create mode 100644 app/src/main/java/com/nextcloud/talk/remotefilebrowser/repositories/RemoteFileBrowserItemsRepository.kt create mode 100644 app/src/main/java/com/nextcloud/talk/remotefilebrowser/repositories/RemoteFileBrowserItemsRepositoryImpl.kt create mode 100644 app/src/main/java/com/nextcloud/talk/remotefilebrowser/viewmodels/RemoteFileBrowserItemsViewModel.kt create mode 100644 app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByDateNew.java create mode 100644 app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByNameNew.java create mode 100644 app/src/main/java/com/nextcloud/talk/utils/FileSortOrderBySizeNew.java create mode 100644 app/src/main/java/com/nextcloud/talk/utils/FileSortOrderNew.java create mode 100644 app/src/main/res/layout/activity_remote_file_browser.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a098c8ff9..afb39eef3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -170,7 +170,11 @@ + android:theme="@style/AppTheme" /> + + () { + Single.fromCallable(new Callable() { @Override - public ReadFilesystemOperation call() { - return new ReadFilesystemOperation(okHttpClient, activeUser, url, 0); + public LegacyReadFilesystemOperation call() { + return new LegacyReadFilesystemOperation(okHttpClient, activeUser, url, 0); } }).observeOn(Schedulers.io()) - .subscribe(new SingleObserver() { + .subscribe(new SingleObserver() { @Override public void onSubscribe(@NonNull Disposable d) { // unused atm } @Override - public void onSuccess(@NonNull ReadFilesystemOperation readFilesystemOperation) { + public void onSuccess(@NonNull LegacyReadFilesystemOperation readFilesystemOperation) { DavResponse davResponse = readFilesystemOperation.readRemotePath(); if (davResponse.data != null) { List browserFileList = (List) davResponse.data; diff --git a/app/src/main/java/com/nextcloud/talk/components/filebrowser/operations/DavListing.java b/app/src/main/java/com/nextcloud/talk/components/filebrowser/operations/DavListing.java index dc69a1422..f368d0b4c 100644 --- a/app/src/main/java/com/nextcloud/talk/components/filebrowser/operations/DavListing.java +++ b/app/src/main/java/com/nextcloud/talk/components/filebrowser/operations/DavListing.java @@ -26,7 +26,7 @@ import android.util.Log; import com.nextcloud.talk.components.filebrowser.interfaces.ListingInterface; import com.nextcloud.talk.components.filebrowser.models.DavResponse; -import com.nextcloud.talk.components.filebrowser.webdav.ReadFilesystemOperation; +import com.nextcloud.talk.components.filebrowser.webdav.LegacyReadFilesystemOperation; import com.nextcloud.talk.models.database.UserEntity; import java.util.concurrent.Callable; @@ -50,20 +50,20 @@ public class DavListing extends ListingAbstractClass { @Override public void getFiles(String path, UserEntity currentUser, @Nullable OkHttpClient okHttpClient) { - Single.fromCallable(new Callable() { + Single.fromCallable(new Callable() { @Override - public ReadFilesystemOperation call() { - return new ReadFilesystemOperation(okHttpClient, currentUser, path, 1); + public LegacyReadFilesystemOperation call() { + return new LegacyReadFilesystemOperation(okHttpClient, currentUser, path, 1); } }).subscribeOn(Schedulers.io()) - .subscribe(new SingleObserver() { + .subscribe(new SingleObserver() { @Override public void onSubscribe(@NonNull Disposable d) { } @Override - public void onSuccess(@NonNull ReadFilesystemOperation readFilesystemOperation) { + public void onSuccess(@NonNull LegacyReadFilesystemOperation readFilesystemOperation) { davResponse = readFilesystemOperation.readRemotePath(); try { listingInterface.listingResult(davResponse); diff --git a/app/src/main/java/com/nextcloud/talk/components/filebrowser/webdav/ReadFilesystemOperation.java b/app/src/main/java/com/nextcloud/talk/components/filebrowser/webdav/LegacyReadFilesystemOperation.java similarity index 96% rename from app/src/main/java/com/nextcloud/talk/components/filebrowser/webdav/ReadFilesystemOperation.java rename to app/src/main/java/com/nextcloud/talk/components/filebrowser/webdav/LegacyReadFilesystemOperation.java index ed8e978cf..35766e07f 100644 --- a/app/src/main/java/com/nextcloud/talk/components/filebrowser/webdav/ReadFilesystemOperation.java +++ b/app/src/main/java/com/nextcloud/talk/components/filebrowser/webdav/LegacyReadFilesystemOperation.java @@ -40,14 +40,15 @@ import kotlin.jvm.functions.Function2; import okhttp3.HttpUrl; import okhttp3.OkHttpClient; -public class ReadFilesystemOperation { +@Deprecated +public class LegacyReadFilesystemOperation { private static final String TAG = "ReadFilesystemOperation"; private final OkHttpClient okHttpClient; private final String url; private final int depth; private final String basePath; - public ReadFilesystemOperation(OkHttpClient okHttpClient, UserEntity currentUser, String path, int depth) { + public LegacyReadFilesystemOperation(OkHttpClient okHttpClient, UserEntity currentUser, String path, int depth) { OkHttpClient.Builder okHttpClientBuilder = okHttpClient.newBuilder(); okHttpClientBuilder.followRedirects(false); okHttpClientBuilder.followSslRedirects(false); diff --git a/app/src/main/java/com/nextcloud/talk/components/filebrowser/webdav/ReadFilesystemOperation.kt b/app/src/main/java/com/nextcloud/talk/components/filebrowser/webdav/ReadFilesystemOperation.kt new file mode 100644 index 000000000..b0d86c0ea --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/components/filebrowser/webdav/ReadFilesystemOperation.kt @@ -0,0 +1,184 @@ +/* + * Nextcloud Talk application + * + * @author Andy Scherzinger + * @author Mario Danic + * Copyright (C) 2022 Andy Scherzinger + * Copyright (C) 2017-2019 Mario Danic + * + * This program 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 . + */ +package com.nextcloud.talk.components.filebrowser.webdav + +import android.net.Uri +import android.text.TextUtils +import android.util.Log +import at.bitfire.dav4jvm.DavResource +import at.bitfire.dav4jvm.Property +import at.bitfire.dav4jvm.Response +import at.bitfire.dav4jvm.Response.HrefRelation +import at.bitfire.dav4jvm.exception.DavException +import at.bitfire.dav4jvm.property.DisplayName +import at.bitfire.dav4jvm.property.GetContentType +import at.bitfire.dav4jvm.property.GetLastModified +import at.bitfire.dav4jvm.property.ResourceType +import com.nextcloud.talk.components.filebrowser.models.DavResponse +import com.nextcloud.talk.components.filebrowser.models.properties.NCEncrypted +import com.nextcloud.talk.components.filebrowser.models.properties.NCPermission +import com.nextcloud.talk.components.filebrowser.models.properties.NCPreview +import com.nextcloud.talk.components.filebrowser.models.properties.OCFavorite +import com.nextcloud.talk.components.filebrowser.models.properties.OCId +import com.nextcloud.talk.components.filebrowser.models.properties.OCSize +import com.nextcloud.talk.dagger.modules.RestModule.MagicAuthenticator +import com.nextcloud.talk.models.database.UserEntity +import com.nextcloud.talk.remotefilebrowser.model.RemoteFileBrowserItem +import com.nextcloud.talk.utils.ApiUtils +import okhttp3.HttpUrl.Companion.toHttpUrlOrNull +import okhttp3.OkHttpClient +import java.io.File +import java.io.IOException + +class ReadFilesystemOperation(okHttpClient: OkHttpClient, currentUser: UserEntity, path: String, depth: Int) { + private val okHttpClient: OkHttpClient + private val url: String + private val depth: Int + private val basePath: String + fun readRemotePath(): DavResponse { + val davResponse = DavResponse() + val memberElements: MutableList = ArrayList() + val rootElement = arrayOfNulls(1) + val remoteFiles: MutableList = ArrayList() + try { + DavResource( + okHttpClient, + url.toHttpUrlOrNull()!! + ).propfind( + depth = depth, + reqProp = DavUtils.getAllPropSet() + ) { response: Response, hrefRelation: HrefRelation? -> + davResponse.setResponse(response) + when (hrefRelation) { + HrefRelation.MEMBER -> memberElements.add(response) + HrefRelation.SELF -> rootElement[0] = response + HrefRelation.OTHER -> {} + else -> {} + } + Unit + } + } catch (e: IOException) { + Log.w(TAG, "Error reading remote path") + } catch (e: DavException) { + Log.w(TAG, "Error reading remote path") + } + remoteFiles.add( + getModelFromResponse( + rootElement[0]!!, + rootElement[0]!! + .href + .toString() + .substring(basePath.length) + ) + ) + for (memberElement in memberElements) { + remoteFiles.add( + getModelFromResponse( + memberElement, + memberElement + .href + .toString() + .substring(basePath.length) + ) + ) + } + davResponse.setData(remoteFiles) + return davResponse + } + + companion object { + private const val TAG = "ReadFilesystemOperation" + } + + init { + val okHttpClientBuilder: OkHttpClient.Builder = okHttpClient.newBuilder() + okHttpClientBuilder.followRedirects(false) + okHttpClientBuilder.followSslRedirects(false) + okHttpClientBuilder.authenticator( + MagicAuthenticator( + ApiUtils.getCredentials( + currentUser.username, + currentUser.token + ), + "Authorization" + ) + ) + this.okHttpClient = okHttpClientBuilder.build() + basePath = currentUser.baseUrl + DavUtils.DAV_PATH + currentUser.userId + url = basePath + path + this.depth = depth + } + + private fun getModelFromResponse(response: Response, remotePath: String): RemoteFileBrowserItem { + val remoteFileBrowserItem = RemoteFileBrowserItem() + remoteFileBrowserItem.path = Uri.decode(remotePath) + remoteFileBrowserItem.displayName = Uri.decode(File(remotePath).name) + val properties = response.properties + for (property in properties) { + mapPropertyToBrowserFile(property, remoteFileBrowserItem) + } + if (remoteFileBrowserItem.permissions != null && remoteFileBrowserItem.permissions!!.contains("R")) { + remoteFileBrowserItem.isAllowedToReShare = true + } + if (TextUtils.isEmpty(remoteFileBrowserItem.mimeType) && !remoteFileBrowserItem.isFile) { + remoteFileBrowserItem.mimeType = "inode/directory" + } + + return remoteFileBrowserItem + } + + @Suppress("Detekt.ComplexMethod") + private fun mapPropertyToBrowserFile(property: Property, remoteFileBrowserItem: RemoteFileBrowserItem) { + when (property) { + is OCId -> { + remoteFileBrowserItem.remoteId = property.ocId + } + is ResourceType -> { + remoteFileBrowserItem.isFile = !property.types.contains(ResourceType.COLLECTION) + } + is GetLastModified -> { + remoteFileBrowserItem.modifiedTimestamp = property.lastModified + } + is GetContentType -> { + remoteFileBrowserItem.mimeType = property.type + } + is OCSize -> { + remoteFileBrowserItem.size = property.ocSize + } + is NCPreview -> { + remoteFileBrowserItem.hasPreview = property.isNcPreview + } + is OCFavorite -> { + remoteFileBrowserItem.isFavorite = property.isOcFavorite + } + is DisplayName -> { + remoteFileBrowserItem.displayName = property.displayName + } + is NCEncrypted -> { + remoteFileBrowserItem.isEncrypted = property.isNcEncrypted + } + is NCPermission -> { + remoteFileBrowserItem.permissions = property.ncPermission + } + } + } +} diff --git a/app/src/main/java/com/nextcloud/talk/controllers/ProfileController.kt b/app/src/main/java/com/nextcloud/talk/controllers/ProfileController.kt index 19aa363e0..cfcd00202 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/ProfileController.kt +++ b/app/src/main/java/com/nextcloud/talk/controllers/ProfileController.kt @@ -29,7 +29,6 @@ import android.graphics.BitmapFactory import android.graphics.Color import android.net.Uri import android.os.Bundle -import android.os.Environment import android.text.Editable import android.text.TextUtils import android.text.TextWatcher @@ -48,8 +47,6 @@ import androidx.core.graphics.drawable.DrawableCompat import androidx.core.view.ViewCompat import androidx.recyclerview.widget.RecyclerView import autodagger.AutoInjector -import com.bluelinelabs.conductor.RouterTransaction -import com.bluelinelabs.conductor.changehandler.VerticalChangeHandler import com.github.dhaval2404.imagepicker.ImagePicker import com.github.dhaval2404.imagepicker.ImagePicker.Companion.getError import com.github.dhaval2404.imagepicker.ImagePicker.Companion.getFile @@ -59,7 +56,6 @@ import com.nextcloud.talk.api.NcApi import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication import com.nextcloud.talk.components.filebrowser.controllers.BrowserController.BrowserType -import com.nextcloud.talk.components.filebrowser.controllers.BrowserForAvatarController import com.nextcloud.talk.controllers.base.NewBaseController import com.nextcloud.talk.controllers.util.viewBinding import com.nextcloud.talk.databinding.ControllerProfileBinding @@ -71,11 +67,15 @@ import com.nextcloud.talk.models.json.userprofile.Scope import com.nextcloud.talk.models.json.userprofile.UserProfileData import com.nextcloud.talk.models.json.userprofile.UserProfileFieldsOverall import com.nextcloud.talk.models.json.userprofile.UserProfileOverall +import com.nextcloud.talk.remotefilebrowser.activities.RemoteFileBrowserActivity import com.nextcloud.talk.ui.dialog.ScopeDialog import com.nextcloud.talk.utils.ApiUtils import com.nextcloud.talk.utils.DisplayUtils +import com.nextcloud.talk.utils.FileUtils import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_BROWSER_TYPE +import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_MIME_TYPE_FILTER import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN +import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_SINGLE_SELECTION import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_USER_ENTITY import com.nextcloud.talk.utils.database.user.UserUtils import io.reactivex.Observer @@ -496,12 +496,22 @@ class ProfileController : NewBaseController(R.layout.controller_profile) { KEY_USER_ENTITY, Parcels.wrap(UserEntity::class.java, currentUser) ) + bundle.putBoolean(KEY_SINGLE_SELECTION, true) + bundle.putString(KEY_MIME_TYPE_FILTER, "image/") bundle.putString(KEY_ROOM_TOKEN, "123") + + val avatarIntent = Intent(activity, RemoteFileBrowserActivity::class.java) + avatarIntent.putExtras(bundle) + + startActivityForResult(avatarIntent, RemoteFileBrowserActivity.REQUEST_CODE_SELECT_AVATAR) + + /* router.pushController( RouterTransaction.with(BrowserForAvatarController(bundle, this)) .pushChangeHandler(VerticalChangeHandler()) .popChangeHandler(VerticalChangeHandler()) ) + */ } fun handleAvatar(remotePath: String?) { @@ -526,10 +536,7 @@ class ProfileController : NewBaseController(R.layout.controller_profile) { private fun saveBitmapAndPassToImagePicker(bitmap: Bitmap) { var file: File? = null try { - file = File.createTempFile( - "avatar", "png", - Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM) - ) + file = FileUtils.getTempCacheFile(context!!, "avatar/avatar.png") try { FileOutputStream(file).use { out -> bitmap.compress(Bitmap.CompressFormat.PNG, FULL_QUALITY, out) } } catch (e: IOException) { @@ -555,6 +562,7 @@ class ProfileController : NewBaseController(R.layout.controller_profile) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { if (resultCode == Activity.RESULT_OK) { + uploadAvatar(getFile(data)) } else if (resultCode == ImagePicker.RESULT_ERROR) { Toast.makeText(activity, getError(data), Toast.LENGTH_SHORT).show() diff --git a/app/src/main/java/com/nextcloud/talk/dagger/modules/RepositoryModule.kt b/app/src/main/java/com/nextcloud/talk/dagger/modules/RepositoryModule.kt index 0e62a8645..267ab6b41 100644 --- a/app/src/main/java/com/nextcloud/talk/dagger/modules/RepositoryModule.kt +++ b/app/src/main/java/com/nextcloud/talk/dagger/modules/RepositoryModule.kt @@ -22,6 +22,8 @@ package com.nextcloud.talk.dagger.modules import com.nextcloud.talk.api.NcApi +import com.nextcloud.talk.remotefilebrowser.repositories.RemoteFileBrowserItemsRepository +import com.nextcloud.talk.remotefilebrowser.repositories.RemoteFileBrowserItemsRepositoryImpl import com.nextcloud.talk.repositories.unifiedsearch.UnifiedSearchRepository import com.nextcloud.talk.repositories.unifiedsearch.UnifiedSearchRepositoryImpl import com.nextcloud.talk.shareditems.repositories.SharedItemsRepository @@ -29,6 +31,7 @@ import com.nextcloud.talk.shareditems.repositories.SharedItemsRepositoryImpl import com.nextcloud.talk.utils.database.user.CurrentUserProvider import dagger.Module import dagger.Provides +import okhttp3.OkHttpClient @Module class RepositoryModule { @@ -41,4 +44,10 @@ class RepositoryModule { fun provideUnifiedSearchRepository(ncApi: NcApi, userProvider: CurrentUserProvider): UnifiedSearchRepository { return UnifiedSearchRepositoryImpl(ncApi, userProvider) } + + @Provides + fun provideRemoteFileBrowserItemsRepository(okHttpClient: OkHttpClient, userProvider: CurrentUserProvider): + RemoteFileBrowserItemsRepository { + return RemoteFileBrowserItemsRepositoryImpl(okHttpClient, userProvider) + } } diff --git a/app/src/main/java/com/nextcloud/talk/dagger/modules/ViewModelModule.kt b/app/src/main/java/com/nextcloud/talk/dagger/modules/ViewModelModule.kt index b0f7170d8..f2356d0ab 100644 --- a/app/src/main/java/com/nextcloud/talk/dagger/modules/ViewModelModule.kt +++ b/app/src/main/java/com/nextcloud/talk/dagger/modules/ViewModelModule.kt @@ -23,6 +23,7 @@ package com.nextcloud.talk.dagger.modules import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider +import com.nextcloud.talk.remotefilebrowser.viewmodels.RemoteFileBrowserItemsViewModel import com.nextcloud.talk.messagesearch.MessageSearchViewModel import com.nextcloud.talk.shareditems.viewmodels.SharedItemsViewModel import dagger.Binds @@ -59,4 +60,9 @@ abstract class ViewModelModule { @IntoMap @ViewModelKey(MessageSearchViewModel::class) abstract fun messageSearchViewModel(viewModel: MessageSearchViewModel): ViewModel + + @Binds + @IntoMap + @ViewModelKey(RemoteFileBrowserItemsViewModel::class) + abstract fun remoteFileBrowserItemsViewModel(viewModel: RemoteFileBrowserItemsViewModel): ViewModel } diff --git a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/activities/RemoteFileBrowserActivity.kt b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/activities/RemoteFileBrowserActivity.kt new file mode 100644 index 000000000..47f777c7c --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/activities/RemoteFileBrowserActivity.kt @@ -0,0 +1,345 @@ +/* + * Nextcloud Talk application + * + * @author Andy Scherzinger + * Copyright (C) 2022 Andy Scherzinger + * + * This program 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 . + */ + +package com.nextcloud.talk.remotefilebrowser.activities + +import android.app.Activity +import android.content.Intent +import android.os.Bundle +import android.util.Log +import android.view.Menu +import android.view.MenuItem +import android.view.View +import androidx.appcompat.app.AppCompatActivity +import androidx.core.content.res.ResourcesCompat +import androidx.fragment.app.DialogFragment +import androidx.lifecycle.ViewModelProvider +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout +import autodagger.AutoInjector +import com.nextcloud.talk.R +import com.nextcloud.talk.application.NextcloudTalkApplication +import com.nextcloud.talk.databinding.ActivityRemoteFileBrowserBinding +import com.nextcloud.talk.interfaces.SelectionInterface +import com.nextcloud.talk.remotefilebrowser.adapters.RemoteFileBrowserItemsAdapter +import com.nextcloud.talk.remotefilebrowser.model.RemoteFileBrowserItem +import com.nextcloud.talk.remotefilebrowser.viewmodels.RemoteFileBrowserItemsViewModel +import com.nextcloud.talk.ui.dialog.SortingOrderDialogFragment +import com.nextcloud.talk.utils.DisplayUtils +import com.nextcloud.talk.utils.FileSortOrder +import com.nextcloud.talk.utils.FileSortOrderNew +import com.nextcloud.talk.utils.database.user.UserUtils +import com.nextcloud.talk.utils.preferences.AppPreferences +import net.orange_box.storebox.listeners.OnPreferenceValueChangedListener +import java.io.File +import java.util.Collections +import java.util.TreeSet +import javax.inject.Inject + +@AutoInjector(NextcloudTalkApplication::class) +class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, SwipeRefreshLayout.OnRefreshListener { + + @Inject + lateinit var viewModelFactory: ViewModelProvider.Factory + + @Inject + lateinit var appPreferences: AppPreferences + + @Inject + lateinit var userUtils: UserUtils + + private lateinit var binding: ActivityRemoteFileBrowserBinding + private lateinit var viewModel: RemoteFileBrowserItemsViewModel + + private var filesSelectionDoneMenuItem: MenuItem? = null + + private val selectedPaths: MutableSet = Collections.synchronizedSet(TreeSet()) + private var currentPath: String = "/" + + private var browserItems: List = emptyList() + private var adapter: RemoteFileBrowserItemsAdapter? = null + + private var sortingChangeListener: OnPreferenceValueChangedListener? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this) + + binding = ActivityRemoteFileBrowserBinding.inflate(layoutInflater) + setSupportActionBar(binding.remoteFileBrowserItemsToolbar) + setContentView(binding.root) + + DisplayUtils.applyColorToStatusBar( + this, + ResourcesCompat.getColor( + resources, R.color.appbar, null + ) + ) + DisplayUtils.applyColorToNavigationBar( + this.window, + ResourcesCompat.getColor(resources, R.color.bg_default, null) + ) + + supportActionBar?.title = "current patch" + supportActionBar?.setDisplayHomeAsUpEnabled(true) + + initViewModel() + + binding.swipeRefreshList.setOnRefreshListener(this) + binding.swipeRefreshList.setColorSchemeResources(R.color.colorPrimary) + binding.swipeRefreshList.setProgressBackgroundColorSchemeResource(R.color.refresh_spinner_background) + + appPreferences.registerSortingChangeListener( + SortingChangeListener(this).also { + sortingChangeListener = it + } + ) + + viewModel.loadItems(currentPath) + } + + private fun initViewModel() { + viewModel = ViewModelProvider(this, viewModelFactory)[RemoteFileBrowserItemsViewModel::class.java] + + viewModel.viewState.observe(this) { state -> + clearEmptyLoading() + when (state) { + is RemoteFileBrowserItemsViewModel.LoadingItemsState, RemoteFileBrowserItemsViewModel.InitialState -> { + showLoading() + } + + is RemoteFileBrowserItemsViewModel.NoRemoteFileItemsState -> { + showEmpty() + } + + is RemoteFileBrowserItemsViewModel.LoadedState -> { + val remoteFileBrowserItems = state.items + Log.d(TAG, "Items received: $remoteFileBrowserItems") + + // TODO make shwoGrid based on preferences + val showGrid = false + val layoutManager = if (showGrid) { + GridLayoutManager(this, SPAN_COUNT) + } else { + LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false) + } + + // TODO make mimeTypeSelectionFilter a bundled arg for the activity + val mimeTypeSelectionFilter = "image/" + val adapter = RemoteFileBrowserItemsAdapter( + showGrid = showGrid, + mimeTypeSelectionFilter = mimeTypeSelectionFilter, + userEntity = userUtils.currentUser!!, + selectionInterface = this + ) { remoteFileBrowserItem -> + onItemClicked(remoteFileBrowserItem) + } + .apply { + items = if (remoteFileBrowserItems.size > 1) { + remoteFileBrowserItems.subList(1, remoteFileBrowserItems.size) + } else { + ArrayList() + } + browserItems = items + } + + binding.recyclerView.adapter = adapter + binding.recyclerView.layoutManager = layoutManager + binding.recyclerView.setHasFixedSize(true) + + showList() + } + } + } + } + + override fun onCreateOptionsMenu(menu: Menu?): Boolean { + super.onCreateOptionsMenu(menu) + menuInflater.inflate(R.menu.menu_share_files, menu) + filesSelectionDoneMenuItem = menu?.findItem(R.id.files_selection_done) + filesSelectionDoneMenuItem?.isVisible = selectedPaths.size > 0 + return true + } + + private fun onItemClicked(remoteFileBrowserItem: RemoteFileBrowserItem) { + if ("inode/directory" == remoteFileBrowserItem.mimeType) { + currentPath = remoteFileBrowserItem.path!! + viewModel.loadItems(currentPath) + } else { + toggleBrowserItemSelection(remoteFileBrowserItem.path!!) + } + } + + override fun onResume() { + super.onResume() + + binding.pathNavigationBackButton.setOnClickListener { goBack() } + binding.sortButton.setOnClickListener { changeSorting() } + + binding.sortButton.setText( + DisplayUtils.getSortOrderStringId(FileSortOrder.getFileSortOrder(appPreferences.sorting)) + ) + + refreshCurrentPath() + } + + fun changeSorting() { + val newFragment: DialogFragment = SortingOrderDialogFragment + .newInstance(FileSortOrder.getFileSortOrder(appPreferences.sorting)) + newFragment.show( + supportFragmentManager, + SortingOrderDialogFragment.SORTING_ORDER_FRAGMENT + ) + } + + private fun goBack(): Boolean { + if (currentPath != "/") { + viewModel.loadItems(File(currentPath).parent!!) + } + return true + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + return when (item.itemId) { + android.R.id.home -> { + onBackPressed() + true + } + R.id.files_selection_done -> { + onFileSelectionDone() + true + } + else -> { + return super.onOptionsItemSelected(item) + } + } + } + + private fun onFileSelectionDone() { + val data = Intent() + data.putStringArrayListExtra(EXTRA_SELECTED_PATHS, ArrayList(selectedPaths)) + setResult(Activity.RESULT_OK, data) + finish() + } + + private fun clearEmptyLoading() { + binding.emptyContainer.emptyListView.visibility = View.GONE + } + + private fun showLoading() { + binding.emptyContainer.emptyListViewHeadline.text = getString(R.string.file_list_loading) + binding.emptyContainer.emptyListView.visibility = View.VISIBLE + binding.recyclerView.visibility = View.GONE + } + + private fun showEmpty() { + binding.emptyContainer.emptyListViewHeadline.text = getString(R.string.nc_shared_items_empty) + binding.emptyContainer.emptyListView.visibility = View.VISIBLE + binding.recyclerView.visibility = View.GONE + } + + private fun showList() { + binding.recyclerView.visibility = View.VISIBLE + } + + override fun onRefresh() { + refreshCurrentPath() + } + + private fun refreshCurrentPath() { + viewModel.loadItems(currentPath) + } + + private fun shouldPathBeSelectedDueToParent(currentPath: String): Boolean { + var file = File(currentPath) + if (selectedPaths.size > 0 && file.parent != "/") { + while (file.parent != null) { + var parent = file.parent!! + if (File(file.parent!!).parent != null) { + parent += "/" + } + if (selectedPaths.contains(parent)) { + return true + } + file = File(file.parent!!) + } + } + return false + } + + private fun checkAndRemoveAnySelectedParents(currentPath: String) { + var file = File(currentPath) + selectedPaths.remove(currentPath) + while (file.parent != null) { + selectedPaths.remove(file.parent!! + "/") + file = File(file.parent!!) + } + runOnUiThread { + binding.recyclerView.adapter!!.notifyDataSetChanged() + } + } + + companion object { + private val TAG = RemoteFileBrowserActivity::class.simpleName + const val SPAN_COUNT: Int = 4 + const val EXTRA_SELECTED_PATHS = "EXTRA_SELECTED_PATH" + const val REQUEST_CODE_SELECT_AVATAR = 22 + } + + override fun toggleBrowserItemSelection(path: String) { + if (selectedPaths.contains(path) || shouldPathBeSelectedDueToParent(path)) { + checkAndRemoveAnySelectedParents(path) + } else { + // TODO if it's a folder, remove all the children we added manually + selectedPaths.add(path) + } + filesSelectionDoneMenuItem?.isVisible = selectedPaths.size > 0 + } + + override fun isPathSelected(path: String): Boolean { + return selectedPaths.contains(path) || shouldPathBeSelectedDueToParent(path) + } + + override fun shouldOnlySelectOneImageFile(): Boolean { + return true + } + + @Suppress("Detekt.TooGenericExceptionCaught") + private class SortingChangeListener(private val activity: RemoteFileBrowserActivity) : + OnPreferenceValueChangedListener { + override fun onChanged(newValue: String) { + try { + val sortOrder = FileSortOrderNew.getFileSortOrder(newValue) + + activity.binding.sortButton.setText(DisplayUtils.getSortOrderStringId(sortOrder)) + activity.browserItems = sortOrder.sortCloudFiles(activity.browserItems) + + activity.runOnUiThread { + activity.adapter!!.updateDataSet(activity.browserItems) + } + } catch (npe: NullPointerException) { + // view binding can be null + // since this is called asynchronously and UI might have been destroyed in the meantime + Log.i(TAG, "UI destroyed - view binding already gone") + } + } + } +} diff --git a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/adapters/RemoteFileBrowserItemsAdapter.kt b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/adapters/RemoteFileBrowserItemsAdapter.kt new file mode 100644 index 000000000..0af1015ee --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/adapters/RemoteFileBrowserItemsAdapter.kt @@ -0,0 +1,86 @@ +/* + * Nextcloud Talk application + * + * @author Andy Scherzinger + * Copyright (C) 2022 Andy Scherzinger + * + * This program 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 . + */ + +package com.nextcloud.talk.remotefilebrowser.adapters + +import android.annotation.SuppressLint +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.nextcloud.talk.databinding.RvItemBrowserFileBinding +import com.nextcloud.talk.interfaces.SelectionInterface +import com.nextcloud.talk.models.database.UserEntity +import com.nextcloud.talk.remotefilebrowser.model.RemoteFileBrowserItem + +class RemoteFileBrowserItemsAdapter( + private val showGrid: Boolean = false, + private val mimeTypeSelectionFilter: String? = null, + private val userEntity: UserEntity, + private val selectionInterface: SelectionInterface, + private val onItemClicked: (RemoteFileBrowserItem) -> Unit +) : RecyclerView.Adapter() { + + var items: List = emptyList() + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RemoteFileBrowserItemsViewHolder { + + return if (showGrid) { + RemoteFileBrowserItemsListViewHolder( + RvItemBrowserFileBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false + ), + mimeTypeSelectionFilter, + userEntity, + selectionInterface + ) { + onItemClicked(items[it]) + } + } else { + RemoteFileBrowserItemsListViewHolder( + RvItemBrowserFileBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false + ), + mimeTypeSelectionFilter, + userEntity, + selectionInterface + ) { + onItemClicked(items[it]) + } + } + } + + override fun onBindViewHolder(holder: RemoteFileBrowserItemsViewHolder, position: Int) { + holder.onBind(items[position]) + } + + override fun getItemCount(): Int { + return items.size + } + + @SuppressLint("NotifyDataSetChanged") + fun updateDataSet(browserItems: List) { + items = browserItems + notifyDataSetChanged() + } +} diff --git a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/adapters/RemoteFileBrowserItemsListViewHolder.kt b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/adapters/RemoteFileBrowserItemsListViewHolder.kt new file mode 100644 index 000000000..7317c2a3f --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/adapters/RemoteFileBrowserItemsListViewHolder.kt @@ -0,0 +1,153 @@ +/* + * Nextcloud Talk application + * + * @author Andy Scherzinger + * Copyright (C) 202 Andy Scherzinger + * + * This program 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 . + */ + +package com.nextcloud.talk.remotefilebrowser.adapters + +import android.text.format.Formatter +import android.util.Log +import android.view.View +import androidx.appcompat.content.res.AppCompatResources +import autodagger.AutoInjector +import com.facebook.drawee.backends.pipeline.Fresco +import com.facebook.drawee.interfaces.DraweeController +import com.facebook.drawee.view.SimpleDraweeView +import com.nextcloud.talk.R +import com.nextcloud.talk.application.NextcloudTalkApplication +import com.nextcloud.talk.databinding.RvItemBrowserFileBinding +import com.nextcloud.talk.interfaces.SelectionInterface +import com.nextcloud.talk.models.database.UserEntity +import com.nextcloud.talk.remotefilebrowser.model.RemoteFileBrowserItem +import com.nextcloud.talk.utils.ApiUtils +import com.nextcloud.talk.utils.DateUtils.getLocalDateTimeStringFromTimestamp +import com.nextcloud.talk.utils.DisplayUtils +import com.nextcloud.talk.utils.DrawableUtils.getDrawableResourceIdForMimeType + +@AutoInjector(NextcloudTalkApplication::class) +class RemoteFileBrowserItemsListViewHolder( + override val binding: RvItemBrowserFileBinding, + mimeTypeSelectionFilter: String?, + currentUser: UserEntity, + selectionInterface: SelectionInterface, + onItemClicked: (Int) -> Unit +) : RemoteFileBrowserItemsViewHolder(binding, mimeTypeSelectionFilter, currentUser, selectionInterface) { + + override val fileIcon: SimpleDraweeView + get() = binding.fileIcon + + private var selectable : Boolean = true + private var clickable : Boolean = true + + init { + itemView.setOnClickListener { + if (clickable) { + onItemClicked(bindingAdapterPosition) + if (selectable) { + binding.selectFileCheckbox.toggle() + } + } + } + } + + override fun onBind(item: RemoteFileBrowserItem) { + + super.onBind(item) + + binding.fileIcon.controller = null + if (!item.isAllowedToReShare || item.isEncrypted) { + binding.root.isEnabled = false + binding.root.alpha = DISABLED_ALPHA + } else { + binding.root.isEnabled = true + binding.root.alpha = ENABLED_ALPHA + } + + binding.fileEncryptedImageView.visibility = + if (item.isEncrypted) { + View.VISIBLE + } else { + View.GONE + } + + binding.fileFavoriteImageView.visibility = + if (item.isFavorite) { + View.VISIBLE + } else { + View.GONE + } + + calculateSelectability(item) + calculateClickability(item, selectable) + setSelectability() + + binding.fileIcon + .hierarchy + .setPlaceholderImage( + AppCompatResources.getDrawable( + binding.fileIcon.context, getDrawableResourceIdForMimeType(item.mimeType) + ) + ) + + if (item.hasPreview) { + val path = ApiUtils.getUrlForFilePreviewWithRemotePath( + currentUser.baseUrl, + item.path, + binding.fileIcon.context.resources.getDimensionPixelSize(R.dimen.small_item_height) + ) + if (path.isNotEmpty()) { + val draweeController: DraweeController = Fresco.newDraweeControllerBuilder() + .setAutoPlayAnimations(true) + .setImageRequest(DisplayUtils.getImageRequestForUrl(path, null)) + .build() + binding.fileIcon.controller = draweeController + } + } + + binding.filenameTextView.text = item.displayName + binding.fileModifiedInfo.text = String.format( + binding.fileModifiedInfo.context.getString(R.string.nc_last_modified), + Formatter.formatShortFileSize(binding.fileModifiedInfo.context, item.size), + getLocalDateTimeStringFromTimestamp(item.modifiedTimestamp) + ) + + binding.selectFileCheckbox.isChecked = selectionInterface.isPathSelected(item.path!!) + } + + private fun setSelectability() { + if (selectable) { + binding.selectFileCheckbox.visibility = View.VISIBLE + } else { + binding.selectFileCheckbox.visibility = View.GONE + } + } + + private fun calculateSelectability(item: RemoteFileBrowserItem) { + selectable = item.isFile && + (mimeTypeSelectionFilter == null || item.mimeType?.startsWith(mimeTypeSelectionFilter) == true) + } + + private fun calculateClickability(item: RemoteFileBrowserItem, selectableItem: Boolean) { + clickable = selectableItem || "inode/directory" == item.mimeType + } + + companion object { + private const val DISABLED_ALPHA: Float = 0.38f + private const val ENABLED_ALPHA: Float = 1.0f + } +} diff --git a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/adapters/RemoteFileBrowserItemsViewHolder.kt b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/adapters/RemoteFileBrowserItemsViewHolder.kt new file mode 100644 index 000000000..4ebc5f7b9 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/adapters/RemoteFileBrowserItemsViewHolder.kt @@ -0,0 +1,53 @@ +/* + * Nextcloud Talk application + * + * @author Andy Scherzinger + * Copyright (C) 2022 Andy Scherzinger + * + * This program 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 . + */ + +package com.nextcloud.talk.remotefilebrowser.adapters + +import android.graphics.drawable.Drawable +import androidx.core.content.ContextCompat +import androidx.recyclerview.widget.RecyclerView +import androidx.viewbinding.ViewBinding +import com.facebook.drawee.view.SimpleDraweeView +import com.nextcloud.talk.interfaces.SelectionInterface +import com.nextcloud.talk.models.database.UserEntity +import com.nextcloud.talk.remotefilebrowser.model.RemoteFileBrowserItem +import com.nextcloud.talk.utils.DrawableUtils + +abstract class RemoteFileBrowserItemsViewHolder( + open val binding: ViewBinding, + val mimeTypeSelectionFilter: String? = null, + val currentUser: UserEntity, + val selectionInterface: SelectionInterface, +) : RecyclerView.ViewHolder(binding.root) { + + abstract val fileIcon: SimpleDraweeView + + open fun onBind(item: RemoteFileBrowserItem) { + fileIcon.hierarchy.setPlaceholderImage(staticImage(item.mimeType, fileIcon)) + } + + private fun staticImage( + mimeType: String?, + image: SimpleDraweeView + ): Drawable { + val drawableResourceId = DrawableUtils.getDrawableResourceIdForMimeType(mimeType) + return ContextCompat.getDrawable(image.context, drawableResourceId)!! + } +} diff --git a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/model/RemoteFileBrowserItem.kt b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/model/RemoteFileBrowserItem.kt new file mode 100644 index 000000000..32e06fba8 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/model/RemoteFileBrowserItem.kt @@ -0,0 +1,49 @@ +/* + * Nextcloud Talk application + * + * @author Andy Scherzinger + * @author Mario Danic + * Copyright (C) 202 Andy Scherzinger + * Copyright (C) 2017-2018 Mario Danic + * + * This program 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 . + */ + +package com.nextcloud.talk.remotefilebrowser.model + +import android.os.Parcelable +import com.bluelinelabs.logansquare.annotation.JsonObject +import kotlinx.android.parcel.Parcelize + +@Parcelize +@JsonObject +data class RemoteFileBrowserItem( + var path: String? = null, + var displayName: String? = null, + var mimeType: String? = null, + var modifiedTimestamp: Long = 0, + var size: Long = 0, + var isFile: Boolean = false, + + // Used for remote files + var remoteId: String? = null, + var hasPreview: Boolean = false, + var isFavorite: Boolean = false, + var isEncrypted: Boolean = false, + var permissions: String? = null, + var isAllowedToReShare: Boolean = false +) : Parcelable { + // This constructor is added to work with the 'com.bluelinelabs.logansquare.annotation.JsonObject' + constructor() : this(null, null, null, 0, 0, false, null, false, false, false, null, false) +} diff --git a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/repositories/RemoteFileBrowserItemsRepository.kt b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/repositories/RemoteFileBrowserItemsRepository.kt new file mode 100644 index 000000000..a2ea15009 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/repositories/RemoteFileBrowserItemsRepository.kt @@ -0,0 +1,29 @@ +/* + * Nextcloud Talk application + * + * @author Andy Scherzinger + * Copyright (C) 202 Andy Scherzinger + * + * This program 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 . + */ + +package com.nextcloud.talk.remotefilebrowser.repositories + +import com.nextcloud.talk.remotefilebrowser.model.RemoteFileBrowserItem +import io.reactivex.Observable + +interface RemoteFileBrowserItemsRepository { + + fun listFolder(path: String): Observable> +} diff --git a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/repositories/RemoteFileBrowserItemsRepositoryImpl.kt b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/repositories/RemoteFileBrowserItemsRepositoryImpl.kt new file mode 100644 index 000000000..c992462aa --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/repositories/RemoteFileBrowserItemsRepositoryImpl.kt @@ -0,0 +1,56 @@ +/* + * Nextcloud Talk application + * + * @author Andy Scherzinger + * Copyright (C) 202 Andy Scherzinger + * + * This program 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 . + */ + +package com.nextcloud.talk.remotefilebrowser.repositories + +import com.nextcloud.talk.components.filebrowser.webdav.ReadFilesystemOperation +import com.nextcloud.talk.models.database.UserEntity +import com.nextcloud.talk.remotefilebrowser.model.RemoteFileBrowserItem +import com.nextcloud.talk.utils.database.user.CurrentUserProvider +import io.reactivex.Observable +import okhttp3.OkHttpClient +import javax.inject.Inject + +class RemoteFileBrowserItemsRepositoryImpl @Inject constructor( + private val okHttpClient: OkHttpClient, + private val userProvider: CurrentUserProvider +) : RemoteFileBrowserItemsRepository { + + private val userEntity: UserEntity + get() = userProvider.currentUser!! + + override fun listFolder(path: String): + Observable> { + return Observable.fromCallable { + val operation = + ReadFilesystemOperation( + okHttpClient, + userEntity, + path, + 1 + ) + val davResponse = operation.readRemotePath() + if (davResponse.getData() != null) { + return@fromCallable davResponse.getData() as List + } + return@fromCallable emptyList() + } + } +} diff --git a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/viewmodels/RemoteFileBrowserItemsViewModel.kt b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/viewmodels/RemoteFileBrowserItemsViewModel.kt new file mode 100644 index 000000000..f37edcfbb --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/viewmodels/RemoteFileBrowserItemsViewModel.kt @@ -0,0 +1,93 @@ +/* + * Nextcloud Talk application + * + * @author Andy Scherzinger + * Copyright (C) 202 Andy Scherzinger + * + * This program 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 . + */ + +package com.nextcloud.talk.remotefilebrowser.viewmodels + +import android.util.Log +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import com.nextcloud.talk.remotefilebrowser.model.RemoteFileBrowserItem +import com.nextcloud.talk.remotefilebrowser.repositories.RemoteFileBrowserItemsRepository +import io.reactivex.Observer +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.Disposable +import io.reactivex.schedulers.Schedulers +import javax.inject.Inject + +class RemoteFileBrowserItemsViewModel @Inject constructor( + private val repository: RemoteFileBrowserItemsRepository +) : + ViewModel() { + + sealed interface ViewState + object InitialState : ViewState + object NoRemoteFileItemsState : ViewState + object LoadingItemsState : ViewState + class LoadedState(val items: List) : ViewState + + private val _viewState: MutableLiveData = MutableLiveData(InitialState) + + val viewState: LiveData + get() = _viewState + + fun loadItems(path: String) { + _viewState.value = LoadingItemsState + repository.listFolder(path).subscribeOn(Schedulers.io()) + ?.observeOn(AndroidSchedulers.mainThread()) + ?.subscribe(RemoteFileBrowserItemsObserver()) + } + + inner class RemoteFileBrowserItemsObserver : Observer> { + + var newRemoteFileBrowserItems: List? = null + + override fun onSubscribe(d: Disposable) = Unit + + override fun onNext(response: List) { + newRemoteFileBrowserItems = response + } + + override fun onError(e: Throwable) { + Log.d(TAG, "An error occurred: $e") + } + + override fun onComplete() { + if (newRemoteFileBrowserItems.isNullOrEmpty()) { + this@RemoteFileBrowserItemsViewModel._viewState.value = NoRemoteFileItemsState + } else { + setCurrentState(newRemoteFileBrowserItems!!) + } + } + + private fun setCurrentState(items: List) { + when (this@RemoteFileBrowserItemsViewModel._viewState.value) { + is LoadedState, LoadingItemsState -> { + this@RemoteFileBrowserItemsViewModel._viewState.value = LoadedState(items) + } + else -> return + } + } + } + + companion object { + private val TAG = RemoteFileBrowserItemsViewModel::class.simpleName + } +} diff --git a/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.java b/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.java index b51b589e2..de2f682ee 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.java +++ b/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.java @@ -636,6 +636,25 @@ public class DisplayUtils { } } + public static @StringRes + int getSortOrderStringId(FileSortOrderNew sortOrder) { + switch (sortOrder.name) { + case sort_z_to_a_id: + return R.string.menu_item_sort_by_name_z_a; + case sort_new_to_old_id: + return R.string.menu_item_sort_by_date_newest_first; + case sort_old_to_new_id: + return R.string.menu_item_sort_by_date_oldest_first; + case sort_big_to_small_id: + return R.string.menu_item_sort_by_size_biggest_first; + case sort_small_to_big_id: + return R.string.menu_item_sort_by_size_smallest_first; + case sort_a_to_z_id: + default: + return R.string.menu_item_sort_by_name_a_z; + } + } + /** * calculates the relative time string based on the given modification timestamp. * diff --git a/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByDateNew.java b/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByDateNew.java new file mode 100644 index 000000000..bcd2444e1 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByDateNew.java @@ -0,0 +1,52 @@ +/* + * Nextcloud Talk application + * + * @author Sven R. Kunze + * @author Andy Scherzinger + * Copyright (C) 2021 Andy Scherzinger + * Copyright (C) 2017 Sven R. Kunze + * + * This program 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 . + */ + +package com.nextcloud.talk.utils; + +import com.nextcloud.talk.remotefilebrowser.model.RemoteFileBrowserItem; + +import java.util.Collections; +import java.util.List; + +/** + * Created by srkunze on 28.08.17. + */ +public class FileSortOrderByDateNew extends FileSortOrderNew { + + FileSortOrderByDateNew(String name, boolean ascending) { + super(name, ascending); + } + + /** + * Sorts list by Date. + * + * @param files list of files to sort + */ + public List sortCloudFiles(List files) { + final int multiplier = isAscending ? 1 : -1; + + Collections.sort(files, (o1, o2) -> + multiplier * Long.compare(o1.getModifiedTimestamp(), o2.getModifiedTimestamp())); + + return super.sortCloudFiles(files); + } +} diff --git a/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByNameNew.java b/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByNameNew.java new file mode 100644 index 000000000..7d36e6ef4 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByNameNew.java @@ -0,0 +1,63 @@ +/* + * Nextcloud Talk application + * + * @author Sven R. Kunze + * @author Andy Scherzinger + * Copyright (C) 2021 Andy Scherzinger + * Copyright (C) 2017 Sven R. Kunze + * + * This program 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 . + */ + +package com.nextcloud.talk.utils; + +import com.nextcloud.talk.remotefilebrowser.model.RemoteFileBrowserItem; + +import java.util.Collections; +import java.util.List; + +import third_parties.daveKoeller.AlphanumComparator; + +/** + * Created by srkunze on 28.08.17. + */ +public class FileSortOrderByNameNew extends FileSortOrderNew { + + FileSortOrderByNameNew(String name, boolean ascending) { + super(name, ascending); + } + + /** + * Sorts list by Name. + * + * @param files files to sort + */ + @SuppressWarnings("Bx") + public List sortCloudFiles(List files) { + final int multiplier = isAscending ? 1 : -1; + + Collections.sort(files, (o1, o2) -> { + if (!o1.isFile() && !o2.isFile()) { + return multiplier * new AlphanumComparator().compare(o1, o2); + } else if (!o1.isFile()) { + return -1; + } else if (!o2.isFile()) { + return 1; + } + return multiplier * new AlphanumComparator().compare(o1, o2); + }); + + return super.sortCloudFiles(files); + } +} diff --git a/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderBySizeNew.java b/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderBySizeNew.java new file mode 100644 index 000000000..fc071c058 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderBySizeNew.java @@ -0,0 +1,61 @@ +/* + * Nextcloud Talk application + * + * @author Sven R. Kunze + * @author Andy Scherzinger + * Copyright (C) 2021 Andy Scherzinger + * Copyright (C) 2017 Sven R. Kunze + * + * This program 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 . + */ + +package com.nextcloud.talk.utils; + +import com.nextcloud.talk.remotefilebrowser.model.RemoteFileBrowserItem; + +import java.util.Collections; +import java.util.List; + +/** + * Sorts files by sizes + */ +public class FileSortOrderBySizeNew extends FileSortOrderNew { + + FileSortOrderBySizeNew(String name, boolean ascending) { + super(name, ascending); + } + + /** + * Sorts list by Size. + * + * @param files list of files to sort + */ + public List sortCloudFiles(List files) { + final int multiplier = isAscending ? 1 : -1; + + Collections.sort(files, (o1, o2) -> { + if (!o1.isFile() && !o2.isFile()) { + return multiplier * Long.compare(o1.getSize(), o2.getSize()); + } else if (!o1.isFile()) { + return -1; + } else if (!o2.isFile()) { + return 1; + } else { + return multiplier * Long.compare(o1.getSize(), o2.getSize()); + } + }); + + return super.sortCloudFiles(files); + } +} diff --git a/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderNew.java b/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderNew.java new file mode 100644 index 000000000..876fa581b --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderNew.java @@ -0,0 +1,108 @@ +/* + * Nextcloud Talk application + * + * @author Sven R. Kunze + * @author Andy Scherzinger + * Copyright (C) 2021 Andy Scherzinger + * Copyright (C) 2017 Sven R. Kunze + * + * This program 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 . + */ + +package com.nextcloud.talk.utils; + +import android.text.TextUtils; + +import com.nextcloud.talk.components.filebrowser.adapters.items.BrowserFileItem; +import com.nextcloud.talk.remotefilebrowser.model.RemoteFileBrowserItem; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import androidx.annotation.Nullable; + +/** + * Sort order + */ +public class FileSortOrderNew { + public static final String sort_a_to_z_id = "sort_a_to_z"; + public static final String sort_z_to_a_id = "sort_z_to_a"; + public static final String sort_old_to_new_id = "sort_old_to_new"; + public static final String sort_new_to_old_id = "sort_new_to_old"; + public static final String sort_small_to_big_id = "sort_small_to_big"; + public static final String sort_big_to_small_id = "sort_big_to_small"; + + public static final FileSortOrderNew sort_a_to_z = new FileSortOrderByNameNew(sort_a_to_z_id, true); + public static final FileSortOrderNew sort_z_to_a = new FileSortOrderByNameNew(sort_z_to_a_id, false); + public static final FileSortOrderNew sort_old_to_new = new FileSortOrderByDateNew(sort_old_to_new_id, true); + public static final FileSortOrderNew sort_new_to_old = new FileSortOrderByDateNew(sort_new_to_old_id, false); + public static final FileSortOrderNew sort_small_to_big = new FileSortOrderBySizeNew(sort_small_to_big_id, true); + public static final FileSortOrderNew sort_big_to_small = new FileSortOrderBySizeNew(sort_big_to_small_id, false); + + public static final Map sortOrders; + + static { + HashMap temp = new HashMap<>(); + temp.put(sort_a_to_z.name, sort_a_to_z); + temp.put(sort_z_to_a.name, sort_z_to_a); + temp.put(sort_old_to_new.name, sort_old_to_new); + temp.put(sort_new_to_old.name, sort_new_to_old); + temp.put(sort_small_to_big.name, sort_small_to_big); + temp.put(sort_big_to_small.name, sort_big_to_small); + + sortOrders = Collections.unmodifiableMap(temp); + } + + public String name; + public boolean isAscending; + + public FileSortOrderNew(String name, boolean ascending) { + this.name = name; + isAscending = ascending; + } + + public static FileSortOrderNew getFileSortOrder(@Nullable String key) { + if (TextUtils.isEmpty(key) || !sortOrders.containsKey(key)) { + return sort_a_to_z; + } else { + return sortOrders.get(key); + } + } + + public List sortCloudFiles(List files) { + return sortCloudFilesByFavourite(files); + } + + /** + * Sorts list by Favourites. + * + * @param files files to sort + */ + public static List sortCloudFilesByFavourite(List files) { + Collections.sort(files, (o1, o2) -> { + if (o1.isFavorite() && o2.isFavorite()) { + return 0; + } else if (o1.isFavorite()) { + return -1; + } else if (o2.isFavorite()) { + return 1; + } + return 0; + }); + + return files; + } +} diff --git a/app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.kt b/app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.kt index 02e1b0abe..dad594bdd 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.kt @@ -74,4 +74,6 @@ object BundleKeys { val KEY_FORWARD_HIDE_SOURCE_ROOM = "KEY_FORWARD_HIDE_SOURCE_ROOM" val KEY_SYSTEM_NOTIFICATION_ID = "KEY_SYSTEM_NOTIFICATION_ID" const val KEY_MESSAGE_ID = "KEY_MESSAGE_ID" + const val KEY_SINGLE_SELECTION = "KEY_SINGLE_SELECTION" + const val KEY_MIME_TYPE_FILTER = "KEY_MIME_TYPE_FILTER" } diff --git a/app/src/main/res/layout/activity_remote_file_browser.xml b/app/src/main/res/layout/activity_remote_file_browser.xml new file mode 100644 index 000000000..52db0abfc --- /dev/null +++ b/app/src/main/res/layout/activity_remote_file_browser.xml @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 9d4745ee9b8f5e285ab5881f028a7edb1f14f639 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Brey?= Date: Mon, 6 Jun 2022 16:07:20 +0200 Subject: [PATCH 02/29] RemoteFileBrowser: do sorting in ViewModel, not activity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Álvaro Brey --- .../activities/RemoteFileBrowserActivity.kt | 62 ++++--------------- .../RemoteFileBrowserItemsListViewHolder.kt | 5 +- .../RemoteFileBrowserItemsViewModel.kt | 44 ++++++++++++- 3 files changed, 55 insertions(+), 56 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/activities/RemoteFileBrowserActivity.kt b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/activities/RemoteFileBrowserActivity.kt index 47f777c7c..208065148 100644 --- a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/activities/RemoteFileBrowserActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/activities/RemoteFileBrowserActivity.kt @@ -45,10 +45,7 @@ import com.nextcloud.talk.remotefilebrowser.viewmodels.RemoteFileBrowserItemsVie import com.nextcloud.talk.ui.dialog.SortingOrderDialogFragment import com.nextcloud.talk.utils.DisplayUtils import com.nextcloud.talk.utils.FileSortOrder -import com.nextcloud.talk.utils.FileSortOrderNew import com.nextcloud.talk.utils.database.user.UserUtils -import com.nextcloud.talk.utils.preferences.AppPreferences -import net.orange_box.storebox.listeners.OnPreferenceValueChangedListener import java.io.File import java.util.Collections import java.util.TreeSet @@ -60,9 +57,7 @@ class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, Swipe @Inject lateinit var viewModelFactory: ViewModelProvider.Factory - @Inject - lateinit var appPreferences: AppPreferences - + // TODO use CurrentUserProvider instead for narrower scope @Inject lateinit var userUtils: UserUtils @@ -74,11 +69,6 @@ class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, Swipe private val selectedPaths: MutableSet = Collections.synchronizedSet(TreeSet()) private var currentPath: String = "/" - private var browserItems: List = emptyList() - private var adapter: RemoteFileBrowserItemsAdapter? = null - - private var sortingChangeListener: OnPreferenceValueChangedListener? = null - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this) @@ -107,11 +97,8 @@ class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, Swipe binding.swipeRefreshList.setColorSchemeResources(R.color.colorPrimary) binding.swipeRefreshList.setProgressBackgroundColorSchemeResource(R.color.refresh_spinner_background) - appPreferences.registerSortingChangeListener( - SortingChangeListener(this).also { - sortingChangeListener = it - } - ) + binding.pathNavigationBackButton.setOnClickListener { goBack() } + binding.sortButton.setOnClickListener { changeSorting() } viewModel.loadItems(currentPath) } @@ -125,11 +112,9 @@ class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, Swipe is RemoteFileBrowserItemsViewModel.LoadingItemsState, RemoteFileBrowserItemsViewModel.InitialState -> { showLoading() } - is RemoteFileBrowserItemsViewModel.NoRemoteFileItemsState -> { showEmpty() } - is RemoteFileBrowserItemsViewModel.LoadedState -> { val remoteFileBrowserItems = state.items Log.d(TAG, "Items received: $remoteFileBrowserItems") @@ -144,6 +129,7 @@ class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, Swipe // TODO make mimeTypeSelectionFilter a bundled arg for the activity val mimeTypeSelectionFilter = "image/" + // TODO do not needlesly recreate adapter if it can be reused val adapter = RemoteFileBrowserItemsAdapter( showGrid = showGrid, mimeTypeSelectionFilter = mimeTypeSelectionFilter, @@ -158,7 +144,6 @@ class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, Swipe } else { ArrayList() } - browserItems = items } binding.recyclerView.adapter = adapter @@ -169,6 +154,12 @@ class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, Swipe } } } + + viewModel.fileSortOrder.observe(this) { sortOrder -> + if (sortOrder != null) { + binding.sortButton.setText(DisplayUtils.getSortOrderStringId(sortOrder)) + } + } } override fun onCreateOptionsMenu(menu: Menu?): Boolean { @@ -190,20 +181,12 @@ class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, Swipe override fun onResume() { super.onResume() - - binding.pathNavigationBackButton.setOnClickListener { goBack() } - binding.sortButton.setOnClickListener { changeSorting() } - - binding.sortButton.setText( - DisplayUtils.getSortOrderStringId(FileSortOrder.getFileSortOrder(appPreferences.sorting)) - ) - refreshCurrentPath() } - fun changeSorting() { + private fun changeSorting() { val newFragment: DialogFragment = SortingOrderDialogFragment - .newInstance(FileSortOrder.getFileSortOrder(appPreferences.sorting)) + .newInstance(FileSortOrder.getFileSortOrder(viewModel.fileSortOrder.value!!.name)) newFragment.show( supportFragmentManager, SortingOrderDialogFragment.SORTING_ORDER_FRAGMENT @@ -321,25 +304,4 @@ class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, Swipe override fun shouldOnlySelectOneImageFile(): Boolean { return true } - - @Suppress("Detekt.TooGenericExceptionCaught") - private class SortingChangeListener(private val activity: RemoteFileBrowserActivity) : - OnPreferenceValueChangedListener { - override fun onChanged(newValue: String) { - try { - val sortOrder = FileSortOrderNew.getFileSortOrder(newValue) - - activity.binding.sortButton.setText(DisplayUtils.getSortOrderStringId(sortOrder)) - activity.browserItems = sortOrder.sortCloudFiles(activity.browserItems) - - activity.runOnUiThread { - activity.adapter!!.updateDataSet(activity.browserItems) - } - } catch (npe: NullPointerException) { - // view binding can be null - // since this is called asynchronously and UI might have been destroyed in the meantime - Log.i(TAG, "UI destroyed - view binding already gone") - } - } - } } diff --git a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/adapters/RemoteFileBrowserItemsListViewHolder.kt b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/adapters/RemoteFileBrowserItemsListViewHolder.kt index 7317c2a3f..61bf4be53 100644 --- a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/adapters/RemoteFileBrowserItemsListViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/adapters/RemoteFileBrowserItemsListViewHolder.kt @@ -21,7 +21,6 @@ package com.nextcloud.talk.remotefilebrowser.adapters import android.text.format.Formatter -import android.util.Log import android.view.View import androidx.appcompat.content.res.AppCompatResources import autodagger.AutoInjector @@ -51,8 +50,8 @@ class RemoteFileBrowserItemsListViewHolder( override val fileIcon: SimpleDraweeView get() = binding.fileIcon - private var selectable : Boolean = true - private var clickable : Boolean = true + private var selectable: Boolean = true + private var clickable: Boolean = true init { itemView.setOnClickListener { diff --git a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/viewmodels/RemoteFileBrowserItemsViewModel.kt b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/viewmodels/RemoteFileBrowserItemsViewModel.kt index f37edcfbb..6fb244ed1 100644 --- a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/viewmodels/RemoteFileBrowserItemsViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/viewmodels/RemoteFileBrowserItemsViewModel.kt @@ -26,14 +26,18 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import com.nextcloud.talk.remotefilebrowser.model.RemoteFileBrowserItem import com.nextcloud.talk.remotefilebrowser.repositories.RemoteFileBrowserItemsRepository +import com.nextcloud.talk.utils.FileSortOrderNew +import com.nextcloud.talk.utils.preferences.AppPreferences import io.reactivex.Observer import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.Disposable import io.reactivex.schedulers.Schedulers +import net.orange_box.storebox.listeners.OnPreferenceValueChangedListener import javax.inject.Inject class RemoteFileBrowserItemsViewModel @Inject constructor( - private val repository: RemoteFileBrowserItemsRepository + private val repository: RemoteFileBrowserItemsRepository, + private val appPreferences: AppPreferences ) : ViewModel() { @@ -43,11 +47,33 @@ class RemoteFileBrowserItemsViewModel @Inject constructor( object LoadingItemsState : ViewState class LoadedState(val items: List) : ViewState - private val _viewState: MutableLiveData = MutableLiveData(InitialState) + private val initialSortOrder = FileSortOrderNew.getFileSortOrder(appPreferences.sorting) + private val sortingPrefListener: SortChangeListener = SortChangeListener() + private val _viewState: MutableLiveData = MutableLiveData(InitialState) val viewState: LiveData get() = _viewState + // TODO incorporate into view state object? + private val _fileSortOrder: MutableLiveData = MutableLiveData(initialSortOrder) + val fileSortOrder: LiveData + get() = _fileSortOrder + + init { + appPreferences.registerSortingChangeListener(sortingPrefListener) + } + + inner class SortChangeListener : OnPreferenceValueChangedListener { + override fun onChanged(newValue: String) { + onSelectSortOrder(newValue) + } + } + + override fun onCleared() { + super.onCleared() + appPreferences.unregisterSortingChangeListener(sortingPrefListener) + } + fun loadItems(path: String) { _viewState.value = LoadingItemsState repository.listFolder(path).subscribeOn(Schedulers.io()) @@ -62,7 +88,7 @@ class RemoteFileBrowserItemsViewModel @Inject constructor( override fun onSubscribe(d: Disposable) = Unit override fun onNext(response: List) { - newRemoteFileBrowserItems = response + newRemoteFileBrowserItems = fileSortOrder.value!!.sortCloudFiles(response) } override fun onError(e: Throwable) { @@ -87,6 +113,18 @@ class RemoteFileBrowserItemsViewModel @Inject constructor( } } + private fun onSelectSortOrder(newSortOrderString: String) { + val newSortOrder = FileSortOrderNew.getFileSortOrder(newSortOrderString) + if (newSortOrder.name != fileSortOrder.value?.name) { + _fileSortOrder.value = newSortOrder + val currentState = viewState.value + if (currentState is LoadedState) { + val sortedItems = newSortOrder.sortCloudFiles(currentState.items) + _viewState.value = LoadedState(sortedItems) + } + } + } + companion object { private val TAG = RemoteFileBrowserItemsViewModel::class.simpleName } From 2fd97856d8bdf949f344deffdb973213e93e9913 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Brey?= Date: Mon, 6 Jun 2022 17:40:35 +0200 Subject: [PATCH 03/29] RemoteFileBrowser: fix file filtering and move it to viewmodel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Álvaro Brey --- .../activities/RemoteFileBrowserActivity.kt | 6 +----- .../viewmodels/RemoteFileBrowserItemsViewModel.kt | 5 ++++- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/activities/RemoteFileBrowserActivity.kt b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/activities/RemoteFileBrowserActivity.kt index 208065148..f6455bd10 100644 --- a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/activities/RemoteFileBrowserActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/activities/RemoteFileBrowserActivity.kt @@ -139,11 +139,7 @@ class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, Swipe onItemClicked(remoteFileBrowserItem) } .apply { - items = if (remoteFileBrowserItems.size > 1) { - remoteFileBrowserItems.subList(1, remoteFileBrowserItems.size) - } else { - ArrayList() - } + items = remoteFileBrowserItems } binding.recyclerView.adapter = adapter diff --git a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/viewmodels/RemoteFileBrowserItemsViewModel.kt b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/viewmodels/RemoteFileBrowserItemsViewModel.kt index 6fb244ed1..c0b6394a1 100644 --- a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/viewmodels/RemoteFileBrowserItemsViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/viewmodels/RemoteFileBrowserItemsViewModel.kt @@ -88,7 +88,8 @@ class RemoteFileBrowserItemsViewModel @Inject constructor( override fun onSubscribe(d: Disposable) = Unit override fun onNext(response: List) { - newRemoteFileBrowserItems = fileSortOrder.value!!.sortCloudFiles(response) + val itemsWithoutRoot = response.filterNot { it.mimeType == MIME_DIRECTORY && it.path == ROOT_PATH } + newRemoteFileBrowserItems = fileSortOrder.value!!.sortCloudFiles(itemsWithoutRoot) } override fun onError(e: Throwable) { @@ -127,5 +128,7 @@ class RemoteFileBrowserItemsViewModel @Inject constructor( companion object { private val TAG = RemoteFileBrowserItemsViewModel::class.simpleName + private const val ROOT_PATH = "/" + private const val MIME_DIRECTORY = "inode/directory" } } From ffdadc6c012a91e0de86b0b2033c2947715f7115 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Brey?= Date: Mon, 6 Jun 2022 17:40:57 +0200 Subject: [PATCH 04/29] RemoteFileBrowser: move currentPath to viewmodel, and fix title bar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Álvaro Brey --- .../activities/RemoteFileBrowserActivity.kt | 24 ++++++++----------- .../RemoteFileBrowserItemsViewModel.kt | 22 +++++++++++++++-- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/activities/RemoteFileBrowserActivity.kt b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/activities/RemoteFileBrowserActivity.kt index f6455bd10..547ede4f0 100644 --- a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/activities/RemoteFileBrowserActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/activities/RemoteFileBrowserActivity.kt @@ -67,7 +67,6 @@ class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, Swipe private var filesSelectionDoneMenuItem: MenuItem? = null private val selectedPaths: MutableSet = Collections.synchronizedSet(TreeSet()) - private var currentPath: String = "/" override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -88,7 +87,6 @@ class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, Swipe ResourcesCompat.getColor(resources, R.color.bg_default, null) ) - supportActionBar?.title = "current patch" supportActionBar?.setDisplayHomeAsUpEnabled(true) initViewModel() @@ -97,10 +95,10 @@ class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, Swipe binding.swipeRefreshList.setColorSchemeResources(R.color.colorPrimary) binding.swipeRefreshList.setProgressBackgroundColorSchemeResource(R.color.refresh_spinner_background) - binding.pathNavigationBackButton.setOnClickListener { goBack() } + binding.pathNavigationBackButton.setOnClickListener { viewModel.navigateUp() } binding.sortButton.setOnClickListener { changeSorting() } - viewModel.loadItems(currentPath) + viewModel.loadItems() } private fun initViewModel() { @@ -156,6 +154,12 @@ class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, Swipe binding.sortButton.setText(DisplayUtils.getSortOrderStringId(sortOrder)) } } + + viewModel.currentPath.observe(this) { path -> + if (path != null) { + supportActionBar?.title = path + } + } } override fun onCreateOptionsMenu(menu: Menu?): Boolean { @@ -168,8 +172,7 @@ class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, Swipe private fun onItemClicked(remoteFileBrowserItem: RemoteFileBrowserItem) { if ("inode/directory" == remoteFileBrowserItem.mimeType) { - currentPath = remoteFileBrowserItem.path!! - viewModel.loadItems(currentPath) + viewModel.changePath(remoteFileBrowserItem.path!!) } else { toggleBrowserItemSelection(remoteFileBrowserItem.path!!) } @@ -189,13 +192,6 @@ class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, Swipe ) } - private fun goBack(): Boolean { - if (currentPath != "/") { - viewModel.loadItems(File(currentPath).parent!!) - } - return true - } - override fun onOptionsItemSelected(item: MenuItem): Boolean { return when (item.itemId) { android.R.id.home -> { @@ -244,7 +240,7 @@ class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, Swipe } private fun refreshCurrentPath() { - viewModel.loadItems(currentPath) + viewModel.loadItems() } private fun shouldPathBeSelectedDueToParent(currentPath: String): Boolean { diff --git a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/viewmodels/RemoteFileBrowserItemsViewModel.kt b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/viewmodels/RemoteFileBrowserItemsViewModel.kt index c0b6394a1..d98cdefae 100644 --- a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/viewmodels/RemoteFileBrowserItemsViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/viewmodels/RemoteFileBrowserItemsViewModel.kt @@ -33,6 +33,7 @@ import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.Disposable import io.reactivex.schedulers.Schedulers import net.orange_box.storebox.listeners.OnPreferenceValueChangedListener +import java.io.File import javax.inject.Inject class RemoteFileBrowserItemsViewModel @Inject constructor( @@ -59,6 +60,10 @@ class RemoteFileBrowserItemsViewModel @Inject constructor( val fileSortOrder: LiveData get() = _fileSortOrder + private val _currentPath: MutableLiveData = MutableLiveData(ROOT_PATH) + val currentPath: LiveData + get() = _currentPath + init { appPreferences.registerSortingChangeListener(sortingPrefListener) } @@ -74,9 +79,9 @@ class RemoteFileBrowserItemsViewModel @Inject constructor( appPreferences.unregisterSortingChangeListener(sortingPrefListener) } - fun loadItems(path: String) { + fun loadItems() { _viewState.value = LoadingItemsState - repository.listFolder(path).subscribeOn(Schedulers.io()) + repository.listFolder(currentPath.value!!).subscribeOn(Schedulers.io()) ?.observeOn(AndroidSchedulers.mainThread()) ?.subscribe(RemoteFileBrowserItemsObserver()) } @@ -126,6 +131,19 @@ class RemoteFileBrowserItemsViewModel @Inject constructor( } } + fun changePath(path: String) { + _currentPath.value = path + loadItems() + } + + fun navigateUp() { + val path = _currentPath.value + if (path!! != ROOT_PATH) { + _currentPath.value = File(path).parent!! + loadItems() + } + } + companion object { private val TAG = RemoteFileBrowserItemsViewModel::class.simpleName private const val ROOT_PATH = "/" From eba697b8f2ef5022d1312a4f835c74835608c452 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Brey?= Date: Mon, 6 Jun 2022 18:38:45 +0200 Subject: [PATCH 05/29] RemoteFileBrowser: move selected paths from activity to viewmodel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Álvaro Brey --- .../activities/RemoteFileBrowserActivity.kt | 80 +++++-------------- .../RemoteFileBrowserItemsViewModel.kt | 77 ++++++++++++++++++ 2 files changed, 95 insertions(+), 62 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/activities/RemoteFileBrowserActivity.kt b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/activities/RemoteFileBrowserActivity.kt index 547ede4f0..d55dee823 100644 --- a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/activities/RemoteFileBrowserActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/activities/RemoteFileBrowserActivity.kt @@ -40,15 +40,11 @@ import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.databinding.ActivityRemoteFileBrowserBinding import com.nextcloud.talk.interfaces.SelectionInterface import com.nextcloud.talk.remotefilebrowser.adapters.RemoteFileBrowserItemsAdapter -import com.nextcloud.talk.remotefilebrowser.model.RemoteFileBrowserItem import com.nextcloud.talk.remotefilebrowser.viewmodels.RemoteFileBrowserItemsViewModel import com.nextcloud.talk.ui.dialog.SortingOrderDialogFragment import com.nextcloud.talk.utils.DisplayUtils import com.nextcloud.talk.utils.FileSortOrder import com.nextcloud.talk.utils.database.user.UserUtils -import java.io.File -import java.util.Collections -import java.util.TreeSet import javax.inject.Inject @AutoInjector(NextcloudTalkApplication::class) @@ -66,8 +62,6 @@ class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, Swipe private var filesSelectionDoneMenuItem: MenuItem? = null - private val selectedPaths: MutableSet = Collections.synchronizedSet(TreeSet()) - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this) @@ -132,13 +126,10 @@ class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, Swipe showGrid = showGrid, mimeTypeSelectionFilter = mimeTypeSelectionFilter, userEntity = userUtils.currentUser!!, - selectionInterface = this - ) { remoteFileBrowserItem -> - onItemClicked(remoteFileBrowserItem) - } - .apply { - items = remoteFileBrowserItems - } + selectionInterface = this, + onItemClicked = viewModel::onItemClicked + ) + adapter.items = remoteFileBrowserItems binding.recyclerView.adapter = adapter binding.recyclerView.layoutManager = layoutManager @@ -146,6 +137,9 @@ class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, Swipe showList() } + is RemoteFileBrowserItemsViewModel.FinishState -> { + finishWithResult(state.selectedPaths) + } } } @@ -160,24 +154,20 @@ class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, Swipe supportActionBar?.title = path } } + + viewModel.selectedPaths.observe(this) { selectedPaths -> + filesSelectionDoneMenuItem?.isVisible = !selectedPaths.isNullOrEmpty() + binding.recyclerView.adapter?.notifyDataSetChanged() + } } override fun onCreateOptionsMenu(menu: Menu?): Boolean { super.onCreateOptionsMenu(menu) menuInflater.inflate(R.menu.menu_share_files, menu) filesSelectionDoneMenuItem = menu?.findItem(R.id.files_selection_done) - filesSelectionDoneMenuItem?.isVisible = selectedPaths.size > 0 return true } - private fun onItemClicked(remoteFileBrowserItem: RemoteFileBrowserItem) { - if ("inode/directory" == remoteFileBrowserItem.mimeType) { - viewModel.changePath(remoteFileBrowserItem.path!!) - } else { - toggleBrowserItemSelection(remoteFileBrowserItem.path!!) - } - } - override fun onResume() { super.onResume() refreshCurrentPath() @@ -199,7 +189,7 @@ class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, Swipe true } R.id.files_selection_done -> { - onFileSelectionDone() + viewModel.onSelectionDone() true } else -> { @@ -208,7 +198,7 @@ class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, Swipe } } - private fun onFileSelectionDone() { + private fun finishWithResult(selectedPaths: Set) { val data = Intent() data.putStringArrayListExtra(EXTRA_SELECTED_PATHS, ArrayList(selectedPaths)) setResult(Activity.RESULT_OK, data) @@ -243,35 +233,6 @@ class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, Swipe viewModel.loadItems() } - private fun shouldPathBeSelectedDueToParent(currentPath: String): Boolean { - var file = File(currentPath) - if (selectedPaths.size > 0 && file.parent != "/") { - while (file.parent != null) { - var parent = file.parent!! - if (File(file.parent!!).parent != null) { - parent += "/" - } - if (selectedPaths.contains(parent)) { - return true - } - file = File(file.parent!!) - } - } - return false - } - - private fun checkAndRemoveAnySelectedParents(currentPath: String) { - var file = File(currentPath) - selectedPaths.remove(currentPath) - while (file.parent != null) { - selectedPaths.remove(file.parent!! + "/") - file = File(file.parent!!) - } - runOnUiThread { - binding.recyclerView.adapter!!.notifyDataSetChanged() - } - } - companion object { private val TAG = RemoteFileBrowserActivity::class.simpleName const val SPAN_COUNT: Int = 4 @@ -280,20 +241,15 @@ class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, Swipe } override fun toggleBrowserItemSelection(path: String) { - if (selectedPaths.contains(path) || shouldPathBeSelectedDueToParent(path)) { - checkAndRemoveAnySelectedParents(path) - } else { - // TODO if it's a folder, remove all the children we added manually - selectedPaths.add(path) - } - filesSelectionDoneMenuItem?.isVisible = selectedPaths.size > 0 + // unused, viewmodel gets called directly } override fun isPathSelected(path: String): Boolean { - return selectedPaths.contains(path) || shouldPathBeSelectedDueToParent(path) + // TODO figure out a better way to do this. Narrower interface? + return viewModel.isPathSelected(path) } override fun shouldOnlySelectOneImageFile(): Boolean { - return true + return true // unused } } diff --git a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/viewmodels/RemoteFileBrowserItemsViewModel.kt b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/viewmodels/RemoteFileBrowserItemsViewModel.kt index d98cdefae..8efa8770b 100644 --- a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/viewmodels/RemoteFileBrowserItemsViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/viewmodels/RemoteFileBrowserItemsViewModel.kt @@ -36,6 +36,19 @@ import net.orange_box.storebox.listeners.OnPreferenceValueChangedListener import java.io.File import javax.inject.Inject +/** + * @startuml + * hide empty description + * [*] --> InitialState + * InitialState --> LoadingItemsState + * LoadingItemsState --> NoRemoteFileItemsState + * NoRemoteFileItemsState --> LoadingItemsState + * LoadingItemsState --> LoadedState + * LoadedState --> LoadingItemsState + * LoadedState --> FinishState + * FinishState --> [*] + * @enduml + */ class RemoteFileBrowserItemsViewModel @Inject constructor( private val repository: RemoteFileBrowserItemsRepository, private val appPreferences: AppPreferences @@ -47,6 +60,7 @@ class RemoteFileBrowserItemsViewModel @Inject constructor( object NoRemoteFileItemsState : ViewState object LoadingItemsState : ViewState class LoadedState(val items: List) : ViewState + class FinishState(val selectedPaths: Set) : ViewState private val initialSortOrder = FileSortOrderNew.getFileSortOrder(appPreferences.sorting) private val sortingPrefListener: SortChangeListener = SortChangeListener() @@ -64,6 +78,10 @@ class RemoteFileBrowserItemsViewModel @Inject constructor( val currentPath: LiveData get() = _currentPath + private val _selectedPaths: MutableLiveData> = MutableLiveData(emptySet()) + val selectedPaths: LiveData> + get() = _selectedPaths + init { appPreferences.registerSortingChangeListener(sortingPrefListener) } @@ -144,6 +162,65 @@ class RemoteFileBrowserItemsViewModel @Inject constructor( } } + fun onSelectionDone() { + val selection = selectedPaths.value + if (!selection.isNullOrEmpty()) { + _viewState.value = FinishState(selection) + } + } + + fun onItemClicked(remoteFileBrowserItem: RemoteFileBrowserItem) { + if (remoteFileBrowserItem.mimeType == MIME_DIRECTORY) { + changePath(remoteFileBrowserItem.path!!) + } else { + toggleBrowserItemSelection(remoteFileBrowserItem.path!!) + } + } + + private fun toggleBrowserItemSelection(path: String) { + val paths = selectedPaths.value!!.toMutableSet() + if (paths.contains(path) || shouldPathBeSelectedDueToParent(path)) { + checkAndRemoveAnySelectedParents(path) + } else { + // TODO if it's a folder, remove all the children we added manually + paths.add(path) + _selectedPaths.value = paths + } + } + + private fun checkAndRemoveAnySelectedParents(currentPath: String) { + var file = File(currentPath) + val paths = selectedPaths.value!!.toMutableSet() + paths.remove(currentPath) + while (file.parent != null) { + paths.remove(file.parent!! + File.pathSeparator) + file = File(file.parent!!) + } + _selectedPaths.value = paths + } + + private fun shouldPathBeSelectedDueToParent(currentPath: String): Boolean { + var file = File(currentPath) + val paths = selectedPaths.value!! + if (paths.isNotEmpty() && file.parent != ROOT_PATH) { + while (file.parent != null) { + var parent = file.parent!! + if (File(file.parent!!).parent != null) { + parent += File.pathSeparator + } + if (paths.contains(parent)) { + return true + } + file = File(file.parent!!) + } + } + return false + } + + fun isPathSelected(path: String): Boolean { + return selectedPaths.value?.contains(path) == true || shouldPathBeSelectedDueToParent(path) + } + companion object { private val TAG = RemoteFileBrowserItemsViewModel::class.simpleName private const val ROOT_PATH = "/" From 9da5b57804fa4e783a43168c5d063a13c1fb01fd Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Tue, 7 Jun 2022 10:34:17 +0200 Subject: [PATCH 06/29] remove self path from dav result Signed-off-by: Andy Scherzinger --- .../filebrowser/webdav/ReadFilesystemOperation.kt | 9 --------- 1 file changed, 9 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/components/filebrowser/webdav/ReadFilesystemOperation.kt b/app/src/main/java/com/nextcloud/talk/components/filebrowser/webdav/ReadFilesystemOperation.kt index b0d86c0ea..acc1a30ce 100644 --- a/app/src/main/java/com/nextcloud/talk/components/filebrowser/webdav/ReadFilesystemOperation.kt +++ b/app/src/main/java/com/nextcloud/talk/components/filebrowser/webdav/ReadFilesystemOperation.kt @@ -81,15 +81,6 @@ class ReadFilesystemOperation(okHttpClient: OkHttpClient, currentUser: UserEntit } catch (e: DavException) { Log.w(TAG, "Error reading remote path") } - remoteFiles.add( - getModelFromResponse( - rootElement[0]!!, - rootElement[0]!! - .href - .toString() - .substring(basePath.length) - ) - ) for (memberElement in memberElements) { remoteFiles.add( getModelFromResponse( From 57ef995543e93f72084892112e4a11dab171a86a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Brey?= Date: Tue, 7 Jun 2022 12:07:38 +0200 Subject: [PATCH 07/29] RemoteFileBrowser viewmodel: don't filter out root dir MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The relevant operation no longer returns the current path Signed-off-by: Álvaro Brey --- .../viewmodels/RemoteFileBrowserItemsViewModel.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/viewmodels/RemoteFileBrowserItemsViewModel.kt b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/viewmodels/RemoteFileBrowserItemsViewModel.kt index 8efa8770b..fed164345 100644 --- a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/viewmodels/RemoteFileBrowserItemsViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/viewmodels/RemoteFileBrowserItemsViewModel.kt @@ -111,8 +111,7 @@ class RemoteFileBrowserItemsViewModel @Inject constructor( override fun onSubscribe(d: Disposable) = Unit override fun onNext(response: List) { - val itemsWithoutRoot = response.filterNot { it.mimeType == MIME_DIRECTORY && it.path == ROOT_PATH } - newRemoteFileBrowserItems = fileSortOrder.value!!.sortCloudFiles(itemsWithoutRoot) + newRemoteFileBrowserItems = fileSortOrder.value!!.sortCloudFiles(response) } override fun onError(e: Throwable) { From c71d1da334149c8f21298aeb0ecd676487cecd24 Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Tue, 7 Jun 2022 12:10:15 +0200 Subject: [PATCH 08/29] mark deprecated and rename legacy sort implementation Signed-off-by: Andy Scherzinger --- .../controllers/BrowserController.kt | 10 +++--- .../activities/RemoteFileBrowserActivity.kt | 4 +-- .../ui/dialog/SortingOrderDialogFragment.java | 36 +++++++++---------- .../nextcloud/talk/utils/DisplayUtils.java | 14 ++++---- ...ortOrder.java => LegacyFileSortOrder.java} | 24 ++++++------- ...te.java => LegacyFileSortOrderByDate.java} | 5 +-- ...me.java => LegacyFileSortOrderByName.java} | 5 +-- ...ze.java => LegacyFileSortOrderBySize.java} | 5 +-- .../utils/preferences/AppPreferences.java | 1 - 9 files changed, 53 insertions(+), 51 deletions(-) rename app/src/main/java/com/nextcloud/talk/utils/{FileSortOrder.java => LegacyFileSortOrder.java} (74%) rename app/src/main/java/com/nextcloud/talk/utils/{FileSortOrderByDate.java => LegacyFileSortOrderByDate.java} (91%) rename app/src/main/java/com/nextcloud/talk/utils/{FileSortOrderByName.java => LegacyFileSortOrderByName.java} (92%) rename app/src/main/java/com/nextcloud/talk/utils/{FileSortOrderBySize.java => LegacyFileSortOrderBySize.java} (92%) diff --git a/app/src/main/java/com/nextcloud/talk/components/filebrowser/controllers/BrowserController.kt b/app/src/main/java/com/nextcloud/talk/components/filebrowser/controllers/BrowserController.kt index c32c534fe..d7fcc0ba1 100644 --- a/app/src/main/java/com/nextcloud/talk/components/filebrowser/controllers/BrowserController.kt +++ b/app/src/main/java/com/nextcloud/talk/components/filebrowser/controllers/BrowserController.kt @@ -50,7 +50,7 @@ import com.nextcloud.talk.interfaces.SelectionInterface import com.nextcloud.talk.models.database.UserEntity import com.nextcloud.talk.ui.dialog.SortingOrderDialogFragment import com.nextcloud.talk.utils.DisplayUtils -import com.nextcloud.talk.utils.FileSortOrder +import com.nextcloud.talk.utils.LegacyFileSortOrder import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_BROWSER_TYPE import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_USER_ENTITY import com.nextcloud.talk.utils.database.user.UserUtils @@ -142,7 +142,7 @@ abstract class BrowserController(args: Bundle) : binding.sortButton.setOnClickListener { changeSorting() } binding.sortButton.setText( - DisplayUtils.getSortOrderStringId(FileSortOrder.getFileSortOrder(appPreferences?.sorting)) + DisplayUtils.getSortOrderStringId(LegacyFileSortOrder.getFileSortOrder(appPreferences?.sorting)) ) refreshCurrentPath() @@ -154,7 +154,7 @@ abstract class BrowserController(args: Bundle) : fun changeSorting() { val newFragment: DialogFragment = SortingOrderDialogFragment - .newInstance(FileSortOrder.getFileSortOrder(appPreferences?.sorting)) + .newInstance(LegacyFileSortOrder.getFileSortOrder(appPreferences?.sorting)) newFragment.show( (activity as MainActivity?)!!.supportFragmentManager, SortingOrderDialogFragment.SORTING_ORDER_FRAGMENT @@ -208,7 +208,7 @@ abstract class BrowserController(args: Bundle) : } } - FileSortOrder.getFileSortOrder(appPreferences?.sorting).sortCloudFiles(recyclerViewItems) + LegacyFileSortOrder.getFileSortOrder(appPreferences?.sorting).sortCloudFiles(recyclerViewItems) if (activity != null) { activity!!.runOnUiThread { @@ -319,7 +319,7 @@ abstract class BrowserController(args: Bundle) : OnPreferenceValueChangedListener { override fun onChanged(newValue: String) { try { - val sortOrder = FileSortOrder.getFileSortOrder(newValue) + val sortOrder = LegacyFileSortOrder.getFileSortOrder(newValue) browserController.binding.sortButton.setText(DisplayUtils.getSortOrderStringId(sortOrder)) browserController.recyclerViewItems = sortOrder.sortCloudFiles(browserController.recyclerViewItems) diff --git a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/activities/RemoteFileBrowserActivity.kt b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/activities/RemoteFileBrowserActivity.kt index d55dee823..ee5de9120 100644 --- a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/activities/RemoteFileBrowserActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/activities/RemoteFileBrowserActivity.kt @@ -43,7 +43,7 @@ import com.nextcloud.talk.remotefilebrowser.adapters.RemoteFileBrowserItemsAdapt import com.nextcloud.talk.remotefilebrowser.viewmodels.RemoteFileBrowserItemsViewModel import com.nextcloud.talk.ui.dialog.SortingOrderDialogFragment import com.nextcloud.talk.utils.DisplayUtils -import com.nextcloud.talk.utils.FileSortOrder +import com.nextcloud.talk.utils.LegacyFileSortOrder import com.nextcloud.talk.utils.database.user.UserUtils import javax.inject.Inject @@ -175,7 +175,7 @@ class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, Swipe private fun changeSorting() { val newFragment: DialogFragment = SortingOrderDialogFragment - .newInstance(FileSortOrder.getFileSortOrder(viewModel.fileSortOrder.value!!.name)) + .newInstance(LegacyFileSortOrder.getFileSortOrder(viewModel.fileSortOrder.value!!.name)) newFragment.show( supportFragmentManager, SortingOrderDialogFragment.SORTING_ORDER_FRAGMENT diff --git a/app/src/main/java/com/nextcloud/talk/ui/dialog/SortingOrderDialogFragment.java b/app/src/main/java/com/nextcloud/talk/ui/dialog/SortingOrderDialogFragment.java index 715abb9a6..f69360a9b 100644 --- a/app/src/main/java/com/nextcloud/talk/ui/dialog/SortingOrderDialogFragment.java +++ b/app/src/main/java/com/nextcloud/talk/ui/dialog/SortingOrderDialogFragment.java @@ -36,7 +36,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.nextcloud.talk.R; import com.nextcloud.talk.application.NextcloudTalkApplication; import com.nextcloud.talk.databinding.SortingOrderFragmentBinding; -import com.nextcloud.talk.utils.FileSortOrder; +import com.nextcloud.talk.utils.LegacyFileSortOrder; import com.nextcloud.talk.utils.preferences.AppPreferences; import javax.inject.Inject; @@ -67,7 +67,7 @@ public class SortingOrderDialogFragment extends DialogFragment implements View.O private View[] taggedViews; private String currentSortOrderName; - public static SortingOrderDialogFragment newInstance(FileSortOrder sortOrder) { + public static SortingOrderDialogFragment newInstance(LegacyFileSortOrder sortOrder) { SortingOrderDialogFragment dialogFragment = new SortingOrderDialogFragment(); Bundle args = new Bundle(); @@ -84,7 +84,7 @@ public class SortingOrderDialogFragment extends DialogFragment implements View.O setRetainInstance(true); if (getArguments() != null) { - currentSortOrderName = getArguments().getString(KEY_SORT_ORDER, FileSortOrder.sort_a_to_z.name); + currentSortOrderName = getArguments().getString(KEY_SORT_ORDER, LegacyFileSortOrder.sort_a_to_z.name); } } @@ -120,29 +120,29 @@ public class SortingOrderDialogFragment extends DialogFragment implements View.O taggedViews = new View[12]; taggedViews[0] = binding.sortByNameAscending; - taggedViews[0].setTag(FileSortOrder.sort_a_to_z); + taggedViews[0].setTag(LegacyFileSortOrder.sort_a_to_z); taggedViews[1] = binding.sortByNameAZText; - taggedViews[1].setTag(FileSortOrder.sort_a_to_z); + taggedViews[1].setTag(LegacyFileSortOrder.sort_a_to_z); taggedViews[2] = binding.sortByNameDescending; - taggedViews[2].setTag(FileSortOrder.sort_z_to_a); + taggedViews[2].setTag(LegacyFileSortOrder.sort_z_to_a); taggedViews[3] = binding.sortByNameZAText; - taggedViews[3].setTag(FileSortOrder.sort_z_to_a); + taggedViews[3].setTag(LegacyFileSortOrder.sort_z_to_a); taggedViews[4] = binding.sortByModificationDateAscending; - taggedViews[4].setTag(FileSortOrder.sort_old_to_new); + taggedViews[4].setTag(LegacyFileSortOrder.sort_old_to_new); taggedViews[5] = binding.sortByModificationDateOldestFirstText; - taggedViews[5].setTag(FileSortOrder.sort_old_to_new); + taggedViews[5].setTag(LegacyFileSortOrder.sort_old_to_new); taggedViews[6] = binding.sortByModificationDateDescending; - taggedViews[6].setTag(FileSortOrder.sort_new_to_old); + taggedViews[6].setTag(LegacyFileSortOrder.sort_new_to_old); taggedViews[7] = binding.sortByModificationDateNewestFirstText; - taggedViews[7].setTag(FileSortOrder.sort_new_to_old); + taggedViews[7].setTag(LegacyFileSortOrder.sort_new_to_old); taggedViews[8] = binding.sortBySizeAscending; - taggedViews[8].setTag(FileSortOrder.sort_small_to_big); + taggedViews[8].setTag(LegacyFileSortOrder.sort_small_to_big); taggedViews[9] = binding.sortBySizeSmallestFirstText; - taggedViews[9].setTag(FileSortOrder.sort_small_to_big); + taggedViews[9].setTag(LegacyFileSortOrder.sort_small_to_big); taggedViews[10] = binding.sortBySizeDescending; - taggedViews[10].setTag(FileSortOrder.sort_big_to_small); + taggedViews[10].setTag(LegacyFileSortOrder.sort_big_to_small); taggedViews[11] = binding.sortBySizeBiggestFirstText; - taggedViews[11].setTag(FileSortOrder.sort_big_to_small); + taggedViews[11].setTag(LegacyFileSortOrder.sort_big_to_small); setupActiveOrderSelection(); } @@ -154,8 +154,8 @@ public class SortingOrderDialogFragment extends DialogFragment implements View.O final int color = getResources().getColor(R.color.colorPrimary); Log.i("SortOrder", "currentSortOrderName="+currentSortOrderName); for (View view : taggedViews) { - Log.i("SortOrder", ((FileSortOrder) view.getTag()).name); - if (!((FileSortOrder) view.getTag()).name.equals(currentSortOrderName)) { + Log.i("SortOrder", ((LegacyFileSortOrder) view.getTag()).name); + if (!((LegacyFileSortOrder) view.getTag()).name.equals(currentSortOrderName)) { continue; } if (view instanceof MaterialButton) { @@ -192,7 +192,7 @@ public class SortingOrderDialogFragment extends DialogFragment implements View.O @Override public void onClick(View v) { - appPreferences.setSorting(((FileSortOrder) v.getTag()).name); + appPreferences.setSorting(((LegacyFileSortOrder) v.getTag()).name); dismiss(); } } diff --git a/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.java b/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.java index de2f682ee..cc165b6f5 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.java +++ b/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.java @@ -110,12 +110,12 @@ import androidx.core.graphics.ColorUtils; import androidx.core.graphics.drawable.DrawableCompat; import androidx.emoji.text.EmojiCompat; -import static com.nextcloud.talk.utils.FileSortOrder.sort_a_to_z_id; -import static com.nextcloud.talk.utils.FileSortOrder.sort_big_to_small_id; -import static com.nextcloud.talk.utils.FileSortOrder.sort_new_to_old_id; -import static com.nextcloud.talk.utils.FileSortOrder.sort_old_to_new_id; -import static com.nextcloud.talk.utils.FileSortOrder.sort_small_to_big_id; -import static com.nextcloud.talk.utils.FileSortOrder.sort_z_to_a_id; +import static com.nextcloud.talk.utils.LegacyFileSortOrder.sort_a_to_z_id; +import static com.nextcloud.talk.utils.LegacyFileSortOrder.sort_big_to_small_id; +import static com.nextcloud.talk.utils.LegacyFileSortOrder.sort_new_to_old_id; +import static com.nextcloud.talk.utils.LegacyFileSortOrder.sort_old_to_new_id; +import static com.nextcloud.talk.utils.LegacyFileSortOrder.sort_small_to_big_id; +import static com.nextcloud.talk.utils.LegacyFileSortOrder.sort_z_to_a_id; public class DisplayUtils { @@ -618,7 +618,7 @@ public class DisplayUtils { } public static @StringRes - int getSortOrderStringId(FileSortOrder sortOrder) { + int getSortOrderStringId(LegacyFileSortOrder sortOrder) { switch (sortOrder.name) { case sort_z_to_a_id: return R.string.menu_item_sort_by_name_z_a; diff --git a/app/src/main/java/com/nextcloud/talk/utils/FileSortOrder.java b/app/src/main/java/com/nextcloud/talk/utils/LegacyFileSortOrder.java similarity index 74% rename from app/src/main/java/com/nextcloud/talk/utils/FileSortOrder.java rename to app/src/main/java/com/nextcloud/talk/utils/LegacyFileSortOrder.java index ec88d0e4a..ada429d78 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/FileSortOrder.java +++ b/app/src/main/java/com/nextcloud/talk/utils/LegacyFileSortOrder.java @@ -26,7 +26,6 @@ import android.text.TextUtils; import com.nextcloud.talk.components.filebrowser.adapters.items.BrowserFileItem; -import java.io.File; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -37,7 +36,8 @@ import androidx.annotation.Nullable; /** * Sort order */ -public class FileSortOrder { +@Deprecated +public class LegacyFileSortOrder { public static final String sort_a_to_z_id = "sort_a_to_z"; public static final String sort_z_to_a_id = "sort_z_to_a"; public static final String sort_old_to_new_id = "sort_old_to_new"; @@ -45,17 +45,17 @@ public class FileSortOrder { public static final String sort_small_to_big_id = "sort_small_to_big"; public static final String sort_big_to_small_id = "sort_big_to_small"; - public static final FileSortOrder sort_a_to_z = new FileSortOrderByName(sort_a_to_z_id, true); - public static final FileSortOrder sort_z_to_a = new FileSortOrderByName(sort_z_to_a_id, false); - public static final FileSortOrder sort_old_to_new = new FileSortOrderByDate(sort_old_to_new_id, true); - public static final FileSortOrder sort_new_to_old = new FileSortOrderByDate(sort_new_to_old_id, false); - public static final FileSortOrder sort_small_to_big = new FileSortOrderBySize(sort_small_to_big_id, true); - public static final FileSortOrder sort_big_to_small = new FileSortOrderBySize(sort_big_to_small_id, false); + public static final LegacyFileSortOrder sort_a_to_z = new LegacyFileSortOrderByName(sort_a_to_z_id, true); + public static final LegacyFileSortOrder sort_z_to_a = new LegacyFileSortOrderByName(sort_z_to_a_id, false); + public static final LegacyFileSortOrder sort_old_to_new = new LegacyFileSortOrderByDate(sort_old_to_new_id, true); + public static final LegacyFileSortOrder sort_new_to_old = new LegacyFileSortOrderByDate(sort_new_to_old_id, false); + public static final LegacyFileSortOrder sort_small_to_big = new LegacyFileSortOrderBySize(sort_small_to_big_id, true); + public static final LegacyFileSortOrder sort_big_to_small = new LegacyFileSortOrderBySize(sort_big_to_small_id, false); - public static final Map sortOrders; + public static final Map sortOrders; static { - HashMap temp = new HashMap<>(); + HashMap temp = new HashMap<>(); temp.put(sort_a_to_z.name, sort_a_to_z); temp.put(sort_z_to_a.name, sort_z_to_a); temp.put(sort_old_to_new.name, sort_old_to_new); @@ -69,12 +69,12 @@ public class FileSortOrder { public String name; public boolean isAscending; - public FileSortOrder(String name, boolean ascending) { + public LegacyFileSortOrder(String name, boolean ascending) { this.name = name; isAscending = ascending; } - public static FileSortOrder getFileSortOrder(@Nullable String key) { + public static LegacyFileSortOrder getFileSortOrder(@Nullable String key) { if (TextUtils.isEmpty(key) || !sortOrders.containsKey(key)) { return sort_a_to_z; } else { diff --git a/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByDate.java b/app/src/main/java/com/nextcloud/talk/utils/LegacyFileSortOrderByDate.java similarity index 91% rename from app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByDate.java rename to app/src/main/java/com/nextcloud/talk/utils/LegacyFileSortOrderByDate.java index 2d24e88b0..774d27d59 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByDate.java +++ b/app/src/main/java/com/nextcloud/talk/utils/LegacyFileSortOrderByDate.java @@ -30,9 +30,10 @@ import java.util.List; /** * Created by srkunze on 28.08.17. */ -public class FileSortOrderByDate extends FileSortOrder { +@Deprecated +public class LegacyFileSortOrderByDate extends LegacyFileSortOrder { - FileSortOrderByDate(String name, boolean ascending) { + LegacyFileSortOrderByDate(String name, boolean ascending) { super(name, ascending); } diff --git a/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByName.java b/app/src/main/java/com/nextcloud/talk/utils/LegacyFileSortOrderByName.java similarity index 92% rename from app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByName.java rename to app/src/main/java/com/nextcloud/talk/utils/LegacyFileSortOrderByName.java index c5035fd60..d3b7befe7 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByName.java +++ b/app/src/main/java/com/nextcloud/talk/utils/LegacyFileSortOrderByName.java @@ -32,9 +32,10 @@ import third_parties.daveKoeller.AlphanumComparator; /** * Created by srkunze on 28.08.17. */ -public class FileSortOrderByName extends FileSortOrder { +@Deprecated +public class LegacyFileSortOrderByName extends LegacyFileSortOrder { - FileSortOrderByName(String name, boolean ascending) { + LegacyFileSortOrderByName(String name, boolean ascending) { super(name, ascending); } diff --git a/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderBySize.java b/app/src/main/java/com/nextcloud/talk/utils/LegacyFileSortOrderBySize.java similarity index 92% rename from app/src/main/java/com/nextcloud/talk/utils/FileSortOrderBySize.java rename to app/src/main/java/com/nextcloud/talk/utils/LegacyFileSortOrderBySize.java index 4eab78668..80829c751 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderBySize.java +++ b/app/src/main/java/com/nextcloud/talk/utils/LegacyFileSortOrderBySize.java @@ -30,9 +30,10 @@ import java.util.List; /** * Sorts files by sizes */ -public class FileSortOrderBySize extends FileSortOrder { +@Deprecated +public class LegacyFileSortOrderBySize extends LegacyFileSortOrder { - FileSortOrderBySize(String name, boolean ascending) { + LegacyFileSortOrderBySize(String name, boolean ascending) { super(name, ascending); } diff --git a/app/src/main/java/com/nextcloud/talk/utils/preferences/AppPreferences.java b/app/src/main/java/com/nextcloud/talk/utils/preferences/AppPreferences.java index 6ff15688c..fd141a4d1 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/preferences/AppPreferences.java +++ b/app/src/main/java/com/nextcloud/talk/utils/preferences/AppPreferences.java @@ -25,7 +25,6 @@ package com.nextcloud.talk.utils.preferences; import com.nextcloud.talk.R; -import com.nextcloud.talk.utils.FileSortOrder; import net.orange_box.storebox.annotations.method.ClearMethod; import net.orange_box.storebox.annotations.method.DefaultValue; From c5c52f2f6e4badc85c5f4056e4b679c454a51727 Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Tue, 7 Jun 2022 12:11:27 +0200 Subject: [PATCH 09/29] remove "New" suffix from classes Signed-off-by: Andy Scherzinger --- .../RemoteFileBrowserItemsViewModel.kt | 10 ++++---- .../nextcloud/talk/utils/DisplayUtils.java | 2 +- ...leSortOrderNew.java => FileSortOrder.java} | 23 +++++++++---------- ...yDateNew.java => FileSortOrderByDate.java} | 4 ++-- ...yNameNew.java => FileSortOrderByName.java} | 4 ++-- ...ySizeNew.java => FileSortOrderBySize.java} | 4 ++-- 6 files changed, 23 insertions(+), 24 deletions(-) rename app/src/main/java/com/nextcloud/talk/utils/{FileSortOrderNew.java => FileSortOrder.java} (73%) rename app/src/main/java/com/nextcloud/talk/utils/{FileSortOrderByDateNew.java => FileSortOrderByDate.java} (92%) rename app/src/main/java/com/nextcloud/talk/utils/{FileSortOrderByNameNew.java => FileSortOrderByName.java} (93%) rename app/src/main/java/com/nextcloud/talk/utils/{FileSortOrderBySizeNew.java => FileSortOrderBySize.java} (93%) diff --git a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/viewmodels/RemoteFileBrowserItemsViewModel.kt b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/viewmodels/RemoteFileBrowserItemsViewModel.kt index fed164345..2b961fff3 100644 --- a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/viewmodels/RemoteFileBrowserItemsViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/viewmodels/RemoteFileBrowserItemsViewModel.kt @@ -26,7 +26,7 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import com.nextcloud.talk.remotefilebrowser.model.RemoteFileBrowserItem import com.nextcloud.talk.remotefilebrowser.repositories.RemoteFileBrowserItemsRepository -import com.nextcloud.talk.utils.FileSortOrderNew +import com.nextcloud.talk.utils.FileSortOrder import com.nextcloud.talk.utils.preferences.AppPreferences import io.reactivex.Observer import io.reactivex.android.schedulers.AndroidSchedulers @@ -62,7 +62,7 @@ class RemoteFileBrowserItemsViewModel @Inject constructor( class LoadedState(val items: List) : ViewState class FinishState(val selectedPaths: Set) : ViewState - private val initialSortOrder = FileSortOrderNew.getFileSortOrder(appPreferences.sorting) + private val initialSortOrder = FileSortOrder.getFileSortOrder(appPreferences.sorting) private val sortingPrefListener: SortChangeListener = SortChangeListener() private val _viewState: MutableLiveData = MutableLiveData(InitialState) @@ -70,8 +70,8 @@ class RemoteFileBrowserItemsViewModel @Inject constructor( get() = _viewState // TODO incorporate into view state object? - private val _fileSortOrder: MutableLiveData = MutableLiveData(initialSortOrder) - val fileSortOrder: LiveData + private val _fileSortOrder: MutableLiveData = MutableLiveData(initialSortOrder) + val fileSortOrder: LiveData get() = _fileSortOrder private val _currentPath: MutableLiveData = MutableLiveData(ROOT_PATH) @@ -137,7 +137,7 @@ class RemoteFileBrowserItemsViewModel @Inject constructor( } private fun onSelectSortOrder(newSortOrderString: String) { - val newSortOrder = FileSortOrderNew.getFileSortOrder(newSortOrderString) + val newSortOrder = FileSortOrder.getFileSortOrder(newSortOrderString) if (newSortOrder.name != fileSortOrder.value?.name) { _fileSortOrder.value = newSortOrder val currentState = viewState.value diff --git a/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.java b/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.java index cc165b6f5..8da1b07d7 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.java +++ b/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.java @@ -637,7 +637,7 @@ public class DisplayUtils { } public static @StringRes - int getSortOrderStringId(FileSortOrderNew sortOrder) { + int getSortOrderStringId(FileSortOrder sortOrder) { switch (sortOrder.name) { case sort_z_to_a_id: return R.string.menu_item_sort_by_name_z_a; diff --git a/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderNew.java b/app/src/main/java/com/nextcloud/talk/utils/FileSortOrder.java similarity index 73% rename from app/src/main/java/com/nextcloud/talk/utils/FileSortOrderNew.java rename to app/src/main/java/com/nextcloud/talk/utils/FileSortOrder.java index 876fa581b..53b443693 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderNew.java +++ b/app/src/main/java/com/nextcloud/talk/utils/FileSortOrder.java @@ -24,7 +24,6 @@ package com.nextcloud.talk.utils; import android.text.TextUtils; -import com.nextcloud.talk.components.filebrowser.adapters.items.BrowserFileItem; import com.nextcloud.talk.remotefilebrowser.model.RemoteFileBrowserItem; import java.util.Collections; @@ -37,7 +36,7 @@ import androidx.annotation.Nullable; /** * Sort order */ -public class FileSortOrderNew { +public class FileSortOrder { public static final String sort_a_to_z_id = "sort_a_to_z"; public static final String sort_z_to_a_id = "sort_z_to_a"; public static final String sort_old_to_new_id = "sort_old_to_new"; @@ -45,17 +44,17 @@ public class FileSortOrderNew { public static final String sort_small_to_big_id = "sort_small_to_big"; public static final String sort_big_to_small_id = "sort_big_to_small"; - public static final FileSortOrderNew sort_a_to_z = new FileSortOrderByNameNew(sort_a_to_z_id, true); - public static final FileSortOrderNew sort_z_to_a = new FileSortOrderByNameNew(sort_z_to_a_id, false); - public static final FileSortOrderNew sort_old_to_new = new FileSortOrderByDateNew(sort_old_to_new_id, true); - public static final FileSortOrderNew sort_new_to_old = new FileSortOrderByDateNew(sort_new_to_old_id, false); - public static final FileSortOrderNew sort_small_to_big = new FileSortOrderBySizeNew(sort_small_to_big_id, true); - public static final FileSortOrderNew sort_big_to_small = new FileSortOrderBySizeNew(sort_big_to_small_id, false); + public static final FileSortOrder sort_a_to_z = new FileSortOrderByName(sort_a_to_z_id, true); + public static final FileSortOrder sort_z_to_a = new FileSortOrderByName(sort_z_to_a_id, false); + public static final FileSortOrder sort_old_to_new = new FileSortOrderByDate(sort_old_to_new_id, true); + public static final FileSortOrder sort_new_to_old = new FileSortOrderByDate(sort_new_to_old_id, false); + public static final FileSortOrder sort_small_to_big = new FileSortOrderBySize(sort_small_to_big_id, true); + public static final FileSortOrder sort_big_to_small = new FileSortOrderBySize(sort_big_to_small_id, false); - public static final Map sortOrders; + public static final Map sortOrders; static { - HashMap temp = new HashMap<>(); + HashMap temp = new HashMap<>(); temp.put(sort_a_to_z.name, sort_a_to_z); temp.put(sort_z_to_a.name, sort_z_to_a); temp.put(sort_old_to_new.name, sort_old_to_new); @@ -69,12 +68,12 @@ public class FileSortOrderNew { public String name; public boolean isAscending; - public FileSortOrderNew(String name, boolean ascending) { + public FileSortOrder(String name, boolean ascending) { this.name = name; isAscending = ascending; } - public static FileSortOrderNew getFileSortOrder(@Nullable String key) { + public static FileSortOrder getFileSortOrder(@Nullable String key) { if (TextUtils.isEmpty(key) || !sortOrders.containsKey(key)) { return sort_a_to_z; } else { diff --git a/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByDateNew.java b/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByDate.java similarity index 92% rename from app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByDateNew.java rename to app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByDate.java index bcd2444e1..48f661019 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByDateNew.java +++ b/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByDate.java @@ -30,9 +30,9 @@ import java.util.List; /** * Created by srkunze on 28.08.17. */ -public class FileSortOrderByDateNew extends FileSortOrderNew { +public class FileSortOrderByDate extends FileSortOrder { - FileSortOrderByDateNew(String name, boolean ascending) { + FileSortOrderByDate(String name, boolean ascending) { super(name, ascending); } diff --git a/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByNameNew.java b/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByName.java similarity index 93% rename from app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByNameNew.java rename to app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByName.java index 7d36e6ef4..a2cfdbf4c 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByNameNew.java +++ b/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByName.java @@ -32,9 +32,9 @@ import third_parties.daveKoeller.AlphanumComparator; /** * Created by srkunze on 28.08.17. */ -public class FileSortOrderByNameNew extends FileSortOrderNew { +public class FileSortOrderByName extends FileSortOrder { - FileSortOrderByNameNew(String name, boolean ascending) { + FileSortOrderByName(String name, boolean ascending) { super(name, ascending); } diff --git a/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderBySizeNew.java b/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderBySize.java similarity index 93% rename from app/src/main/java/com/nextcloud/talk/utils/FileSortOrderBySizeNew.java rename to app/src/main/java/com/nextcloud/talk/utils/FileSortOrderBySize.java index fc071c058..8ecbdd2b9 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderBySizeNew.java +++ b/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderBySize.java @@ -30,9 +30,9 @@ import java.util.List; /** * Sorts files by sizes */ -public class FileSortOrderBySizeNew extends FileSortOrderNew { +public class FileSortOrderBySize extends FileSortOrder { - FileSortOrderBySizeNew(String name, boolean ascending) { + FileSortOrderBySize(String name, boolean ascending) { super(name, ascending); } From 670b4c02951599c3549607b96ab470a7d9668deb Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Tue, 7 Jun 2022 12:13:03 +0200 Subject: [PATCH 10/29] bump lint score Signed-off-by: Andy Scherzinger --- scripts/analysis/lint-results.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/analysis/lint-results.txt b/scripts/analysis/lint-results.txt index 9ab1d14f7..35212832b 100644 --- a/scripts/analysis/lint-results.txt +++ b/scripts/analysis/lint-results.txt @@ -1,2 +1,2 @@ DO NOT TOUCH; GENERATED BY DRONE - Lint Report: 2 errors and 123 warnings + Lint Report: 2 errors and 124 warnings From f2119770bc804d6c395986b646062dae17f0cffb Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Tue, 7 Jun 2022 18:15:17 +0200 Subject: [PATCH 11/29] migrate sorter classes to kotlin Signed-off-by: Andy Scherzinger --- .../nextcloud/talk/utils/DisplayUtils.java | 3 +- .../nextcloud/talk/utils/FileSortOrder.java | 107 ------------------ .../com/nextcloud/talk/utils/FileSortOrder.kt | 98 ++++++++++++++++ ...rderByDate.java => FileSortOrderByDate.kt} | 34 +++--- .../talk/utils/FileSortOrderByName.java | 63 ----------- .../talk/utils/FileSortOrderByName.kt | 59 ++++++++++ .../talk/utils/FileSortOrderBySize.java | 61 ---------- .../talk/utils/FileSortOrderBySize.kt | 58 ++++++++++ 8 files changed, 233 insertions(+), 250 deletions(-) delete mode 100644 app/src/main/java/com/nextcloud/talk/utils/FileSortOrder.java create mode 100644 app/src/main/java/com/nextcloud/talk/utils/FileSortOrder.kt rename app/src/main/java/com/nextcloud/talk/utils/{FileSortOrderByDate.java => FileSortOrderByDate.kt} (53%) delete mode 100644 app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByName.java create mode 100644 app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByName.kt delete mode 100644 app/src/main/java/com/nextcloud/talk/utils/FileSortOrderBySize.java create mode 100644 app/src/main/java/com/nextcloud/talk/utils/FileSortOrderBySize.kt diff --git a/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.java b/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.java index 8da1b07d7..c5baf6ffd 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.java +++ b/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.java @@ -617,6 +617,7 @@ public class DisplayUtils { targetView.setController(newController); } + @Deprecated public static @StringRes int getSortOrderStringId(LegacyFileSortOrder sortOrder) { switch (sortOrder.name) { @@ -638,7 +639,7 @@ public class DisplayUtils { public static @StringRes int getSortOrderStringId(FileSortOrder sortOrder) { - switch (sortOrder.name) { + switch (sortOrder.getName()) { case sort_z_to_a_id: return R.string.menu_item_sort_by_name_z_a; case sort_new_to_old_id: diff --git a/app/src/main/java/com/nextcloud/talk/utils/FileSortOrder.java b/app/src/main/java/com/nextcloud/talk/utils/FileSortOrder.java deleted file mode 100644 index 53b443693..000000000 --- a/app/src/main/java/com/nextcloud/talk/utils/FileSortOrder.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Nextcloud Talk application - * - * @author Sven R. Kunze - * @author Andy Scherzinger - * Copyright (C) 2021 Andy Scherzinger - * Copyright (C) 2017 Sven R. Kunze - * - * This program 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 . - */ - -package com.nextcloud.talk.utils; - -import android.text.TextUtils; - -import com.nextcloud.talk.remotefilebrowser.model.RemoteFileBrowserItem; - -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import androidx.annotation.Nullable; - -/** - * Sort order - */ -public class FileSortOrder { - public static final String sort_a_to_z_id = "sort_a_to_z"; - public static final String sort_z_to_a_id = "sort_z_to_a"; - public static final String sort_old_to_new_id = "sort_old_to_new"; - public static final String sort_new_to_old_id = "sort_new_to_old"; - public static final String sort_small_to_big_id = "sort_small_to_big"; - public static final String sort_big_to_small_id = "sort_big_to_small"; - - public static final FileSortOrder sort_a_to_z = new FileSortOrderByName(sort_a_to_z_id, true); - public static final FileSortOrder sort_z_to_a = new FileSortOrderByName(sort_z_to_a_id, false); - public static final FileSortOrder sort_old_to_new = new FileSortOrderByDate(sort_old_to_new_id, true); - public static final FileSortOrder sort_new_to_old = new FileSortOrderByDate(sort_new_to_old_id, false); - public static final FileSortOrder sort_small_to_big = new FileSortOrderBySize(sort_small_to_big_id, true); - public static final FileSortOrder sort_big_to_small = new FileSortOrderBySize(sort_big_to_small_id, false); - - public static final Map sortOrders; - - static { - HashMap temp = new HashMap<>(); - temp.put(sort_a_to_z.name, sort_a_to_z); - temp.put(sort_z_to_a.name, sort_z_to_a); - temp.put(sort_old_to_new.name, sort_old_to_new); - temp.put(sort_new_to_old.name, sort_new_to_old); - temp.put(sort_small_to_big.name, sort_small_to_big); - temp.put(sort_big_to_small.name, sort_big_to_small); - - sortOrders = Collections.unmodifiableMap(temp); - } - - public String name; - public boolean isAscending; - - public FileSortOrder(String name, boolean ascending) { - this.name = name; - isAscending = ascending; - } - - public static FileSortOrder getFileSortOrder(@Nullable String key) { - if (TextUtils.isEmpty(key) || !sortOrders.containsKey(key)) { - return sort_a_to_z; - } else { - return sortOrders.get(key); - } - } - - public List sortCloudFiles(List files) { - return sortCloudFilesByFavourite(files); - } - - /** - * Sorts list by Favourites. - * - * @param files files to sort - */ - public static List sortCloudFilesByFavourite(List files) { - Collections.sort(files, (o1, o2) -> { - if (o1.isFavorite() && o2.isFavorite()) { - return 0; - } else if (o1.isFavorite()) { - return -1; - } else if (o2.isFavorite()) { - return 1; - } - return 0; - }); - - return files; - } -} diff --git a/app/src/main/java/com/nextcloud/talk/utils/FileSortOrder.kt b/app/src/main/java/com/nextcloud/talk/utils/FileSortOrder.kt new file mode 100644 index 000000000..de4935457 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/utils/FileSortOrder.kt @@ -0,0 +1,98 @@ +/* + * Nextcloud Talk application + * + * @author Sven R. Kunze + * @author Andy Scherzinger + * Copyright (C) 2021-2022 Andy Scherzinger + * Copyright (C) 2017 Sven R. Kunze + * + * This program 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 . + */ +package com.nextcloud.talk.utils + +import android.text.TextUtils +import com.nextcloud.talk.remotefilebrowser.model.RemoteFileBrowserItem +import java.util.Collections + +/** + * Sort order + */ +open class FileSortOrder(var name: String, var isAscending: Boolean) { + companion object { + const val sort_a_to_z_id = "sort_a_to_z" + const val sort_z_to_a_id = "sort_z_to_a" + const val sort_old_to_new_id = "sort_old_to_new" + const val sort_new_to_old_id = "sort_new_to_old" + const val sort_small_to_big_id = "sort_small_to_big" + const val sort_big_to_small_id = "sort_big_to_small" + + val sort_a_to_z: FileSortOrder = FileSortOrderByName(sort_a_to_z_id, true) + val sort_z_to_a: FileSortOrder = FileSortOrderByName(sort_z_to_a_id, false) + val sort_old_to_new: FileSortOrder = FileSortOrderByDate(sort_old_to_new_id, true) + val sort_new_to_old: FileSortOrder = FileSortOrderByDate(sort_new_to_old_id, false) + val sort_small_to_big: FileSortOrder = FileSortOrderBySize(sort_small_to_big_id, true) + val sort_big_to_small: FileSortOrder = FileSortOrderBySize(sort_big_to_small_id, false) + + val sortOrders: Map = mapOf( + sort_a_to_z.name to sort_a_to_z, + sort_z_to_a.name to sort_z_to_a, + sort_old_to_new.name to sort_old_to_new, + sort_new_to_old.name to sort_new_to_old, + sort_small_to_big.name to sort_small_to_big, + sort_big_to_small.name to sort_big_to_small, + ) + + fun getFileSortOrder(key: String?): FileSortOrder { + return if (TextUtils.isEmpty(key) || !sortOrders.containsKey(key)) { + sort_a_to_z + } else { + sortOrders[key]!! + } + } + + /** + * Sorts list by Favourites. + * + * @param files files to sort + */ + fun sortCloudFilesByFavourite(files: List): List { + Collections.sort(files, RemoteFileBrowserItemFavoriteComparator()) + return files + } + } + + open fun sortCloudFiles(files: List): List { + return sortCloudFilesByFavourite(files) + } + + val multiplier : Int + get() = if (isAscending) 1 else -1 + + /** + * Comparator for RemoteFileBrowserItems, sorts favorite state. + */ + class RemoteFileBrowserItemFavoriteComparator : Comparator { + override fun compare(left: RemoteFileBrowserItem, right: RemoteFileBrowserItem): Int { + return if (left.isFavorite && right.isFavorite) { + 0 + } else if (left.isFavorite) { + -1 + } else if (right.isFavorite) { + 1 + } else { + 0 + } + } + } +} diff --git a/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByDate.java b/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByDate.kt similarity index 53% rename from app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByDate.java rename to app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByDate.kt index 48f661019..c6d66d6ed 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByDate.java +++ b/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByDate.kt @@ -3,7 +3,7 @@ * * @author Sven R. Kunze * @author Andy Scherzinger - * Copyright (C) 2021 Andy Scherzinger + * Copyright (C) 2021-2022 Andy Scherzinger * Copyright (C) 2017 Sven R. Kunze * * This program is free software: you can redistribute it and/or modify @@ -19,34 +19,32 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ +package com.nextcloud.talk.utils -package com.nextcloud.talk.utils; - -import com.nextcloud.talk.remotefilebrowser.model.RemoteFileBrowserItem; - -import java.util.Collections; -import java.util.List; +import com.nextcloud.talk.remotefilebrowser.model.RemoteFileBrowserItem +import java.util.Collections /** * Created by srkunze on 28.08.17. */ -public class FileSortOrderByDate extends FileSortOrder { - - FileSortOrderByDate(String name, boolean ascending) { - super(name, ascending); - } - +class FileSortOrderByDate internal constructor(name: String, ascending: Boolean) : FileSortOrder(name, ascending) { /** * Sorts list by Date. * * @param files list of files to sort */ - public List sortCloudFiles(List files) { - final int multiplier = isAscending ? 1 : -1; + override fun sortCloudFiles(files: List): List { + Collections.sort(files, RemoteFileBrowserItemDateComparator(multiplier)) + return super.sortCloudFiles(files) + } - Collections.sort(files, (o1, o2) -> - multiplier * Long.compare(o1.getModifiedTimestamp(), o2.getModifiedTimestamp())); + /** + * Comparator for RemoteFileBrowserItems, sorts by modified timestamp. + */ + class RemoteFileBrowserItemDateComparator(private val multiplier: Int) : Comparator { - return super.sortCloudFiles(files); + override fun compare(left: RemoteFileBrowserItem, right: RemoteFileBrowserItem): Int { + return multiplier * left.modifiedTimestamp.compareTo(right.modifiedTimestamp) + } } } diff --git a/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByName.java b/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByName.java deleted file mode 100644 index a2cfdbf4c..000000000 --- a/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByName.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Nextcloud Talk application - * - * @author Sven R. Kunze - * @author Andy Scherzinger - * Copyright (C) 2021 Andy Scherzinger - * Copyright (C) 2017 Sven R. Kunze - * - * This program 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 . - */ - -package com.nextcloud.talk.utils; - -import com.nextcloud.talk.remotefilebrowser.model.RemoteFileBrowserItem; - -import java.util.Collections; -import java.util.List; - -import third_parties.daveKoeller.AlphanumComparator; - -/** - * Created by srkunze on 28.08.17. - */ -public class FileSortOrderByName extends FileSortOrder { - - FileSortOrderByName(String name, boolean ascending) { - super(name, ascending); - } - - /** - * Sorts list by Name. - * - * @param files files to sort - */ - @SuppressWarnings("Bx") - public List sortCloudFiles(List files) { - final int multiplier = isAscending ? 1 : -1; - - Collections.sort(files, (o1, o2) -> { - if (!o1.isFile() && !o2.isFile()) { - return multiplier * new AlphanumComparator().compare(o1, o2); - } else if (!o1.isFile()) { - return -1; - } else if (!o2.isFile()) { - return 1; - } - return multiplier * new AlphanumComparator().compare(o1, o2); - }); - - return super.sortCloudFiles(files); - } -} diff --git a/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByName.kt b/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByName.kt new file mode 100644 index 000000000..8062b8a8d --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByName.kt @@ -0,0 +1,59 @@ +/* + * Nextcloud Talk application + * + * @author Sven R. Kunze + * @author Andy Scherzinger + * Copyright (C) 2021-2022 Andy Scherzinger + * Copyright (C) 2017 Sven R. Kunze + * + * This program 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 . + */ +package com.nextcloud.talk.utils + +import com.nextcloud.talk.remotefilebrowser.model.RemoteFileBrowserItem +import third_parties.daveKoeller.AlphanumComparator +import java.util.Collections + +/** + * Created by srkunze on 28.08.17. + */ +class FileSortOrderByName internal constructor(name: String, ascending: Boolean) : FileSortOrder(name, ascending) { + /** + * Sorts list by Name. + * + * @param files files to sort + */ + override fun sortCloudFiles(files: List): List { + Collections.sort(files, RemoteFileBrowserItemNameComparator(multiplier)) + return super.sortCloudFiles(files) + } + + /** + * Comparator for RemoteFileBrowserItems, sorts by name. + */ + class RemoteFileBrowserItemNameComparator(private val multiplier: Int) : Comparator { + + override fun compare(left: RemoteFileBrowserItem, right: RemoteFileBrowserItem): Int { + return if (!left.isFile && !right.isFile) { + return multiplier * AlphanumComparator().compare(left, right) + } else if (!left.isFile) { + -1 + } else if (!right.isFile) { + 1 + } else { + multiplier * AlphanumComparator().compare(left, right) + } + } + } +} diff --git a/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderBySize.java b/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderBySize.java deleted file mode 100644 index 8ecbdd2b9..000000000 --- a/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderBySize.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Nextcloud Talk application - * - * @author Sven R. Kunze - * @author Andy Scherzinger - * Copyright (C) 2021 Andy Scherzinger - * Copyright (C) 2017 Sven R. Kunze - * - * This program 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 . - */ - -package com.nextcloud.talk.utils; - -import com.nextcloud.talk.remotefilebrowser.model.RemoteFileBrowserItem; - -import java.util.Collections; -import java.util.List; - -/** - * Sorts files by sizes - */ -public class FileSortOrderBySize extends FileSortOrder { - - FileSortOrderBySize(String name, boolean ascending) { - super(name, ascending); - } - - /** - * Sorts list by Size. - * - * @param files list of files to sort - */ - public List sortCloudFiles(List files) { - final int multiplier = isAscending ? 1 : -1; - - Collections.sort(files, (o1, o2) -> { - if (!o1.isFile() && !o2.isFile()) { - return multiplier * Long.compare(o1.getSize(), o2.getSize()); - } else if (!o1.isFile()) { - return -1; - } else if (!o2.isFile()) { - return 1; - } else { - return multiplier * Long.compare(o1.getSize(), o2.getSize()); - } - }); - - return super.sortCloudFiles(files); - } -} diff --git a/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderBySize.kt b/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderBySize.kt new file mode 100644 index 000000000..d0390251d --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderBySize.kt @@ -0,0 +1,58 @@ +/* + * Nextcloud Talk application + * + * @author Sven R. Kunze + * @author Andy Scherzinger + * Copyright (C) 2021-2022 Andy Scherzinger + * Copyright (C) 2017 Sven R. Kunze + * + * This program 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 . + */ +package com.nextcloud.talk.utils + +import com.nextcloud.talk.remotefilebrowser.model.RemoteFileBrowserItem +import java.util.Collections + +/** + * Sorts files by sizes + */ +class FileSortOrderBySize internal constructor(name: String, ascending: Boolean) : FileSortOrder(name, ascending) { + /** + * Sorts list by Size. + * + * @param files list of files to sort + */ + override fun sortCloudFiles(files: List): List { + Collections.sort(files, RemoteFileBrowserItemSizeComparator(multiplier)) + return super.sortCloudFiles(files) + } + + /** + * Comparator for RemoteFileBrowserItems, sorts by name. + */ + class RemoteFileBrowserItemSizeComparator(private val multiplier: Int) : Comparator { + + override fun compare(left: RemoteFileBrowserItem, right: RemoteFileBrowserItem): Int { + return if (!left.isFile && !right.isFile) { + return multiplier * left.size.compareTo(right.size) + } else if (!left.isFile) { + -1 + } else if (!right.isFile) { + 1 + } else { + multiplier * left.size.compareTo(right.size) + } + } + } +} From ed09934c7a16b661e3f34347d057192ca1d36c4f Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Tue, 7 Jun 2022 18:17:25 +0200 Subject: [PATCH 12/29] reformat kotlin Signed-off-by: Andy Scherzinger --- app/src/main/java/com/nextcloud/talk/utils/FileSortOrder.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/utils/FileSortOrder.kt b/app/src/main/java/com/nextcloud/talk/utils/FileSortOrder.kt index de4935457..9519874a7 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/FileSortOrder.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/FileSortOrder.kt @@ -72,13 +72,13 @@ open class FileSortOrder(var name: String, var isAscending: Boolean) { } } + val multiplier: Int + get() = if (isAscending) 1 else -1 + open fun sortCloudFiles(files: List): List { return sortCloudFilesByFavourite(files) } - val multiplier : Int - get() = if (isAscending) 1 else -1 - /** * Comparator for RemoteFileBrowserItems, sorts favorite state. */ From 80eccf3176cdc980f7bd351749de8a86aa7378a7 Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Tue, 7 Jun 2022 18:38:41 +0200 Subject: [PATCH 13/29] create narrow(er) interface for file selection Signed-off-by: Andy Scherzinger --- .../talk/interfaces/SelectionInterface.kt | 1 + .../remotefilebrowser/SelectionInterface.kt | 27 +++++++++++++++++++ .../activities/RemoteFileBrowserActivity.kt | 14 +++------- .../adapters/RemoteFileBrowserItemsAdapter.kt | 2 +- .../RemoteFileBrowserItemsListViewHolder.kt | 2 +- .../RemoteFileBrowserItemsViewHolder.kt | 2 +- .../RemoteFileBrowserItemsViewModel.kt | 4 ++- 7 files changed, 38 insertions(+), 14 deletions(-) create mode 100644 app/src/main/java/com/nextcloud/talk/remotefilebrowser/SelectionInterface.kt diff --git a/app/src/main/java/com/nextcloud/talk/interfaces/SelectionInterface.kt b/app/src/main/java/com/nextcloud/talk/interfaces/SelectionInterface.kt index 23fda533b..d5b20d191 100644 --- a/app/src/main/java/com/nextcloud/talk/interfaces/SelectionInterface.kt +++ b/app/src/main/java/com/nextcloud/talk/interfaces/SelectionInterface.kt @@ -20,6 +20,7 @@ package com.nextcloud.talk.interfaces +@Deprecated("To be replaced with com.nextcloud.talk.remotefilebrowser.SelectionInterface") interface SelectionInterface { fun toggleBrowserItemSelection(path: String) diff --git a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/SelectionInterface.kt b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/SelectionInterface.kt new file mode 100644 index 000000000..0ddfe8ffd --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/SelectionInterface.kt @@ -0,0 +1,27 @@ +/* + * Nextcloud Talk application + * + * @author Mario Danic + * @author Andy Scherzinger + * Copyright (C) 2022 Andy Scherzinger + * Copyright (C) 2017-2018 Mario Danic + * + * This program 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 . + */ + +package com.nextcloud.talk.remotefilebrowser + +interface SelectionInterface { + fun isPathSelected(path: String): Boolean +} diff --git a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/activities/RemoteFileBrowserActivity.kt b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/activities/RemoteFileBrowserActivity.kt index ee5de9120..51bf85811 100644 --- a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/activities/RemoteFileBrowserActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/activities/RemoteFileBrowserActivity.kt @@ -2,7 +2,9 @@ * Nextcloud Talk application * * @author Andy Scherzinger + * @author Álvaro Brey * Copyright (C) 2022 Andy Scherzinger + * Copyright (C) 2022 Álvaro Brey * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -38,7 +40,7 @@ import autodagger.AutoInjector import com.nextcloud.talk.R import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.databinding.ActivityRemoteFileBrowserBinding -import com.nextcloud.talk.interfaces.SelectionInterface +import com.nextcloud.talk.remotefilebrowser.SelectionInterface import com.nextcloud.talk.remotefilebrowser.adapters.RemoteFileBrowserItemsAdapter import com.nextcloud.talk.remotefilebrowser.viewmodels.RemoteFileBrowserItemsViewModel import com.nextcloud.talk.ui.dialog.SortingOrderDialogFragment @@ -121,7 +123,7 @@ class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, Swipe // TODO make mimeTypeSelectionFilter a bundled arg for the activity val mimeTypeSelectionFilter = "image/" - // TODO do not needlesly recreate adapter if it can be reused + // TODO do not needlessly recreate adapter if it can be reused val adapter = RemoteFileBrowserItemsAdapter( showGrid = showGrid, mimeTypeSelectionFilter = mimeTypeSelectionFilter, @@ -240,16 +242,8 @@ class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, Swipe const val REQUEST_CODE_SELECT_AVATAR = 22 } - override fun toggleBrowserItemSelection(path: String) { - // unused, viewmodel gets called directly - } - override fun isPathSelected(path: String): Boolean { // TODO figure out a better way to do this. Narrower interface? return viewModel.isPathSelected(path) } - - override fun shouldOnlySelectOneImageFile(): Boolean { - return true // unused - } } diff --git a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/adapters/RemoteFileBrowserItemsAdapter.kt b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/adapters/RemoteFileBrowserItemsAdapter.kt index 0af1015ee..2d6020394 100644 --- a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/adapters/RemoteFileBrowserItemsAdapter.kt +++ b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/adapters/RemoteFileBrowserItemsAdapter.kt @@ -25,8 +25,8 @@ import android.view.LayoutInflater import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView import com.nextcloud.talk.databinding.RvItemBrowserFileBinding -import com.nextcloud.talk.interfaces.SelectionInterface import com.nextcloud.talk.models.database.UserEntity +import com.nextcloud.talk.remotefilebrowser.SelectionInterface import com.nextcloud.talk.remotefilebrowser.model.RemoteFileBrowserItem class RemoteFileBrowserItemsAdapter( diff --git a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/adapters/RemoteFileBrowserItemsListViewHolder.kt b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/adapters/RemoteFileBrowserItemsListViewHolder.kt index 61bf4be53..1644b61ef 100644 --- a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/adapters/RemoteFileBrowserItemsListViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/adapters/RemoteFileBrowserItemsListViewHolder.kt @@ -30,8 +30,8 @@ import com.facebook.drawee.view.SimpleDraweeView import com.nextcloud.talk.R import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.databinding.RvItemBrowserFileBinding -import com.nextcloud.talk.interfaces.SelectionInterface import com.nextcloud.talk.models.database.UserEntity +import com.nextcloud.talk.remotefilebrowser.SelectionInterface import com.nextcloud.talk.remotefilebrowser.model.RemoteFileBrowserItem import com.nextcloud.talk.utils.ApiUtils import com.nextcloud.talk.utils.DateUtils.getLocalDateTimeStringFromTimestamp diff --git a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/adapters/RemoteFileBrowserItemsViewHolder.kt b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/adapters/RemoteFileBrowserItemsViewHolder.kt index 4ebc5f7b9..71f343eb9 100644 --- a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/adapters/RemoteFileBrowserItemsViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/adapters/RemoteFileBrowserItemsViewHolder.kt @@ -25,8 +25,8 @@ import androidx.core.content.ContextCompat import androidx.recyclerview.widget.RecyclerView import androidx.viewbinding.ViewBinding import com.facebook.drawee.view.SimpleDraweeView -import com.nextcloud.talk.interfaces.SelectionInterface import com.nextcloud.talk.models.database.UserEntity +import com.nextcloud.talk.remotefilebrowser.SelectionInterface import com.nextcloud.talk.remotefilebrowser.model.RemoteFileBrowserItem import com.nextcloud.talk.utils.DrawableUtils diff --git a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/viewmodels/RemoteFileBrowserItemsViewModel.kt b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/viewmodels/RemoteFileBrowserItemsViewModel.kt index 2b961fff3..ef45577bd 100644 --- a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/viewmodels/RemoteFileBrowserItemsViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/viewmodels/RemoteFileBrowserItemsViewModel.kt @@ -2,7 +2,9 @@ * Nextcloud Talk application * * @author Andy Scherzinger - * Copyright (C) 202 Andy Scherzinger + * @author Álvaro Brey + * Copyright (C) 2022 Andy Scherzinger + * Copyright (C) 2022 Álvaro Brey * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by From 5bf90157bca2e19e4818f116ff236d3ac7887c52 Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Tue, 7 Jun 2022 20:42:39 +0200 Subject: [PATCH 14/29] remove legacy references and fix avatar upload permission issues ...by using a different location and remove previous avatars upfront Signed-off-by: Andy Scherzinger --- .../talk/controllers/ProfileController.kt | 51 ++++++++----------- .../activities/RemoteFileBrowserActivity.kt | 23 +++++---- .../ui/dialog/SortingOrderDialogFragment.java | 15 ++++++ .../com/nextcloud/talk/utils/FileUtils.java | 17 +++++++ .../nextcloud/talk/utils/bundle/BundleKeys.kt | 1 - 5 files changed, 64 insertions(+), 43 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/controllers/ProfileController.kt b/app/src/main/java/com/nextcloud/talk/controllers/ProfileController.kt index cfcd00202..beb6fb073 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/ProfileController.kt +++ b/app/src/main/java/com/nextcloud/talk/controllers/ProfileController.kt @@ -55,7 +55,6 @@ import com.nextcloud.talk.R import com.nextcloud.talk.api.NcApi import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication -import com.nextcloud.talk.components.filebrowser.controllers.BrowserController.BrowserType import com.nextcloud.talk.controllers.base.NewBaseController import com.nextcloud.talk.controllers.util.viewBinding import com.nextcloud.talk.databinding.ControllerProfileBinding @@ -72,11 +71,7 @@ import com.nextcloud.talk.ui.dialog.ScopeDialog import com.nextcloud.talk.utils.ApiUtils import com.nextcloud.talk.utils.DisplayUtils import com.nextcloud.talk.utils.FileUtils -import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_BROWSER_TYPE import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_MIME_TYPE_FILTER -import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN -import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_SINGLE_SELECTION -import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_USER_ENTITY import com.nextcloud.talk.utils.database.user.UserUtils import io.reactivex.Observer import io.reactivex.android.schedulers.AndroidSchedulers @@ -86,7 +81,6 @@ import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.MultipartBody import okhttp3.RequestBody import okhttp3.ResponseBody -import org.parceler.Parcels import retrofit2.Call import retrofit2.Callback import retrofit2.Response @@ -199,7 +193,7 @@ class ProfileController : NewBaseController(R.layout.controller_profile) { currentUser = userUtils.currentUser val credentials = ApiUtils.getCredentials(currentUser!!.username, currentUser!!.token) binding.avatarUpload.setOnClickListener { sendSelectLocalFileIntent() } - binding.avatarChoose.setOnClickListener { showBrowserScreen(BrowserType.DAV_BROWSER) } + binding.avatarChoose.setOnClickListener { showBrowserScreen() } binding.avatarDelete.setOnClickListener { ncApi.deleteAvatar( credentials, @@ -486,32 +480,14 @@ class ProfileController : NewBaseController(R.layout.controller_profile) { startActivityForResult(intent, 1) } - private fun showBrowserScreen(browserType: BrowserType) { + private fun showBrowserScreen() { val bundle = Bundle() - bundle.putParcelable( - KEY_BROWSER_TYPE, - Parcels.wrap(BrowserType::class.java, browserType) - ) - bundle.putParcelable( - KEY_USER_ENTITY, - Parcels.wrap(UserEntity::class.java, currentUser) - ) - bundle.putBoolean(KEY_SINGLE_SELECTION, true) bundle.putString(KEY_MIME_TYPE_FILTER, "image/") - bundle.putString(KEY_ROOM_TOKEN, "123") val avatarIntent = Intent(activity, RemoteFileBrowserActivity::class.java) avatarIntent.putExtras(bundle) startActivityForResult(avatarIntent, RemoteFileBrowserActivity.REQUEST_CODE_SELECT_AVATAR) - - /* - router.pushController( - RouterTransaction.with(BrowserForAvatarController(bundle, this)) - .pushChangeHandler(VerticalChangeHandler()) - .popChangeHandler(VerticalChangeHandler()) - ) - */ } fun handleAvatar(remotePath: String?) { @@ -536,7 +512,14 @@ class ProfileController : NewBaseController(R.layout.controller_profile) { private fun saveBitmapAndPassToImagePicker(bitmap: Bitmap) { var file: File? = null try { - file = FileUtils.getTempCacheFile(context!!, "avatar/avatar.png") + FileUtils.removeTempCacheFile( + this.context!!, + "photos/avatar.png" + ) + file = FileUtils.getTempCacheFile( + this.context!!, + "photos/avatar.png" + ) try { FileOutputStream(file).use { out -> bitmap.compress(Bitmap.CompressFormat.PNG, FULL_QUALITY, out) } } catch (e: IOException) { @@ -560,12 +543,18 @@ class ProfileController : NewBaseController(R.layout.controller_profile) { startActivityForResult(intent, REQUEST_CODE_IMAGE_PICKER) } - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) { if (resultCode == Activity.RESULT_OK) { - - uploadAvatar(getFile(data)) + if (requestCode == REQUEST_CODE_IMAGE_PICKER) { + uploadAvatar(getFile(intent)) + } else { + val pathList = intent?.getStringArrayListExtra(RemoteFileBrowserActivity.EXTRA_SELECTED_PATHS) + if (pathList?.size!! >= 1) { + handleAvatar(pathList[0]) + } + } } else if (resultCode == ImagePicker.RESULT_ERROR) { - Toast.makeText(activity, getError(data), Toast.LENGTH_SHORT).show() + Toast.makeText(activity, getError(intent), Toast.LENGTH_SHORT).show() } else { Toast.makeText(activity, "Task Cancelled", Toast.LENGTH_SHORT).show() } diff --git a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/activities/RemoteFileBrowserActivity.kt b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/activities/RemoteFileBrowserActivity.kt index 51bf85811..755380a6f 100644 --- a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/activities/RemoteFileBrowserActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/activities/RemoteFileBrowserActivity.kt @@ -45,8 +45,9 @@ import com.nextcloud.talk.remotefilebrowser.adapters.RemoteFileBrowserItemsAdapt import com.nextcloud.talk.remotefilebrowser.viewmodels.RemoteFileBrowserItemsViewModel import com.nextcloud.talk.ui.dialog.SortingOrderDialogFragment import com.nextcloud.talk.utils.DisplayUtils -import com.nextcloud.talk.utils.LegacyFileSortOrder -import com.nextcloud.talk.utils.database.user.UserUtils +import com.nextcloud.talk.utils.FileSortOrder +import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_MIME_TYPE_FILTER +import com.nextcloud.talk.utils.database.user.CurrentUserProvider import javax.inject.Inject @AutoInjector(NextcloudTalkApplication::class) @@ -55,9 +56,8 @@ class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, Swipe @Inject lateinit var viewModelFactory: ViewModelProvider.Factory - // TODO use CurrentUserProvider instead for narrower scope @Inject - lateinit var userUtils: UserUtils + lateinit var currentUserProvider: CurrentUserProvider private lateinit var binding: ActivityRemoteFileBrowserBinding private lateinit var viewModel: RemoteFileBrowserItemsViewModel @@ -85,7 +85,10 @@ class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, Swipe supportActionBar?.setDisplayHomeAsUpEnabled(true) - initViewModel() + val extras = intent.extras + val mimeTypeSelectionFilter = extras?.getString(KEY_MIME_TYPE_FILTER, null) + + initViewModel(mimeTypeSelectionFilter) binding.swipeRefreshList.setOnRefreshListener(this) binding.swipeRefreshList.setColorSchemeResources(R.color.colorPrimary) @@ -97,7 +100,7 @@ class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, Swipe viewModel.loadItems() } - private fun initViewModel() { + private fun initViewModel(mimeTypeSelectionFilter: String?) { viewModel = ViewModelProvider(this, viewModelFactory)[RemoteFileBrowserItemsViewModel::class.java] viewModel.viewState.observe(this) { state -> @@ -113,7 +116,7 @@ class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, Swipe val remoteFileBrowserItems = state.items Log.d(TAG, "Items received: $remoteFileBrowserItems") - // TODO make shwoGrid based on preferences + // TODO make showGrid based on preferences (when available) val showGrid = false val layoutManager = if (showGrid) { GridLayoutManager(this, SPAN_COUNT) @@ -121,13 +124,11 @@ class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, Swipe LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false) } - // TODO make mimeTypeSelectionFilter a bundled arg for the activity - val mimeTypeSelectionFilter = "image/" // TODO do not needlessly recreate adapter if it can be reused val adapter = RemoteFileBrowserItemsAdapter( showGrid = showGrid, mimeTypeSelectionFilter = mimeTypeSelectionFilter, - userEntity = userUtils.currentUser!!, + userEntity = currentUserProvider.currentUser!!, selectionInterface = this, onItemClicked = viewModel::onItemClicked ) @@ -177,7 +178,7 @@ class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, Swipe private fun changeSorting() { val newFragment: DialogFragment = SortingOrderDialogFragment - .newInstance(LegacyFileSortOrder.getFileSortOrder(viewModel.fileSortOrder.value!!.name)) + .newInstance(FileSortOrder.getFileSortOrder(viewModel.fileSortOrder.value!!.name)) newFragment.show( supportFragmentManager, SortingOrderDialogFragment.SORTING_ORDER_FRAGMENT diff --git a/app/src/main/java/com/nextcloud/talk/ui/dialog/SortingOrderDialogFragment.java b/app/src/main/java/com/nextcloud/talk/ui/dialog/SortingOrderDialogFragment.java index f69360a9b..f91d31997 100644 --- a/app/src/main/java/com/nextcloud/talk/ui/dialog/SortingOrderDialogFragment.java +++ b/app/src/main/java/com/nextcloud/talk/ui/dialog/SortingOrderDialogFragment.java @@ -36,9 +36,13 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.nextcloud.talk.R; import com.nextcloud.talk.application.NextcloudTalkApplication; import com.nextcloud.talk.databinding.SortingOrderFragmentBinding; +import com.nextcloud.talk.utils.FileSortOrder; import com.nextcloud.talk.utils.LegacyFileSortOrder; import com.nextcloud.talk.utils.preferences.AppPreferences; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + import javax.inject.Inject; import androidx.annotation.NonNull; @@ -67,6 +71,7 @@ public class SortingOrderDialogFragment extends DialogFragment implements View.O private View[] taggedViews; private String currentSortOrderName; + @Deprecated public static SortingOrderDialogFragment newInstance(LegacyFileSortOrder sortOrder) { SortingOrderDialogFragment dialogFragment = new SortingOrderDialogFragment(); @@ -77,6 +82,16 @@ public class SortingOrderDialogFragment extends DialogFragment implements View.O return dialogFragment; } + public static SortingOrderDialogFragment newInstance(@NotNull FileSortOrder sortOrder) { + SortingOrderDialogFragment dialogFragment = new SortingOrderDialogFragment(); + + Bundle args = new Bundle(); + args.putString(KEY_SORT_ORDER, sortOrder.getName()); + dialogFragment.setArguments(args); + + return dialogFragment; + } + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); diff --git a/app/src/main/java/com/nextcloud/talk/utils/FileUtils.java b/app/src/main/java/com/nextcloud/talk/utils/FileUtils.java index 796337f83..ceb8f1bb9 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/FileUtils.java +++ b/app/src/main/java/com/nextcloud/talk/utils/FileUtils.java @@ -65,4 +65,21 @@ public class FileUtils { return cacheFile; } + + /** + * Creates a new {@link File} + */ + public static void removeTempCacheFile(@NonNull Context context, String fileName) throws IOException { + File cacheFile = new File(context.getApplicationContext().getFilesDir().getAbsolutePath() + "/" + fileName); + + Log.v(TAG, "Full path for new cache file:" + cacheFile.getAbsolutePath()); + + if (cacheFile.exists()) { + if(cacheFile.delete()) { + Log.v(TAG, "Deletion successful"); + } else { + throw new IOException("Directory for temporary file does not exist and could not be created."); + } + } + } } diff --git a/app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.kt b/app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.kt index dad594bdd..75ca6b9d3 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.kt @@ -74,6 +74,5 @@ object BundleKeys { val KEY_FORWARD_HIDE_SOURCE_ROOM = "KEY_FORWARD_HIDE_SOURCE_ROOM" val KEY_SYSTEM_NOTIFICATION_ID = "KEY_SYSTEM_NOTIFICATION_ID" const val KEY_MESSAGE_ID = "KEY_MESSAGE_ID" - const val KEY_SINGLE_SELECTION = "KEY_SINGLE_SELECTION" const val KEY_MIME_TYPE_FILTER = "KEY_MIME_TYPE_FILTER" } From 4f234032aa6e502bd5189694ce18d42b3d7a22ef Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Tue, 7 Jun 2022 20:43:44 +0200 Subject: [PATCH 15/29] remove now obsolete BrowserForAvatarController Signed-off-by: Andy Scherzinger --- .../BrowserForAvatarController.java | 59 ------------------- 1 file changed, 59 deletions(-) delete mode 100644 app/src/main/java/com/nextcloud/talk/components/filebrowser/controllers/BrowserForAvatarController.java diff --git a/app/src/main/java/com/nextcloud/talk/components/filebrowser/controllers/BrowserForAvatarController.java b/app/src/main/java/com/nextcloud/talk/components/filebrowser/controllers/BrowserForAvatarController.java deleted file mode 100644 index 9075d3788..000000000 --- a/app/src/main/java/com/nextcloud/talk/components/filebrowser/controllers/BrowserForAvatarController.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Nextcloud Talk application - * - * @author Tobias Kaminsky - * Copyright (C) 2021 Tobias Kaminsky - * - * This program 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 . - */ - -package com.nextcloud.talk.components.filebrowser.controllers; - -import android.content.Intent; -import android.os.Bundle; - -import com.nextcloud.talk.controllers.ProfileController; - -import androidx.annotation.Nullable; - -public class BrowserForAvatarController extends BrowserController { - private ProfileController controller; - - public BrowserForAvatarController(Bundle args) { - super(args); - } - - public BrowserForAvatarController(Bundle args, ProfileController controller) { - super(args); - - this.controller = controller; - } - - @Override - public void onFileSelectionDone() { - controller.handleAvatar(selectedPaths.iterator().next()); - - getRouter().popCurrentController(); - } - - @Override - public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { - super.onActivityResult(requestCode, resultCode, data); - } - - @Override - public boolean shouldOnlySelectOneImageFile() { - return true; - } -} From 3330df3b665377eb61c1c94b90e4f3be0563f17f Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Tue, 7 Jun 2022 20:46:55 +0200 Subject: [PATCH 16/29] rename to ReadFolderListingOperation Signed-off-by: Andy Scherzinger --- ...adFilesystemOperation.kt => ReadFolderListingOperation.kt} | 2 +- .../repositories/RemoteFileBrowserItemsRepositoryImpl.kt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) rename app/src/main/java/com/nextcloud/talk/components/filebrowser/webdav/{ReadFilesystemOperation.kt => ReadFolderListingOperation.kt} (98%) diff --git a/app/src/main/java/com/nextcloud/talk/components/filebrowser/webdav/ReadFilesystemOperation.kt b/app/src/main/java/com/nextcloud/talk/components/filebrowser/webdav/ReadFolderListingOperation.kt similarity index 98% rename from app/src/main/java/com/nextcloud/talk/components/filebrowser/webdav/ReadFilesystemOperation.kt rename to app/src/main/java/com/nextcloud/talk/components/filebrowser/webdav/ReadFolderListingOperation.kt index acc1a30ce..0a511607b 100644 --- a/app/src/main/java/com/nextcloud/talk/components/filebrowser/webdav/ReadFilesystemOperation.kt +++ b/app/src/main/java/com/nextcloud/talk/components/filebrowser/webdav/ReadFolderListingOperation.kt @@ -49,7 +49,7 @@ import okhttp3.OkHttpClient import java.io.File import java.io.IOException -class ReadFilesystemOperation(okHttpClient: OkHttpClient, currentUser: UserEntity, path: String, depth: Int) { +class ReadFolderListingOperation(okHttpClient: OkHttpClient, currentUser: UserEntity, path: String, depth: Int) { private val okHttpClient: OkHttpClient private val url: String private val depth: Int diff --git a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/repositories/RemoteFileBrowserItemsRepositoryImpl.kt b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/repositories/RemoteFileBrowserItemsRepositoryImpl.kt index c992462aa..2f33f32af 100644 --- a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/repositories/RemoteFileBrowserItemsRepositoryImpl.kt +++ b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/repositories/RemoteFileBrowserItemsRepositoryImpl.kt @@ -20,7 +20,7 @@ package com.nextcloud.talk.remotefilebrowser.repositories -import com.nextcloud.talk.components.filebrowser.webdav.ReadFilesystemOperation +import com.nextcloud.talk.components.filebrowser.webdav.ReadFolderListingOperation import com.nextcloud.talk.models.database.UserEntity import com.nextcloud.talk.remotefilebrowser.model.RemoteFileBrowserItem import com.nextcloud.talk.utils.database.user.CurrentUserProvider @@ -40,7 +40,7 @@ class RemoteFileBrowserItemsRepositoryImpl @Inject constructor( Observable> { return Observable.fromCallable { val operation = - ReadFilesystemOperation( + ReadFolderListingOperation( okHttpClient, userEntity, path, From 7f85a2f2288bb331997e56e6619db33a9b9221cb Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Tue, 7 Jun 2022 20:47:56 +0200 Subject: [PATCH 17/29] Rename ReadFilesystemOperation Signed-off-by: Andy Scherzinger --- .../messages/MagicPreviewMessageViewHolder.java | 12 ++++++------ .../filebrowser/operations/DavListing.java | 12 ++++++------ ...emOperation.java => ReadFilesystemOperation.java} | 7 +++---- 3 files changed, 15 insertions(+), 16 deletions(-) rename app/src/main/java/com/nextcloud/talk/components/filebrowser/webdav/{LegacyReadFilesystemOperation.java => ReadFilesystemOperation.java} (94%) diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/MagicPreviewMessageViewHolder.java b/app/src/main/java/com/nextcloud/talk/adapters/messages/MagicPreviewMessageViewHolder.java index 0e7cf5d8a..8cce972d4 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/MagicPreviewMessageViewHolder.java +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/MagicPreviewMessageViewHolder.java @@ -45,7 +45,7 @@ import com.nextcloud.talk.R; import com.nextcloud.talk.application.NextcloudTalkApplication; import com.nextcloud.talk.components.filebrowser.models.BrowserFile; import com.nextcloud.talk.components.filebrowser.models.DavResponse; -import com.nextcloud.talk.components.filebrowser.webdav.LegacyReadFilesystemOperation; +import com.nextcloud.talk.components.filebrowser.webdav.ReadFilesystemOperation; import com.nextcloud.talk.databinding.ReactionsInsideMessageBinding; import com.nextcloud.talk.models.database.UserEntity; import com.nextcloud.talk.models.json.chat.ChatMessage; @@ -289,20 +289,20 @@ public abstract class MagicPreviewMessageViewHolder extends MessageHolders.Incom } private void fetchFileInformation(String url, UserEntity activeUser) { - Single.fromCallable(new Callable() { + Single.fromCallable(new Callable() { @Override - public LegacyReadFilesystemOperation call() { - return new LegacyReadFilesystemOperation(okHttpClient, activeUser, url, 0); + public ReadFilesystemOperation call() { + return new ReadFilesystemOperation(okHttpClient, activeUser, url, 0); } }).observeOn(Schedulers.io()) - .subscribe(new SingleObserver() { + .subscribe(new SingleObserver() { @Override public void onSubscribe(@NonNull Disposable d) { // unused atm } @Override - public void onSuccess(@NonNull LegacyReadFilesystemOperation readFilesystemOperation) { + public void onSuccess(@NonNull ReadFilesystemOperation readFilesystemOperation) { DavResponse davResponse = readFilesystemOperation.readRemotePath(); if (davResponse.data != null) { List browserFileList = (List) davResponse.data; diff --git a/app/src/main/java/com/nextcloud/talk/components/filebrowser/operations/DavListing.java b/app/src/main/java/com/nextcloud/talk/components/filebrowser/operations/DavListing.java index f368d0b4c..dc69a1422 100644 --- a/app/src/main/java/com/nextcloud/talk/components/filebrowser/operations/DavListing.java +++ b/app/src/main/java/com/nextcloud/talk/components/filebrowser/operations/DavListing.java @@ -26,7 +26,7 @@ import android.util.Log; import com.nextcloud.talk.components.filebrowser.interfaces.ListingInterface; import com.nextcloud.talk.components.filebrowser.models.DavResponse; -import com.nextcloud.talk.components.filebrowser.webdav.LegacyReadFilesystemOperation; +import com.nextcloud.talk.components.filebrowser.webdav.ReadFilesystemOperation; import com.nextcloud.talk.models.database.UserEntity; import java.util.concurrent.Callable; @@ -50,20 +50,20 @@ public class DavListing extends ListingAbstractClass { @Override public void getFiles(String path, UserEntity currentUser, @Nullable OkHttpClient okHttpClient) { - Single.fromCallable(new Callable() { + Single.fromCallable(new Callable() { @Override - public LegacyReadFilesystemOperation call() { - return new LegacyReadFilesystemOperation(okHttpClient, currentUser, path, 1); + public ReadFilesystemOperation call() { + return new ReadFilesystemOperation(okHttpClient, currentUser, path, 1); } }).subscribeOn(Schedulers.io()) - .subscribe(new SingleObserver() { + .subscribe(new SingleObserver() { @Override public void onSubscribe(@NonNull Disposable d) { } @Override - public void onSuccess(@NonNull LegacyReadFilesystemOperation readFilesystemOperation) { + public void onSuccess(@NonNull ReadFilesystemOperation readFilesystemOperation) { davResponse = readFilesystemOperation.readRemotePath(); try { listingInterface.listingResult(davResponse); diff --git a/app/src/main/java/com/nextcloud/talk/components/filebrowser/webdav/LegacyReadFilesystemOperation.java b/app/src/main/java/com/nextcloud/talk/components/filebrowser/webdav/ReadFilesystemOperation.java similarity index 94% rename from app/src/main/java/com/nextcloud/talk/components/filebrowser/webdav/LegacyReadFilesystemOperation.java rename to app/src/main/java/com/nextcloud/talk/components/filebrowser/webdav/ReadFilesystemOperation.java index 35766e07f..09c1fc2b7 100644 --- a/app/src/main/java/com/nextcloud/talk/components/filebrowser/webdav/LegacyReadFilesystemOperation.java +++ b/app/src/main/java/com/nextcloud/talk/components/filebrowser/webdav/ReadFilesystemOperation.java @@ -40,15 +40,14 @@ import kotlin.jvm.functions.Function2; import okhttp3.HttpUrl; import okhttp3.OkHttpClient; -@Deprecated -public class LegacyReadFilesystemOperation { +public class ReadFilesystemOperation { private static final String TAG = "ReadFilesystemOperation"; private final OkHttpClient okHttpClient; private final String url; private final int depth; private final String basePath; - public LegacyReadFilesystemOperation(OkHttpClient okHttpClient, UserEntity currentUser, String path, int depth) { + public ReadFilesystemOperation(OkHttpClient okHttpClient, UserEntity currentUser, String path, int depth) { OkHttpClient.Builder okHttpClientBuilder = okHttpClient.newBuilder(); okHttpClientBuilder.followRedirects(false); okHttpClientBuilder.followSslRedirects(false); @@ -92,7 +91,7 @@ public class LegacyReadFilesystemOperation { } }); } catch (IOException | DavException e) { - Log.w("", "Error reading remote path"); + Log.w(TAG, "Error reading remote path"); } remoteFiles.add(BrowserFile.Companion.getModelFromResponse(rootElement[0], From aa353f064fdc55d2b527a356bae37d1a4a4fdb99 Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Tue, 7 Jun 2022 21:03:24 +0200 Subject: [PATCH 18/29] fix selection on click for new implementation, move sorting dialog references to new sorting class references ... needs duplication of the layout file Signed-off-by: Andy Scherzinger --- .../adapters/items/BrowserFileItem.java | 5 +- .../ui/dialog/SortingOrderDialogFragment.java | 34 +++--- .../main/res/layout/controller_browser.xml | 2 +- .../main/res/layout/rv_item_browser_file.xml | 4 +- .../res/layout/rv_item_browser_file_old.xml | 105 ++++++++++++++++++ 5 files changed, 128 insertions(+), 22 deletions(-) create mode 100644 app/src/main/res/layout/rv_item_browser_file_old.xml diff --git a/app/src/main/java/com/nextcloud/talk/components/filebrowser/adapters/items/BrowserFileItem.java b/app/src/main/java/com/nextcloud/talk/components/filebrowser/adapters/items/BrowserFileItem.java index 274b849f6..09926a663 100644 --- a/app/src/main/java/com/nextcloud/talk/components/filebrowser/adapters/items/BrowserFileItem.java +++ b/app/src/main/java/com/nextcloud/talk/components/filebrowser/adapters/items/BrowserFileItem.java @@ -34,6 +34,7 @@ import com.nextcloud.talk.R; import com.nextcloud.talk.application.NextcloudTalkApplication; import com.nextcloud.talk.components.filebrowser.models.BrowserFile; import com.nextcloud.talk.databinding.RvItemBrowserFileBinding; +import com.nextcloud.talk.databinding.RvItemBrowserFileOldBinding; import com.nextcloud.talk.interfaces.SelectionInterface; import com.nextcloud.talk.models.database.UserEntity; import com.nextcloud.talk.utils.ApiUtils; @@ -199,11 +200,11 @@ public class BrowserFileItem extends AbstractFlexibleItem + tools:listitem="@layout/rv_item_browser_file_old" /> diff --git a/app/src/main/res/layout/rv_item_browser_file.xml b/app/src/main/res/layout/rv_item_browser_file.xml index dfc50383f..08958cdff 100644 --- a/app/src/main/res/layout/rv_item_browser_file.xml +++ b/app/src/main/res/layout/rv_item_browser_file.xml @@ -34,8 +34,8 @@ android:layout_height="48dp" android:layout_alignParentEnd="true" android:layout_centerVertical="true" - android:clickable="true" - android:focusable="true" + android:clickable="false" + android:focusable="false" android:longClickable="false" android:visibility="visible" /> diff --git a/app/src/main/res/layout/rv_item_browser_file_old.xml b/app/src/main/res/layout/rv_item_browser_file_old.xml new file mode 100644 index 000000000..dfc50383f --- /dev/null +++ b/app/src/main/res/layout/rv_item_browser_file_old.xml @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + From 41694b64bb986219b2f4b8c9003d18fc4943d8eb Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Wed, 8 Jun 2022 18:16:37 +0200 Subject: [PATCH 19/29] fix copyright year in header Signed-off-by: Andy Scherzinger --- .../adapters/RemoteFileBrowserItemsListViewHolder.kt | 2 +- .../talk/remotefilebrowser/model/RemoteFileBrowserItem.kt | 2 +- .../repositories/RemoteFileBrowserItemsRepository.kt | 2 +- .../repositories/RemoteFileBrowserItemsRepositoryImpl.kt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/adapters/RemoteFileBrowserItemsListViewHolder.kt b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/adapters/RemoteFileBrowserItemsListViewHolder.kt index 1644b61ef..24b1df6c6 100644 --- a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/adapters/RemoteFileBrowserItemsListViewHolder.kt +++ b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/adapters/RemoteFileBrowserItemsListViewHolder.kt @@ -2,7 +2,7 @@ * Nextcloud Talk application * * @author Andy Scherzinger - * Copyright (C) 202 Andy Scherzinger + * Copyright (C) 2022 Andy Scherzinger * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/model/RemoteFileBrowserItem.kt b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/model/RemoteFileBrowserItem.kt index 32e06fba8..3904cd18c 100644 --- a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/model/RemoteFileBrowserItem.kt +++ b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/model/RemoteFileBrowserItem.kt @@ -3,7 +3,7 @@ * * @author Andy Scherzinger * @author Mario Danic - * Copyright (C) 202 Andy Scherzinger + * Copyright (C) 2022 Andy Scherzinger * Copyright (C) 2017-2018 Mario Danic * * This program is free software: you can redistribute it and/or modify diff --git a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/repositories/RemoteFileBrowserItemsRepository.kt b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/repositories/RemoteFileBrowserItemsRepository.kt index a2ea15009..6f2239d83 100644 --- a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/repositories/RemoteFileBrowserItemsRepository.kt +++ b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/repositories/RemoteFileBrowserItemsRepository.kt @@ -2,7 +2,7 @@ * Nextcloud Talk application * * @author Andy Scherzinger - * Copyright (C) 202 Andy Scherzinger + * Copyright (C) 2022 Andy Scherzinger * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/repositories/RemoteFileBrowserItemsRepositoryImpl.kt b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/repositories/RemoteFileBrowserItemsRepositoryImpl.kt index 2f33f32af..33b89c244 100644 --- a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/repositories/RemoteFileBrowserItemsRepositoryImpl.kt +++ b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/repositories/RemoteFileBrowserItemsRepositoryImpl.kt @@ -2,7 +2,7 @@ * Nextcloud Talk application * * @author Andy Scherzinger - * Copyright (C) 202 Andy Scherzinger + * Copyright (C) 2022 Andy Scherzinger * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by From df61a4df87cc2b842621f4602ba73c8898c726d5 Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Wed, 8 Jun 2022 23:24:20 +0200 Subject: [PATCH 20/29] replace share files remote item chooser with new implementation and remove any legacy implementation Signed-off-by: Andy Scherzinger --- .../adapters/items/BrowserFileItem.java | 210 ----------- .../controllers/BrowserController.kt | 344 ------------------ .../BrowserForSharingController.java | 80 ---- .../interfaces/ListingInterface.java | 27 -- .../filebrowser/operations/DavListing.java | 81 ----- .../operations/ListingAbstractClass.java | 48 --- .../talk/controllers/ChatController.kt | 48 ++- .../talk/controllers/ProfileController.kt | 7 +- .../talk/interfaces/SelectionInterface.kt | 30 -- .../activities/RemoteFileBrowserActivity.kt | 10 +- .../talk/ui/dialog/AttachmentDialog.kt | 3 +- .../ui/dialog/SortingOrderDialogFragment.java | 12 - .../nextcloud/talk/utils/DisplayUtils.java | 32 +- .../com/nextcloud/talk/utils/FileSortOrder.kt | 3 - .../talk/utils/FileSortOrderByDate.kt | 3 - .../talk/utils/FileSortOrderByName.kt | 8 +- .../talk/utils/FileSortOrderBySize.kt | 3 - .../talk/utils/LegacyFileSortOrder.java | 108 ------ .../talk/utils/LegacyFileSortOrderByDate.java | 53 --- .../talk/utils/LegacyFileSortOrderByName.java | 64 ---- .../talk/utils/LegacyFileSortOrderBySize.java | 62 ---- .../daveKoeller/AlphanumComparator.java | 9 +- .../main/res/layout/controller_browser.xml | 100 ----- .../res/layout/rv_item_browser_file_old.xml | 105 ------ app/src/main/res/menu/file_browser_path.xml | 28 -- 25 files changed, 58 insertions(+), 1420 deletions(-) delete mode 100644 app/src/main/java/com/nextcloud/talk/components/filebrowser/adapters/items/BrowserFileItem.java delete mode 100644 app/src/main/java/com/nextcloud/talk/components/filebrowser/controllers/BrowserController.kt delete mode 100644 app/src/main/java/com/nextcloud/talk/components/filebrowser/controllers/BrowserForSharingController.java delete mode 100644 app/src/main/java/com/nextcloud/talk/components/filebrowser/interfaces/ListingInterface.java delete mode 100644 app/src/main/java/com/nextcloud/talk/components/filebrowser/operations/DavListing.java delete mode 100644 app/src/main/java/com/nextcloud/talk/components/filebrowser/operations/ListingAbstractClass.java delete mode 100644 app/src/main/java/com/nextcloud/talk/interfaces/SelectionInterface.kt delete mode 100644 app/src/main/java/com/nextcloud/talk/utils/LegacyFileSortOrder.java delete mode 100644 app/src/main/java/com/nextcloud/talk/utils/LegacyFileSortOrderByDate.java delete mode 100644 app/src/main/java/com/nextcloud/talk/utils/LegacyFileSortOrderByName.java delete mode 100644 app/src/main/java/com/nextcloud/talk/utils/LegacyFileSortOrderBySize.java delete mode 100644 app/src/main/res/layout/controller_browser.xml delete mode 100644 app/src/main/res/layout/rv_item_browser_file_old.xml delete mode 100644 app/src/main/res/menu/file_browser_path.xml diff --git a/app/src/main/java/com/nextcloud/talk/components/filebrowser/adapters/items/BrowserFileItem.java b/app/src/main/java/com/nextcloud/talk/components/filebrowser/adapters/items/BrowserFileItem.java deleted file mode 100644 index 09926a663..000000000 --- a/app/src/main/java/com/nextcloud/talk/components/filebrowser/adapters/items/BrowserFileItem.java +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Nextcloud Talk application - * - * @author Mario Danic - * @author Andy Scherzinger - * Copyright (C) 2022 Andy Scherzinger - * Copyright (C) 2017-2018 Mario Danic - * - * This program 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 . - */ - -package com.nextcloud.talk.components.filebrowser.adapters.items; - -import android.content.Context; -import android.text.format.Formatter; -import android.view.View; -import android.widget.CheckBox; -import android.widget.Toast; - -import com.facebook.drawee.backends.pipeline.Fresco; -import com.facebook.drawee.interfaces.DraweeController; -import com.nextcloud.talk.R; -import com.nextcloud.talk.application.NextcloudTalkApplication; -import com.nextcloud.talk.components.filebrowser.models.BrowserFile; -import com.nextcloud.talk.databinding.RvItemBrowserFileBinding; -import com.nextcloud.talk.databinding.RvItemBrowserFileOldBinding; -import com.nextcloud.talk.interfaces.SelectionInterface; -import com.nextcloud.talk.models.database.UserEntity; -import com.nextcloud.talk.utils.ApiUtils; -import com.nextcloud.talk.utils.DateUtils; -import com.nextcloud.talk.utils.DisplayUtils; -import com.nextcloud.talk.utils.DrawableUtils; - -import java.util.List; - -import javax.inject.Inject; - -import androidx.appcompat.content.res.AppCompatResources; -import autodagger.AutoInjector; -import eu.davidea.flexibleadapter.FlexibleAdapter; -import eu.davidea.flexibleadapter.items.AbstractFlexibleItem; -import eu.davidea.flexibleadapter.items.IFilterable; -import eu.davidea.flexibleadapter.items.IFlexible; -import eu.davidea.viewholders.FlexibleViewHolder; - -@AutoInjector(NextcloudTalkApplication.class) -public class BrowserFileItem extends AbstractFlexibleItem implements IFilterable { - @Inject - Context context; - private final BrowserFile browserFile; - private final UserEntity activeUser; - private final SelectionInterface selectionInterface; - private boolean selected; - - public BrowserFileItem(BrowserFile browserFile, UserEntity activeUser, SelectionInterface selectionInterface) { - this.browserFile = browserFile; - this.activeUser = activeUser; - this.selectionInterface = selectionInterface; - NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this); - } - - @Override - public boolean equals(Object o) { - if (o instanceof BrowserFileItem) { - BrowserFileItem inItem = (BrowserFileItem) o; - return browserFile.getPath().equals(inItem.getModel().getPath()); - } - - return false; - } - - public BrowserFile getModel() { - return browserFile; - } - - @Override - public int getLayoutRes() { - return R.layout.rv_item_browser_file; - } - - @Override - public BrowserFileItemViewHolder createViewHolder(View view, FlexibleAdapter adapter) { - return new BrowserFileItemViewHolder(view, adapter); - } - - private boolean isSelected() { - return selected; - } - - private void setSelected(boolean selected) { - this.selected = selected; - } - - @Override - public void bindViewHolder(FlexibleAdapter adapter, - BrowserFileItemViewHolder holder, - int position, - List payloads) { - holder.binding.fileIcon.setController(null); - if (!browserFile.isAllowedToReShare() || browserFile.isEncrypted()) { - holder.itemView.setEnabled(false); - holder.itemView.setAlpha(0.38f); - } else { - holder.itemView.setEnabled(true); - holder.itemView.setAlpha(1.0f); - } - - if (browserFile.isEncrypted()) { - holder.binding.fileEncryptedImageView.setVisibility(View.VISIBLE); - - } else { - holder.binding.fileEncryptedImageView.setVisibility(View.GONE); - } - - if (browserFile.isFavorite()) { - holder.binding.fileFavoriteImageView.setVisibility(View.VISIBLE); - } else { - holder.binding.fileFavoriteImageView.setVisibility(View.GONE); - } - - if (selectionInterface.shouldOnlySelectOneImageFile()) { - if (browserFile.isFile() && browserFile.getMimeType().startsWith("image/")) { - holder.binding.selectFileCheckbox.setVisibility(View.VISIBLE); - } else { - holder.binding.selectFileCheckbox.setVisibility(View.GONE); - } - } else { - holder.binding.selectFileCheckbox.setVisibility(View.VISIBLE); - } - - if (context != null) { - holder - .binding - .fileIcon - .getHierarchy() - .setPlaceholderImage( - AppCompatResources.getDrawable( - context, DrawableUtils.INSTANCE.getDrawableResourceIdForMimeType(browserFile.getMimeType()))); - } - - if (browserFile.getHasPreview()) { - String path = ApiUtils.getUrlForFilePreviewWithRemotePath(activeUser.getBaseUrl(), - browserFile.getPath(), - context.getResources().getDimensionPixelSize(R.dimen.small_item_height)); - - if (path.length() > 0) { - DraweeController draweeController = Fresco.newDraweeControllerBuilder() - .setAutoPlayAnimations(true) - .setImageRequest(DisplayUtils.getImageRequestForUrl(path, null)) - .build(); - holder.binding.fileIcon.setController(draweeController); - } - } - - holder.binding.filenameTextView.setText(browserFile.getDisplayName()); - holder.binding.fileModifiedInfo.setText(String.format(context.getString(R.string.nc_last_modified), - Formatter.formatShortFileSize(context, browserFile.getSize()), - DateUtils.INSTANCE.getLocalDateTimeStringFromTimestamp(browserFile.getModifiedTimestamp()))); - setSelected(selectionInterface.isPathSelected(browserFile.getPath())); - holder.binding.selectFileCheckbox.setChecked(isSelected()); - - if (!browserFile.isEncrypted()) { - holder.binding.selectFileCheckbox.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (!browserFile.isAllowedToReShare()) { - ((CheckBox) v).setChecked(false); - Toast.makeText( - context, - context.getResources().getString(R.string.nc_file_browser_reshare_forbidden), - Toast.LENGTH_LONG) - .show(); - } else if (((CheckBox) v).isChecked() != isSelected()) { - setSelected(((CheckBox) v).isChecked()); - selectionInterface.toggleBrowserItemSelection(browserFile.getPath()); - } - } - }); - } - - holder.binding.filenameTextView.setSelected(true); - holder.binding.fileModifiedInfo.setSelected(true); - } - - @Override - public boolean filter(String constraint) { - return false; - } - - static class BrowserFileItemViewHolder extends FlexibleViewHolder { - - RvItemBrowserFileOldBinding binding; - - BrowserFileItemViewHolder(View view, FlexibleAdapter adapter) { - super(view, adapter); - binding = RvItemBrowserFileOldBinding.bind(view); - } - } -} diff --git a/app/src/main/java/com/nextcloud/talk/components/filebrowser/controllers/BrowserController.kt b/app/src/main/java/com/nextcloud/talk/components/filebrowser/controllers/BrowserController.kt deleted file mode 100644 index d7fcc0ba1..000000000 --- a/app/src/main/java/com/nextcloud/talk/components/filebrowser/controllers/BrowserController.kt +++ /dev/null @@ -1,344 +0,0 @@ -/* - * Nextcloud Talk application - * - * @author Mario Danic - * @author Andy Scherzinger - * Copyright (C) 2021 Andy Scherzinger - * Copyright (C) 2017-2018 Mario Danic - * - * This program 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 . - */ -package com.nextcloud.talk.components.filebrowser.controllers - -import android.annotation.SuppressLint -import android.os.Bundle -import android.os.Parcelable -import android.util.Log -import android.view.Menu -import android.view.MenuInflater -import android.view.MenuItem -import android.view.View -import androidx.fragment.app.DialogFragment -import androidx.recyclerview.widget.RecyclerView -import androidx.swiperefreshlayout.widget.SwipeRefreshLayout -import autodagger.AutoInjector -import com.nextcloud.talk.R -import com.nextcloud.talk.activities.MainActivity -import com.nextcloud.talk.application.NextcloudTalkApplication -import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication -import com.nextcloud.talk.components.filebrowser.adapters.items.BrowserFileItem -import com.nextcloud.talk.components.filebrowser.interfaces.ListingInterface -import com.nextcloud.talk.components.filebrowser.models.BrowserFile -import com.nextcloud.talk.components.filebrowser.models.DavResponse -import com.nextcloud.talk.components.filebrowser.operations.DavListing -import com.nextcloud.talk.components.filebrowser.operations.ListingAbstractClass -import com.nextcloud.talk.controllers.base.NewBaseController -import com.nextcloud.talk.controllers.util.viewBinding -import com.nextcloud.talk.databinding.ControllerBrowserBinding -import com.nextcloud.talk.interfaces.SelectionInterface -import com.nextcloud.talk.models.database.UserEntity -import com.nextcloud.talk.ui.dialog.SortingOrderDialogFragment -import com.nextcloud.talk.utils.DisplayUtils -import com.nextcloud.talk.utils.LegacyFileSortOrder -import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_BROWSER_TYPE -import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_USER_ENTITY -import com.nextcloud.talk.utils.database.user.UserUtils -import eu.davidea.flexibleadapter.FlexibleAdapter -import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager -import kotlinx.android.parcel.Parcelize -import net.orange_box.storebox.listeners.OnPreferenceValueChangedListener -import okhttp3.OkHttpClient -import org.parceler.Parcels -import java.io.File -import java.util.ArrayList -import java.util.Collections -import java.util.TreeSet -import javax.inject.Inject - -@AutoInjector(NextcloudTalkApplication::class) -abstract class BrowserController(args: Bundle) : - NewBaseController( - R.layout.controller_browser, - args - ), - ListingInterface, - FlexibleAdapter.OnItemClickListener, - SwipeRefreshLayout.OnRefreshListener, - SelectionInterface { - - private val binding: ControllerBrowserBinding by viewBinding(ControllerBrowserBinding::bind) - - @JvmField - protected val selectedPaths: MutableSet - - @JvmField - @Inject - var userUtils: UserUtils? = null - - @JvmField - @Inject - var okHttpClient: OkHttpClient? = null - - @JvmField - protected var activeUser: UserEntity - - private var filesSelectionDoneMenuItem: MenuItem? = null - private var layoutManager: RecyclerView.LayoutManager? = null - private var adapter: FlexibleAdapter? = null - private var recyclerViewItems: List = ArrayList() - private var listingAbstractClass: ListingAbstractClass? = null - private val browserType: BrowserType - private var currentPath: String - - private var sortingChangeListener: OnPreferenceValueChangedListener? = null - - override fun onViewBound(view: View) { - super.onViewBound(view) - if (adapter == null) { - adapter = FlexibleAdapter(recyclerViewItems, context, false) - } - - appPreferences!!.registerSortingChangeListener( - SortingChangeListener(this).also { - sortingChangeListener = it - } - ) - - changeEnabledStatusForBarItems(true) - prepareViews() - } - - abstract fun onFileSelectionDone() - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { - super.onCreateOptionsMenu(menu, inflater) - inflater.inflate(R.menu.menu_share_files, menu) - filesSelectionDoneMenuItem = menu.findItem(R.id.files_selection_done) - filesSelectionDoneMenuItem?.isVisible = selectedPaths.size > 0 - } - - override fun onOptionsItemSelected(item: MenuItem): Boolean { - if (item.itemId == R.id.files_selection_done) { - onFileSelectionDone() - return true - } - return super.onOptionsItemSelected(item) - } - - override fun onAttach(view: View) { - super.onAttach(view) - - binding.pathNavigation.menu.findItem(R.id.action_back)?.setOnMenuItemClickListener { goBack() } - binding.sortButton.setOnClickListener { changeSorting() } - - binding.sortButton.setText( - DisplayUtils.getSortOrderStringId(LegacyFileSortOrder.getFileSortOrder(appPreferences?.sorting)) - ) - - refreshCurrentPath() - } - - override fun onRefresh() { - refreshCurrentPath() - } - - fun changeSorting() { - val newFragment: DialogFragment = SortingOrderDialogFragment - .newInstance(LegacyFileSortOrder.getFileSortOrder(appPreferences?.sorting)) - newFragment.show( - (activity as MainActivity?)!!.supportFragmentManager, - SortingOrderDialogFragment.SORTING_ORDER_FRAGMENT - ) - } - - public override fun onDestroy() { - super.onDestroy() - listingAbstractClass!!.tearDown() - } - - override val title: String - get() = - currentPath - - fun goBack(): Boolean { - fetchPath(File(currentPath).parent) - return true - } - - fun refreshCurrentPath(): Boolean { - fetchPath(currentPath) - return true - } - - @SuppressLint("RestrictedApi") - private fun changeEnabledStatusForBarItems(shouldBeEnabled: Boolean) { - binding.pathNavigation.menu.findItem(R.id.action_back)?.isEnabled = shouldBeEnabled && currentPath != "/" - } - - private fun fetchPath(path: String) { - listingAbstractClass!!.cancelAllJobs() - changeEnabledStatusForBarItems(false) - listingAbstractClass!!.getFiles( - path, - activeUser, - if (BrowserType.DAV_BROWSER == browserType) okHttpClient else null - ) - } - - override fun listingResult(davResponse: DavResponse) { - recyclerViewItems = ArrayList() - if (davResponse.getData() != null) { - val objectList = davResponse.getData() as List - currentPath = objectList[0].path!! - if (activity != null) { - activity!!.runOnUiThread { setTitle() } - } - for (i in 1 until objectList.size) { - (recyclerViewItems as ArrayList).add(BrowserFileItem(objectList[i], activeUser, this)) - } - } - - LegacyFileSortOrder.getFileSortOrder(appPreferences?.sorting).sortCloudFiles(recyclerViewItems) - - if (activity != null) { - activity!!.runOnUiThread { - adapter!!.clear() - adapter!!.addItems(0, recyclerViewItems) - adapter!!.notifyDataSetChanged() - changeEnabledStatusForBarItems(true) - } - } - - binding.swipeRefreshList.isRefreshing = false - } - - private fun shouldPathBeSelectedDueToParent(currentPath: String): Boolean { - if (selectedPaths.size > 0) { - var file = File(currentPath) - if (file.parent != "/") { - while (file.parent != null) { - var parent = file.parent!! - if (File(file.parent!!).parent != null) { - parent += "/" - } - if (selectedPaths.contains(parent)) { - return true - } - file = File(file.parent!!) - } - } - } - return false - } - - private fun checkAndRemoveAnySelectedParents(currentPath: String) { - var file = File(currentPath) - selectedPaths.remove(currentPath) - while (file.parent != null) { - selectedPaths.remove(file.parent!! + "/") - file = File(file.parent!!) - } - if (activity != null) { - activity!!.runOnUiThread { - adapter!!.notifyDataSetChanged() - } - } - } - - override fun onItemClick(view: View, position: Int): Boolean { - val browserFile = (adapter!!.getItem(position) as BrowserFileItem).model - if ("inode/directory" == browserFile.mimeType) { - fetchPath(browserFile.path!!) - return true - } - return false - } - - private fun prepareViews() { - if (activity != null) { - layoutManager = SmoothScrollLinearLayoutManager(activity) - binding.recyclerView.layoutManager = layoutManager - binding.recyclerView.setHasFixedSize(true) - binding.recyclerView.adapter = adapter - adapter!!.addListener(this) - - binding.swipeRefreshList.setOnRefreshListener(this) - binding.swipeRefreshList.setColorSchemeResources(R.color.colorPrimary) - binding.swipeRefreshList.setProgressBackgroundColorSchemeResource(R.color.refresh_spinner_background) - } - } - - @SuppressLint("RestrictedApi") - override fun toggleBrowserItemSelection(path: String) { - if (selectedPaths.contains(path) || shouldPathBeSelectedDueToParent(path)) { - checkAndRemoveAnySelectedParents(path) - } else { - // TOOD: if it's a folder, remove all the children we added manually - selectedPaths.add(path) - } - filesSelectionDoneMenuItem?.isVisible = selectedPaths.size > 0 - } - - override fun isPathSelected(path: String): Boolean { - return selectedPaths.contains(path) || shouldPathBeSelectedDueToParent(path) - } - - abstract override fun shouldOnlySelectOneImageFile(): Boolean - - @Parcelize - enum class BrowserType : Parcelable { - FILE_BROWSER, DAV_BROWSER - } - - init { - setHasOptionsMenu(true) - sharedApplication!!.componentApplication.inject(this) - browserType = Parcels.unwrap(args.getParcelable(KEY_BROWSER_TYPE)) - activeUser = Parcels.unwrap(args.getParcelable(KEY_USER_ENTITY)) - currentPath = "/" - if (BrowserType.DAV_BROWSER == browserType) { - listingAbstractClass = DavListing(this) - } // else { - // listingAbstractClass = new LocalListing(this); - // } - selectedPaths = Collections.synchronizedSet(TreeSet()) - } - - @Suppress("Detekt.TooGenericExceptionCaught") - private class SortingChangeListener(private val browserController: BrowserController) : - OnPreferenceValueChangedListener { - override fun onChanged(newValue: String) { - try { - val sortOrder = LegacyFileSortOrder.getFileSortOrder(newValue) - - browserController.binding.sortButton.setText(DisplayUtils.getSortOrderStringId(sortOrder)) - browserController.recyclerViewItems = sortOrder.sortCloudFiles(browserController.recyclerViewItems) - - if (browserController.activity != null) { - browserController.activity!!.runOnUiThread { - browserController.adapter!!.updateDataSet(browserController.recyclerViewItems) - browserController.changeEnabledStatusForBarItems(true) - } - } - } catch (npe: NullPointerException) { - // view binding can be null - // since this is called asynchronously and UI might have been destroyed in the meantime - Log.i(BrowserController.TAG, "UI destroyed - view binding already gone") - } - } - } - - companion object { - private const val TAG = "BrowserController" - } -} diff --git a/app/src/main/java/com/nextcloud/talk/components/filebrowser/controllers/BrowserForSharingController.java b/app/src/main/java/com/nextcloud/talk/components/filebrowser/controllers/BrowserForSharingController.java deleted file mode 100644 index f0b0e640a..000000000 --- a/app/src/main/java/com/nextcloud/talk/components/filebrowser/controllers/BrowserForSharingController.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Nextcloud Talk application - * - * @author Tobias Kaminsky - * Copyright (C) 2021 Tobias Kaminsky - * - * This program 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 . - */ - -package com.nextcloud.talk.components.filebrowser.controllers; - -import android.os.Bundle; - -import com.nextcloud.talk.jobs.ShareOperationWorker; -import com.nextcloud.talk.utils.bundle.BundleKeys; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import androidx.work.Data; -import androidx.work.OneTimeWorkRequest; -import androidx.work.WorkManager; - -public class BrowserForSharingController extends BrowserController { - private final String roomToken; - - public BrowserForSharingController(Bundle args) { - super(args); - - roomToken = args.getString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN()); - } - - @Override - public void onFileSelectionDone() { - synchronized (selectedPaths) { - Iterator iterator = selectedPaths.iterator(); - - List paths = new ArrayList<>(); - Data data; - OneTimeWorkRequest shareWorker; - - while (iterator.hasNext()) { - String path = iterator.next(); - paths.add(path); - iterator.remove(); - if (paths.size() == 10 || !iterator.hasNext()) { - data = new Data.Builder() - .putLong(BundleKeys.INSTANCE.getKEY_INTERNAL_USER_ID(), activeUser.getId()) - .putString(BundleKeys.INSTANCE.getKEY_ROOM_TOKEN(), roomToken) - .putStringArray(BundleKeys.INSTANCE.getKEY_FILE_PATHS(), paths.toArray(new String[0])) - .build(); - shareWorker = new OneTimeWorkRequest.Builder(ShareOperationWorker.class) - .setInputData(data) - .build(); - WorkManager.getInstance().enqueue(shareWorker); - paths = new ArrayList<>(); - } - } - } - - getRouter().popCurrentController(); - } - - @Override - public boolean shouldOnlySelectOneImageFile() { - return false; - } -} diff --git a/app/src/main/java/com/nextcloud/talk/components/filebrowser/interfaces/ListingInterface.java b/app/src/main/java/com/nextcloud/talk/components/filebrowser/interfaces/ListingInterface.java deleted file mode 100644 index c953d8a59..000000000 --- a/app/src/main/java/com/nextcloud/talk/components/filebrowser/interfaces/ListingInterface.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Nextcloud Talk application - * - * @author Mario Danic - * Copyright (C) 2017-2018 Mario Danic - * - * This program 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 . - */ - -package com.nextcloud.talk.components.filebrowser.interfaces; - -import com.nextcloud.talk.components.filebrowser.models.DavResponse; - -public interface ListingInterface { - void listingResult(DavResponse davResponse); -} diff --git a/app/src/main/java/com/nextcloud/talk/components/filebrowser/operations/DavListing.java b/app/src/main/java/com/nextcloud/talk/components/filebrowser/operations/DavListing.java deleted file mode 100644 index dc69a1422..000000000 --- a/app/src/main/java/com/nextcloud/talk/components/filebrowser/operations/DavListing.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Nextcloud Talk application - * - * @author Mario Danic - * @author Andy Scherzinger - * Copyright (C) 2022 Andy Scherzinger - * Copyright (C) 2017-2018 Mario Danic - * - * This program 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 . - */ - -package com.nextcloud.talk.components.filebrowser.operations; - -import android.util.Log; - -import com.nextcloud.talk.components.filebrowser.interfaces.ListingInterface; -import com.nextcloud.talk.components.filebrowser.models.DavResponse; -import com.nextcloud.talk.components.filebrowser.webdav.ReadFilesystemOperation; -import com.nextcloud.talk.models.database.UserEntity; - -import java.util.concurrent.Callable; - -import androidx.annotation.Nullable; -import io.reactivex.Single; -import io.reactivex.SingleObserver; -import io.reactivex.annotations.NonNull; -import io.reactivex.disposables.Disposable; -import io.reactivex.schedulers.Schedulers; -import okhttp3.OkHttpClient; - -public class DavListing extends ListingAbstractClass { - private static final String TAG = DavListing.class.getSimpleName(); - - private DavResponse davResponse = new DavResponse(); - - public DavListing(ListingInterface listingInterface) { - super(listingInterface); - } - - @Override - public void getFiles(String path, UserEntity currentUser, @Nullable OkHttpClient okHttpClient) { - Single.fromCallable(new Callable() { - @Override - public ReadFilesystemOperation call() { - return new ReadFilesystemOperation(okHttpClient, currentUser, path, 1); - } - }).subscribeOn(Schedulers.io()) - .subscribe(new SingleObserver() { - @Override - public void onSubscribe(@NonNull Disposable d) { - - } - - @Override - public void onSuccess(@NonNull ReadFilesystemOperation readFilesystemOperation) { - davResponse = readFilesystemOperation.readRemotePath(); - try { - listingInterface.listingResult(davResponse); - } catch (NullPointerException npe) { - Log.i(TAG, "Error loading remote folder - due to view already been terminated", npe); - } - } - - @Override - public void onError(@NonNull Throwable e) { - listingInterface.listingResult(davResponse); - } - }); - } -} diff --git a/app/src/main/java/com/nextcloud/talk/components/filebrowser/operations/ListingAbstractClass.java b/app/src/main/java/com/nextcloud/talk/components/filebrowser/operations/ListingAbstractClass.java deleted file mode 100644 index b01bc31cc..000000000 --- a/app/src/main/java/com/nextcloud/talk/components/filebrowser/operations/ListingAbstractClass.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Nextcloud Talk application - * - * @author Mario Danic - * Copyright (C) 2017-2018 Mario Danic - * - * This program 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 . - */ - -package com.nextcloud.talk.components.filebrowser.operations; - -import android.os.Handler; -import androidx.annotation.Nullable; -import com.nextcloud.talk.components.filebrowser.interfaces.ListingInterface; -import com.nextcloud.talk.models.database.UserEntity; -import okhttp3.OkHttpClient; - -public abstract class ListingAbstractClass { - Handler handler; - ListingInterface listingInterface; - - ListingAbstractClass(ListingInterface listingInterface) { - handler = new Handler(); - this.listingInterface = listingInterface; - } - - public abstract void getFiles(String path, UserEntity currentUser, @Nullable OkHttpClient okHttpClient); - - public void cancelAllJobs() { - handler.removeCallbacksAndMessages(null); - } - - public void tearDown() { - cancelAllJobs(); - handler = null; - } -} diff --git a/app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt b/app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt index 15fbbe98f..18631506a 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt +++ b/app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt @@ -91,7 +91,6 @@ import autodagger.AutoInjector import coil.load import com.bluelinelabs.conductor.RouterTransaction import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler -import com.bluelinelabs.conductor.changehandler.VerticalChangeHandler import com.facebook.common.executors.UiThreadImmediateExecutorService import com.facebook.common.references.CloseableReference import com.facebook.datasource.DataSource @@ -121,14 +120,13 @@ import com.nextcloud.talk.adapters.messages.VoiceMessageInterface import com.nextcloud.talk.api.NcApi import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.callbacks.MentionAutocompleteCallback -import com.nextcloud.talk.components.filebrowser.controllers.BrowserController -import com.nextcloud.talk.components.filebrowser.controllers.BrowserForSharingController import com.nextcloud.talk.controllers.base.NewBaseController import com.nextcloud.talk.controllers.util.viewBinding import com.nextcloud.talk.databinding.ControllerChatBinding import com.nextcloud.talk.events.UserMentionClickEvent import com.nextcloud.talk.events.WebSocketCommunicationEvent import com.nextcloud.talk.jobs.DownloadFileToCacheWorker +import com.nextcloud.talk.jobs.ShareOperationWorker import com.nextcloud.talk.jobs.UploadAndShareFilesWorker import com.nextcloud.talk.messagesearch.MessageSearchActivity import com.nextcloud.talk.models.database.CapabilitiesUtil @@ -143,6 +141,7 @@ import com.nextcloud.talk.models.json.conversations.RoomsOverall import com.nextcloud.talk.models.json.generic.GenericOverall import com.nextcloud.talk.models.json.mention.Mention import com.nextcloud.talk.presenters.MentionAutocompletePresenter +import com.nextcloud.talk.remotefilebrowser.activities.RemoteFileBrowserActivity import com.nextcloud.talk.shareditems.activities.SharedItemsActivity import com.nextcloud.talk.ui.bottom.sheet.ProfileBottomSheet import com.nextcloud.talk.ui.dialog.AttachmentDialog @@ -164,6 +163,8 @@ import com.nextcloud.talk.utils.UriUtils import com.nextcloud.talk.utils.bundle.BundleKeys import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ACTIVE_CONVERSATION import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_CONVERSATION_NAME +import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_FILE_PATHS +import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_INTERNAL_USER_ID import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_ID import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_USER_ENTITY @@ -1352,6 +1353,33 @@ class ChatController(args: Bundle) : } when (requestCode) { + REQUEST_CODE_SELECT_REMOTE_FILES -> { + val pathList = intent?.getStringArrayListExtra(RemoteFileBrowserActivity.EXTRA_SELECTED_PATHS) + if (pathList?.size!! >= 1) { + var paths: MutableList = ArrayList() + var data: Data + var shareWorker: OneTimeWorkRequest + val iterator = pathList.iterator() + + while (iterator.hasNext()) { + val path = iterator.next() + paths.add(path) + iterator.remove() + if (paths.size == 10 || !iterator.hasNext()) { + data = Data.Builder() + .putLong(KEY_INTERNAL_USER_ID, conversationUser!!.id) + .putString(KEY_ROOM_TOKEN, roomToken) + .putStringArray(KEY_FILE_PATHS, paths.toTypedArray()) + .build() + shareWorker = OneTimeWorkRequest.Builder(ShareOperationWorker::class.java) + .setInputData(data) + .build() + WorkManager.getInstance().enqueue(shareWorker) + paths = java.util.ArrayList() + } + } + } + } REQUEST_CODE_CHOOSE_FILE -> { try { checkNotNull(intent) @@ -1606,16 +1634,9 @@ class ChatController(args: Bundle) : requestReadContacts() } - fun showBrowserScreen(browserType: BrowserController.BrowserType) { - val bundle = Bundle() - bundle.putParcelable(BundleKeys.KEY_BROWSER_TYPE, Parcels.wrap(browserType)) - bundle.putParcelable(BundleKeys.KEY_USER_ENTITY, Parcels.wrap(conversationUser)) - bundle.putString(KEY_ROOM_TOKEN, roomToken) - router.pushController( - RouterTransaction.with(BrowserForSharingController(bundle)) - .pushChangeHandler(VerticalChangeHandler()) - .popChangeHandler(VerticalChangeHandler()) - ) + fun showBrowserScreen() { + val sharingFileBrowserIntent = Intent(activity, RemoteFileBrowserActivity::class.java) + startActivityForResult(sharingFileBrowserIntent, REQUEST_CODE_SELECT_REMOTE_FILES) } fun showShareLocationScreen() { @@ -3142,6 +3163,7 @@ class ChatController(args: Bundle) : private const val REQUEST_READ_CONTACT_PERMISSION = 234 private const val REQUEST_CAMERA_PERMISSION = 223 private const val REQUEST_CODE_PICK_CAMERA: Int = 333 + private const val REQUEST_CODE_SELECT_REMOTE_FILES = 888 private const val OBJECT_MESSAGE: String = "{object}" private const val MINIMUM_VOICE_RECORD_DURATION: Int = 1000 private const val VOICE_RECORD_CANCEL_SLIDER_X: Int = -50 diff --git a/app/src/main/java/com/nextcloud/talk/controllers/ProfileController.kt b/app/src/main/java/com/nextcloud/talk/controllers/ProfileController.kt index beb6fb073..3616efee1 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/ProfileController.kt +++ b/app/src/main/java/com/nextcloud/talk/controllers/ProfileController.kt @@ -487,7 +487,7 @@ class ProfileController : NewBaseController(R.layout.controller_profile) { val avatarIntent = Intent(activity, RemoteFileBrowserActivity::class.java) avatarIntent.putExtras(bundle) - startActivityForResult(avatarIntent, RemoteFileBrowserActivity.REQUEST_CODE_SELECT_AVATAR) + startActivityForResult(avatarIntent, REQUEST_CODE_SELECT_REMOTE_FILES) } fun handleAvatar(remotePath: String?) { @@ -547,11 +547,13 @@ class ProfileController : NewBaseController(R.layout.controller_profile) { if (resultCode == Activity.RESULT_OK) { if (requestCode == REQUEST_CODE_IMAGE_PICKER) { uploadAvatar(getFile(intent)) - } else { + } else if (requestCode == REQUEST_CODE_SELECT_REMOTE_FILES) { val pathList = intent?.getStringArrayListExtra(RemoteFileBrowserActivity.EXTRA_SELECTED_PATHS) if (pathList?.size!! >= 1) { handleAvatar(pathList[0]) } + } else { + Log.w(TAG, "Unknown intent request code") } } else if (resultCode == ImagePicker.RESULT_ERROR) { Toast.makeText(activity, getError(intent), Toast.LENGTH_SHORT).show() @@ -806,6 +808,7 @@ class ProfileController : NewBaseController(R.layout.controller_profile) { companion object { private const val TAG: String = "ProfileController" + private const val REQUEST_CODE_SELECT_REMOTE_FILES = 22 private const val DEFAULT_CACHE_SIZE: Int = 20 private const val DEFAULT_RETRIES: Long = 3 private const val MAX_SIZE: Int = 1024 diff --git a/app/src/main/java/com/nextcloud/talk/interfaces/SelectionInterface.kt b/app/src/main/java/com/nextcloud/talk/interfaces/SelectionInterface.kt deleted file mode 100644 index d5b20d191..000000000 --- a/app/src/main/java/com/nextcloud/talk/interfaces/SelectionInterface.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Nextcloud Talk application - * - * @author Mario Danic - * Copyright (C) 2017-2018 Mario Danic - * - * This program 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 . - */ - -package com.nextcloud.talk.interfaces - -@Deprecated("To be replaced with com.nextcloud.talk.remotefilebrowser.SelectionInterface") -interface SelectionInterface { - fun toggleBrowserItemSelection(path: String) - - fun isPathSelected(path: String): Boolean - - fun shouldOnlySelectOneImageFile(): Boolean -} diff --git a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/activities/RemoteFileBrowserActivity.kt b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/activities/RemoteFileBrowserActivity.kt index 755380a6f..53a6372e9 100644 --- a/app/src/main/java/com/nextcloud/talk/remotefilebrowser/activities/RemoteFileBrowserActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/remotefilebrowser/activities/RemoteFileBrowserActivity.kt @@ -236,15 +236,13 @@ class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, Swipe viewModel.loadItems() } + override fun isPathSelected(path: String): Boolean { + return viewModel.isPathSelected(path) + } + companion object { private val TAG = RemoteFileBrowserActivity::class.simpleName const val SPAN_COUNT: Int = 4 const val EXTRA_SELECTED_PATHS = "EXTRA_SELECTED_PATH" - const val REQUEST_CODE_SELECT_AVATAR = 22 - } - - override fun isPathSelected(path: String): Boolean { - // TODO figure out a better way to do this. Narrower interface? - return viewModel.isPathSelected(path) } } diff --git a/app/src/main/java/com/nextcloud/talk/ui/dialog/AttachmentDialog.kt b/app/src/main/java/com/nextcloud/talk/ui/dialog/AttachmentDialog.kt index 77c5acbfb..c88db9ca6 100644 --- a/app/src/main/java/com/nextcloud/talk/ui/dialog/AttachmentDialog.kt +++ b/app/src/main/java/com/nextcloud/talk/ui/dialog/AttachmentDialog.kt @@ -29,7 +29,6 @@ import android.view.ViewGroup import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetDialog import com.nextcloud.talk.R -import com.nextcloud.talk.components.filebrowser.controllers.BrowserController import com.nextcloud.talk.controllers.ChatController import com.nextcloud.talk.databinding.DialogAttachmentBinding import com.nextcloud.talk.models.database.CapabilitiesUtil @@ -76,7 +75,7 @@ class AttachmentDialog(val activity: Activity, var chatController: ChatControlle } dialogAttachmentBinding.menuAttachFileFromCloud.setOnClickListener { - chatController.showBrowserScreen(BrowserController.BrowserType.DAV_BROWSER) + chatController.showBrowserScreen() dismiss() } diff --git a/app/src/main/java/com/nextcloud/talk/ui/dialog/SortingOrderDialogFragment.java b/app/src/main/java/com/nextcloud/talk/ui/dialog/SortingOrderDialogFragment.java index a8c901b90..f2d5c8d66 100644 --- a/app/src/main/java/com/nextcloud/talk/ui/dialog/SortingOrderDialogFragment.java +++ b/app/src/main/java/com/nextcloud/talk/ui/dialog/SortingOrderDialogFragment.java @@ -37,7 +37,6 @@ import com.nextcloud.talk.R; import com.nextcloud.talk.application.NextcloudTalkApplication; import com.nextcloud.talk.databinding.SortingOrderFragmentBinding; import com.nextcloud.talk.utils.FileSortOrder; -import com.nextcloud.talk.utils.LegacyFileSortOrder; import com.nextcloud.talk.utils.preferences.AppPreferences; import org.jetbrains.annotations.NotNull; @@ -70,17 +69,6 @@ public class SortingOrderDialogFragment extends DialogFragment implements View.O private View[] taggedViews; private String currentSortOrderName; - @Deprecated - public static SortingOrderDialogFragment newInstance(LegacyFileSortOrder sortOrder) { - SortingOrderDialogFragment dialogFragment = new SortingOrderDialogFragment(); - - Bundle args = new Bundle(); - args.putString(KEY_SORT_ORDER, sortOrder.name); - dialogFragment.setArguments(args); - - return dialogFragment; - } - public static SortingOrderDialogFragment newInstance(@NotNull FileSortOrder sortOrder) { SortingOrderDialogFragment dialogFragment = new SortingOrderDialogFragment(); diff --git a/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.java b/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.java index c5baf6ffd..526b09c04 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.java +++ b/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.java @@ -110,12 +110,12 @@ import androidx.core.graphics.ColorUtils; import androidx.core.graphics.drawable.DrawableCompat; import androidx.emoji.text.EmojiCompat; -import static com.nextcloud.talk.utils.LegacyFileSortOrder.sort_a_to_z_id; -import static com.nextcloud.talk.utils.LegacyFileSortOrder.sort_big_to_small_id; -import static com.nextcloud.talk.utils.LegacyFileSortOrder.sort_new_to_old_id; -import static com.nextcloud.talk.utils.LegacyFileSortOrder.sort_old_to_new_id; -import static com.nextcloud.talk.utils.LegacyFileSortOrder.sort_small_to_big_id; -import static com.nextcloud.talk.utils.LegacyFileSortOrder.sort_z_to_a_id; +import static com.nextcloud.talk.utils.FileSortOrder.sort_a_to_z_id; +import static com.nextcloud.talk.utils.FileSortOrder.sort_big_to_small_id; +import static com.nextcloud.talk.utils.FileSortOrder.sort_new_to_old_id; +import static com.nextcloud.talk.utils.FileSortOrder.sort_old_to_new_id; +import static com.nextcloud.talk.utils.FileSortOrder.sort_small_to_big_id; +import static com.nextcloud.talk.utils.FileSortOrder.sort_z_to_a_id; public class DisplayUtils { @@ -617,26 +617,6 @@ public class DisplayUtils { targetView.setController(newController); } - @Deprecated - public static @StringRes - int getSortOrderStringId(LegacyFileSortOrder sortOrder) { - switch (sortOrder.name) { - case sort_z_to_a_id: - return R.string.menu_item_sort_by_name_z_a; - case sort_new_to_old_id: - return R.string.menu_item_sort_by_date_newest_first; - case sort_old_to_new_id: - return R.string.menu_item_sort_by_date_oldest_first; - case sort_big_to_small_id: - return R.string.menu_item_sort_by_size_biggest_first; - case sort_small_to_big_id: - return R.string.menu_item_sort_by_size_smallest_first; - case sort_a_to_z_id: - default: - return R.string.menu_item_sort_by_name_a_z; - } - } - public static @StringRes int getSortOrderStringId(FileSortOrder sortOrder) { switch (sortOrder.getName()) { diff --git a/app/src/main/java/com/nextcloud/talk/utils/FileSortOrder.kt b/app/src/main/java/com/nextcloud/talk/utils/FileSortOrder.kt index 9519874a7..53511b7a6 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/FileSortOrder.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/FileSortOrder.kt @@ -25,9 +25,6 @@ import android.text.TextUtils import com.nextcloud.talk.remotefilebrowser.model.RemoteFileBrowserItem import java.util.Collections -/** - * Sort order - */ open class FileSortOrder(var name: String, var isAscending: Boolean) { companion object { const val sort_a_to_z_id = "sort_a_to_z" diff --git a/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByDate.kt b/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByDate.kt index c6d66d6ed..f7bcc5e05 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByDate.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByDate.kt @@ -24,9 +24,6 @@ package com.nextcloud.talk.utils import com.nextcloud.talk.remotefilebrowser.model.RemoteFileBrowserItem import java.util.Collections -/** - * Created by srkunze on 28.08.17. - */ class FileSortOrderByDate internal constructor(name: String, ascending: Boolean) : FileSortOrder(name, ascending) { /** * Sorts list by Date. diff --git a/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByName.kt b/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByName.kt index 8062b8a8d..4c5535938 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByName.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderByName.kt @@ -25,9 +25,6 @@ import com.nextcloud.talk.remotefilebrowser.model.RemoteFileBrowserItem import third_parties.daveKoeller.AlphanumComparator import java.util.Collections -/** - * Created by srkunze on 28.08.17. - */ class FileSortOrderByName internal constructor(name: String, ascending: Boolean) : FileSortOrder(name, ascending) { /** * Sorts list by Name. @@ -46,13 +43,14 @@ class FileSortOrderByName internal constructor(name: String, ascending: Boolean) override fun compare(left: RemoteFileBrowserItem, right: RemoteFileBrowserItem): Int { return if (!left.isFile && !right.isFile) { - return multiplier * AlphanumComparator().compare(left, right) + return multiplier * AlphanumComparator() + .compareRemoteFileBrowserItem(left, right) } else if (!left.isFile) { -1 } else if (!right.isFile) { 1 } else { - multiplier * AlphanumComparator().compare(left, right) + multiplier * AlphanumComparator().compareRemoteFileBrowserItem(left, right) } } } diff --git a/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderBySize.kt b/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderBySize.kt index d0390251d..9beab94a4 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderBySize.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/FileSortOrderBySize.kt @@ -24,9 +24,6 @@ package com.nextcloud.talk.utils import com.nextcloud.talk.remotefilebrowser.model.RemoteFileBrowserItem import java.util.Collections -/** - * Sorts files by sizes - */ class FileSortOrderBySize internal constructor(name: String, ascending: Boolean) : FileSortOrder(name, ascending) { /** * Sorts list by Size. diff --git a/app/src/main/java/com/nextcloud/talk/utils/LegacyFileSortOrder.java b/app/src/main/java/com/nextcloud/talk/utils/LegacyFileSortOrder.java deleted file mode 100644 index ada429d78..000000000 --- a/app/src/main/java/com/nextcloud/talk/utils/LegacyFileSortOrder.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Nextcloud Talk application - * - * @author Sven R. Kunze - * @author Andy Scherzinger - * Copyright (C) 2021 Andy Scherzinger - * Copyright (C) 2017 Sven R. Kunze - * - * This program 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 . - */ - -package com.nextcloud.talk.utils; - -import android.text.TextUtils; - -import com.nextcloud.talk.components.filebrowser.adapters.items.BrowserFileItem; - -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import androidx.annotation.Nullable; - -/** - * Sort order - */ -@Deprecated -public class LegacyFileSortOrder { - public static final String sort_a_to_z_id = "sort_a_to_z"; - public static final String sort_z_to_a_id = "sort_z_to_a"; - public static final String sort_old_to_new_id = "sort_old_to_new"; - public static final String sort_new_to_old_id = "sort_new_to_old"; - public static final String sort_small_to_big_id = "sort_small_to_big"; - public static final String sort_big_to_small_id = "sort_big_to_small"; - - public static final LegacyFileSortOrder sort_a_to_z = new LegacyFileSortOrderByName(sort_a_to_z_id, true); - public static final LegacyFileSortOrder sort_z_to_a = new LegacyFileSortOrderByName(sort_z_to_a_id, false); - public static final LegacyFileSortOrder sort_old_to_new = new LegacyFileSortOrderByDate(sort_old_to_new_id, true); - public static final LegacyFileSortOrder sort_new_to_old = new LegacyFileSortOrderByDate(sort_new_to_old_id, false); - public static final LegacyFileSortOrder sort_small_to_big = new LegacyFileSortOrderBySize(sort_small_to_big_id, true); - public static final LegacyFileSortOrder sort_big_to_small = new LegacyFileSortOrderBySize(sort_big_to_small_id, false); - - public static final Map sortOrders; - - static { - HashMap temp = new HashMap<>(); - temp.put(sort_a_to_z.name, sort_a_to_z); - temp.put(sort_z_to_a.name, sort_z_to_a); - temp.put(sort_old_to_new.name, sort_old_to_new); - temp.put(sort_new_to_old.name, sort_new_to_old); - temp.put(sort_small_to_big.name, sort_small_to_big); - temp.put(sort_big_to_small.name, sort_big_to_small); - - sortOrders = Collections.unmodifiableMap(temp); - } - - public String name; - public boolean isAscending; - - public LegacyFileSortOrder(String name, boolean ascending) { - this.name = name; - isAscending = ascending; - } - - public static LegacyFileSortOrder getFileSortOrder(@Nullable String key) { - if (TextUtils.isEmpty(key) || !sortOrders.containsKey(key)) { - return sort_a_to_z; - } else { - return sortOrders.get(key); - } - } - - public List sortCloudFiles(List files) { - return sortCloudFilesByFavourite(files); - } - - /** - * Sorts list by Favourites. - * - * @param files files to sort - */ - public static List sortCloudFilesByFavourite(List files) { - Collections.sort(files, (o1, o2) -> { - if (o1.getModel().isFavorite() && o2.getModel().isFavorite()) { - return 0; - } else if (o1.getModel().isFavorite()) { - return -1; - } else if (o2.getModel().isFavorite()) { - return 1; - } - return 0; - }); - - return files; - } -} diff --git a/app/src/main/java/com/nextcloud/talk/utils/LegacyFileSortOrderByDate.java b/app/src/main/java/com/nextcloud/talk/utils/LegacyFileSortOrderByDate.java deleted file mode 100644 index 774d27d59..000000000 --- a/app/src/main/java/com/nextcloud/talk/utils/LegacyFileSortOrderByDate.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Nextcloud Talk application - * - * @author Sven R. Kunze - * @author Andy Scherzinger - * Copyright (C) 2021 Andy Scherzinger - * Copyright (C) 2017 Sven R. Kunze - * - * This program 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 . - */ - -package com.nextcloud.talk.utils; - -import com.nextcloud.talk.components.filebrowser.adapters.items.BrowserFileItem; - -import java.util.Collections; -import java.util.List; - -/** - * Created by srkunze on 28.08.17. - */ -@Deprecated -public class LegacyFileSortOrderByDate extends LegacyFileSortOrder { - - LegacyFileSortOrderByDate(String name, boolean ascending) { - super(name, ascending); - } - - /** - * Sorts list by Date. - * - * @param files list of files to sort - */ - public List sortCloudFiles(List files) { - final int multiplier = isAscending ? 1 : -1; - - Collections.sort(files, (o1, o2) -> - multiplier * Long.compare(o1.getModel().getModifiedTimestamp(), o2.getModel().getModifiedTimestamp())); - - return super.sortCloudFiles(files); - } -} diff --git a/app/src/main/java/com/nextcloud/talk/utils/LegacyFileSortOrderByName.java b/app/src/main/java/com/nextcloud/talk/utils/LegacyFileSortOrderByName.java deleted file mode 100644 index d3b7befe7..000000000 --- a/app/src/main/java/com/nextcloud/talk/utils/LegacyFileSortOrderByName.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Nextcloud Talk application - * - * @author Sven R. Kunze - * @author Andy Scherzinger - * Copyright (C) 2021 Andy Scherzinger - * Copyright (C) 2017 Sven R. Kunze - * - * This program 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 . - */ - -package com.nextcloud.talk.utils; - -import com.nextcloud.talk.components.filebrowser.adapters.items.BrowserFileItem; - -import java.util.Collections; -import java.util.List; - -import third_parties.daveKoeller.AlphanumComparator; - -/** - * Created by srkunze on 28.08.17. - */ -@Deprecated -public class LegacyFileSortOrderByName extends LegacyFileSortOrder { - - LegacyFileSortOrderByName(String name, boolean ascending) { - super(name, ascending); - } - - /** - * Sorts list by Name. - * - * @param files files to sort - */ - @SuppressWarnings("Bx") - public List sortCloudFiles(List files) { - final int multiplier = isAscending ? 1 : -1; - - Collections.sort(files, (o1, o2) -> { - if (!o1.getModel().isFile() && !o2.getModel().isFile()) { - return multiplier * new AlphanumComparator().compare(o1, o2); - } else if (!o1.getModel().isFile()) { - return -1; - } else if (!o2.getModel().isFile()) { - return 1; - } - return multiplier * new AlphanumComparator().compare(o1, o2); - }); - - return super.sortCloudFiles(files); - } -} diff --git a/app/src/main/java/com/nextcloud/talk/utils/LegacyFileSortOrderBySize.java b/app/src/main/java/com/nextcloud/talk/utils/LegacyFileSortOrderBySize.java deleted file mode 100644 index 80829c751..000000000 --- a/app/src/main/java/com/nextcloud/talk/utils/LegacyFileSortOrderBySize.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Nextcloud Talk application - * - * @author Sven R. Kunze - * @author Andy Scherzinger - * Copyright (C) 2021 Andy Scherzinger - * Copyright (C) 2017 Sven R. Kunze - * - * This program 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 . - */ - -package com.nextcloud.talk.utils; - -import com.nextcloud.talk.components.filebrowser.adapters.items.BrowserFileItem; - -import java.util.Collections; -import java.util.List; - -/** - * Sorts files by sizes - */ -@Deprecated -public class LegacyFileSortOrderBySize extends LegacyFileSortOrder { - - LegacyFileSortOrderBySize(String name, boolean ascending) { - super(name, ascending); - } - - /** - * Sorts list by Size. - * - * @param files list of files to sort - */ - public List sortCloudFiles(List files) { - final int multiplier = isAscending ? 1 : -1; - - Collections.sort(files, (o1, o2) -> { - if (!o1.getModel().isFile() && !o2.getModel().isFile()) { - return multiplier * Long.compare(o1.getModel().getSize(), o2.getModel().getSize()); - } else if (!o1.getModel().isFile()) { - return -1; - } else if (!o2.getModel().isFile()) { - return 1; - } else { - return multiplier * Long.compare(o1.getModel().getSize(), o2.getModel().getSize()); - } - }); - - return super.sortCloudFiles(files); - } -} diff --git a/app/src/main/java/third_parties/daveKoeller/AlphanumComparator.java b/app/src/main/java/third_parties/daveKoeller/AlphanumComparator.java index af25c47b2..9f7025136 100644 --- a/app/src/main/java/third_parties/daveKoeller/AlphanumComparator.java +++ b/app/src/main/java/third_parties/daveKoeller/AlphanumComparator.java @@ -24,9 +24,8 @@ package third_parties.daveKoeller; -import com.nextcloud.talk.components.filebrowser.adapters.items.BrowserFileItem; +import com.nextcloud.talk.remotefilebrowser.model.RemoteFileBrowserItem; -import java.io.File; import java.io.Serializable; import java.math.BigInteger; import java.text.Collator; @@ -87,9 +86,9 @@ public class AlphanumComparator implements Comparator, Serializable { return chunk.toString(); } - public int compare(BrowserFileItem f1, BrowserFileItem f2) { - String s1 = f1.getModel().getPath(); - String s2 = f2.getModel().getPath(); + public int compareRemoteFileBrowserItem(RemoteFileBrowserItem f1, RemoteFileBrowserItem f2) { + String s1 = f1.getPath(); + String s2 = f2.getPath(); return compare(s1, s2); } diff --git a/app/src/main/res/layout/controller_browser.xml b/app/src/main/res/layout/controller_browser.xml deleted file mode 100644 index 0fc96eb12..000000000 --- a/app/src/main/res/layout/controller_browser.xml +++ /dev/null @@ -1,100 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/rv_item_browser_file_old.xml b/app/src/main/res/layout/rv_item_browser_file_old.xml deleted file mode 100644 index dfc50383f..000000000 --- a/app/src/main/res/layout/rv_item_browser_file_old.xml +++ /dev/null @@ -1,105 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/menu/file_browser_path.xml b/app/src/main/res/menu/file_browser_path.xml deleted file mode 100644 index 67c6dfd52..000000000 --- a/app/src/main/res/menu/file_browser_path.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - \ No newline at end of file From 07620f3a65d7521cbac578d9a2a632ddd669ec4d Mon Sep 17 00:00:00 2001 From: drone Date: Wed, 8 Jun 2022 21:47:21 +0000 Subject: [PATCH 21/29] Drone: update FindBugs results to reflect reduced error/warning count [skip ci] Signed-off-by: drone --- scripts/analysis/findbugs-results.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/analysis/findbugs-results.txt b/scripts/analysis/findbugs-results.txt index cde50ca2f..4a8d92402 100644 --- a/scripts/analysis/findbugs-results.txt +++ b/scripts/analysis/findbugs-results.txt @@ -1 +1 @@ -179 \ No newline at end of file +174 \ No newline at end of file From 6bc007151a78ba5924ee02fd44e1a25eabeae2ef Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Wed, 8 Jun 2022 23:47:51 +0200 Subject: [PATCH 22/29] make avatar buttons clickable min-sized for a11y Signed-off-by: Andy Scherzinger --- app/src/main/res/drawable/round_corner.xml | 2 +- app/src/main/res/layout/controller_profile.xml | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/src/main/res/drawable/round_corner.xml b/app/src/main/res/drawable/round_corner.xml index ecc82cfd1..6888a97bf 100644 --- a/app/src/main/res/drawable/round_corner.xml +++ b/app/src/main/res/drawable/round_corner.xml @@ -1,5 +1,5 @@ - + diff --git a/app/src/main/res/layout/controller_profile.xml b/app/src/main/res/layout/controller_profile.xml index 9b6e7de19..9cf360582 100644 --- a/app/src/main/res/layout/controller_profile.xml +++ b/app/src/main/res/layout/controller_profile.xml @@ -78,8 +78,8 @@ Date: Wed, 8 Jun 2022 23:53:12 +0200 Subject: [PATCH 23/29] remove unused style after removing bottom sheet Signed-off-by: Andy Scherzinger --- app/src/main/res/values/styles.xml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index d16b13034..02455e83e 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -63,11 +63,7 @@ @color/fontAppbar - - - +