From 999c8f00c53050152d72550d40cefe7293d0b98f Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Mon, 10 Aug 2026 16:24:17 +0200 Subject: [PATCH 1/6] Rename .java to .kt Signed-off-by: alperozturk96 --- .../{LocalFileListFragment.java => LocalFileListFragment.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename app/src/main/java/com/owncloud/android/ui/fragment/{LocalFileListFragment.java => LocalFileListFragment.kt} (100%) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/LocalFileListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/LocalFileListFragment.kt similarity index 100% rename from app/src/main/java/com/owncloud/android/ui/fragment/LocalFileListFragment.java rename to app/src/main/java/com/owncloud/android/ui/fragment/LocalFileListFragment.kt From a93cec205f947cd2802e73145e4e069e3c2c3107 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Mon, 10 Aug 2026 16:24:18 +0200 Subject: [PATCH 2/6] convert to kt Signed-off-by: alperozturk96 --- .../ui/fragment/LocalFileListFragment.kt | 543 +++++++----------- 1 file changed, 196 insertions(+), 347 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/LocalFileListFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/LocalFileListFragment.kt index e9ace77bed2a..165e3b87767d 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/LocalFileListFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/LocalFileListFragment.kt @@ -1,435 +1,284 @@ /* - * Nextcloud Android client application + * Nextcloud - Android Client * - * @author Tobias Kaminsky - * Copyright (C) 2018 Tobias Kaminsky - * Copyright (C) 2018 Nextcloud - * - * SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only - */ -package com.owncloud.android.ui.fragment; - -import android.annotation.SuppressLint; -import android.app.Activity; -import android.content.Context; -import android.os.Bundle; -import android.os.Environment; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.View; -import android.view.ViewGroup; - -import com.nextcloud.client.di.Injectable; -import com.owncloud.android.R; -import com.owncloud.android.lib.common.utils.Log_OC; -import com.owncloud.android.ui.adapter.localFileList.LocalFileListAdapter; -import com.owncloud.android.ui.interfaces.LocalFileListFragmentInterface; -import com.owncloud.android.utils.DisplayUtils; -import com.owncloud.android.utils.FileSortOrder; - -import java.io.File; -import java.util.List; - -import androidx.annotation.NonNull; -import androidx.annotation.VisibleForTesting; -import androidx.recyclerview.widget.GridLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - -import static com.owncloud.android.utils.DisplayUtils.openSortingOrderDialogFragment; - - -/** - * A Fragment that lists all files and folders in a given LOCAL path. + * SPDX-FileCopyrightText: 2026 Alper Ozturk + * SPDX-License-Identifier: AGPL-3.0-or-later */ -public class LocalFileListFragment extends ExtendedListFragment implements +package com.owncloud.android.ui.fragment + +import android.annotation.SuppressLint +import android.content.Context +import android.os.Bundle +import android.os.Environment +import android.view.LayoutInflater +import android.view.Menu +import android.view.MenuInflater +import android.view.MenuItem +import android.view.View +import android.view.ViewGroup +import androidx.annotation.VisibleForTesting +import androidx.core.view.MenuProvider +import androidx.lifecycle.Lifecycle +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.GridLayoutManager.SpanSizeLookup +import androidx.recyclerview.widget.RecyclerView +import com.nextcloud.client.di.Injectable +import com.owncloud.android.R +import com.owncloud.android.lib.common.utils.Log_OC +import com.owncloud.android.ui.adapter.localFileList.LocalFileListAdapter +import com.owncloud.android.ui.interfaces.LocalFileListFragmentInterface +import com.owncloud.android.utils.DisplayUtils +import com.owncloud.android.utils.FileSortOrder +import java.io.File + +class LocalFileListFragment : + ExtendedListFragment(), LocalFileListFragmentInterface, Injectable { + var currentDirectory: File? = null + private set - private static final String TAG = LocalFileListFragment.class.getSimpleName(); - - /** Reference to the Activity which this fragment is attached to. For callbacks */ - private LocalFileListFragment.ContainerActivity mContainerActivity; - - /** Directory to show */ - private File mDirectory; + private lateinit var adapter: LocalFileListAdapter + private lateinit var containerActivity: ContainerActivity - /** Adapter to connect the data from the directory with the View object */ - private LocalFileListAdapter mAdapter; - - @Override - public void onAttach(@NonNull Context context) { - super.onAttach(context); - } + private val menuProvider = object : MenuProvider { + override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) { + if (containerActivity.isFolderPickerMode) { + menu.removeItem(R.id.action_select_all) + menu.removeItem(R.id.action_search) + } + } - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setHasOptionsMenu(true); + override fun onMenuItemSelected(menuItem: MenuItem): Boolean = false } - /** - * {@inheritDoc} - */ - @Override - public void onAttach(@NonNull Activity activity) { - super.onAttach(activity); - try { - mContainerActivity = (ContainerActivity) activity; - } catch (ClassCastException e) { - throw new IllegalArgumentException(activity.toString() + " must implement " + - LocalFileListFragment.ContainerActivity.class.getSimpleName(), e); - } + override fun onAttach(context: Context) { + super.onAttach(context) + containerActivity = context as? ContainerActivity + ?: throw IllegalArgumentException( + "$context must implement ${ContainerActivity::class.java.simpleName}" + ) } - /** - * {@inheritDoc} - */ - @Override - public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - Log_OC.i(TAG, "onCreateView() start"); - View v = super.onCreateView(inflater, container, savedInstanceState); + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + Log_OC.i(TAG, "onCreateView() start") + val v = super.onCreateView(inflater, container, savedInstanceState) - if (mContainerActivity.isFolderPickerMode()) { - setEmptyListMessage(EmptyListState.LOCAL_FILE_LIST_EMPTY_FOLDER); + if (containerActivity.isFolderPickerMode) { + setEmptyListMessage(EmptyListState.LOCAL_FILE_LIST_EMPTY_FOLDER) } else { - setEmptyListMessage(EmptyListState.LOCAL_FILE_LIST_EMPTY_FILE); + setEmptyListMessage(EmptyListState.LOCAL_FILE_LIST_EMPTY_FILE) } - setSwipeEnabled(false); // Disable pull-to-refresh + // Disable pull-to-refresh + setSwipeEnabled(false) - Log_OC.i(TAG, "onCreateView() end"); - return v; + Log_OC.i(TAG, "onCreateView() end") + return v } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + requireActivity().addMenuProvider(menuProvider, viewLifecycleOwner, Lifecycle.State.RESUMED) - /** - * {@inheritDoc} - */ - @Override - public void onActivityCreated(Bundle savedInstanceState) { - Log_OC.i(TAG, "onActivityCreated() start"); - - super.onActivityCreated(savedInstanceState); - - mAdapter = new LocalFileListAdapter(mContainerActivity.isFolderPickerMode(), - this, - preferences, - getActivity(), - viewThemeUtils, - mContainerActivity.isWithinEncryptedFolder()); - setRecyclerViewAdapter(mAdapter); - - listDirectory(mContainerActivity.getInitialDirectory()); - - if (mSortButton != null) { - mSortButton.setOnClickListener(v -> { - FileSortOrder sortOrder = preferences.getSortOrderByType(FileSortOrder.Type.localFileListView); - openSortingOrderDialogFragment(requireFragmentManager(), sortOrder); - }); + setupAdapter() + listDirectory(containerActivity.initialDirectory) + setupSortButton() + setupGridViewButton() + } - FileSortOrder sortOrder = preferences.getSortOrderByType(FileSortOrder.Type.localFileListView); - if (sortOrder != null) { - mSortButton.setText(DisplayUtils.getSortOrderStringId(sortOrder)); - } - } + private fun setupAdapter() { + adapter = LocalFileListAdapter( + containerActivity.isFolderPickerMode, + this, + preferences, + requireActivity(), + viewThemeUtils, + containerActivity.isWithinEncryptedFolder + ) + setRecyclerViewAdapter(adapter) + } - setLayoutSwitchButton(); + private fun setupSortButton() { + val button = mSortButton ?: return - if (mSwitchGridViewButton != null) { - mSwitchGridViewButton.setOnClickListener(v -> { - if (isGridEnabled()) { - switchToListView(); - } else { - switchToGridView(); - } - setLayoutSwitchButton(); - }); + button.setOnClickListener { + val sortOrder = preferences.getSortOrderByType(FileSortOrder.Type.localFileListView) + DisplayUtils.openSortingOrderDialogFragment(parentFragmentManager, sortOrder) } - Log_OC.i(TAG, "onActivityCreated() stop"); + val sortOrder = preferences.getSortOrderByType(FileSortOrder.Type.localFileListView) ?: return + button.setText(DisplayUtils.getSortOrderStringId(sortOrder)) } - /** - * {@inheritDoc} - */ - @Override - public void onCreateOptionsMenu(Menu menu, @NonNull MenuInflater inflater) { - if (mContainerActivity.isFolderPickerMode()) { - menu.removeItem(R.id.action_select_all); - menu.removeItem(R.id.action_search); - } else { - super.onCreateOptionsMenu(menu, inflater); + private fun setupGridViewButton() { + setLayoutSwitchButton() + + mSwitchGridViewButton?.setOnClickListener { + if (isGridEnabled) { + switchToListView() + } else { + switchToGridView() + } + setLayoutSwitchButton() } } - /** - * Checks the file clicked over. Browses inside if it is a directory. Otherwise behaves like the checkbox was - * clicked. - * Notifies the container activity in any case. - */ - @Override - public void onItemClicked(File file) { - if (file != null) { - /// Click on a directory - if (file.isDirectory()) { - // just local updates - listDirectory(file); - // notify the click to container Activity - mContainerActivity.onDirectoryClick(file); - - // save index and top position - saveIndexAndTopPosition(mAdapter.getItemPosition(file)); - - } else { /// Click on a file, behave like checkbox was clicked - onItemCheckboxClicked(file); - } + override fun onItemClicked(file: File?) { + if (file == null) { + Log_OC.w(TAG, "file is null") + return + } - } else { - Log_OC.w(TAG, "Null object in ListAdapter!!"); + if (file.isDirectory()) { + listDirectory(file) + containerActivity.onDirectoryClick(file) + saveIndexAndTopPosition(adapter.getItemPosition(file)) + return } - } - /** - * Toggle selection of checked/unchecked file and notify adapter. - */ - @Override - public void onItemCheckboxClicked(File file) { - if (file != null) { - if (mAdapter.isCheckedFile(file)) { - // uncheck - mAdapter.removeCheckedFile(file); - } else { - // check - mAdapter.addCheckedFile(file); - } + onItemCheckboxClicked(file) + } - final int position = mAdapter.getItemPosition(file); - if (position != RecyclerView.NO_POSITION) { - mAdapter.notifyItemChanged(position); - } + override fun onItemCheckboxClicked(file: File?) { + if (file == null) { + Log_OC.w(TAG, "file is null") + return + } - // notify the change to the container Activity - mContainerActivity.onFileClick(file); + if (adapter.isCheckedFile(file)) { + adapter.removeCheckedFile(file) } else { - Log_OC.w(TAG, "Null object in ListAdapter!!"); + adapter.addCheckedFile(file) } - } - /** - * Call this, when the user presses the up button - */ - public void onNavigateUp() { - File parentDir = null; - if (mDirectory != null) { - parentDir = mDirectory.getParentFile(); // can be null + val position = adapter.getItemPosition(file) + if (position != RecyclerView.NO_POSITION) { + adapter.notifyItemChanged(position) } - listDirectory(parentDir); - // restore index and top position - restoreIndexAndTopPosition(); + containerActivity.onFileClick(file) } - - /** - * Use this to query the {@link File} object for the directory - * that is currently being displayed by this fragment - * - * @return File The currently displayed directory - */ - public File getCurrentDirectory() { - return mDirectory; + fun onNavigateUp() { + val parentDir = currentDirectory?.getParentFile() + listDirectory(parentDir) + restoreIndexAndTopPosition() } + @JvmOverloads + fun listDirectory(directory: File? = null) { + val target = directory ?: currentDirectory ?: Environment.getExternalStorageDirectory() ?: return + val folder = target.asDirectoryOrParent() ?: return - /** - * Calls {@link LocalFileListFragment#listDirectory(File)} with a null parameter - * to refresh the current directory. - */ - public void listDirectory() { - listDirectory(null); - } - + adapter.removeAllFilesFromCheckedFiles() + adapter.swapDirectory(folder) + currentDirectory = folder - /** - * Lists the given directory on the view. When the input parameter is null, - * it will either refresh the last known directory. list the root - * if there never was a directory. - * - * @param directory Directory to be listed - */ - public void listDirectory(File directory) { - if (directory == null) { - directory = (mDirectory != null) ? mDirectory : Environment.getExternalStorageDirectory(); - if (directory == null) return; - } + recyclerView?.scrollToPosition(0) + } - // If input is not a directory, list its parent - if (!directory.isDirectory()) { - Log_OC.w(TAG, "You see, that is not a directory -> " + directory); - directory = directory.getParentFile(); - if (directory == null) { - Log_OC.w(TAG, "parent directory is null, cannot swap directory"); - return; - } + private fun File.asDirectoryOrParent(): File? { + if (isDirectory) { + return this } - mAdapter.removeAllFilesFromCheckedFiles(); - mAdapter.swapDirectory(directory); + Log_OC.w(TAG, "You see, that is not a directory -> $this") - mDirectory = directory; - - final var recyclerView = getRecyclerView(); - if (recyclerView != null) { - recyclerView.scrollToPosition(0); + val parent = parentFile + if (parent == null) { + Log_OC.w(TAG, "parent directory is null, cannot swap directory") } + + return parent } + val checkedFilePaths: Array + get() = adapter.checkedFilesPath - /** - * Returns the full paths to the files checked by the user - * - * @return File paths to the files checked by the user. - */ - public String[] getCheckedFilePaths() { - return mAdapter.getCheckedFilesPath(); - } + val checkedFilesCount: Int + get() = adapter.checkedFilesCount() - public int getCheckedFilesCount() { - return mAdapter.checkedFilesCount(); - } - - public int getFilesCount() { - return mAdapter.getFilesCount(); - } + val filesCount: Int + get() = adapter.filesCount - public void sortFiles(FileSortOrder sortOrder) { - if (mSortButton != null) { - mSortButton.setText(DisplayUtils.getSortOrderStringId(sortOrder)); - } - mAdapter.setSortOrder(sortOrder); + fun sortFiles(sortOrder: FileSortOrder) { + mSortButton?.setText(DisplayUtils.getSortOrderStringId(sortOrder)) + adapter.setSortOrder(sortOrder) } - /** - * De-/select all elements in the local file list. - * - * @param select true to select all, false to deselect all - */ - public void selectAllFiles(boolean select) { - if (getRecyclerView() == null) { - return; + fun selectAllFiles(select: Boolean) { + if (recyclerView == null) { + return } - final var localFileListAdapter = (LocalFileListAdapter) getRecyclerView().getAdapter(); - if (localFileListAdapter == null) { - return; - } + val localFileListAdapter = recyclerView?.adapter as? LocalFileListAdapter? ?: return if (select) { - localFileListAdapter.addAllFilesToCheckedFiles(); + localFileListAdapter.addAllFilesToCheckedFiles() } else { - localFileListAdapter.removeAllFilesFromCheckedFiles(); + localFileListAdapter.removeAllFilesFromCheckedFiles() } - mAdapter.notifyItemRangeChanged(0, mAdapter.getItemCount()); + adapter.notifyItemRangeChanged(0, adapter.getItemCount()) } - @Override - public void switchToGridView() { - if (getRecyclerView() == null) { - return; + override fun switchToGridView() { + if (recyclerView == null) { + return } - mAdapter.setGridView(true); - /* - * Set recyclerview adapter again to force new view for items. If this is not done - * a few items keep their old view. - * - * https://stackoverflow.com/questions/36495009/force-recyclerview-to-redraw-android - */ - getRecyclerView().setAdapter(mAdapter); - - if (!isGridEnabled()) { - RecyclerView.LayoutManager layoutManager; - layoutManager = new GridLayoutManager(getContext(), getColumnsCount()); - ((GridLayoutManager) layoutManager).setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { - @Override - public int getSpanSize(int position) { - if (position == mAdapter.getItemCount() - 1) { - return ((GridLayoutManager) layoutManager).getSpanCount(); - } else { - return 1; - } + adapter.gridView = true + recyclerView?.setAdapter(adapter) + + if (!isGridEnabled) { + val layoutManager = GridLayoutManager(context, columnsCount) + layoutManager.spanSizeLookup = object : SpanSizeLookup() { + override fun getSpanSize(position: Int): Int = if (position == adapter.getItemCount() - 1) { + layoutManager.spanCount + } else { + 1 } - }); + } - getRecyclerView().setLayoutManager(layoutManager); + recyclerView?.setLayoutManager(layoutManager) } } - @Override - public void switchToListView() { - if (getRecyclerView() == null) { - return; + override fun switchToListView() { + if (recyclerView == null) { + return } - mAdapter.setGridView(false); - /* Same problem here, see switchToGridView() */ - getRecyclerView().setAdapter(mAdapter); - super.switchToListView(); + adapter.gridView = false + recyclerView?.setAdapter(adapter) + super.switchToListView() } @VisibleForTesting - public void setFiles(List newFiles) { - mAdapter.setFiles(newFiles); + fun setFiles(newFiles: MutableList) { + adapter.setFiles(newFiles) } - /** - * Interface to implement by any Activity that includes some instance of LocalFileListFragment - */ - public interface ContainerActivity { - - /** - * Callback method invoked when a directory is clicked by the user on the files list - * - * @param directory - */ - void onDirectoryClick(File directory); - - /** - * Callback method invoked when a file (non directory) - * is clicked by the user on the files list - * - * @param file - */ - void onFileClick(File file); - - /** - * Callback method invoked when the parent activity - * is fully created to get the directory to list firstly. - * - * @return Directory to list firstly. Can be NULL. - */ - File getInitialDirectory(); - - /** - * config check if the list should behave in folder picker mode only displaying folders but no files. - * - * @return true if folder picker mode, else false - */ - boolean isFolderPickerMode(); - - boolean isWithinEncryptedFolder(); + interface ContainerActivity { + fun onDirectoryClick(directory: File?) + fun onFileClick(file: File?) + val initialDirectory: File? + val isFolderPickerMode: Boolean + val isWithinEncryptedFolder: Boolean } @SuppressLint("NotifyDataSetChanged") - public void setupStoragePermissionWarningBanner() { - mAdapter.notifyDataSetChanged(); + fun setupStoragePermissionWarningBanner() { + adapter.notifyDataSetChanged() + } + + override fun onDestroyView() { + adapter.cleanup() + super.onDestroyView() } - @Override - public void onDestroyView() { - mAdapter.cleanup(); - super.onDestroyView(); + companion object { + private val TAG: String = LocalFileListFragment::class.java.getSimpleName() } } From 6976f78e23094b4636a69af2546e03918230d8e4 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Mon, 10 Aug 2026 16:27:55 +0200 Subject: [PATCH 3/6] simplify Signed-off-by: alperozturk96 --- .../localFileList/LocalFileListAdapter.kt | 13 +++++ .../ui/fragment/LocalFileListFragment.kt | 55 +++++++------------ 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/localFileList/LocalFileListAdapter.kt b/app/src/main/java/com/owncloud/android/ui/adapter/localFileList/LocalFileListAdapter.kt index 90f49c7a8fc9..6719469c7bf1 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/localFileList/LocalFileListAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/localFileList/LocalFileListAdapter.kt @@ -99,6 +99,19 @@ class LocalFileListAdapter( fun isCheckedFile(file: File): Boolean = checkedFiles.contains(file) + fun onItemCheckboxClicked(file: File) { + if (isCheckedFile(file)) { + removeCheckedFile(file) + } else { + addCheckedFile(file) + } + + val position = getItemPosition(file) + if (position != RecyclerView.NO_POSITION) { + notifyItemChanged(position) + } + } + fun addCheckedFile(file: File) { checkedFiles.add(file) } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/LocalFileListFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/LocalFileListFragment.kt index 165e3b87767d..c3544fdade94 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/LocalFileListFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/LocalFileListFragment.kt @@ -21,7 +21,6 @@ import androidx.core.view.MenuProvider import androidx.lifecycle.Lifecycle import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager.SpanSizeLookup -import androidx.recyclerview.widget.RecyclerView import com.nextcloud.client.di.Injectable import com.owncloud.android.R import com.owncloud.android.lib.common.utils.Log_OC @@ -125,10 +124,7 @@ class LocalFileListFragment : } override fun onItemClicked(file: File?) { - if (file == null) { - Log_OC.w(TAG, "file is null") - return - } + val file = file ?: return if (file.isDirectory()) { listDirectory(file) @@ -141,22 +137,8 @@ class LocalFileListFragment : } override fun onItemCheckboxClicked(file: File?) { - if (file == null) { - Log_OC.w(TAG, "file is null") - return - } - - if (adapter.isCheckedFile(file)) { - adapter.removeCheckedFile(file) - } else { - adapter.addCheckedFile(file) - } - - val position = adapter.getItemPosition(file) - if (position != RecyclerView.NO_POSITION) { - adapter.notifyItemChanged(position) - } - + val file = file ?: return + adapter.onItemCheckboxClicked(file) containerActivity.onFileClick(file) } @@ -224,25 +206,29 @@ class LocalFileListFragment : } override fun switchToGridView() { - if (recyclerView == null) { + val recyclerView = recyclerView ?: return + + adapter.gridView = true + recyclerView.adapter = adapter + + if (isGridEnabled) { return } - adapter.gridView = true - recyclerView?.setAdapter(adapter) + recyclerView.layoutManager = createGridLayoutManager() + } - if (!isGridEnabled) { - val layoutManager = GridLayoutManager(context, columnsCount) - layoutManager.spanSizeLookup = object : SpanSizeLookup() { - override fun getSpanSize(position: Int): Int = if (position == adapter.getItemCount() - 1) { - layoutManager.spanCount - } else { - 1 - } - } + private fun createGridLayoutManager(): GridLayoutManager { + val layoutManager = GridLayoutManager(context, columnsCount) - recyclerView?.setLayoutManager(layoutManager) + layoutManager.spanSizeLookup = object : SpanSizeLookup() { + override fun getSpanSize(position: Int): Int = when (position) { + adapter.itemCount - 1 -> layoutManager.spanCount + else -> SINGLE_SPAN + } } + + return layoutManager } override fun switchToListView() { @@ -279,6 +265,7 @@ class LocalFileListFragment : } companion object { + private const val SINGLE_SPAN = 1 private val TAG: String = LocalFileListFragment::class.java.getSimpleName() } } From db2b38cc0114ac3302374e47c4945628e7a21dd3 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Mon, 10 Aug 2026 16:29:40 +0200 Subject: [PATCH 4/6] simplify Signed-off-by: alperozturk96 --- .../android/ui/interfaces/LocalFileListFragmentInterface.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/owncloud/android/ui/interfaces/LocalFileListFragmentInterface.kt b/app/src/main/java/com/owncloud/android/ui/interfaces/LocalFileListFragmentInterface.kt index fca93caaacc3..32ebfcdf73aa 100644 --- a/app/src/main/java/com/owncloud/android/ui/interfaces/LocalFileListFragmentInterface.kt +++ b/app/src/main/java/com/owncloud/android/ui/interfaces/LocalFileListFragmentInterface.kt @@ -12,5 +12,5 @@ interface LocalFileListFragmentInterface { val columnsCount: Int fun onItemClicked(file: File?) fun onItemCheckboxClicked(file: File?) - fun setLoading(loading: Boolean) + fun setLoading(enabled: Boolean) } From dd2b15fcd108bfe474c22d25375f2f807879d093 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Wed, 12 Aug 2026 08:30:31 +0200 Subject: [PATCH 5/6] wip Signed-off-by: alperozturk96 --- .../nextcloud/client/di/ComponentsModule.java | 2 +- .../ui/activity/UploadFilesActivity.java | 6 +-- .../LocalFileListFragment.kt | 38 ++++++++----------- .../localfilelist/LocalFileListListener.kt | 18 +++++++++ .../main/res/layout/upload_files_layout.xml | 2 +- 5 files changed, 39 insertions(+), 27 deletions(-) rename app/src/main/java/com/owncloud/android/ui/fragment/{ => localfilelist}/LocalFileListFragment.kt (87%) create mode 100644 app/src/main/java/com/owncloud/android/ui/fragment/localfilelist/LocalFileListListener.kt diff --git a/app/src/main/java/com/nextcloud/client/di/ComponentsModule.java b/app/src/main/java/com/nextcloud/client/di/ComponentsModule.java index 438fa1768cf5..7cd7c1112326 100644 --- a/app/src/main/java/com/nextcloud/client/di/ComponentsModule.java +++ b/app/src/main/java/com/nextcloud/client/di/ComponentsModule.java @@ -108,7 +108,7 @@ import com.owncloud.android.ui.fragment.GalleryFragment; import com.owncloud.android.ui.fragment.GalleryFragmentBottomSheetDialog; import com.owncloud.android.ui.fragment.GroupfolderListFragment; -import com.owncloud.android.ui.fragment.LocalFileListFragment; +import com.owncloud.android.ui.fragment.localfilelist.LocalFileListFragment; import com.owncloud.android.ui.fragment.OCFileListBottomSheetDialog; import com.owncloud.android.ui.fragment.OCFileListFragment; import com.owncloud.android.ui.fragment.SharedListFragment; diff --git a/app/src/main/java/com/owncloud/android/ui/activity/UploadFilesActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/UploadFilesActivity.java index 5dab3516d444..4280eac6bf6f 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/UploadFilesActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/UploadFilesActivity.java @@ -49,7 +49,8 @@ import com.owncloud.android.ui.dialog.LocalStoragePathPickerDialogFragment; import com.owncloud.android.ui.dialog.SortingOrderDialogFragment; import com.owncloud.android.ui.fragment.ExtendedListFragment; -import com.owncloud.android.ui.fragment.LocalFileListFragment; +import com.owncloud.android.ui.fragment.localfilelist.LocalFileListFragment; +import com.owncloud.android.ui.fragment.localfilelist.LocalFileListListener; import com.owncloud.android.utils.FileSortOrder; import com.owncloud.android.utils.FileUtil; import com.owncloud.android.utils.PermissionUtil; @@ -70,14 +71,13 @@ import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; import kotlin.Unit; -import kotlin.jvm.functions.Function1; import static com.owncloud.android.ui.activity.FileActivity.EXTRA_USER; /** * Displays local files and let the user choose what of them wants to upload to the current Nextcloud account. */ -public class UploadFilesActivity extends DrawerActivity implements LocalFileListFragment.ContainerActivity, +public class UploadFilesActivity extends DrawerActivity implements LocalFileListListener, OnClickListener, ConfirmationDialogFragmentListener, SortingOrderDialogFragment.OnSortingOrderListener, CheckAvailableSpaceTask.CheckAvailableSpaceListener, StoragePathAdapter.StoragePathAdapterListener, Injectable { diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/LocalFileListFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/localfilelist/LocalFileListFragment.kt similarity index 87% rename from app/src/main/java/com/owncloud/android/ui/fragment/LocalFileListFragment.kt rename to app/src/main/java/com/owncloud/android/ui/fragment/localfilelist/LocalFileListFragment.kt index c3544fdade94..7ecb9f872bac 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/LocalFileListFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/localfilelist/LocalFileListFragment.kt @@ -4,7 +4,8 @@ * SPDX-FileCopyrightText: 2026 Alper Ozturk * SPDX-License-Identifier: AGPL-3.0-or-later */ -package com.owncloud.android.ui.fragment + +package com.owncloud.android.ui.fragment.localfilelist import android.annotation.SuppressLint import android.content.Context @@ -20,11 +21,12 @@ import androidx.annotation.VisibleForTesting import androidx.core.view.MenuProvider import androidx.lifecycle.Lifecycle import androidx.recyclerview.widget.GridLayoutManager -import androidx.recyclerview.widget.GridLayoutManager.SpanSizeLookup import com.nextcloud.client.di.Injectable import com.owncloud.android.R import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.ui.adapter.localFileList.LocalFileListAdapter +import com.owncloud.android.ui.fragment.EmptyListState +import com.owncloud.android.ui.fragment.ExtendedListFragment import com.owncloud.android.ui.interfaces.LocalFileListFragmentInterface import com.owncloud.android.utils.DisplayUtils import com.owncloud.android.utils.FileSortOrder @@ -38,11 +40,11 @@ class LocalFileListFragment : private set private lateinit var adapter: LocalFileListAdapter - private lateinit var containerActivity: ContainerActivity + private lateinit var listener: LocalFileListListener private val menuProvider = object : MenuProvider { override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) { - if (containerActivity.isFolderPickerMode) { + if (listener.isFolderPickerMode) { menu.removeItem(R.id.action_select_all) menu.removeItem(R.id.action_search) } @@ -53,9 +55,9 @@ class LocalFileListFragment : override fun onAttach(context: Context) { super.onAttach(context) - containerActivity = context as? ContainerActivity + listener = context as? LocalFileListListener ?: throw IllegalArgumentException( - "$context must implement ${ContainerActivity::class.java.simpleName}" + "$context must implement ${LocalFileListListener::class.java.simpleName}" ) } @@ -63,7 +65,7 @@ class LocalFileListFragment : Log_OC.i(TAG, "onCreateView() start") val v = super.onCreateView(inflater, container, savedInstanceState) - if (containerActivity.isFolderPickerMode) { + if (listener.isFolderPickerMode) { setEmptyListMessage(EmptyListState.LOCAL_FILE_LIST_EMPTY_FOLDER) } else { setEmptyListMessage(EmptyListState.LOCAL_FILE_LIST_EMPTY_FILE) @@ -81,19 +83,19 @@ class LocalFileListFragment : requireActivity().addMenuProvider(menuProvider, viewLifecycleOwner, Lifecycle.State.RESUMED) setupAdapter() - listDirectory(containerActivity.initialDirectory) + listDirectory(listener.initialDirectory) setupSortButton() setupGridViewButton() } private fun setupAdapter() { adapter = LocalFileListAdapter( - containerActivity.isFolderPickerMode, + listener.isFolderPickerMode, this, preferences, requireActivity(), viewThemeUtils, - containerActivity.isWithinEncryptedFolder + listener.isWithinEncryptedFolder ) setRecyclerViewAdapter(adapter) } @@ -128,7 +130,7 @@ class LocalFileListFragment : if (file.isDirectory()) { listDirectory(file) - containerActivity.onDirectoryClick(file) + listener.onDirectoryClick(file) saveIndexAndTopPosition(adapter.getItemPosition(file)) return } @@ -139,7 +141,7 @@ class LocalFileListFragment : override fun onItemCheckboxClicked(file: File?) { val file = file ?: return adapter.onItemCheckboxClicked(file) - containerActivity.onFileClick(file) + listener.onFileClick(file) } fun onNavigateUp() { @@ -221,7 +223,7 @@ class LocalFileListFragment : private fun createGridLayoutManager(): GridLayoutManager { val layoutManager = GridLayoutManager(context, columnsCount) - layoutManager.spanSizeLookup = object : SpanSizeLookup() { + layoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() { override fun getSpanSize(position: Int): Int = when (position) { adapter.itemCount - 1 -> layoutManager.spanCount else -> SINGLE_SPAN @@ -242,18 +244,10 @@ class LocalFileListFragment : } @VisibleForTesting - fun setFiles(newFiles: MutableList) { + fun setFiles(newFiles: List) { adapter.setFiles(newFiles) } - interface ContainerActivity { - fun onDirectoryClick(directory: File?) - fun onFileClick(file: File?) - val initialDirectory: File? - val isFolderPickerMode: Boolean - val isWithinEncryptedFolder: Boolean - } - @SuppressLint("NotifyDataSetChanged") fun setupStoragePermissionWarningBanner() { adapter.notifyDataSetChanged() diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/localfilelist/LocalFileListListener.kt b/app/src/main/java/com/owncloud/android/ui/fragment/localfilelist/LocalFileListListener.kt new file mode 100644 index 000000000000..9ce0f0f83b97 --- /dev/null +++ b/app/src/main/java/com/owncloud/android/ui/fragment/localfilelist/LocalFileListListener.kt @@ -0,0 +1,18 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2026 Alper Ozturk + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +package com.owncloud.android.ui.fragment.localfilelist + +import java.io.File + +interface LocalFileListListener { + fun onDirectoryClick(directory: File?) + fun onFileClick(file: File?) + val initialDirectory: File? + val isFolderPickerMode: Boolean + val isWithinEncryptedFolder: Boolean +} diff --git a/app/src/main/res/layout/upload_files_layout.xml b/app/src/main/res/layout/upload_files_layout.xml index 4012193eb6a9..38d17a7566a8 100644 --- a/app/src/main/res/layout/upload_files_layout.xml +++ b/app/src/main/res/layout/upload_files_layout.xml @@ -20,7 +20,7 @@ Date: Wed, 12 Aug 2026 08:35:32 +0200 Subject: [PATCH 6/6] wip Signed-off-by: alperozturk96 --- .../localfilelist/LocalFileListFragment.kt | 34 +++++++++++++------ 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/localfilelist/LocalFileListFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/localfilelist/LocalFileListFragment.kt index 7ecb9f872bac..f9f75264a701 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/localfilelist/LocalFileListFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/localfilelist/LocalFileListFragment.kt @@ -53,6 +53,7 @@ class LocalFileListFragment : override fun onMenuItemSelected(menuItem: MenuItem): Boolean = false } + //region Lifecycle override fun onAttach(context: Context) { super.onAttach(context) listener = context as? LocalFileListListener @@ -88,6 +89,13 @@ class LocalFileListFragment : setupGridViewButton() } + override fun onDestroyView() { + adapter.cleanup() + super.onDestroyView() + } + //endregion + + //region Setup private fun setupAdapter() { adapter = LocalFileListAdapter( listener.isFolderPickerMode, @@ -124,7 +132,9 @@ class LocalFileListFragment : setLayoutSwitchButton() } } + //endregion + //region Item clicks override fun onItemClicked(file: File?) { val file = file ?: return @@ -143,7 +153,9 @@ class LocalFileListFragment : adapter.onItemCheckboxClicked(file) listener.onFileClick(file) } + //endregion + //region Directory navigation fun onNavigateUp() { val parentDir = currentDirectory?.getParentFile() listDirectory(parentDir) @@ -176,7 +188,9 @@ class LocalFileListFragment : return parent } + //endregion + //region File selection val checkedFilePaths: Array get() = adapter.checkedFilesPath @@ -186,11 +200,6 @@ class LocalFileListFragment : val filesCount: Int get() = adapter.filesCount - fun sortFiles(sortOrder: FileSortOrder) { - mSortButton?.setText(DisplayUtils.getSortOrderStringId(sortOrder)) - adapter.setSortOrder(sortOrder) - } - fun selectAllFiles(select: Boolean) { if (recyclerView == null) { return @@ -206,6 +215,13 @@ class LocalFileListFragment : adapter.notifyItemRangeChanged(0, adapter.getItemCount()) } + //endregion + + //region View options + fun sortFiles(sortOrder: FileSortOrder) { + mSortButton?.setText(DisplayUtils.getSortOrderStringId(sortOrder)) + adapter.setSortOrder(sortOrder) + } override fun switchToGridView() { val recyclerView = recyclerView ?: return @@ -242,7 +258,9 @@ class LocalFileListFragment : recyclerView?.setAdapter(adapter) super.switchToListView() } + //endregion + //region Adapter updates @VisibleForTesting fun setFiles(newFiles: List) { adapter.setFiles(newFiles) @@ -252,11 +270,7 @@ class LocalFileListFragment : fun setupStoragePermissionWarningBanner() { adapter.notifyDataSetChanged() } - - override fun onDestroyView() { - adapter.cleanup() - super.onDestroyView() - } + //endregion companion object { private const val SINGLE_SPAN = 1