From 5a4f6c20e0241d9e7152de53996631c46c49d384 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Wed, 18 Feb 2026 15:51:57 +0100 Subject: [PATCH 1/6] fix(unified-search): thumbnail icon Signed-off-by: alperozturk96 --- .../com/nextcloud/client/di/AppModule.java | 12 +++ .../ui/fileactions/FileActionsBottomSheet.kt | 7 +- .../TrashbinFileActionsBottomSheet.kt | 7 +- .../datamodel/SyncedFolderProvider.java | 4 + .../android/ui/adapter/OCFileListAdapter.java | 8 +- .../android/ui/adapter/OCFileListDelegate.kt | 21 ++++- .../UnifiedSearchCurrentDirItemViewHolder.kt | 7 +- .../ui/adapter/UnifiedSearchItemViewHolder.kt | 38 ++++++--- .../ui/adapter/UnifiedSearchListAdapter.kt | 16 ++-- .../ui/dialog/ConflictsResolveDialog.kt | 7 +- .../ui/fragment/OCFileListFragment.java | 5 +- .../ui/fragment/UnifiedSearchFragment.kt | 80 ++++++++++++------- .../owncloud/android/utils/DisplayUtils.java | 53 +----------- .../android/utils/overlay/OverlayManager.kt | 50 ++++++++++++ 14 files changed, 206 insertions(+), 109 deletions(-) create mode 100644 app/src/main/java/com/owncloud/android/utils/overlay/OverlayManager.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 32a0150aa0f3..58dee51ee036 100644 --- a/app/src/main/java/com/nextcloud/client/di/AppModule.java +++ b/app/src/main/java/com/nextcloud/client/di/AppModule.java @@ -57,6 +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.owncloud.android.utils.theme.ViewThemeUtils; import org.greenrobot.eventbus.EventBus; @@ -268,4 +269,15 @@ UsersAndGroupsSearchConfig userAndGroupSearchConfig() { CertificateValidator certificateValidator() { return new CertificateValidator(); } + + @Provides + @Singleton + OverlayManager overlayManager( + SyncedFolderProvider syncedFolderProvider, + AppPreferences appPreferences, + ViewThemeUtils viewThemeUtils, + Context context, + UserAccountManager accountManager) { + return new OverlayManager(syncedFolderProvider, 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 28619ed1741f..2adeecfa8359 100644 --- a/app/src/main/java/com/nextcloud/ui/fileactions/FileActionsBottomSheet.kt +++ b/app/src/main/java/com/nextcloud/ui/fileactions/FileActionsBottomSheet.kt @@ -46,6 +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.owncloud.android.utils.overlay.OverlayManager import com.owncloud.android.utils.theme.ViewThemeUtils import javax.inject.Inject @@ -68,6 +69,9 @@ class FileActionsBottomSheet : @Inject lateinit var syncedFolderProvider: SyncedFolderProvider + @Inject + lateinit var overlayManager: OverlayManager + private lateinit var viewModel: FileActionsViewModel private var _binding: FileActionsBottomSheetBinding? = null @@ -153,7 +157,8 @@ class FileActionsBottomSheet : binding.thumbnailLayout.thumbnailShimmer, syncedFolderProvider.preferences, viewThemeUtils, - syncedFolderProvider + syncedFolderProvider, + 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 82422d9e64ee..cb1c13bad955 100644 --- a/app/src/main/java/com/nextcloud/ui/trashbinFileActions/TrashbinFileActionsBottomSheet.kt +++ b/app/src/main/java/com/nextcloud/ui/trashbinFileActions/TrashbinFileActionsBottomSheet.kt @@ -35,6 +35,7 @@ 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 import com.owncloud.android.utils.theme.ViewThemeUtils import javax.inject.Inject @@ -57,6 +58,9 @@ class TrashbinFileActionsBottomSheet : @Inject lateinit var syncedFolderProvider: SyncedFolderProvider + @Inject + lateinit var overlayManager: OverlayManager + private lateinit var viewModel: TrashbinFileActionsViewModel private var _binding: FileActionsBottomSheetBinding? = null @@ -129,7 +133,8 @@ class TrashbinFileActionsBottomSheet : binding.thumbnailLayout.thumbnailShimmer, syncedFolderProvider.preferences, viewThemeUtils, - syncedFolderProvider + syncedFolderProvider, + overlayManager ) } } diff --git a/app/src/main/java/com/owncloud/android/datamodel/SyncedFolderProvider.java b/app/src/main/java/com/owncloud/android/datamodel/SyncedFolderProvider.java index ff4c00cfb269..a2fb5cb0afb4 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/SyncedFolderProvider.java +++ b/app/src/main/java/com/owncloud/android/datamodel/SyncedFolderProvider.java @@ -432,6 +432,10 @@ private ContentValues createContentValuesFromSyncedFolder(SyncedFolder syncedFol * @return true if exist, false otherwise */ public boolean findByRemotePathAndAccount(String remotePath, User user) { + if (user == null) { + return false; + } + boolean result = false; //if path ends with / then remove the last / to work the query right way 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 c93624ba352c..63b5d6951c13 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 @@ -67,6 +67,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.owncloud.android.utils.theme.CapabilityUtils; import com.owncloud.android.utils.theme.ViewThemeUtils; @@ -134,6 +135,7 @@ public class OCFileListAdapter extends RecyclerView.Adapter recommendedFiles = new ArrayList<>(); private RecommendedFilesAdapter recommendedFilesAdapter; private final OCFileListAdapterHelper helper = new OCFileListAdapterHelper(); + private final OverlayManager overlayManager; public OCFileListAdapter( Activity activity, @@ -144,7 +146,9 @@ public OCFileListAdapter( OCFileListFragmentInterface ocFileListFragmentInterface, boolean argHideItemOptions, boolean gridView, - final ViewThemeUtils viewThemeUtils) { + final ViewThemeUtils viewThemeUtils, + OverlayManager overlayManager) { + this.overlayManager = overlayManager; this.ocFileListFragmentInterface = ocFileListFragmentInterface; this.activity = activity; this.preferences = preferences; @@ -476,7 +480,7 @@ public void bindRecommendedFilesHolder(OCFileListRecommendedItemViewHolder holde } private void bindHolder(@NonNull RecyclerView.ViewHolder holder, ListViewHolder viewHolder, OCFile file) { - ocFileListDelegate.bindViewHolder(viewHolder, file, currentDirectory, searchType); + ocFileListDelegate.bindViewHolder(viewHolder, file, currentDirectory, searchType, overlayManager); 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 343659e8938a..fbc222c63a76 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,6 +37,7 @@ 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.overlay.OverlayManager import com.owncloud.android.utils.theme.ViewThemeUtils import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -175,7 +176,12 @@ class OCFileListDelegate( } } - fun setThumbnail(thumbnail: ImageView, shimmerThumbnail: LoaderImageView?, file: OCFile) { + fun setThumbnail( + thumbnail: ImageView, + shimmerThumbnail: LoaderImageView?, + file: OCFile, + overlayManager: OverlayManager + ) { DisplayUtils.setThumbnail( file, thumbnail, @@ -187,16 +193,23 @@ class OCFileListDelegate( shimmerThumbnail, preferences, viewThemeUtils, - syncFolderProvider + syncFolderProvider, + overlayManager ) } @Suppress("MagicNumber") - fun bindViewHolder(viewHolder: ListViewHolder, file: OCFile, currentDirectory: OCFile?, searchType: SearchType?) { + fun bindViewHolder( + viewHolder: ListViewHolder, + file: OCFile, + currentDirectory: OCFile?, + searchType: SearchType?, + overlayManager: OverlayManager + ) { // thumbnail viewHolder.imageFileName?.text = file.fileName viewHolder.thumbnail.tag = file.fileId - setThumbnail(viewHolder.thumbnail, viewHolder.shimmerThumbnail, file) + setThumbnail(viewHolder.thumbnail, viewHolder.shimmerThumbnail, file, overlayManager) // 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 a355cd5d4d0b..7100f9bf6367 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 @@ -20,6 +20,7 @@ import com.owncloud.android.datamodel.SyncedFolderProvider 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") @@ -32,7 +33,8 @@ class UnifiedSearchCurrentDirItemViewHolder( private val user: User, private val appPreferences: AppPreferences, private val syncedFolderProvider: SyncedFolderProvider, - private val action: UnifiedSearchCurrentDirItemAction + private val action: UnifiedSearchCurrentDirItemAction, + private val overlayManager: OverlayManager ) : SectionedViewHolder(binding.unifiedSearchCurrentDirItemLayout) { fun bind(file: OCFile) { @@ -61,7 +63,8 @@ class UnifiedSearchCurrentDirItemViewHolder( binding.thumbnailShimmer, appPreferences, viewThemeUtils, - syncedFolderProvider + syncedFolderProvider, + overlayManager ) 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 fcc8f4661f39..b311b18c1da1 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 @@ -11,6 +11,7 @@ import android.content.Context import android.view.View import com.afollestad.sectionedrecyclerview.SectionedViewHolder import com.nextcloud.android.common.ui.theme.utils.ColorRole +import com.nextcloud.client.account.User import com.nextcloud.common.NextcloudClient import com.nextcloud.model.SearchResultEntryType import com.nextcloud.utils.CalendarEventManager @@ -19,8 +20,10 @@ import com.nextcloud.utils.GlideHelper import com.nextcloud.utils.extensions.getType 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.overlay.OverlayManager import com.owncloud.android.utils.theme.ViewThemeUtils @Suppress("LongParameterList") @@ -31,12 +34,14 @@ class UnifiedSearchItemViewHolder( private val listInterface: UnifiedSearchListInterface, private val filesAction: FilesAction, val context: Context, - private val nextcloudClient: NextcloudClient, - private val viewThemeUtils: ViewThemeUtils + private val viewThemeUtils: ViewThemeUtils, + private val user: User, + private val overlayManager: OverlayManager ) : SectionedViewHolder(binding.root) { interface FilesAction { fun showFilesAction(searchResultEntry: SearchResultEntry) + fun loadFileThumbnail(searchResultEntry: SearchResultEntry, onClientReady: (NextcloudClient) -> Unit) } private val contactManager = ContactManager(context) @@ -52,16 +57,27 @@ class UnifiedSearchItemViewHolder( binding.localFileIndicator.visibility = View.GONE } - val entryType = entry.getType() viewThemeUtils.platform.colorImageView(binding.thumbnail, ColorRole.PRIMARY) - GlideHelper.loadIntoImageView( - context, - nextcloudClient, - entry.thumbnailUrl, - binding.thumbnail, - entryType.iconId(), - circleCrop = entry.rounded - ) + + val remotePath = entry.remotePath() + OCFile.PATH_SEPARATOR + val file = storageManager.getFileByDecryptedRemotePath(remotePath) + val entryType = entry.getType() + + if (file?.isFolder == true) { + // FIXME: icon is not visible + overlayManager.setFolderThumbnail(file, binding.thumbnail, binding.thumbnailShimmer) + } else { + filesAction.loadFileThumbnail(entry, onClientReady = { + GlideHelper.loadIntoImageView( + context, + it, + entry.thumbnailUrl, + binding.thumbnail, + entryType.iconId(), + circleCrop = entry.rounded + ) + }) + } if (entry.isFile) { binding.more.visibility = View.VISIBLE 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 da62218ff348..f0c91e2d7cf3 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 @@ -17,7 +17,6 @@ import com.afollestad.sectionedrecyclerview.SectionedRecyclerViewAdapter import com.afollestad.sectionedrecyclerview.SectionedViewHolder import com.nextcloud.client.account.User import com.nextcloud.client.preferences.AppPreferences -import com.nextcloud.common.NextcloudClient import com.owncloud.android.R import com.owncloud.android.databinding.UnifiedSearchCurrentDirectoryItemBinding import com.owncloud.android.databinding.UnifiedSearchEmptyBinding @@ -32,12 +31,13 @@ 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.owncloud.android.utils.theme.ViewThemeUtils /** * This Adapter populates a SectionedRecyclerView with search results by unified search */ -@Suppress("LongParameterList") +@Suppress("LongParameterList", "LongMethod") class UnifiedSearchListAdapter( private val supportsOpeningCalendarContactsLocally: Boolean, private val storageManager: FileDataStorageManager, @@ -48,8 +48,8 @@ class UnifiedSearchListAdapter( private val viewThemeUtils: ViewThemeUtils, private val appPreferences: AppPreferences, private val syncedFolderProvider: SyncedFolderProvider, - private val nextcloudClient: NextcloudClient, - private val currentDirItemAction: UnifiedSearchCurrentDirItemAction + private val currentDirItemAction: UnifiedSearchCurrentDirItemAction, + private val overlayManager: OverlayManager ) : SectionedRecyclerViewAdapter() { companion object { private const val VIEW_TYPE_EMPTY = Int.MAX_VALUE @@ -93,8 +93,9 @@ class UnifiedSearchListAdapter( listInterface, filesAction, context, - nextcloudClient, - viewThemeUtils + viewThemeUtils, + user, + overlayManager ) } @@ -110,7 +111,8 @@ class UnifiedSearchListAdapter( user, appPreferences, syncedFolderProvider, - currentDirItemAction + currentDirItemAction, + overlayManager ) } 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 522626227391..907023906334 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 @@ -33,6 +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.owncloud.android.utils.overlay.OverlayManager import com.owncloud.android.utils.theme.ViewThemeUtils import java.io.File import javax.inject.Inject @@ -63,6 +64,9 @@ class ConflictsResolveDialog : @Inject lateinit var fileDataStorageManager: FileDataStorageManager + @Inject + lateinit var overlayManager: OverlayManager + enum class Decision { CANCEL, KEEP_BOTH, @@ -232,7 +236,8 @@ class ConflictsResolveDialog : null, syncedFolderProvider.preferences, viewThemeUtils, - syncedFolderProvider + syncedFolderProvider, + overlayManager ) } 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 828aca199a55..e19b355e283e 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 @@ -114,6 +114,7 @@ import com.owncloud.android.utils.FileSortOrder; import com.owncloud.android.utils.FileStorageUtils; import com.owncloud.android.utils.PermissionUtil; +import com.owncloud.android.utils.overlay.OverlayManager; import com.owncloud.android.utils.theme.ThemeUtils; import org.apache.commons.httpclient.HttpStatus; @@ -206,6 +207,7 @@ public class OCFileListFragment extends ExtendedListFragment implements @Inject ShortcutUtil shortcutUtil; @Inject SyncedFolderProvider syncedFolderProvider; @Inject AppScanOptionalFeature appScanOptionalFeature; + @Inject OverlayManager overlayManager; protected FileFragment.ContainerActivity mContainerActivity; @@ -461,7 +463,8 @@ protected void setAdapter(Bundle args) { this, hideItemOptions, isGridViewPreferred(mFile), - viewThemeUtils + viewThemeUtils, + overlayManager ); 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 7c8bd588807f..4f94423d584b 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 @@ -36,6 +36,7 @@ import com.nextcloud.client.di.Injectable import com.nextcloud.client.di.ViewModelFactory import com.nextcloud.client.network.ClientFactory import com.nextcloud.client.preferences.AppPreferences +import com.nextcloud.common.NextcloudClient import com.nextcloud.utils.extensions.getTypedActivity import com.nextcloud.utils.extensions.searchFilesByName import com.nextcloud.utils.extensions.setVisibleIf @@ -62,6 +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.owncloud.android.utils.theme.ViewThemeUtils import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -106,6 +108,9 @@ class UnifiedSearchFragment : } } + @Inject + lateinit var overlayManager: OverlayManager + @Inject lateinit var vmFactory: ViewModelFactory @@ -133,6 +138,8 @@ class UnifiedSearchFragment : @Inject lateinit var clock: Clock + @Volatile private var client: NextcloudClient? = null + private var listOfHiddenFiles = ArrayList() private var showMoreActions = false private var currentDir: OCFile? = null @@ -371,37 +378,30 @@ class UnifiedSearchFragment : val syncedFolderProvider = SyncedFolderProvider(requireContext().contentResolver, appPreferences, clock) val gridLayoutManager = GridLayoutManager(requireContext(), 1) - lifecycleScope.launch(Dispatchers.IO) { - val client = - getTypedActivity(FileActivity::class.java)?.clientRepository?.getNextcloudClient() ?: return@launch + adapter = UnifiedSearchListAdapter( + supportsOpeningCalendarContactsLocally(), + storageManager, + this@UnifiedSearchFragment, + this@UnifiedSearchFragment, + currentAccountProvider.user, + requireContext(), + viewThemeUtils, + appPreferences, + syncedFolderProvider, + this@UnifiedSearchFragment, + overlayManager + ) + + adapter.shouldShowFooters(true) + adapter.setLayoutManager(gridLayoutManager) + binding.listRoot.layoutManager = gridLayoutManager + binding.listRoot.adapter = adapter + searchInCurrentDirectory(initialQuery ?: "") - withContext(Dispatchers.Main) { - adapter = UnifiedSearchListAdapter( - supportsOpeningCalendarContactsLocally(), - storageManager, - this@UnifiedSearchFragment, - this@UnifiedSearchFragment, - currentAccountProvider.user, - requireContext(), - viewThemeUtils, - appPreferences, - syncedFolderProvider, - client, - this@UnifiedSearchFragment - ) - - adapter.shouldShowFooters(true) - adapter.setLayoutManager(gridLayoutManager) - binding.listRoot.layoutManager = gridLayoutManager - binding.listRoot.adapter = adapter - searchInCurrentDirectory(initialQuery ?: "") - - setUpViewModel() - if (!initialQuery.isNullOrEmpty()) { - vm.setQuery(initialQuery!!) - vm.initialQuery() - } - } + setUpViewModel() + if (!initialQuery.isNullOrEmpty()) { + vm.setQuery(initialQuery!!) + vm.initialQuery() } } @@ -466,6 +466,26 @@ class UnifiedSearchFragment : vm.openResult(searchResultEntry) } + override fun loadFileThumbnail(searchResultEntry: SearchResultEntry, onClientReady: (NextcloudClient) -> Unit) { + client?.let { + onClientReady(it) + return + } + + lifecycleScope.launch(Dispatchers.IO) { + val newClient = getTypedActivity(FileActivity::class.java) + ?.clientRepository + ?.getNextcloudClient() + ?: return@launch + + client = newClient + + withContext(Dispatchers.Main) { + onClientReady(newClient) + } + } + } + override fun openFile(remotePath: String, showMoreActions: Boolean) { this.showMoreActions = showMoreActions vm.getRemoteFile(remotePath) 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 45a2a2831ee8..afd1196cbf2c 100644 --- a/app/src/main/java/com/owncloud/android/utils/DisplayUtils.java +++ b/app/src/main/java/com/owncloud/android/utils/DisplayUtils.java @@ -64,6 +64,7 @@ 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; @@ -111,12 +112,10 @@ public final class DisplayUtils { private static final String[] sizeSuffixes = {"B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"}; private static final int[] sizeScales = {0, 0, 1, 1, 1, 2, 2, 2, 2}; - private static final String MIME_TYPE_UNKNOWN = "Unknown type"; private static final String HTTP_PROTOCOL = "http://"; private static final String HTTPS_PROTOCOL = "https://"; private static final String TWITTER_HANDLE_PREFIX = "@"; - private static final int MIMETYPE_PARTS_COUNT = 2; private static final int BYTE_SIZE_DIVIDER = 1024; private static final double BYTE_SIZE_DIVIDER_DOUBLE = 1024.0; private static final int DATE_TIME_PARTS_SIZE = 2; @@ -124,7 +123,6 @@ public final class DisplayUtils { public static final String MONTH_YEAR_PATTERN = "MMMM yyyy"; public static final String MONTH_PATTERN = "MMMM"; public static final String YEAR_PATTERN = "yyyy"; - public static final int SVG_SIZE = 512; private static Map mimeType2HumanReadable; @@ -174,24 +172,6 @@ public static String bytesToHumanReadable(long bytes) { } } - /** - * Converts MIME types like "image/jpg" to more end user friendly output - * like "JPG image". - * - * @param mimetype MIME type to convert - * @return A human friendly version of the MIME type, {@link #MIME_TYPE_UNKNOWN} if it can't be converted - */ - public static String convertMIMEtoPrettyPrint(String mimetype) { - final String humanReadableMime = mimeType2HumanReadable.get(mimetype); - if (humanReadableMime != null) { - return humanReadableMime; - } - if (mimetype.split("/").length >= MIMETYPE_PARTS_COUNT) { - return mimetype.split("/")[1].toUpperCase(Locale.getDefault()) + " file"; - } - return MIME_TYPE_UNKNOWN; - } - /** * Converts Unix time to human readable format * @@ -356,21 +336,6 @@ public static CharSequence getRelativeDateTimeString(Context c, } } - /** - * Update the passed path removing the last "/" if it is not the root folder. - * - * @param path the path to be trimmed - */ - public static String getPathWithoutLastSlash(String path) { - - // Remove last slash from path - if (path.length() > 1 && path.charAt(path.length() - 1) == OCFile.PATH_SEPARATOR.charAt(0)) { - return path.substring(0, path.length() - 1); - } - - return path; - } - /** * Gets the screen size in pixels. * @@ -843,7 +808,8 @@ public static void setThumbnail(OCFile file, LoaderImageView shimmerThumbnail, AppPreferences preferences, ViewThemeUtils viewThemeUtils, - SyncedFolderProvider syncedFolderProvider) { + SyncedFolderProvider syncedFolderProvider, + OverlayManager overlayManager) { if (file == null || thumbnailView == null || context == null) { return; } @@ -854,7 +820,7 @@ public static void setThumbnail(OCFile file, } if (file.isFolder()) { - setThumbnailForFolder(file, thumbnailView, shimmerThumbnail, user, syncedFolderProvider, preferences, context, viewThemeUtils); + overlayManager.setFolderThumbnail(file, thumbnailView, shimmerThumbnail); return; } @@ -899,17 +865,6 @@ private static void setThumbnailForOfflineOperation(OCFile file, ImageView thumb } } - private static void setThumbnailForFolder(OCFile file, ImageView thumbnailView, LoaderImageView shimmerThumbnail, User user, SyncedFolderProvider syncedFolderProvider, AppPreferences preferences, Context context, ViewThemeUtils viewThemeUtils) { - stopShimmer(shimmerThumbnail, thumbnailView); - - boolean isAutoUploadFolder = SyncedFolderProvider.isAutoUploadFolder(syncedFolderProvider, file, user); - boolean isDarkModeActive = preferences.isDarkModeEnabled(); - - final var overlayIconId = file.getFileOverlayIconId(isAutoUploadFolder); - final var fileIcon = MimeTypeUtil.getFolderIcon(isDarkModeActive, overlayIconId, context, viewThemeUtils); - thumbnailView.setImageDrawable(fileIcon); - } - private 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()); if (thumbnail == null || file.isUpdateThumbnailNeeded()) { 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 new file mode 100644 index 000000000000..ef91ea580775 --- /dev/null +++ b/app/src/main/java/com/owncloud/android/utils/overlay/OverlayManager.kt @@ -0,0 +1,50 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2026 Alper Ozturk + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +package com.owncloud.android.utils.overlay + +import android.content.Context +import android.widget.ImageView +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.datamodel.OCFile +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 + +class OverlayManager @Inject constructor( + private val syncedFolderProvider: SyncedFolderProvider, + private val preferences: AppPreferences, + private val viewThemeUtils: ViewThemeUtils, + private val context: Context, + private val accountManager: UserAccountManager +) : Injectable { + + fun setFolderThumbnail(folder: OCFile?, imageView: ImageView, loaderImageView: LoaderImageView?) { + if (folder == null) { + return + } + + if (!folder.isFolder) { + return + } + + DisplayUtils.stopShimmer(loaderImageView, imageView) + + val isAutoUploadFolder = + SyncedFolderProvider.isAutoUploadFolder(syncedFolderProvider, folder, accountManager.user) + val isDarkModeActive = preferences.isDarkModeEnabled() + + val overlayIconId = folder.getFileOverlayIconId(isAutoUploadFolder) + val icon = MimeTypeUtil.getFolderIcon(isDarkModeActive, overlayIconId, context, viewThemeUtils) + imageView.setImageDrawable(icon) + } +} From 481c2b977bfa5628720765a28e0ba07ec4b66041 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Thu, 19 Feb 2026 09:08:53 +0100 Subject: [PATCH 2/6] getFileByRemotePath Signed-off-by: alperozturk96 --- .../datamodel/FileDataStorageManager.java | 11 +++++++++++ .../ui/adapter/UnifiedSearchItemViewHolder.kt | 16 +++++++++++++--- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java b/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java index 497776f6babf..a5e78636fa0d 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java +++ b/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java @@ -147,6 +147,17 @@ OCFile getFileByDecryptedRemotePath(String path) { return getFileByPath(ProviderTableMeta.FILE_PATH_DECRYPTED, path); } + @Nullable + public OCFile getFileByRemotePath(String path) { + OCFile file = getFileByDecryptedRemotePath(path); + + if (file == null) { + file = getFileByDecryptedRemotePath(path + OCFile.PATH_SEPARATOR); + } + + return file; + } + public void addCreateFileOfflineOperation(String[] localPaths, String[] remotePaths) { if (localPaths.length != remotePaths.length) { Log_OC.d(TAG, "Local path and remote path size do not match"); 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 b311b18c1da1..46f2ce587533 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 @@ -17,6 +17,7 @@ import com.nextcloud.model.SearchResultEntryType import com.nextcloud.utils.CalendarEventManager import com.nextcloud.utils.ContactManager import com.nextcloud.utils.GlideHelper +import com.nextcloud.utils.extensions.getPreviewEndpoint import com.nextcloud.utils.extensions.getType import com.owncloud.android.databinding.UnifiedSearchItemBinding import com.owncloud.android.datamodel.FileDataStorageManager @@ -59,15 +60,24 @@ class UnifiedSearchItemViewHolder( viewThemeUtils.platform.colorImageView(binding.thumbnail, ColorRole.PRIMARY) - val remotePath = entry.remotePath() + OCFile.PATH_SEPARATOR - val file = storageManager.getFileByDecryptedRemotePath(remotePath) + val file = storageManager.getFileByRemotePath(entry.remotePath()) val entryType = entry.getType() if (file?.isFolder == true) { // FIXME: icon is not visible - overlayManager.setFolderThumbnail(file, binding.thumbnail, binding.thumbnailShimmer) + overlayManager.setFolderThumbnail( + file, + binding.thumbnail, + binding.thumbnailShimmer + ) } else { filesAction.loadFileThumbnail(entry, onClientReady = { + if (binding.thumbnail.tag == entry.thumbnailUrl) { + return@loadFileThumbnail + } + + binding.thumbnail.tag = entry.thumbnailUrl + GlideHelper.loadIntoImageView( context, it, From fbf5f0bbc5a76d7704fa2816c53abbfd7ba40ceb Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Thu, 19 Feb 2026 11:19:57 +0100 Subject: [PATCH 3/6] fix icon alignment, thumbnail icon, folder overlay icon Signed-off-by: alperozturk96 --- .../ui/adapter/UnifiedSearchItemViewHolder.kt | 54 +++++++++------ .../ui/adapter/UnifiedSearchListAdapter.kt | 1 - .../android/utils/overlay/OverlayManager.kt | 65 +++++++++++++++++-- .../main/res/layout/unified_search_item.xml | 16 ++++- 4 files changed, 107 insertions(+), 29 deletions(-) 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 46f2ce587533..a0be7a709bc6 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 @@ -11,19 +11,19 @@ import android.content.Context import android.view.View import com.afollestad.sectionedrecyclerview.SectionedViewHolder import com.nextcloud.android.common.ui.theme.utils.ColorRole -import com.nextcloud.client.account.User import com.nextcloud.common.NextcloudClient import com.nextcloud.model.SearchResultEntryType import com.nextcloud.utils.CalendarEventManager import com.nextcloud.utils.ContactManager import com.nextcloud.utils.GlideHelper -import com.nextcloud.utils.extensions.getPreviewEndpoint import com.nextcloud.utils.extensions.getType +import com.nextcloud.utils.extensions.setVisibleIf +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.overlay.OverlayManager import com.owncloud.android.utils.theme.ViewThemeUtils @@ -36,7 +36,6 @@ class UnifiedSearchItemViewHolder( private val filesAction: FilesAction, val context: Context, private val viewThemeUtils: ViewThemeUtils, - private val user: User, private val overlayManager: OverlayManager ) : SectionedViewHolder(binding.root) { @@ -50,26 +49,41 @@ class UnifiedSearchItemViewHolder( fun bind(entry: SearchResultEntry) { binding.title.text = entry.title - binding.subline.text = entry.subline + bindSubline(entry) + bindLocalFileIndicator(entry) - if (entry.isFile && storageManager.getFileByDecryptedRemotePath(entry.remotePath()) != null) { - binding.localFileIndicator.visibility = View.VISIBLE + val entryType = entry.getType() + bindThumbnail(entry, entryType) + bindMoreButton(entry) + binding.unifiedSearchItemLayout.setOnClickListener { + searchEntryOnClick(entry, entryType) + } + } + + private fun bindSubline(entry: SearchResultEntry) { + if (entry.subline.isNotBlank()) { + binding.subline.visibility = View.VISIBLE + binding.subline.text = entry.subline } else { - binding.localFileIndicator.visibility = View.GONE + binding.subline.visibility = View.GONE + + val paddingInDp = context.resources.getDimension(R.dimen.standard_padding) + val paddingInPx = DisplayUtils.convertDpToPixel(paddingInDp, context) + binding.titleContainer.setPadding(0, paddingInPx, 0, 0) } + } - viewThemeUtils.platform.colorImageView(binding.thumbnail, ColorRole.PRIMARY) + private fun bindLocalFileIndicator(entry: SearchResultEntry) { + val showLocalFileIndicator = + (entry.isFile && storageManager.getFileByDecryptedRemotePath(entry.remotePath()) != null) + binding.localFileIndicator.setVisibleIf(showLocalFileIndicator) + } + private fun bindThumbnail(entry: SearchResultEntry, entryType: SearchResultEntryType) { val file = storageManager.getFileByRemotePath(entry.remotePath()) - val entryType = entry.getType() - if (file?.isFolder == true) { - // FIXME: icon is not visible - overlayManager.setFolderThumbnail( - file, - binding.thumbnail, - binding.thumbnailShimmer - ) + viewThemeUtils.platform.colorImageView(binding.thumbnail, ColorRole.PRIMARY) + overlayManager.setFolderOverlayIcon(file, binding.thumbnailOverlayIcon) } else { filesAction.loadFileThumbnail(entry, onClientReady = { if (binding.thumbnail.tag == entry.thumbnailUrl) { @@ -88,7 +102,9 @@ class UnifiedSearchItemViewHolder( ) }) } + } + private fun bindMoreButton(entry: SearchResultEntry) { if (entry.isFile) { binding.more.visibility = View.VISIBLE binding.more.setOnClickListener { @@ -97,10 +113,6 @@ class UnifiedSearchItemViewHolder( } else { binding.more.visibility = View.GONE } - - binding.unifiedSearchItemLayout.setOnClickListener { - searchEntryOnClick(entry, entryType) - } } private fun searchEntryOnClick(entry: SearchResultEntry, entryType: SearchResultEntryType) { 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 f0c91e2d7cf3..b7b3762d5326 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 @@ -94,7 +94,6 @@ class UnifiedSearchListAdapter( filesAction, context, viewThemeUtils, - user, overlayManager ) } 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 ef91ea580775..4005a3435828 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 @@ -8,7 +8,9 @@ package com.owncloud.android.utils.overlay import android.content.Context +import android.view.View import android.widget.ImageView +import androidx.core.content.ContextCompat import com.elyeproj.loaderviewlibrary.LoaderImageView import com.nextcloud.client.account.UserAccountManager import com.nextcloud.client.di.Injectable @@ -28,14 +30,65 @@ class OverlayManager @Inject constructor( private val accountManager: UserAccountManager ) : Injectable { - fun setFolderThumbnail(folder: OCFile?, imageView: ImageView, loaderImageView: LoaderImageView?) { - if (folder == null) { - return - } + /** + * Sets the overlay icon for a folder into the provided [ImageView]. + * + * The icon is only applied when: + * - The [folder] is not null + * - The [folder] represents a directory + * - A valid overlay icon resource can be resolved + * + * The overlay icon depends on whether the folder is configured + * as an auto-upload folder for the current user. + * + * @param folder The [OCFile] representing the folder. + * @param imageView The [ImageView] where the overlay icon will be displayed. + */ + fun setFolderOverlayIcon(folder: OCFile?, imageView: ImageView) { + val overlayIconId = folder + ?.takeIf { it.isFolder } + ?.let { currentFolder -> + val isAutoUploadFolder = SyncedFolderProvider.isAutoUploadFolder( + syncedFolderProvider, + currentFolder, + accountManager.user + ) + currentFolder.getFileOverlayIconId(isAutoUploadFolder) + } - if (!folder.isFolder) { - return + if (overlayIconId == null) { + imageView.visibility = View.GONE + } else { + imageView.visibility = View.VISIBLE + imageView.setImageDrawable(ContextCompat.getDrawable(context, overlayIconId)) } + } + + /** + * Sets the thumbnail for a folder into the provided [ImageView]. + * + * This method: + * - Ensures the given [folder] is not null and represents a directory. + * - Stops any active shimmer/loading animation on [loaderImageView]. + * - Resolves whether the folder is configured as an auto-upload folder + * for the current user. + * - Detects whether dark mode is currently enabled. + * - Retrieves the appropriate folder icon and overlay. + * + * The final drawable is created via `MimeTypeUtil.getFolderIcon(...)`, + * which returns a LayerDrawable. This drawable is built programmatically + * by stacking multiple layers (e.g., base folder icon + optional overlay icon) + * on top of each other, so everything is rendered inside a single [ImageView]. + * + * @param folder The [OCFile] representing the folder. + * @param imageView The [ImageView] where the composed folder thumbnail + * will be displayed. + * @param loaderImageView Optional [LoaderImageView] used for shimmer/loading + * state handling. If provided, its shimmer animation will be stopped before + * applying the final icon. + */ + fun setFolderThumbnail(folder: OCFile?, imageView: ImageView, loaderImageView: LoaderImageView?) { + if (folder == null || !folder.isFolder) return DisplayUtils.stopShimmer(loaderImageView, imageView) diff --git a/app/src/main/res/layout/unified_search_item.xml b/app/src/main/res/layout/unified_search_item.xml index 9f65a55268ca..ab8cf4038490 100755 --- a/app/src/main/res/layout/unified_search_item.xml +++ b/app/src/main/res/layout/unified_search_item.xml @@ -39,6 +39,18 @@ android:contentDescription="@null" android:src="@drawable/folder" /> + + From 495f13da07aa3c7bac64a77af5dbf36e9321716e Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Thu, 19 Feb 2026 11:32:04 +0100 Subject: [PATCH 4/6] add documentation forget getFileByRemotePath Signed-off-by: alperozturk96 --- .../owncloud/android/datamodel/FileDataStorageManager.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java b/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java index a5e78636fa0d..c999706f9fe3 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java +++ b/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java @@ -147,6 +147,13 @@ OCFile getFileByDecryptedRemotePath(String path) { return getFileByPath(ProviderTableMeta.FILE_PATH_DECRYPTED, path); } + /** + * Returns the {@link OCFile} for the given remote path. + * Tries the path as-is first; if not found, appends a trailing "/" for folders. + * + * @param path The file or folder path. + * @return The matching {@link OCFile}, or null if not found. + */ @Nullable public OCFile getFileByRemotePath(String path) { OCFile file = getFileByDecryptedRemotePath(path); From eef81659eaa8dd6918d8a1ff2883a3e66fa6216e Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Thu, 19 Feb 2026 11:41:42 +0100 Subject: [PATCH 5/6] fix spotbugs Signed-off-by: alperozturk96 --- .../ui/fileactions/FileActionsBottomSheet.kt | 1 - .../TrashbinFileActionsBottomSheet.kt | 1 - .../android/ui/adapter/OCFileListDelegate.kt | 1 - .../UnifiedSearchCurrentDirItemViewHolder.kt | 1 - .../ui/dialog/ConflictsResolveDialog.kt | 1 - .../owncloud/android/utils/DisplayUtils.java | 21 ------------------- 6 files changed, 26 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 2adeecfa8359..6ebd22edf63e 100644 --- a/app/src/main/java/com/nextcloud/ui/fileactions/FileActionsBottomSheet.kt +++ b/app/src/main/java/com/nextcloud/ui/fileactions/FileActionsBottomSheet.kt @@ -157,7 +157,6 @@ class FileActionsBottomSheet : binding.thumbnailLayout.thumbnailShimmer, syncedFolderProvider.preferences, viewThemeUtils, - syncedFolderProvider, 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 cb1c13bad955..89573ec5f443 100644 --- a/app/src/main/java/com/nextcloud/ui/trashbinFileActions/TrashbinFileActionsBottomSheet.kt +++ b/app/src/main/java/com/nextcloud/ui/trashbinFileActions/TrashbinFileActionsBottomSheet.kt @@ -133,7 +133,6 @@ class TrashbinFileActionsBottomSheet : binding.thumbnailLayout.thumbnailShimmer, syncedFolderProvider.preferences, viewThemeUtils, - syncedFolderProvider, overlayManager ) } 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 fbc222c63a76..9e2d812282cb 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 @@ -193,7 +193,6 @@ class OCFileListDelegate( shimmerThumbnail, preferences, viewThemeUtils, - syncFolderProvider, overlayManager ) } 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 7100f9bf6367..643b9fa6a840 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 @@ -63,7 +63,6 @@ class UnifiedSearchCurrentDirItemViewHolder( binding.thumbnailShimmer, appPreferences, viewThemeUtils, - syncedFolderProvider, overlayManager ) 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 907023906334..db515bb7aa30 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 @@ -236,7 +236,6 @@ class ConflictsResolveDialog : null, syncedFolderProvider.preferences, viewThemeUtils, - syncedFolderProvider, overlayManager ) } 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 afd1196cbf2c..7848e262e19e 100644 --- a/app/src/main/java/com/owncloud/android/utils/DisplayUtils.java +++ b/app/src/main/java/com/owncloud/android/utils/DisplayUtils.java @@ -57,7 +57,6 @@ import com.owncloud.android.datamodel.ArbitraryDataProviderImpl; 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.common.OwnCloudAccount; import com.owncloud.android.lib.common.utils.Log_OC; @@ -81,10 +80,8 @@ import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; -import java.util.HashMap; import java.util.List; import java.util.Locale; -import java.util.Map; import java.util.TimeZone; import androidx.annotation.NonNull; @@ -124,23 +121,6 @@ public final class DisplayUtils { public static final String MONTH_PATTERN = "MMMM"; public static final String YEAR_PATTERN = "yyyy"; - private static Map mimeType2HumanReadable; - - static { - mimeType2HumanReadable = new HashMap<>(); - // images - mimeType2HumanReadable.put("image/jpeg", "JPEG image"); - mimeType2HumanReadable.put("image/jpg", "JPEG image"); - mimeType2HumanReadable.put("image/png", "PNG image"); - mimeType2HumanReadable.put("image/bmp", "Bitmap image"); - mimeType2HumanReadable.put("image/gif", "GIF image"); - mimeType2HumanReadable.put("image/svg+xml", "JPEG image"); - mimeType2HumanReadable.put("image/tiff", "TIFF image"); - // music - mimeType2HumanReadable.put("audio/mpeg", "MP3 music file"); - mimeType2HumanReadable.put("application/ogg", "OGG music file"); - } - private DisplayUtils() { // utility class -> private constructor } @@ -808,7 +788,6 @@ public static void setThumbnail(OCFile file, LoaderImageView shimmerThumbnail, AppPreferences preferences, ViewThemeUtils viewThemeUtils, - SyncedFolderProvider syncedFolderProvider, OverlayManager overlayManager) { if (file == null || thumbnailView == null || context == null) { return; From 4d43e39922b9267e558313a91668b8bcfa5414be Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Mon, 23 Feb 2026 15:04:03 +0100 Subject: [PATCH 6/6] check url before parse Signed-off-by: alperozturk96 --- .../UnifiedSearchCurrentDirItemViewHolder.kt | 2 - .../ui/adapter/UnifiedSearchItemViewHolder.kt | 41 +++++++++++++------ .../ui/adapter/UnifiedSearchListAdapter.kt | 1 - 3 files changed, 29 insertions(+), 15 deletions(-) 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 643b9fa6a840..d34f33c80b08 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 @@ -32,7 +32,6 @@ class UnifiedSearchCurrentDirItemViewHolder( private val isRTL: Boolean, private val user: User, private val appPreferences: AppPreferences, - private val syncedFolderProvider: SyncedFolderProvider, private val action: UnifiedSearchCurrentDirItemAction, private val overlayManager: OverlayManager ) : SectionedViewHolder(binding.unifiedSearchCurrentDirItemLayout) { @@ -51,7 +50,6 @@ class UnifiedSearchCurrentDirItemViewHolder( binding.filename.text = filename } - viewThemeUtils.platform.colorImageView(binding.thumbnail, ColorRole.PRIMARY) DisplayUtils.setThumbnail( file, binding.thumbnail, 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 a0be7a709bc6..b83e9de200b6 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 @@ -22,8 +22,10 @@ import com.owncloud.android.R import com.owncloud.android.databinding.UnifiedSearchItemBinding import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.lib.common.SearchResultEntry +import com.owncloud.android.lib.common.utils.Log_OC 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 @@ -81,26 +83,41 @@ class UnifiedSearchItemViewHolder( private fun bindThumbnail(entry: SearchResultEntry, entryType: SearchResultEntryType) { val file = storageManager.getFileByRemotePath(entry.remotePath()) + if (file?.isFolder == true) { + Log_OC.d("DEBUG FOLDER", "Path: ${entry.remotePath()}, isFolder=${file.isFolder}, " + + "mime=${file?.mimeType}") + viewThemeUtils.platform.colorImageView(binding.thumbnail, ColorRole.PRIMARY) overlayManager.setFolderOverlayIcon(file, binding.thumbnailOverlayIcon) } else { - filesAction.loadFileThumbnail(entry, onClientReady = { - if (binding.thumbnail.tag == entry.thumbnailUrl) { - return@loadFileThumbnail - } + binding.thumbnail.clearColorFilter() - binding.thumbnail.tag = entry.thumbnailUrl + if (file != null) { + Log_OC.d("DEBUG FILE", "Path: ${entry.remotePath()}, isFolder=${file.isFolder}, " + + "mime=${file?.mimeType}") - GlideHelper.loadIntoImageView( + val icon = MimeTypeUtil.getFileTypeIcon( + file.mimeType, + file.fileName, context, - it, - entry.thumbnailUrl, - binding.thumbnail, - entryType.iconId(), - circleCrop = entry.rounded + viewThemeUtils ) - }) + binding.thumbnail.setImageDrawable(icon) + } else if (entry.thumbnailUrl.isNotBlank()) { + Log_OC.d("DEBUG GLIDE", "URL: " + entry.thumbnailUrl) + + filesAction.loadFileThumbnail(entry) { client -> + GlideHelper.loadIntoImageView( + context, + client, + entry.thumbnailUrl, + binding.thumbnail, + entryType.iconId(), + circleCrop = entry.rounded + ) + } + } // FIXME: Settings, Apps category } } 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 b7b3762d5326..9b97dc82a219 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 @@ -109,7 +109,6 @@ class UnifiedSearchListAdapter( isRTL, user, appPreferences, - syncedFolderProvider, currentDirItemAction, overlayManager )