Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import androidx.room.Dao
import androidx.room.Query
import com.nextcloud.client.database.entity.SyncedFolderEntity
import com.owncloud.android.db.ProviderMeta
import kotlinx.coroutines.flow.Flow

@Dao
interface SyncedFolderDao {
Expand All @@ -23,4 +24,7 @@ interface SyncedFolderDao {
"""
)
fun findByLocalPathAndAccount(localPath: String, account: String): SyncedFolderEntity?

@Query("SELECT * FROM ${ProviderMeta.ProviderTableMeta.SYNCED_FOLDERS_TABLE_NAME}")
fun getAllAsFlow(): Flow<List<SyncedFolderEntity>>
}
3 changes: 2 additions & 1 deletion app/src/main/java/com/nextcloud/utils/ShortcutUtil.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import androidx.core.graphics.drawable.toDrawable
import com.nextcloud.client.account.User
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
Expand Down Expand Up @@ -91,7 +92,7 @@ class ShortcutUtil @Inject constructor(private val mContext: Context) {
thumbnail != null -> IconCompat.createWithAdaptiveBitmap(bitmapToAdaptiveBitmap(thumbnail))

file.isFolder -> {
val isAutoUploadFolder = SyncedFolderProvider.isAutoUploadFolder(syncedFolderProvider, file, user)
val isAutoUploadFolder = SyncedFolderObserver.isAutoUploadFolder(file, user)
val isDarkModeActive = syncedFolderProvider.preferences.isDarkModeEnabled
val overlayIconId = file.getFileOverlayIconId(isAutoUploadFolder)
val drawable = MimeTypeUtil.getFolderIcon(isDarkModeActive, overlayIconId, mContext, viewThemeUtils)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2026 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

package com.owncloud.android.datamodel

import com.nextcloud.client.account.User
import com.nextcloud.client.database.dao.SyncedFolderDao
import com.owncloud.android.lib.resources.files.model.ServerFileInterface
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.launch

object SyncedFolderObserver {

@Volatile
private var syncedFoldersMap = mapOf<String, Set<String>>()

private var job: Job? = null
private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())

fun start(dao: SyncedFolderDao) {
if (job?.isActive == true) return

job = scope.launch {
dao.getAllAsFlow()
.distinctUntilChanged()
.collect { updatedEntities ->
syncedFoldersMap = updatedEntities
.filter { it.remotePath != null && it.account != null }
.groupBy { it.account!! }
.mapValues { (_, entities) ->
entities.map { it.remotePath!!.trimEnd('/') }.toSet()
}
}
}
}

@Suppress("ReturnCount")
fun isAutoUploadFolder(file: ServerFileInterface, user: User): Boolean {
val accountFolders = syncedFoldersMap[user.accountName] ?: return false
val normalizedRemotePath = file.remotePath.trimEnd('/')
if (normalizedRemotePath.isEmpty()) return false
return accountFolders.any { entityPath ->
normalizedRemotePath == entityPath
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import com.owncloud.android.MainApp;
import com.owncloud.android.db.ProviderMeta;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.lib.resources.files.model.ServerFileInterface;

import java.io.File;
import java.util.ArrayList;
Expand Down Expand Up @@ -61,6 +60,7 @@ public SyncedFolderProvider(ContentResolver contentResolver, AppPreferences pref
mContentResolver = contentResolver;
this.preferences = preferences;
this.clock = clock;
SyncedFolderObserver.INSTANCE.start(dao);
}

/**
Expand All @@ -84,10 +84,6 @@ public long storeSyncedFolder(SyncedFolder syncedFolder) {
}
}

public static boolean isAutoUploadFolder(SyncedFolderProvider syncedFolderProvider, ServerFileInterface file, User user) {
return syncedFolderProvider != null && syncedFolderProvider.findByRemotePathAndAccount(file.getRemotePath(), user);
}

public int countEnabledSyncedFolders() {
int count = 0;
Cursor cursor = mContentResolver.query(
Expand Down Expand Up @@ -423,44 +419,4 @@ private ContentValues createContentValuesFromSyncedFolder(SyncedFolder syncedFol
cv.put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_LAST_SCAN_TIMESTAMP_MS, syncedFolder.getLastScanTimestampMs());
return cv;
}

/**
* method to check if sync folder for the remote path exist in table or not
*
* @param remotePath to be check
* @param user for which we are looking
* @return <code>true</code> if exist, <code>false</code> otherwise
*/
public boolean findByRemotePathAndAccount(String remotePath, User user) {
boolean result = false;

//if path ends with / then remove the last / to work the query right way
//because the sub folders of synced folders will not have the slash at the end
if (remotePath.endsWith("/")) {
remotePath = remotePath.substring(0, remotePath.length() - 1);
}

Cursor cursor = mContentResolver.query(
ProviderMeta.ProviderTableMeta.CONTENT_URI_SYNCED_FOLDERS,
null,
ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_REMOTE_PATH + " LIKE ? AND " +
ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_ACCOUNT + " =? ",
new String[]{"%" + remotePath + "%", user.getAccountName()},
null);

if (cursor != null && cursor.getCount() >= 1) {
result = true;
} else {
if (cursor == null) {
Log_OC.e(TAG, "Sync folder db cursor for remote path = " + remotePath + " in NULL.");
}
}

if (cursor != null) {
cursor.close();
}

return result;

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import com.owncloud.android.R;
import com.owncloud.android.databinding.RichdocumentsWebviewBinding;
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.asynctasks.TextEditorLoadUrlTask;
Expand Down Expand Up @@ -251,7 +252,7 @@ protected void setThumbnailView(final User user) {
// Todo minimize: only icon by mimetype
OCFile file = getFile();
if (file.isFolder()) {
boolean isAutoUploadFolder = SyncedFolderProvider.isAutoUploadFolder(syncedFolderProvider, file, user);
boolean isAutoUploadFolder = SyncedFolderObserver.INSTANCE.isAutoUploadFolder(file, user);

Integer overlayIconId = file.getFileOverlayIconId(isAutoUploadFolder);
LayerDrawable drawable = MimeTypeUtil.getFolderIcon(preferences.isDarkModeEnabled(), overlayIconId, this, viewThemeUtils);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.owncloud.android.R;
import com.owncloud.android.databinding.ShareActivityBinding;
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.lib.common.operations.RemoteOperation;
Expand Down Expand Up @@ -63,14 +64,14 @@ protected void onCreate(Bundle savedInstanceState) {

OCFile file = getFile();
Optional<User> optionalUser = getUser();
if (!optionalUser.isPresent()) {
if (optionalUser.isEmpty()) {
finish();
return;
}

// Icon
if (file.isFolder()) {
boolean isAutoUploadFolder = SyncedFolderProvider.isAutoUploadFolder(syncedFolderProvider, file, optionalUser.get());
boolean isAutoUploadFolder = SyncedFolderObserver.INSTANCE.isAutoUploadFolder(file, optionalUser.get());

Integer overlayIconId = file.getFileOverlayIconId(isAutoUploadFolder);
LayerDrawable drawable = MimeTypeUtil.getFolderIcon(preferences.isDarkModeEnabled(), overlayIconId, this, viewThemeUtils);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import com.nextcloud.client.account.User
import com.owncloud.android.databinding.UploaderListItemLayoutBinding
import com.owncloud.android.datamodel.FileDataStorageManager
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.datamodel.ThumbnailsCacheManager.AsyncThumbnailDrawable
Expand Down Expand Up @@ -112,7 +113,7 @@ class ReceiveExternalFilesAdapter(
}

private fun setupThumbnailForFolder(thumbnailImageView: ImageView, file: OCFile) {
val isAutoUploadFolder = SyncedFolderProvider.isAutoUploadFolder(syncedFolderProvider, file, user)
val isAutoUploadFolder = SyncedFolderObserver.isAutoUploadFolder(file, user)
val isDarkModeActive = syncedFolderProvider.preferences.isDarkModeEnabled
val overlayIconId = file.getFileOverlayIconId(isAutoUploadFolder)
val icon = MimeTypeUtil.getFolderIcon(isDarkModeActive, overlayIconId, context, viewThemeUtils)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
import com.owncloud.android.datamodel.ArbitraryDataProviderImpl;
import com.owncloud.android.datamodel.FileDataStorageManager;
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.lib.common.OwnCloudAccount;
Expand Down Expand Up @@ -902,7 +903,7 @@ 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 isAutoUploadFolder = SyncedFolderObserver.INSTANCE.isAutoUploadFolder(file, user);
boolean isDarkModeActive = preferences.isDarkModeEnabled();

final var overlayIconId = file.getFileOverlayIconId(isAutoUploadFolder);
Expand Down
Loading