From 13ef964855f52768c77d95f3fccd838599813075 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Fri, 9 Oct 2026 12:13:39 +0200 Subject: [PATCH] feat(file-details): previews Signed-off-by: alperozturk96 --- .../ui/fileDetail/FileDetailPreview.kt | 67 ++++++++++++++++++ .../thumbnail/FolderThumbnailGenerator.kt | 7 +- .../android/ui/activity/ToolbarActivity.java | 30 -------- .../ui/fragment/FileDetailFragment.java | 69 +++---------------- 4 files changed, 82 insertions(+), 91 deletions(-) create mode 100644 app/src/main/java/com/nextcloud/ui/fileDetail/FileDetailPreview.kt diff --git a/app/src/main/java/com/nextcloud/ui/fileDetail/FileDetailPreview.kt b/app/src/main/java/com/nextcloud/ui/fileDetail/FileDetailPreview.kt new file mode 100644 index 000000000000..fd8630800dac --- /dev/null +++ b/app/src/main/java/com/nextcloud/ui/fileDetail/FileDetailPreview.kt @@ -0,0 +1,67 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2026 Alper Ozturk + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +package com.nextcloud.ui.fileDetail + +import android.graphics.Bitmap +import android.graphics.drawable.Drawable +import android.widget.ImageView +import com.nextcloud.utils.extensions.getSmallThumbnail +import com.nextcloud.utils.thumbnail.FolderThumbnailGenerator +import com.nextcloud.utils.thumbnail.VideoOverlayGenerator +import com.owncloud.android.R +import com.owncloud.android.datamodel.OCFile +import com.owncloud.android.ui.activity.ToolbarActivity +import com.owncloud.android.utils.MimeTypeUtil +import com.owncloud.android.utils.theme.ViewThemeUtils + +class FileDetailPreview( + private val toolbarActivity: ToolbarActivity, + private val folderThumbnailGenerator: FolderThumbnailGenerator, + private val viewThemeUtils: ViewThemeUtils +) { + private val previewImageView: ImageView? = toolbarActivity.previewImageView + + fun show(file: OCFile) { + if (file.isFolder) { + setIcon(folderThumbnailGenerator.getFolderIcon(file)) + return + } + + val thumbnail = file.getSmallThumbnail() + if (thumbnail == null) { + setIcon(MimeTypeUtil.getFileTypeIcon(file.mimeType, file.fileName, toolbarActivity, viewThemeUtils)) + } else { + setImage(thumbnail.withVideoOverlay(file)) + } + } + + private fun Bitmap.withVideoOverlay(file: OCFile): Bitmap = if (MimeTypeUtil.isVideo(file)) { + VideoOverlayGenerator.addOverlay(this, toolbarActivity) + } else { + this + } + + private fun setImage(bitmap: Bitmap) { + previewImageView?.setImageBitmap(bitmap) + applyScaling(ImageView.ScaleType.CENTER_CROP, 0) + } + + private fun setIcon(icon: Drawable) { + previewImageView?.setImageDrawable(icon) + val padding = toolbarActivity.resources.getDimensionPixelSize(R.dimen.standard_double_padding) + applyScaling(ImageView.ScaleType.FIT_CENTER, padding) + } + + private fun applyScaling(scaleType: ImageView.ScaleType, padding: Int) { + previewImageView?.run { + this.scaleType = scaleType + setPadding(padding, padding, padding, padding) + } + toolbarActivity.setPreviewImageVisibility(true) + } +} 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 4e5f0547d273..5632d5d5632b 100644 --- a/app/src/main/java/com/nextcloud/utils/thumbnail/FolderThumbnailGenerator.kt +++ b/app/src/main/java/com/nextcloud/utils/thumbnail/FolderThumbnailGenerator.kt @@ -8,6 +8,7 @@ package com.nextcloud.utils.thumbnail import android.content.Context +import android.graphics.drawable.LayerDrawable import android.view.View import android.widget.ImageView import androidx.core.content.ContextCompat @@ -52,13 +53,15 @@ class FolderThumbnailGenerator @Inject constructor( if (folder == null || !folder.isFolder) return imageView.stopShimmer(loaderImageView) + imageView.setImageDrawable(getFolderIcon(folder)) + } + fun getFolderIcon(folder: OCFile): LayerDrawable { val isAutoUploadFolder = SyncedFolderObserver.isAutoUploadFolder(folder, accountManager.user) val isDarkModeActive = preferences.isDarkModeEnabled() val overlayIconId = folder.getFileOverlayIconId(isAutoUploadFolder) - val icon = MimeTypeUtil.getFolderIcon(isDarkModeActive, overlayIconId, context, viewThemeUtils) - imageView.setImageDrawable(icon) + return MimeTypeUtil.getFolderIcon(isDarkModeActive, overlayIconId, context, viewThemeUtils) } } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ToolbarActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/ToolbarActivity.java index e8628ddc6ca3..814bc39aef4a 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ToolbarActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ToolbarActivity.java @@ -15,9 +15,7 @@ import android.animation.AnimatorInflater; import android.annotation.SuppressLint; -import android.graphics.Bitmap; import android.graphics.Color; -import android.graphics.drawable.Drawable; import android.view.View; import android.widget.FrameLayout; import android.widget.ImageView; @@ -381,30 +379,6 @@ public boolean sortListGroupVisibility(){ return view.getVisibility() == View.VISIBLE; } - /** - * Change the bitmap for the toolbar's preview image. - * - * @param bitmap bitmap of the preview image - */ - public void setPreviewImageBitmap(Bitmap bitmap) { - if (mPreviewImage != null) { - mPreviewImage.setImageBitmap(bitmap); - setPreviewImageVisibility(true); - } - } - - /** - * Change the drawable for the toolbar's preview image. - * - * @param drawable drawable of the preview image - */ - public void setPreviewImageDrawable(Drawable drawable) { - if (mPreviewImage != null) { - mPreviewImage.setImageDrawable(drawable); - setPreviewImageVisibility(true); - } - } - /** * get the toolbar's preview image view. */ @@ -412,10 +386,6 @@ public ImageView getPreviewImageView() { return mPreviewImage; } - public FrameLayout getPreviewImageContainer() { - return mPreviewImageContainer; - } - public void updateToolbarSubtitle(@NonNull String subtitle) { ActionBar actionBar = getSupportActionBar(); if (actionBar != null) { 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 6115a903b305..4813eb0d44c7 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 @@ -11,7 +11,6 @@ import android.content.Context; import android.content.res.ColorStateList; -import android.graphics.Bitmap; import android.graphics.Color; import android.os.Bundle; import android.view.LayoutInflater; @@ -30,24 +29,22 @@ import com.nextcloud.client.jobs.download.FileDownloadHelper; import com.nextcloud.client.jobs.upload.FileUploadHelper; import com.nextcloud.client.network.ClientFactory; -import com.nextcloud.client.network.ConnectivityService; import com.nextcloud.client.preferences.AppPreferences; import com.nextcloud.ui.fileactions.FileAction; +import com.nextcloud.ui.fileDetail.FileDetailPreview; import com.nextcloud.ui.fileactions.FileActionsBottomSheet; import com.nextcloud.ui.tags.TagManagementBottomSheet; import com.nextcloud.utils.HumanReadableFormatter; import com.nextcloud.utils.MenuUtils; import com.nextcloud.utils.SnackbarUtil; import com.nextcloud.utils.extensions.BundleExtensionsKt; -import com.nextcloud.utils.extensions.FileExtensionsKt; import com.nextcloud.utils.mdm.MDMConfig; import com.nextcloud.utils.text.DisplayTextFormatter; -import com.owncloud.android.MainApp; +import com.nextcloud.utils.thumbnail.FolderThumbnailGenerator; import com.owncloud.android.R; import com.owncloud.android.databinding.FileDetailsFragmentBinding; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; -import com.owncloud.android.datamodel.ThumbnailsCacheManager; import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.lib.common.utils.Log_OC; @@ -110,12 +107,12 @@ public class FileDetailFragment extends FileFragment implements OnClickListener, private int activeTab; @Inject AppPreferences preferences; - @Inject ConnectivityService connectivityService; @Inject UserAccountManager accountManager; @Inject ClientFactory clientFactory; @Inject FileDataStorageManager storageManager; @Inject ViewThemeUtils viewThemeUtils; @Inject BackgroundJobManager backgroundJobManager; + @Inject FolderThumbnailGenerator folderThumbnailGenerator; /** * Public factory method to create new FileDetailFragment instances. @@ -605,17 +602,14 @@ public void updateFileDetails(boolean transferring, boolean refresh) { OCFile file = getFile(); // set file details - if (MimeTypeUtil.isImage(file)) { - binding.filename.setText(file.getFileName()); - } else { - binding.filename.setVisibility(View.GONE); - } + binding.filename.setText(file.getFileName()); binding.size.setText(HumanReadableFormatter.formatBytes(file.getFileLength())); boolean showDetailedTimestamp = preferences.isShowDetailedTimestampEnabled(); setFileModificationTimestamp(file, showDetailedTimestamp); setFilePreview(file); + binding.filename.setVisibility(previewLoaded ? View.VISIBLE : View.GONE); setFavoriteIconStatus(file.isFavorite()); // configure UI for depending upon local state of the file @@ -705,56 +699,13 @@ private boolean readyToShow() { * @param file a {@link OCFile} to be previewed */ private void setFilePreview(OCFile file) { - Bitmap resizedImage; - - if (toolbarActivity != null && MimeTypeUtil.isImage(file)) { - resizedImage = FileExtensionsKt.getBigThumbnail(file); - - if (resizedImage != null && !file.isUpdateThumbnailNeeded()) { - toolbarActivity.setPreviewImageBitmap(resizedImage); - previewLoaded = true; - } else { - // show thumbnail while loading resized image - Bitmap thumbnail = FileExtensionsKt.getSmallThumbnail(file); - if (thumbnail != null) { - toolbarActivity.setPreviewImageBitmap(thumbnail); - } else { - thumbnail = ThumbnailsCacheManager.mDefaultImg; - } - - // generate new resized image - if (ThumbnailsCacheManager.cancelPotentialThumbnailWork(getFile(), toolbarActivity.getPreviewImageView()) && - containerActivity.getStorageManager() != null) { - final ThumbnailsCacheManager.ResizedImageGenerationTask task = - new ThumbnailsCacheManager.ResizedImageGenerationTask(this, - toolbarActivity.getPreviewImageView(), - toolbarActivity.getPreviewImageContainer(), - containerActivity.getStorageManager(), - connectivityService, - containerActivity.getStorageManager().getUser(), - getResources().getColor(R.color.background_color_inverse, - requireContext().getTheme()) - ); - - if (resizedImage == null) { - resizedImage = thumbnail; - } - - final ThumbnailsCacheManager.AsyncResizedImageDrawable asyncDrawable = - new ThumbnailsCacheManager.AsyncResizedImageDrawable( - MainApp.getAppContext().getResources(), - resizedImage, - task - ); - - toolbarActivity.setPreviewImageDrawable(asyncDrawable); - previewLoaded = true; - task.execute(getFile()); - } - } - } else { + if (toolbarActivity == null) { previewLoaded = false; + return; } + + new FileDetailPreview(toolbarActivity, folderThumbnailGenerator, viewThemeUtils).show(file); + previewLoaded = true; } /**