Skip to content

Commit 38284af

Browse files
alperozturk96tobiasKaminsky
authored andcommitted
file list layout manager
Signed-off-by: alperozturk96 <alper_ozturk@proton.me>
1 parent 44737c2 commit 38284af

5 files changed

Lines changed: 152 additions & 119 deletions

File tree

app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1482,7 +1482,7 @@ class FileDisplayActivity :
14821482

14831483
override fun onSortingOrderChosen(selection: FileSortOrder?) {
14841484
val ocFileListFragment = this.listOfFilesFragment
1485-
ocFileListFragment?.sortFiles(selection)
1485+
ocFileListFragment?.fileListLayoutManager?.sortFiles(selection)
14861486
}
14871487

14881488
override fun downloadFile(file: OCFile?, packageName: String?, activityName: String?) {

app/src/main/java/com/owncloud/android/ui/activity/FolderPickerActivity.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -668,7 +668,7 @@ open class FolderPickerActivity :
668668
}
669669

670670
override fun onSortingOrderChosen(selection: FileSortOrder?) {
671-
listOfFilesFragment?.sortFiles(selection)
671+
listOfFilesFragment?.fileListLayoutManager?.sortFiles(selection)
672672
}
673673

674674
companion object {

app/src/main/java/com/owncloud/android/ui/fragment/ExtendedListFragment.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ open class ExtendedListFragment :
103103
protected var mRefreshListLayout: SwipeRefreshLayout? = null
104104

105105
@JvmField
106-
protected var mSortButton: MaterialButton? = null
106+
public var mSortButton: MaterialButton? = null
107107

108108
@JvmField
109109
protected var mSwitchGridViewButton: MaterialButton? = null
@@ -137,7 +137,7 @@ open class ExtendedListFragment :
137137
mRecyclerView?.setAdapter(recyclerViewAdapter)
138138
}
139139

140-
protected val recyclerView: RecyclerView?
140+
public val recyclerView: RecyclerView?
141141
get() = mRecyclerView
142142

143143
open fun setLoading(enabled: Boolean) {
@@ -784,7 +784,7 @@ open class ExtendedListFragment :
784784
setLayoutSwitchButton(isGridEnabled)
785785
}
786786

787-
protected fun setLayoutSwitchButton(isGrid: Boolean) {
787+
fun setLayoutSwitchButton(isGrid: Boolean) {
788788
mSwitchGridViewButton?.let {
789789
if (isGrid) {
790790
it.setContentDescription(getString(R.string.action_switch_list_view))
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
/*
2+
* Nextcloud - Android Client
3+
*
4+
* SPDX-FileCopyrightText: 2026 Alper Ozturk <alper.ozturk@nextcloud.com>
5+
* SPDX-License-Identifier: AGPL-3.0-or-later
6+
*/
7+
8+
package com.owncloud.android.ui.fragment
9+
10+
import android.annotation.SuppressLint
11+
import android.content.Context
12+
import androidx.recyclerview.widget.GridLayoutManager
13+
import androidx.recyclerview.widget.GridLayoutManager.SpanSizeLookup
14+
import androidx.recyclerview.widget.LinearLayoutManager
15+
import androidx.recyclerview.widget.RecyclerView
16+
import com.nextcloud.client.preferences.AppPreferences
17+
import com.owncloud.android.datamodel.OCFile
18+
import com.owncloud.android.lib.common.utils.Log_OC
19+
import com.owncloud.android.ui.adapter.OCFileListAdapter
20+
import com.owncloud.android.utils.DisplayUtils
21+
import com.owncloud.android.utils.FileSortOrder
22+
23+
class FileListLayoutManager(private val fragment: OCFileListFragment, private val preferences: AppPreferences) {
24+
25+
fun sortFiles(sortOrder: FileSortOrder?) {
26+
fragment.mSortButton?.setText(DisplayUtils.getSortOrderStringId(sortOrder))
27+
sortOrder?.let { fragment.mAdapter.setSortOrder(fragment.mFile, it) }
28+
}
29+
30+
/**
31+
* Determines whether a folder should be displayed in grid or list view.
32+
*
33+
*
34+
* The preference is checked for the given folder. If the folder itself does not have a preference set,
35+
* it will fall back to its parent folder recursively until a preference is found (root folder is always set).
36+
* Additionally, if a search event is active and is of type `SHARED_FILTER`, grid view is disabled.
37+
*
38+
* @param folder The folder to check, or `null` to refer to the root folder.
39+
* @return `true` if the folder should be displayed in grid mode, `false` if list mode is preferred.
40+
*/
41+
fun isGridViewPreferred(folder: OCFile?): Boolean {
42+
return if (fragment.searchEvent != null) {
43+
(fragment.searchEvent.toSearchType() != SearchType.SHARED_FILTER) &&
44+
OCFileListFragment.FOLDER_LAYOUT_GRID == preferences.getFolderLayout(folder)
45+
} else {
46+
OCFileListFragment.FOLDER_LAYOUT_GRID == preferences.getFolderLayout(folder)
47+
}
48+
}
49+
50+
fun setLayoutViewMode() {
51+
val isGrid = isGridViewPreferred(fragment.mFile)
52+
53+
if (isGrid) {
54+
switchToGridView()
55+
} else {
56+
switchToListView()
57+
}
58+
59+
fragment.setLayoutSwitchButton(isGrid)
60+
}
61+
62+
fun setListAsPreferred() {
63+
preferences.setFolderLayout(fragment.mFile, OCFileListFragment.FOLDER_LAYOUT_LIST)
64+
switchToListView()
65+
}
66+
67+
fun switchToListView() {
68+
if (fragment.isGridEnabled) {
69+
switchLayoutManager(false)
70+
}
71+
}
72+
73+
fun setGridAsPreferred() {
74+
preferences.setFolderLayout(fragment.mFile, OCFileListFragment.FOLDER_LAYOUT_GRID)
75+
switchToGridView()
76+
}
77+
78+
fun switchToGridView() {
79+
if (!fragment.isGridEnabled) {
80+
switchLayoutManager(true)
81+
}
82+
}
83+
84+
@SuppressLint("NotifyDataSetChanged")
85+
fun switchLayoutManager(grid: Boolean) {
86+
val recyclerView: RecyclerView? = fragment.recyclerView
87+
val adapter: OCFileListAdapter? = fragment.adapter
88+
val context: Context? = fragment.context
89+
90+
if (context == null || adapter == null || recyclerView == null) {
91+
Log_OC.e(OCFileListFragment.TAG, "cannot switch layout, arguments are null")
92+
return
93+
}
94+
95+
var position = 0
96+
97+
if (recyclerView.layoutManager is LinearLayoutManager) {
98+
val linearLayoutManager = recyclerView.layoutManager as LinearLayoutManager
99+
position = linearLayoutManager.findFirstCompletelyVisibleItemPosition()
100+
}
101+
102+
val layoutManager: RecyclerView.LayoutManager?
103+
if (grid) {
104+
layoutManager = GridLayoutManager(context, fragment.columnsCount)
105+
val gridLayoutManager = layoutManager
106+
gridLayoutManager.spanSizeLookup = object : SpanSizeLookup() {
107+
override fun getSpanSize(position: Int): Int {
108+
return if (position == fragment.adapter.itemCount - 1 ||
109+
position == 0 && fragment.adapter.shouldShowHeader()
110+
) {
111+
gridLayoutManager.spanCount
112+
} else {
113+
1
114+
}
115+
}
116+
}
117+
} else {
118+
layoutManager = LinearLayoutManager(context)
119+
}
120+
121+
recyclerView.setLayoutManager(layoutManager)
122+
recyclerView.scrollToPosition(position)
123+
adapter.setGridView(grid)
124+
recyclerView.setAdapter(adapter)
125+
adapter.notifyDataSetChanged()
126+
}
127+
}

app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java

Lines changed: 20 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -143,9 +143,6 @@
143143
import androidx.fragment.app.FragmentActivity;
144144
import androidx.fragment.app.FragmentManager;
145145
import androidx.media3.common.util.UnstableApi;
146-
import androidx.recyclerview.widget.GridLayoutManager;
147-
import androidx.recyclerview.widget.LinearLayoutManager;
148-
import androidx.recyclerview.widget.RecyclerView;
149146
import kotlin.Unit;
150147

151148
import static com.owncloud.android.datamodel.OCFile.ROOT_PATH;
@@ -211,7 +208,7 @@ public class OCFileListFragment extends ExtendedListFragment implements
211208
protected FileFragment.ContainerActivity mContainerActivity;
212209

213210
protected OCFile mFile;
214-
private OCFileListAdapter mAdapter;
211+
protected OCFileListAdapter mAdapter;
215212
protected boolean mOnlyFoldersClickable;
216213
protected boolean mFileSelectable;
217214

@@ -228,6 +225,7 @@ public class OCFileListFragment extends ExtendedListFragment implements
228225
private FloatingActionButton mFabMain;
229226
public static boolean isMultipleFileSelectedForCopyOrMove = false;
230227
public final ParentFolderFinder parentFolderFinder = new ParentFolderFinder();
228+
public FileListLayoutManager fileListLayoutManager;
231229

232230
private static final Intent scanIntentExternalApp = new Intent("org.fairscan.app.action.SCAN_TO_PDF");
233231

@@ -251,6 +249,7 @@ public void onCreate(Bundle savedInstanceState) {
251249
super.onCreate(savedInstanceState);
252250
setHasOptionsMenu(true);
253251
mMultiChoiceModeListener = new MultiChoiceModeListener();
252+
fileListLayoutManager = new FileListLayoutManager(this, preferences);
254253

255254
final Bundle state = savedInstanceState != null ? savedInstanceState : getArguments();
256255
setSearchArgs(state);
@@ -445,10 +444,12 @@ public void prepareOCFileList(Bundle savedInstanceState) {
445444

446445
if (mSwitchGridViewButton != null) {
447446
mSwitchGridViewButton.setOnClickListener(v -> {
448-
if (isGridEnabled()) {
449-
setListAsPreferred();
450-
} else {
451-
setGridAsPreferred();
447+
if (fileListLayoutManager != null) {
448+
if (isGridEnabled()) {
449+
fileListLayoutManager.setListAsPreferred();
450+
} else {
451+
fileListLayoutManager.setGridAsPreferred();
452+
}
452453
}
453454
setLayoutSwitchButton();
454455
});
@@ -461,6 +462,10 @@ public void prepareOCFileList(Bundle savedInstanceState) {
461462

462463
protected void setAdapter(Bundle args) {
463464
boolean hideItemOptions = args != null && args.getBoolean(ARG_HIDE_ITEM_OPTIONS, false);
465+
boolean isGridViewPreferred = false;
466+
if (fileListLayoutManager != null) {
467+
isGridViewPreferred = fileListLayoutManager.isGridViewPreferred(mFile);
468+
}
464469

465470
mAdapter = new OCFileListAdapter(
466471
getActivity(),
@@ -470,7 +475,7 @@ protected void setAdapter(Bundle args) {
470475
mContainerActivity,
471476
this,
472477
hideItemOptions,
473-
isGridViewPreferred(mFile),
478+
isGridViewPreferred,
474479
viewThemeUtils,
475480
overlayManager
476481
);
@@ -1612,7 +1617,9 @@ public void updateOCFile(@NonNull OCFile file) {
16121617
}
16131618

16141619
private void updateLayout() {
1615-
setLayoutViewMode();
1620+
if (fileListLayoutManager != null) {
1621+
fileListLayoutManager.setLayoutViewMode();
1622+
}
16161623
updateSortButton();
16171624
setLayoutSwitchButton();
16181625

@@ -1642,109 +1649,6 @@ private void invalidateActionMode() {
16421649
}
16431650
}
16441651

1645-
public void sortFiles(FileSortOrder sortOrder) {
1646-
if (mSortButton != null) {
1647-
mSortButton.setText(DisplayUtils.getSortOrderStringId(sortOrder));
1648-
}
1649-
mAdapter.setSortOrder(mFile, sortOrder);
1650-
}
1651-
1652-
/**
1653-
* Determines whether a folder should be displayed in grid or list view.
1654-
* <p>
1655-
* The preference is checked for the given folder. If the folder itself does not have a preference set,
1656-
* it will fall back to its parent folder recursively until a preference is found (root folder is always set).
1657-
* Additionally, if a search event is active and is of type {@code SHARED_FILTER}, grid view is disabled.
1658-
*
1659-
* @param folder The folder to check, or {@code null} to refer to the root folder.
1660-
* @return {@code true} if the folder should be displayed in grid mode, {@code false} if list mode is preferred.
1661-
*/
1662-
private boolean isGridViewPreferred(@Nullable OCFile folder) {
1663-
if (searchEvent != null) {
1664-
return (searchEvent.toSearchType() != SHARED_FILTER) &&
1665-
FOLDER_LAYOUT_GRID.equals(preferences.getFolderLayout(folder));
1666-
} else {
1667-
return FOLDER_LAYOUT_GRID.equals(preferences.getFolderLayout(folder));
1668-
}
1669-
}
1670-
1671-
private void setLayoutViewMode() {
1672-
boolean isGrid = isGridViewPreferred(mFile);
1673-
1674-
if (isGrid) {
1675-
switchToGridView();
1676-
} else {
1677-
switchToListView();
1678-
}
1679-
1680-
setLayoutSwitchButton(isGrid);
1681-
}
1682-
1683-
public void setListAsPreferred() {
1684-
preferences.setFolderLayout(mFile, FOLDER_LAYOUT_LIST);
1685-
switchToListView();
1686-
}
1687-
1688-
public void switchToListView() {
1689-
if (isGridEnabled()) {
1690-
switchLayoutManager(false);
1691-
}
1692-
}
1693-
1694-
public void setGridAsPreferred() {
1695-
preferences.setFolderLayout(mFile, FOLDER_LAYOUT_GRID);
1696-
switchToGridView();
1697-
}
1698-
1699-
public void switchToGridView() {
1700-
if (!isGridEnabled()) {
1701-
switchLayoutManager(true);
1702-
}
1703-
}
1704-
1705-
@SuppressLint("NotifyDataSetChanged")
1706-
public void switchLayoutManager(boolean grid) {
1707-
final var recyclerView = getRecyclerView();
1708-
final var adapter = getAdapter();
1709-
final var context = getContext();
1710-
1711-
if (context == null || adapter == null || recyclerView == null) {
1712-
Log_OC.e(TAG, "cannot switch layout, arguments are null");
1713-
return;
1714-
}
1715-
1716-
int position = 0;
1717-
1718-
if (recyclerView.getLayoutManager() instanceof LinearLayoutManager linearLayoutManager) {
1719-
position = linearLayoutManager.findFirstCompletelyVisibleItemPosition();
1720-
}
1721-
1722-
RecyclerView.LayoutManager layoutManager;
1723-
if (grid) {
1724-
layoutManager = new GridLayoutManager(context, getColumnsCount());
1725-
GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;
1726-
gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
1727-
@Override
1728-
public int getSpanSize(int position) {
1729-
if (position == getAdapter().getItemCount() - 1 ||
1730-
position == 0 && getAdapter().shouldShowHeader()) {
1731-
return gridLayoutManager.getSpanCount();
1732-
} else {
1733-
return 1;
1734-
}
1735-
}
1736-
});
1737-
} else {
1738-
layoutManager = new LinearLayoutManager(context);
1739-
}
1740-
1741-
recyclerView.setLayoutManager(layoutManager);
1742-
recyclerView.scrollToPosition(position);
1743-
adapter.setGridView(grid);
1744-
recyclerView.setAdapter(adapter);
1745-
adapter.notifyDataSetChanged();
1746-
}
1747-
17481652
public CommonOCFileListAdapterInterface getCommonAdapter() {
17491653
return mAdapter;
17501654
}
@@ -1923,7 +1827,9 @@ protected void handleSearchEvent(SearchEvent event) {
19231827

19241828
new Handler(Looper.getMainLooper()).post(() -> {
19251829
updateSortButton();
1926-
setLayoutViewMode();
1830+
if (fileListLayoutManager != null) {
1831+
fileListLayoutManager.setLayoutViewMode();
1832+
}
19271833
});
19281834

19291835
final User currentUser = accountManager.getUser();

0 commit comments

Comments
 (0)