From 82fc3cf217c15ae0960d8edeac2676c838881c8f Mon Sep 17 00:00:00 2001 From: JinWeiyang Date: Fri, 15 Dec 2023 23:24:48 +0800 Subject: [PATCH 01/10] add exclude hidden file or folder option when create custom media folder type Signed-off-by: JinWeiyang --- .../client/SyncedFoldersActivityIT.java | 3 +- .../android/utils/SyncedFolderUtilsTest.kt | 6 ++- .../database/entity/SyncedFolderEntity.kt | 4 +- .../android/datamodel/SyncedFolder.java | 21 ++++++-- .../datamodel/SyncedFolderDisplayItem.java | 13 +++-- .../datamodel/SyncedFolderProvider.java | 6 ++- .../com/owncloud/android/db/ProviderMeta.java | 1 + .../ui/activity/SyncedFoldersActivity.kt | 23 ++++++--- .../SyncedFolderPreferencesDialogFragment.kt | 19 ++++++- .../dialog/parcel/SyncedFolderParcelable.java | 12 +++++ .../com/owncloud/android/utils/FileUtil.java | 20 ++++++++ .../android/utils/FilesSyncHelper.java | 29 +++++++---- .../layout/synced_folders_settings_layout.xml | 51 +++++++++++++++++++ app/src/main/res/values/strings.xml | 2 + .../activity/SyncedFoldersActivityTest.java | 3 +- 15 files changed, 182 insertions(+), 31 deletions(-) diff --git a/app/src/androidTest/java/com/nextcloud/client/SyncedFoldersActivityIT.java b/app/src/androidTest/java/com/nextcloud/client/SyncedFoldersActivityIT.java index b28c89db95..6ebeaaa054 100644 --- a/app/src/androidTest/java/com/nextcloud/client/SyncedFoldersActivityIT.java +++ b/app/src/androidTest/java/com/nextcloud/client/SyncedFoldersActivityIT.java @@ -74,7 +74,8 @@ public class SyncedFoldersActivityIT extends AbstractIT { "Name", MediaFolderType.IMAGE, false, - SubFolderRule.YEAR_MONTH); + SubFolderRule.YEAR_MONTH, + false); SyncedFolderPreferencesDialogFragment sut = SyncedFolderPreferencesDialogFragment.newInstance(item, 0); Intent intent = new Intent(targetContext, SyncedFoldersActivity.class); diff --git a/app/src/androidTest/java/com/owncloud/android/utils/SyncedFolderUtilsTest.kt b/app/src/androidTest/java/com/owncloud/android/utils/SyncedFolderUtilsTest.kt index ff4ec14b05..9cd65727ad 100644 --- a/app/src/androidTest/java/com/owncloud/android/utils/SyncedFolderUtilsTest.kt +++ b/app/src/androidTest/java/com/owncloud/android/utils/SyncedFolderUtilsTest.kt @@ -187,7 +187,8 @@ class SyncedFolderUtilsTest : AbstractIT() { 0L, MediaFolderType.IMAGE, false, - SubFolderRule.YEAR_MONTH + SubFolderRule.YEAR_MONTH, + false ) Assert.assertFalse(SyncedFolderUtils.isQualifyingMediaFolder(folder)) } @@ -210,7 +211,8 @@ class SyncedFolderUtilsTest : AbstractIT() { 0L, MediaFolderType.IMAGE, false, - SubFolderRule.YEAR_MONTH + SubFolderRule.YEAR_MONTH, + false ) Assert.assertFalse(SyncedFolderUtils.isQualifyingMediaFolder(folder)) } diff --git a/app/src/main/java/com/nextcloud/client/database/entity/SyncedFolderEntity.kt b/app/src/main/java/com/nextcloud/client/database/entity/SyncedFolderEntity.kt index 5934bae96c..811cb0423d 100644 --- a/app/src/main/java/com/nextcloud/client/database/entity/SyncedFolderEntity.kt +++ b/app/src/main/java/com/nextcloud/client/database/entity/SyncedFolderEntity.kt @@ -59,5 +59,7 @@ data class SyncedFolderEntity( @ColumnInfo(name = ProviderTableMeta.SYNCED_FOLDER_HIDDEN) val hidden: Int?, @ColumnInfo(name = ProviderTableMeta.SYNCED_FOLDER_SUBFOLDER_RULE) - val subFolderRule: Int? + val subFolderRule: Int?, + @ColumnInfo(name = ProviderTableMeta.SYNCED_EXCLUDE_HIDDEN) + val excludeHidden: Int? ) diff --git a/app/src/main/java/com/owncloud/android/datamodel/SyncedFolder.java b/app/src/main/java/com/owncloud/android/datamodel/SyncedFolder.java index 4d86f435c8..17655bdc80 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/SyncedFolder.java +++ b/app/src/main/java/com/owncloud/android/datamodel/SyncedFolder.java @@ -51,6 +51,7 @@ public class SyncedFolder implements Serializable, Cloneable { private MediaFolderType type; private boolean hidden; private SubFolderRule subfolderRule; + private boolean excludeHidden; /** * constructor for new, to be persisted entity. @@ -68,6 +69,8 @@ public class SyncedFolder implements Serializable, Cloneable { * @param timestampMs the current timestamp in milliseconds * @param type the type of the folder * @param hidden hide item flag + * @param subFolderRule whether to filter subFolder by year/month/day + * @param excludeHidden exclude hidden file or folder, for {@link MediaFolderType#CUSTOM} only */ public SyncedFolder(String localPath, String remotePath, @@ -82,7 +85,8 @@ public class SyncedFolder implements Serializable, Cloneable { long timestampMs, MediaFolderType type, boolean hidden, - SubFolderRule subFolderRule) { + SubFolderRule subFolderRule, + boolean excludeHidden) { this(UNPERSISTED_ID, localPath, remotePath, @@ -97,7 +101,8 @@ public class SyncedFolder implements Serializable, Cloneable { timestampMs, type, hidden, - subFolderRule); + subFolderRule, + excludeHidden); } /** @@ -119,7 +124,8 @@ public class SyncedFolder implements Serializable, Cloneable { long timestampMs, MediaFolderType type, boolean hidden, - SubFolderRule subFolderRule) { + SubFolderRule subFolderRule, + boolean excludeHidden) { this.id = id; this.localPath = localPath; this.remotePath = remotePath; @@ -134,6 +140,7 @@ public class SyncedFolder implements Serializable, Cloneable { this.type = type; this.hidden = hidden; this.subfolderRule = subFolderRule; + this.excludeHidden = excludeHidden; } /** @@ -263,4 +270,12 @@ public class SyncedFolder implements Serializable, Cloneable { } public void setSubFolderRule(SubFolderRule subFolderRule) { this.subfolderRule = subFolderRule; } + + public boolean isExcludeHidden() { + return excludeHidden; + } + + public void setExcludeHidden(boolean excludeHidden) { + this.excludeHidden = excludeHidden; + } } diff --git a/app/src/main/java/com/owncloud/android/datamodel/SyncedFolderDisplayItem.java b/app/src/main/java/com/owncloud/android/datamodel/SyncedFolderDisplayItem.java index c8ec28197e..fe716270fe 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/SyncedFolderDisplayItem.java +++ b/app/src/main/java/com/owncloud/android/datamodel/SyncedFolderDisplayItem.java @@ -54,6 +54,7 @@ public class SyncedFolderDisplayItem extends SyncedFolder { * @param type the type of the folder * @param hidden hide item flag * @param subFolderRule whether to filter subFolder by year/month/day + * @param excludeHidden exclude hidden file or folder, for {@link MediaFolderType#CUSTOM} only */ public SyncedFolderDisplayItem(long id, String localPath, @@ -72,7 +73,8 @@ public class SyncedFolderDisplayItem extends SyncedFolder { long numberOfFiles, MediaFolderType type, boolean hidden, - SubFolderRule subFolderRule) { + SubFolderRule subFolderRule, + boolean excludeHidden) { super(id, localPath, remotePath, @@ -87,7 +89,8 @@ public class SyncedFolderDisplayItem extends SyncedFolder { timestampMs, type, hidden, - subFolderRule); + subFolderRule, + excludeHidden); this.filePaths = filePaths; this.folderName = folderName; this.numberOfFiles = numberOfFiles; @@ -108,7 +111,8 @@ public class SyncedFolderDisplayItem extends SyncedFolder { String folderName, MediaFolderType type, boolean hidden, - SubFolderRule subFolderRule) { + SubFolderRule subFolderRule, + boolean excludeHidden) { super(id, localPath, remotePath, @@ -123,7 +127,8 @@ public class SyncedFolderDisplayItem extends SyncedFolder { timestampMs, type, hidden, - subFolderRule); + subFolderRule, + excludeHidden); this.folderName = folderName; } 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 3c25f30fc9..370f5de824 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/SyncedFolderProvider.java +++ b/app/src/main/java/com/owncloud/android/datamodel/SyncedFolderProvider.java @@ -372,6 +372,8 @@ public class SyncedFolderProvider extends Observable { ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_HIDDEN)) == 1; SubFolderRule subFolderRule = SubFolderRule.values()[cursor.getInt( cursor.getColumnIndexOrThrow(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_SUBFOLDER_RULE))]; + boolean excludeHidden = cursor.getInt(cursor.getColumnIndexOrThrow( + ProviderMeta.ProviderTableMeta.SYNCED_EXCLUDE_HIDDEN)) == 1; syncedFolder = new SyncedFolder(id, @@ -388,7 +390,8 @@ public class SyncedFolderProvider extends Observable { enabledTimestampMs, type, hidden, - subFolderRule); + subFolderRule, + excludeHidden); } return syncedFolder; } @@ -417,6 +420,7 @@ public class SyncedFolderProvider extends Observable { cv.put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_TYPE, syncedFolder.getType().id); cv.put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_HIDDEN, syncedFolder.isHidden()); cv.put(ProviderMeta.ProviderTableMeta.SYNCED_FOLDER_SUBFOLDER_RULE, syncedFolder.getSubfolderRule().ordinal()); + cv.put(ProviderMeta.ProviderTableMeta.SYNCED_EXCLUDE_HIDDEN, syncedFolder.isExcludeHidden()); return cv; } diff --git a/app/src/main/java/com/owncloud/android/db/ProviderMeta.java b/app/src/main/java/com/owncloud/android/db/ProviderMeta.java index 1a4ccc5845..7340346abd 100644 --- a/app/src/main/java/com/owncloud/android/db/ProviderMeta.java +++ b/app/src/main/java/com/owncloud/android/db/ProviderMeta.java @@ -302,6 +302,7 @@ public class ProviderMeta { public static final String SYNCED_FOLDER_NAME_COLLISION_POLICY = "name_collision_policy"; public static final String SYNCED_FOLDER_HIDDEN = "hidden"; public static final String SYNCED_FOLDER_SUBFOLDER_RULE = "sub_folder_rule"; + public static final String SYNCED_EXCLUDE_HIDDEN = "exclude_hidden"; // Columns of external links table public static final String EXTERNAL_LINKS_ICON_URL = "icon_url"; diff --git a/app/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.kt index e4f3242cee..55cf725a00 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.kt @@ -403,7 +403,8 @@ class SyncedFoldersActivity : files.size.toLong(), syncedFolder.type, syncedFolder.isHidden, - syncedFolder.subfolderRule + syncedFolder.subfolderRule, + syncedFolder.isExcludeHidden ) } @@ -433,7 +434,8 @@ class SyncedFoldersActivity : mediaFolder.numberOfFiles, mediaFolder.type, syncedFolder.isHidden, - syncedFolder.subfolderRule + syncedFolder.subfolderRule, + syncedFolder.isExcludeHidden ) } @@ -462,7 +464,8 @@ class SyncedFoldersActivity : mediaFolder.numberOfFiles, mediaFolder.type, false, - SubFolderRule.YEAR_MONTH + SubFolderRule.YEAR_MONTH, + false ) } @@ -554,7 +557,8 @@ class SyncedFoldersActivity : null, MediaFolderType.CUSTOM, false, - SubFolderRule.YEAR_MONTH + SubFolderRule.YEAR_MONTH, + false ) onSyncFolderSettingsClick(0, emptyCustomFolder) } else { @@ -670,7 +674,8 @@ class SyncedFoldersActivity : File(syncedFolder.localPath).name, syncedFolder.type, syncedFolder.isHidden, - syncedFolder.subFolderRule + syncedFolder.subFolderRule, + syncedFolder.isExcludeHidden ) saveOrUpdateSyncedFolder(newCustomFolder) adapter.addSyncFolderItem(newCustomFolder) @@ -688,7 +693,8 @@ class SyncedFoldersActivity : syncedFolder.uploadAction, syncedFolder.nameCollisionPolicy.serialize(), syncedFolder.isEnabled, - syncedFolder.subFolderRule + syncedFolder.subFolderRule, + syncedFolder.isExcludeHidden ) saveOrUpdateSyncedFolder(item) @@ -759,6 +765,7 @@ class SyncedFoldersActivity : * @param uploadAction upload action * @param nameCollisionPolicy what to do on name collision * @param enabled is sync enabled + * @param excludeHidden exclude hidden file or folder, for {@link MediaFolderType#CUSTOM} only */ @Suppress("LongParameterList") private fun updateSyncedFolderItem( @@ -773,7 +780,8 @@ class SyncedFoldersActivity : uploadAction: Int, nameCollisionPolicy: Int, enabled: Boolean, - subFolderRule: SubFolderRule + subFolderRule: SubFolderRule, + excludeHidden: Boolean ) { item.id = id item.localPath = localPath @@ -786,6 +794,7 @@ class SyncedFoldersActivity : item.setNameCollisionPolicy(nameCollisionPolicy) item.setEnabled(enabled, clock.currentTime) item.setSubFolderRule(subFolderRule) + item.setExcludeHidden(excludeHidden) } override fun onRequestPermissionsResult( diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/SyncedFolderPreferencesDialogFragment.kt b/app/src/main/java/com/owncloud/android/ui/dialog/SyncedFolderPreferencesDialogFragment.kt index 90c1bb13a4..c10cc878bf 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/SyncedFolderPreferencesDialogFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/dialog/SyncedFolderPreferencesDialogFragment.kt @@ -130,12 +130,16 @@ class SyncedFolderPreferencesDialogFragment : DialogFragment(), Injectable { // hide local folder chooser and delete for non-custom folders binding.localFolderContainer.visibility = View.GONE isNeutralButtonActive = false + binding.settingInstantUploadExcludeHiddenContainer.visibility = View.GONE } else if (syncedFolder!!.id <= SyncedFolder.UNPERSISTED_ID) { isNeutralButtonActive = false // Hide delete/enabled for unpersisted custom folders binding.syncEnabled.visibility = View.GONE + // Show exclude hidden checkbox when {@link MediaFolderType#CUSTOM} + binding.settingInstantUploadExcludeHiddenContainer.visibility = View.VISIBLE + // auto set custom folder to enabled syncedFolder?.isEnabled = true @@ -146,6 +150,10 @@ class SyncedFolderPreferencesDialogFragment : DialogFragment(), Injectable { binding.btnPositive.isEnabled = false } else { binding.localFolderContainer.visibility = View.GONE + if (MediaFolderType.CUSTOM.id == syncedFolder!!.type.id) { + // Show exclude hidden checkbox when {@link MediaFolderType#CUSTOM} + binding.settingInstantUploadExcludeHiddenContainer.visibility = View.VISIBLE + } } } @@ -156,7 +164,8 @@ class SyncedFolderPreferencesDialogFragment : DialogFragment(), Injectable { binding.settingInstantUploadOnWifiCheckbox, binding.settingInstantUploadOnChargingCheckbox, binding.settingInstantUploadExistingCheckbox, - binding.settingInstantUploadPathUseSubfoldersCheckbox + binding.settingInstantUploadPathUseSubfoldersCheckbox, + binding.settingInstantUploadExcludeHiddenCheckbox ) viewThemeUtils?.material?.colorMaterialButtonPrimaryTonal(binding.btnPositive) @@ -209,6 +218,7 @@ class SyncedFolderPreferencesDialogFragment : DialogFragment(), Injectable { binding.settingInstantUploadOnChargingCheckbox.isChecked = it.isChargingOnly binding.settingInstantUploadExistingCheckbox.isChecked = it.isExisting binding.settingInstantUploadPathUseSubfoldersCheckbox.isChecked = it.isSubfolderByDate + binding.settingInstantUploadExcludeHiddenCheckbox.isChecked = it.isExcludeHidden binding.settingInstantUploadSubfolderRuleSpinner.setSelection(it.subFolderRule.ordinal) @@ -311,6 +321,8 @@ class SyncedFolderPreferencesDialogFragment : DialogFragment(), Injectable { binding.settingInstantUploadExistingContainer.alpha = alpha binding.settingInstantUploadPathUseSubfoldersContainer.isEnabled = enable binding.settingInstantUploadPathUseSubfoldersContainer.alpha = alpha + binding.settingInstantUploadExcludeHiddenContainer.isEnabled = enable + binding.settingInstantUploadExcludeHiddenContainer.alpha = alpha binding.remoteFolderContainer.isEnabled = enable binding.remoteFolderContainer.alpha = alpha binding.localFolderContainer.isEnabled = enable @@ -321,6 +333,7 @@ class SyncedFolderPreferencesDialogFragment : DialogFragment(), Injectable { binding.settingInstantUploadOnChargingCheckbox.isEnabled = enable binding.settingInstantUploadExistingCheckbox.isEnabled = enable binding.settingInstantUploadPathUseSubfoldersCheckbox.isEnabled = enable + binding.settingInstantUploadExcludeHiddenCheckbox.isEnabled = enable } checkWritableFolder() @@ -364,6 +377,10 @@ class SyncedFolderPreferencesDialogFragment : DialogFragment(), Injectable { binding.settingInstantUploadSubfolderRuleContainer.visibility = View.GONE } } + binding.settingInstantUploadExcludeHiddenContainer.setOnClickListener { + syncedFolder.isExcludeHidden = !syncedFolder.isExcludeHidden + binding.settingInstantUploadExcludeHiddenCheckbox.toggle() + } binding.settingInstantUploadSubfolderRuleSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { override fun onItemSelected(adapterView: AdapterView<*>?, view: View, i: Int, l: Long) { diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/parcel/SyncedFolderParcelable.java b/app/src/main/java/com/owncloud/android/ui/dialog/parcel/SyncedFolderParcelable.java index 24baca8850..3b9116515c 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/parcel/SyncedFolderParcelable.java +++ b/app/src/main/java/com/owncloud/android/ui/dialog/parcel/SyncedFolderParcelable.java @@ -49,6 +49,7 @@ public class SyncedFolderParcelable implements Parcelable { private String account; private int section; private SubFolderRule subFolderRule; + private boolean excludeHidden; public SyncedFolderParcelable(SyncedFolderDisplayItem syncedFolderDisplayItem, int section) { id = syncedFolderDisplayItem.getId(); @@ -68,6 +69,7 @@ public class SyncedFolderParcelable implements Parcelable { this.section = section; hidden = syncedFolderDisplayItem.isHidden(); subFolderRule = syncedFolderDisplayItem.getSubfolderRule(); + excludeHidden = syncedFolderDisplayItem.isExcludeHidden(); } private SyncedFolderParcelable(Parcel read) { @@ -87,6 +89,7 @@ public class SyncedFolderParcelable implements Parcelable { section = read.readInt(); hidden = read.readInt() != 0; subFolderRule = SubFolderRule.values()[read.readInt()]; + excludeHidden = read.readInt() != 0; } public SyncedFolderParcelable() { @@ -111,6 +114,7 @@ public class SyncedFolderParcelable implements Parcelable { dest.writeInt(section); dest.writeInt(hidden ? 1 : 0); dest.writeInt(subFolderRule.ordinal()); + dest.writeInt(excludeHidden ? 1 : 0); } public static final Creator CREATOR = @@ -279,4 +283,12 @@ public class SyncedFolderParcelable implements Parcelable { this.section = section; } public void setSubFolderRule(SubFolderRule subFolderRule) { this.subFolderRule = subFolderRule; } + + public boolean isExcludeHidden() { + return excludeHidden; + } + + public void setExcludeHidden(boolean excludeHidden) { + this.excludeHidden = excludeHidden; + } } diff --git a/app/src/main/java/com/owncloud/android/utils/FileUtil.java b/app/src/main/java/com/owncloud/android/utils/FileUtil.java index e87007152c..dd6e4b31ce 100644 --- a/app/src/main/java/com/owncloud/android/utils/FileUtil.java +++ b/app/src/main/java/com/owncloud/android/utils/FileUtil.java @@ -26,6 +26,11 @@ import android.text.TextUtils; import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.lib.resources.files.UploadFileRemoteOperation; +import org.lukhnos.nnio.file.FileVisitResult; +import org.lukhnos.nnio.file.FileVisitor; +import org.lukhnos.nnio.file.Path; +import org.lukhnos.nnio.file.impl.FileBasedPathImpl; + import java.io.File; import java.io.IOException; import java.nio.file.Files; @@ -77,4 +82,19 @@ public final class FileUtil { return null; } } + + public static Path walkFileTree(Path start, FileVisitor visitor) throws IOException { + if (org.lukhnos.nnio.file.Files.isDirectory(start)) { + org.lukhnos.nnio.file.FileVisitResult preVisitDirectoryResult = visitor.preVisitDirectory(start, null); + if (preVisitDirectoryResult == FileVisitResult.CONTINUE) { + for (File child : start.toFile().listFiles()) { + walkFileTree(FileBasedPathImpl.get(child), visitor); + } + } + visitor.postVisitDirectory(start, null); + } else { + visitor.visitFile(start, new org.lukhnos.nnio.file.attribute.BasicFileAttributes(start.toFile())); + } + return start; + } } diff --git a/app/src/main/java/com/owncloud/android/utils/FilesSyncHelper.java b/app/src/main/java/com/owncloud/android/utils/FilesSyncHelper.java index 65545ea7df..6c4b1a9fd2 100644 --- a/app/src/main/java/com/owncloud/android/utils/FilesSyncHelper.java +++ b/app/src/main/java/com/owncloud/android/utils/FilesSyncHelper.java @@ -48,7 +48,6 @@ import com.owncloud.android.db.UploadResult; import com.owncloud.android.lib.common.utils.Log_OC; import org.lukhnos.nnio.file.FileVisitResult; -import org.lukhnos.nnio.file.Files; import org.lukhnos.nnio.file.Path; import org.lukhnos.nnio.file.Paths; import org.lukhnos.nnio.file.SimpleFileVisitor; @@ -94,10 +93,14 @@ public final class FilesSyncHelper { FilesystemDataProvider filesystemDataProvider = new FilesystemDataProvider(contentResolver); Path path = Paths.get(syncedFolder.getLocalPath()); - Files.walkFileTree(path, new SimpleFileVisitor() { + FileUtil.walkFileTree(path, new SimpleFileVisitor() { @Override public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) { File file = path.toFile(); + if (syncedFolder.isExcludeHidden() && file.isHidden()) { + // exclude hidden file or folder + return FileVisitResult.CONTINUE; + } if (syncedFolder.isExisting() || attrs.lastModifiedTime().toMillis() >= enabledTimestampMs) { filesystemDataProvider.storeOrUpdateFileValue(path.toAbsolutePath().toString(), attrs.lastModifiedTime().toMillis(), @@ -107,6 +110,14 @@ public final class FilesSyncHelper { return FileVisitResult.CONTINUE; } + @Override + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { + if (syncedFolder.isExcludeHidden() && dir.compareTo(Paths.get(syncedFolder.getLocalPath())) != 0 && dir.toFile().isHidden()) { + return null; + } + return FileVisitResult.CONTINUE; + } + @Override public FileVisitResult visitFileFailed(Path file, IOException exc) { return FileVisitResult.CONTINUE; @@ -186,11 +197,10 @@ public final class FilesSyncHelper { for (OCUpload failedUpload : failedUploads) { accountExists = false; - if(!failedUpload.isWhileChargingOnly()){ + if (!failedUpload.isWhileChargingOnly()) { whileChargingOnly = false; } - if(!failedUpload.isUseWifiOnly()) - { + if (!failedUpload.isUseWifiOnly()) { useWifiOnly = false; } @@ -208,22 +218,21 @@ public final class FilesSyncHelper { } failedUploads = uploadsStorageManager.getFailedUploads(); - if(failedUploads.length == 0) - { + if (failedUploads.length == 0) { //nothing to do return; } - if(whileChargingOnly){ + if (whileChargingOnly) { final BatteryStatus batteryStatus = powerManagementService.getBattery(); final boolean charging = batteryStatus.isCharging() || batteryStatus.isFull(); - if(!charging){ + if (!charging) { //all uploads requires charging return; } } - if (useWifiOnly && !connectivityService.getConnectivity().isWifi()){ + if (useWifiOnly && !connectivityService.getConnectivity().isWifi()) { //all uploads requires wifi return; } diff --git a/app/src/main/res/layout/synced_folders_settings_layout.xml b/app/src/main/res/layout/synced_folders_settings_layout.xml index 14dc2f0d96..5c0da7dce1 100644 --- a/app/src/main/res/layout/synced_folders_settings_layout.xml +++ b/app/src/main/res/layout/synced_folders_settings_layout.xml @@ -305,6 +305,57 @@ + + + + + + + + + + + + + + + + Remote folder Use subfolders Store in subfolders based on date + Exclude hidden + Exclude hidden file or folder Subfolder options diff --git a/app/src/test/java/com/owncloud/android/ui/activity/SyncedFoldersActivityTest.java b/app/src/test/java/com/owncloud/android/ui/activity/SyncedFoldersActivityTest.java index 37602cdd84..ddad4103a6 100644 --- a/app/src/test/java/com/owncloud/android/ui/activity/SyncedFoldersActivityTest.java +++ b/app/src/test/java/com/owncloud/android/ui/activity/SyncedFoldersActivityTest.java @@ -178,6 +178,7 @@ public class SyncedFoldersActivityTest { 2, MediaFolderType.IMAGE, false, - SubFolderRule.YEAR_MONTH); + SubFolderRule.YEAR_MONTH, + true); } } From cc480e49c95f53505d5e5934deae4db49fee73e8 Mon Sep 17 00:00:00 2001 From: JinWeiyang Date: Wed, 17 Jan 2024 23:26:25 +0800 Subject: [PATCH 02/10] [feature] update db Signed-off-by: JinWeiyang --- .../java/com/nextcloud/client/database/NextcloudDatabase.kt | 3 ++- app/src/main/java/com/owncloud/android/db/ProviderMeta.java | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/database/NextcloudDatabase.kt b/app/src/main/java/com/nextcloud/client/database/NextcloudDatabase.kt index 5f3e16a036..70a95c9797 100644 --- a/app/src/main/java/com/nextcloud/client/database/NextcloudDatabase.kt +++ b/app/src/main/java/com/nextcloud/client/database/NextcloudDatabase.kt @@ -70,7 +70,8 @@ import com.owncloud.android.db.ProviderMeta AutoMigration(from = 73, to = 74, spec = DatabaseMigrationUtil.ResetCapabilitiesPostMigration::class), AutoMigration(from = 74, to = 75), AutoMigration(from = 75, to = 76), - AutoMigration(from = 76, to = 77) + AutoMigration(from = 76, to = 77), + AutoMigration(from = 77, to = 78), ], exportSchema = true ) diff --git a/app/src/main/java/com/owncloud/android/db/ProviderMeta.java b/app/src/main/java/com/owncloud/android/db/ProviderMeta.java index 7340346abd..6d2f72438f 100644 --- a/app/src/main/java/com/owncloud/android/db/ProviderMeta.java +++ b/app/src/main/java/com/owncloud/android/db/ProviderMeta.java @@ -35,7 +35,7 @@ import java.util.List; */ public class ProviderMeta { public static final String DB_NAME = "filelist"; - public static final int DB_VERSION = 77; + public static final int DB_VERSION = 78; private ProviderMeta() { // No instance From 4cc92354eacdf0a98a76b6ac2b997180c120c887 Mon Sep 17 00:00:00 2001 From: JinWeiyang Date: Wed, 17 Jan 2024 23:33:22 +0800 Subject: [PATCH 03/10] [feature] update db Signed-off-by: JinWeiyang --- .../78.json | 1197 +++++++++++++++++ 1 file changed, 1197 insertions(+) create mode 100644 app/schemas/com.nextcloud.client.database.NextcloudDatabase/78.json diff --git a/app/schemas/com.nextcloud.client.database.NextcloudDatabase/78.json b/app/schemas/com.nextcloud.client.database.NextcloudDatabase/78.json new file mode 100644 index 0000000000..21af9f58d8 --- /dev/null +++ b/app/schemas/com.nextcloud.client.database.NextcloudDatabase/78.json @@ -0,0 +1,1197 @@ +{ + "formatVersion": 1, + "database": { + "version": 78, + "identityHash": "f26afed3b9b87a3acb578947a26223ac", + "entities": [ + { + "tableName": "arbitrary_data", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `cloud_id` TEXT, `key` TEXT, `value` TEXT)", + "fields": [ + { + "fieldPath": "id", + "columnName": "_id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "cloudId", + "columnName": "cloud_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "key", + "columnName": "key", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "value", + "columnName": "value", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "capabilities", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `account` TEXT, `version_mayor` INTEGER, `version_minor` INTEGER, `version_micro` INTEGER, `version_string` TEXT, `version_edition` TEXT, `extended_support` INTEGER, `core_pollinterval` INTEGER, `sharing_api_enabled` INTEGER, `sharing_public_enabled` INTEGER, `sharing_public_password_enforced` INTEGER, `sharing_public_expire_date_enabled` INTEGER, `sharing_public_expire_date_days` INTEGER, `sharing_public_expire_date_enforced` INTEGER, `sharing_public_send_mail` INTEGER, `sharing_public_upload` INTEGER, `sharing_user_send_mail` INTEGER, `sharing_resharing` INTEGER, `sharing_federation_outgoing` INTEGER, `sharing_federation_incoming` INTEGER, `files_bigfilechunking` INTEGER, `files_undelete` INTEGER, `files_versioning` INTEGER, `external_links` INTEGER, `server_name` TEXT, `server_color` TEXT, `server_text_color` TEXT, `server_element_color` TEXT, `server_slogan` TEXT, `server_logo` TEXT, `background_url` TEXT, `end_to_end_encryption` INTEGER, `end_to_end_encryption_keys_exist` INTEGER, `end_to_end_encryption_api_version` TEXT, `activity` INTEGER, `background_default` INTEGER, `background_plain` INTEGER, `richdocument` INTEGER, `richdocument_mimetype_list` TEXT, `richdocument_direct_editing` INTEGER, `richdocument_direct_templates` INTEGER, `richdocument_optional_mimetype_list` TEXT, `sharing_public_ask_for_optional_password` INTEGER, `richdocument_product_name` TEXT, `direct_editing_etag` TEXT, `user_status` INTEGER, `user_status_supports_emoji` INTEGER, `etag` TEXT, `files_locking_version` TEXT, `groupfolders` INTEGER, `drop_account` INTEGER, `security_guard` INTEGER)", + "fields": [ + { + "fieldPath": "id", + "columnName": "_id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "accountName", + "columnName": "account", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "versionMajor", + "columnName": "version_mayor", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "versionMinor", + "columnName": "version_minor", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "versionMicro", + "columnName": "version_micro", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "versionString", + "columnName": "version_string", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "versionEditor", + "columnName": "version_edition", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "extendedSupport", + "columnName": "extended_support", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "corePollinterval", + "columnName": "core_pollinterval", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "sharingApiEnabled", + "columnName": "sharing_api_enabled", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "sharingPublicEnabled", + "columnName": "sharing_public_enabled", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "sharingPublicPasswordEnforced", + "columnName": "sharing_public_password_enforced", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "sharingPublicExpireDateEnabled", + "columnName": "sharing_public_expire_date_enabled", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "sharingPublicExpireDateDays", + "columnName": "sharing_public_expire_date_days", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "sharingPublicExpireDateEnforced", + "columnName": "sharing_public_expire_date_enforced", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "sharingPublicSendMail", + "columnName": "sharing_public_send_mail", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "sharingPublicUpload", + "columnName": "sharing_public_upload", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "sharingUserSendMail", + "columnName": "sharing_user_send_mail", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "sharingResharing", + "columnName": "sharing_resharing", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "sharingFederationOutgoing", + "columnName": "sharing_federation_outgoing", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "sharingFederationIncoming", + "columnName": "sharing_federation_incoming", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "filesBigfilechunking", + "columnName": "files_bigfilechunking", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "filesUndelete", + "columnName": "files_undelete", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "filesVersioning", + "columnName": "files_versioning", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "externalLinks", + "columnName": "external_links", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "serverName", + "columnName": "server_name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "serverColor", + "columnName": "server_color", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "serverTextColor", + "columnName": "server_text_color", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "serverElementColor", + "columnName": "server_element_color", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "serverSlogan", + "columnName": "server_slogan", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "serverLogo", + "columnName": "server_logo", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "serverBackgroundUrl", + "columnName": "background_url", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "endToEndEncryption", + "columnName": "end_to_end_encryption", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "endToEndEncryptionKeysExist", + "columnName": "end_to_end_encryption_keys_exist", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "endToEndEncryptionApiVersion", + "columnName": "end_to_end_encryption_api_version", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "activity", + "columnName": "activity", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "serverBackgroundDefault", + "columnName": "background_default", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "serverBackgroundPlain", + "columnName": "background_plain", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "richdocument", + "columnName": "richdocument", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "richdocumentMimetypeList", + "columnName": "richdocument_mimetype_list", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "richdocumentDirectEditing", + "columnName": "richdocument_direct_editing", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "richdocumentTemplates", + "columnName": "richdocument_direct_templates", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "richdocumentOptionalMimetypeList", + "columnName": "richdocument_optional_mimetype_list", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "sharingPublicAskForOptionalPassword", + "columnName": "sharing_public_ask_for_optional_password", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "richdocumentProductName", + "columnName": "richdocument_product_name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "directEditingEtag", + "columnName": "direct_editing_etag", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "userStatus", + "columnName": "user_status", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "userStatusSupportsEmoji", + "columnName": "user_status_supports_emoji", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "etag", + "columnName": "etag", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "filesLockingVersion", + "columnName": "files_locking_version", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "groupfolders", + "columnName": "groupfolders", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "dropAccount", + "columnName": "drop_account", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "securityGuard", + "columnName": "security_guard", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "external_links", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `icon_url` TEXT, `language` TEXT, `type` INTEGER, `name` TEXT, `url` TEXT, `redirect` INTEGER)", + "fields": [ + { + "fieldPath": "id", + "columnName": "_id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "iconUrl", + "columnName": "icon_url", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "language", + "columnName": "language", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "redirect", + "columnName": "redirect", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "filelist", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `filename` TEXT, `encrypted_filename` TEXT, `path` TEXT, `path_decrypted` TEXT, `parent` INTEGER, `created` INTEGER, `modified` INTEGER, `content_type` TEXT, `content_length` INTEGER, `media_path` TEXT, `file_owner` TEXT, `last_sync_date` INTEGER, `last_sync_date_for_data` INTEGER, `modified_at_last_sync_for_data` INTEGER, `etag` TEXT, `etag_on_server` TEXT, `share_by_link` INTEGER, `permissions` TEXT, `remote_id` TEXT, `local_id` INTEGER NOT NULL DEFAULT -1, `update_thumbnail` INTEGER, `is_downloading` INTEGER, `favorite` INTEGER, `hidden` INTEGER, `is_encrypted` INTEGER, `etag_in_conflict` TEXT, `shared_via_users` INTEGER, `mount_type` INTEGER, `has_preview` INTEGER, `unread_comments_count` INTEGER, `owner_id` TEXT, `owner_display_name` TEXT, `note` TEXT, `sharees` TEXT, `rich_workspace` TEXT, `metadata_size` TEXT, `metadata_live_photo` TEXT, `locked` INTEGER, `lock_type` INTEGER, `lock_owner` TEXT, `lock_owner_display_name` TEXT, `lock_owner_editor` TEXT, `lock_timestamp` INTEGER, `lock_timeout` INTEGER, `lock_token` TEXT, `tags` TEXT, `metadata_gps` TEXT, `e2e_counter` INTEGER)", + "fields": [ + { + "fieldPath": "id", + "columnName": "_id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "name", + "columnName": "filename", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "encryptedName", + "columnName": "encrypted_filename", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "path", + "columnName": "path", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "pathDecrypted", + "columnName": "path_decrypted", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "parent", + "columnName": "parent", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "creation", + "columnName": "created", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "modified", + "columnName": "modified", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "contentType", + "columnName": "content_type", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "contentLength", + "columnName": "content_length", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "storagePath", + "columnName": "media_path", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "accountOwner", + "columnName": "file_owner", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "lastSyncDate", + "columnName": "last_sync_date", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "lastSyncDateForData", + "columnName": "last_sync_date_for_data", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "modifiedAtLastSyncForData", + "columnName": "modified_at_last_sync_for_data", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "etag", + "columnName": "etag", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "etagOnServer", + "columnName": "etag_on_server", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "sharedViaLink", + "columnName": "share_by_link", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "permissions", + "columnName": "permissions", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "remoteId", + "columnName": "remote_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "localId", + "columnName": "local_id", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "-1" + }, + { + "fieldPath": "updateThumbnail", + "columnName": "update_thumbnail", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "isDownloading", + "columnName": "is_downloading", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "favorite", + "columnName": "favorite", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "hidden", + "columnName": "hidden", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "isEncrypted", + "columnName": "is_encrypted", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "etagInConflict", + "columnName": "etag_in_conflict", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "sharedWithSharee", + "columnName": "shared_via_users", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "mountType", + "columnName": "mount_type", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "hasPreview", + "columnName": "has_preview", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "unreadCommentsCount", + "columnName": "unread_comments_count", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "ownerId", + "columnName": "owner_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "ownerDisplayName", + "columnName": "owner_display_name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "note", + "columnName": "note", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "sharees", + "columnName": "sharees", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "richWorkspace", + "columnName": "rich_workspace", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "metadataSize", + "columnName": "metadata_size", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "metadataLivePhoto", + "columnName": "metadata_live_photo", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "locked", + "columnName": "locked", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "lockType", + "columnName": "lock_type", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "lockOwner", + "columnName": "lock_owner", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "lockOwnerDisplayName", + "columnName": "lock_owner_display_name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "lockOwnerEditor", + "columnName": "lock_owner_editor", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "lockTimestamp", + "columnName": "lock_timestamp", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "lockTimeout", + "columnName": "lock_timeout", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "lockToken", + "columnName": "lock_token", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "tags", + "columnName": "tags", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "metadataGPS", + "columnName": "metadata_gps", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "e2eCounter", + "columnName": "e2e_counter", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "filesystem", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `local_path` TEXT, `is_folder` INTEGER, `found_at` INTEGER, `upload_triggered` INTEGER, `syncedfolder_id` TEXT, `crc32` TEXT, `modified_at` INTEGER)", + "fields": [ + { + "fieldPath": "id", + "columnName": "_id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "localPath", + "columnName": "local_path", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "fileIsFolder", + "columnName": "is_folder", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "fileFoundRecently", + "columnName": "found_at", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "fileSentForUpload", + "columnName": "upload_triggered", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "syncedFolderId", + "columnName": "syncedfolder_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "crc32", + "columnName": "crc32", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "fileModified", + "columnName": "modified_at", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "ocshares", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `file_source` INTEGER, `item_source` INTEGER, `share_type` INTEGER, `shate_with` TEXT, `path` TEXT, `permissions` INTEGER, `shared_date` INTEGER, `expiration_date` INTEGER, `token` TEXT, `shared_with_display_name` TEXT, `is_directory` INTEGER, `user_id` INTEGER, `id_remote_shared` INTEGER, `owner_share` TEXT, `is_password_protected` INTEGER, `note` TEXT, `hide_download` INTEGER, `share_link` TEXT, `share_label` TEXT)", + "fields": [ + { + "fieldPath": "id", + "columnName": "_id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "fileSource", + "columnName": "file_source", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "itemSource", + "columnName": "item_source", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "shareType", + "columnName": "share_type", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "shareWith", + "columnName": "shate_with", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "path", + "columnName": "path", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "permissions", + "columnName": "permissions", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "sharedDate", + "columnName": "shared_date", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "expirationDate", + "columnName": "expiration_date", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "token", + "columnName": "token", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "shareWithDisplayName", + "columnName": "shared_with_display_name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "isDirectory", + "columnName": "is_directory", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "userId", + "columnName": "user_id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "idRemoteShared", + "columnName": "id_remote_shared", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "accountOwner", + "columnName": "owner_share", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "isPasswordProtected", + "columnName": "is_password_protected", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "note", + "columnName": "note", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "hideDownload", + "columnName": "hide_download", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "shareLink", + "columnName": "share_link", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "shareLabel", + "columnName": "share_label", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "synced_folders", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `local_path` TEXT, `remote_path` TEXT, `wifi_only` INTEGER, `charging_only` INTEGER, `existing` INTEGER, `enabled` INTEGER, `enabled_timestamp_ms` INTEGER, `subfolder_by_date` INTEGER, `account` TEXT, `upload_option` INTEGER, `name_collision_policy` INTEGER, `type` INTEGER, `hidden` INTEGER, `sub_folder_rule` INTEGER, `exclude_hidden` INTEGER)", + "fields": [ + { + "fieldPath": "id", + "columnName": "_id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "localPath", + "columnName": "local_path", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "remotePath", + "columnName": "remote_path", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "wifiOnly", + "columnName": "wifi_only", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "chargingOnly", + "columnName": "charging_only", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "existing", + "columnName": "existing", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "enabled", + "columnName": "enabled", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "enabledTimestampMs", + "columnName": "enabled_timestamp_ms", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "subfolderByDate", + "columnName": "subfolder_by_date", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "account", + "columnName": "account", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "uploadAction", + "columnName": "upload_option", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "nameCollisionPolicy", + "columnName": "name_collision_policy", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "hidden", + "columnName": "hidden", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "subFolderRule", + "columnName": "sub_folder_rule", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "excludeHidden", + "columnName": "exclude_hidden", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "list_of_uploads", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `local_path` TEXT, `remote_path` TEXT, `account_name` TEXT, `file_size` INTEGER, `status` INTEGER, `local_behaviour` INTEGER, `upload_time` INTEGER, `name_collision_policy` INTEGER, `is_create_remote_folder` INTEGER, `upload_end_timestamp` INTEGER, `last_result` INTEGER, `is_while_charging_only` INTEGER, `is_wifi_only` INTEGER, `created_by` INTEGER, `folder_unlock_token` TEXT)", + "fields": [ + { + "fieldPath": "id", + "columnName": "_id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "localPath", + "columnName": "local_path", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "remotePath", + "columnName": "remote_path", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "accountName", + "columnName": "account_name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "fileSize", + "columnName": "file_size", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "localBehaviour", + "columnName": "local_behaviour", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "uploadTime", + "columnName": "upload_time", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "nameCollisionPolicy", + "columnName": "name_collision_policy", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "isCreateRemoteFolder", + "columnName": "is_create_remote_folder", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "uploadEndTimestamp", + "columnName": "upload_end_timestamp", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "lastResult", + "columnName": "last_result", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "isWhileChargingOnly", + "columnName": "is_while_charging_only", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "isWifiOnly", + "columnName": "is_wifi_only", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "createdBy", + "columnName": "created_by", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "folderUnlockToken", + "columnName": "folder_unlock_token", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "_id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "virtual", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `type` TEXT, `ocfile_id` INTEGER)", + "fields": [ + { + "fieldPath": "id", + "columnName": "_id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "ocFileId", + "columnName": "ocfile_id", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "_id" + ] + }, + "indices": [], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'f26afed3b9b87a3acb578947a26223ac')" + ] + } +} \ No newline at end of file From beaeb99dd4004b604c4e26c721d17d87b87d73a8 Mon Sep 17 00:00:00 2001 From: JinWeiyang Date: Sun, 28 Jan 2024 18:53:36 +0800 Subject: [PATCH 04/10] Update app/src/main/res/values/strings.xml Co-authored-by: Jan C. Borchardt <925062+jancborchardt@users.noreply.github.com> Signed-off-by: JinWeiyang --- app/src/main/res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 48c88c3686..275d65f207 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -369,7 +369,7 @@ Use subfolders Store in subfolders based on date Exclude hidden - Exclude hidden file or folder + Exclude hidden files and folders Subfolder options From 4b20f26774dbad2305f64cdee239fd811558ed20 Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Sun, 11 Feb 2024 14:57:58 +0100 Subject: [PATCH 05/10] Fix formatting Signed-off-by: Andy Scherzinger --- .../java/com/nextcloud/client/database/NextcloudDatabase.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/client/database/NextcloudDatabase.kt b/app/src/main/java/com/nextcloud/client/database/NextcloudDatabase.kt index 70a95c9797..57560286dd 100644 --- a/app/src/main/java/com/nextcloud/client/database/NextcloudDatabase.kt +++ b/app/src/main/java/com/nextcloud/client/database/NextcloudDatabase.kt @@ -71,7 +71,7 @@ import com.owncloud.android.db.ProviderMeta AutoMigration(from = 74, to = 75), AutoMigration(from = 75, to = 76), AutoMigration(from = 76, to = 77), - AutoMigration(from = 77, to = 78), + AutoMigration(from = 77, to = 78) ], exportSchema = true ) From 9f43823bba810da80f7a61a7551b107ed556b25f Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Sun, 11 Feb 2024 16:13:41 +0100 Subject: [PATCH 06/10] Suppress "TooGenericExceptionCaught" Signed-off-by: Andy Scherzinger --- app/src/main/java/com/owncloud/android/utils/WebViewUtil.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/owncloud/android/utils/WebViewUtil.kt b/app/src/main/java/com/owncloud/android/utils/WebViewUtil.kt index deb2f998ad..c8a6c6291c 100644 --- a/app/src/main/java/com/owncloud/android/utils/WebViewUtil.kt +++ b/app/src/main/java/com/owncloud/android/utils/WebViewUtil.kt @@ -122,7 +122,7 @@ class WebViewUtil(private val context: Context) { * * @return */ - @SuppressLint("PrivateApi", "DiscouragedPrivateApi") + @SuppressLint("PrivateApi", "DiscouragedPrivateApi", "TooGenericExceptionCaught") fun setProxyKKPlus(webView: WebView) { val proxyHost = OwnCloudClientManagerFactory.getProxyHost() val proxyPort = OwnCloudClientManagerFactory.getProxyPort() From 6c091bdb7293861ef311ce87cd7c7d5b9aacae82 Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Sun, 11 Feb 2024 16:29:14 +0100 Subject: [PATCH 07/10] Use YAML array instead of a comma-separated String Signed-off-by: Andy Scherzinger --- app/detekt.yml | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/app/detekt.yml b/app/detekt.yml index 34dae685e8..5e9aad61c9 100644 --- a/app/detekt.yml +++ b/app/detekt.yml @@ -59,7 +59,7 @@ complexity: excludes: ['**/androidTest/**'] LabeledExpression: active: false - ignoredLabels: "" + ignoredLabels: [] LargeClass: active: true threshold: 600 @@ -132,7 +132,7 @@ exceptions: active: true ExceptionRaisedInUnexpectedLocation: active: false - methodNames: 'toString,hashCode,equals,finalize' + methodNames: [toString,hashCode,equals,finalize] InstanceOfCheckForException: active: false NotImplementedDeclaration: @@ -145,14 +145,14 @@ exceptions: active: false SwallowedException: active: false - ignoredExceptionTypes: 'InterruptedException,NumberFormatException,ParseException,MalformedURLException' + ignoredExceptionTypes: [InterruptedException,NumberFormatException,ParseException,MalformedURLException] ThrowingExceptionFromFinally: active: false ThrowingExceptionInMain: active: false ThrowingExceptionsWithoutMessageOrCause: active: false - exceptions: 'IllegalArgumentException,IllegalStateException,IOException' + exceptions: [IllegalArgumentException,IllegalStateException,IOException] ThrowingNewInstanceOfSameException: active: false TooGenericExceptionCaught: @@ -190,7 +190,7 @@ naming: enumEntryPattern: '^[A-Z][_a-zA-Z0-9]*' ForbiddenClassName: active: false - forbiddenName: '' + forbiddenName: [] FunctionMaxLength: active: false maximumFunctionNameLength: 30 @@ -291,7 +291,7 @@ style: active: false DataClassContainsFunctions: active: false - conversionFunctionPrefix: 'to' + conversionFunctionPrefix: [to] EqualsNullCall: active: false EqualsOnSignatureLine: @@ -306,19 +306,19 @@ style: values: 'TODO:,FIXME:,STOPSHIP:' ForbiddenImport: active: false - imports: '' + imports: [] ForbiddenVoid: active: false FunctionOnlyReturningConstant: active: false ignoreOverridableFunction: true - excludedFunctions: 'describeContents' + excludedFunctions: [describeContents] LoopWithTooManyJumpStatements: active: false maxJumpCount: 1 MagicNumber: active: true - ignoreNumbers: '-1,0,1,2' + ignoreNumbers: ["-1","0","1","2"] ignoreHashCodeFunction: true ignorePropertyDeclaration: false ignoreConstantDeclaration: true @@ -362,7 +362,7 @@ style: ReturnCount: active: true max: 2 - excludedFunctions: "equals" + excludedFunctions: [equals] excludeLabeled: false excludeReturnFromLambda: true SafeCast: @@ -409,4 +409,4 @@ style: active: false WildcardImport: active: true - excludeImports: 'java.util.*,kotlinx.android.synthetic.*' + excludeImports: [java.util.*,kotlinx.android.synthetic.*] From 20e4fa512900e92b998e22b0de505f8e2b42d545 Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Sun, 11 Feb 2024 16:29:44 +0100 Subject: [PATCH 08/10] Suppress too generic exception caught Signed-off-by: Andy Scherzinger --- app/src/main/java/com/owncloud/android/utils/WebViewUtil.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/owncloud/android/utils/WebViewUtil.kt b/app/src/main/java/com/owncloud/android/utils/WebViewUtil.kt index c8a6c6291c..550297e3df 100644 --- a/app/src/main/java/com/owncloud/android/utils/WebViewUtil.kt +++ b/app/src/main/java/com/owncloud/android/utils/WebViewUtil.kt @@ -122,7 +122,8 @@ class WebViewUtil(private val context: Context) { * * @return */ - @SuppressLint("PrivateApi", "DiscouragedPrivateApi", "TooGenericExceptionCaught") + @SuppressLint("PrivateApi", "DiscouragedPrivateApi") + @Suppress("TooGenericExceptionCaught") fun setProxyKKPlus(webView: WebView) { val proxyHost = OwnCloudClientManagerFactory.getProxyHost() val proxyPort = OwnCloudClientManagerFactory.getProxyPort() From 88f7ca5affd602f0546af2e26ae045f501c8bff0 Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Sun, 11 Feb 2024 16:52:32 +0100 Subject: [PATCH 09/10] Revert com.mebigfatguy.fb-contrib:fb-contrib to 7.6.0 Signed-off-by: Andy Scherzinger --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index c302a55c2f..c48aed6f95 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -291,7 +291,7 @@ dependencies { qaImplementation project(':appscan') spotbugsPlugins 'com.h3xstream.findsecbugs:findsecbugs-plugin:1.12.0' - spotbugsPlugins 'com.mebigfatguy.fb-contrib:fb-contrib:7.6.4' + spotbugsPlugins 'com.mebigfatguy.fb-contrib:fb-contrib:7.6.0' implementation "com.google.dagger:dagger:$daggerVersion" implementation "com.google.dagger:dagger-android:$daggerVersion" From 0bdf85ca08e9ce095dcc099c2218fdcb12dafb3c Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Sun, 11 Feb 2024 18:05:47 +0100 Subject: [PATCH 10/10] remove unused variable Signed-off-by: Andy Scherzinger --- .../operations/RemoveRemoteEncryptedFileOperation.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/operations/RemoveRemoteEncryptedFileOperation.java b/app/src/main/java/com/owncloud/android/operations/RemoveRemoteEncryptedFileOperation.java index e01059aa2f..d863c2ba58 100644 --- a/app/src/main/java/com/owncloud/android/operations/RemoveRemoteEncryptedFileOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/RemoveRemoteEncryptedFileOperation.java @@ -24,8 +24,6 @@ package com.owncloud.android.operations; import android.content.Context; import com.nextcloud.client.account.User; -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.e2e.v2.decrypted.DecryptedFolderMetadataFile; @@ -55,7 +53,6 @@ public class RemoveRemoteEncryptedFileOperation extends RemoteOperation { private final String fileName; private final Context context; private final boolean isFolder; - private final ArbitraryDataProvider arbitraryDataProvider; /** * Constructor @@ -75,8 +72,6 @@ public class RemoveRemoteEncryptedFileOperation extends RemoteOperation { this.context = context; this.parentFolder = parentFolder; this.isFolder = isFolder; - - arbitraryDataProvider = new ArbitraryDataProviderImpl(context); } /**