From b902cb3d3212c9ec829343947aa02385190370f4 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Thu, 6 Aug 2026 15:45:23 +0200 Subject: [PATCH 01/20] unify PREFIX_THUMBNAIL key usages Signed-off-by: alperozturk96 # Conflicts: # app/src/main/java/com/owncloud/android/ui/adapter/LocalFileListAdapter.java --- .../nextcloud/ui/fileInfo/ImageDetailInfo.kt | 5 +--- .../java/com/nextcloud/utils/ShortcutUtil.kt | 6 +--- .../utils/extensions/FileExtensions.kt | 10 +++++++ .../owncloud/android/datamodel/OCFile.java | 12 ++++++++ .../datamodel/ThumbnailsCacheManager.java | 4 +-- .../DiskLruImageCacheFileProvider.java | 3 +- .../providers/DocumentsStorageProvider.java | 3 +- .../android/ui/activity/EditorWebView.java | 3 +- .../ui/fragment/FileDetailFragment.java | 4 +-- .../ui/preview/PreviewImageFragment.kt | 5 +--- .../owncloud/android/utils/DisplayUtils.java | 29 +++++++++---------- 11 files changed, 45 insertions(+), 39 deletions(-) diff --git a/app/src/main/java/com/nextcloud/ui/fileInfo/ImageDetailInfo.kt b/app/src/main/java/com/nextcloud/ui/fileInfo/ImageDetailInfo.kt index 00baceba14d9..245d5ecf13e7 100644 --- a/app/src/main/java/com/nextcloud/ui/fileInfo/ImageDetailInfo.kt +++ b/app/src/main/java/com/nextcloud/ui/fileInfo/ImageDetailInfo.kt @@ -23,7 +23,6 @@ import com.owncloud.android.MainApp import com.owncloud.android.R import com.owncloud.android.databinding.FileInfoFragmentBinding import com.owncloud.android.datamodel.OCFile -import com.owncloud.android.datamodel.ThumbnailsCacheManager import com.owncloud.android.utils.BitmapUtils import com.owncloud.android.utils.DisplayUtils import com.owncloud.android.utils.theme.ViewThemeUtils @@ -259,9 +258,7 @@ class ImageDetailInfo(private val fragment: FileInfoFragment, private val viewTh private fun imagePinDrawable(context: Context, file: OCFile): LayerDrawable = (ContextCompat.getDrawable(context, R.drawable.photo_pin) as LayerDrawable).apply { - val bitmap = ThumbnailsCacheManager.getBitmapFromDiskCache( - ThumbnailsCacheManager.PREFIX_THUMBNAIL + file.remoteId - ) + val bitmap = file.smallThumbnail BitmapUtils.bitmapToCircularBitmapDrawable(fragment.resources, bitmap)?.let { setDrawable(1, it) } diff --git a/app/src/main/java/com/nextcloud/utils/ShortcutUtil.kt b/app/src/main/java/com/nextcloud/utils/ShortcutUtil.kt index f614e50aa4ba..8783ef79c525 100644 --- a/app/src/main/java/com/nextcloud/utils/ShortcutUtil.kt +++ b/app/src/main/java/com/nextcloud/utils/ShortcutUtil.kt @@ -26,7 +26,6 @@ import com.owncloud.android.R import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.SyncedFolderObserver import com.owncloud.android.datamodel.SyncedFolderProvider -import com.owncloud.android.datamodel.ThumbnailsCacheManager import com.owncloud.android.ui.activity.FileActivity import com.owncloud.android.ui.activity.FileDisplayActivity import com.owncloud.android.utils.MimeTypeUtil @@ -84,10 +83,7 @@ class ShortcutUtil @Inject constructor(private val mContext: Context) { user: User, syncedFolderProvider: SyncedFolderProvider ): IconCompat { - val thumbnail = ThumbnailsCacheManager.getBitmapFromDiskCache( - ThumbnailsCacheManager.PREFIX_THUMBNAIL + file.remoteId - ) - + val thumbnail = file.smallThumbnail return when { thumbnail != null -> IconCompat.createWithAdaptiveBitmap(bitmapToAdaptiveBitmap(thumbnail)) diff --git a/app/src/main/java/com/nextcloud/utils/extensions/FileExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/FileExtensions.kt index b7fedf75857c..4f4f4f694cac 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/FileExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/FileExtensions.kt @@ -7,8 +7,10 @@ package com.nextcloud.utils.extensions +import android.graphics.Bitmap import androidx.exifinterface.media.ExifInterface import com.owncloud.android.datamodel.OCFile +import com.owncloud.android.datamodel.ThumbnailsCacheManager import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.utils.DisplayUtils import java.io.File @@ -22,6 +24,14 @@ fun OCFile?.logFileSize(tag: String) { Log_OC.d(tag, "onSaveInstanceState: $size, raw byte $rawByte") } +fun File?.getSmallThumbnail(): Bitmap? { + return ThumbnailsCacheManager.getBitmapFromDiskCache(getSmallThumbnailKey()) +} + +fun File?.getSmallThumbnailKey(): String { + return ThumbnailsCacheManager.PREFIX_THUMBNAIL + hashCode() +} + fun File?.logFileSize(tag: String) { val size = DisplayUtils.bytesToHumanReadable(this?.length() ?: -1) val rawByte = this?.length() ?: -1 diff --git a/app/src/main/java/com/owncloud/android/datamodel/OCFile.java b/app/src/main/java/com/owncloud/android/datamodel/OCFile.java index 0e0fe3af993f..c49a9c86cce5 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/OCFile.java +++ b/app/src/main/java/com/owncloud/android/datamodel/OCFile.java @@ -15,6 +15,7 @@ import android.content.ContentResolver; import android.content.Context; +import android.graphics.Bitmap; import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; @@ -815,6 +816,17 @@ public String getRemoteId() { return this.remoteId; } + /** + * Capped to the 512KB. + */ + public String getSmallThumbnailKey() { + return ThumbnailsCacheManager.PREFIX_THUMBNAIL + getRemoteId(); + } + + public Bitmap getSmallThumbnail() { + return ThumbnailsCacheManager.getBitmapFromDiskCache(getSmallThumbnailKey()); + } + public boolean isUpdateThumbnailNeeded() { return this.updateThumbnailNeeded; } diff --git a/app/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java b/app/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java index 66b215e733dc..d626bb82b5ea 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java +++ b/app/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java @@ -217,7 +217,7 @@ public static void removeFromCache(@Nullable OCFile file) { return; } - final var keys = new String[] { PREFIX_RESIZED_IMAGE + file.getRemoteId(), PREFIX_THUMBNAIL + file.getRemoteId() }; + final var keys = new String[] { PREFIX_RESIZED_IMAGE + file.getRemoteId(), file.getSmallThumbnailKey() }; synchronized (mThumbnailsDiskCacheLock) { if (mThumbnailCache == null) { @@ -1208,7 +1208,7 @@ public static void generateThumbnailFromOCFile(OCFile file, User user, Context c int pxW; int pxH; pxW = pxH = getThumbnailDimension(); - String imageKey = PREFIX_THUMBNAIL + file.getRemoteId(); + String imageKey = file.getSmallThumbnailKey(); GetMethod getMethod = null; diff --git a/app/src/main/java/com/owncloud/android/providers/DiskLruImageCacheFileProvider.java b/app/src/main/java/com/owncloud/android/providers/DiskLruImageCacheFileProvider.java index 2ec6a718abbc..5ba403c928a1 100644 --- a/app/src/main/java/com/owncloud/android/providers/DiskLruImageCacheFileProvider.java +++ b/app/src/main/java/com/owncloud/android/providers/DiskLruImageCacheFileProvider.java @@ -67,8 +67,7 @@ public static ParcelFileDescriptor getParcelFileDescriptorForOCFile(OCFile ocFil // fallback to thumbnail if (thumbnail == null) { - thumbnail = ThumbnailsCacheManager.getBitmapFromDiskCache( - ThumbnailsCacheManager.PREFIX_THUMBNAIL + ocFile.getRemoteId()); + thumbnail = ocFile.getSmallThumbnail(); } // fallback to default image diff --git a/app/src/main/java/com/owncloud/android/providers/DocumentsStorageProvider.java b/app/src/main/java/com/owncloud/android/providers/DocumentsStorageProvider.java index 2097e025e23a..e761f0c8087d 100644 --- a/app/src/main/java/com/owncloud/android/providers/DocumentsStorageProvider.java +++ b/app/src/main/java/com/owncloud/android/providers/DocumentsStorageProvider.java @@ -382,8 +382,7 @@ public AssetFileDescriptor openDocumentThumbnail(String documentId, Document document = toDocument(documentId); OCFile file = document.getFile(); - boolean exists = ThumbnailsCacheManager.containsBitmap(ThumbnailsCacheManager.PREFIX_THUMBNAIL - + file.getRemoteId()); + boolean exists = ThumbnailsCacheManager.containsBitmap(file.getSmallThumbnailKey()); if (!exists) { ThumbnailsCacheManager.generateThumbnailFromOCFile(file, document.getUser(), getContext()); } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/EditorWebView.java b/app/src/main/java/com/owncloud/android/ui/activity/EditorWebView.java index 4721bbbe434f..0bde1568f334 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/EditorWebView.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/EditorWebView.java @@ -258,8 +258,7 @@ protected void setThumbnailView(final User user) { } else { if ((MimeTypeUtil.isImage(file) || MimeTypeUtil.isVideo(file)) && file.getRemoteId() != null) { // Thumbnail in cache? - Bitmap thumbnail = ThumbnailsCacheManager.getBitmapFromDiskCache( - ThumbnailsCacheManager.PREFIX_THUMBNAIL + file.getRemoteId()); + Bitmap thumbnail = file.getSmallThumbnail(); if (thumbnail != null && !file.isUpdateThumbnailNeeded()) { if (MimeTypeUtil.isVideo(file)) { diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java index 4774dfc5f996..748b0d1c6a1d 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java @@ -674,9 +674,7 @@ private void setFilePreview(OCFile file) { previewLoaded = true; } else { // show thumbnail while loading resized image - Bitmap thumbnail = ThumbnailsCacheManager.getBitmapFromDiskCache( - ThumbnailsCacheManager.PREFIX_THUMBNAIL + getFile().getRemoteId()); - + Bitmap thumbnail = getFile().getSmallThumbnail(); if (thumbnail != null) { toolbarActivity.setPreviewImageBitmap(thumbnail); } else { diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageFragment.kt b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageFragment.kt index 9326613dd511..906684250c70 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageFragment.kt @@ -241,7 +241,7 @@ class PreviewImageFragment : binding.image.visibility = View.GONE binding.emptyListProgress.visibility = View.VISIBLE - var thumbnail = getThumbnailBitmap(file) + var thumbnail = file.smallThumbnail if (thumbnail != null) { binding.shimmer.visibility = View.VISIBLE binding.shimmerThumbnail.setImageBitmap(thumbnail) @@ -327,9 +327,6 @@ class PreviewImageFragment : return cachedImage } - private fun getThumbnailBitmap(file: OCFile): Bitmap? = - ThumbnailsCacheManager.getBitmapFromDiskCache(ThumbnailsCacheManager.PREFIX_THUMBNAIL + file.remoteId) - override fun onStop() { Log_OC.d(TAG, "onStop starts") loadBitmapTask?.cancel(true) 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 ff8fd1e9d408..d2565b9de06c 100644 --- a/app/src/main/java/com/owncloud/android/utils/DisplayUtils.java +++ b/app/src/main/java/com/owncloud/android/utils/DisplayUtils.java @@ -803,7 +803,7 @@ public static void setThumbnail(OCFile file, private static void setThumbnailFirstTimeForFile(OCFile file, ImageView thumbnailView, FileDataStorageManager storageManager, List asyncTasks, boolean gridView, LoaderImageView shimmerThumbnail, User user, AppPreferences preferences, Context context, ViewThemeUtils viewThemeUtils) { if (file.getRemoteId() != null) { - generateNewThumbnail(file, thumbnailView, user, storageManager, new ArrayList<>(asyncTasks), gridView, context, shimmerThumbnail, preferences, viewThemeUtils); + generateNewThumbnailIfNecessary(file, thumbnailView, user, storageManager, new ArrayList<>(asyncTasks), gridView, context, shimmerThumbnail, preferences, viewThemeUtils); return; } @@ -835,9 +835,9 @@ private static void setThumbnailForOfflineOperation(OCFile file, ImageView thumb } public static void setThumbnailFromCache(OCFile file, ImageView thumbnailView, FileDataStorageManager storageManager, List asyncTasks, boolean gridView, LoaderImageView shimmerThumbnail, User user, AppPreferences preferences, Context context, ViewThemeUtils viewThemeUtils) { - final var thumbnail = ThumbnailsCacheManager.getBitmapFromDiskCache(ThumbnailsCacheManager.PREFIX_THUMBNAIL + file.getRemoteId()); + final var thumbnail = file.getSmallThumbnail(); if (thumbnail == null || file.isUpdateThumbnailNeeded()) { - generateNewThumbnail(file, thumbnailView, user, storageManager, new ArrayList<>(asyncTasks), gridView, context, shimmerThumbnail, preferences, viewThemeUtils); + generateNewThumbnailIfNecessary(file, thumbnailView, user, storageManager, new ArrayList<>(asyncTasks), gridView, context, shimmerThumbnail, preferences, viewThemeUtils); setThumbnailBackgroundForPNGFileIfNeeded(file, context, thumbnailView); return; } @@ -861,22 +861,21 @@ private static void setThumbnailBackgroundForPNGFileIfNeeded(ServerFileInterface } } - private static void generateNewThumbnail(OCFile file, - ImageView thumbnailView, - User user, - FileDataStorageManager storageManager, - ArrayList asyncTasks, - boolean gridView, - Context context, - LoaderImageView shimmerThumbnail, - AppPreferences preferences, - ViewThemeUtils viewThemeUtils) { + private static void generateNewThumbnailIfNecessary(OCFile file, + ImageView thumbnailView, + User user, + FileDataStorageManager storageManager, + ArrayList asyncTasks, + boolean gridView, + Context context, + LoaderImageView shimmerThumbnail, + AppPreferences preferences, + ViewThemeUtils viewThemeUtils) { if (!ThumbnailsCacheManager.cancelPotentialThumbnailWork(file, thumbnailView)) { return; } - Bitmap thumbnail = ThumbnailsCacheManager.getBitmapFromDiskCache( - ThumbnailsCacheManager.PREFIX_THUMBNAIL + file.getRemoteId()); + Bitmap thumbnail = file.getSmallThumbnail(); if (thumbnail != null) { // If thumbnail is already in cache, display it immediately From 6da797a1ae7a6e25b6fb7217c78ec24830b30779 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Thu, 6 Aug 2026 15:49:01 +0200 Subject: [PATCH 02/20] unify PREFIX_THUMBNAIL key usages Signed-off-by: alperozturk96 --- .../com/nextcloud/utils/extensions/FileExtensions.kt | 12 ++++++++++++ .../java/com/owncloud/android/datamodel/OCFile.java | 8 +++----- .../android/datamodel/ThumbnailsCacheManager.java | 3 ++- .../android/ui/adapter/TrashbinListAdapter.java | 6 ++---- 4 files changed, 19 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/nextcloud/utils/extensions/FileExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/FileExtensions.kt index 4f4f4f694cac..1457a6b42320 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/FileExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/FileExtensions.kt @@ -12,6 +12,7 @@ import androidx.exifinterface.media.ExifInterface import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.ThumbnailsCacheManager import com.owncloud.android.lib.common.utils.Log_OC +import com.owncloud.android.lib.resources.files.model.ServerFileInterface import com.owncloud.android.utils.DisplayUtils import java.io.File import java.nio.file.Path @@ -24,6 +25,17 @@ fun OCFile?.logFileSize(tag: String) { Log_OC.d(tag, "onSaveInstanceState: $size, raw byte $rawByte") } +fun ServerFileInterface.getSmallThumbnail(): Bitmap? { + return ThumbnailsCacheManager.getBitmapFromDiskCache(getSmallThumbnailKey()) +} + +/** + * Capped to the 512KB. + */ +fun ServerFileInterface.getSmallThumbnailKey(): String { + return ThumbnailsCacheManager.PREFIX_THUMBNAIL + remoteId +} + fun File?.getSmallThumbnail(): Bitmap? { return ThumbnailsCacheManager.getBitmapFromDiskCache(getSmallThumbnailKey()) } diff --git a/app/src/main/java/com/owncloud/android/datamodel/OCFile.java b/app/src/main/java/com/owncloud/android/datamodel/OCFile.java index c49a9c86cce5..6d3c1eb73ef7 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/OCFile.java +++ b/app/src/main/java/com/owncloud/android/datamodel/OCFile.java @@ -22,6 +22,7 @@ import android.text.TextUtils; import com.nextcloud.utils.BuildHelper; +import com.nextcloud.utils.extensions.FileExtensionsKt; import com.nextcloud.utils.extensions.StringExtensionsKt; import com.owncloud.android.R; import com.owncloud.android.lib.common.network.WebdavEntry; @@ -816,15 +817,12 @@ public String getRemoteId() { return this.remoteId; } - /** - * Capped to the 512KB. - */ public String getSmallThumbnailKey() { - return ThumbnailsCacheManager.PREFIX_THUMBNAIL + getRemoteId(); + return FileExtensionsKt.getSmallThumbnailKey(this); } public Bitmap getSmallThumbnail() { - return ThumbnailsCacheManager.getBitmapFromDiskCache(getSmallThumbnailKey()); + return FileExtensionsKt.getSmallThumbnail(this); } public boolean isUpdateThumbnailNeeded() { diff --git a/app/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java b/app/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java index d626bb82b5ea..5ee35b0e56f4 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java +++ b/app/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java @@ -38,6 +38,7 @@ import com.nextcloud.client.account.User; import com.nextcloud.client.network.ConnectivityService; import com.nextcloud.utils.BitmapExtensionsKt; +import com.nextcloud.utils.extensions.FileExtensionsKt; import com.nextcloud.utils.extensions.OCFileExtensionsKt; import com.nextcloud.utils.extensions.OwnCloudClientExtensionsKt; import com.owncloud.android.MainApp; @@ -575,7 +576,7 @@ public void setListener(Listener listener){ private Bitmap doThumbnailFromOCFileInBackground() { Bitmap thumbnail; ServerFileInterface file = (ServerFileInterface) mFile; - String imageKey = PREFIX_THUMBNAIL + file.getRemoteId(); + String imageKey = FileExtensionsKt.getSmallThumbnailKey(file); boolean updateEnforced = (file instanceof OCFile && ((OCFile) file).isUpdateThumbnailNeeded()); diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/TrashbinListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/TrashbinListAdapter.java index 3f3e15870adb..3f281d0704d9 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/TrashbinListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/TrashbinListAdapter.java @@ -20,6 +20,7 @@ import com.nextcloud.android.common.ui.theme.utils.ColorRole; import com.nextcloud.client.account.User; import com.nextcloud.client.preferences.AppPreferences; +import com.nextcloud.utils.extensions.FileExtensionsKt; import com.nextcloud.utils.extensions.ViewExtensionsKt; import com.owncloud.android.R; import com.owncloud.android.databinding.ListFooterBinding; @@ -256,10 +257,7 @@ private void setThumbnail(TrashbinFile file, ImageView thumbnailView) { } else { if ((MimeTypeUtil.isImage(file) || MimeTypeUtil.isVideo(file)) && file.getRemoteId() != null) { // Thumbnail in cache? - Bitmap thumbnail = ThumbnailsCacheManager.getBitmapFromDiskCache( - ThumbnailsCacheManager.PREFIX_THUMBNAIL + file.getRemoteId() - ); - + Bitmap thumbnail = FileExtensionsKt.getSmallThumbnail(file); if (thumbnail != null) { if (MimeTypeUtil.isVideo(file)) { Bitmap withOverlay = ThumbnailsCacheManager.addVideoOverlay(thumbnail, context); From 02050d4c52af313aa0c0c8e1e0110f301926b300 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Thu, 6 Aug 2026 15:53:42 +0200 Subject: [PATCH 03/20] unify PREFIX_THUMBNAIL key usages Signed-off-by: alperozturk96 --- .../utils/extensions/FileExtensions.kt | 17 +++++------------ .../datamodel/ThumbnailsCacheManager.java | 2 +- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/com/nextcloud/utils/extensions/FileExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/FileExtensions.kt index 1457a6b42320..1a3eeb22297b 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/FileExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/FileExtensions.kt @@ -25,24 +25,17 @@ fun OCFile?.logFileSize(tag: String) { Log_OC.d(tag, "onSaveInstanceState: $size, raw byte $rawByte") } -fun ServerFileInterface.getSmallThumbnail(): Bitmap? { - return ThumbnailsCacheManager.getBitmapFromDiskCache(getSmallThumbnailKey()) -} +fun ServerFileInterface.getSmallThumbnail(): Bitmap? = + ThumbnailsCacheManager.getBitmapFromDiskCache(getSmallThumbnailKey()) /** * Capped to the 512KB. */ -fun ServerFileInterface.getSmallThumbnailKey(): String { - return ThumbnailsCacheManager.PREFIX_THUMBNAIL + remoteId -} +fun ServerFileInterface.getSmallThumbnailKey(): String = ThumbnailsCacheManager.PREFIX_THUMBNAIL + remoteId -fun File?.getSmallThumbnail(): Bitmap? { - return ThumbnailsCacheManager.getBitmapFromDiskCache(getSmallThumbnailKey()) -} +fun File?.getSmallThumbnail(): Bitmap? = ThumbnailsCacheManager.getBitmapFromDiskCache(getSmallThumbnailKey()) -fun File?.getSmallThumbnailKey(): String { - return ThumbnailsCacheManager.PREFIX_THUMBNAIL + hashCode() -} +fun File?.getSmallThumbnailKey(): String = ThumbnailsCacheManager.PREFIX_THUMBNAIL + hashCode() fun File?.logFileSize(tag: String) { val size = DisplayUtils.bytesToHumanReadable(this?.length() ?: -1) diff --git a/app/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java b/app/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java index 5ee35b0e56f4..7f1f6c7f1746 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java +++ b/app/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java @@ -719,7 +719,7 @@ private Bitmap doFileInBackground() { final String imageKey = Objects.requireNonNullElseGet(mImageKey, () -> String.valueOf(file.hashCode())); // local file should always generate a thumbnail - mImageKey = PREFIX_THUMBNAIL + mImageKey; + mImageKey = FileExtensionsKt.getSmallThumbnailKey(file); // Check disk cache in background thread Bitmap thumbnail = getBitmapFromDiskCache(imageKey); From 7d9d776f31091436d3ac58c811f123049ba8c18c Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Thu, 6 Aug 2026 16:02:57 +0200 Subject: [PATCH 04/20] unify PREFIX_RESIZED_IMAGE key usages Signed-off-by: alperozturk96 --- .../owncloud/android/ui/fragment/GalleryFragmentIT.kt | 5 ++--- .../client/jobs/gallery/GalleryImageGenerationJob.kt | 10 +++++----- .../com/nextcloud/utils/extensions/FileExtensions.kt | 4 ++++ .../java/com/owncloud/android/datamodel/OCFile.java | 8 ++++++++ .../android/datamodel/ThumbnailsCacheManager.java | 8 ++++---- .../providers/DiskLruImageCacheFileProvider.java | 4 ++-- .../owncloud/android/ui/adapter/OCFileListDelegate.kt | 4 ++-- .../android/ui/fragment/FileDetailFragment.java | 3 +-- .../android/ui/preview/PreviewImageFragment.kt | 2 +- 9 files changed, 29 insertions(+), 19 deletions(-) diff --git a/app/src/androidTest/java/com/owncloud/android/ui/fragment/GalleryFragmentIT.kt b/app/src/androidTest/java/com/owncloud/android/ui/fragment/GalleryFragmentIT.kt index 07a6443365b3..a248b1c32d92 100644 --- a/app/src/androidTest/java/com/owncloud/android/ui/fragment/GalleryFragmentIT.kt +++ b/app/src/androidTest/java/com/owncloud/android/ui/fragment/GalleryFragmentIT.kt @@ -33,7 +33,6 @@ import com.owncloud.android.AbstractIT import com.owncloud.android.R import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.ThumbnailsCacheManager -import com.owncloud.android.datamodel.ThumbnailsCacheManager.PREFIX_RESIZED_IMAGE import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.lib.resources.files.model.ImageDimension import com.owncloud.android.ui.adapter.GalleryRowHolder @@ -221,9 +220,9 @@ class GalleryFragmentIT : AbstractIT() { drawRGB(random.nextInt(256), random.nextInt(256), random.nextInt(256)) drawCircle(w / 2f, h / 2f, w.coerceAtMost(h) / 2f, Paint().apply { color = Color.BLACK }) } - ThumbnailsCacheManager.addBitmapToCache(PREFIX_RESIZED_IMAGE + file.remoteId, bitmap) + ThumbnailsCacheManager.addBitmapToCache(file.bigThumbnailKey, bitmap) - assertNotNull(ThumbnailsCacheManager.getBitmapFromDiskCache(PREFIX_RESIZED_IMAGE + file.remoteId)) + assertNotNull(file.bigThumbnail) Log_OC.d("Gallery_thumbnail", "created $id with ${bitmap.width} x ${bitmap.height}") } diff --git a/app/src/main/java/com/nextcloud/client/jobs/gallery/GalleryImageGenerationJob.kt b/app/src/main/java/com/nextcloud/client/jobs/gallery/GalleryImageGenerationJob.kt index 5ca2202ea0aa..9eb0b5e2a163 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/gallery/GalleryImageGenerationJob.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/gallery/GalleryImageGenerationJob.kt @@ -17,6 +17,8 @@ import android.view.WindowManager import android.widget.ImageView import androidx.core.content.ContextCompat import com.nextcloud.client.account.User +import com.nextcloud.utils.extensions.getBigThumbnail +import com.nextcloud.utils.extensions.getBigThumbnailKey import com.nextcloud.utils.extensions.isPNG import com.nextcloud.utils.extensions.toFile import com.owncloud.android.MainApp @@ -110,9 +112,7 @@ class GalleryImageGenerationJob(private val user: User, private val storageManag } private suspend fun getBitmap(file: OCFile, onNewThumbnail: () -> Unit): Bitmap? = withContext(Dispatchers.IO) { - val cacheKey = ThumbnailsCacheManager.PREFIX_RESIZED_IMAGE + file.remoteId - - val cached = ThumbnailsCacheManager.getBitmapFromDiskCache(cacheKey) + val cached = file.getBigThumbnail() if (cached != null && !file.isUpdateThumbnailNeeded) { return@withContext applyVideoOverlayIfNeeded(file, cached) } @@ -122,7 +122,7 @@ class GalleryImageGenerationJob(private val user: User, private val storageManag if (file.isDown) { val local = decodeLocalThumbnail(file) if (local != null) { - ThumbnailsCacheManager.addBitmapToCache(cacheKey, local) + ThumbnailsCacheManager.addBitmapToCache(file.getBigThumbnailKey(), local) return@withContext applyVideoOverlayIfNeeded(file, local) } } @@ -149,7 +149,7 @@ class GalleryImageGenerationJob(private val user: User, private val storageManag val pxW = p.x val pxH = p.y - val cacheKey = ThumbnailsCacheManager.PREFIX_RESIZED_IMAGE + file.remoteId + val cacheKey = file.bigThumbnailKey var bitmap = BitmapUtils.decodeSampledBitmapFromFile(file.storagePath, pxW, pxH) ?: return null diff --git a/app/src/main/java/com/nextcloud/utils/extensions/FileExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/FileExtensions.kt index 1a3eeb22297b..a3046c68d5aa 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/FileExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/FileExtensions.kt @@ -25,6 +25,10 @@ fun OCFile?.logFileSize(tag: String) { Log_OC.d(tag, "onSaveInstanceState: $size, raw byte $rawByte") } +fun ServerFileInterface.getBigThumbnail(): Bitmap? = ThumbnailsCacheManager.getBitmapFromDiskCache(getBigThumbnailKey()) + +fun ServerFileInterface.getBigThumbnailKey(): String = ThumbnailsCacheManager.PREFIX_RESIZED_IMAGE + remoteId + fun ServerFileInterface.getSmallThumbnail(): Bitmap? = ThumbnailsCacheManager.getBitmapFromDiskCache(getSmallThumbnailKey()) diff --git a/app/src/main/java/com/owncloud/android/datamodel/OCFile.java b/app/src/main/java/com/owncloud/android/datamodel/OCFile.java index 6d3c1eb73ef7..96f736ae9571 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/OCFile.java +++ b/app/src/main/java/com/owncloud/android/datamodel/OCFile.java @@ -817,6 +817,14 @@ public String getRemoteId() { return this.remoteId; } + public String getBigThumbnailKey() { + return FileExtensionsKt.getBigThumbnailKey(this); + } + + public Bitmap getBigThumbnail() { + return FileExtensionsKt.getBigThumbnail(this); + } + public String getSmallThumbnailKey() { return FileExtensionsKt.getSmallThumbnailKey(this); } diff --git a/app/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java b/app/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java index 7f1f6c7f1746..3ef1340af2bc 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java +++ b/app/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java @@ -218,7 +218,7 @@ public static void removeFromCache(@Nullable OCFile file) { return; } - final var keys = new String[] { PREFIX_RESIZED_IMAGE + file.getRemoteId(), file.getSmallThumbnailKey() }; + final var keys = new String[] { file.getBigThumbnailKey(), file.getSmallThumbnailKey() }; synchronized (mThumbnailsDiskCacheLock) { if (mThumbnailCache == null) { @@ -623,7 +623,7 @@ private Bitmap doThumbnailFromOCFileInBackground() { // Check resized version in disk cache if still null if (thumbnail == null) { - String resizedImageKey = PREFIX_RESIZED_IMAGE + file.getRemoteId(); + String resizedImageKey = FileExtensionsKt.getBigThumbnailKey(file); Bitmap resizedImage = null; if (!updateEnforced) { @@ -1191,7 +1191,7 @@ public static void generateResizedImage(OCFile file) { Point p = getScreenDimension(); int pxW = p.x; int pxH = p.y; - String imageKey = PREFIX_RESIZED_IMAGE + file.getRemoteId(); + String imageKey = file.getBigThumbnailKey(); Bitmap bitmap = BitmapUtils.decodeSampledBitmapFromFile(file.getStoragePath(), pxW, pxH); @@ -1276,7 +1276,7 @@ public static void setClient(OwnCloudClient client) { public static Bitmap doResizedImageInBackground(OCFile file, FileDataStorageManager storageManager) { Bitmap thumbnail; - String imageKey = PREFIX_RESIZED_IMAGE + file.getRemoteId(); + String imageKey = file.getBigThumbnailKey(); // Check disk cache in background thread thumbnail = getBitmapFromDiskCache(imageKey); diff --git a/app/src/main/java/com/owncloud/android/providers/DiskLruImageCacheFileProvider.java b/app/src/main/java/com/owncloud/android/providers/DiskLruImageCacheFileProvider.java index 5ba403c928a1..01fb5ff8d504 100644 --- a/app/src/main/java/com/owncloud/android/providers/DiskLruImageCacheFileProvider.java +++ b/app/src/main/java/com/owncloud/android/providers/DiskLruImageCacheFileProvider.java @@ -19,6 +19,7 @@ import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; +import com.nextcloud.utils.extensions.FileExtensionsKt; import com.owncloud.android.MainApp; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; @@ -62,8 +63,7 @@ public ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode) thr } public static ParcelFileDescriptor getParcelFileDescriptorForOCFile(OCFile ocFile) throws FileNotFoundException { - Bitmap thumbnail = ThumbnailsCacheManager.getBitmapFromDiskCache( - ThumbnailsCacheManager.PREFIX_RESIZED_IMAGE + ocFile.getRemoteId()); + Bitmap thumbnail = FileExtensionsKt.getBigThumbnail(ocFile); // fallback to thumbnail if (thumbnail == null) { diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt index d871787a4d96..2405f5daabc6 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt @@ -20,6 +20,7 @@ import com.nextcloud.client.jobs.gallery.GalleryImageGenerationListener import com.nextcloud.client.jobs.upload.FileUploadHelper import com.nextcloud.client.preferences.AppPreferences import com.nextcloud.utils.OCFileUtils +import com.nextcloud.utils.extensions.getBigThumbnail import com.nextcloud.utils.extensions.makeRounded import com.nextcloud.utils.extensions.setVisibleIf import com.nextcloud.utils.mdm.MDMConfig @@ -113,8 +114,7 @@ class OCFileListDelegate( imageView.tag = file.fileId // set placeholder before async job - val cacheKey = ThumbnailsCacheManager.PREFIX_RESIZED_IMAGE + file.remoteId - val cachedBitmap = ThumbnailsCacheManager.getBitmapFromDiskCache(cacheKey) + val cachedBitmap = file.getBigThumbnail() if (cachedBitmap != null) { val overlay = if (MimeTypeUtil.isVideo(file)) { ThumbnailsCacheManager.addVideoOverlay(cachedBitmap, context) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java index 748b0d1c6a1d..015f888fbd93 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java @@ -666,8 +666,7 @@ private void setFilePreview(OCFile file) { Bitmap resizedImage; if (toolbarActivity != null && MimeTypeUtil.isImage(file)) { - String tagId = ThumbnailsCacheManager.PREFIX_RESIZED_IMAGE + getFile().getRemoteId(); - resizedImage = ThumbnailsCacheManager.getBitmapFromDiskCache(tagId); + resizedImage = file.getBigThumbnail(); if (resizedImage != null && !file.isUpdateThumbnailNeeded()) { toolbarActivity.setPreviewImageBitmap(resizedImage); diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageFragment.kt b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageFragment.kt index 906684250c70..96bbb52b7889 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageFragment.kt @@ -313,7 +313,7 @@ class PreviewImageFragment : while (i < 3 && cachedImage == null) { try { cachedImage = ThumbnailsCacheManager.getScaledBitmapFromDiskCache( - ThumbnailsCacheManager.PREFIX_RESIZED_IMAGE + file.remoteId, + file.getBigThumbnailKey(), scaledWidth, scaledHeight ) From 3c5b51c276169f1b04d9ac1b90d5bc6a0a11d690 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Thu, 6 Aug 2026 16:11:01 +0200 Subject: [PATCH 05/20] wip Signed-off-by: alperozturk96 --- .../android/ui/activity/UploadListActivity.kt | 1 + .../adapter/uploadList/UploadListAdapter.kt | 32 ++++++++++--------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/UploadListActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/UploadListActivity.kt index b6ef36356a6b..81bb9e11f0cb 100755 --- a/app/src/main/java/com/owncloud/android/ui/activity/UploadListActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/UploadListActivity.kt @@ -112,6 +112,7 @@ class UploadListActivity : adapterHelper = UploadListAdapterHelper(this) uploadListAdapter = UploadListAdapter( this, + storageManager, uploadsStorageManager, userAccountManager, connectivityService, diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/uploadList/UploadListAdapter.kt b/app/src/main/java/com/owncloud/android/ui/adapter/uploadList/UploadListAdapter.kt index c218bea7d16b..110983aac662 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/uploadList/UploadListAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/uploadList/UploadListAdapter.kt @@ -25,6 +25,7 @@ import com.nextcloud.client.device.PowerManagementService import com.nextcloud.client.jobs.upload.FileUploadHelper import com.nextcloud.client.jobs.upload.FileUploadWorker import com.nextcloud.client.network.ConnectivityService +import com.nextcloud.utils.extensions.getSmallThumbnail import com.nextcloud.utils.extensions.getStatusText import com.nextcloud.utils.extensions.isLastResultConflictError import com.nextcloud.utils.extensions.setVisibleIf @@ -67,6 +68,7 @@ import java.util.function.Consumer ) class UploadListAdapter( private val activity: FileActivity, + private val fileDataStorageManager: FileDataStorageManager, private val uploadsStorageManager: UploadsStorageManager, private val accountManager: UserAccountManager, private val connectivityService: ConnectivityService, @@ -488,23 +490,24 @@ class UploadListAdapter( private fun bindItemThumbnail(holder: ItemViewHolder, item: OCUpload) { holder.binding.thumbnail.setImageResource(R.drawable.file) - val fakeFile = OCFile(item.remotePath).apply { - setStoragePath(item.localPath) - mimeType = item.mimeType - } + val ocFile = + fileDataStorageManager.getFileByDecryptedRemotePath(item.remotePath) ?: OCFile(item.remotePath).apply { + setStoragePath(item.localPath) + mimeType = item.mimeType + } val allowedToCreateNewThumbnail = - ThumbnailsCacheManager.cancelPotentialThumbnailWork(fakeFile, holder.binding.thumbnail) + ThumbnailsCacheManager.cancelPotentialThumbnailWork(ocFile, holder.binding.thumbnail) val optionalUser = accountManager.getUser(item.accountName) val fileName = File(item.remotePath).name.takeIf { it.isNotEmpty() } ?: File.separator when { - MimeTypeUtil.isImage(fakeFile) && fakeFile.remoteId != null && + MimeTypeUtil.isImage(ocFile) && ocFile.remoteId != null && item.uploadStatus == UploadsStorageManager.UploadStatus.UPLOAD_SUCCEEDED -> - bindRemoteThumbnail(holder, item, fakeFile, allowedToCreateNewThumbnail) + bindRemoteThumbnail(holder, item, ocFile, allowedToCreateNewThumbnail) - MimeTypeUtil.isImage(fakeFile) -> + MimeTypeUtil.isImage(ocFile) -> bindLocalThumbnail(holder, item, allowedToCreateNewThumbnail) optionalUser.isPresent -> { @@ -517,13 +520,12 @@ class UploadListAdapter( private fun bindRemoteThumbnail( holder: ItemViewHolder, item: OCUpload, - fakeFile: OCFile, + file: OCFile, allowedToCreateNewThumbnail: Boolean ) { - val cacheKey = fakeFile.remoteId.toString() - var thumbnail = ThumbnailsCacheManager.getBitmapFromDiskCache(cacheKey) + var thumbnail = file.smallThumbnail - if (thumbnail != null && !fakeFile.isUpdateThumbnailNeeded) { + if (thumbnail != null && !file.isUpdateThumbnailNeeded) { holder.binding.thumbnail.setImageBitmap(thumbnail) } else if (allowedToCreateNewThumbnail) { val user = activity.user @@ -533,7 +535,7 @@ class UploadListAdapter( activity.storageManager, user.get() ) - thumbnail = thumbnail ?: if (MimeTypeUtil.isVideo(fakeFile)) { + thumbnail = thumbnail ?: if (MimeTypeUtil.isVideo(file)) { ThumbnailsCacheManager.mDefaultVideo } else { ThumbnailsCacheManager.mDefaultImg @@ -541,7 +543,7 @@ class UploadListAdapter( holder.binding.thumbnail.setImageDrawable( ThumbnailsCacheManager.AsyncThumbnailDrawable(activity.resources, thumbnail, task) ) - task.execute(ThumbnailsCacheManager.ThumbnailGenerationTaskObject(fakeFile, null)) + task.execute(ThumbnailsCacheManager.ThumbnailGenerationTaskObject(file, null)) } } @@ -552,7 +554,7 @@ class UploadListAdapter( private fun bindLocalThumbnail(holder: ItemViewHolder, item: OCUpload, allowedToCreateNewThumbnail: Boolean) { val file = File(item.localPath) - val thumbnail = ThumbnailsCacheManager.getBitmapFromDiskCache(file.hashCode().toString()) + val thumbnail = file.getSmallThumbnail() if (thumbnail != null) { holder.binding.thumbnail.setImageBitmap(thumbnail) From 8241cc6e38679cd080327348b29191cfad886369 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Fri, 7 Aug 2026 08:30:17 +0200 Subject: [PATCH 06/20] fix thumbnail visibility for video file in upload list adapter Signed-off-by: alperozturk96 --- .../adapter/uploadList/UploadListAdapter.kt | 31 ++++++++++++++----- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/uploadList/UploadListAdapter.kt b/app/src/main/java/com/owncloud/android/ui/adapter/uploadList/UploadListAdapter.kt index 110983aac662..e5ac80d9bcb0 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/uploadList/UploadListAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/uploadList/UploadListAdapter.kt @@ -91,7 +91,9 @@ class UploadListAdapter( internal class HeaderViewHolder(val binding: UploadListHeaderBinding) : SectionedViewHolder(binding.root) - internal class ItemViewHolder(val binding: UploadListItemBinding) : SectionedViewHolder(binding.root) + internal class ItemViewHolder(val binding: UploadListItemBinding) : SectionedViewHolder(binding.root) { + var boundUploadId: Long = -1 + } override fun getSectionCount(): Int = uploadListSections.size @@ -489,13 +491,28 @@ class UploadListAdapter( private fun bindItemThumbnail(holder: ItemViewHolder, item: OCUpload) { holder.binding.thumbnail.setImageResource(R.drawable.file) + holder.boundUploadId = item.uploadId + + activity.lifecycleScope.launch { + val ocFile = withContext(Dispatchers.IO) { item.toOCFile() } - val ocFile = - fileDataStorageManager.getFileByDecryptedRemotePath(item.remotePath) ?: OCFile(item.remotePath).apply { - setStoragePath(item.localPath) - mimeType = item.mimeType + if (holder.boundUploadId != item.uploadId) { + return@launch } + bindItemThumbnail(holder, item, ocFile) + } + } + + private fun OCUpload.toOCFile(): OCFile = + fileDataStorageManager.getFileByDecryptedRemotePath(remotePath) ?: OCFile(remotePath).apply { + setStoragePath(localPath) + mimeType = this@toOCFile.mimeType + } + + private fun bindItemThumbnail(holder: ItemViewHolder, item: OCUpload, ocFile: OCFile) { + holder.binding.thumbnail.tag = ocFile.fileId + val allowedToCreateNewThumbnail = ThumbnailsCacheManager.cancelPotentialThumbnailWork(ocFile, holder.binding.thumbnail) @@ -503,11 +520,11 @@ class UploadListAdapter( val fileName = File(item.remotePath).name.takeIf { it.isNotEmpty() } ?: File.separator when { - MimeTypeUtil.isImage(ocFile) && ocFile.remoteId != null && + MimeTypeUtil.isImageOrVideo(ocFile) && ocFile.remoteId != null && item.uploadStatus == UploadsStorageManager.UploadStatus.UPLOAD_SUCCEEDED -> bindRemoteThumbnail(holder, item, ocFile, allowedToCreateNewThumbnail) - MimeTypeUtil.isImage(ocFile) -> + MimeTypeUtil.isImageOrVideo(ocFile) -> bindLocalThumbnail(holder, item, allowedToCreateNewThumbnail) optionalUser.isPresent -> { From ed866f538f170592493295846ee7e755cb1589a2 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Fri, 7 Aug 2026 08:43:57 +0200 Subject: [PATCH 07/20] introduce FileThumbnailGenerator Signed-off-by: alperozturk96 --- .../com/nextcloud/client/di/AppModule.java | 12 + .../utils/thumbnail/FileThumbnailGenerator.kt | 274 ++++++++++++++++++ 2 files changed, 286 insertions(+) create mode 100644 app/src/main/java/com/nextcloud/utils/thumbnail/FileThumbnailGenerator.kt diff --git a/app/src/main/java/com/nextcloud/client/di/AppModule.java b/app/src/main/java/com/nextcloud/client/di/AppModule.java index 8748efcfaa4a..1242354fffd7 100644 --- a/app/src/main/java/com/nextcloud/client/di/AppModule.java +++ b/app/src/main/java/com/nextcloud/client/di/AppModule.java @@ -42,6 +42,7 @@ import com.nextcloud.client.notifications.AppNotificationManagerImpl; import com.nextcloud.client.preferences.AppPreferences; import com.nextcloud.client.utils.Throttler; +import com.nextcloud.utils.thumbnail.FileThumbnailGenerator; import com.owncloud.android.providers.UsersAndGroupsSearchConfig; import com.owncloud.android.authentication.PassCodeManager; import com.owncloud.android.datamodel.ArbitraryDataProvider; @@ -279,4 +280,15 @@ OverlayManager overlayManager( UserAccountManager accountManager) { return new OverlayManager(appPreferences, viewThemeUtils, context, accountManager); } + + @Provides + @Singleton + FileThumbnailGenerator fileThumbnailGenerator( + FileDataStorageManager storageManager, + AppPreferences appPreferences, + ViewThemeUtils viewThemeUtils, + Context context, + UserAccountManager accountManager) { + return new FileThumbnailGenerator(storageManager, appPreferences, viewThemeUtils, context, accountManager); + } } diff --git a/app/src/main/java/com/nextcloud/utils/thumbnail/FileThumbnailGenerator.kt b/app/src/main/java/com/nextcloud/utils/thumbnail/FileThumbnailGenerator.kt new file mode 100644 index 000000000000..2825a3d7e4b1 --- /dev/null +++ b/app/src/main/java/com/nextcloud/utils/thumbnail/FileThumbnailGenerator.kt @@ -0,0 +1,274 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2026 Alper Ozturk + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +package com.nextcloud.utils.thumbnail + +import android.content.Context +import android.graphics.Color +import android.graphics.Point +import android.os.AsyncTask +import android.view.WindowManager +import android.widget.FrameLayout +import android.widget.ImageView +import androidx.core.content.ContextCompat +import androidx.core.content.res.ResourcesCompat +import androidx.core.graphics.drawable.toDrawable +import com.elyeproj.loaderviewlibrary.LoaderImageView +import com.nextcloud.client.account.UserAccountManager +import com.nextcloud.client.di.Injectable +import com.nextcloud.client.preferences.AppPreferences +import com.owncloud.android.R +import com.owncloud.android.datamodel.FileDataStorageManager +import com.owncloud.android.datamodel.OCFile +import com.owncloud.android.datamodel.ThumbnailsCacheManager +import com.owncloud.android.datamodel.ThumbnailsCacheManager.AsyncThumbnailDrawable +import com.owncloud.android.datamodel.ThumbnailsCacheManager.ThumbnailGenerationTask +import com.owncloud.android.datamodel.ThumbnailsCacheManager.ThumbnailGenerationTaskObject +import com.owncloud.android.lib.common.utils.Log_OC +import com.owncloud.android.lib.resources.files.model.ServerFileInterface +import com.owncloud.android.utils.BitmapUtils +import com.owncloud.android.utils.DisplayUtils +import com.owncloud.android.utils.MimeTypeUtil +import com.owncloud.android.utils.theme.ViewThemeUtils +import javax.inject.Inject +import kotlin.math.roundToInt + +class FileThumbnailGenerator @Inject constructor( + private val storageManager: FileDataStorageManager, + private val preferences: AppPreferences, + private val viewThemeUtils: ViewThemeUtils, + private val context: Context, + private val accountManager: UserAccountManager +) : Injectable { + + companion object { + private const val TAG = "FileThumbnailGenerator" + } + + private val tasks: MutableList = ArrayList() + + fun execute( + file: OCFile, + thumbnailView: ImageView, + gridView: Boolean, + shimmerThumbnail: LoaderImageView? + ) { + if (file.remoteId == null || !file.isPreviewAvailable) { + setThumbnailFirstTimeForFile( + file, + thumbnailView, + gridView, + shimmerThumbnail, + ) + return + } + + setThumbnailFromCache( + file, + thumbnailView, + gridView, + shimmerThumbnail + ) + } + + private fun setThumbnailFirstTimeForFile( + file: OCFile, + thumbnailView: ImageView, + gridView: Boolean, + shimmerThumbnail: LoaderImageView? + ) { + if (file.remoteId != null) { + generateNewThumbnailIfNecessary( + file, + thumbnailView, + gridView, + shimmerThumbnail, + ) + return + } + + DisplayUtils.stopShimmer(shimmerThumbnail, thumbnailView) + val icon = MimeTypeUtil.getFileTypeIcon(file.mimeType, file.fileName, context, viewThemeUtils) + thumbnailView.setImageDrawable(icon) + } + + fun setThumbnailFromCache( + file: OCFile, + thumbnailView: ImageView, + gridView: Boolean, + shimmerThumbnail: LoaderImageView? + ) { + val thumbnail = file.smallThumbnail + if (thumbnail == null || file.isUpdateThumbnailNeeded) { + generateNewThumbnailIfNecessary( + file, + thumbnailView, + gridView, + shimmerThumbnail, + ) + setThumbnailBackgroundForPNGFileIfNeeded(file, context, thumbnailView) + return + } + + DisplayUtils.stopShimmer(shimmerThumbnail, thumbnailView) + + if (MimeTypeUtil.isVideo(file)) { + val withOverlay = ThumbnailsCacheManager.addVideoOverlay(thumbnail, context) + thumbnailView.setImageBitmap(withOverlay) + } else { + BitmapUtils.setRoundedBitmapAccordingToListType(gridView, thumbnail, thumbnailView) + } + + setThumbnailBackgroundForPNGFileIfNeeded(file, context, thumbnailView) + } + + private fun generateNewThumbnailIfNecessary( + file: OCFile, + thumbnailView: ImageView, + gridView: Boolean, + shimmerThumbnail: LoaderImageView? + ) { + if (!ThumbnailsCacheManager.cancelPotentialThumbnailWork(file, thumbnailView)) { + return + } + + var thumbnail = file.smallThumbnail + + if (thumbnail != null) { + // If thumbnail is already in cache, display it immediately + thumbnailView.setImageBitmap(thumbnail) + DisplayUtils.stopShimmer(shimmerThumbnail, thumbnailView) + return + } + + for (task in tasks) { + if (file.remoteId != null && task.imageKey != null && + file.remoteId == task.imageKey + ) { + return + } + } + + thumbnailView.tag = file.fileId + + try { + val task = + ThumbnailGenerationTask( + thumbnailView, + storageManager, + accountManager.user, + tasks, + gridView, + file.remoteId + ) + var drawable = MimeTypeUtil.getFileTypeIcon( + file.mimeType, + file.fileName, + context, + viewThemeUtils + ) + if (drawable == null) { + drawable = ResourcesCompat.getDrawable( + context.resources, + R.drawable.file_image, + null + ) + } + if (drawable == null) { + drawable = Color.GRAY.toDrawable() + } + + val px = ThumbnailsCacheManager.getThumbnailDimension() + thumbnail = BitmapUtils.drawableToBitmap(drawable, px, px) + val asyncDrawable = + AsyncThumbnailDrawable( + context.resources, + thumbnail, task + ) + + shimmerThumbnail?.postDelayed({ + if (thumbnailView.getDrawable() == null) { + if (gridView) { + configShimmerGridImageSize(shimmerThumbnail, preferences.getGridColumns()) + } + DisplayUtils.startShimmer(shimmerThumbnail, thumbnailView) + } + }, 100) + + task.setListener(object : ThumbnailGenerationTask.Listener { + override fun onSuccess() { + DisplayUtils.stopShimmer(shimmerThumbnail, thumbnailView) + } + + override fun onError() { + DisplayUtils.stopShimmer(shimmerThumbnail, thumbnailView) + val icon = + MimeTypeUtil.getFileTypeIcon(file.mimeType, file.fileName, context, viewThemeUtils) + thumbnailView.setImageDrawable(icon) + thumbnailView.invalidate() + Log_OC.w(TAG, "setting thumbnail failed, using icon from mime type") + } + }) + + thumbnailView.setImageDrawable(asyncDrawable) + tasks.add(task) + task.executeOnExecutor( + AsyncTask.THREAD_POOL_EXECUTOR, + ThumbnailGenerationTaskObject( + file, + file.remoteId + ) + ) + thumbnailView.invalidate() + } catch (e: Exception) { + Log_OC.d(TAG, "ThumbnailGenerationTask : " + e.message) + } + } + + private fun configShimmerGridImageSize(thumbnailShimmer: LoaderImageView, gridColumns: Float) { + try { + val targetLayoutParams = thumbnailShimmer.layoutParams as FrameLayout.LayoutParams + + val screenSize = getScreenSize() + val marginLeftAndRight = targetLayoutParams.leftMargin + targetLayoutParams.rightMargin + val size = (screenSize.x / gridColumns - marginLeftAndRight).roundToInt() + + val params = FrameLayout.LayoutParams(size, size) + params.setMargins( + targetLayoutParams.leftMargin, + targetLayoutParams.topMargin, + targetLayoutParams.rightMargin, + targetLayoutParams.bottomMargin + ) + thumbnailShimmer.setLayoutParams(params) + } catch (exception: Exception) { + Log_OC.e("ConfigShimmer", exception.message) + } + } + + private fun getScreenSize(): Point { + val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager? + if (windowManager != null) { + val displaySize = Point() + windowManager.getDefaultDisplay().getSize(displaySize) + return displaySize + } else { + throw Exception("WindowManager not found") + } + } + + private fun setThumbnailBackgroundForPNGFileIfNeeded( + file: ServerFileInterface, + context: Context, + thumbnailView: ImageView + ) { + if ("image/png".equals(file.mimeType, ignoreCase = true)) { + val color = ContextCompat.getColor(context, R.color.bg_default) + thumbnailView.setBackgroundColor(color) + } + } +} From 7cf1adc1a6c82d1f1876cddcae4869dfb5397230 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Fri, 7 Aug 2026 08:55:10 +0200 Subject: [PATCH 08/20] simplify FileThumbnailGenerator Signed-off-by: alperozturk96 --- .../com/nextcloud/client/di/AppModule.java | 11 - .../utils/thumbnail/FileThumbnailGenerator.kt | 318 +++++++----------- 2 files changed, 129 insertions(+), 200 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/di/AppModule.java b/app/src/main/java/com/nextcloud/client/di/AppModule.java index 1242354fffd7..eca8f4668618 100644 --- a/app/src/main/java/com/nextcloud/client/di/AppModule.java +++ b/app/src/main/java/com/nextcloud/client/di/AppModule.java @@ -42,7 +42,6 @@ import com.nextcloud.client.notifications.AppNotificationManagerImpl; import com.nextcloud.client.preferences.AppPreferences; import com.nextcloud.client.utils.Throttler; -import com.nextcloud.utils.thumbnail.FileThumbnailGenerator; import com.owncloud.android.providers.UsersAndGroupsSearchConfig; import com.owncloud.android.authentication.PassCodeManager; import com.owncloud.android.datamodel.ArbitraryDataProvider; @@ -281,14 +280,4 @@ OverlayManager overlayManager( return new OverlayManager(appPreferences, viewThemeUtils, context, accountManager); } - @Provides - @Singleton - FileThumbnailGenerator fileThumbnailGenerator( - FileDataStorageManager storageManager, - AppPreferences appPreferences, - ViewThemeUtils viewThemeUtils, - Context context, - UserAccountManager accountManager) { - return new FileThumbnailGenerator(storageManager, appPreferences, viewThemeUtils, context, accountManager); - } } diff --git a/app/src/main/java/com/nextcloud/utils/thumbnail/FileThumbnailGenerator.kt b/app/src/main/java/com/nextcloud/utils/thumbnail/FileThumbnailGenerator.kt index 2825a3d7e4b1..9ff60aa927eb 100644 --- a/app/src/main/java/com/nextcloud/utils/thumbnail/FileThumbnailGenerator.kt +++ b/app/src/main/java/com/nextcloud/utils/thumbnail/FileThumbnailGenerator.kt @@ -8,10 +8,9 @@ package com.nextcloud.utils.thumbnail import android.content.Context +import android.graphics.Bitmap import android.graphics.Color -import android.graphics.Point -import android.os.AsyncTask -import android.view.WindowManager +import android.graphics.drawable.Drawable import android.widget.FrameLayout import android.widget.ImageView import androidx.core.content.ContextCompat @@ -19,7 +18,6 @@ import androidx.core.content.res.ResourcesCompat import androidx.core.graphics.drawable.toDrawable import com.elyeproj.loaderviewlibrary.LoaderImageView import com.nextcloud.client.account.UserAccountManager -import com.nextcloud.client.di.Injectable import com.nextcloud.client.preferences.AppPreferences import com.owncloud.android.R import com.owncloud.android.datamodel.FileDataStorageManager @@ -32,243 +30,185 @@ import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.lib.resources.files.model.ServerFileInterface import com.owncloud.android.utils.BitmapUtils import com.owncloud.android.utils.DisplayUtils +import com.owncloud.android.utils.MimeType import com.owncloud.android.utils.MimeTypeUtil import com.owncloud.android.utils.theme.ViewThemeUtils +import java.util.Collections +import java.util.concurrent.Executors import javax.inject.Inject +import javax.inject.Provider +import javax.inject.Singleton import kotlin.math.roundToInt +@Singleton class FileThumbnailGenerator @Inject constructor( - private val storageManager: FileDataStorageManager, + private val storageManager: Provider, private val preferences: AppPreferences, private val viewThemeUtils: ViewThemeUtils, private val context: Context, private val accountManager: UserAccountManager -) : Injectable { +) { companion object { private const val TAG = "FileThumbnailGenerator" + private const val SHIMMER_DELAY_MS = 100L + private const val MIN_THREADS = 3 + private const val CORES_PER_THREAD = 2 } - private val tasks: MutableList = ArrayList() + private val executor = Executors.newFixedThreadPool( + maxOf(MIN_THREADS, Runtime.getRuntime().availableProcessors() / CORES_PER_THREAD) + ) - fun execute( - file: OCFile, - thumbnailView: ImageView, - gridView: Boolean, - shimmerThumbnail: LoaderImageView? - ) { - if (file.remoteId == null || !file.isPreviewAvailable) { - setThumbnailFirstTimeForFile( - file, - thumbnailView, - gridView, - shimmerThumbnail, - ) + private val tasks = Collections.synchronizedList(mutableListOf()) + + fun setThumbnail(file: OCFile, view: ImageView, isGrid: Boolean, shimmer: LoaderImageView?) { + if (file.remoteId == null) { + DisplayUtils.stopShimmer(shimmer, view) + view.setImageDrawable(file.mimeIcon()) return } - setThumbnailFromCache( - file, - thumbnailView, - gridView, - shimmerThumbnail - ) - } - - private fun setThumbnailFirstTimeForFile( - file: OCFile, - thumbnailView: ImageView, - gridView: Boolean, - shimmerThumbnail: LoaderImageView? - ) { - if (file.remoteId != null) { - generateNewThumbnailIfNecessary( - file, - thumbnailView, - gridView, - shimmerThumbnail, - ) + if (!file.isPreviewAvailable) { + generate(file, view, isGrid, shimmer) return } - DisplayUtils.stopShimmer(shimmerThumbnail, thumbnailView) - val icon = MimeTypeUtil.getFileTypeIcon(file.mimeType, file.fileName, context, viewThemeUtils) - thumbnailView.setImageDrawable(icon) + val cached = file.smallThumbnail + if (cached == null || file.isUpdateThumbnailNeeded) { + generate(file, view, isGrid, shimmer) + } else { + show(cached, file, view, isGrid, shimmer) + } + + applyPngBackground(file, view) } - fun setThumbnailFromCache( - file: OCFile, - thumbnailView: ImageView, - gridView: Boolean, - shimmerThumbnail: LoaderImageView? - ) { - val thumbnail = file.smallThumbnail - if (thumbnail == null || file.isUpdateThumbnailNeeded) { - generateNewThumbnailIfNecessary( - file, - thumbnailView, - gridView, - shimmerThumbnail, - ) - setThumbnailBackgroundForPNGFileIfNeeded(file, context, thumbnailView) - return + fun cancelPendingTasks() { + synchronized(tasks) { + tasks.forEach { task -> + task.cancel(true) + task.getMethod?.abort() + } + tasks.clear() } + } - DisplayUtils.stopShimmer(shimmerThumbnail, thumbnailView) + private fun show(bitmap: Bitmap, file: OCFile, view: ImageView, isGrid: Boolean, shimmer: LoaderImageView?) { + DisplayUtils.stopShimmer(shimmer, view) if (MimeTypeUtil.isVideo(file)) { - val withOverlay = ThumbnailsCacheManager.addVideoOverlay(thumbnail, context) - thumbnailView.setImageBitmap(withOverlay) + view.setImageBitmap(ThumbnailsCacheManager.addVideoOverlay(bitmap, context)) } else { - BitmapUtils.setRoundedBitmapAccordingToListType(gridView, thumbnail, thumbnailView) + BitmapUtils.setRoundedBitmapAccordingToListType(isGrid, bitmap, view) } - - setThumbnailBackgroundForPNGFileIfNeeded(file, context, thumbnailView) } - private fun generateNewThumbnailIfNecessary( - file: OCFile, - thumbnailView: ImageView, - gridView: Boolean, - shimmerThumbnail: LoaderImageView? - ) { - if (!ThumbnailsCacheManager.cancelPotentialThumbnailWork(file, thumbnailView)) { + private fun generate(file: OCFile, view: ImageView, isGrid: Boolean, shimmer: LoaderImageView?) { + if (!ThumbnailsCacheManager.cancelPotentialThumbnailWork(file, view)) { return } - var thumbnail = file.smallThumbnail - - if (thumbnail != null) { - // If thumbnail is already in cache, display it immediately - thumbnailView.setImageBitmap(thumbnail) - DisplayUtils.stopShimmer(shimmerThumbnail, thumbnailView) + file.smallThumbnail?.let { cached -> + view.setImageBitmap(cached) + DisplayUtils.stopShimmer(shimmer, view) return } - for (task in tasks) { - if (file.remoteId != null && task.imageKey != null && - file.remoteId == task.imageKey - ) { - return - } + startTask(file, view, isGrid, shimmer) + } + + @Suppress("TooGenericExceptionCaught") + private fun startTask(file: OCFile, view: ImageView, isGrid: Boolean, shimmer: LoaderImageView?) { + if (tasks.any { it.imageKey == file.remoteId }) { + return } - thumbnailView.tag = file.fileId + view.tag = file.fileId try { - val task = - ThumbnailGenerationTask( - thumbnailView, - storageManager, - accountManager.user, - tasks, - gridView, - file.remoteId - ) - var drawable = MimeTypeUtil.getFileTypeIcon( - file.mimeType, - file.fileName, - context, - viewThemeUtils - ) - if (drawable == null) { - drawable = ResourcesCompat.getDrawable( - context.resources, - R.drawable.file_image, - null - ) - } - if (drawable == null) { - drawable = Color.GRAY.toDrawable() - } - - val px = ThumbnailsCacheManager.getThumbnailDimension() - thumbnail = BitmapUtils.drawableToBitmap(drawable, px, px) - val asyncDrawable = - AsyncThumbnailDrawable( - context.resources, - thumbnail, task - ) - - shimmerThumbnail?.postDelayed({ - if (thumbnailView.getDrawable() == null) { - if (gridView) { - configShimmerGridImageSize(shimmerThumbnail, preferences.getGridColumns()) - } - DisplayUtils.startShimmer(shimmerThumbnail, thumbnailView) - } - }, 100) - - task.setListener(object : ThumbnailGenerationTask.Listener { - override fun onSuccess() { - DisplayUtils.stopShimmer(shimmerThumbnail, thumbnailView) - } - - override fun onError() { - DisplayUtils.stopShimmer(shimmerThumbnail, thumbnailView) - val icon = - MimeTypeUtil.getFileTypeIcon(file.mimeType, file.fileName, context, viewThemeUtils) - thumbnailView.setImageDrawable(icon) - thumbnailView.invalidate() - Log_OC.w(TAG, "setting thumbnail failed, using icon from mime type") - } - }) - - thumbnailView.setImageDrawable(asyncDrawable) + val task = newTask(file, view, isGrid, shimmer) + view.setImageDrawable(AsyncThumbnailDrawable(context.resources, file.placeholder(), task)) + startShimmerLater(view, isGrid, shimmer) tasks.add(task) - task.executeOnExecutor( - AsyncTask.THREAD_POOL_EXECUTOR, - ThumbnailGenerationTaskObject( - file, - file.remoteId - ) - ) - thumbnailView.invalidate() + task.execute(file) + view.invalidate() } catch (e: Exception) { - Log_OC.d(TAG, "ThumbnailGenerationTask : " + e.message) + Log_OC.d(TAG, "ThumbnailGenerationTask: ${e.message}") } } - private fun configShimmerGridImageSize(thumbnailShimmer: LoaderImageView, gridColumns: Float) { - try { - val targetLayoutParams = thumbnailShimmer.layoutParams as FrameLayout.LayoutParams - - val screenSize = getScreenSize() - val marginLeftAndRight = targetLayoutParams.leftMargin + targetLayoutParams.rightMargin - val size = (screenSize.x / gridColumns - marginLeftAndRight).roundToInt() - - val params = FrameLayout.LayoutParams(size, size) - params.setMargins( - targetLayoutParams.leftMargin, - targetLayoutParams.topMargin, - targetLayoutParams.rightMargin, - targetLayoutParams.bottomMargin - ) - thumbnailShimmer.setLayoutParams(params) - } catch (exception: Exception) { - Log_OC.e("ConfigShimmer", exception.message) - } + private fun newTask( + file: OCFile, + view: ImageView, + isGrid: Boolean, + shimmer: LoaderImageView? + ): ThumbnailGenerationTask = ThumbnailGenerationTask( + view, + storageManager.get(), + accountManager.user, + tasks, + isGrid, + file.remoteId + ).apply { + setListener(object : ThumbnailGenerationTask.Listener { + override fun onSuccess() = DisplayUtils.stopShimmer(shimmer, view) + + override fun onError() { + DisplayUtils.stopShimmer(shimmer, view) + view.setImageDrawable(file.mimeIcon()) + view.invalidate() + Log_OC.w(TAG, "setting thumbnail failed, using icon from mime type") + } + }) } - private fun getScreenSize(): Point { - val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager? - if (windowManager != null) { - val displaySize = Point() - windowManager.getDefaultDisplay().getSize(displaySize) - return displaySize - } else { - throw Exception("WindowManager not found") + @Suppress("DEPRECATION") + private fun ThumbnailGenerationTask.execute(file: OCFile) { + executeOnExecutor(executor, ThumbnailGenerationTaskObject(file, file.remoteId)) + } + + private fun startShimmerLater(view: ImageView, isGrid: Boolean, shimmer: LoaderImageView?) { + shimmer?.postDelayed({ + if (view.drawable != null) { + return@postDelayed + } + + if (isGrid) { + shimmer.resizeToGridCell(preferences.gridColumns) + } + + DisplayUtils.startShimmer(shimmer, view) + }, SHIMMER_DELAY_MS) + } + + private fun LoaderImageView.resizeToGridCell(columns: Float) { + val current = layoutParams as? FrameLayout.LayoutParams ?: return + val horizontalMargin = current.leftMargin + current.rightMargin + val screenWidth = context.resources.displayMetrics.widthPixels + val size = (screenWidth / columns - horizontalMargin).roundToInt() + + layoutParams = FrameLayout.LayoutParams(size, size).apply { + setMargins(current.leftMargin, current.topMargin, current.rightMargin, current.bottomMargin) } } - private fun setThumbnailBackgroundForPNGFileIfNeeded( - file: ServerFileInterface, - context: Context, - thumbnailView: ImageView - ) { - if ("image/png".equals(file.mimeType, ignoreCase = true)) { - val color = ContextCompat.getColor(context, R.color.bg_default) - thumbnailView.setBackgroundColor(color) + private fun OCFile.mimeIcon(): Drawable? = MimeTypeUtil.getFileTypeIcon(mimeType, fileName, context, viewThemeUtils) + + private fun OCFile.placeholder(): Bitmap { + val drawable = mimeIcon() + ?: ResourcesCompat.getDrawable(context.resources, R.drawable.file_image, null) + ?: Color.GRAY.toDrawable() + val size = ThumbnailsCacheManager.getThumbnailDimension() + + return BitmapUtils.drawableToBitmap(drawable, size, size) + } + + private fun applyPngBackground(file: ServerFileInterface, view: ImageView) { + if (!MimeType.PNG.equals(file.mimeType, ignoreCase = true)) { + return } + + view.setBackgroundColor(ContextCompat.getColor(context, R.color.bg_default)) } } From 4f6eda18094a8c13c0660cb73b21b5f39064f1b4 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Fri, 7 Aug 2026 09:15:30 +0200 Subject: [PATCH 09/20] unify file thumbnail generation Signed-off-by: alperozturk96 --- .../ui/fileactions/FileActionsBottomSheet.kt | 13 +- .../TrashbinFileActionsBottomSheet.kt | 14 +- .../utils/extensions/ImageViewExtensions.kt | 16 ++ .../utils/thumbnail/FileThumbnailGenerator.kt | 36 ++- .../android/ui/activity/ShareActivity.kt | 11 +- .../android/ui/adapter/GalleryAdapter.kt | 6 +- .../android/ui/adapter/OCFileListAdapter.java | 13 +- .../android/ui/adapter/OCFileListDelegate.kt | 33 +-- .../UnifiedSearchCurrentDirItemViewHolder.kt | 11 +- .../ui/adapter/UnifiedSearchItemViewHolder.kt | 16 +- .../ui/adapter/UnifiedSearchListAdapter.kt | 8 +- .../ui/dialog/ConflictsResolveDialog.kt | 24 +- .../android/ui/fragment/GalleryFragment.kt | 3 +- .../ui/fragment/OCFileListFragment.java | 5 +- .../ui/fragment/UnifiedSearchFragment.kt | 7 +- .../owncloud/android/utils/DisplayUtils.java | 234 +----------------- .../android/utils/overlay/OverlayManager.kt | 5 +- .../android/ui/adapter/GalleryAdapterTest.kt | 10 +- 18 files changed, 126 insertions(+), 339 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 733b87b1693a..8571d40bc9cd 100644 --- a/app/src/main/java/com/nextcloud/ui/fileactions/FileActionsBottomSheet.kt +++ b/app/src/main/java/com/nextcloud/ui/fileactions/FileActionsBottomSheet.kt @@ -35,6 +35,7 @@ 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.nextcloud.utils.thumbnail.FileThumbnailGenerator import com.owncloud.android.R import com.owncloud.android.databinding.FileActionsBottomSheetBinding import com.owncloud.android.databinding.FileActionsBottomSheetItemBinding @@ -73,6 +74,9 @@ class FileActionsBottomSheet : @Inject lateinit var overlayManager: OverlayManager + @Inject + lateinit var fileThumbnailGenerator: FileThumbnailGenerator + private lateinit var viewModel: FileActionsViewModel private var _binding: FileActionsBottomSheetBinding? = null @@ -81,8 +85,6 @@ class FileActionsBottomSheet : private lateinit var componentsGetter: ComponentsGetter - private val thumbnailAsyncTasks = mutableListOf() - private var endpoints: List? = mutableListOf() private lateinit var clientIntegration: ClientIntegration @@ -152,14 +154,9 @@ class FileActionsBottomSheet : DisplayUtils.setThumbnail( it, binding.thumbnailLayout.thumbnail, - currentUserProvider.user, - storageManager, - thumbnailAsyncTasks, false, - context, binding.thumbnailLayout.thumbnailShimmer, - syncedFolderProvider.preferences, - viewThemeUtils, + fileThumbnailGenerator, overlayManager ) } diff --git a/app/src/main/java/com/nextcloud/ui/trashbinFileActions/TrashbinFileActionsBottomSheet.kt b/app/src/main/java/com/nextcloud/ui/trashbinFileActions/TrashbinFileActionsBottomSheet.kt index 89573ec5f443..7f20ca201d8b 100644 --- a/app/src/main/java/com/nextcloud/ui/trashbinFileActions/TrashbinFileActionsBottomSheet.kt +++ b/app/src/main/java/com/nextcloud/ui/trashbinFileActions/TrashbinFileActionsBottomSheet.kt @@ -27,12 +27,12 @@ import com.nextcloud.client.account.CurrentAccountProvider import com.nextcloud.client.di.Injectable import com.nextcloud.client.di.ViewModelFactory import com.nextcloud.utils.extensions.toOCFile +import com.nextcloud.utils.thumbnail.FileThumbnailGenerator import com.owncloud.android.R import com.owncloud.android.databinding.FileActionsBottomSheetBinding import com.owncloud.android.databinding.FileActionsBottomSheetItemBinding import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.SyncedFolderProvider -import com.owncloud.android.datamodel.ThumbnailsCacheManager import com.owncloud.android.lib.resources.trashbin.model.TrashbinFile import com.owncloud.android.utils.DisplayUtils import com.owncloud.android.utils.overlay.OverlayManager @@ -61,14 +61,15 @@ class TrashbinFileActionsBottomSheet : @Inject lateinit var overlayManager: OverlayManager + @Inject + lateinit var fileThumbnailGenerator: FileThumbnailGenerator + private lateinit var viewModel: TrashbinFileActionsViewModel private var _binding: FileActionsBottomSheetBinding? = null val binding get() = _binding!! - private val thumbnailAsyncTasks = mutableListOf() - fun interface ResultListener { fun onResult(@IdRes actionId: Int) } @@ -125,14 +126,9 @@ class TrashbinFileActionsBottomSheet : DisplayUtils.setThumbnail( it.toOCFile(), binding.thumbnailLayout.thumbnail, - currentUserProvider.user, - storageManager, - thumbnailAsyncTasks, false, - context, binding.thumbnailLayout.thumbnailShimmer, - syncedFolderProvider.preferences, - viewThemeUtils, + fileThumbnailGenerator, overlayManager ) } diff --git a/app/src/main/java/com/nextcloud/utils/extensions/ImageViewExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/ImageViewExtensions.kt index 896d26dca84e..4f66f3fe17e7 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/ImageViewExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/ImageViewExtensions.kt @@ -10,13 +10,29 @@ package com.nextcloud.utils.extensions import android.content.Context import android.graphics.drawable.GradientDrawable import android.util.TypedValue +import android.view.View import android.view.ViewOutlineProvider import android.widget.ImageView import androidx.annotation.ColorInt import androidx.annotation.DrawableRes import androidx.core.content.ContextCompat +import com.elyeproj.loaderviewlibrary.LoaderImageView import com.owncloud.android.R +fun ImageView.startShimmer(shimmer: LoaderImageView) { + shimmer.setImageResource(R.drawable.background) + shimmer.resetLoader() + setVisibility(View.GONE) + shimmer.setVisibility(View.VISIBLE) +} + +fun ImageView.stopShimmer(shimmer: LoaderImageView?) { + shimmer?.let { + it.visibility = View.GONE + } + setVisibility(View.VISIBLE) +} + @JvmOverloads fun ImageView.makeRoundedWithIcon( context: Context, diff --git a/app/src/main/java/com/nextcloud/utils/thumbnail/FileThumbnailGenerator.kt b/app/src/main/java/com/nextcloud/utils/thumbnail/FileThumbnailGenerator.kt index 9ff60aa927eb..438fd5c6a482 100644 --- a/app/src/main/java/com/nextcloud/utils/thumbnail/FileThumbnailGenerator.kt +++ b/app/src/main/java/com/nextcloud/utils/thumbnail/FileThumbnailGenerator.kt @@ -19,6 +19,9 @@ import androidx.core.graphics.drawable.toDrawable import com.elyeproj.loaderviewlibrary.LoaderImageView import com.nextcloud.client.account.UserAccountManager import com.nextcloud.client.preferences.AppPreferences +import com.nextcloud.model.OfflineOperationType +import com.nextcloud.utils.extensions.startShimmer +import com.nextcloud.utils.extensions.stopShimmer import com.owncloud.android.R import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile @@ -29,7 +32,6 @@ import com.owncloud.android.datamodel.ThumbnailsCacheManager.ThumbnailGeneration import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.lib.resources.files.model.ServerFileInterface import com.owncloud.android.utils.BitmapUtils -import com.owncloud.android.utils.DisplayUtils import com.owncloud.android.utils.MimeType import com.owncloud.android.utils.MimeTypeUtil import com.owncloud.android.utils.theme.ViewThemeUtils @@ -54,6 +56,8 @@ class FileThumbnailGenerator @Inject constructor( private const val SHIMMER_DELAY_MS = 100L private const val MIN_THREADS = 3 private const val CORES_PER_THREAD = 2 + private const val OFFLINE_ICON_SIZE = 105 + private const val OFFLINE_ICON_ALPHA = 100 } private val executor = Executors.newFixedThreadPool( @@ -64,7 +68,7 @@ class FileThumbnailGenerator @Inject constructor( fun setThumbnail(file: OCFile, view: ImageView, isGrid: Boolean, shimmer: LoaderImageView?) { if (file.remoteId == null) { - DisplayUtils.stopShimmer(shimmer, view) + view.stopShimmer(shimmer) view.setImageDrawable(file.mimeIcon()) return } @@ -84,6 +88,24 @@ class FileThumbnailGenerator @Inject constructor( applyPngBackground(file, view) } + fun setOfflineOperationThumbnail(file: OCFile, view: ImageView) { + if (file.isFolder) { + view.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_folder_offline)) + return + } + + file.offlineCreateFileBitmap()?.let { bitmap -> + view.setImageBitmap(BitmapUtils.addColorFilter(bitmap, Color.GRAY, OFFLINE_ICON_ALPHA)) + } + } + + private fun OCFile.offlineCreateFileBitmap(): Bitmap? { + val operation = storageManager.get().offlineOperationDao.getByPath(decryptedRemotePath) + val localPath = (operation?.type as? OfflineOperationType.CreateFile)?.localPath ?: return null + + return BitmapUtils.decodeSampledBitmapFromFile(localPath, OFFLINE_ICON_SIZE, OFFLINE_ICON_SIZE) + } + fun cancelPendingTasks() { synchronized(tasks) { tasks.forEach { task -> @@ -95,7 +117,7 @@ class FileThumbnailGenerator @Inject constructor( } private fun show(bitmap: Bitmap, file: OCFile, view: ImageView, isGrid: Boolean, shimmer: LoaderImageView?) { - DisplayUtils.stopShimmer(shimmer, view) + view.stopShimmer(shimmer) if (MimeTypeUtil.isVideo(file)) { view.setImageBitmap(ThumbnailsCacheManager.addVideoOverlay(bitmap, context)) @@ -111,7 +133,7 @@ class FileThumbnailGenerator @Inject constructor( file.smallThumbnail?.let { cached -> view.setImageBitmap(cached) - DisplayUtils.stopShimmer(shimmer, view) + view.stopShimmer(shimmer) return } @@ -152,10 +174,10 @@ class FileThumbnailGenerator @Inject constructor( file.remoteId ).apply { setListener(object : ThumbnailGenerationTask.Listener { - override fun onSuccess() = DisplayUtils.stopShimmer(shimmer, view) + override fun onSuccess() = view.stopShimmer(shimmer) override fun onError() { - DisplayUtils.stopShimmer(shimmer, view) + view.stopShimmer(shimmer) view.setImageDrawable(file.mimeIcon()) view.invalidate() Log_OC.w(TAG, "setting thumbnail failed, using icon from mime type") @@ -178,7 +200,7 @@ class FileThumbnailGenerator @Inject constructor( shimmer.resizeToGridCell(preferences.gridColumns) } - DisplayUtils.startShimmer(shimmer, view) + view.startShimmer(shimmer) }, SHIMMER_DELAY_MS) } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ShareActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/ShareActivity.kt index d03e13f708a6..fbbc8f4e2430 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ShareActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/ShareActivity.kt @@ -18,6 +18,7 @@ import androidx.lifecycle.lifecycleScope import com.nextcloud.android.common.ui.theme.utils.ColorRole import com.nextcloud.client.account.User import com.nextcloud.client.di.Injectable +import com.nextcloud.utils.thumbnail.FileThumbnailGenerator import com.owncloud.android.R import com.owncloud.android.databinding.ShareActivityBinding import com.owncloud.android.datamodel.OCFile @@ -50,6 +51,9 @@ class ShareActivity : @Inject lateinit var overlayManager: OverlayManager + @Inject + lateinit var fileThumbnailGenerator: FileThumbnailGenerator + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -142,14 +146,9 @@ class ShareActivity : DisplayUtils.setThumbnail( file, binding.shareFileIcon, - user, - storageManager, - mutableListOf(), false, - this, null, - preferences, - viewThemeUtils, + fileThumbnailGenerator, overlayManager ) } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt b/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt index 41df5a06cb99..a07c8654fdd0 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt @@ -24,6 +24,7 @@ import com.afollestad.sectionedrecyclerview.SectionedViewHolder import com.nextcloud.client.account.User import com.nextcloud.client.preferences.AppPreferences import com.nextcloud.utils.extensions.toGalleryItems +import com.nextcloud.utils.thumbnail.FileThumbnailGenerator import com.owncloud.android.databinding.GalleryHeaderBinding import com.owncloud.android.databinding.GalleryRowBinding import com.owncloud.android.datamodel.FileDataStorageManager @@ -46,7 +47,8 @@ class GalleryAdapter( transferServiceGetter: ComponentsGetter, private val viewThemeUtils: ViewThemeUtils, var columns: Int, - private val defaultThumbnailSize: Int + private val defaultThumbnailSize: Int, + private val fileThumbnailGenerator: FileThumbnailGenerator ) : SectionedRecyclerViewAdapter(), CommonOCFileListAdapterInterface, PopupTextProvider { @@ -231,7 +233,7 @@ class GalleryAdapter( override fun isMultiSelect(): Boolean = ocFileListDelegate.isMultiSelect override fun cancelAllPendingTasks() { - ocFileListDelegate.cancelAllPendingTasks() + fileThumbnailGenerator.cancelPendingTasks() } override fun addCheckedFile(file: OCFile) { 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 e68ba687ec1f..b838e2fb06ae 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 @@ -35,8 +35,10 @@ import com.nextcloud.client.preferences.AppPreferences; import com.nextcloud.model.OfflineOperationType; import com.nextcloud.utils.e2ee.E2EVersionHelper; +import com.nextcloud.utils.extensions.ImageViewExtensionsKt; import com.nextcloud.utils.extensions.ViewExtensionsKt; import com.nextcloud.utils.mdm.MDMConfig; +import com.nextcloud.utils.thumbnail.FileThumbnailGenerator; import com.owncloud.android.MainApp; import com.owncloud.android.R; import com.owncloud.android.databinding.GridItemBinding; @@ -136,6 +138,7 @@ public class OCFileListAdapter extends RecyclerView.Adapter = HashSet() private var highlightedItem: OCFile? = null var isMultiSelect = false - private val asyncTasks: MutableList = ArrayList() private val ioScope = CoroutineScope(SupervisorJob() + Dispatchers.IO) private val galleryImageGenerationJob = GalleryImageGenerationJob(user, storageManager) @@ -136,7 +136,7 @@ class OCFileListDelegate( if (imageView.tag == file.fileId) { Log_OC.d(tag, "setGalleryImage.onSuccess()") galleryRowHolder.binding.rowLayout.invalidate() - DisplayUtils.stopShimmer(shimmer, imageView) + imageView.stopShimmer(shimmer) } } @@ -150,7 +150,7 @@ class OCFileListDelegate( override fun onError() { if (imageView.tag == file.fileId) { Log_OC.d(tag, "setGalleryImage.onError()") - DisplayUtils.stopShimmer(shimmer, imageView) + imageView.stopShimmer(shimmer) } } } @@ -183,19 +183,15 @@ class OCFileListDelegate( thumbnail: ImageView, shimmerThumbnail: LoaderImageView?, file: OCFile, + thumbnailGenerator: FileThumbnailGenerator, overlayManager: OverlayManager ) { DisplayUtils.setThumbnail( file, thumbnail, - user, - storageManager, - asyncTasks, gridView, - context, shimmerThumbnail, - preferences, - viewThemeUtils, + thumbnailGenerator, overlayManager ) } @@ -206,6 +202,7 @@ class OCFileListDelegate( file: OCFile, currentDirectory: OCFile?, searchType: SearchType?, + thumbnailGenerator: FileThumbnailGenerator, overlayManager: OverlayManager ) { // thumbnail @@ -221,7 +218,7 @@ class OCFileListDelegate( viewHolder.thumbnail.setPadding(padding, padding, padding, padding) } } - setThumbnail(viewHolder.thumbnail, viewHolder.shimmerThumbnail, file, overlayManager) + setThumbnail(viewHolder.thumbnail, viewHolder.shimmerThumbnail, file, thumbnailGenerator, overlayManager) // item layout + click listeners bindGridItemLayout(file, viewHolder) @@ -428,17 +425,6 @@ class OCFileListDelegate( } } - fun cancelAllPendingTasks() { - for (task in asyncTasks) { - task.cancel(true) - if (task.getMethod != null) { - Log_OC.d(TAG, "cancel: abort get method directly") - task.getMethod.abort() - } - } - asyncTasks.clear() - } - fun setShowShareAvatar(bool: Boolean) { showShareAvatar = bool } @@ -453,9 +439,6 @@ class OCFileListDelegate( Log_OC.e(TAG, "exception: ", e) } - // cancel async tasks from ThumbnailsCacheManager - cancelAllPendingTasks() - Log_OC.d(TAG, "background jobs cancelled") } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchCurrentDirItemViewHolder.kt b/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchCurrentDirItemViewHolder.kt index d4bc6d68114a..82b7d424dc35 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchCurrentDirItemViewHolder.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchCurrentDirItemViewHolder.kt @@ -12,6 +12,7 @@ import android.view.View import com.afollestad.sectionedrecyclerview.SectionedViewHolder import com.nextcloud.client.account.User import com.nextcloud.client.preferences.AppPreferences +import com.nextcloud.utils.thumbnail.FileThumbnailGenerator import com.owncloud.android.databinding.UnifiedSearchCurrentDirectoryItemBinding import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile @@ -31,7 +32,8 @@ class UnifiedSearchCurrentDirItemViewHolder( private val user: User, private val appPreferences: AppPreferences, private val action: UnifiedSearchCurrentDirItemAction, - private val overlayManager: OverlayManager + private val overlayManager: OverlayManager, + private val fileThumbnailGenerator: FileThumbnailGenerator ) : SectionedViewHolder(binding.unifiedSearchCurrentDirItemLayout) { fun bind(file: OCFile) { @@ -51,14 +53,9 @@ class UnifiedSearchCurrentDirItemViewHolder( DisplayUtils.setThumbnail( file, binding.thumbnail, - user, - storageManager, - listOf(), false, - context, binding.thumbnailShimmer, - appPreferences, - viewThemeUtils, + fileThumbnailGenerator, overlayManager ) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchItemViewHolder.kt b/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchItemViewHolder.kt index 97c32785c018..0186925ba260 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchItemViewHolder.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchItemViewHolder.kt @@ -24,13 +24,13 @@ import com.nextcloud.utils.ContactManager import com.nextcloud.utils.GlideHelper import com.nextcloud.utils.extensions.getType import com.nextcloud.utils.extensions.setVisibleIf +import com.nextcloud.utils.thumbnail.FileThumbnailGenerator import com.owncloud.android.R import com.owncloud.android.databinding.UnifiedSearchItemBinding import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile import com.owncloud.android.lib.common.SearchResultEntry import com.owncloud.android.ui.interfaces.UnifiedSearchListInterface -import com.owncloud.android.utils.DisplayUtils import com.owncloud.android.utils.MimeTypeUtil import com.owncloud.android.utils.overlay.OverlayManager import com.owncloud.android.utils.theme.ViewThemeUtils @@ -45,6 +45,7 @@ class UnifiedSearchItemViewHolder( val context: Context, private val viewThemeUtils: ViewThemeUtils, private val overlayManager: OverlayManager, + private val fileThumbnailGenerator: FileThumbnailGenerator, private val user: User, private val preferences: AppPreferences ) : SectionedViewHolder(binding.root) { @@ -114,18 +115,7 @@ class UnifiedSearchItemViewHolder( ImageViewCompat.setImageTintList(this, null) } } else { - DisplayUtils.setThumbnailFromCache( - file, - binding.thumbnail, - storageManager, - listOf(), - false, - binding.thumbnailShimmer, - user, - preferences, - context, - viewThemeUtils - ) + fileThumbnailGenerator.setThumbnail(file, binding.thumbnail, false, binding.thumbnailShimmer) } } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchListAdapter.kt b/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchListAdapter.kt index 6224f610a154..7cb9bed99fd5 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchListAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchListAdapter.kt @@ -32,6 +32,7 @@ import com.owncloud.android.ui.interfaces.UnifiedSearchCurrentDirItemAction import com.owncloud.android.ui.interfaces.UnifiedSearchListInterface import com.owncloud.android.ui.unifiedsearch.UnifiedSearchSection import com.owncloud.android.utils.DisplayUtils +import com.nextcloud.utils.thumbnail.FileThumbnailGenerator import com.owncloud.android.utils.overlay.OverlayManager import com.owncloud.android.utils.theme.ViewThemeUtils @@ -49,7 +50,8 @@ class UnifiedSearchListAdapter( private val viewThemeUtils: ViewThemeUtils, private val appPreferences: AppPreferences, private val currentDirItemAction: UnifiedSearchCurrentDirItemAction, - private val overlayManager: OverlayManager + private val overlayManager: OverlayManager, + private val fileThumbnailGenerator: FileThumbnailGenerator ) : SectionedRecyclerViewAdapter() { companion object { private const val VIEW_TYPE_EMPTY = Int.MAX_VALUE @@ -138,6 +140,7 @@ class UnifiedSearchListAdapter( context, viewThemeUtils, overlayManager, + fileThumbnailGenerator, user, appPreferences ) @@ -155,7 +158,8 @@ class UnifiedSearchListAdapter( user, appPreferences, currentDirItemAction, - overlayManager + overlayManager, + fileThumbnailGenerator ) } diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/ConflictsResolveDialog.kt b/app/src/main/java/com/owncloud/android/ui/dialog/ConflictsResolveDialog.kt index 055213311ea8..b3ec930a0c94 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/ConflictsResolveDialog.kt +++ b/app/src/main/java/com/owncloud/android/ui/dialog/ConflictsResolveDialog.kt @@ -21,6 +21,7 @@ import com.nextcloud.client.database.entity.OfflineOperationEntity import com.nextcloud.client.di.Injectable import com.nextcloud.utils.extensions.getParcelableArgument import com.nextcloud.utils.extensions.getSerializableArgument +import com.nextcloud.utils.thumbnail.FileThumbnailGenerator import com.owncloud.android.R import com.owncloud.android.databinding.ConflictResolveDialogBinding import com.owncloud.android.datamodel.FileDataStorageManager @@ -47,7 +48,6 @@ class ConflictsResolveDialog : private lateinit var binding: ConflictResolveDialogBinding var listener: OnConflictDecisionMadeListener? = null - private val asyncTasks: MutableList = ArrayList() private var positiveButton: MaterialButton? = null private var data: ConflictDialogData? = null @@ -67,6 +67,9 @@ class ConflictsResolveDialog : @Inject lateinit var overlayManager: OverlayManager + @Inject + lateinit var fileThumbnailGenerator: FileThumbnailGenerator + enum class Decision { CANCEL, KEEP_BOTH, @@ -231,14 +234,9 @@ class ConflictsResolveDialog : DisplayUtils.setThumbnail( rightDataFile, binding.rightThumbnail, - user, - fileDataStorageManager, - asyncTasks, false, - context, null, - syncedFolderProvider.preferences, - viewThemeUtils, + fileThumbnailGenerator, overlayManager ) } @@ -283,18 +281,6 @@ class ConflictsResolveDialog : fun conflictDecisionMade(decision: Decision?) } - override fun onStop() { - super.onStop() - - asyncTasks.forEach { - it.cancel(true) - Log_OC.d(this, "cancel: abort get method directly") - it.getMethod?.abort() - } - - asyncTasks.clear() - } - companion object { private const val ARG_CONFLICT_DATA = "CONFLICT_DATA" private const val ARG_LEFT_FILE = "LEFT_FILE" diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/GalleryFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/GalleryFragment.kt index 86d298bb69f3..6143a265a276 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/GalleryFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/GalleryFragment.kt @@ -194,7 +194,8 @@ class GalleryFragment : mContainerActivity, viewThemeUtils, this.columnsCount, - ThumbnailsCacheManager.getThumbnailDimension() + ThumbnailsCacheManager.getThumbnailDimension(), + fileThumbnailGenerator ) adapter?.setHasStableIds(true) setRecyclerViewAdapter(adapter) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java index 1ce195ff29b8..a354d7a2fa62 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -121,6 +121,7 @@ import com.owncloud.android.utils.FileStorageUtils; import com.owncloud.android.utils.MimeTypeUtil; import com.owncloud.android.utils.PermissionUtil; +import com.nextcloud.utils.thumbnail.FileThumbnailGenerator; import com.owncloud.android.utils.overlay.OverlayManager; import com.owncloud.android.utils.theme.ThemeUtils; @@ -210,6 +211,7 @@ public class OCFileListFragment extends ExtendedListFragment implements @Inject SyncedFolderProvider syncedFolderProvider; @Inject AppScanOptionalFeature appScanOptionalFeature; @Inject OverlayManager overlayManager; + @Inject FileThumbnailGenerator fileThumbnailGenerator; protected FileFragment.ContainerActivity mContainerActivity; @@ -483,7 +485,8 @@ protected void setAdapter(Bundle args) { hideItemOptions, isGridViewPreferred, viewThemeUtils, - overlayManager + overlayManager, + fileThumbnailGenerator ); setRecyclerViewAdapter(mAdapter); diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/UnifiedSearchFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/UnifiedSearchFragment.kt index 31abab9602fc..c8db71230fe6 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/UnifiedSearchFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/UnifiedSearchFragment.kt @@ -41,6 +41,7 @@ import com.nextcloud.utils.extensions.getTypedActivity import com.nextcloud.utils.extensions.searchFilesByName import com.nextcloud.utils.extensions.setVisibleIf import com.nextcloud.utils.extensions.typedActivity +import com.nextcloud.utils.thumbnail.FileThumbnailGenerator import com.owncloud.android.R import com.owncloud.android.databinding.ListFragmentBinding import com.owncloud.android.datamodel.FileDataStorageManager @@ -110,6 +111,9 @@ class UnifiedSearchFragment : @Inject lateinit var overlayManager: OverlayManager + @Inject + lateinit var fileThumbnailGenerator: FileThumbnailGenerator + @Inject lateinit var vmFactory: ViewModelFactory @@ -382,7 +386,8 @@ class UnifiedSearchFragment : viewThemeUtils, appPreferences, this@UnifiedSearchFragment, - overlayManager + overlayManager, + fileThumbnailGenerator ) adapter.shouldShowFooters(true) 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 d2565b9de06c..4e7ddfea58bd 100644 --- a/app/src/main/java/com/owncloud/android/utils/DisplayUtils.java +++ b/app/src/main/java/com/owncloud/android/utils/DisplayUtils.java @@ -28,13 +28,9 @@ import android.content.Intent; import android.content.res.Configuration; import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.Color; import android.graphics.Point; -import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; -import android.os.AsyncTask; import android.os.Handler; import android.os.Looper; import android.text.Spannable; @@ -44,29 +40,23 @@ import android.text.style.StyleSpan; import android.util.DisplayMetrics; import android.view.View; -import android.view.WindowManager; -import android.widget.FrameLayout; import android.widget.ImageView; import com.elyeproj.loaderviewlibrary.LoaderImageView; import com.google.android.material.snackbar.Snackbar; import com.nextcloud.client.account.User; -import com.nextcloud.client.preferences.AppPreferences; -import com.nextcloud.model.OfflineOperationType; +import com.nextcloud.utils.thumbnail.FileThumbnailGenerator; import com.owncloud.android.MainApp; import com.owncloud.android.R; import com.owncloud.android.datamodel.ArbitraryDataProvider; import com.owncloud.android.datamodel.ArbitraryDataProviderImpl; -import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.datamodel.ThumbnailsCacheManager; import com.owncloud.android.lib.common.OwnCloudAccount; import com.owncloud.android.lib.common.utils.Log_OC; -import com.owncloud.android.lib.resources.files.model.ServerFileInterface; import com.owncloud.android.ui.TextDrawable; import com.owncloud.android.ui.dialog.SortingOrderDialogFragment; import com.owncloud.android.utils.overlay.OverlayManager; -import com.owncloud.android.utils.theme.ViewThemeUtils; import java.io.BufferedReader; import java.io.IOException; @@ -80,9 +70,7 @@ import java.nio.charset.Charset; import java.text.DateFormat; import java.text.SimpleDateFormat; -import java.util.ArrayList; import java.util.Date; -import java.util.List; import java.util.Locale; import java.util.TimeZone; @@ -770,21 +758,16 @@ public static String getDateByPattern(long timestamp, @Nullable Context context, */ public static void setThumbnail(OCFile file, ImageView thumbnailView, - User user, - FileDataStorageManager storageManager, - List asyncTasks, boolean gridView, - Context context, LoaderImageView shimmerThumbnail, - AppPreferences preferences, - ViewThemeUtils viewThemeUtils, + FileThumbnailGenerator thumbnailGenerator, OverlayManager overlayManager) { - if (file == null || thumbnailView == null || context == null) { + if (file == null || thumbnailView == null) { return; } if (file.isOfflineOperation()) { - setThumbnailForOfflineOperation(file, thumbnailView, storageManager, context); + thumbnailGenerator.setOfflineOperationThumbnail(file, thumbnailView); return; } @@ -793,213 +776,6 @@ public static void setThumbnail(OCFile file, return; } - if (file.getRemoteId() == null || !file.isPreviewAvailable()) { - setThumbnailFirstTimeForFile(file, thumbnailView, storageManager, asyncTasks, gridView, shimmerThumbnail, user, preferences, context, viewThemeUtils); - return; - } - - setThumbnailFromCache(file, thumbnailView, storageManager, asyncTasks, gridView, shimmerThumbnail, user, preferences, context, viewThemeUtils); - } - - private static void setThumbnailFirstTimeForFile(OCFile file, ImageView thumbnailView, FileDataStorageManager storageManager, List asyncTasks, boolean gridView, LoaderImageView shimmerThumbnail, User user, AppPreferences preferences, Context context, ViewThemeUtils viewThemeUtils) { - if (file.getRemoteId() != null) { - generateNewThumbnailIfNecessary(file, thumbnailView, user, storageManager, new ArrayList<>(asyncTasks), gridView, context, shimmerThumbnail, preferences, viewThemeUtils); - return; - } - - stopShimmer(shimmerThumbnail, thumbnailView); - final var icon = MimeTypeUtil.getFileTypeIcon(file.getMimeType(), file.getFileName(), context, viewThemeUtils); - thumbnailView.setImageDrawable(icon); - } - - private static void setThumbnailForOfflineOperation(OCFile file, ImageView thumbnailView, FileDataStorageManager storageManager, Context context) { - if (file.isFolder()) { - thumbnailView.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_folder_offline)); - return; - } - - final var entity = storageManager.offlineOperationDao.getByPath(file.getDecryptedRemotePath()); - if (entity == null) { - return; - } - - if (entity.getType() instanceof OfflineOperationType.CreateFile createFileOperation) { - final var bitmap = BitmapUtils.decodeSampledBitmapFromFile(createFileOperation.getLocalPath(), 105, 105); - if (bitmap == null) { - return; - } - - final var thumbnail = BitmapUtils.addColorFilter(bitmap, Color.GRAY, 100); - thumbnailView.setImageBitmap(thumbnail); - } - } - - public static void setThumbnailFromCache(OCFile file, ImageView thumbnailView, FileDataStorageManager storageManager, List asyncTasks, boolean gridView, LoaderImageView shimmerThumbnail, User user, AppPreferences preferences, Context context, ViewThemeUtils viewThemeUtils) { - final var thumbnail = file.getSmallThumbnail(); - if (thumbnail == null || file.isUpdateThumbnailNeeded()) { - generateNewThumbnailIfNecessary(file, thumbnailView, user, storageManager, new ArrayList<>(asyncTasks), gridView, context, shimmerThumbnail, preferences, viewThemeUtils); - setThumbnailBackgroundForPNGFileIfNeeded(file, context, thumbnailView); - return; - } - - stopShimmer(shimmerThumbnail, thumbnailView); - - if (MimeTypeUtil.isVideo(file)) { - final var withOverlay = ThumbnailsCacheManager.addVideoOverlay(thumbnail, context); - thumbnailView.setImageBitmap(withOverlay); - } else { - BitmapUtils.setRoundedBitmapAccordingToListType(gridView, thumbnail, thumbnailView); - } - - setThumbnailBackgroundForPNGFileIfNeeded(file, context, thumbnailView); - } - - private static void setThumbnailBackgroundForPNGFileIfNeeded(ServerFileInterface file, Context context, ImageView thumbnailView) { - if ("image/png".equalsIgnoreCase(file.getMimeType())) { - final var color = ContextCompat.getColor(context, R.color.bg_default); - thumbnailView.setBackgroundColor(color); - } - } - - private static void generateNewThumbnailIfNecessary(OCFile file, - ImageView thumbnailView, - User user, - FileDataStorageManager storageManager, - ArrayList asyncTasks, - boolean gridView, - Context context, - LoaderImageView shimmerThumbnail, - AppPreferences preferences, - ViewThemeUtils viewThemeUtils) { - if (!ThumbnailsCacheManager.cancelPotentialThumbnailWork(file, thumbnailView)) { - return; - } - - Bitmap thumbnail = file.getSmallThumbnail(); - - if (thumbnail != null) { - // If thumbnail is already in cache, display it immediately - thumbnailView.setImageBitmap(thumbnail); - stopShimmer(shimmerThumbnail, thumbnailView); - return; - } - - for (ThumbnailsCacheManager.ThumbnailGenerationTask task : asyncTasks) { - if (file.getRemoteId() != null && task.getImageKey() != null && - file.getRemoteId().equals(task.getImageKey())) { - return; - } - } - - thumbnailView.setTag(file.getFileId()); - - try { - final ThumbnailsCacheManager.ThumbnailGenerationTask task = - new ThumbnailsCacheManager.ThumbnailGenerationTask(thumbnailView, - storageManager, - user, - asyncTasks, - gridView, - file.getRemoteId()); - Drawable drawable = MimeTypeUtil.getFileTypeIcon(file.getMimeType(), - file.getFileName(), - context, - viewThemeUtils); - if (drawable == null) { - drawable = ResourcesCompat.getDrawable(context.getResources(), - R.drawable.file_image, - null); - } - if (drawable == null) { - drawable = new ColorDrawable(Color.GRAY); - } - - int px = ThumbnailsCacheManager.getThumbnailDimension(); - thumbnail = BitmapUtils.drawableToBitmap(drawable, px, px); - final ThumbnailsCacheManager.AsyncThumbnailDrawable asyncDrawable = - new ThumbnailsCacheManager.AsyncThumbnailDrawable(context.getResources(), - thumbnail, task); - - if (shimmerThumbnail != null) { - shimmerThumbnail.postDelayed(() -> { - if (thumbnailView.getDrawable() == null) { - if (gridView) { - configShimmerGridImageSize(shimmerThumbnail, preferences.getGridColumns()); - } - startShimmer(shimmerThumbnail, thumbnailView); - } - }, 100); - } - - task.setListener(new ThumbnailsCacheManager.ThumbnailGenerationTask.Listener() { - @Override - public void onSuccess() { - stopShimmer(shimmerThumbnail, thumbnailView); - } - - @Override - public void onError() { - stopShimmer(shimmerThumbnail, thumbnailView); - final var icon = MimeTypeUtil.getFileTypeIcon(file.getMimeType(), file.getFileName(), context, viewThemeUtils); - thumbnailView.setImageDrawable(icon); - thumbnailView.invalidate(); - Log_OC.w(TAG, "setting thumbnail failed, using icon from mime type"); - } - }); - - thumbnailView.setImageDrawable(asyncDrawable); - asyncTasks.add(task); - task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, - new ThumbnailsCacheManager.ThumbnailGenerationTaskObject(file, - file.getRemoteId())); - thumbnailView.invalidate(); - } catch (Exception e) { - Log_OC.d(TAG, "ThumbnailGenerationTask : " + e.getMessage()); - } - } - - public static void startShimmer(LoaderImageView thumbnailShimmer, ImageView thumbnailView) { - thumbnailShimmer.setImageResource(R.drawable.background); - thumbnailShimmer.resetLoader(); - thumbnailView.setVisibility(View.GONE); - thumbnailShimmer.setVisibility(View.VISIBLE); - } - - public static void stopShimmer(@Nullable LoaderImageView thumbnailShimmer, ImageView thumbnailView) { - if (thumbnailShimmer != null) { - thumbnailShimmer.setVisibility(View.GONE); - } - - thumbnailView.setVisibility(View.VISIBLE); - } - - private static void configShimmerGridImageSize(LoaderImageView thumbnailShimmer, float gridColumns) { - try { - FrameLayout.LayoutParams targetLayoutParams = (FrameLayout.LayoutParams) thumbnailShimmer.getLayoutParams(); - - final Point screenSize = getScreenSize(thumbnailShimmer.getContext()); - final int marginLeftAndRight = targetLayoutParams.leftMargin + targetLayoutParams.rightMargin; - final int size = Math.round(screenSize.x / gridColumns - marginLeftAndRight); - - FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(size, size); - params.setMargins(targetLayoutParams.leftMargin, - targetLayoutParams.topMargin, - targetLayoutParams.rightMargin, - targetLayoutParams.bottomMargin); - thumbnailShimmer.setLayoutParams(params); - } catch (Exception exception) { - Log_OC.e("ConfigShimmer", exception.getMessage()); - } - } - - private static Point getScreenSize(Context context) throws Exception { - final WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); - if (windowManager != null) { - final Point displaySize = new Point(); - windowManager.getDefaultDisplay().getSize(displaySize); - return displaySize; - } else { - throw new Exception("WindowManager not found"); - } + thumbnailGenerator.setThumbnail(file, thumbnailView, gridView, shimmerThumbnail); } } diff --git a/app/src/main/java/com/owncloud/android/utils/overlay/OverlayManager.kt b/app/src/main/java/com/owncloud/android/utils/overlay/OverlayManager.kt index b26a41d17c38..b4c8e4f5d34d 100644 --- a/app/src/main/java/com/owncloud/android/utils/overlay/OverlayManager.kt +++ b/app/src/main/java/com/owncloud/android/utils/overlay/OverlayManager.kt @@ -15,10 +15,9 @@ import com.elyeproj.loaderviewlibrary.LoaderImageView import com.nextcloud.client.account.UserAccountManager import com.nextcloud.client.di.Injectable import com.nextcloud.client.preferences.AppPreferences +import com.nextcloud.utils.extensions.stopShimmer import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.SyncedFolderObserver -import com.owncloud.android.datamodel.SyncedFolderProvider -import com.owncloud.android.utils.DisplayUtils import com.owncloud.android.utils.MimeTypeUtil import com.owncloud.android.utils.theme.ViewThemeUtils import javax.inject.Inject @@ -52,7 +51,7 @@ class OverlayManager @Inject constructor( fun setFolderThumbnail(folder: OCFile?, imageView: ImageView, loaderImageView: LoaderImageView?) { if (folder == null || !folder.isFolder) return - DisplayUtils.stopShimmer(loaderImageView, imageView) + imageView.stopShimmer(loaderImageView) val isAutoUploadFolder = SyncedFolderObserver.isAutoUploadFolder(folder, accountManager.user) diff --git a/app/src/test/java/com/owncloud/android/ui/adapter/GalleryAdapterTest.kt b/app/src/test/java/com/owncloud/android/ui/adapter/GalleryAdapterTest.kt index 2b7bb193a56e..10e7f98852c1 100644 --- a/app/src/test/java/com/owncloud/android/ui/adapter/GalleryAdapterTest.kt +++ b/app/src/test/java/com/owncloud/android/ui/adapter/GalleryAdapterTest.kt @@ -12,6 +12,7 @@ import android.text.TextUtils import com.nextcloud.client.account.User import com.nextcloud.client.jobs.upload.FileUploadHelper import com.nextcloud.client.preferences.AppPreferences +import com.nextcloud.utils.thumbnail.FileThumbnailGenerator import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.GalleryItems import com.owncloud.android.datamodel.GalleryRow @@ -57,6 +58,9 @@ class GalleryAdapterTest { @Mock lateinit var viewThemeUtils: ViewThemeUtils + @Mock + lateinit var fileThumbnailGenerator: FileThumbnailGenerator + private lateinit var mocks: AutoCloseable @Before @@ -89,7 +93,8 @@ class GalleryAdapterTest { transferServiceGetter, viewThemeUtils, 5, - thumbnailSize + thumbnailSize, + fileThumbnailGenerator ) val list = listOf( @@ -121,7 +126,8 @@ class GalleryAdapterTest { transferServiceGetter, viewThemeUtils, 5, - thumbnailSize + thumbnailSize, + fileThumbnailGenerator ) val rows = mutableListOf() From 680490179cd19722742125e2fbdadec25aa2f704 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Fri, 7 Aug 2026 09:26:53 +0200 Subject: [PATCH 10/20] use display util for upload list Signed-off-by: alperozturk96 --- .../utils/thumbnail/FileThumbnailGenerator.kt | 47 +++++--- .../android/ui/activity/UploadListActivity.kt | 10 +- .../adapter/uploadList/UploadListAdapter.kt | 114 +++--------------- 3 files changed, 52 insertions(+), 119 deletions(-) diff --git a/app/src/main/java/com/nextcloud/utils/thumbnail/FileThumbnailGenerator.kt b/app/src/main/java/com/nextcloud/utils/thumbnail/FileThumbnailGenerator.kt index 438fd5c6a482..8a5e0c43b8ab 100644 --- a/app/src/main/java/com/nextcloud/utils/thumbnail/FileThumbnailGenerator.kt +++ b/app/src/main/java/com/nextcloud/utils/thumbnail/FileThumbnailGenerator.kt @@ -22,6 +22,7 @@ import com.nextcloud.client.preferences.AppPreferences import com.nextcloud.model.OfflineOperationType import com.nextcloud.utils.extensions.startShimmer import com.nextcloud.utils.extensions.stopShimmer +import com.nextcloud.utils.extensions.toFile import com.owncloud.android.R import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile @@ -68,8 +69,7 @@ class FileThumbnailGenerator @Inject constructor( fun setThumbnail(file: OCFile, view: ImageView, isGrid: Boolean, shimmer: LoaderImageView?) { if (file.remoteId == null) { - view.stopShimmer(shimmer) - view.setImageDrawable(file.mimeIcon()) + setLocalThumbnail(file, view, isGrid, shimmer) return } @@ -126,34 +126,48 @@ class FileThumbnailGenerator @Inject constructor( } } + private fun setLocalThumbnail(file: OCFile, view: ImageView, isGrid: Boolean, shimmer: LoaderImageView?) { + val localFile = file.storagePath.toFile() + + if (localFile == null || !MimeTypeUtil.isImageOrVideo(file)) { + view.stopShimmer(shimmer) + view.setImageDrawable(file.mimeIcon()) + } else if (ThumbnailsCacheManager.cancelPotentialThumbnailWork(localFile, view)) { + startTask(file, view, isGrid, shimmer, ThumbnailGenerationTaskObject(localFile, null), localFile.hashCode()) + } + } + private fun generate(file: OCFile, view: ImageView, isGrid: Boolean, shimmer: LoaderImageView?) { if (!ThumbnailsCacheManager.cancelPotentialThumbnailWork(file, view)) { return } - file.smallThumbnail?.let { cached -> + val cached = file.smallThumbnail + if (cached != null) { view.setImageBitmap(cached) view.stopShimmer(shimmer) - return + } else if (tasks.none { it.imageKey == file.remoteId }) { + startTask(file, view, isGrid, shimmer, ThumbnailGenerationTaskObject(file, file.remoteId), file.fileId) } - - startTask(file, view, isGrid, shimmer) } - @Suppress("TooGenericExceptionCaught") - private fun startTask(file: OCFile, view: ImageView, isGrid: Boolean, shimmer: LoaderImageView?) { - if (tasks.any { it.imageKey == file.remoteId }) { - return - } - - view.tag = file.fileId + @Suppress("TooGenericExceptionCaught", "LongParameterList", "DEPRECATION") + private fun startTask( + file: OCFile, + view: ImageView, + isGrid: Boolean, + shimmer: LoaderImageView?, + target: ThumbnailGenerationTaskObject, + tag: Any + ) { + view.tag = tag try { val task = newTask(file, view, isGrid, shimmer) view.setImageDrawable(AsyncThumbnailDrawable(context.resources, file.placeholder(), task)) startShimmerLater(view, isGrid, shimmer) tasks.add(task) - task.execute(file) + task.executeOnExecutor(executor, target) view.invalidate() } catch (e: Exception) { Log_OC.d(TAG, "ThumbnailGenerationTask: ${e.message}") @@ -185,11 +199,6 @@ class FileThumbnailGenerator @Inject constructor( }) } - @Suppress("DEPRECATION") - private fun ThumbnailGenerationTask.execute(file: OCFile) { - executeOnExecutor(executor, ThumbnailGenerationTaskObject(file, file.remoteId)) - } - private fun startShimmerLater(view: ImageView, isGrid: Boolean, shimmer: LoaderImageView?) { shimmer?.postDelayed({ if (view.drawable != null) { diff --git a/app/src/main/java/com/owncloud/android/ui/activity/UploadListActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/UploadListActivity.kt index 81bb9e11f0cb..e081341d71cd 100755 --- a/app/src/main/java/com/owncloud/android/ui/activity/UploadListActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/UploadListActivity.kt @@ -41,6 +41,7 @@ import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.lib.resources.files.ExistenceCheckRemoteOperation import com.owncloud.android.operations.CheckCurrentCredentialsOperation +import com.nextcloud.utils.thumbnail.FileThumbnailGenerator import com.owncloud.android.operations.factory.UploadFileOperationFactory import com.owncloud.android.ui.adapter.uploadList.UploadListAdapter import com.owncloud.android.ui.adapter.uploadList.helper.ConflictHandlingResult @@ -50,6 +51,7 @@ import com.owncloud.android.ui.adapter.uploadList.helper.UploadListAdapterHelper import com.owncloud.android.ui.adapter.uploadList.helper.UploadListItemOnClick import com.owncloud.android.ui.decoration.MediaGridItemDecoration import com.owncloud.android.utils.FilesSyncHelper +import com.owncloud.android.utils.overlay.OverlayManager import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -73,6 +75,10 @@ class UploadListActivity : @Inject lateinit var uploadFileOperationFactory: UploadFileOperationFactory + @Inject lateinit var fileThumbnailGenerator: FileThumbnailGenerator + + @Inject lateinit var overlayManager: OverlayManager + private var uploadWarningCard: UploadWarningCard? = null private var swipeListRefreshLayout: SwipeRefreshLayout? = null @@ -119,7 +125,9 @@ class UploadListActivity : powerManagementService, viewThemeUtils, this, - adapterHelper + adapterHelper, + fileThumbnailGenerator, + overlayManager ) binding?.autoUploadBatterySaverWarningCard?.let { diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/uploadList/UploadListAdapter.kt b/app/src/main/java/com/owncloud/android/ui/adapter/uploadList/UploadListAdapter.kt index e5ac80d9bcb0..457912853215 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/uploadList/UploadListAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/uploadList/UploadListAdapter.kt @@ -15,7 +15,6 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.PopupMenu -import androidx.core.content.ContextCompat import androidx.lifecycle.lifecycleScope import com.afollestad.sectionedrecyclerview.SectionedRecyclerViewAdapter import com.afollestad.sectionedrecyclerview.SectionedViewHolder @@ -25,18 +24,17 @@ import com.nextcloud.client.device.PowerManagementService import com.nextcloud.client.jobs.upload.FileUploadHelper import com.nextcloud.client.jobs.upload.FileUploadWorker import com.nextcloud.client.network.ConnectivityService -import com.nextcloud.utils.extensions.getSmallThumbnail import com.nextcloud.utils.extensions.getStatusText import com.nextcloud.utils.extensions.isLastResultConflictError import com.nextcloud.utils.extensions.setVisibleIf import com.nextcloud.utils.extensions.sortedByUploadOrder import com.nextcloud.utils.extensions.toFile +import com.nextcloud.utils.thumbnail.FileThumbnailGenerator import com.owncloud.android.R import com.owncloud.android.databinding.UploadListHeaderBinding import com.owncloud.android.databinding.UploadListItemBinding import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile -import com.owncloud.android.datamodel.ThumbnailsCacheManager import com.owncloud.android.datamodel.UploadsStorageManager import com.owncloud.android.db.OCUpload import com.owncloud.android.db.UploadResult @@ -48,7 +46,7 @@ import com.owncloud.android.ui.adapter.uploadList.helper.UploadListItemOnClick import com.owncloud.android.ui.adapter.uploadList.model.UploadListSection import com.owncloud.android.ui.adapter.uploadList.model.UploadListType import com.owncloud.android.utils.DisplayUtils -import com.owncloud.android.utils.MimeTypeUtil +import com.owncloud.android.utils.overlay.OverlayManager import com.owncloud.android.utils.theme.ViewThemeUtils import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -75,7 +73,9 @@ class UploadListAdapter( private val powerManagementService: PowerManagementService, private val viewThemeUtils: ViewThemeUtils, private val itemOnClick: UploadListItemOnClick, - private val helper: UploadListAdapterHelper + private val helper: UploadListAdapterHelper, + private val fileThumbnailGenerator: FileThumbnailGenerator, + private val overlayManager: OverlayManager ) : SectionedRecyclerViewAdapter() { private val uploadListSections = UploadListSection.sections() @@ -500,7 +500,7 @@ class UploadListAdapter( return@launch } - bindItemThumbnail(holder, item, ocFile) + bindItemThumbnail(holder, ocFile) } } @@ -510,107 +510,23 @@ class UploadListAdapter( mimeType = this@toOCFile.mimeType } - private fun bindItemThumbnail(holder: ItemViewHolder, item: OCUpload, ocFile: OCFile) { + private fun bindItemThumbnail(holder: ItemViewHolder, ocFile: OCFile) { holder.binding.thumbnail.tag = ocFile.fileId - val allowedToCreateNewThumbnail = - ThumbnailsCacheManager.cancelPotentialThumbnailWork(ocFile, holder.binding.thumbnail) - - val optionalUser = accountManager.getUser(item.accountName) - val fileName = File(item.remotePath).name.takeIf { it.isNotEmpty() } ?: File.separator - - when { - MimeTypeUtil.isImageOrVideo(ocFile) && ocFile.remoteId != null && - item.uploadStatus == UploadsStorageManager.UploadStatus.UPLOAD_SUCCEEDED -> - bindRemoteThumbnail(holder, item, ocFile, allowedToCreateNewThumbnail) - - MimeTypeUtil.isImageOrVideo(ocFile) -> - bindLocalThumbnail(holder, item, allowedToCreateNewThumbnail) - - optionalUser.isPresent -> { - val icon = MimeTypeUtil.getFileTypeIcon(item.mimeType, fileName, activity, viewThemeUtils) - holder.binding.thumbnail.setImageDrawable(icon) - } - } - } - - private fun bindRemoteThumbnail( - holder: ItemViewHolder, - item: OCUpload, - file: OCFile, - allowedToCreateNewThumbnail: Boolean - ) { - var thumbnail = file.smallThumbnail - - if (thumbnail != null && !file.isUpdateThumbnailNeeded) { - holder.binding.thumbnail.setImageBitmap(thumbnail) - } else if (allowedToCreateNewThumbnail) { - val user = activity.user - if (user.isPresent) { - val task = ThumbnailsCacheManager.ThumbnailGenerationTask( - holder.binding.thumbnail, - activity.storageManager, - user.get() - ) - thumbnail = thumbnail ?: if (MimeTypeUtil.isVideo(file)) { - ThumbnailsCacheManager.mDefaultVideo - } else { - ThumbnailsCacheManager.mDefaultImg - } - holder.binding.thumbnail.setImageDrawable( - ThumbnailsCacheManager.AsyncThumbnailDrawable(activity.resources, thumbnail, task) - ) - task.execute(ThumbnailsCacheManager.ThumbnailGenerationTaskObject(file, null)) - } - } - - if (item.mimeType == "image/png") { - holder.binding.thumbnail.setBackgroundColor(ContextCompat.getColor(activity, R.color.bg_default)) - } + DisplayUtils.setThumbnail( + ocFile, + holder.binding.thumbnail, + false, + null, + fileThumbnailGenerator, + overlayManager + ) } - private fun bindLocalThumbnail(holder: ItemViewHolder, item: OCUpload, allowedToCreateNewThumbnail: Boolean) { - val file = File(item.localPath) - val thumbnail = file.getSmallThumbnail() - - if (thumbnail != null) { - holder.binding.thumbnail.setImageBitmap(thumbnail) - } else if (allowedToCreateNewThumbnail) { - getThumbnailFromFileTypeAndSetIcon(item.localPath, holder) - val task = ThumbnailsCacheManager.ThumbnailGenerationTask(holder.binding.thumbnail) - val defaultThumbnail = if (MimeTypeUtil.isVideo(file)) { - ThumbnailsCacheManager.mDefaultVideo - } else { - ThumbnailsCacheManager.mDefaultImg - } - val asyncDrawable = - ThumbnailsCacheManager.AsyncThumbnailDrawable(activity.resources, defaultThumbnail, task) - task.execute(ThumbnailsCacheManager.ThumbnailGenerationTaskObject(file, null)) - task.setListener(object : ThumbnailsCacheManager.ThumbnailGenerationTask.Listener { - override fun onSuccess() { - holder.binding.thumbnail.setImageDrawable(asyncDrawable) - } - - override fun onError() { - getThumbnailFromFileTypeAndSetIcon(item.localPath, holder) - } - }) - Log_OC.v(TAG, "Executing task to generate a new thumbnail") - } - - if (item.mimeType.equals("image/png", ignoreCase = true)) { - holder.binding.thumbnail.setBackgroundColor(ContextCompat.getColor(activity, R.color.bg_default)) - } - } // endregion override fun onBindFooterViewHolder(holder: SectionedViewHolder?, section: Int) = Unit - private fun getThumbnailFromFileTypeAndSetIcon(localPath: String?, itemViewHolder: ItemViewHolder) { - val drawable = MimeTypeUtil.getIcon(localPath, activity, viewThemeUtils) ?: return - itemViewHolder.binding.thumbnail.setImageDrawable(drawable) - } - private fun showItemConflictPopup(item: OCUpload, view: View) { PopupMenu(activity, view).apply { inflate(R.menu.upload_list_item_file_conflict) From 1f90ad4cdc54cb1ebec552bcfc9bd687b5dc1aab Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Fri, 7 Aug 2026 09:30:52 +0200 Subject: [PATCH 11/20] fix thumbnail in media tab Signed-off-by: alperozturk96 --- .../client/jobs/gallery/GalleryImageGenerationJob.kt | 8 ++++++-- .../com/owncloud/android/ui/adapter/OCFileListDelegate.kt | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/gallery/GalleryImageGenerationJob.kt b/app/src/main/java/com/nextcloud/client/jobs/gallery/GalleryImageGenerationJob.kt index 9eb0b5e2a163..319424cd42f1 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/gallery/GalleryImageGenerationJob.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/gallery/GalleryImageGenerationJob.kt @@ -117,21 +117,25 @@ class GalleryImageGenerationJob(private val user: User, private val storageManag return@withContext applyVideoOverlayIfNeeded(file, cached) } - onNewThumbnail() - if (file.isDown) { val local = decodeLocalThumbnail(file) if (local != null) { ThumbnailsCacheManager.addBitmapToCache(file.getBigThumbnailKey(), local) + onNewThumbnail() return@withContext applyVideoOverlayIfNeeded(file, local) } } val remote = semaphore.withPermit { fetchFromServer(file) } if (remote != null) { + onNewThumbnail() return@withContext applyVideoOverlayIfNeeded(file, remote) } + file.smallThumbnail?.let { small -> + return@withContext applyVideoOverlayIfNeeded(file, small) + } + null } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt index e875ea5ffcc9..62f5ff0b1791 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt @@ -114,7 +114,7 @@ class OCFileListDelegate( imageView.tag = file.fileId // set placeholder before async job - val cachedBitmap = file.getBigThumbnail() + val cachedBitmap = file.bigThumbnail ?: file.smallThumbnail if (cachedBitmap != null) { val overlay = if (MimeTypeUtil.isVideo(file)) { ThumbnailsCacheManager.addVideoOverlay(cachedBitmap, context) From 584070bd8e7fea89ad8d582a89a2ad7ba7dea4ce Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Fri, 7 Aug 2026 09:33:25 +0200 Subject: [PATCH 12/20] clean imports Signed-off-by: alperozturk96 --- .../com/nextcloud/ui/fileactions/FileActionsBottomSheet.kt | 1 - .../java/com/owncloud/android/ui/adapter/GalleryAdapter.kt | 1 - .../com/owncloud/android/ui/adapter/OCFileListAdapter.java | 1 - .../com/owncloud/android/ui/adapter/OCFileListDelegate.kt | 2 -- .../ui/adapter/UnifiedSearchCurrentDirItemViewHolder.kt | 6 ------ .../owncloud/android/ui/adapter/UnifiedSearchListAdapter.kt | 5 +---- 6 files changed, 1 insertion(+), 15 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 8571d40bc9cd..3fe2bfb43bcf 100644 --- a/app/src/main/java/com/nextcloud/ui/fileactions/FileActionsBottomSheet.kt +++ b/app/src/main/java/com/nextcloud/ui/fileactions/FileActionsBottomSheet.kt @@ -42,7 +42,6 @@ import com.owncloud.android.databinding.FileActionsBottomSheetItemBinding import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.SyncedFolderProvider -import com.owncloud.android.datamodel.ThumbnailsCacheManager import com.owncloud.android.lib.resources.files.model.FileLockType import com.owncloud.android.ui.activity.ComponentsGetter import com.owncloud.android.utils.DisplayUtils diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt b/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt index a07c8654fdd0..f1836f69e299 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt @@ -85,7 +85,6 @@ class GalleryAdapter( user, storageManager, false, - preferences, true, transferServiceGetter, showMetadata = false, 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 b838e2fb06ae..c92245af834c 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 @@ -184,7 +184,6 @@ public OCFileListAdapter( user, mStorageManager, hideItemOptions, - preferences, gridView, transferServiceGetter, true, diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt index 62f5ff0b1791..8eda3e926e47 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt @@ -18,7 +18,6 @@ import com.nextcloud.client.jobs.download.FileDownloadHelper import com.nextcloud.client.jobs.gallery.GalleryImageGenerationJob import com.nextcloud.client.jobs.gallery.GalleryImageGenerationListener import com.nextcloud.client.jobs.upload.FileUploadHelper -import com.nextcloud.client.preferences.AppPreferences import com.nextcloud.utils.OCFileUtils import com.nextcloud.utils.extensions.makeRounded import com.nextcloud.utils.extensions.setVisibleIf @@ -55,7 +54,6 @@ class OCFileListDelegate( private val user: User, private val storageManager: FileDataStorageManager, private val hideItemOptions: Boolean, - private val preferences: AppPreferences, private val gridView: Boolean, private val transferServiceGetter: ComponentsGetter, private val showMetadata: Boolean, diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchCurrentDirItemViewHolder.kt b/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchCurrentDirItemViewHolder.kt index 82b7d424dc35..409339654962 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchCurrentDirItemViewHolder.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchCurrentDirItemViewHolder.kt @@ -10,8 +10,6 @@ package com.owncloud.android.ui.adapter import android.content.Context import android.view.View import com.afollestad.sectionedrecyclerview.SectionedViewHolder -import com.nextcloud.client.account.User -import com.nextcloud.client.preferences.AppPreferences import com.nextcloud.utils.thumbnail.FileThumbnailGenerator import com.owncloud.android.databinding.UnifiedSearchCurrentDirectoryItemBinding import com.owncloud.android.datamodel.FileDataStorageManager @@ -20,17 +18,13 @@ import com.owncloud.android.ui.interfaces.UnifiedSearchCurrentDirItemAction import com.owncloud.android.utils.DisplayUtils import com.owncloud.android.utils.FileStorageUtils import com.owncloud.android.utils.overlay.OverlayManager -import com.owncloud.android.utils.theme.ViewThemeUtils @Suppress("LongParameterList") class UnifiedSearchCurrentDirItemViewHolder( val binding: UnifiedSearchCurrentDirectoryItemBinding, val context: Context, - private val viewThemeUtils: ViewThemeUtils, private val storageManager: FileDataStorageManager, private val isRTL: Boolean, - private val user: User, - private val appPreferences: AppPreferences, private val action: UnifiedSearchCurrentDirItemAction, private val overlayManager: OverlayManager, private val fileThumbnailGenerator: FileThumbnailGenerator diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchListAdapter.kt b/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchListAdapter.kt index 7cb9bed99fd5..ecfd0e2f00e0 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchListAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchListAdapter.kt @@ -19,6 +19,7 @@ import com.afollestad.sectionedrecyclerview.SectionedViewHolder import com.bumptech.glide.Glide import com.nextcloud.client.account.User import com.nextcloud.client.preferences.AppPreferences +import com.nextcloud.utils.thumbnail.FileThumbnailGenerator import com.owncloud.android.R import com.owncloud.android.databinding.UnifiedSearchCurrentDirectoryItemBinding import com.owncloud.android.databinding.UnifiedSearchEmptyBinding @@ -32,7 +33,6 @@ import com.owncloud.android.ui.interfaces.UnifiedSearchCurrentDirItemAction import com.owncloud.android.ui.interfaces.UnifiedSearchListInterface import com.owncloud.android.ui.unifiedsearch.UnifiedSearchSection import com.owncloud.android.utils.DisplayUtils -import com.nextcloud.utils.thumbnail.FileThumbnailGenerator import com.owncloud.android.utils.overlay.OverlayManager import com.owncloud.android.utils.theme.ViewThemeUtils @@ -152,11 +152,8 @@ class UnifiedSearchListAdapter( UnifiedSearchCurrentDirItemViewHolder( binding, context, - viewThemeUtils, storageManager, isRTL, - user, - appPreferences, currentDirItemAction, overlayManager, fileThumbnailGenerator From 8a6cd4f3c95deebbf14d7b1ae74accf8cc1fa7a9 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Fri, 7 Aug 2026 09:39:17 +0200 Subject: [PATCH 13/20] rename overlay manager to folder thumbnail generator Signed-off-by: alperozturk96 --- .../android/ui/adapter/UnifiedSearchListAdapterIT.kt | 8 ++++---- .../main/java/com/nextcloud/client/di/AppModule.java | 6 +++--- .../nextcloud/ui/fileactions/FileActionsBottomSheet.kt | 6 +++--- .../TrashbinFileActionsBottomSheet.kt | 6 +++--- .../utils/thumbnail/FolderThumbnailGenerator.kt} | 6 +++--- .../com/owncloud/android/ui/activity/ShareActivity.kt | 6 +++--- .../owncloud/android/ui/activity/UploadListActivity.kt | 6 +++--- .../owncloud/android/ui/adapter/OCFileListAdapter.java | 10 +++++----- .../owncloud/android/ui/adapter/OCFileListDelegate.kt | 10 +++++----- .../adapter/UnifiedSearchCurrentDirItemViewHolder.kt | 6 +++--- .../android/ui/adapter/UnifiedSearchItemViewHolder.kt | 6 +++--- .../android/ui/adapter/UnifiedSearchListAdapter.kt | 8 ++++---- .../android/ui/adapter/uploadList/UploadListAdapter.kt | 6 +++--- .../android/ui/dialog/ConflictsResolveDialog.kt | 6 +++--- .../android/ui/fragment/OCFileListFragment.java | 6 +++--- .../android/ui/fragment/UnifiedSearchFragment.kt | 6 +++--- .../java/com/owncloud/android/utils/DisplayUtils.java | 6 +++--- 17 files changed, 57 insertions(+), 57 deletions(-) rename app/src/main/java/com/{owncloud/android/utils/overlay/OverlayManager.kt => nextcloud/utils/thumbnail/FolderThumbnailGenerator.kt} (96%) diff --git a/app/src/androidTest/java/com/owncloud/android/ui/adapter/UnifiedSearchListAdapterIT.kt b/app/src/androidTest/java/com/owncloud/android/ui/adapter/UnifiedSearchListAdapterIT.kt index f3fff0c9742a..264d7c62e728 100644 --- a/app/src/androidTest/java/com/owncloud/android/ui/adapter/UnifiedSearchListAdapterIT.kt +++ b/app/src/androidTest/java/com/owncloud/android/ui/adapter/UnifiedSearchListAdapterIT.kt @@ -23,7 +23,7 @@ import com.owncloud.android.ui.unifiedsearch.ProviderID import com.owncloud.android.ui.unifiedsearch.UnifiedSearchSection import com.owncloud.android.utils.MimeType import com.owncloud.android.utils.ScreenshotTest -import com.owncloud.android.utils.overlay.OverlayManager +import com.nextcloud.utils.thumbnail.FolderThumbnailGenerator import org.junit.Before import org.junit.Test @@ -32,7 +32,7 @@ class UnifiedSearchListAdapterIT : AbstractIT() { private val testClassName = "com.owncloud.android.ui.adapter.UnifiedSearchListAdapterIT" - private lateinit var overlayManager: OverlayManager + private lateinit var folderThumbnailGenerator: FolderThumbnailGenerator private lateinit var preferences: AppPreferences @Suppress("DEPRECATION") @@ -134,7 +134,7 @@ class UnifiedSearchListAdapterIT : AbstractIT() { ): UnifiedSearchListAdapter { val accountManager = UserAccountManagerImpl.fromContext(targetContext) - overlayManager = OverlayManager( + folderThumbnailGenerator = FolderThumbnailGenerator( preferences = preferences, viewThemeUtils = sut.viewThemeUtils, context = targetContext, @@ -157,7 +157,7 @@ class UnifiedSearchListAdapterIT : AbstractIT() { viewThemeUtils = sut.viewThemeUtils, appPreferences = preferences, currentDirItemAction = noopCurrentDirAction, - overlayManager = overlayManager + folderThumbnailGenerator = folderThumbnailGenerator ) adapter.shouldShowFooters(true) diff --git a/app/src/main/java/com/nextcloud/client/di/AppModule.java b/app/src/main/java/com/nextcloud/client/di/AppModule.java index eca8f4668618..481ef6719d28 100644 --- a/app/src/main/java/com/nextcloud/client/di/AppModule.java +++ b/app/src/main/java/com/nextcloud/client/di/AppModule.java @@ -57,7 +57,7 @@ import com.owncloud.android.ui.activities.data.files.FilesServiceApiImpl; import com.owncloud.android.ui.activities.data.files.RemoteFilesRepository; import com.owncloud.android.ui.dialog.setupEncryption.CertificateValidator; -import com.owncloud.android.utils.overlay.OverlayManager; +import com.nextcloud.utils.thumbnail.FolderThumbnailGenerator; import com.owncloud.android.utils.theme.ViewThemeUtils; import org.greenrobot.eventbus.EventBus; @@ -272,12 +272,12 @@ CertificateValidator certificateValidator() { @Provides @Singleton - OverlayManager overlayManager( + FolderThumbnailGenerator folderThumbnailGenerator( AppPreferences appPreferences, ViewThemeUtils viewThemeUtils, Context context, UserAccountManager accountManager) { - return new OverlayManager(appPreferences, viewThemeUtils, context, accountManager); + return new FolderThumbnailGenerator(appPreferences, viewThemeUtils, context, accountManager); } } 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 3fe2bfb43bcf..b9bcc3d47b32 100644 --- a/app/src/main/java/com/nextcloud/ui/fileactions/FileActionsBottomSheet.kt +++ b/app/src/main/java/com/nextcloud/ui/fileactions/FileActionsBottomSheet.kt @@ -47,7 +47,7 @@ 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.overlay.OverlayManager +import com.nextcloud.utils.thumbnail.FolderThumbnailGenerator import com.owncloud.android.utils.theme.ViewThemeUtils import javax.inject.Inject @@ -71,7 +71,7 @@ class FileActionsBottomSheet : lateinit var syncedFolderProvider: SyncedFolderProvider @Inject - lateinit var overlayManager: OverlayManager + lateinit var folderThumbnailGenerator: FolderThumbnailGenerator @Inject lateinit var fileThumbnailGenerator: FileThumbnailGenerator @@ -156,7 +156,7 @@ class FileActionsBottomSheet : false, binding.thumbnailLayout.thumbnailShimmer, fileThumbnailGenerator, - overlayManager + folderThumbnailGenerator ) } } diff --git a/app/src/main/java/com/nextcloud/ui/trashbinFileActions/TrashbinFileActionsBottomSheet.kt b/app/src/main/java/com/nextcloud/ui/trashbinFileActions/TrashbinFileActionsBottomSheet.kt index 7f20ca201d8b..08b6bc994c08 100644 --- a/app/src/main/java/com/nextcloud/ui/trashbinFileActions/TrashbinFileActionsBottomSheet.kt +++ b/app/src/main/java/com/nextcloud/ui/trashbinFileActions/TrashbinFileActionsBottomSheet.kt @@ -35,7 +35,7 @@ import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.SyncedFolderProvider import com.owncloud.android.lib.resources.trashbin.model.TrashbinFile import com.owncloud.android.utils.DisplayUtils -import com.owncloud.android.utils.overlay.OverlayManager +import com.nextcloud.utils.thumbnail.FolderThumbnailGenerator import com.owncloud.android.utils.theme.ViewThemeUtils import javax.inject.Inject @@ -59,7 +59,7 @@ class TrashbinFileActionsBottomSheet : lateinit var syncedFolderProvider: SyncedFolderProvider @Inject - lateinit var overlayManager: OverlayManager + lateinit var folderThumbnailGenerator: FolderThumbnailGenerator @Inject lateinit var fileThumbnailGenerator: FileThumbnailGenerator @@ -129,7 +129,7 @@ class TrashbinFileActionsBottomSheet : false, binding.thumbnailLayout.thumbnailShimmer, fileThumbnailGenerator, - overlayManager + folderThumbnailGenerator ) } } diff --git a/app/src/main/java/com/owncloud/android/utils/overlay/OverlayManager.kt b/app/src/main/java/com/nextcloud/utils/thumbnail/FolderThumbnailGenerator.kt similarity index 96% rename from app/src/main/java/com/owncloud/android/utils/overlay/OverlayManager.kt rename to app/src/main/java/com/nextcloud/utils/thumbnail/FolderThumbnailGenerator.kt index b4c8e4f5d34d..93589d905ed7 100644 --- a/app/src/main/java/com/owncloud/android/utils/overlay/OverlayManager.kt +++ b/app/src/main/java/com/nextcloud/utils/thumbnail/FolderThumbnailGenerator.kt @@ -5,7 +5,7 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ -package com.owncloud.android.utils.overlay +package com.nextcloud.utils.thumbnail import android.content.Context import android.view.View @@ -22,7 +22,7 @@ import com.owncloud.android.utils.MimeTypeUtil import com.owncloud.android.utils.theme.ViewThemeUtils import javax.inject.Inject -class OverlayManager @Inject constructor( +class FolderThumbnailGenerator @Inject constructor( private val preferences: AppPreferences, private val viewThemeUtils: ViewThemeUtils, private val context: Context, @@ -61,4 +61,4 @@ class OverlayManager @Inject constructor( val icon = MimeTypeUtil.getFolderIcon(isDarkModeActive, overlayIconId, context, viewThemeUtils) imageView.setImageDrawable(icon) } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ShareActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/ShareActivity.kt index fbbc8f4e2430..fe414c423944 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ShareActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/ShareActivity.kt @@ -35,7 +35,7 @@ import com.owncloud.android.ui.fragment.FileDetailSharingFragment import com.owncloud.android.ui.fragment.FileDetailsSharingProcessFragment import com.owncloud.android.utils.DisplayUtils import com.owncloud.android.utils.MimeTypeUtil -import com.owncloud.android.utils.overlay.OverlayManager +import com.nextcloud.utils.thumbnail.FolderThumbnailGenerator import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -49,7 +49,7 @@ class ShareActivity : lateinit var syncedFolderProvider: SyncedFolderProvider @Inject - lateinit var overlayManager: OverlayManager + lateinit var folderThumbnailGenerator: FolderThumbnailGenerator @Inject lateinit var fileThumbnailGenerator: FileThumbnailGenerator @@ -149,7 +149,7 @@ class ShareActivity : false, null, fileThumbnailGenerator, - overlayManager + folderThumbnailGenerator ) } } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/UploadListActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/UploadListActivity.kt index e081341d71cd..e45ac6a46cab 100755 --- a/app/src/main/java/com/owncloud/android/ui/activity/UploadListActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/UploadListActivity.kt @@ -51,7 +51,7 @@ import com.owncloud.android.ui.adapter.uploadList.helper.UploadListAdapterHelper import com.owncloud.android.ui.adapter.uploadList.helper.UploadListItemOnClick import com.owncloud.android.ui.decoration.MediaGridItemDecoration import com.owncloud.android.utils.FilesSyncHelper -import com.owncloud.android.utils.overlay.OverlayManager +import com.nextcloud.utils.thumbnail.FolderThumbnailGenerator import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -77,7 +77,7 @@ class UploadListActivity : @Inject lateinit var fileThumbnailGenerator: FileThumbnailGenerator - @Inject lateinit var overlayManager: OverlayManager + @Inject lateinit var folderThumbnailGenerator: FolderThumbnailGenerator private var uploadWarningCard: UploadWarningCard? = null @@ -127,7 +127,7 @@ class UploadListActivity : this, adapterHelper, fileThumbnailGenerator, - overlayManager + folderThumbnailGenerator ) binding?.autoUploadBatterySaverWarningCard?.let { 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 c92245af834c..318b7ce5001c 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 @@ -69,7 +69,7 @@ import com.owncloud.android.utils.FileSortOrder; import com.owncloud.android.utils.FileStorageUtils; import com.owncloud.android.utils.MimeTypeUtil; -import com.owncloud.android.utils.overlay.OverlayManager; +import com.nextcloud.utils.thumbnail.FolderThumbnailGenerator; import com.owncloud.android.utils.theme.CapabilityUtils; import com.owncloud.android.utils.theme.ViewThemeUtils; @@ -137,7 +137,7 @@ public class OCFileListAdapter extends RecyclerView.Adapter recommendedFiles = new ArrayList<>(); private RecommendedFilesAdapter recommendedFilesAdapter; private final OCFileListAdapterHelper helper = new OCFileListAdapterHelper(); - private final OverlayManager overlayManager; + private final FolderThumbnailGenerator folderThumbnailGenerator; private final FileThumbnailGenerator fileThumbnailGenerator; public OCFileListAdapter( @@ -150,9 +150,9 @@ public OCFileListAdapter( boolean argHideItemOptions, boolean gridView, final ViewThemeUtils viewThemeUtils, - OverlayManager overlayManager, + FolderThumbnailGenerator folderThumbnailGenerator, FileThumbnailGenerator fileThumbnailGenerator) { - this.overlayManager = overlayManager; + this.folderThumbnailGenerator = folderThumbnailGenerator; this.fileThumbnailGenerator = fileThumbnailGenerator; this.ocFileListFragmentInterface = ocFileListFragmentInterface; this.activity = activity; @@ -498,7 +498,7 @@ public void bindRecommendedFilesHolder(OCFileListRecommendedItemViewHolder holde } private void bindHolder(@NonNull RecyclerView.ViewHolder holder, ListViewHolder viewHolder, OCFile file) { - ocFileListDelegate.bindViewHolder(viewHolder, file, currentDirectory, searchType, fileThumbnailGenerator, overlayManager); + ocFileListDelegate.bindViewHolder(viewHolder, file, currentDirectory, searchType, fileThumbnailGenerator, folderThumbnailGenerator); if (holder instanceof ListItemViewHolder itemViewHolder) { bindListItemViewHolder(itemViewHolder, file); diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt index 8eda3e926e47..c1ba4c3cf92b 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt @@ -37,7 +37,7 @@ import com.owncloud.android.ui.interfaces.OCFileListFragmentInterface import com.owncloud.android.utils.DisplayUtils import com.owncloud.android.utils.EncryptionUtils import com.owncloud.android.utils.MimeTypeUtil -import com.owncloud.android.utils.overlay.OverlayManager +import com.nextcloud.utils.thumbnail.FolderThumbnailGenerator import com.owncloud.android.utils.theme.ViewThemeUtils import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -182,7 +182,7 @@ class OCFileListDelegate( shimmerThumbnail: LoaderImageView?, file: OCFile, thumbnailGenerator: FileThumbnailGenerator, - overlayManager: OverlayManager + folderThumbnailGenerator: FolderThumbnailGenerator ) { DisplayUtils.setThumbnail( file, @@ -190,7 +190,7 @@ class OCFileListDelegate( gridView, shimmerThumbnail, thumbnailGenerator, - overlayManager + folderThumbnailGenerator ) } @@ -201,7 +201,7 @@ class OCFileListDelegate( currentDirectory: OCFile?, searchType: SearchType?, thumbnailGenerator: FileThumbnailGenerator, - overlayManager: OverlayManager + folderThumbnailGenerator: FolderThumbnailGenerator ) { // thumbnail viewHolder.imageFileName?.text = file.fileName @@ -216,7 +216,7 @@ class OCFileListDelegate( viewHolder.thumbnail.setPadding(padding, padding, padding, padding) } } - setThumbnail(viewHolder.thumbnail, viewHolder.shimmerThumbnail, file, thumbnailGenerator, overlayManager) + setThumbnail(viewHolder.thumbnail, viewHolder.shimmerThumbnail, file, thumbnailGenerator, folderThumbnailGenerator) // item layout + click listeners bindGridItemLayout(file, viewHolder) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchCurrentDirItemViewHolder.kt b/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchCurrentDirItemViewHolder.kt index 409339654962..8d94b0942e1a 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchCurrentDirItemViewHolder.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchCurrentDirItemViewHolder.kt @@ -17,7 +17,7 @@ import com.owncloud.android.datamodel.OCFile import com.owncloud.android.ui.interfaces.UnifiedSearchCurrentDirItemAction import com.owncloud.android.utils.DisplayUtils import com.owncloud.android.utils.FileStorageUtils -import com.owncloud.android.utils.overlay.OverlayManager +import com.nextcloud.utils.thumbnail.FolderThumbnailGenerator @Suppress("LongParameterList") class UnifiedSearchCurrentDirItemViewHolder( @@ -26,7 +26,7 @@ class UnifiedSearchCurrentDirItemViewHolder( private val storageManager: FileDataStorageManager, private val isRTL: Boolean, private val action: UnifiedSearchCurrentDirItemAction, - private val overlayManager: OverlayManager, + private val folderThumbnailGenerator: FolderThumbnailGenerator, private val fileThumbnailGenerator: FileThumbnailGenerator ) : SectionedViewHolder(binding.unifiedSearchCurrentDirItemLayout) { @@ -50,7 +50,7 @@ class UnifiedSearchCurrentDirItemViewHolder( false, binding.thumbnailShimmer, fileThumbnailGenerator, - overlayManager + folderThumbnailGenerator ) binding.more.setOnClickListener { diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchItemViewHolder.kt b/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchItemViewHolder.kt index 0186925ba260..c723a5ab16fb 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchItemViewHolder.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchItemViewHolder.kt @@ -32,7 +32,7 @@ import com.owncloud.android.datamodel.OCFile import com.owncloud.android.lib.common.SearchResultEntry import com.owncloud.android.ui.interfaces.UnifiedSearchListInterface import com.owncloud.android.utils.MimeTypeUtil -import com.owncloud.android.utils.overlay.OverlayManager +import com.nextcloud.utils.thumbnail.FolderThumbnailGenerator import com.owncloud.android.utils.theme.ViewThemeUtils @Suppress("LongParameterList") @@ -44,7 +44,7 @@ class UnifiedSearchItemViewHolder( private val filesAction: FilesAction, val context: Context, private val viewThemeUtils: ViewThemeUtils, - private val overlayManager: OverlayManager, + private val folderThumbnailGenerator: FolderThumbnailGenerator, private val fileThumbnailGenerator: FileThumbnailGenerator, private val user: User, private val preferences: AppPreferences @@ -103,7 +103,7 @@ class UnifiedSearchItemViewHolder( setImageDrawable(ContextCompat.getDrawable(context, R.drawable.folder)) viewThemeUtils.platform.colorImageView(this, ColorRole.PRIMARY) } - overlayManager.setFolderOverlayIcon(file, binding.thumbnailOverlayIcon) + folderThumbnailGenerator.setFolderOverlayIcon(file, binding.thumbnailOverlayIcon) } private fun bindLocalFileThumbnail(file: OCFile) { diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchListAdapter.kt b/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchListAdapter.kt index ecfd0e2f00e0..60403160371d 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchListAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchListAdapter.kt @@ -33,7 +33,7 @@ import com.owncloud.android.ui.interfaces.UnifiedSearchCurrentDirItemAction import com.owncloud.android.ui.interfaces.UnifiedSearchListInterface import com.owncloud.android.ui.unifiedsearch.UnifiedSearchSection import com.owncloud.android.utils.DisplayUtils -import com.owncloud.android.utils.overlay.OverlayManager +import com.nextcloud.utils.thumbnail.FolderThumbnailGenerator import com.owncloud.android.utils.theme.ViewThemeUtils /** @@ -50,7 +50,7 @@ class UnifiedSearchListAdapter( private val viewThemeUtils: ViewThemeUtils, private val appPreferences: AppPreferences, private val currentDirItemAction: UnifiedSearchCurrentDirItemAction, - private val overlayManager: OverlayManager, + private val folderThumbnailGenerator: FolderThumbnailGenerator, private val fileThumbnailGenerator: FileThumbnailGenerator ) : SectionedRecyclerViewAdapter() { companion object { @@ -139,7 +139,7 @@ class UnifiedSearchListAdapter( filesAction, context, viewThemeUtils, - overlayManager, + folderThumbnailGenerator, fileThumbnailGenerator, user, appPreferences @@ -155,7 +155,7 @@ class UnifiedSearchListAdapter( storageManager, isRTL, currentDirItemAction, - overlayManager, + folderThumbnailGenerator, fileThumbnailGenerator ) } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/uploadList/UploadListAdapter.kt b/app/src/main/java/com/owncloud/android/ui/adapter/uploadList/UploadListAdapter.kt index 457912853215..ef522d684a74 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/uploadList/UploadListAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/uploadList/UploadListAdapter.kt @@ -46,7 +46,7 @@ import com.owncloud.android.ui.adapter.uploadList.helper.UploadListItemOnClick import com.owncloud.android.ui.adapter.uploadList.model.UploadListSection import com.owncloud.android.ui.adapter.uploadList.model.UploadListType import com.owncloud.android.utils.DisplayUtils -import com.owncloud.android.utils.overlay.OverlayManager +import com.nextcloud.utils.thumbnail.FolderThumbnailGenerator import com.owncloud.android.utils.theme.ViewThemeUtils import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -75,7 +75,7 @@ class UploadListAdapter( private val itemOnClick: UploadListItemOnClick, private val helper: UploadListAdapterHelper, private val fileThumbnailGenerator: FileThumbnailGenerator, - private val overlayManager: OverlayManager + private val folderThumbnailGenerator: FolderThumbnailGenerator ) : SectionedRecyclerViewAdapter() { private val uploadListSections = UploadListSection.sections() @@ -519,7 +519,7 @@ class UploadListAdapter( false, null, fileThumbnailGenerator, - overlayManager + folderThumbnailGenerator ) } diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/ConflictsResolveDialog.kt b/app/src/main/java/com/owncloud/android/ui/dialog/ConflictsResolveDialog.kt index b3ec930a0c94..6a8149db905f 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/ConflictsResolveDialog.kt +++ b/app/src/main/java/com/owncloud/android/ui/dialog/ConflictsResolveDialog.kt @@ -34,7 +34,7 @@ import com.owncloud.android.ui.dialog.parcel.ConflictDialogData import com.owncloud.android.ui.dialog.parcel.ConflictFileData import com.owncloud.android.utils.DisplayUtils import com.owncloud.android.utils.MimeTypeUtil -import com.owncloud.android.utils.overlay.OverlayManager +import com.nextcloud.utils.thumbnail.FolderThumbnailGenerator import com.owncloud.android.utils.theme.ViewThemeUtils import java.io.File import javax.inject.Inject @@ -65,7 +65,7 @@ class ConflictsResolveDialog : lateinit var fileDataStorageManager: FileDataStorageManager @Inject - lateinit var overlayManager: OverlayManager + lateinit var folderThumbnailGenerator: FolderThumbnailGenerator @Inject lateinit var fileThumbnailGenerator: FileThumbnailGenerator @@ -237,7 +237,7 @@ class ConflictsResolveDialog : false, null, fileThumbnailGenerator, - overlayManager + folderThumbnailGenerator ) } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java index a354d7a2fa62..ea2a2d1b55ab 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -122,7 +122,7 @@ import com.owncloud.android.utils.MimeTypeUtil; import com.owncloud.android.utils.PermissionUtil; import com.nextcloud.utils.thumbnail.FileThumbnailGenerator; -import com.owncloud.android.utils.overlay.OverlayManager; +import com.nextcloud.utils.thumbnail.FolderThumbnailGenerator; import com.owncloud.android.utils.theme.ThemeUtils; import org.apache.commons.httpclient.HttpStatus; @@ -210,7 +210,7 @@ public class OCFileListFragment extends ExtendedListFragment implements @Inject ShortcutUtil shortcutUtil; @Inject SyncedFolderProvider syncedFolderProvider; @Inject AppScanOptionalFeature appScanOptionalFeature; - @Inject OverlayManager overlayManager; + @Inject FolderThumbnailGenerator folderThumbnailGenerator; @Inject FileThumbnailGenerator fileThumbnailGenerator; protected FileFragment.ContainerActivity mContainerActivity; @@ -485,7 +485,7 @@ protected void setAdapter(Bundle args) { hideItemOptions, isGridViewPreferred, viewThemeUtils, - overlayManager, + folderThumbnailGenerator, fileThumbnailGenerator ); diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/UnifiedSearchFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/UnifiedSearchFragment.kt index c8db71230fe6..08ef322859c3 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/UnifiedSearchFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/UnifiedSearchFragment.kt @@ -63,7 +63,7 @@ import com.owncloud.android.ui.unifiedsearch.UnifiedSearchViewModel import com.owncloud.android.ui.unifiedsearch.filterOutHiddenFiles import com.owncloud.android.utils.DisplayUtils import com.owncloud.android.utils.PermissionUtil -import com.owncloud.android.utils.overlay.OverlayManager +import com.nextcloud.utils.thumbnail.FolderThumbnailGenerator import com.owncloud.android.utils.theme.ViewThemeUtils import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -109,7 +109,7 @@ class UnifiedSearchFragment : } @Inject - lateinit var overlayManager: OverlayManager + lateinit var folderThumbnailGenerator: FolderThumbnailGenerator @Inject lateinit var fileThumbnailGenerator: FileThumbnailGenerator @@ -386,7 +386,7 @@ class UnifiedSearchFragment : viewThemeUtils, appPreferences, this@UnifiedSearchFragment, - overlayManager, + folderThumbnailGenerator, fileThumbnailGenerator ) 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 4e7ddfea58bd..55357bdba659 100644 --- a/app/src/main/java/com/owncloud/android/utils/DisplayUtils.java +++ b/app/src/main/java/com/owncloud/android/utils/DisplayUtils.java @@ -56,7 +56,7 @@ import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.ui.TextDrawable; import com.owncloud.android.ui.dialog.SortingOrderDialogFragment; -import com.owncloud.android.utils.overlay.OverlayManager; +import com.nextcloud.utils.thumbnail.FolderThumbnailGenerator; import java.io.BufferedReader; import java.io.IOException; @@ -761,7 +761,7 @@ public static void setThumbnail(OCFile file, boolean gridView, LoaderImageView shimmerThumbnail, FileThumbnailGenerator thumbnailGenerator, - OverlayManager overlayManager) { + FolderThumbnailGenerator folderThumbnailGenerator) { if (file == null || thumbnailView == null) { return; } @@ -772,7 +772,7 @@ public static void setThumbnail(OCFile file, } if (file.isFolder()) { - overlayManager.setFolderThumbnail(file, thumbnailView, shimmerThumbnail); + folderThumbnailGenerator.setFolderThumbnail(file, thumbnailView, shimmerThumbnail); return; } From 7877ed9d26e144cefcda4c6418c9829f09d0de37 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Fri, 7 Aug 2026 09:44:40 +0200 Subject: [PATCH 14/20] introduce ThumbnailGenerator.kt Signed-off-by: alperozturk96 --- .../thumbnail/FolderThumbnailGenerator.kt | 2 +- .../utils/thumbnail/ThumbnailGenerator.kt | 34 +++++++++++++++++++ .../android/ui/adapter/OCFileListDelegate.kt | 8 ++++- 3 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/com/nextcloud/utils/thumbnail/ThumbnailGenerator.kt diff --git a/app/src/main/java/com/nextcloud/utils/thumbnail/FolderThumbnailGenerator.kt b/app/src/main/java/com/nextcloud/utils/thumbnail/FolderThumbnailGenerator.kt index 93589d905ed7..4e5f0547d273 100644 --- a/app/src/main/java/com/nextcloud/utils/thumbnail/FolderThumbnailGenerator.kt +++ b/app/src/main/java/com/nextcloud/utils/thumbnail/FolderThumbnailGenerator.kt @@ -61,4 +61,4 @@ class FolderThumbnailGenerator @Inject constructor( val icon = MimeTypeUtil.getFolderIcon(isDarkModeActive, overlayIconId, context, viewThemeUtils) imageView.setImageDrawable(icon) } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/nextcloud/utils/thumbnail/ThumbnailGenerator.kt b/app/src/main/java/com/nextcloud/utils/thumbnail/ThumbnailGenerator.kt new file mode 100644 index 000000000000..4f521e59f8f3 --- /dev/null +++ b/app/src/main/java/com/nextcloud/utils/thumbnail/ThumbnailGenerator.kt @@ -0,0 +1,34 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2026 Alper Ozturk + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +package com.nextcloud.utils.thumbnail + +import android.widget.ImageView +import com.elyeproj.loaderviewlibrary.LoaderImageView +import com.owncloud.android.datamodel.OCFile +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class ThumbnailGenerator @Inject constructor( + val fileThumbnailGenerator: FileThumbnailGenerator, + val folderThumbnailGenerator: FolderThumbnailGenerator +) { + + @JvmOverloads + fun setThumbnail(ocFile: OCFile?, view: ImageView?, isGrid: Boolean = false, shimmer: LoaderImageView? = null) { + if (ocFile == null || view == null) { + return + } + + when { + ocFile.isOfflineOperation -> fileThumbnailGenerator.setOfflineOperationThumbnail(ocFile, view) + ocFile.isFolder -> folderThumbnailGenerator.setFolderThumbnail(ocFile, view, shimmer) + else -> fileThumbnailGenerator.setThumbnail(ocFile, view, isGrid, shimmer) + } + } +} diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt index c1ba4c3cf92b..4d8c296b2d77 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt @@ -216,7 +216,13 @@ class OCFileListDelegate( viewHolder.thumbnail.setPadding(padding, padding, padding, padding) } } - setThumbnail(viewHolder.thumbnail, viewHolder.shimmerThumbnail, file, thumbnailGenerator, folderThumbnailGenerator) + setThumbnail( + viewHolder.thumbnail, + viewHolder.shimmerThumbnail, + file, + thumbnailGenerator, + folderThumbnailGenerator + ) // item layout + click listeners bindGridItemLayout(file, viewHolder) From 0faf153c4093e1ec31e63f5ca929b5be7cf8e85a Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Fri, 7 Aug 2026 09:52:48 +0200 Subject: [PATCH 15/20] use ThumbnailGenerator only Signed-off-by: alperozturk96 --- .../ui/adapter/UnifiedSearchListAdapterIT.kt | 26 ++++++--- .../ui/fileactions/FileActionsBottomSheet.kt | 15 ++--- .../TrashbinFileActionsBottomSheet.kt | 15 ++--- .../android/ui/activity/ShareActivity.kt | 17 +----- .../android/ui/activity/UploadListActivity.kt | 10 +--- .../android/ui/adapter/GalleryAdapter.kt | 6 +- .../android/ui/adapter/OCFileListAdapter.java | 16 ++--- .../android/ui/adapter/OCFileListDelegate.kt | 33 ++--------- .../UnifiedSearchCurrentDirItemViewHolder.kt | 16 +---- .../ui/adapter/UnifiedSearchItemViewHolder.kt | 10 ++-- .../ui/adapter/UnifiedSearchListAdapter.kt | 12 ++-- .../adapter/uploadList/UploadListAdapter.kt | 15 +---- .../ui/dialog/ConflictsResolveDialog.kt | 17 +----- .../android/ui/fragment/GalleryFragment.kt | 2 +- .../ui/fragment/OCFileListFragment.java | 9 +-- .../ui/fragment/UnifiedSearchFragment.kt | 11 +--- .../owncloud/android/utils/DisplayUtils.java | 58 ------------------- .../android/ui/adapter/GalleryAdapterTest.kt | 8 +-- 18 files changed, 74 insertions(+), 222 deletions(-) diff --git a/app/src/androidTest/java/com/owncloud/android/ui/adapter/UnifiedSearchListAdapterIT.kt b/app/src/androidTest/java/com/owncloud/android/ui/adapter/UnifiedSearchListAdapterIT.kt index 264d7c62e728..8025c9d41a08 100644 --- a/app/src/androidTest/java/com/owncloud/android/ui/adapter/UnifiedSearchListAdapterIT.kt +++ b/app/src/androidTest/java/com/owncloud/android/ui/adapter/UnifiedSearchListAdapterIT.kt @@ -23,7 +23,10 @@ import com.owncloud.android.ui.unifiedsearch.ProviderID import com.owncloud.android.ui.unifiedsearch.UnifiedSearchSection import com.owncloud.android.utils.MimeType import com.owncloud.android.utils.ScreenshotTest +import com.nextcloud.utils.thumbnail.FileThumbnailGenerator import com.nextcloud.utils.thumbnail.FolderThumbnailGenerator +import com.nextcloud.utils.thumbnail.ThumbnailGenerator +import javax.inject.Provider import org.junit.Before import org.junit.Test @@ -32,7 +35,7 @@ class UnifiedSearchListAdapterIT : AbstractIT() { private val testClassName = "com.owncloud.android.ui.adapter.UnifiedSearchListAdapterIT" - private lateinit var folderThumbnailGenerator: FolderThumbnailGenerator + private lateinit var thumbnailGenerator: ThumbnailGenerator private lateinit var preferences: AppPreferences @Suppress("DEPRECATION") @@ -134,11 +137,20 @@ class UnifiedSearchListAdapterIT : AbstractIT() { ): UnifiedSearchListAdapter { val accountManager = UserAccountManagerImpl.fromContext(targetContext) - folderThumbnailGenerator = FolderThumbnailGenerator( - preferences = preferences, - viewThemeUtils = sut.viewThemeUtils, - context = targetContext, - accountManager = accountManager + thumbnailGenerator = ThumbnailGenerator( + fileThumbnailGenerator = FileThumbnailGenerator( + storageManager = Provider { sut.storageManager }, + preferences = preferences, + viewThemeUtils = sut.viewThemeUtils, + context = targetContext, + accountManager = accountManager + ), + folderThumbnailGenerator = FolderThumbnailGenerator( + preferences = preferences, + viewThemeUtils = sut.viewThemeUtils, + context = targetContext, + accountManager = accountManager + ) ) val adapter = UnifiedSearchListAdapter( @@ -157,7 +169,7 @@ class UnifiedSearchListAdapterIT : AbstractIT() { viewThemeUtils = sut.viewThemeUtils, appPreferences = preferences, currentDirItemAction = noopCurrentDirAction, - folderThumbnailGenerator = folderThumbnailGenerator + thumbnailGenerator = thumbnailGenerator ) adapter.shouldShowFooters(true) 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 b9bcc3d47b32..b689a3c404b8 100644 --- a/app/src/main/java/com/nextcloud/ui/fileactions/FileActionsBottomSheet.kt +++ b/app/src/main/java/com/nextcloud/ui/fileactions/FileActionsBottomSheet.kt @@ -35,7 +35,6 @@ 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.nextcloud.utils.thumbnail.FileThumbnailGenerator import com.owncloud.android.R import com.owncloud.android.databinding.FileActionsBottomSheetBinding import com.owncloud.android.databinding.FileActionsBottomSheetItemBinding @@ -47,7 +46,7 @@ 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.nextcloud.utils.thumbnail.FolderThumbnailGenerator +import com.nextcloud.utils.thumbnail.ThumbnailGenerator import com.owncloud.android.utils.theme.ViewThemeUtils import javax.inject.Inject @@ -71,10 +70,7 @@ class FileActionsBottomSheet : lateinit var syncedFolderProvider: SyncedFolderProvider @Inject - lateinit var folderThumbnailGenerator: FolderThumbnailGenerator - - @Inject - lateinit var fileThumbnailGenerator: FileThumbnailGenerator + lateinit var thumbnailGenerator: ThumbnailGenerator private lateinit var viewModel: FileActionsViewModel @@ -150,13 +146,10 @@ class FileActionsBottomSheet : private fun loadFileThumbnail(titleFile: OCFile?) { titleFile?.let { - DisplayUtils.setThumbnail( + thumbnailGenerator.setThumbnail( it, binding.thumbnailLayout.thumbnail, - false, - binding.thumbnailLayout.thumbnailShimmer, - fileThumbnailGenerator, - folderThumbnailGenerator + shimmer = binding.thumbnailLayout.thumbnailShimmer ) } } diff --git a/app/src/main/java/com/nextcloud/ui/trashbinFileActions/TrashbinFileActionsBottomSheet.kt b/app/src/main/java/com/nextcloud/ui/trashbinFileActions/TrashbinFileActionsBottomSheet.kt index 08b6bc994c08..6b51f44360b9 100644 --- a/app/src/main/java/com/nextcloud/ui/trashbinFileActions/TrashbinFileActionsBottomSheet.kt +++ b/app/src/main/java/com/nextcloud/ui/trashbinFileActions/TrashbinFileActionsBottomSheet.kt @@ -27,7 +27,6 @@ import com.nextcloud.client.account.CurrentAccountProvider import com.nextcloud.client.di.Injectable import com.nextcloud.client.di.ViewModelFactory import com.nextcloud.utils.extensions.toOCFile -import com.nextcloud.utils.thumbnail.FileThumbnailGenerator import com.owncloud.android.R import com.owncloud.android.databinding.FileActionsBottomSheetBinding import com.owncloud.android.databinding.FileActionsBottomSheetItemBinding @@ -35,7 +34,7 @@ import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.SyncedFolderProvider import com.owncloud.android.lib.resources.trashbin.model.TrashbinFile import com.owncloud.android.utils.DisplayUtils -import com.nextcloud.utils.thumbnail.FolderThumbnailGenerator +import com.nextcloud.utils.thumbnail.ThumbnailGenerator import com.owncloud.android.utils.theme.ViewThemeUtils import javax.inject.Inject @@ -59,10 +58,7 @@ class TrashbinFileActionsBottomSheet : lateinit var syncedFolderProvider: SyncedFolderProvider @Inject - lateinit var folderThumbnailGenerator: FolderThumbnailGenerator - - @Inject - lateinit var fileThumbnailGenerator: FileThumbnailGenerator + lateinit var thumbnailGenerator: ThumbnailGenerator private lateinit var viewModel: TrashbinFileActionsViewModel @@ -123,13 +119,10 @@ class TrashbinFileActionsBottomSheet : private fun loadFileThumbnail(titleFile: TrashbinFile?) { titleFile?.let { - DisplayUtils.setThumbnail( + thumbnailGenerator.setThumbnail( it.toOCFile(), binding.thumbnailLayout.thumbnail, - false, - binding.thumbnailLayout.thumbnailShimmer, - fileThumbnailGenerator, - folderThumbnailGenerator + shimmer = binding.thumbnailLayout.thumbnailShimmer ) } } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ShareActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/ShareActivity.kt index fe414c423944..b60f3997eb6d 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ShareActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/ShareActivity.kt @@ -18,7 +18,6 @@ import androidx.lifecycle.lifecycleScope import com.nextcloud.android.common.ui.theme.utils.ColorRole import com.nextcloud.client.account.User import com.nextcloud.client.di.Injectable -import com.nextcloud.utils.thumbnail.FileThumbnailGenerator import com.owncloud.android.R import com.owncloud.android.databinding.ShareActivityBinding import com.owncloud.android.datamodel.OCFile @@ -35,7 +34,7 @@ import com.owncloud.android.ui.fragment.FileDetailSharingFragment import com.owncloud.android.ui.fragment.FileDetailsSharingProcessFragment import com.owncloud.android.utils.DisplayUtils import com.owncloud.android.utils.MimeTypeUtil -import com.nextcloud.utils.thumbnail.FolderThumbnailGenerator +import com.nextcloud.utils.thumbnail.ThumbnailGenerator import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -49,10 +48,7 @@ class ShareActivity : lateinit var syncedFolderProvider: SyncedFolderProvider @Inject - lateinit var folderThumbnailGenerator: FolderThumbnailGenerator - - @Inject - lateinit var fileThumbnailGenerator: FileThumbnailGenerator + lateinit var thumbnailGenerator: ThumbnailGenerator override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -143,14 +139,7 @@ class ShareActivity : ) ) } else { - DisplayUtils.setThumbnail( - file, - binding.shareFileIcon, - false, - null, - fileThumbnailGenerator, - folderThumbnailGenerator - ) + thumbnailGenerator.setThumbnail(file, binding.shareFileIcon) } } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/UploadListActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/UploadListActivity.kt index e45ac6a46cab..33a63a157dc7 100755 --- a/app/src/main/java/com/owncloud/android/ui/activity/UploadListActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/UploadListActivity.kt @@ -41,7 +41,7 @@ import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.lib.resources.files.ExistenceCheckRemoteOperation import com.owncloud.android.operations.CheckCurrentCredentialsOperation -import com.nextcloud.utils.thumbnail.FileThumbnailGenerator +import com.nextcloud.utils.thumbnail.ThumbnailGenerator import com.owncloud.android.operations.factory.UploadFileOperationFactory import com.owncloud.android.ui.adapter.uploadList.UploadListAdapter import com.owncloud.android.ui.adapter.uploadList.helper.ConflictHandlingResult @@ -51,7 +51,6 @@ import com.owncloud.android.ui.adapter.uploadList.helper.UploadListAdapterHelper import com.owncloud.android.ui.adapter.uploadList.helper.UploadListItemOnClick import com.owncloud.android.ui.decoration.MediaGridItemDecoration import com.owncloud.android.utils.FilesSyncHelper -import com.nextcloud.utils.thumbnail.FolderThumbnailGenerator import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -75,9 +74,7 @@ class UploadListActivity : @Inject lateinit var uploadFileOperationFactory: UploadFileOperationFactory - @Inject lateinit var fileThumbnailGenerator: FileThumbnailGenerator - - @Inject lateinit var folderThumbnailGenerator: FolderThumbnailGenerator + @Inject lateinit var thumbnailGenerator: ThumbnailGenerator private var uploadWarningCard: UploadWarningCard? = null @@ -126,8 +123,7 @@ class UploadListActivity : viewThemeUtils, this, adapterHelper, - fileThumbnailGenerator, - folderThumbnailGenerator + thumbnailGenerator ) binding?.autoUploadBatterySaverWarningCard?.let { diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt b/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt index f1836f69e299..af897486404f 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt @@ -24,7 +24,7 @@ import com.afollestad.sectionedrecyclerview.SectionedViewHolder import com.nextcloud.client.account.User import com.nextcloud.client.preferences.AppPreferences import com.nextcloud.utils.extensions.toGalleryItems -import com.nextcloud.utils.thumbnail.FileThumbnailGenerator +import com.nextcloud.utils.thumbnail.ThumbnailGenerator import com.owncloud.android.databinding.GalleryHeaderBinding import com.owncloud.android.databinding.GalleryRowBinding import com.owncloud.android.datamodel.FileDataStorageManager @@ -48,7 +48,7 @@ class GalleryAdapter( private val viewThemeUtils: ViewThemeUtils, var columns: Int, private val defaultThumbnailSize: Int, - private val fileThumbnailGenerator: FileThumbnailGenerator + private val thumbnailGenerator: ThumbnailGenerator ) : SectionedRecyclerViewAdapter(), CommonOCFileListAdapterInterface, PopupTextProvider { @@ -232,7 +232,7 @@ class GalleryAdapter( override fun isMultiSelect(): Boolean = ocFileListDelegate.isMultiSelect override fun cancelAllPendingTasks() { - fileThumbnailGenerator.cancelPendingTasks() + thumbnailGenerator.fileThumbnailGenerator.cancelPendingTasks() } override fun addCheckedFile(file: OCFile) { 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 318b7ce5001c..0f07a706c60c 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 @@ -38,7 +38,6 @@ import com.nextcloud.utils.extensions.ImageViewExtensionsKt; import com.nextcloud.utils.extensions.ViewExtensionsKt; import com.nextcloud.utils.mdm.MDMConfig; -import com.nextcloud.utils.thumbnail.FileThumbnailGenerator; import com.owncloud.android.MainApp; import com.owncloud.android.R; import com.owncloud.android.databinding.GridItemBinding; @@ -69,7 +68,7 @@ import com.owncloud.android.utils.FileSortOrder; import com.owncloud.android.utils.FileStorageUtils; import com.owncloud.android.utils.MimeTypeUtil; -import com.nextcloud.utils.thumbnail.FolderThumbnailGenerator; +import com.nextcloud.utils.thumbnail.ThumbnailGenerator; import com.owncloud.android.utils.theme.CapabilityUtils; import com.owncloud.android.utils.theme.ViewThemeUtils; @@ -137,8 +136,7 @@ public class OCFileListAdapter extends RecyclerView.Adapter recommendedFiles = new ArrayList<>(); private RecommendedFilesAdapter recommendedFilesAdapter; private final OCFileListAdapterHelper helper = new OCFileListAdapterHelper(); - private final FolderThumbnailGenerator folderThumbnailGenerator; - private final FileThumbnailGenerator fileThumbnailGenerator; + private final ThumbnailGenerator thumbnailGenerator; public OCFileListAdapter( Activity activity, @@ -150,10 +148,8 @@ public OCFileListAdapter( boolean argHideItemOptions, boolean gridView, final ViewThemeUtils viewThemeUtils, - FolderThumbnailGenerator folderThumbnailGenerator, - FileThumbnailGenerator fileThumbnailGenerator) { - this.folderThumbnailGenerator = folderThumbnailGenerator; - this.fileThumbnailGenerator = fileThumbnailGenerator; + ThumbnailGenerator thumbnailGenerator) { + this.thumbnailGenerator = thumbnailGenerator; this.ocFileListFragmentInterface = ocFileListFragmentInterface; this.activity = activity; this.preferences = preferences; @@ -498,7 +494,7 @@ public void bindRecommendedFilesHolder(OCFileListRecommendedItemViewHolder holde } private void bindHolder(@NonNull RecyclerView.ViewHolder holder, ListViewHolder viewHolder, OCFile file) { - ocFileListDelegate.bindViewHolder(viewHolder, file, currentDirectory, searchType, fileThumbnailGenerator, folderThumbnailGenerator); + ocFileListDelegate.bindViewHolder(viewHolder, file, currentDirectory, searchType, thumbnailGenerator); if (holder instanceof ListItemViewHolder itemViewHolder) { bindListItemViewHolder(itemViewHolder, file); @@ -1013,7 +1009,7 @@ public void setHighlightedItem(OCFile file) { } public void cancelAllPendingTasks() { - fileThumbnailGenerator.cancelPendingTasks(); + thumbnailGenerator.getFileThumbnailGenerator().cancelPendingTasks(); } public void setGridView(boolean bool) { diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt index 4d8c296b2d77..97b3bd9b5c3a 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt @@ -23,7 +23,7 @@ import com.nextcloud.utils.extensions.makeRounded import com.nextcloud.utils.extensions.setVisibleIf import com.nextcloud.utils.extensions.stopShimmer import com.nextcloud.utils.mdm.MDMConfig -import com.nextcloud.utils.thumbnail.FileThumbnailGenerator +import com.nextcloud.utils.thumbnail.ThumbnailGenerator import com.owncloud.android.R import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile @@ -34,10 +34,8 @@ import com.owncloud.android.ui.activity.ComponentsGetter import com.owncloud.android.ui.activity.FolderPickerActivity import com.owncloud.android.ui.fragment.SearchType import com.owncloud.android.ui.interfaces.OCFileListFragmentInterface -import com.owncloud.android.utils.DisplayUtils import com.owncloud.android.utils.EncryptionUtils import com.owncloud.android.utils.MimeTypeUtil -import com.nextcloud.utils.thumbnail.FolderThumbnailGenerator import com.owncloud.android.utils.theme.ViewThemeUtils import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -177,31 +175,13 @@ class OCFileListDelegate( } } - fun setThumbnail( - thumbnail: ImageView, - shimmerThumbnail: LoaderImageView?, - file: OCFile, - thumbnailGenerator: FileThumbnailGenerator, - folderThumbnailGenerator: FolderThumbnailGenerator - ) { - DisplayUtils.setThumbnail( - file, - thumbnail, - gridView, - shimmerThumbnail, - thumbnailGenerator, - folderThumbnailGenerator - ) - } - @Suppress("MagicNumber") fun bindViewHolder( viewHolder: ListViewHolder, file: OCFile, currentDirectory: OCFile?, searchType: SearchType?, - thumbnailGenerator: FileThumbnailGenerator, - folderThumbnailGenerator: FolderThumbnailGenerator + thumbnailGenerator: ThumbnailGenerator ) { // thumbnail viewHolder.imageFileName?.text = file.fileName @@ -216,13 +196,8 @@ class OCFileListDelegate( viewHolder.thumbnail.setPadding(padding, padding, padding, padding) } } - setThumbnail( - viewHolder.thumbnail, - viewHolder.shimmerThumbnail, - file, - thumbnailGenerator, - folderThumbnailGenerator - ) + + thumbnailGenerator.setThumbnail(file, viewHolder.shimmerThumbnail, gridView) // item layout + click listeners bindGridItemLayout(file, viewHolder) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchCurrentDirItemViewHolder.kt b/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchCurrentDirItemViewHolder.kt index 8d94b0942e1a..3b805ad2a5bb 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchCurrentDirItemViewHolder.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchCurrentDirItemViewHolder.kt @@ -10,14 +10,12 @@ package com.owncloud.android.ui.adapter import android.content.Context import android.view.View import com.afollestad.sectionedrecyclerview.SectionedViewHolder -import com.nextcloud.utils.thumbnail.FileThumbnailGenerator +import com.nextcloud.utils.thumbnail.ThumbnailGenerator import com.owncloud.android.databinding.UnifiedSearchCurrentDirectoryItemBinding import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile import com.owncloud.android.ui.interfaces.UnifiedSearchCurrentDirItemAction -import com.owncloud.android.utils.DisplayUtils import com.owncloud.android.utils.FileStorageUtils -import com.nextcloud.utils.thumbnail.FolderThumbnailGenerator @Suppress("LongParameterList") class UnifiedSearchCurrentDirItemViewHolder( @@ -26,8 +24,7 @@ class UnifiedSearchCurrentDirItemViewHolder( private val storageManager: FileDataStorageManager, private val isRTL: Boolean, private val action: UnifiedSearchCurrentDirItemAction, - private val folderThumbnailGenerator: FolderThumbnailGenerator, - private val fileThumbnailGenerator: FileThumbnailGenerator + private val thumbnailGenerator: ThumbnailGenerator ) : SectionedViewHolder(binding.unifiedSearchCurrentDirItemLayout) { fun bind(file: OCFile) { @@ -44,14 +41,7 @@ class UnifiedSearchCurrentDirItemViewHolder( binding.filename.text = filename } - DisplayUtils.setThumbnail( - file, - binding.thumbnail, - false, - binding.thumbnailShimmer, - fileThumbnailGenerator, - folderThumbnailGenerator - ) + thumbnailGenerator.setThumbnail(file, binding.thumbnail, shimmer = binding.thumbnailShimmer) binding.more.setOnClickListener { action.openFile(file.decryptedRemotePath, true) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchItemViewHolder.kt b/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchItemViewHolder.kt index c723a5ab16fb..36f1ad40db83 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchItemViewHolder.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchItemViewHolder.kt @@ -24,7 +24,6 @@ import com.nextcloud.utils.ContactManager import com.nextcloud.utils.GlideHelper import com.nextcloud.utils.extensions.getType import com.nextcloud.utils.extensions.setVisibleIf -import com.nextcloud.utils.thumbnail.FileThumbnailGenerator import com.owncloud.android.R import com.owncloud.android.databinding.UnifiedSearchItemBinding import com.owncloud.android.datamodel.FileDataStorageManager @@ -32,7 +31,7 @@ import com.owncloud.android.datamodel.OCFile import com.owncloud.android.lib.common.SearchResultEntry import com.owncloud.android.ui.interfaces.UnifiedSearchListInterface import com.owncloud.android.utils.MimeTypeUtil -import com.nextcloud.utils.thumbnail.FolderThumbnailGenerator +import com.nextcloud.utils.thumbnail.ThumbnailGenerator import com.owncloud.android.utils.theme.ViewThemeUtils @Suppress("LongParameterList") @@ -44,8 +43,7 @@ class UnifiedSearchItemViewHolder( private val filesAction: FilesAction, val context: Context, private val viewThemeUtils: ViewThemeUtils, - private val folderThumbnailGenerator: FolderThumbnailGenerator, - private val fileThumbnailGenerator: FileThumbnailGenerator, + private val thumbnailGenerator: ThumbnailGenerator, private val user: User, private val preferences: AppPreferences ) : SectionedViewHolder(binding.root) { @@ -103,7 +101,7 @@ class UnifiedSearchItemViewHolder( setImageDrawable(ContextCompat.getDrawable(context, R.drawable.folder)) viewThemeUtils.platform.colorImageView(this, ColorRole.PRIMARY) } - folderThumbnailGenerator.setFolderOverlayIcon(file, binding.thumbnailOverlayIcon) + thumbnailGenerator.folderThumbnailGenerator.setFolderOverlayIcon(file, binding.thumbnailOverlayIcon) } private fun bindLocalFileThumbnail(file: OCFile) { @@ -115,7 +113,7 @@ class UnifiedSearchItemViewHolder( ImageViewCompat.setImageTintList(this, null) } } else { - fileThumbnailGenerator.setThumbnail(file, binding.thumbnail, false, binding.thumbnailShimmer) + thumbnailGenerator.setThumbnail(file, binding.thumbnail, shimmer = binding.thumbnailShimmer) } } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchListAdapter.kt b/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchListAdapter.kt index 60403160371d..c127c34fad7f 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchListAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchListAdapter.kt @@ -19,7 +19,6 @@ import com.afollestad.sectionedrecyclerview.SectionedViewHolder import com.bumptech.glide.Glide import com.nextcloud.client.account.User import com.nextcloud.client.preferences.AppPreferences -import com.nextcloud.utils.thumbnail.FileThumbnailGenerator import com.owncloud.android.R import com.owncloud.android.databinding.UnifiedSearchCurrentDirectoryItemBinding import com.owncloud.android.databinding.UnifiedSearchEmptyBinding @@ -33,7 +32,7 @@ import com.owncloud.android.ui.interfaces.UnifiedSearchCurrentDirItemAction import com.owncloud.android.ui.interfaces.UnifiedSearchListInterface import com.owncloud.android.ui.unifiedsearch.UnifiedSearchSection import com.owncloud.android.utils.DisplayUtils -import com.nextcloud.utils.thumbnail.FolderThumbnailGenerator +import com.nextcloud.utils.thumbnail.ThumbnailGenerator import com.owncloud.android.utils.theme.ViewThemeUtils /** @@ -50,8 +49,7 @@ class UnifiedSearchListAdapter( private val viewThemeUtils: ViewThemeUtils, private val appPreferences: AppPreferences, private val currentDirItemAction: UnifiedSearchCurrentDirItemAction, - private val folderThumbnailGenerator: FolderThumbnailGenerator, - private val fileThumbnailGenerator: FileThumbnailGenerator + private val thumbnailGenerator: ThumbnailGenerator ) : SectionedRecyclerViewAdapter() { companion object { private const val VIEW_TYPE_EMPTY = Int.MAX_VALUE @@ -139,8 +137,7 @@ class UnifiedSearchListAdapter( filesAction, context, viewThemeUtils, - folderThumbnailGenerator, - fileThumbnailGenerator, + thumbnailGenerator, user, appPreferences ) @@ -155,8 +152,7 @@ class UnifiedSearchListAdapter( storageManager, isRTL, currentDirItemAction, - folderThumbnailGenerator, - fileThumbnailGenerator + thumbnailGenerator ) } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/uploadList/UploadListAdapter.kt b/app/src/main/java/com/owncloud/android/ui/adapter/uploadList/UploadListAdapter.kt index ef522d684a74..e1f34a37e5f9 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/uploadList/UploadListAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/uploadList/UploadListAdapter.kt @@ -29,7 +29,7 @@ import com.nextcloud.utils.extensions.isLastResultConflictError import com.nextcloud.utils.extensions.setVisibleIf import com.nextcloud.utils.extensions.sortedByUploadOrder import com.nextcloud.utils.extensions.toFile -import com.nextcloud.utils.thumbnail.FileThumbnailGenerator +import com.nextcloud.utils.thumbnail.ThumbnailGenerator import com.owncloud.android.R import com.owncloud.android.databinding.UploadListHeaderBinding import com.owncloud.android.databinding.UploadListItemBinding @@ -46,7 +46,6 @@ import com.owncloud.android.ui.adapter.uploadList.helper.UploadListItemOnClick import com.owncloud.android.ui.adapter.uploadList.model.UploadListSection import com.owncloud.android.ui.adapter.uploadList.model.UploadListType import com.owncloud.android.utils.DisplayUtils -import com.nextcloud.utils.thumbnail.FolderThumbnailGenerator import com.owncloud.android.utils.theme.ViewThemeUtils import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -74,8 +73,7 @@ class UploadListAdapter( private val viewThemeUtils: ViewThemeUtils, private val itemOnClick: UploadListItemOnClick, private val helper: UploadListAdapterHelper, - private val fileThumbnailGenerator: FileThumbnailGenerator, - private val folderThumbnailGenerator: FolderThumbnailGenerator + private val thumbnailGenerator: ThumbnailGenerator ) : SectionedRecyclerViewAdapter() { private val uploadListSections = UploadListSection.sections() @@ -513,14 +511,7 @@ class UploadListAdapter( private fun bindItemThumbnail(holder: ItemViewHolder, ocFile: OCFile) { holder.binding.thumbnail.tag = ocFile.fileId - DisplayUtils.setThumbnail( - ocFile, - holder.binding.thumbnail, - false, - null, - fileThumbnailGenerator, - folderThumbnailGenerator - ) + thumbnailGenerator.setThumbnail(ocFile, holder.binding.thumbnail) } // endregion diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/ConflictsResolveDialog.kt b/app/src/main/java/com/owncloud/android/ui/dialog/ConflictsResolveDialog.kt index 6a8149db905f..ba43a10a4581 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/ConflictsResolveDialog.kt +++ b/app/src/main/java/com/owncloud/android/ui/dialog/ConflictsResolveDialog.kt @@ -21,7 +21,6 @@ import com.nextcloud.client.database.entity.OfflineOperationEntity import com.nextcloud.client.di.Injectable import com.nextcloud.utils.extensions.getParcelableArgument import com.nextcloud.utils.extensions.getSerializableArgument -import com.nextcloud.utils.thumbnail.FileThumbnailGenerator import com.owncloud.android.R import com.owncloud.android.databinding.ConflictResolveDialogBinding import com.owncloud.android.datamodel.FileDataStorageManager @@ -34,7 +33,7 @@ import com.owncloud.android.ui.dialog.parcel.ConflictDialogData import com.owncloud.android.ui.dialog.parcel.ConflictFileData import com.owncloud.android.utils.DisplayUtils import com.owncloud.android.utils.MimeTypeUtil -import com.nextcloud.utils.thumbnail.FolderThumbnailGenerator +import com.nextcloud.utils.thumbnail.ThumbnailGenerator import com.owncloud.android.utils.theme.ViewThemeUtils import java.io.File import javax.inject.Inject @@ -65,10 +64,7 @@ class ConflictsResolveDialog : lateinit var fileDataStorageManager: FileDataStorageManager @Inject - lateinit var folderThumbnailGenerator: FolderThumbnailGenerator - - @Inject - lateinit var fileThumbnailGenerator: FileThumbnailGenerator + lateinit var thumbnailGenerator: ThumbnailGenerator enum class Decision { CANCEL, @@ -231,14 +227,7 @@ class ConflictsResolveDialog : viewThemeUtils ) - DisplayUtils.setThumbnail( - rightDataFile, - binding.rightThumbnail, - false, - null, - fileThumbnailGenerator, - folderThumbnailGenerator - ) + thumbnailGenerator.setThumbnail(rightDataFile, binding.rightThumbnail) } private fun setOnClickListeners() { diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/GalleryFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/GalleryFragment.kt index 6143a265a276..3b12ee6bf401 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/GalleryFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/GalleryFragment.kt @@ -195,7 +195,7 @@ class GalleryFragment : viewThemeUtils, this.columnsCount, ThumbnailsCacheManager.getThumbnailDimension(), - fileThumbnailGenerator + thumbnailGenerator ) adapter?.setHasStableIds(true) setRecyclerViewAdapter(adapter) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java index ea2a2d1b55ab..c84ed7a12c84 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -121,8 +121,7 @@ import com.owncloud.android.utils.FileStorageUtils; import com.owncloud.android.utils.MimeTypeUtil; import com.owncloud.android.utils.PermissionUtil; -import com.nextcloud.utils.thumbnail.FileThumbnailGenerator; -import com.nextcloud.utils.thumbnail.FolderThumbnailGenerator; +import com.nextcloud.utils.thumbnail.ThumbnailGenerator; import com.owncloud.android.utils.theme.ThemeUtils; import org.apache.commons.httpclient.HttpStatus; @@ -210,8 +209,7 @@ public class OCFileListFragment extends ExtendedListFragment implements @Inject ShortcutUtil shortcutUtil; @Inject SyncedFolderProvider syncedFolderProvider; @Inject AppScanOptionalFeature appScanOptionalFeature; - @Inject FolderThumbnailGenerator folderThumbnailGenerator; - @Inject FileThumbnailGenerator fileThumbnailGenerator; + @Inject ThumbnailGenerator thumbnailGenerator; protected FileFragment.ContainerActivity mContainerActivity; @@ -485,8 +483,7 @@ protected void setAdapter(Bundle args) { hideItemOptions, isGridViewPreferred, viewThemeUtils, - folderThumbnailGenerator, - fileThumbnailGenerator + thumbnailGenerator ); setRecyclerViewAdapter(mAdapter); diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/UnifiedSearchFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/UnifiedSearchFragment.kt index 08ef322859c3..ae30732e9729 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/UnifiedSearchFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/UnifiedSearchFragment.kt @@ -41,7 +41,6 @@ import com.nextcloud.utils.extensions.getTypedActivity import com.nextcloud.utils.extensions.searchFilesByName import com.nextcloud.utils.extensions.setVisibleIf import com.nextcloud.utils.extensions.typedActivity -import com.nextcloud.utils.thumbnail.FileThumbnailGenerator import com.owncloud.android.R import com.owncloud.android.databinding.ListFragmentBinding import com.owncloud.android.datamodel.FileDataStorageManager @@ -63,7 +62,7 @@ import com.owncloud.android.ui.unifiedsearch.UnifiedSearchViewModel import com.owncloud.android.ui.unifiedsearch.filterOutHiddenFiles import com.owncloud.android.utils.DisplayUtils import com.owncloud.android.utils.PermissionUtil -import com.nextcloud.utils.thumbnail.FolderThumbnailGenerator +import com.nextcloud.utils.thumbnail.ThumbnailGenerator import com.owncloud.android.utils.theme.ViewThemeUtils import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -109,10 +108,7 @@ class UnifiedSearchFragment : } @Inject - lateinit var folderThumbnailGenerator: FolderThumbnailGenerator - - @Inject - lateinit var fileThumbnailGenerator: FileThumbnailGenerator + lateinit var thumbnailGenerator: ThumbnailGenerator @Inject lateinit var vmFactory: ViewModelFactory @@ -386,8 +382,7 @@ class UnifiedSearchFragment : viewThemeUtils, appPreferences, this@UnifiedSearchFragment, - folderThumbnailGenerator, - fileThumbnailGenerator + thumbnailGenerator ) adapter.shouldShowFooters(true) 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 55357bdba659..9519fdbd4d07 100644 --- a/app/src/main/java/com/owncloud/android/utils/DisplayUtils.java +++ b/app/src/main/java/com/owncloud/android/utils/DisplayUtils.java @@ -40,23 +40,18 @@ import android.text.style.StyleSpan; import android.util.DisplayMetrics; import android.view.View; -import android.widget.ImageView; -import com.elyeproj.loaderviewlibrary.LoaderImageView; import com.google.android.material.snackbar.Snackbar; import com.nextcloud.client.account.User; -import com.nextcloud.utils.thumbnail.FileThumbnailGenerator; import com.owncloud.android.MainApp; import com.owncloud.android.R; import com.owncloud.android.datamodel.ArbitraryDataProvider; import com.owncloud.android.datamodel.ArbitraryDataProviderImpl; -import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.datamodel.ThumbnailsCacheManager; import com.owncloud.android.lib.common.OwnCloudAccount; import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.ui.TextDrawable; import com.owncloud.android.ui.dialog.SortingOrderDialogFragment; -import com.nextcloud.utils.thumbnail.FolderThumbnailGenerator; import java.io.BufferedReader; import java.io.IOException; @@ -725,57 +720,4 @@ public static String getDateByPattern(long timestamp, @Nullable Context context, return df.format(timestamp); } - - /** - * Sets a thumbnail for a offline file, file or folder with various display options and states. - *

- * - * This method handles multiple thumbnail scenarios: - * - *

- * - * 1. Offline Files: - * - For folders: Shows an offline folder icon - * - For files: Loads thumbnail from local path with a gray filter - *

- * - * 2. Folders: - * - Displays folder icon with overlays - *

- * - * 3. Files: - * - Checks disk cache for existing thumbnails - * - Handles preview availability and updates - * - Supports grid and list view display modes - * - Generates new thumbnails if needed - * - Sets background color for PNG files - * - *

- * - * The method uses a shimmer effect while loading thumbnails, which is stopped - * once the thumbnail is successfully loaded or if an error occurs. - * - */ - public static void setThumbnail(OCFile file, - ImageView thumbnailView, - boolean gridView, - LoaderImageView shimmerThumbnail, - FileThumbnailGenerator thumbnailGenerator, - FolderThumbnailGenerator folderThumbnailGenerator) { - if (file == null || thumbnailView == null) { - return; - } - - if (file.isOfflineOperation()) { - thumbnailGenerator.setOfflineOperationThumbnail(file, thumbnailView); - return; - } - - if (file.isFolder()) { - folderThumbnailGenerator.setFolderThumbnail(file, thumbnailView, shimmerThumbnail); - return; - } - - thumbnailGenerator.setThumbnail(file, thumbnailView, gridView, shimmerThumbnail); - } } diff --git a/app/src/test/java/com/owncloud/android/ui/adapter/GalleryAdapterTest.kt b/app/src/test/java/com/owncloud/android/ui/adapter/GalleryAdapterTest.kt index 10e7f98852c1..4e52500c06df 100644 --- a/app/src/test/java/com/owncloud/android/ui/adapter/GalleryAdapterTest.kt +++ b/app/src/test/java/com/owncloud/android/ui/adapter/GalleryAdapterTest.kt @@ -12,7 +12,7 @@ import android.text.TextUtils import com.nextcloud.client.account.User import com.nextcloud.client.jobs.upload.FileUploadHelper import com.nextcloud.client.preferences.AppPreferences -import com.nextcloud.utils.thumbnail.FileThumbnailGenerator +import com.nextcloud.utils.thumbnail.ThumbnailGenerator import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.GalleryItems import com.owncloud.android.datamodel.GalleryRow @@ -59,7 +59,7 @@ class GalleryAdapterTest { lateinit var viewThemeUtils: ViewThemeUtils @Mock - lateinit var fileThumbnailGenerator: FileThumbnailGenerator + lateinit var thumbnailGenerator: ThumbnailGenerator private lateinit var mocks: AutoCloseable @@ -94,7 +94,7 @@ class GalleryAdapterTest { viewThemeUtils, 5, thumbnailSize, - fileThumbnailGenerator + thumbnailGenerator ) val list = listOf( @@ -127,7 +127,7 @@ class GalleryAdapterTest { viewThemeUtils, 5, thumbnailSize, - fileThumbnailGenerator + thumbnailGenerator ) val rows = mutableListOf() From 7492dda92bcc902ef9f20daa502ace1a3da38818 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Fri, 7 Aug 2026 10:06:28 +0200 Subject: [PATCH 16/20] fix shimmer Signed-off-by: alperozturk96 --- .../utils/thumbnail/FileThumbnailGenerator.kt | 12 +++++++++++- .../android/ui/adapter/OCFileListDelegate.kt | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/nextcloud/utils/thumbnail/FileThumbnailGenerator.kt b/app/src/main/java/com/nextcloud/utils/thumbnail/FileThumbnailGenerator.kt index 8a5e0c43b8ab..73335ca32142 100644 --- a/app/src/main/java/com/nextcloud/utils/thumbnail/FileThumbnailGenerator.kt +++ b/app/src/main/java/com/nextcloud/utils/thumbnail/FileThumbnailGenerator.kt @@ -11,6 +11,7 @@ import android.content.Context import android.graphics.Bitmap import android.graphics.Color import android.graphics.drawable.Drawable +import android.os.AsyncTask import android.widget.FrameLayout import android.widget.ImageView import androidx.core.content.ContextCompat @@ -137,6 +138,7 @@ class FileThumbnailGenerator @Inject constructor( } } + @Suppress("DEPRECATION") private fun generate(file: OCFile, view: ImageView, isGrid: Boolean, shimmer: LoaderImageView?) { if (!ThumbnailsCacheManager.cancelPotentialThumbnailWork(file, view)) { return @@ -146,7 +148,15 @@ class FileThumbnailGenerator @Inject constructor( if (cached != null) { view.setImageBitmap(cached) view.stopShimmer(shimmer) - } else if (tasks.none { it.imageKey == file.remoteId }) { + return + } + + val alreadyRunning = synchronized(tasks) { + tasks.removeAll { it.isCancelled || it.status == AsyncTask.Status.FINISHED } + tasks.any { it.imageKey == file.remoteId } + } + + if (!alreadyRunning) { startTask(file, view, isGrid, shimmer, ThumbnailGenerationTaskObject(file, file.remoteId), file.fileId) } } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt index 97b3bd9b5c3a..5dc84be9d753 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt @@ -197,7 +197,7 @@ class OCFileListDelegate( } } - thumbnailGenerator.setThumbnail(file, viewHolder.shimmerThumbnail, gridView) + thumbnailGenerator.setThumbnail(file, viewHolder.thumbnail, gridView, viewHolder.shimmerThumbnail) // item layout + click listeners bindGridItemLayout(file, viewHolder) From 235541cda3932ac1485b3f2fdb4984116e3ae99b Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Fri, 7 Aug 2026 10:29:59 +0200 Subject: [PATCH 17/20] check and set preview enable before fetching from server blindly Signed-off-by: alperozturk96 --- .../android/datamodel/ThumbnailsCacheManager.java | 8 +++++++- .../owncloud/android/operations/UploadFileOperation.java | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java b/app/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java index 3ef1340af2bc..1dd13ab23be8 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java +++ b/app/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java @@ -638,8 +638,14 @@ private Bitmap doThumbnailFromOCFileInBackground() { } } + boolean serverHasPreview = !(file instanceof OCFile) || ((OCFile) file).isPreviewAvailable(); + + if (thumbnail == null && !serverHasPreview) { + Log_OC.d(TAG, "Server reports no preview for file: " + file.getFileName()); + } + // Download thumbnail from server if still null - if (thumbnail == null && mClient != null) { + if (thumbnail == null && mClient != null && serverHasPreview) { Log_OC.d(TAG, "Attempting to download thumbnail from server for file: " + file.getFileName()); GetMethod getMethod = null; diff --git a/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java b/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java index be27f80f040c..d6a5d7461c11 100644 --- a/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java @@ -1785,6 +1785,7 @@ private void updateOCFile(OCFile file, RemoteFile remoteFile) { file.setRemoteId(remoteFile.getRemoteId()); file.setPermissions(remoteFile.getPermissions()); file.setUploadTimestamp(remoteFile.getUploadTimestamp()); + file.setPreviewAvailable(remoteFile.isHasPreview()); } public interface OnRenameListener { From ca631c7d298787976e799e8246e37a99376ee189 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Fri, 7 Aug 2026 11:00:57 +0200 Subject: [PATCH 18/20] only use extension Signed-off-by: alperozturk96 --- .../android/ui/fragment/GalleryFragmentIT.kt | 6 ++++-- .../jobs/gallery/GalleryImageGenerationJob.kt | 5 +++-- .../nextcloud/ui/fileInfo/ImageDetailInfo.kt | 3 ++- .../java/com/nextcloud/utils/ShortcutUtil.kt | 3 ++- .../utils/extensions/FileExtensions.kt | 2 ++ .../utils/thumbnail/FileThumbnailGenerator.kt | 5 +++-- .../owncloud/android/datamodel/OCFile.java | 20 +------------------ .../datamodel/ThumbnailsCacheManager.java | 10 ++++------ .../DiskLruImageCacheFileProvider.java | 2 +- .../providers/DocumentsStorageProvider.java | 3 ++- .../android/ui/activity/EditorWebView.java | 3 ++- .../android/ui/adapter/OCFileListDelegate.kt | 4 +++- .../ui/fragment/FileDetailFragment.java | 5 +++-- .../ui/preview/PreviewImageFragment.kt | 6 ++++-- 14 files changed, 36 insertions(+), 41 deletions(-) diff --git a/app/src/androidTest/java/com/owncloud/android/ui/fragment/GalleryFragmentIT.kt b/app/src/androidTest/java/com/owncloud/android/ui/fragment/GalleryFragmentIT.kt index a248b1c32d92..3a68ff53e31c 100644 --- a/app/src/androidTest/java/com/owncloud/android/ui/fragment/GalleryFragmentIT.kt +++ b/app/src/androidTest/java/com/owncloud/android/ui/fragment/GalleryFragmentIT.kt @@ -29,6 +29,8 @@ import androidx.test.espresso.matcher.ViewMatchers.isRoot import androidx.test.espresso.matcher.ViewMatchers.withId import com.nextcloud.test.Flaky import com.nextcloud.test.TestActivity +import com.nextcloud.utils.extensions.getBigThumbnail +import com.nextcloud.utils.extensions.getBigThumbnailKey import com.owncloud.android.AbstractIT import com.owncloud.android.R import com.owncloud.android.datamodel.OCFile @@ -220,9 +222,9 @@ class GalleryFragmentIT : AbstractIT() { drawRGB(random.nextInt(256), random.nextInt(256), random.nextInt(256)) drawCircle(w / 2f, h / 2f, w.coerceAtMost(h) / 2f, Paint().apply { color = Color.BLACK }) } - ThumbnailsCacheManager.addBitmapToCache(file.bigThumbnailKey, bitmap) + ThumbnailsCacheManager.addBitmapToCache(file.getBigThumbnailKey(), bitmap) - assertNotNull(file.bigThumbnail) + assertNotNull(file.getBigThumbnail()) Log_OC.d("Gallery_thumbnail", "created $id with ${bitmap.width} x ${bitmap.height}") } diff --git a/app/src/main/java/com/nextcloud/client/jobs/gallery/GalleryImageGenerationJob.kt b/app/src/main/java/com/nextcloud/client/jobs/gallery/GalleryImageGenerationJob.kt index 319424cd42f1..7baaf488154b 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/gallery/GalleryImageGenerationJob.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/gallery/GalleryImageGenerationJob.kt @@ -19,6 +19,7 @@ import androidx.core.content.ContextCompat import com.nextcloud.client.account.User import com.nextcloud.utils.extensions.getBigThumbnail import com.nextcloud.utils.extensions.getBigThumbnailKey +import com.nextcloud.utils.extensions.getSmallThumbnail import com.nextcloud.utils.extensions.isPNG import com.nextcloud.utils.extensions.toFile import com.owncloud.android.MainApp @@ -132,7 +133,7 @@ class GalleryImageGenerationJob(private val user: User, private val storageManag return@withContext applyVideoOverlayIfNeeded(file, remote) } - file.smallThumbnail?.let { small -> + file.getSmallThumbnail()?.let { small -> return@withContext applyVideoOverlayIfNeeded(file, small) } @@ -153,7 +154,7 @@ class GalleryImageGenerationJob(private val user: User, private val storageManag val pxW = p.x val pxH = p.y - val cacheKey = file.bigThumbnailKey + val cacheKey = file.getBigThumbnailKey() var bitmap = BitmapUtils.decodeSampledBitmapFromFile(file.storagePath, pxW, pxH) ?: return null diff --git a/app/src/main/java/com/nextcloud/ui/fileInfo/ImageDetailInfo.kt b/app/src/main/java/com/nextcloud/ui/fileInfo/ImageDetailInfo.kt index 245d5ecf13e7..76f5511b93aa 100644 --- a/app/src/main/java/com/nextcloud/ui/fileInfo/ImageDetailInfo.kt +++ b/app/src/main/java/com/nextcloud/ui/fileInfo/ImageDetailInfo.kt @@ -19,6 +19,7 @@ import androidx.lifecycle.lifecycleScope import com.nextcloud.android.common.ui.theme.utils.ColorRole import com.nextcloud.client.NominatimClient import com.nextcloud.ui.fileInfo.model.ImageMetadata +import com.nextcloud.utils.extensions.getSmallThumbnail import com.owncloud.android.MainApp import com.owncloud.android.R import com.owncloud.android.databinding.FileInfoFragmentBinding @@ -258,7 +259,7 @@ class ImageDetailInfo(private val fragment: FileInfoFragment, private val viewTh private fun imagePinDrawable(context: Context, file: OCFile): LayerDrawable = (ContextCompat.getDrawable(context, R.drawable.photo_pin) as LayerDrawable).apply { - val bitmap = file.smallThumbnail + val bitmap = file.getSmallThumbnail() BitmapUtils.bitmapToCircularBitmapDrawable(fragment.resources, bitmap)?.let { setDrawable(1, it) } diff --git a/app/src/main/java/com/nextcloud/utils/ShortcutUtil.kt b/app/src/main/java/com/nextcloud/utils/ShortcutUtil.kt index 8783ef79c525..e89bb9849933 100644 --- a/app/src/main/java/com/nextcloud/utils/ShortcutUtil.kt +++ b/app/src/main/java/com/nextcloud/utils/ShortcutUtil.kt @@ -22,6 +22,7 @@ import androidx.core.graphics.drawable.IconCompat import androidx.core.graphics.drawable.toBitmap import androidx.core.graphics.drawable.toDrawable import com.nextcloud.client.account.User +import com.nextcloud.utils.extensions.getSmallThumbnail import com.owncloud.android.R import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.SyncedFolderObserver @@ -83,7 +84,7 @@ class ShortcutUtil @Inject constructor(private val mContext: Context) { user: User, syncedFolderProvider: SyncedFolderProvider ): IconCompat { - val thumbnail = file.smallThumbnail + val thumbnail = file.getSmallThumbnail() return when { thumbnail != null -> IconCompat.createWithAdaptiveBitmap(bitmapToAdaptiveBitmap(thumbnail)) diff --git a/app/src/main/java/com/nextcloud/utils/extensions/FileExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/FileExtensions.kt index a3046c68d5aa..9b6afe392e17 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/FileExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/FileExtensions.kt @@ -25,6 +25,8 @@ fun OCFile?.logFileSize(tag: String) { Log_OC.d(tag, "onSaveInstanceState: $size, raw byte $rawByte") } +fun ServerFileInterface.getThumbnailKeys(): List = listOf(getBigThumbnailKey(), getSmallThumbnailKey()) + fun ServerFileInterface.getBigThumbnail(): Bitmap? = ThumbnailsCacheManager.getBitmapFromDiskCache(getBigThumbnailKey()) fun ServerFileInterface.getBigThumbnailKey(): String = ThumbnailsCacheManager.PREFIX_RESIZED_IMAGE + remoteId diff --git a/app/src/main/java/com/nextcloud/utils/thumbnail/FileThumbnailGenerator.kt b/app/src/main/java/com/nextcloud/utils/thumbnail/FileThumbnailGenerator.kt index 73335ca32142..82351d23e6a3 100644 --- a/app/src/main/java/com/nextcloud/utils/thumbnail/FileThumbnailGenerator.kt +++ b/app/src/main/java/com/nextcloud/utils/thumbnail/FileThumbnailGenerator.kt @@ -21,6 +21,7 @@ import com.elyeproj.loaderviewlibrary.LoaderImageView import com.nextcloud.client.account.UserAccountManager import com.nextcloud.client.preferences.AppPreferences import com.nextcloud.model.OfflineOperationType +import com.nextcloud.utils.extensions.getSmallThumbnail import com.nextcloud.utils.extensions.startShimmer import com.nextcloud.utils.extensions.stopShimmer import com.nextcloud.utils.extensions.toFile @@ -79,7 +80,7 @@ class FileThumbnailGenerator @Inject constructor( return } - val cached = file.smallThumbnail + val cached = file.getSmallThumbnail() if (cached == null || file.isUpdateThumbnailNeeded) { generate(file, view, isGrid, shimmer) } else { @@ -144,7 +145,7 @@ class FileThumbnailGenerator @Inject constructor( return } - val cached = file.smallThumbnail + val cached = file.getSmallThumbnail() if (cached != null) { view.setImageBitmap(cached) view.stopShimmer(shimmer) diff --git a/app/src/main/java/com/owncloud/android/datamodel/OCFile.java b/app/src/main/java/com/owncloud/android/datamodel/OCFile.java index 96f736ae9571..eac2dc488c9f 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/OCFile.java +++ b/app/src/main/java/com/owncloud/android/datamodel/OCFile.java @@ -15,14 +15,12 @@ import android.content.ContentResolver; import android.content.Context; -import android.graphics.Bitmap; import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; import com.nextcloud.utils.BuildHelper; -import com.nextcloud.utils.extensions.FileExtensionsKt; import com.nextcloud.utils.extensions.StringExtensionsKt; import com.owncloud.android.R; import com.owncloud.android.lib.common.network.WebdavEntry; @@ -34,6 +32,7 @@ import com.owncloud.android.lib.resources.shares.ShareeUser; import com.owncloud.android.lib.resources.tags.Tag; import com.owncloud.android.utils.MimeType; +import com.owncloud.android.utils.sort.AlphanumericComparator; import java.io.File; import java.util.ArrayList; @@ -44,7 +43,6 @@ import androidx.annotation.Nullable; import androidx.core.content.FileProvider; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import com.owncloud.android.utils.sort.AlphanumericComparator; public class OCFile implements Parcelable, Comparable, ServerFileInterface { @@ -817,22 +815,6 @@ public String getRemoteId() { return this.remoteId; } - public String getBigThumbnailKey() { - return FileExtensionsKt.getBigThumbnailKey(this); - } - - public Bitmap getBigThumbnail() { - return FileExtensionsKt.getBigThumbnail(this); - } - - public String getSmallThumbnailKey() { - return FileExtensionsKt.getSmallThumbnailKey(this); - } - - public Bitmap getSmallThumbnail() { - return FileExtensionsKt.getSmallThumbnail(this); - } - public boolean isUpdateThumbnailNeeded() { return this.updateThumbnailNeeded; } diff --git a/app/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java b/app/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java index 1dd13ab23be8..ce045298723d 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java +++ b/app/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java @@ -218,14 +218,12 @@ public static void removeFromCache(@Nullable OCFile file) { return; } - final var keys = new String[] { file.getBigThumbnailKey(), file.getSmallThumbnailKey() }; - synchronized (mThumbnailsDiskCacheLock) { if (mThumbnailCache == null) { return; } - for (String key: keys) { + for (String key: FileExtensionsKt.getThumbnailKeys(file)) { mThumbnailCache.removeKey(key); } } @@ -1197,7 +1195,7 @@ public static void generateResizedImage(OCFile file) { Point p = getScreenDimension(); int pxW = p.x; int pxH = p.y; - String imageKey = file.getBigThumbnailKey(); + String imageKey = FileExtensionsKt.getBigThumbnailKey(file); Bitmap bitmap = BitmapUtils.decodeSampledBitmapFromFile(file.getStoragePath(), pxW, pxH); @@ -1215,7 +1213,7 @@ public static void generateThumbnailFromOCFile(OCFile file, User user, Context c int pxW; int pxH; pxW = pxH = getThumbnailDimension(); - String imageKey = file.getSmallThumbnailKey(); + String imageKey = FileExtensionsKt.getSmallThumbnailKey(file); GetMethod getMethod = null; @@ -1282,7 +1280,7 @@ public static void setClient(OwnCloudClient client) { public static Bitmap doResizedImageInBackground(OCFile file, FileDataStorageManager storageManager) { Bitmap thumbnail; - String imageKey = file.getBigThumbnailKey(); + String imageKey = FileExtensionsKt.getBigThumbnailKey(file); // Check disk cache in background thread thumbnail = getBitmapFromDiskCache(imageKey); diff --git a/app/src/main/java/com/owncloud/android/providers/DiskLruImageCacheFileProvider.java b/app/src/main/java/com/owncloud/android/providers/DiskLruImageCacheFileProvider.java index 01fb5ff8d504..97b2f0188979 100644 --- a/app/src/main/java/com/owncloud/android/providers/DiskLruImageCacheFileProvider.java +++ b/app/src/main/java/com/owncloud/android/providers/DiskLruImageCacheFileProvider.java @@ -67,7 +67,7 @@ public static ParcelFileDescriptor getParcelFileDescriptorForOCFile(OCFile ocFil // fallback to thumbnail if (thumbnail == null) { - thumbnail = ocFile.getSmallThumbnail(); + thumbnail = FileExtensionsKt.getSmallThumbnail(ocFile); } // fallback to default image diff --git a/app/src/main/java/com/owncloud/android/providers/DocumentsStorageProvider.java b/app/src/main/java/com/owncloud/android/providers/DocumentsStorageProvider.java index e761f0c8087d..8aacf15a18b3 100644 --- a/app/src/main/java/com/owncloud/android/providers/DocumentsStorageProvider.java +++ b/app/src/main/java/com/owncloud/android/providers/DocumentsStorageProvider.java @@ -35,6 +35,7 @@ import com.nextcloud.client.preferences.AppPreferencesImpl; import com.nextcloud.client.utils.HashUtil; import com.nextcloud.utils.extensions.ContextExtensionsKt; +import com.nextcloud.utils.extensions.FileExtensionsKt; import com.nextcloud.utils.fileNameValidator.FileNameValidator; import com.owncloud.android.MainApp; import com.owncloud.android.R; @@ -382,7 +383,7 @@ public AssetFileDescriptor openDocumentThumbnail(String documentId, Document document = toDocument(documentId); OCFile file = document.getFile(); - boolean exists = ThumbnailsCacheManager.containsBitmap(file.getSmallThumbnailKey()); + boolean exists = ThumbnailsCacheManager.containsBitmap(FileExtensionsKt.getSmallThumbnailKey(file)); if (!exists) { ThumbnailsCacheManager.generateThumbnailFromOCFile(file, document.getUser(), getContext()); } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/EditorWebView.java b/app/src/main/java/com/owncloud/android/ui/activity/EditorWebView.java index 0bde1568f334..50c15d7675af 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/EditorWebView.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/EditorWebView.java @@ -24,6 +24,7 @@ import com.google.android.material.snackbar.Snackbar; import com.nextcloud.android.common.ui.theme.utils.ColorRole; import com.nextcloud.client.account.User; +import com.nextcloud.utils.extensions.FileExtensionsKt; import com.nextcloud.utils.extensions.IntentExtensionsKt; import com.owncloud.android.R; import com.owncloud.android.databinding.RichdocumentsWebviewBinding; @@ -258,7 +259,7 @@ protected void setThumbnailView(final User user) { } else { if ((MimeTypeUtil.isImage(file) || MimeTypeUtil.isVideo(file)) && file.getRemoteId() != null) { // Thumbnail in cache? - Bitmap thumbnail = file.getSmallThumbnail(); + Bitmap thumbnail = FileExtensionsKt.getSmallThumbnail(file); if (thumbnail != null && !file.isUpdateThumbnailNeeded()) { if (MimeTypeUtil.isVideo(file)) { diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt index 5dc84be9d753..64e317ad2078 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt @@ -19,6 +19,8 @@ import com.nextcloud.client.jobs.gallery.GalleryImageGenerationJob import com.nextcloud.client.jobs.gallery.GalleryImageGenerationListener import com.nextcloud.client.jobs.upload.FileUploadHelper import com.nextcloud.utils.OCFileUtils +import com.nextcloud.utils.extensions.getBigThumbnail +import com.nextcloud.utils.extensions.getSmallThumbnail import com.nextcloud.utils.extensions.makeRounded import com.nextcloud.utils.extensions.setVisibleIf import com.nextcloud.utils.extensions.stopShimmer @@ -110,7 +112,7 @@ class OCFileListDelegate( imageView.tag = file.fileId // set placeholder before async job - val cachedBitmap = file.bigThumbnail ?: file.smallThumbnail + val cachedBitmap = file.getBigThumbnail() ?: file.getSmallThumbnail() if (cachedBitmap != null) { val overlay = if (MimeTypeUtil.isVideo(file)) { ThumbnailsCacheManager.addVideoOverlay(cachedBitmap, context) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java index 015f888fbd93..c45076cd078e 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java @@ -36,6 +36,7 @@ import com.nextcloud.ui.fileactions.FileActionsBottomSheet; import com.nextcloud.utils.MenuUtils; import com.nextcloud.utils.extensions.BundleExtensionsKt; +import com.nextcloud.utils.extensions.FileExtensionsKt; import com.nextcloud.utils.mdm.MDMConfig; import com.owncloud.android.MainApp; import com.owncloud.android.R; @@ -666,14 +667,14 @@ private void setFilePreview(OCFile file) { Bitmap resizedImage; if (toolbarActivity != null && MimeTypeUtil.isImage(file)) { - resizedImage = file.getBigThumbnail(); + resizedImage = FileExtensionsKt.getBigThumbnail(file); if (resizedImage != null && !file.isUpdateThumbnailNeeded()) { toolbarActivity.setPreviewImageBitmap(resizedImage); previewLoaded = true; } else { // show thumbnail while loading resized image - Bitmap thumbnail = getFile().getSmallThumbnail(); + Bitmap thumbnail = FileExtensionsKt.getSmallThumbnail(file); if (thumbnail != null) { toolbarActivity.setPreviewImageBitmap(thumbnail); } else { diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageFragment.kt b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageFragment.kt index 96bbb52b7889..e180a0cdef07 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageFragment.kt @@ -50,7 +50,9 @@ import com.nextcloud.client.network.ConnectivityService import com.nextcloud.ui.fileactions.FileAction import com.nextcloud.ui.fileactions.FileActionsBottomSheet.Companion.newInstance import com.nextcloud.utils.extensions.clickWithDebounce +import com.nextcloud.utils.extensions.getBigThumbnailKey import com.nextcloud.utils.extensions.getParcelableArgument +import com.nextcloud.utils.extensions.getSmallThumbnail import com.owncloud.android.MainApp import com.owncloud.android.R import com.owncloud.android.databinding.PreviewImageFragmentBinding @@ -241,7 +243,7 @@ class PreviewImageFragment : binding.image.visibility = View.GONE binding.emptyListProgress.visibility = View.VISIBLE - var thumbnail = file.smallThumbnail + var thumbnail = file.getSmallThumbnail() if (thumbnail != null) { binding.shimmer.visibility = View.VISIBLE binding.shimmerThumbnail.setImageBitmap(thumbnail) @@ -317,7 +319,7 @@ class PreviewImageFragment : scaledWidth, scaledHeight ) - } catch (e: OutOfMemoryError) { + } catch (_: OutOfMemoryError) { scaledWidth /= 2 scaledHeight /= 2 } From 988b272b47fce4eba66498b3396cd83d34a66b18 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Fri, 7 Aug 2026 11:11:27 +0200 Subject: [PATCH 19/20] add doc Signed-off-by: alperozturk96 --- .../main/java/com/nextcloud/utils/extensions/FileExtensions.kt | 3 --- .../com/owncloud/android/datamodel/ThumbnailsCacheManager.java | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/nextcloud/utils/extensions/FileExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/FileExtensions.kt index 9b6afe392e17..f1a64c7b18c6 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/FileExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/FileExtensions.kt @@ -34,9 +34,6 @@ fun ServerFileInterface.getBigThumbnailKey(): String = ThumbnailsCacheManager.PR fun ServerFileInterface.getSmallThumbnail(): Bitmap? = ThumbnailsCacheManager.getBitmapFromDiskCache(getSmallThumbnailKey()) -/** - * Capped to the 512KB. - */ fun ServerFileInterface.getSmallThumbnailKey(): String = ThumbnailsCacheManager.PREFIX_THUMBNAIL + remoteId fun File?.getSmallThumbnail(): Bitmap? = ThumbnailsCacheManager.getBitmapFromDiskCache(getSmallThumbnailKey()) diff --git a/app/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java b/app/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java index ce045298723d..43fe8bb1814d 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java +++ b/app/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java @@ -90,7 +90,10 @@ public final class ThumbnailsCacheManager { private static final int READ_TIMEOUT = 40000; private static final int CONNECTION_TIMEOUT = 5000; + /** Cache key prefix {@code }; sized from {@link #getScreenDimension()}. */ public static final String PREFIX_RESIZED_IMAGE = "r"; + + /** Cache key prefix {@code }; square, sized from {@link #getThumbnailDimension()}. */ public static final String PREFIX_THUMBNAIL = "t"; private static final String TAG = ThumbnailsCacheManager.class.getSimpleName(); From 0f8aeb75fc67e29f0ab5ecdcb672d67f5ce51d6a Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 11 Aug 2026 09:04:45 +0200 Subject: [PATCH 20/20] wip Signed-off-by: alperozturk96 --- .../ui/adapter/localFileList/LocalFileThumbnailBinder.kt | 6 ++---- .../owncloud/android/ui/dialog/ConflictsResolveDialog.kt | 4 +--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/localFileList/LocalFileThumbnailBinder.kt b/app/src/main/java/com/owncloud/android/ui/adapter/localFileList/LocalFileThumbnailBinder.kt index 20d5e564c4df..5085255103b3 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/localFileList/LocalFileThumbnailBinder.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/localFileList/LocalFileThumbnailBinder.kt @@ -8,6 +8,7 @@ package com.owncloud.android.ui.adapter.localFileList import android.content.Context import android.widget.ImageView +import com.nextcloud.utils.extensions.getSmallThumbnail import com.owncloud.android.R import com.owncloud.android.datamodel.ThumbnailsCacheManager import com.owncloud.android.datamodel.ThumbnailsCacheManager.AsyncThumbnailDrawable @@ -47,10 +48,7 @@ object LocalFileThumbnailBinder { context: Context, allowedToCreateNewThumbnail: Boolean ) { - val cachedThumbnail = ThumbnailsCacheManager.getBitmapFromDiskCache( - ThumbnailsCacheManager.PREFIX_THUMBNAIL + file.hashCode() - ) - + val cachedThumbnail = file.getSmallThumbnail() when { cachedThumbnail != null -> thumbnailView.setImageBitmap(cachedThumbnail) diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/ConflictsResolveDialog.kt b/app/src/main/java/com/owncloud/android/ui/dialog/ConflictsResolveDialog.kt index ba43a10a4581..b8c65143760a 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/ConflictsResolveDialog.kt +++ b/app/src/main/java/com/owncloud/android/ui/dialog/ConflictsResolveDialog.kt @@ -21,19 +21,17 @@ import com.nextcloud.client.database.entity.OfflineOperationEntity import com.nextcloud.client.di.Injectable import com.nextcloud.utils.extensions.getParcelableArgument import com.nextcloud.utils.extensions.getSerializableArgument +import com.nextcloud.utils.thumbnail.ThumbnailGenerator import com.owncloud.android.R import com.owncloud.android.databinding.ConflictResolveDialogBinding import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.SyncedFolderProvider -import com.owncloud.android.datamodel.ThumbnailsCacheManager.ThumbnailGenerationTask -import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.ui.adapter.localFileList.LocalFileThumbnailBinder import com.owncloud.android.ui.dialog.parcel.ConflictDialogData import com.owncloud.android.ui.dialog.parcel.ConflictFileData import com.owncloud.android.utils.DisplayUtils import com.owncloud.android.utils.MimeTypeUtil -import com.nextcloud.utils.thumbnail.ThumbnailGenerator import com.owncloud.android.utils.theme.ViewThemeUtils import java.io.File import javax.inject.Inject