From f9e8000928384a4c1addfd082974752788024199 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 13 Aug 2025 11:06:04 +0200 Subject: [PATCH 01/35] add: extension text view element Signed-off-by: alperozturk --- .../ui/adapter/ListGridItemViewHolder.kt | 1 + .../android/ui/adapter/OCFileListAdapter.java | 19 +++++-- .../adapter/OCFileListGridItemViewHolder.kt | 2 + .../ui/adapter/OCFileListItemViewHolder.kt | 2 + .../android/utils/FileStorageUtils.java | 27 +++++++++- app/src/main/res/layout/grid_item.xml | 38 ++++++++++---- app/src/main/res/layout/list_item.xml | 30 ++++++++--- app/src/main/res/values/strings.xml | 3 +- .../client/utils/FileStorageUtilsTest.kt | 51 +++++++++++++++++++ 9 files changed, 152 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/ListGridItemViewHolder.kt b/app/src/main/java/com/owncloud/android/ui/adapter/ListGridItemViewHolder.kt index 3132a7fafc60..70a7b6205498 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/ListGridItemViewHolder.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/ListGridItemViewHolder.kt @@ -11,4 +11,5 @@ import android.widget.TextView internal interface ListGridItemViewHolder : ListViewHolder { val fileName: TextView + val extension: TextView } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java index de8746cd5b78..2af88b8c56a0 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java @@ -123,6 +123,7 @@ public class OCFileListAdapter extends RecyclerView.Adapter private constructor } + public static boolean isRTL() { + return TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()) == View.LAYOUT_DIRECTION_RTL; + } + + public static Pair getFilenameAndExtension(String filename, boolean isFolder, boolean isRTL) { + if (isFolder) { + return new Pair<>(filename, ""); + } + + final String base = FilenameUtils.getBaseName(filename); + String extension = FilenameUtils.getExtension(filename); + if (!extension.isEmpty()) { + extension = StringConstants.DOT + extension; + } + + if (isRTL) { + return new Pair<>(extension, base); + } else { + return new Pair<>(base, extension); + } + } + public static boolean isValidExtFilename(String name) { for (int i = 0; i < name.length(); i++) { char c = name.charAt(i); diff --git a/app/src/main/res/layout/grid_item.xml b/app/src/main/res/layout/grid_item.xml index 6b458c334f16..7460c6de771e 100644 --- a/app/src/main/res/layout/grid_item.xml +++ b/app/src/main/res/layout/grid_item.xml @@ -151,22 +151,42 @@ app:layout_constraintTop_toTopOf="parent" tools:visibility="visible" /> - + android:orientation="horizontal"> + + + + + + - + android:orientation="horizontal"> + + + + + - No information about the error This is a placeholder - placeholder.txt + placeholder + .txt 389 KB 2012/05/18 12:23 PM 12:23:45 diff --git a/app/src/test/java/com/nextcloud/client/utils/FileStorageUtilsTest.kt b/app/src/test/java/com/nextcloud/client/utils/FileStorageUtilsTest.kt index c6f223426328..a92c9144a721 100644 --- a/app/src/test/java/com/nextcloud/client/utils/FileStorageUtilsTest.kt +++ b/app/src/test/java/com/nextcloud/client/utils/FileStorageUtilsTest.kt @@ -16,7 +16,9 @@ import org.junit.Test import java.io.File import java.util.Locale +@Suppress("TooManyFunctions") class FileStorageUtilsTest { + @Test fun testValidFilenames() { assertTrue(FileStorageUtils.isValidExtFilename("example.txt")) @@ -207,4 +209,53 @@ class FileStorageUtilsTest { assertEquals(expected, result) } + + @Test + fun testGetFilenameAndExtensionWhenGivenInvalidFilenamesWithSpecialChars() { + val result = FileStorageUtils.getFilenameAndExtension("invoice\u202Ecod.exe", false, false) + assertEquals("invoice\u202Ecod", result.first) + assertEquals(".exe", result.second) + } + + @Test + fun testGetFilenameAndExtensionWhenGivenMultipleDotsInFilename() { + val result = FileStorageUtils.getFilenameAndExtension("archive.tar.gz", false, false) + assertEquals("archive.tar", result.first) + assertEquals(".gz", result.second) + } + + @Test + fun testGetFilenameAndExtensionWhenGivenFolderName() { + val result = FileStorageUtils.getFilenameAndExtension("myFolder", true, false) + assertEquals("myFolder", result.first) + assertEquals("", result.second) + } + + @Test + fun testGetFilenameAndExtensionWhenGivenNormalFile() { + val result = FileStorageUtils.getFilenameAndExtension("document.txt", false, false) + assertEquals("document", result.first) + assertEquals(".txt", result.second) + } + + @Test + fun testGetFilenameAndExtensionRTL() { + val result = FileStorageUtils.getFilenameAndExtension("document.txt", false, true) + assertEquals(".txt", result.first) + assertEquals("document", result.second) + } + + @Test + fun testGetFilenameAndExtensionRTLEmptyExtension() { + val result = FileStorageUtils.getFilenameAndExtension("document", false, true) + assertEquals("", result.first) + assertEquals("document", result.second) + } + + @Test + fun testGetFilenameAndExtensionEmptyExtension() { + val result = FileStorageUtils.getFilenameAndExtension("document", false, false) + assertEquals("document", result.first) + assertEquals("", result.second) + } } From 55487a4b0a1f8cbd7e077d1d71b149a5132403be Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 13 Aug 2025 11:21:29 +0200 Subject: [PATCH 02/35] add: unit and screenshot tests Signed-off-by: alperozturk --- .../ui/fragment/OCFileListFragmentStaticServerIT.kt | 7 +++++++ .../com/nextcloud/client/utils/FileStorageUtilsTest.kt | 10 ++++++++++ 2 files changed, 17 insertions(+) diff --git a/app/src/androidTest/java/com/owncloud/android/ui/fragment/OCFileListFragmentStaticServerIT.kt b/app/src/androidTest/java/com/owncloud/android/ui/fragment/OCFileListFragmentStaticServerIT.kt index a5678e5b8751..b366234370a4 100644 --- a/app/src/androidTest/java/com/owncloud/android/ui/fragment/OCFileListFragmentStaticServerIT.kt +++ b/app/src/androidTest/java/com/owncloud/android/ui/fragment/OCFileListFragmentStaticServerIT.kt @@ -231,6 +231,13 @@ class OCFileListFragmentStaticServerIT : AbstractIT() { sut.storageManager.saveFile(this) } + OCFile("/Foo\\u202Edm.exe").apply { + remoteId = "000000011" + parentId = sut.storageManager.getFileByEncryptedRemotePath("/").fileId + modificationTimestamp = 1000 + sut.storageManager.saveFile(this) + } + sut.addFragment(fragment) val root = sut.storageManager.getFileByEncryptedRemotePath("/") fragment.listDirectory(root, false, false) diff --git a/app/src/test/java/com/nextcloud/client/utils/FileStorageUtilsTest.kt b/app/src/test/java/com/nextcloud/client/utils/FileStorageUtilsTest.kt index a92c9144a721..40046e241c7e 100644 --- a/app/src/test/java/com/nextcloud/client/utils/FileStorageUtilsTest.kt +++ b/app/src/test/java/com/nextcloud/client/utils/FileStorageUtilsTest.kt @@ -258,4 +258,14 @@ class FileStorageUtilsTest { assertEquals("document", result.first) assertEquals("", result.second) } + + @Test + fun testGetFilenameAndExtensionWithRLO() { + val filename = "Foo\u202Edm.exe" + val result = FileStorageUtils.getFilenameAndExtension(filename, false, false) + + // we are not touching the filename that's why expected filename must stay same + assertEquals("Foo\u202Edm", result.first) + assertEquals(".exe", result.second) + } } From 60b190b8f52ee74c8e012594b8598d9703177899 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 13 Aug 2025 11:24:21 +0200 Subject: [PATCH 03/35] fix: more button layout constraint Signed-off-by: alperozturk --- app/src/main/res/layout/grid_item.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/layout/grid_item.xml b/app/src/main/res/layout/grid_item.xml index 7460c6de771e..38ff6bc98e37 100644 --- a/app/src/main/res/layout/grid_item.xml +++ b/app/src/main/res/layout/grid_item.xml @@ -152,6 +152,7 @@ tools:visibility="visible" /> From e3a0d9e6cc39c8498b49c169ef1e9ea58b52e2a2 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 13 Aug 2025 12:30:49 +0200 Subject: [PATCH 04/35] fix: path of screenshot test Signed-off-by: alperozturk --- .../android/ui/fragment/OCFileListFragmentStaticServerIT.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/androidTest/java/com/owncloud/android/ui/fragment/OCFileListFragmentStaticServerIT.kt b/app/src/androidTest/java/com/owncloud/android/ui/fragment/OCFileListFragmentStaticServerIT.kt index b366234370a4..793a6bcb4d71 100644 --- a/app/src/androidTest/java/com/owncloud/android/ui/fragment/OCFileListFragmentStaticServerIT.kt +++ b/app/src/androidTest/java/com/owncloud/android/ui/fragment/OCFileListFragmentStaticServerIT.kt @@ -231,7 +231,7 @@ class OCFileListFragmentStaticServerIT : AbstractIT() { sut.storageManager.saveFile(this) } - OCFile("/Foo\\u202Edm.exe").apply { + OCFile("/Foo%e2%80%aedm.exe").apply { remoteId = "000000011" parentId = sut.storageManager.getFileByEncryptedRemotePath("/").fileId modificationTimestamp = 1000 From acc424672a186440c509889189cff62257e5eaa6 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 14 Aug 2025 15:33:20 +0200 Subject: [PATCH 05/35] add: dimens for grid layout Signed-off-by: alperozturk --- app/src/main/res/layout/grid_item.xml | 101 ++++++++++++-------------- app/src/main/res/values/dims.xml | 18 +++-- 2 files changed, 57 insertions(+), 62 deletions(-) diff --git a/app/src/main/res/layout/grid_item.xml b/app/src/main/res/layout/grid_item.xml index 38ff6bc98e37..2c1180306489 100644 --- a/app/src/main/res/layout/grid_item.xml +++ b/app/src/main/res/layout/grid_item.xml @@ -8,8 +8,8 @@ ~ SPDX-FileCopyrightText: 2015 ownCloud Inc. ~ SPDX-License-Identifier: GPL-2.0-only AND (AGPL-3.0-or-later OR GPL-2.0-only) --> - - - - - @@ -151,56 +140,58 @@ app:layout_constraintTop_toTopOf="parent" tools:visibility="visible" /> - + app:layout_constraintTop_toBottomOf="@+id/thumbnail"> - - - + + + + + + + - - + android:background="@color/transparent" + android:contentDescription="@string/overflow_menu" + android:translationZ="2dp" + app:srcCompat="@drawable/ic_dots_vertical" + app:layout_constraintEnd_toEndOf="parent" + tools:ignore="TouchTargetSizeCheck" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintBottom_toBottomOf="parent" /> - + \ No newline at end of file diff --git a/app/src/main/res/values/dims.xml b/app/src/main/res/values/dims.xml index c57b6f3f9d93..b83683cbecce 100644 --- a/app/src/main/res/values/dims.xml +++ b/app/src/main/res/values/dims.xml @@ -36,9 +36,20 @@ 100dp 100dp 4dp + + 24dp + 60dp 10dp 2dp 22sp + 2dp + 4dp + 18dp + 6dp + 20dp + 130dp + 120dp + 140dp 180dp 2dp @@ -100,13 +111,6 @@ 48dp 24dp 24dp - 2dp - 4dp - 18dp - 6dp - 20dp - 130dp - 120dp 21dp -8dp 40dp From 2ce7fa6c3fcfa0ecc840f83e99c722afe728e00c Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 14 Aug 2025 16:09:22 +0200 Subject: [PATCH 06/35] fix: layout order Signed-off-by: alperozturk --- app/src/main/res/layout/grid_item.xml | 77 ++++++++++++--------------- app/src/main/res/values/dims.xml | 2 - 2 files changed, 33 insertions(+), 46 deletions(-) diff --git a/app/src/main/res/layout/grid_item.xml b/app/src/main/res/layout/grid_item.xml index 2c1180306489..b51579183643 100644 --- a/app/src/main/res/layout/grid_item.xml +++ b/app/src/main/res/layout/grid_item.xml @@ -140,58 +140,47 @@ app:layout_constraintTop_toTopOf="parent" tools:visibility="visible" /> - - - - - - - - - + + + android:maxLines="1" + android:text="@string/placeholder_extension" + android:textSize="@dimen/grid_item_text_size" /> + + + - \ No newline at end of file diff --git a/app/src/main/res/values/dims.xml b/app/src/main/res/values/dims.xml index b83683cbecce..6d02a5f69210 100644 --- a/app/src/main/res/values/dims.xml +++ b/app/src/main/res/values/dims.xml @@ -37,7 +37,6 @@ 100dp 4dp - 24dp 60dp 10dp 2dp @@ -46,7 +45,6 @@ 4dp 18dp 6dp - 20dp 130dp 120dp From 00cfdaa170f37cfb22382a312baffce253ae9d3c Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 15 Aug 2025 13:59:21 +0200 Subject: [PATCH 07/35] fix: layout for small screen devices Signed-off-by: alperozturk --- .../android/ui/adapter/OCFileListAdapter.java | 39 +++++++++- .../owncloud/android/utils/DisplayUtils.java | 4 + .../android/utils/FileStorageUtils.java | 5 -- app/src/main/res/layout/grid_item.xml | 74 ++++++++++--------- app/src/main/res/values/dims.xml | 1 - 5 files changed, 82 insertions(+), 41 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java index 2af88b8c56a0..5946589893aa 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java @@ -26,8 +26,10 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.ViewParent; import android.widget.ImageView; import android.widget.LinearLayout; +import android.widget.TextView; import com.elyeproj.loaderviewlibrary.LoaderImageView; import com.google.android.material.chip.Chip; @@ -133,6 +135,12 @@ public class OCFileListAdapter extends RecyclerView.Adapter private constructor } - public static boolean isRTL() { - return TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()) == View.LAYOUT_DIRECTION_RTL; - } - public static Pair getFilenameAndExtension(String filename, boolean isFolder, boolean isRTL) { if (isFolder) { return new Pair<>(filename, ""); diff --git a/app/src/main/res/layout/grid_item.xml b/app/src/main/res/layout/grid_item.xml index b51579183643..0f273b9d68c6 100644 --- a/app/src/main/res/layout/grid_item.xml +++ b/app/src/main/res/layout/grid_item.xml @@ -141,46 +141,52 @@ tools:visibility="visible" /> - - - + + + + + + + + + android:background="@color/transparent" + android:contentDescription="@string/overflow_menu" + android:translationZ="2dp" + app:srcCompat="@drawable/ic_dots_vertical" + tools:ignore="TouchTargetSizeCheck" /> - - - \ No newline at end of file diff --git a/app/src/main/res/values/dims.xml b/app/src/main/res/values/dims.xml index 6d02a5f69210..61c576e66efd 100644 --- a/app/src/main/res/values/dims.xml +++ b/app/src/main/res/values/dims.xml @@ -37,7 +37,6 @@ 100dp 4dp - 60dp 10dp 2dp 22sp From 9a7a8e268133464803f88d0e144e258876624933 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 15 Aug 2025 14:08:58 +0200 Subject: [PATCH 08/35] fix: configure only for grid view Signed-off-by: alperozturk --- .../com/owncloud/android/ui/adapter/OCFileListAdapter.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java index 5946589893aa..ef1dbdd60a23 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java @@ -593,8 +593,10 @@ private void configureFilenameContainerMargin(ListGridItemViewHolder holder, OCF } private void setFileNameAndExtension(ListGridItemViewHolder holder, OCFile file) { - configureFilenameContainerMargin(holder,file); - configureFilenameMaxWidth(holder,file); + if (gridView) { + configureFilenameContainerMargin(holder,file); + configureFilenameMaxWidth(holder,file); + } final String filename = mStorageManager.getFilenameConsideringOfflineOperation(file); final var pair = FileStorageUtils.getFilenameAndExtension(filename, file.isFolder(), isRTL); From 73692d0c4b2e0d621a1bc6b395c7fa78cdbaf412 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 15 Aug 2025 14:16:39 +0200 Subject: [PATCH 09/35] add: file name landscape margin value Signed-off-by: alperozturk --- .../android/ui/adapter/OCFileListAdapter.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java index ef1dbdd60a23..16918dce4dc6 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java @@ -16,6 +16,7 @@ import android.app.Activity; import android.content.ContentValues; import android.content.res.ColorStateList; +import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Color; import android.graphics.drawable.Drawable; @@ -139,6 +140,7 @@ public class OCFileListAdapter extends RecyclerView.Adapter Date: Fri, 15 Aug 2025 14:24:46 +0200 Subject: [PATCH 10/35] add: orientation utility function Signed-off-by: alperozturk --- .../com/owncloud/android/ui/adapter/OCFileListAdapter.java | 3 +-- .../main/java/com/owncloud/android/utils/DisplayUtils.java | 5 +++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java index 16918dce4dc6..cf96cf3682fd 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java @@ -16,7 +16,6 @@ import android.app.Activity; import android.content.ContentValues; import android.content.res.ColorStateList; -import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Color; import android.graphics.drawable.Drawable; @@ -210,7 +209,7 @@ public OCFileListAdapter( } private static int getFilenameMargin() { - if (MainApp.getAppContext().getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { + if (DisplayUtils.isOrientationLandscape()) { return FILE_NAME_LANDSCAPE_MARGIN_START; } else { return FILE_NAME_MARGIN_START; diff --git a/app/src/main/java/com/owncloud/android/utils/DisplayUtils.java b/app/src/main/java/com/owncloud/android/utils/DisplayUtils.java index 66151dd5ea5d..1850a9c8f855 100644 --- a/app/src/main/java/com/owncloud/android/utils/DisplayUtils.java +++ b/app/src/main/java/com/owncloud/android/utils/DisplayUtils.java @@ -26,6 +26,7 @@ import android.app.Activity; import android.content.Context; import android.content.Intent; +import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Color; @@ -689,6 +690,10 @@ public static boolean isRTL() { return TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()) == View.LAYOUT_DIRECTION_RTL; } + public static boolean isOrientationLandscape() { + return MainApp.getAppContext().getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE; + } + static public void showServerOutdatedSnackbar(Activity activity, int length) { Snackbar.make(activity.findViewById(android.R.id.content), R.string.outdated_server, length) From 632b54e6656805aacb37dbbc3ffcc591736cbeaf Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 15 Aug 2025 14:28:40 +0200 Subject: [PATCH 11/35] add: simpler configuration functions Signed-off-by: alperozturk --- .../android/ui/adapter/OCFileListAdapter.java | 26 +++++++------------ 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java index cf96cf3682fd..3a16e13d00c4 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java @@ -208,7 +208,7 @@ public OCFileListAdapter( isRTL = DisplayUtils.isRTL(); } - private static int getFilenameMargin() { + private static int getFilenameMarginStart() { if (DisplayUtils.isOrientationLandscape()) { return FILE_NAME_LANDSCAPE_MARGIN_START; } else { @@ -576,27 +576,21 @@ private void updateLivePhotoIndicators(ListViewHolder holder, OCFile file) { } private void configureFilenameMaxWidth(ListGridItemViewHolder holder, OCFile file) { - int maxWidthInDp = FILE_NAME_MAX_WIDTH; - if (file.isFolder()) { - maxWidthInDp = FOLDER_NAME_MAX_WIDTH; - } - - int maxWidthInPixel = DisplayUtils.convertDpToPixel(maxWidthInDp, MainApp.getAppContext()); - holder.getFileName().setMaxWidth(maxWidthInPixel); + int dp = file.isFolder() ? FOLDER_NAME_MAX_WIDTH : FILE_NAME_MAX_WIDTH; + int px = DisplayUtils.convertDpToPixel(dp, MainApp.getAppContext()); + holder.getFileName().setMaxWidth(px); } private void configureFilenameContainerMargin(ListGridItemViewHolder holder, OCFile file) { + int dp = file.isFolder() ? FOLDER_NAME_MARGIN_START : getFilenameMarginStart(); + int px = DisplayUtils.convertDpToPixel(dp, MainApp.getAppContext()); + TextView filenameTextView = holder.getFileName(); ViewParent parent = filenameTextView.getParent(); - int marginStartInDp = getFilenameMargin(); - if (file.isFolder()) { - marginStartInDp = FOLDER_NAME_MARGIN_START; - } - - if (parent instanceof LinearLayout filenameContainer && filenameContainer.getLayoutParams() instanceof LinearLayout.LayoutParams params) { - int marginStartInPixel = DisplayUtils.convertDpToPixel(marginStartInDp, MainApp.getAppContext()); - params.setMarginStart(marginStartInPixel); + if (parent instanceof LinearLayout filenameContainer && + filenameContainer.getLayoutParams() instanceof LinearLayout.LayoutParams params) { + params.setMarginStart(px); filenameContainer.setLayoutParams(params); } } From 3872e0ec36e3f80d5a0323efb697b9dd32378298 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 15 Aug 2025 15:42:51 +0200 Subject: [PATCH 12/35] add: filename container to the grid view holder Signed-off-by: alperozturk --- .../ui/adapter/ListGridItemViewHolder.kt | 2 ++ .../android/ui/adapter/OCFileListAdapter.java | 22 +++++++------------ .../adapter/OCFileListGridItemViewHolder.kt | 2 ++ .../ui/adapter/OCFileListItemViewHolder.kt | 2 ++ 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/ListGridItemViewHolder.kt b/app/src/main/java/com/owncloud/android/ui/adapter/ListGridItemViewHolder.kt index 70a7b6205498..a4d18ff4c4d4 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/ListGridItemViewHolder.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/ListGridItemViewHolder.kt @@ -7,9 +7,11 @@ */ package com.owncloud.android.ui.adapter +import android.widget.LinearLayout import android.widget.TextView internal interface ListGridItemViewHolder : ListViewHolder { val fileName: TextView val extension: TextView + val filenameContainer: LinearLayout? } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java index 3a16e13d00c4..329680b11364 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java @@ -26,10 +26,8 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.view.ViewParent; import android.widget.ImageView; import android.widget.LinearLayout; -import android.widget.TextView; import com.elyeproj.loaderviewlibrary.LoaderImageView; import com.google.android.material.chip.Chip; @@ -581,24 +579,20 @@ private void configureFilenameMaxWidth(ListGridItemViewHolder holder, OCFile fil holder.getFileName().setMaxWidth(px); } - private void configureFilenameContainerMargin(ListGridItemViewHolder holder, OCFile file) { - int dp = file.isFolder() ? FOLDER_NAME_MARGIN_START : getFilenameMarginStart(); - int px = DisplayUtils.convertDpToPixel(dp, MainApp.getAppContext()); - - TextView filenameTextView = holder.getFileName(); - ViewParent parent = filenameTextView.getParent(); - - if (parent instanceof LinearLayout filenameContainer && - filenameContainer.getLayoutParams() instanceof LinearLayout.LayoutParams params) { + private void configureFilenameContainerMargin(@NonNull LinearLayout filenameContainer, OCFile file) { + if (filenameContainer.getLayoutParams() instanceof LinearLayout.LayoutParams params) { + int dp = file.isFolder() ? FOLDER_NAME_MARGIN_START : getFilenameMarginStart(); + int px = DisplayUtils.convertDpToPixel(dp, MainApp.getAppContext()); params.setMarginStart(px); filenameContainer.setLayoutParams(params); } } private void setFileNameAndExtension(ListGridItemViewHolder holder, OCFile file) { - if (gridView) { - configureFilenameContainerMargin(holder,file); - configureFilenameMaxWidth(holder,file); + LinearLayout filenameContainer = holder.getFilenameContainer(); + if (gridView && filenameContainer != null) { + configureFilenameContainerMargin(filenameContainer, file); + configureFilenameMaxWidth(holder, file); } final String filename = mStorageManager.getFilenameConsideringOfflineOperation(file); diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridItemViewHolder.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridItemViewHolder.kt index 3c0b4689daac..d23acf4b1048 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridItemViewHolder.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridItemViewHolder.kt @@ -25,6 +25,8 @@ internal class OCFileListGridItemViewHolder(var binding: GridItemBinding) : get() = binding.Filename override val extension: TextView get() = binding.extension + override val filenameContainer: LinearLayout + get() = binding.filenameContainer override val thumbnail: ImageView get() = binding.thumbnail diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListItemViewHolder.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListItemViewHolder.kt index 96da2b7e5c67..99086cf17d55 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListItemViewHolder.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListItemViewHolder.kt @@ -45,6 +45,8 @@ internal class OCFileListItemViewHolder(private var binding: ListItemBinding) : get() = binding.Filename override val extension: TextView get() = binding.extension + override val filenameContainer: LinearLayout? + get() = null override val thumbnail: ImageView get() = binding.thumbnailLayout.thumbnail override val tagsGroup: ChipGroup From 739f21aca60540e8da55bb0e858e8bb1d4d7f89a Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 15 Aug 2025 16:02:35 +0200 Subject: [PATCH 13/35] fix: overly concrete parameter usage Signed-off-by: alperozturk --- .../com/owncloud/android/ui/adapter/OCFileListAdapter.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java index 329680b11364..a9e3f0be7bc9 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java @@ -62,6 +62,7 @@ import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.lib.resources.files.model.RemoteFile; +import com.owncloud.android.lib.resources.files.model.ServerFileInterface; import com.owncloud.android.lib.resources.shares.OCShare; import com.owncloud.android.lib.resources.shares.ShareType; import com.owncloud.android.lib.resources.shares.ShareeUser; @@ -573,13 +574,13 @@ private void updateLivePhotoIndicators(ListViewHolder holder, OCFile file) { } } - private void configureFilenameMaxWidth(ListGridItemViewHolder holder, OCFile file) { + private void configureFilenameMaxWidth(ListGridItemViewHolder holder, ServerFileInterface file) { int dp = file.isFolder() ? FOLDER_NAME_MAX_WIDTH : FILE_NAME_MAX_WIDTH; int px = DisplayUtils.convertDpToPixel(dp, MainApp.getAppContext()); holder.getFileName().setMaxWidth(px); } - private void configureFilenameContainerMargin(@NonNull LinearLayout filenameContainer, OCFile file) { + private void configureFilenameContainerMargin(@NonNull LinearLayout filenameContainer, ServerFileInterface file) { if (filenameContainer.getLayoutParams() instanceof LinearLayout.LayoutParams params) { int dp = file.isFolder() ? FOLDER_NAME_MARGIN_START : getFilenameMarginStart(); int px = DisplayUtils.convertDpToPixel(dp, MainApp.getAppContext()); From 54d468bdbc51037fc3bbaac50f9766b85d9bfffd Mon Sep 17 00:00:00 2001 From: alperozturk Date: Sat, 16 Aug 2025 07:55:50 +0200 Subject: [PATCH 14/35] fix: padding between thumbnail and file name Signed-off-by: alperozturk --- .../com/owncloud/android/ui/adapter/GroupfolderListAdapter.kt | 1 + app/src/main/res/layout/grid_item.xml | 1 + 2 files changed, 2 insertions(+) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/GroupfolderListAdapter.kt b/app/src/main/java/com/owncloud/android/ui/adapter/GroupfolderListAdapter.kt index 7f15ae9610c1..b82e665d596d 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/GroupfolderListAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/GroupfolderListAdapter.kt @@ -53,6 +53,7 @@ class GroupfolderListAdapter( listHolder.apply { fileName.text = file.name fileSize.text = file.parentFile?.path ?: "/" + extension.visibility = View.GONE fileSizeSeparator.visibility = View.GONE lastModification.visibility = View.GONE checkbox.visibility = View.GONE diff --git a/app/src/main/res/layout/grid_item.xml b/app/src/main/res/layout/grid_item.xml index 0f273b9d68c6..3dd0ff40b6bf 100644 --- a/app/src/main/res/layout/grid_item.xml +++ b/app/src/main/res/layout/grid_item.xml @@ -145,6 +145,7 @@ android:layout_width="0dp" android:layout_height="@dimen/iconized_single_line_item_icon_size" android:orientation="horizontal" + app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/thumbnail"> From e256b29d601c226876bd88ba6e7911b439c4d10c Mon Sep 17 00:00:00 2001 From: alperozturk Date: Sat, 16 Aug 2025 08:20:24 +0200 Subject: [PATCH 15/35] fix: folder name max width Signed-off-by: alperozturk --- .../java/com/owncloud/android/ui/adapter/OCFileListAdapter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java index a9e3f0be7bc9..cd71fa233587 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java @@ -135,7 +135,7 @@ public class OCFileListAdapter extends RecyclerView.Adapter Date: Mon, 18 Aug 2025 18:13:27 +0200 Subject: [PATCH 16/35] fix: git conflicts Signed-off-by: alperozturk --- .../ui/adapter/ListGridItemViewHolder.kt | 2 - .../android/ui/adapter/OCFileListAdapter.java | 91 +++++++++++++------ .../adapter/OCFileListGridItemViewHolder.kt | 2 - .../ui/adapter/OCFileListItemViewHolder.kt | 2 - app/src/main/res/layout/grid_item.xml | 38 ++++---- app/src/main/res/values/dims.xml | 1 + 6 files changed, 87 insertions(+), 49 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/ListGridItemViewHolder.kt b/app/src/main/java/com/owncloud/android/ui/adapter/ListGridItemViewHolder.kt index a4d18ff4c4d4..70a7b6205498 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/ListGridItemViewHolder.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/ListGridItemViewHolder.kt @@ -7,11 +7,9 @@ */ package com.owncloud.android.ui.adapter -import android.widget.LinearLayout import android.widget.TextView internal interface ListGridItemViewHolder : ListViewHolder { val fileName: TextView val extension: TextView - val filenameContainer: LinearLayout? } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java index cd71fa233587..0472e7fbbb0c 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java @@ -15,6 +15,7 @@ import android.annotation.SuppressLint; import android.app.Activity; import android.content.ContentValues; +import android.content.Context; import android.content.res.ColorStateList; import android.content.res.Resources; import android.graphics.Color; @@ -134,12 +135,16 @@ public class OCFileListAdapter extends RecyclerView.Adapter - + android:layout_gravity="center" + android:orientation="horizontal"> - - + + \ No newline at end of file diff --git a/app/src/main/res/values/dims.xml b/app/src/main/res/values/dims.xml index 61c576e66efd..fe9bce26d327 100644 --- a/app/src/main/res/values/dims.xml +++ b/app/src/main/res/values/dims.xml @@ -46,6 +46,7 @@ 6dp 130dp 120dp + 50dp 140dp 180dp From 345367f8e0fcc47a89f5bdf6bb17c7bdc45907e8 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Sat, 16 Aug 2025 10:58:12 +0200 Subject: [PATCH 17/35] add: more button margin Signed-off-by: alperozturk --- .../owncloud/android/ui/adapter/OCFileListAdapter.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java index 0472e7fbbb0c..d697317a30b6 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java @@ -141,6 +141,9 @@ public class OCFileListAdapter extends RecyclerView.Adapter Date: Sat, 16 Aug 2025 14:23:10 +0200 Subject: [PATCH 18/35] bi,di2 Signed-off-by: alperozturk --- .../ui/adapter/ListGridItemViewHolder.kt | 2 +- .../android/ui/adapter/OCFileListAdapter.java | 106 ++++--------- .../ui/adapter/OCFileListGridController.kt | 149 ++++++++++++++++++ .../adapter/OCFileListGridItemViewHolder.kt | 19 ++- .../ui/adapter/OCFileListViewHolder.kt | 13 +- .../android/utils/FileStorageUtils.java | 35 ++++ app/src/main/res/layout/grid_item.xml | 50 +++++- app/src/main/res/values/dims.xml | 1 + .../client/utils/FileStorageUtilsTest.kt | 30 ++++ 9 files changed, 313 insertions(+), 92 deletions(-) create mode 100644 app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridController.kt diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/ListGridItemViewHolder.kt b/app/src/main/java/com/owncloud/android/ui/adapter/ListGridItemViewHolder.kt index 70a7b6205498..bbbfc9ade682 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/ListGridItemViewHolder.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/ListGridItemViewHolder.kt @@ -11,5 +11,5 @@ import android.widget.TextView internal interface ListGridItemViewHolder : ListViewHolder { val fileName: TextView - val extension: TextView + val extension: TextView? } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java index d697317a30b6..d4c6cbc623e1 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java @@ -15,7 +15,6 @@ import android.annotation.SuppressLint; import android.app.Activity; import android.content.ContentValues; -import android.content.Context; import android.content.res.ColorStateList; import android.content.res.Resources; import android.graphics.Color; @@ -63,7 +62,6 @@ import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.lib.resources.files.model.RemoteFile; -import com.owncloud.android.lib.resources.files.model.ServerFileInterface; import com.owncloud.android.lib.resources.shares.OCShare; import com.owncloud.android.lib.resources.shares.ShareType; import com.owncloud.android.lib.resources.shares.ShareeUser; @@ -104,6 +102,7 @@ import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import kotlin.Pair; import me.zhanghai.android.fastscroll.PopupTextProvider; /** @@ -135,20 +134,6 @@ public class OCFileListAdapter extends RecyclerView.Adapter recommendedFiles = new ArrayList<>(); @@ -575,78 +561,42 @@ private void updateLivePhotoIndicators(ListViewHolder holder, OCFile file) { } public void invalidateGridLayoutCachedWidths() { - lastColumnCount = -1; - lastScreenWidth = -1; + gridController.invalidateGridLayoutCachedWidths(); } - private void configureFilenameMaxWidth(ListGridItemViewHolder holder, ServerFileInterface file) { - final Context context = MainApp.getAppContext(); - if (context == null) { - Log_OC.w(TAG, "Grid layout max file width configuration cancelled, context is null"); - return; - } - - final int columnCount = ocFileListFragmentInterface.getColumnsCount(); - final int screenWidth = DisplayUtils.convertDpToPixel( - context.getResources().getConfiguration().screenWidthDp, context); - - // dont recalculate same value - if (columnCount != lastColumnCount || screenWidth != lastScreenWidth) { - // available width per column - int cellWidth = screenWidth / columnCount; - - int moreButtonPx = context.getResources().getDimensionPixelSize(R.dimen.iconized_single_line_item_icon_size); - - // 3-4 chars width - int extensionMinPx = (int) (context.getResources().getDisplayMetrics().density * EXTENSION_RESERVED_DP); - - int paddingPx = (int) (context.getResources().getDisplayMetrics().density * SAFETY_MARGIN_DP); - int moreButtonMarginPx = (int) (context.getResources().getDisplayMetrics().density * MORE_BUTTON_MARGIN_DP); - - // name + more button - cachedFolderMaxWidth = cellWidth - moreButtonPx - paddingPx - moreButtonMarginPx; - - // name + extension + more button - cachedFileMaxWidth = cellWidth - moreButtonPx - extensionMinPx - paddingPx - moreButtonMarginPx; - - // fallback - if (cachedFolderMaxWidth < 0) { - cachedFolderMaxWidth = context.getResources().getDimensionPixelSize( - R.dimen.grid_container_default_max_file_name); - } - if (cachedFileMaxWidth < 0) { - cachedFileMaxWidth = context.getResources().getDimensionPixelSize( - R.dimen.grid_container_default_max_file_name); - } - - lastColumnCount = columnCount; - lastScreenWidth = screenWidth; - } + private void setFileNameAndExtension(ListGridItemViewHolder holder, OCFile file) { + final String filename = mStorageManager.getFilenameConsideringOfflineOperation(file); + final var pair = FileStorageUtils.getFilenameAndExtension(filename, file.isFolder(), isRTL); + final boolean isFolder = file.isFolder(); - if (file.isFolder()) { - holder.getFileName().setMaxWidth(cachedFolderMaxWidth); + if (holder instanceof OCFileListGridItemViewHolder gridItemViewHolder) { + final boolean containsBidiControlCharacters = FileStorageUtils.containsBidiControlCharacters(filename); + final int columnCount = ocFileListFragmentInterface.getColumnsCount(); + gridController.handleGridMode(gridItemViewHolder, pair, file, containsBidiControlCharacters, isFolder, columnCount); } else { - holder.getFileName().setMaxWidth(cachedFileMaxWidth); + handleListMode(holder, pair, isFolder); } } - private void setFileNameAndExtension(ListGridItemViewHolder holder, OCFile file) { - if (gridView) { - configureFilenameMaxWidth(holder, file); - } + // List mode ALWAYS uses filename + extension format since we have enough space + private void handleListMode(ListGridItemViewHolder holder, + Pair filenamePair, + boolean isFolder) { + holder.getFileName().setText(filenamePair.getFirst()); - final String filename = mStorageManager.getFilenameConsideringOfflineOperation(file); - final var pair = FileStorageUtils.getFilenameAndExtension(filename, file.isFolder(), isRTL); - - if (file.isFolder()) { - holder.getFileName().setText(pair.getFirst()); - holder.getExtension().setVisibility(View.GONE); - return; + if (holder.getExtension() != null) { + if (isFolder) { + holder.getExtension().setVisibility(View.GONE); + } else { + holder.getExtension().setVisibility(View.VISIBLE); + holder.getExtension().setText(filenamePair.getSecond()); + } } - holder.getExtension().setVisibility(View.VISIBLE); - holder.getFileName().setText(pair.getFirst()); - holder.getExtension().setText(pair.getSecond()); + // Hide bidi filename container + if (holder instanceof OCFileListGridItemViewHolder gridItemViewHolder) { + gridItemViewHolder.getBinding().bidiFilenameContainer.setVisibility(View.GONE); + } } private void bindListItemViewHolder(ListItemViewHolder holder, OCFile file) { diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridController.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridController.kt new file mode 100644 index 000000000000..841bd994df41 --- /dev/null +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridController.kt @@ -0,0 +1,149 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2025 Alper Ozturk + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +package com.owncloud.android.ui.adapter + +import android.view.View +import com.owncloud.android.MainApp +import com.owncloud.android.R +import com.owncloud.android.datamodel.OCFile +import com.owncloud.android.lib.common.utils.Log_OC +import com.owncloud.android.lib.resources.files.model.ServerFileInterface +import com.owncloud.android.utils.DisplayUtils + +class OCFileListGridController { + + companion object { + private const val TAG = "OCFileListGridController" + + // Reserved space for file extension text in DP + private const val EXTENSION_RESERVED_DP: Int = 36 + + // Padding between text and more icon in DP + private const val SAFETY_MARGIN_DP: Int = 8 + + // extra spacing between text and more button + private const val MORE_BUTTON_MARGIN_DP: Int = 8 + } + + private var lastScreenWidth = -1 + private var lastColumnCount = -1 + private var cachedFolderMaxWidth = -1 + private var cachedFileMaxWidth = -1 + + private fun configureFilenameMaxWidth( + holder: OCFileListGridItemViewHolder, + file: ServerFileInterface, + columnCount: Int + ) { + val context = MainApp.getAppContext() + if (context == null) { + Log_OC.w(TAG, "Grid layout max file width configuration cancelled, context is null") + return + } + + val screenWidth = DisplayUtils.convertDpToPixel( + context.resources.configuration.screenWidthDp.toFloat(), + context + ) + + // dont recalculate same value + if (columnCount != lastColumnCount || screenWidth != lastScreenWidth) { + // available width per column + val cellWidth = screenWidth / columnCount + + val moreButtonPx = context.resources.getDimensionPixelSize(R.dimen.iconized_single_line_item_icon_size) + + // 3-4 chars width + + val density = context.resources.displayMetrics.density + val extensionMinPx = (density * EXTENSION_RESERVED_DP).toInt() + val paddingPx = (density * SAFETY_MARGIN_DP).toInt() + val moreButtonMarginPx = (density * MORE_BUTTON_MARGIN_DP).toInt() + + // name + more button + cachedFolderMaxWidth = cellWidth - moreButtonPx - paddingPx - moreButtonMarginPx + + // name + extension + more button + cachedFileMaxWidth = cellWidth - moreButtonPx - extensionMinPx - paddingPx - moreButtonMarginPx + + // fallback + if (cachedFolderMaxWidth < 0) { + cachedFolderMaxWidth = context.resources.getDimensionPixelSize( + R.dimen.grid_container_default_max_file_name + ) + } + if (cachedFileMaxWidth < 0) { + cachedFileMaxWidth = context.resources.getDimensionPixelSize( + R.dimen.grid_container_default_max_file_name + ) + } + + lastColumnCount = columnCount + lastScreenWidth = screenWidth + } + + holder.bidiFilename.maxWidth = if (file.isFolder) cachedFolderMaxWidth else cachedFileMaxWidth + } + + fun invalidateGridLayoutCachedWidths() { + lastColumnCount = -1 + lastScreenWidth = -1 + } + + private fun useBidiSpecificLayout( + gridItemViewHolder: OCFileListGridItemViewHolder, + filenamePair: Pair, + file: OCFile, + columnCount: Int + ) { + val (base, ext) = filenamePair + + gridItemViewHolder.run { + more.visibility = View.GONE + fileName.visibility = View.GONE + binding.bidiFilenameContainer.visibility = View.VISIBLE + + configureFilenameMaxWidth(gridItemViewHolder, file, columnCount) + bidiFilename.text = base + extension?.text = ext + } + } + + private fun useNormalFilenameLayout( + gridItemViewHolder: OCFileListGridItemViewHolder, + filenamePair: Pair, + isFolder: Boolean + ) { + val (base, ext) = filenamePair + + gridItemViewHolder.run { + more.visibility = View.VISIBLE + fileName.visibility = View.VISIBLE + binding.bidiFilenameContainer.visibility = View.GONE + + val displayName = if (isFolder) base else base + ext + fileName.text = displayName + extension?.visibility = View.GONE + } + } + + fun handleGridMode( + gridItemViewHolder: OCFileListGridItemViewHolder, + filenamePair: Pair, + file: OCFile, + containsBidiControlCharacters: Boolean, + isFolder: Boolean, + columnCount: Int + ) { + if (containsBidiControlCharacters) { + useBidiSpecificLayout(gridItemViewHolder, filenamePair, file, columnCount) + } else { + useNormalFilenameLayout(gridItemViewHolder, filenamePair, isFolder) + } + } +} diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridItemViewHolder.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridItemViewHolder.kt index 3c0b4689daac..8d1c019276fd 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridItemViewHolder.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridItemViewHolder.kt @@ -12,19 +12,26 @@ import android.widget.ImageButton import android.widget.ImageView import android.widget.LinearLayout import android.widget.TextView +import androidx.core.view.isVisible import androidx.recyclerview.widget.RecyclerView import com.elyeproj.loaderviewlibrary.LoaderImageView import com.owncloud.android.databinding.GridItemBinding -internal class OCFileListGridItemViewHolder(var binding: GridItemBinding) : +class OCFileListGridItemViewHolder(var binding: GridItemBinding) : RecyclerView.ViewHolder( binding.root ), ListGridItemViewHolder { + val bidiFilename: TextView + get() = binding.bidiFilename override val fileName: TextView get() = binding.Filename - override val extension: TextView - get() = binding.extension + override val extension: TextView? + get() = if (binding.bidiFilenameContainer.isVisible) { + binding.bidiExtension + } else { + null + } override val thumbnail: ImageView get() = binding.thumbnail @@ -58,7 +65,11 @@ internal class OCFileListGridItemViewHolder(var binding: GridItemBinding) : override val fileFeaturesLayout: LinearLayout get() = binding.fileFeaturesLayout override val more: ImageButton - get() = binding.more + get() = if (binding.bidiFilenameContainer.isVisible) { + binding.bidiMore + } else { + binding.more + } init { binding.favoriteAction.drawable.mutate() diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListViewHolder.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListViewHolder.kt index 7805c21c7f6d..b0a0c037cd3a 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListViewHolder.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListViewHolder.kt @@ -12,6 +12,7 @@ import android.widget.ImageButton import android.widget.ImageView import android.widget.LinearLayout import android.widget.TextView +import androidx.core.view.isVisible import androidx.recyclerview.widget.RecyclerView import com.elyeproj.loaderviewlibrary.LoaderImageView import com.owncloud.android.databinding.GridItemBinding @@ -26,7 +27,11 @@ internal class OCFileListViewHolder(var binding: GridItemBinding) : get() = binding.thumbnail override val imageFileName: TextView - get() = binding.Filename + get() = if (binding.bidiFilenameContainer.isVisible) { + binding.bidiFilename + } else { + binding.Filename + } override fun showVideoOverlay() { // noop @@ -47,7 +52,11 @@ internal class OCFileListViewHolder(var binding: GridItemBinding) : override val unreadComments: ImageView get() = binding.unreadComments override val more: ImageButton - get() = binding.more + get() = if (binding.bidiFilenameContainer.isVisible) { + binding.bidiMore + } else { + binding.more + } override val fileFeaturesLayout: LinearLayout get() = binding.fileFeaturesLayout override val gridLivePhotoIndicator: ImageView diff --git a/app/src/main/java/com/owncloud/android/utils/FileStorageUtils.java b/app/src/main/java/com/owncloud/android/utils/FileStorageUtils.java index 2e5e245904f4..d58df9624304 100644 --- a/app/src/main/java/com/owncloud/android/utils/FileStorageUtils.java +++ b/app/src/main/java/com/owncloud/android/utils/FileStorageUtils.java @@ -37,6 +37,9 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -71,6 +74,38 @@ private FileStorageUtils() { // utility class -> private constructor } + public static boolean containsBidiControlCharacters(String filename) { + if (filename == null) return false; + + String decoded; + try { + decoded = URLDecoder.decode(filename, StandardCharsets.UTF_8.toString()); + } catch (UnsupportedEncodingException e) { + return false; + } + + int[] bidiControlCharacters = { + 0x202A, 0x202B, 0x202C, 0x202D, 0x202E, + 0x200E, 0x200F, 0x2066, 0x2067, 0x2068, + 0x2069 + }; + + for (int i = 0; i < decoded.length(); i++) { + int codePoint = decoded.codePointAt(i); + for (int chars : bidiControlCharacters) { + if (codePoint == chars) { + return true; + } + } + } + + for (char c : decoded.toCharArray()) { + if (c < 32) return true; + } + + return false; + } + public static Pair getFilenameAndExtension(String filename, boolean isFolder, boolean isRTL) { if (isFolder) { return new Pair<>(filename, ""); diff --git a/app/src/main/res/layout/grid_item.xml b/app/src/main/res/layout/grid_item.xml index e5b158d3ee17..d86a528733d2 100644 --- a/app/src/main/res/layout/grid_item.xml +++ b/app/src/main/res/layout/grid_item.xml @@ -141,12 +141,14 @@ tools:visibility="visible" /> + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/dims.xml b/app/src/main/res/values/dims.xml index fe9bce26d327..7946613ed0e2 100644 --- a/app/src/main/res/values/dims.xml +++ b/app/src/main/res/values/dims.xml @@ -37,6 +37,7 @@ 100dp 4dp + 20dp 10dp 2dp 22sp diff --git a/app/src/test/java/com/nextcloud/client/utils/FileStorageUtilsTest.kt b/app/src/test/java/com/nextcloud/client/utils/FileStorageUtilsTest.kt index 40046e241c7e..d38dfe37585b 100644 --- a/app/src/test/java/com/nextcloud/client/utils/FileStorageUtilsTest.kt +++ b/app/src/test/java/com/nextcloud/client/utils/FileStorageUtilsTest.kt @@ -268,4 +268,34 @@ class FileStorageUtilsTest { assertEquals("Foo\u202Edm", result.first) assertEquals(".exe", result.second) } + + @Test + fun testContainsBidiControlCharactersWhenGivenNormalFilenameShouldReturnFalse() { + val result = FileStorageUtils.containsBidiControlCharacters("myfile.txt") + assertFalse(result) + } + + @Test + fun testContainsBidiControlCharactersWhenGivenFilenameWithEncodedRtlOverrideShouldReturnTrue() { + val result = FileStorageUtils.containsBidiControlCharacters("myfile%e2%80%aetxt.exe") + assertTrue(result) + } + + @Test + fun testContainsBidiControlCharactersWhenGivenFilenameWithRawRtlOverrideCharShouldReturnTrue() { + val result = FileStorageUtils.containsBidiControlCharacters("safe\u202Eevil.exe") + assertTrue(result) + } + + @Test + fun testContainsBidiControlCharactersWhenGivenFilenameWithControlCharacterShouldReturnTrue() { + val result = FileStorageUtils.containsBidiControlCharacters("hello\u0001world.txt") + assertTrue(result) + } + + @Test + fun testContainsBidiControlCharactersWhenGivenNullShouldReturnFalse() { + val result = FileStorageUtils.containsBidiControlCharacters(null) + assertFalse(result) + } } From 4f38a4f4d8ba04850c5582221556f80e8db4e5a6 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 18 Aug 2025 18:16:27 +0200 Subject: [PATCH 19/35] add: grid layout recalculation Signed-off-by: alperozturk --- .../android/ui/activity/FileDisplayActivity.kt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt index a41d1f3d9599..646a08c26322 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt @@ -354,8 +354,22 @@ class FileDisplayActivity : } } } + + recalculateGridLayoutFilenameMaxWidths() + } + + @SuppressLint("NotifyDataSetChanged") + private fun recalculateGridLayoutFilenameMaxWidths() { + val fragment = fileListFragment ?: return + + val fileListAdapter = fragment.adapter + if (fileListAdapter != null && fileListAdapter.isGridView) { + fileListAdapter.invalidateGridLayoutCachedWidths() + fileListAdapter.notifyDataSetChanged() + } } + override fun onPostCreate(savedInstanceState: Bundle?) { super.onPostCreate(savedInstanceState) From 27194f26172890d169628eadd98471af8ea4a60b Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 19 Aug 2025 14:48:37 +0200 Subject: [PATCH 20/35] add: title and extension in file actions bottom sheet Signed-off-by: alperozturk --- .../ui/fileactions/FileActionsBottomSheet.kt | 13 +++- .../ui/activity/FileDisplayActivity.kt | 1 - .../android/ui/adapter/OCFileListAdapter.java | 10 +-- .../ui/adapter/OCFileListGridController.kt | 69 +++++++------------ .../res/layout/file_actions_bottom_sheet.xml | 17 +++-- 5 files changed, 49 insertions(+), 61 deletions(-) diff --git a/app/src/main/java/com/nextcloud/ui/fileactions/FileActionsBottomSheet.kt b/app/src/main/java/com/nextcloud/ui/fileactions/FileActionsBottomSheet.kt index 336954ea7f44..eea98ebf8439 100644 --- a/app/src/main/java/com/nextcloud/ui/fileactions/FileActionsBottomSheet.kt +++ b/app/src/main/java/com/nextcloud/ui/fileactions/FileActionsBottomSheet.kt @@ -33,6 +33,7 @@ import com.nextcloud.android.common.ui.theme.utils.ColorRole import com.nextcloud.client.account.CurrentAccountProvider import com.nextcloud.client.di.Injectable import com.nextcloud.client.di.ViewModelFactory +import com.nextcloud.utils.extensions.setVisibleIf import com.owncloud.android.R import com.owncloud.android.databinding.FileActionsBottomSheetBinding import com.owncloud.android.databinding.FileActionsBottomSheetItemBinding @@ -44,6 +45,7 @@ import com.owncloud.android.lib.resources.files.model.FileLockType import com.owncloud.android.ui.activity.ComponentsGetter import com.owncloud.android.utils.DisplayUtils import com.owncloud.android.utils.DisplayUtils.AvatarGenerationListener +import com.owncloud.android.utils.FileStorageUtils import com.owncloud.android.utils.theme.ViewThemeUtils import javax.inject.Inject @@ -204,11 +206,18 @@ class FileActionsBottomSheet : private fun displayTitle(titleFile: OCFile?) { val decryptedFileName = titleFile?.decryptedFileName if (decryptedFileName != null) { - decryptedFileName.let { - binding.title.text = it + val isFolder = titleFile.isFolder + val isRTL = DisplayUtils.isRTL() + val (base, ext) = FileStorageUtils.getFilenameAndExtension(decryptedFileName, isFolder, isRTL) + + binding.title.text = base + binding.extension.setVisibleIf(!isFolder) + if (!isFolder) { + binding.extension.text = ext } } else { binding.title.isVisible = false + binding.extension.isVisible = false } } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt index 646a08c26322..163c1a341f9f 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt @@ -369,7 +369,6 @@ class FileDisplayActivity : } } - override fun onPostCreate(savedInstanceState: Bundle?) { super.onPostCreate(savedInstanceState) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java index d4c6cbc623e1..81fa1bb87030 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java @@ -570,15 +570,12 @@ private void setFileNameAndExtension(ListGridItemViewHolder holder, OCFile file) final boolean isFolder = file.isFolder(); if (holder instanceof OCFileListGridItemViewHolder gridItemViewHolder) { - final boolean containsBidiControlCharacters = FileStorageUtils.containsBidiControlCharacters(filename); - final int columnCount = ocFileListFragmentInterface.getColumnsCount(); - gridController.handleGridMode(gridItemViewHolder, pair, file, containsBidiControlCharacters, isFolder, columnCount); + gridController.handleGridMode(filename, ocFileListFragmentInterface, gridItemViewHolder, pair, file); } else { handleListMode(holder, pair, isFolder); } } - // List mode ALWAYS uses filename + extension format since we have enough space private void handleListMode(ListGridItemViewHolder holder, Pair filenamePair, boolean isFolder) { @@ -592,11 +589,6 @@ private void handleListMode(ListGridItemViewHolder holder, holder.getExtension().setText(filenamePair.getSecond()); } } - - // Hide bidi filename container - if (holder instanceof OCFileListGridItemViewHolder gridItemViewHolder) { - gridItemViewHolder.getBinding().bidiFilenameContainer.setVisibility(View.GONE); - } } private void bindListItemViewHolder(ListItemViewHolder holder, OCFile file) { diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridController.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridController.kt index 841bd994df41..55c486bd0541 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridController.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridController.kt @@ -8,12 +8,15 @@ package com.owncloud.android.ui.adapter import android.view.View +import com.nextcloud.utils.extensions.setVisibleIf import com.owncloud.android.MainApp import com.owncloud.android.R import com.owncloud.android.datamodel.OCFile import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.lib.resources.files.model.ServerFileInterface +import com.owncloud.android.ui.interfaces.OCFileListFragmentInterface import com.owncloud.android.utils.DisplayUtils +import com.owncloud.android.utils.FileStorageUtils class OCFileListGridController { @@ -95,55 +98,31 @@ class OCFileListGridController { lastScreenWidth = -1 } - private fun useBidiSpecificLayout( - gridItemViewHolder: OCFileListGridItemViewHolder, - filenamePair: Pair, - file: OCFile, - columnCount: Int - ) { - val (base, ext) = filenamePair - - gridItemViewHolder.run { - more.visibility = View.GONE - fileName.visibility = View.GONE - binding.bidiFilenameContainer.visibility = View.VISIBLE - - configureFilenameMaxWidth(gridItemViewHolder, file, columnCount) - bidiFilename.text = base - extension?.text = ext - } - } - - private fun useNormalFilenameLayout( - gridItemViewHolder: OCFileListGridItemViewHolder, - filenamePair: Pair, - isFolder: Boolean - ) { - val (base, ext) = filenamePair - - gridItemViewHolder.run { - more.visibility = View.VISIBLE - fileName.visibility = View.VISIBLE - binding.bidiFilenameContainer.visibility = View.GONE - - val displayName = if (isFolder) base else base + ext - fileName.text = displayName - extension?.visibility = View.GONE - } - } - fun handleGridMode( + filename: String, + fragmentInterface: OCFileListFragmentInterface, gridItemViewHolder: OCFileListGridItemViewHolder, filenamePair: Pair, - file: OCFile, - containsBidiControlCharacters: Boolean, - isFolder: Boolean, - columnCount: Int + file: OCFile ) { - if (containsBidiControlCharacters) { - useBidiSpecificLayout(gridItemViewHolder, filenamePair, file, columnCount) - } else { - useNormalFilenameLayout(gridItemViewHolder, filenamePair, isFolder) + val containsBidiControlCharacters = FileStorageUtils.containsBidiControlCharacters(filename) + gridItemViewHolder.run { + more.setVisibleIf(!containsBidiControlCharacters) + fileName.setVisibleIf(!containsBidiControlCharacters) + binding.bidiFilenameContainer.setVisibleIf(containsBidiControlCharacters) + + if (containsBidiControlCharacters) { + val (base, ext) = filenamePair + configureFilenameMaxWidth(this, file, fragmentInterface.getColumnsCount()) + more.setOnClickListener { + fragmentInterface.onOverflowIconClicked(file, it) + } + bidiFilename.text = base + extension?.text = ext + } else { + fileName.text = filename + extension?.visibility = View.GONE + } } } } diff --git a/app/src/main/res/layout/file_actions_bottom_sheet.xml b/app/src/main/res/layout/file_actions_bottom_sheet.xml index 92c93182a241..cf2c493069b9 100644 --- a/app/src/main/res/layout/file_actions_bottom_sheet.xml +++ b/app/src/main/res/layout/file_actions_bottom_sheet.xml @@ -40,7 +40,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="@dimen/standard_margin" - android:gravity="center" + android:gravity="start" android:orientation="horizontal" android:visibility="visible"> @@ -53,13 +53,22 @@ + + + tools:text="@string/placeholder_extension" /> From f3cfd576c25cadee7aa1d3a7fcad4d56ee27217d Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 19 Aug 2025 14:53:17 +0200 Subject: [PATCH 21/35] fix: dodgy code in oc file list adapter Signed-off-by: alperozturk --- .../owncloud/android/ui/adapter/OCFileListAdapter.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java index 81fa1bb87030..9f0d356bc7d8 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java @@ -581,12 +581,13 @@ private void handleListMode(ListGridItemViewHolder holder, boolean isFolder) { holder.getFileName().setText(filenamePair.getFirst()); - if (holder.getExtension() != null) { + final var extension = holder.getExtension(); + if (extension != null) { if (isFolder) { - holder.getExtension().setVisibility(View.GONE); + extension.setVisibility(View.GONE); } else { - holder.getExtension().setVisibility(View.VISIBLE); - holder.getExtension().setText(filenamePair.getSecond()); + extension.setVisibility(View.VISIBLE); + extension.setText(filenamePair.getSecond()); } } } From a7c0f2e7554f891d8c1b192ab32e660acf7ab8e3 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 19 Aug 2025 14:54:49 +0200 Subject: [PATCH 22/35] add: new tests Signed-off-by: alperozturk --- .../java/com/nextcloud/client/utils/FileStorageUtilsTest.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/test/java/com/nextcloud/client/utils/FileStorageUtilsTest.kt b/app/src/test/java/com/nextcloud/client/utils/FileStorageUtilsTest.kt index d38dfe37585b..700346430803 100644 --- a/app/src/test/java/com/nextcloud/client/utils/FileStorageUtilsTest.kt +++ b/app/src/test/java/com/nextcloud/client/utils/FileStorageUtilsTest.kt @@ -298,4 +298,10 @@ class FileStorageUtilsTest { val result = FileStorageUtils.containsBidiControlCharacters(null) assertFalse(result) } + + @Test + fun testContainsBidiControlCharactersWhenGivenValidFilenameShouldReturnTrue() { + val result = FileStorageUtils.containsBidiControlCharacters("/Foo%e2%80%aedm.exe") + assertTrue(result) + } } From d863a8b90d5d91c0e23964022b2080379d5f7ca8 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 19 Aug 2025 14:55:18 +0200 Subject: [PATCH 23/35] add: new tests Signed-off-by: alperozturk --- .../java/com/nextcloud/client/utils/FileStorageUtilsTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/test/java/com/nextcloud/client/utils/FileStorageUtilsTest.kt b/app/src/test/java/com/nextcloud/client/utils/FileStorageUtilsTest.kt index 700346430803..f01451085400 100644 --- a/app/src/test/java/com/nextcloud/client/utils/FileStorageUtilsTest.kt +++ b/app/src/test/java/com/nextcloud/client/utils/FileStorageUtilsTest.kt @@ -283,7 +283,7 @@ class FileStorageUtilsTest { @Test fun testContainsBidiControlCharactersWhenGivenFilenameWithRawRtlOverrideCharShouldReturnTrue() { - val result = FileStorageUtils.containsBidiControlCharacters("safe\u202Eevil.exe") + val result = FileStorageUtils.containsBidiControlCharacters("safe\u202Enotsafe.exe") assertTrue(result) } From 6a5791785ca92cc84cf3ccfb55e95af36348f3fd Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 19 Aug 2025 15:59:28 +0200 Subject: [PATCH 24/35] fix: use only one more button Signed-off-by: alperozturk --- .../ui/adapter/OCFileListGridController.kt | 18 ++++- .../adapter/OCFileListGridItemViewHolder.kt | 6 +- .../ui/adapter/OCFileListViewHolder.kt | 6 +- app/src/main/res/layout/grid_item.xml | 75 +++++++------------ 4 files changed, 45 insertions(+), 60 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridController.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridController.kt index 55c486bd0541..91cc4821e549 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridController.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridController.kt @@ -8,6 +8,7 @@ package com.owncloud.android.ui.adapter import android.view.View +import androidx.constraintlayout.widget.ConstraintSet import com.nextcloud.utils.extensions.setVisibleIf import com.owncloud.android.MainApp import com.owncloud.android.R @@ -107,18 +108,27 @@ class OCFileListGridController { ) { val containsBidiControlCharacters = FileStorageUtils.containsBidiControlCharacters(filename) gridItemViewHolder.run { - more.setVisibleIf(!containsBidiControlCharacters) fileName.setVisibleIf(!containsBidiControlCharacters) binding.bidiFilenameContainer.setVisibleIf(containsBidiControlCharacters) if (containsBidiControlCharacters) { val (base, ext) = filenamePair configureFilenameMaxWidth(this, file, fragmentInterface.getColumnsCount()) - more.setOnClickListener { - fragmentInterface.onOverflowIconClicked(file, it) - } bidiFilename.text = base extension?.text = ext + + + val constraintLayout = gridItemViewHolder.binding.ListItemLayout + val set = ConstraintSet() + set.clone(constraintLayout) + set.clear(R.id.more, ConstraintSet.START) + set.connect( + R.id.more, + ConstraintSet.START, + R.id.bidi_extension, + ConstraintSet.END + ) + set.applyTo(constraintLayout) } else { fileName.text = filename extension?.visibility = View.GONE diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridItemViewHolder.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridItemViewHolder.kt index 8d1c019276fd..619703a02a7d 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridItemViewHolder.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridItemViewHolder.kt @@ -65,11 +65,7 @@ class OCFileListGridItemViewHolder(var binding: GridItemBinding) : override val fileFeaturesLayout: LinearLayout get() = binding.fileFeaturesLayout override val more: ImageButton - get() = if (binding.bidiFilenameContainer.isVisible) { - binding.bidiMore - } else { - binding.more - } + get() = binding.more init { binding.favoriteAction.drawable.mutate() diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListViewHolder.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListViewHolder.kt index b0a0c037cd3a..098ebe7be8ac 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListViewHolder.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListViewHolder.kt @@ -52,11 +52,7 @@ internal class OCFileListViewHolder(var binding: GridItemBinding) : override val unreadComments: ImageView get() = binding.unreadComments override val more: ImageButton - get() = if (binding.bidiFilenameContainer.isVisible) { - binding.bidiMore - } else { - binding.more - } + get() = binding.more override val fileFeaturesLayout: LinearLayout get() = binding.fileFeaturesLayout override val gridLivePhotoIndicator: ImageView diff --git a/app/src/main/res/layout/grid_item.xml b/app/src/main/res/layout/grid_item.xml index d86a528733d2..5b45406ceb70 100644 --- a/app/src/main/res/layout/grid_item.xml +++ b/app/src/main/res/layout/grid_item.xml @@ -140,61 +140,44 @@ app:layout_constraintTop_toTopOf="parent" tools:visibility="visible" /> - + app:layout_constraintEnd_toEndOf="parent"> - - - - - - - - + + - - + android:layout_gravity="center" + android:gravity="center" + android:ellipsize="start" + android:maxLength="4" + android:maxLines="1" + android:text="@string/placeholder_extension" + android:textSize="@dimen/grid_item_text_size" /> + + Date: Tue, 19 Aug 2025 16:10:22 +0200 Subject: [PATCH 25/35] fix: more button alignment Signed-off-by: alperozturk --- .../ui/adapter/OCFileListGridController.kt | 27 +++++++++++-------- app/src/main/res/layout/grid_item.xml | 2 -- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridController.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridController.kt index 91cc4821e549..f19459edbaf3 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridController.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridController.kt @@ -117,18 +117,23 @@ class OCFileListGridController { bidiFilename.text = base extension?.text = ext - val constraintLayout = gridItemViewHolder.binding.ListItemLayout - val set = ConstraintSet() - set.clone(constraintLayout) - set.clear(R.id.more, ConstraintSet.START) - set.connect( - R.id.more, - ConstraintSet.START, - R.id.bidi_extension, - ConstraintSet.END - ) - set.applyTo(constraintLayout) + ConstraintSet().run { + clone(constraintLayout) + clear(R.id.more, ConstraintSet.START) + connect( + R.id.more, + ConstraintSet.START, + R.id.bidi_extension, + ConstraintSet.END + ) + + val marginEnd = + constraintLayout.context.resources.getDimensionPixelSize(R.dimen.standard_quarter_margin) + setMargin(R.id.more, ConstraintSet.END, marginEnd) + + applyTo(constraintLayout) + } } else { fileName.text = filename extension?.visibility = View.GONE diff --git a/app/src/main/res/layout/grid_item.xml b/app/src/main/res/layout/grid_item.xml index 5b45406ceb70..64286abf112e 100644 --- a/app/src/main/res/layout/grid_item.xml +++ b/app/src/main/res/layout/grid_item.xml @@ -171,8 +171,6 @@ android:layout_height="match_parent" android:layout_gravity="center" android:gravity="center" - android:ellipsize="start" - android:maxLength="4" android:maxLines="1" android:text="@string/placeholder_extension" android:textSize="@dimen/grid_item_text_size" /> From 82e8de22cb259bcbf9418cc87f91fb55e248c7bf Mon Sep 17 00:00:00 2001 From: alperozturk Date: Tue, 19 Aug 2025 16:26:23 +0200 Subject: [PATCH 26/35] fix: layout padding Signed-off-by: alperozturk --- .../ui/adapter/OCFileListGridController.kt | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridController.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridController.kt index f19459edbaf3..07d2d36325b0 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridController.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridController.kt @@ -25,13 +25,10 @@ class OCFileListGridController { private const val TAG = "OCFileListGridController" // Reserved space for file extension text in DP - private const val EXTENSION_RESERVED_DP: Int = 36 + private const val EXTENSION_RESERVED_DP: Int = 32 // Padding between text and more icon in DP - private const val SAFETY_MARGIN_DP: Int = 8 - - // extra spacing between text and more button - private const val MORE_BUTTON_MARGIN_DP: Int = 8 + private const val SAFETY_MARGIN_DP: Int = 16 } private var lastScreenWidth = -1 @@ -62,18 +59,15 @@ class OCFileListGridController { val moreButtonPx = context.resources.getDimensionPixelSize(R.dimen.iconized_single_line_item_icon_size) - // 3-4 chars width - val density = context.resources.displayMetrics.density val extensionMinPx = (density * EXTENSION_RESERVED_DP).toInt() val paddingPx = (density * SAFETY_MARGIN_DP).toInt() - val moreButtonMarginPx = (density * MORE_BUTTON_MARGIN_DP).toInt() // name + more button - cachedFolderMaxWidth = cellWidth - moreButtonPx - paddingPx - moreButtonMarginPx + cachedFolderMaxWidth = cellWidth - moreButtonPx - paddingPx // name + extension + more button - cachedFileMaxWidth = cellWidth - moreButtonPx - extensionMinPx - paddingPx - moreButtonMarginPx + cachedFileMaxWidth = cellWidth - moreButtonPx - extensionMinPx - paddingPx // fallback if (cachedFolderMaxWidth < 0) { @@ -128,10 +122,6 @@ class OCFileListGridController { ConstraintSet.END ) - val marginEnd = - constraintLayout.context.resources.getDimensionPixelSize(R.dimen.standard_quarter_margin) - setMargin(R.id.more, ConstraintSet.END, marginEnd) - applyTo(constraintLayout) } } else { From 2aab5de02222e957195d45ebca01fb41b9312aed Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 21 Aug 2025 12:49:55 +0200 Subject: [PATCH 27/35] fix: file features layout alignment Signed-off-by: alperozturk --- app/src/main/res/layout/grid_item.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/layout/grid_item.xml b/app/src/main/res/layout/grid_item.xml index 64286abf112e..90fbd63473d1 100644 --- a/app/src/main/res/layout/grid_item.xml +++ b/app/src/main/res/layout/grid_item.xml @@ -53,6 +53,7 @@ android:orientation="horizontal" android:padding="@dimen/standard_quarter_padding" android:translationZ="4dp" + app:layout_constraintStart_toStartOf="parent" app:layout_constraintBottom_toBottomOf="@+id/thumbnail" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.85" From 2a7f54f69481997c7b4a4e5663e58cdaba1fd25e Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 21 Aug 2025 13:48:51 +0200 Subject: [PATCH 28/35] fix: layout alignment Signed-off-by: alperozturk --- .../ui/activity/FileDisplayActivity.kt | 13 --- .../android/ui/adapter/OCFileListAdapter.java | 4 - .../ui/adapter/OCFileListGridController.kt | 97 +------------------ .../adapter/OCFileListGridItemViewHolder.kt | 7 +- .../ui/adapter/OCFileListViewHolder.kt | 6 +- app/src/main/res/layout/grid_item.xml | 76 +++++++++------ 6 files changed, 60 insertions(+), 143 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt index 163c1a341f9f..a41d1f3d9599 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.kt @@ -354,19 +354,6 @@ class FileDisplayActivity : } } } - - recalculateGridLayoutFilenameMaxWidths() - } - - @SuppressLint("NotifyDataSetChanged") - private fun recalculateGridLayoutFilenameMaxWidths() { - val fragment = fileListFragment ?: return - - val fileListAdapter = fragment.adapter - if (fileListAdapter != null && fileListAdapter.isGridView) { - fileListAdapter.invalidateGridLayoutCachedWidths() - fileListAdapter.notifyDataSetChanged() - } } override fun onPostCreate(savedInstanceState: Bundle?) { diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java index 9f0d356bc7d8..d15bcd2a5324 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java @@ -560,10 +560,6 @@ private void updateLivePhotoIndicators(ListViewHolder holder, OCFile file) { } } - public void invalidateGridLayoutCachedWidths() { - gridController.invalidateGridLayoutCachedWidths(); - } - private void setFileNameAndExtension(ListGridItemViewHolder holder, OCFile file) { final String filename = mStorageManager.getFilenameConsideringOfflineOperation(file); final var pair = FileStorageUtils.getFilenameAndExtension(filename, file.isFolder(), isRTL); diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridController.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridController.kt index 07d2d36325b0..f862e1dad8de 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridController.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridController.kt @@ -8,91 +8,12 @@ package com.owncloud.android.ui.adapter import android.view.View -import androidx.constraintlayout.widget.ConstraintSet import com.nextcloud.utils.extensions.setVisibleIf -import com.owncloud.android.MainApp -import com.owncloud.android.R import com.owncloud.android.datamodel.OCFile -import com.owncloud.android.lib.common.utils.Log_OC -import com.owncloud.android.lib.resources.files.model.ServerFileInterface import com.owncloud.android.ui.interfaces.OCFileListFragmentInterface -import com.owncloud.android.utils.DisplayUtils import com.owncloud.android.utils.FileStorageUtils class OCFileListGridController { - - companion object { - private const val TAG = "OCFileListGridController" - - // Reserved space for file extension text in DP - private const val EXTENSION_RESERVED_DP: Int = 32 - - // Padding between text and more icon in DP - private const val SAFETY_MARGIN_DP: Int = 16 - } - - private var lastScreenWidth = -1 - private var lastColumnCount = -1 - private var cachedFolderMaxWidth = -1 - private var cachedFileMaxWidth = -1 - - private fun configureFilenameMaxWidth( - holder: OCFileListGridItemViewHolder, - file: ServerFileInterface, - columnCount: Int - ) { - val context = MainApp.getAppContext() - if (context == null) { - Log_OC.w(TAG, "Grid layout max file width configuration cancelled, context is null") - return - } - - val screenWidth = DisplayUtils.convertDpToPixel( - context.resources.configuration.screenWidthDp.toFloat(), - context - ) - - // dont recalculate same value - if (columnCount != lastColumnCount || screenWidth != lastScreenWidth) { - // available width per column - val cellWidth = screenWidth / columnCount - - val moreButtonPx = context.resources.getDimensionPixelSize(R.dimen.iconized_single_line_item_icon_size) - - val density = context.resources.displayMetrics.density - val extensionMinPx = (density * EXTENSION_RESERVED_DP).toInt() - val paddingPx = (density * SAFETY_MARGIN_DP).toInt() - - // name + more button - cachedFolderMaxWidth = cellWidth - moreButtonPx - paddingPx - - // name + extension + more button - cachedFileMaxWidth = cellWidth - moreButtonPx - extensionMinPx - paddingPx - - // fallback - if (cachedFolderMaxWidth < 0) { - cachedFolderMaxWidth = context.resources.getDimensionPixelSize( - R.dimen.grid_container_default_max_file_name - ) - } - if (cachedFileMaxWidth < 0) { - cachedFileMaxWidth = context.resources.getDimensionPixelSize( - R.dimen.grid_container_default_max_file_name - ) - } - - lastColumnCount = columnCount - lastScreenWidth = screenWidth - } - - holder.bidiFilename.maxWidth = if (file.isFolder) cachedFolderMaxWidth else cachedFileMaxWidth - } - - fun invalidateGridLayoutCachedWidths() { - lastColumnCount = -1 - lastScreenWidth = -1 - } - fun handleGridMode( filename: String, fragmentInterface: OCFileListFragmentInterface, @@ -107,22 +28,12 @@ class OCFileListGridController { if (containsBidiControlCharacters) { val (base, ext) = filenamePair - configureFilenameMaxWidth(this, file, fragmentInterface.getColumnsCount()) + bidiFilename.text = base extension?.text = ext - - val constraintLayout = gridItemViewHolder.binding.ListItemLayout - ConstraintSet().run { - clone(constraintLayout) - clear(R.id.more, ConstraintSet.START) - connect( - R.id.more, - ConstraintSet.START, - R.id.bidi_extension, - ConstraintSet.END - ) - - applyTo(constraintLayout) + binding.more.visibility = View.GONE + binding.bidiMore.setOnClickListener { + fragmentInterface.onOverflowIconClicked(file, it) } } else { fileName.text = filename diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridItemViewHolder.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridItemViewHolder.kt index 619703a02a7d..dc00b032e3c7 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridItemViewHolder.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridItemViewHolder.kt @@ -65,8 +65,11 @@ class OCFileListGridItemViewHolder(var binding: GridItemBinding) : override val fileFeaturesLayout: LinearLayout get() = binding.fileFeaturesLayout override val more: ImageButton - get() = binding.more - + get() = if (binding.bidiFilenameContainer.isVisible) { + binding.bidiMore + } else { + binding.more + } init { binding.favoriteAction.drawable.mutate() } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListViewHolder.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListViewHolder.kt index 098ebe7be8ac..b0a0c037cd3a 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListViewHolder.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListViewHolder.kt @@ -52,7 +52,11 @@ internal class OCFileListViewHolder(var binding: GridItemBinding) : override val unreadComments: ImageView get() = binding.unreadComments override val more: ImageButton - get() = binding.more + get() = if (binding.bidiFilenameContainer.isVisible) { + binding.bidiMore + } else { + binding.more + } override val fileFeaturesLayout: LinearLayout get() = binding.fileFeaturesLayout override val gridLivePhotoIndicator: ImageView diff --git a/app/src/main/res/layout/grid_item.xml b/app/src/main/res/layout/grid_item.xml index 90fbd63473d1..4c5b079b7677 100644 --- a/app/src/main/res/layout/grid_item.xml +++ b/app/src/main/res/layout/grid_item.xml @@ -8,8 +8,7 @@ ~ SPDX-FileCopyrightText: 2015 ownCloud Inc. ~ SPDX-License-Identifier: GPL-2.0-only AND (AGPL-3.0-or-later OR GPL-2.0-only) --> - @@ -106,7 +105,6 @@ + app:layout_constraintTop_toBottomOf="@+id/thumbnail"> - - - - + android:layout_height="match_parent"> + + + + + + + + + + tools:visibility="gone" /> + tools:ignore="TouchTargetSizeCheck" + tools:visibility="gone" /> \ No newline at end of file From 1dfb02b8f53556b43b7d922a5db622c47d9bdbae Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 21 Aug 2025 13:53:02 +0200 Subject: [PATCH 29/35] add: missing bidi character Signed-off-by: alperozturk --- .../main/java/com/owncloud/android/utils/FileStorageUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/owncloud/android/utils/FileStorageUtils.java b/app/src/main/java/com/owncloud/android/utils/FileStorageUtils.java index d58df9624304..550b0e855e21 100644 --- a/app/src/main/java/com/owncloud/android/utils/FileStorageUtils.java +++ b/app/src/main/java/com/owncloud/android/utils/FileStorageUtils.java @@ -87,7 +87,7 @@ public static boolean containsBidiControlCharacters(String filename) { int[] bidiControlCharacters = { 0x202A, 0x202B, 0x202C, 0x202D, 0x202E, 0x200E, 0x200F, 0x2066, 0x2067, 0x2068, - 0x2069 + 0x2069, 0x061C }; for (int i = 0; i < decoded.length(); i++) { From e31d94af95bbe58a3f99557bf0820a45aa4fc961 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 21 Aug 2025 14:16:26 +0200 Subject: [PATCH 30/35] fix: title max width Signed-off-by: alperozturk --- .../com/nextcloud/ui/fileactions/FileActionsBottomSheet.kt | 5 +++++ app/src/main/res/layout/grid_item.xml | 5 +++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/nextcloud/ui/fileactions/FileActionsBottomSheet.kt b/app/src/main/java/com/nextcloud/ui/fileactions/FileActionsBottomSheet.kt index eea98ebf8439..2c32a436620b 100644 --- a/app/src/main/java/com/nextcloud/ui/fileactions/FileActionsBottomSheet.kt +++ b/app/src/main/java/com/nextcloud/ui/fileactions/FileActionsBottomSheet.kt @@ -209,7 +209,12 @@ class FileActionsBottomSheet : val isFolder = titleFile.isFolder val isRTL = DisplayUtils.isRTL() val (base, ext) = FileStorageUtils.getFilenameAndExtension(decryptedFileName, isFolder, isRTL) + val titleMaxWidth = DisplayUtils.convertDpToPixel( + requireContext().resources.configuration.screenWidthDp.times(0.6).toFloat(), + context + ) + binding.title.maxWidth = titleMaxWidth binding.title.text = base binding.extension.setVisibleIf(!isFolder) if (!isFolder) { diff --git a/app/src/main/res/layout/grid_item.xml b/app/src/main/res/layout/grid_item.xml index 4c5b079b7677..627951acdacc 100644 --- a/app/src/main/res/layout/grid_item.xml +++ b/app/src/main/res/layout/grid_item.xml @@ -144,6 +144,7 @@ android:id="@+id/bidi_filename_container" android:layout_width="match_parent" android:layout_height="wrap_content" + android:visibility="gone" android:gravity="center" android:orientation="horizontal" app:layout_constraintBottom_toBottomOf="parent" @@ -209,7 +210,7 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/thumbnail" app:layout_constraintWidth_percent="0.75" - tools:visibility="gone" /> + tools:visibility="visible" /> + tools:visibility="visible" /> \ No newline at end of file From b8fe4e3c8fc3114ce9a792e19324c44dea3467ab Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 21 Aug 2025 14:19:26 +0200 Subject: [PATCH 31/35] fix: title max width Signed-off-by: alperozturk --- app/src/main/res/layout/grid_item.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/layout/grid_item.xml b/app/src/main/res/layout/grid_item.xml index 627951acdacc..e817776cb7a2 100644 --- a/app/src/main/res/layout/grid_item.xml +++ b/app/src/main/res/layout/grid_item.xml @@ -141,9 +141,10 @@ tools:visibility="visible" /> Date: Thu, 21 Aug 2025 14:21:29 +0200 Subject: [PATCH 32/35] add: max file name Signed-off-by: alperozturk --- app/src/main/res/layout/grid_item.xml | 2 +- app/src/main/res/values/dims.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/layout/grid_item.xml b/app/src/main/res/layout/grid_item.xml index e817776cb7a2..885d42571a57 100644 --- a/app/src/main/res/layout/grid_item.xml +++ b/app/src/main/res/layout/grid_item.xml @@ -163,7 +163,7 @@ 6dp 130dp 120dp - 50dp + 80dp 140dp 180dp From b4451ec0131356c12e421e7c40818fd225d78dc4 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 21 Aug 2025 14:30:23 +0200 Subject: [PATCH 33/35] fix: title layout alignment Signed-off-by: alperozturk --- app/src/main/res/layout/grid_item.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/layout/grid_item.xml b/app/src/main/res/layout/grid_item.xml index 885d42571a57..ae065d33d73a 100644 --- a/app/src/main/res/layout/grid_item.xml +++ b/app/src/main/res/layout/grid_item.xml @@ -156,6 +156,7 @@ From 618330cacbf29da755d9e75aad13b54caad8ee7b Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 21 Aug 2025 14:52:15 +0200 Subject: [PATCH 34/35] fix: codacy analysis title max width Signed-off-by: alperozturk --- .../com/nextcloud/ui/fileactions/FileActionsBottomSheet.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/ui/fileactions/FileActionsBottomSheet.kt b/app/src/main/java/com/nextcloud/ui/fileactions/FileActionsBottomSheet.kt index 2c32a436620b..63ccd3b66f2c 100644 --- a/app/src/main/java/com/nextcloud/ui/fileactions/FileActionsBottomSheet.kt +++ b/app/src/main/java/com/nextcloud/ui/fileactions/FileActionsBottomSheet.kt @@ -210,7 +210,7 @@ class FileActionsBottomSheet : val isRTL = DisplayUtils.isRTL() val (base, ext) = FileStorageUtils.getFilenameAndExtension(decryptedFileName, isFolder, isRTL) val titleMaxWidth = DisplayUtils.convertDpToPixel( - requireContext().resources.configuration.screenWidthDp.times(0.6).toFloat(), + requireContext().resources.configuration.screenWidthDp.times(FILENAME_MAX_WIDTH_PERCENTAGE).toFloat(), context ) @@ -314,6 +314,7 @@ class FileActionsBottomSheet : companion object { private const val REQUEST_KEY = "REQUEST_KEY_ACTION" private const val RESULT_KEY_ACTION_ID = "RESULT_KEY_ACTION_ID" + private const val FILENAME_MAX_WIDTH_PERCENTAGE = 0.6 @JvmStatic @JvmOverloads From 013caa14c96b6c745c3109ef61dddc2f136b7d8c Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 21 Aug 2025 15:05:19 +0200 Subject: [PATCH 35/35] remove: file list grid controller Signed-off-by: alperozturk --- .../android/ui/adapter/OCFileListAdapter.java | 28 ++++++++++-- .../ui/adapter/OCFileListGridController.kt | 44 ------------------- 2 files changed, 24 insertions(+), 48 deletions(-) delete mode 100644 app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridController.kt diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java index d15bcd2a5324..47eb68ae6284 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java @@ -144,7 +144,6 @@ public class OCFileListAdapter extends RecyclerView.Adapter recommendedFiles = new ArrayList<>(); @@ -480,7 +479,7 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi } if (holder instanceof ListGridItemViewHolder gridItemViewHolder) { - setFileNameAndExtension(gridItemViewHolder, file); + setFilenameAndExtension(gridItemViewHolder, file); checkVisibilityOfFileFeaturesLayout(gridItemViewHolder); } @@ -560,18 +559,39 @@ private void updateLivePhotoIndicators(ListViewHolder holder, OCFile file) { } } - private void setFileNameAndExtension(ListGridItemViewHolder holder, OCFile file) { + private void setFilenameAndExtension(ListGridItemViewHolder holder, OCFile file) { final String filename = mStorageManager.getFilenameConsideringOfflineOperation(file); final var pair = FileStorageUtils.getFilenameAndExtension(filename, file.isFolder(), isRTL); final boolean isFolder = file.isFolder(); if (holder instanceof OCFileListGridItemViewHolder gridItemViewHolder) { - gridController.handleGridMode(filename, ocFileListFragmentInterface, gridItemViewHolder, pair, file); + handleGridMode(filename, gridItemViewHolder, pair, file); } else { handleListMode(holder, pair, isFolder); } } + private void handleGridMode(String filename, OCFileListGridItemViewHolder holder, Pair filenamePair, OCFile file) { + boolean containsBidiControlCharacters = FileStorageUtils.containsBidiControlCharacters(filename); + ViewExtensionsKt.setVisibleIf(holder.getFileName(),!containsBidiControlCharacters); + ViewExtensionsKt.setVisibleIf(holder.getBinding().bidiFilenameContainer, containsBidiControlCharacters); + final var extension = holder.getExtension(); + + if (containsBidiControlCharacters) { + holder.getBidiFilename().setText(filenamePair.getFirst()); + if (extension != null) { + extension.setText(filenamePair.getSecond()); + } + holder.getBinding().more.setVisibility(View.GONE); + holder.getBinding().bidiMore.setOnClickListener(v -> ocFileListFragmentInterface.onOverflowIconClicked(file, v)); + } else { + holder.getFileName().setText(filename); + if (extension != null) { + extension.setVisibility(View.GONE); + } + } + } + private void handleListMode(ListGridItemViewHolder holder, Pair filenamePair, boolean isFolder) { diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridController.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridController.kt deleted file mode 100644 index f862e1dad8de..000000000000 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridController.kt +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Nextcloud - Android Client - * - * SPDX-FileCopyrightText: 2025 Alper Ozturk - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -package com.owncloud.android.ui.adapter - -import android.view.View -import com.nextcloud.utils.extensions.setVisibleIf -import com.owncloud.android.datamodel.OCFile -import com.owncloud.android.ui.interfaces.OCFileListFragmentInterface -import com.owncloud.android.utils.FileStorageUtils - -class OCFileListGridController { - fun handleGridMode( - filename: String, - fragmentInterface: OCFileListFragmentInterface, - gridItemViewHolder: OCFileListGridItemViewHolder, - filenamePair: Pair, - file: OCFile - ) { - val containsBidiControlCharacters = FileStorageUtils.containsBidiControlCharacters(filename) - gridItemViewHolder.run { - fileName.setVisibleIf(!containsBidiControlCharacters) - binding.bidiFilenameContainer.setVisibleIf(containsBidiControlCharacters) - - if (containsBidiControlCharacters) { - val (base, ext) = filenamePair - - bidiFilename.text = base - extension?.text = ext - binding.more.visibility = View.GONE - binding.bidiMore.setOnClickListener { - fragmentInterface.onOverflowIconClicked(file, it) - } - } else { - fileName.text = filename - extension?.visibility = View.GONE - } - } - } -}