From 555a1abbe4555ce046152a2e4272192d2d2936b8 Mon Sep 17 00:00:00 2001 From: JinWeiyang Date: Fri, 15 Dec 2023 23:24:48 +0800 Subject: [PATCH] add exclude hidden file or folder option when create custom media folder type Signed-off-by: JinWeiyang --- .../77.json | 1185 +++++++++++++++++ .../client/SyncedFoldersActivityIT.java | 3 +- .../android/utils/SyncedFolderUtilsTest.kt | 6 +- .../client/database/NextcloudDatabase.kt | 3 +- .../database/entity/SyncedFolderEntity.kt | 4 +- .../android/datamodel/SyncedFolder.java | 21 +- .../datamodel/SyncedFolderDisplayItem.java | 13 +- .../datamodel/SyncedFolderProvider.java | 6 +- .../com/owncloud/android/db/ProviderMeta.java | 3 +- .../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-zh-rCN/strings.xml | 2 + app/src/main/res/values/strings.xml | 2 + .../activity/SyncedFoldersActivityTest.java | 3 +- 18 files changed, 1372 insertions(+), 33 deletions(-) create mode 100644 app/schemas/com.nextcloud.client.database.NextcloudDatabase/77.json diff --git a/app/schemas/com.nextcloud.client.database.NextcloudDatabase/77.json b/app/schemas/com.nextcloud.client.database.NextcloudDatabase/77.json new file mode 100644 index 000000000000..510ceae9bf77 --- /dev/null +++ b/app/schemas/com.nextcloud.client.database.NextcloudDatabase/77.json @@ -0,0 +1,1185 @@ +{ + "formatVersion": 1, + "database": { + "version": 77, + "identityHash": "11c4b8b675928f83c556038ce8141328", + "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, `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": "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)", + "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 + } + ], + "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, '11c4b8b675928f83c556038ce8141328')" + ] + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/com/nextcloud/client/SyncedFoldersActivityIT.java b/app/src/androidTest/java/com/nextcloud/client/SyncedFoldersActivityIT.java index b28c89db9578..6ebeaaa05481 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 void testSyncedFolderDialog() { "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 ff4ec14b05f3..9cd65727ad22 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/NextcloudDatabase.kt b/app/src/main/java/com/nextcloud/client/database/NextcloudDatabase.kt index 45b3da64643a..5f3e16a036ad 100644 --- a/app/src/main/java/com/nextcloud/client/database/NextcloudDatabase.kt +++ b/app/src/main/java/com/nextcloud/client/database/NextcloudDatabase.kt @@ -69,7 +69,8 @@ import com.owncloud.android.db.ProviderMeta AutoMigration(from = 72, to = 73), AutoMigration(from = 73, to = 74, spec = DatabaseMigrationUtil.ResetCapabilitiesPostMigration::class), AutoMigration(from = 74, to = 75), - AutoMigration(from = 75, to = 76) + AutoMigration(from = 75, to = 76), + AutoMigration(from = 76, to = 77) ], exportSchema = true ) 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 5934bae96c47..811cb0423d7d 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 4d86f435c885..17655bdc80e9 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 SyncedFolder(String localPath, long timestampMs, MediaFolderType type, boolean hidden, - SubFolderRule subFolderRule) { + SubFolderRule subFolderRule, + boolean excludeHidden) { this(UNPERSISTED_ID, localPath, remotePath, @@ -97,7 +101,8 @@ public SyncedFolder(String localPath, timestampMs, type, hidden, - subFolderRule); + subFolderRule, + excludeHidden); } /** @@ -119,7 +124,8 @@ protected SyncedFolder(long id, 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 @@ protected SyncedFolder(long id, this.type = type; this.hidden = hidden; this.subfolderRule = subFolderRule; + this.excludeHidden = excludeHidden; } /** @@ -263,4 +270,12 @@ public void setHidden(boolean hidden) { } 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 c8ec28197ec3..fe716270fe5f 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 SyncedFolderDisplayItem(long id, long numberOfFiles, MediaFolderType type, boolean hidden, - SubFolderRule subFolderRule) { + SubFolderRule subFolderRule, + boolean excludeHidden) { super(id, localPath, remotePath, @@ -87,7 +89,8 @@ public SyncedFolderDisplayItem(long id, timestampMs, type, hidden, - subFolderRule); + subFolderRule, + excludeHidden); this.filePaths = filePaths; this.folderName = folderName; this.numberOfFiles = numberOfFiles; @@ -108,7 +111,8 @@ public SyncedFolderDisplayItem(long id, String folderName, MediaFolderType type, boolean hidden, - SubFolderRule subFolderRule) { + SubFolderRule subFolderRule, + boolean excludeHidden) { super(id, localPath, remotePath, @@ -123,7 +127,8 @@ public SyncedFolderDisplayItem(long id, 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 3c25f30fc973..370f5de82462 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 @@ private SyncedFolder createSyncedFolderFromCursor(Cursor cursor) { 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 @@ private SyncedFolder createSyncedFolderFromCursor(Cursor cursor) { enabledTimestampMs, type, hidden, - subFolderRule); + subFolderRule, + excludeHidden); } return syncedFolder; } @@ -417,6 +420,7 @@ private ContentValues createContentValuesFromSyncedFolder(SyncedFolder syncedFol 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 eafc497902b3..10da9bf3023a 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 @@ */ public class ProviderMeta { public static final String DB_NAME = "filelist"; - public static final int DB_VERSION = 76; + public static final int DB_VERSION = 77; private ProviderMeta() { // No instance @@ -299,6 +299,7 @@ static public class ProviderTableMeta implements BaseColumns { 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 39debb4bad44..1fb2b1793942 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 90c1bb13a412..c10cc878bf7c 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 6a495773de27..fffd2cd0064c 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 SyncedFolderParcelable(SyncedFolderDisplayItem syncedFolderDisplayItem, i this.section = section; hidden = syncedFolderDisplayItem.isHidden(); subFolderRule = syncedFolderDisplayItem.getSubfolderRule(); + excludeHidden = syncedFolderDisplayItem.isExcludeHidden(); } private SyncedFolderParcelable(Parcel read) { @@ -87,6 +89,7 @@ private SyncedFolderParcelable(Parcel read) { section = read.readInt(); hidden = read.readInt() != 0; subFolderRule = SubFolderRule.values()[read.readInt()]; + excludeHidden = read.readInt() != 0; } public SyncedFolderParcelable() { @@ -111,6 +114,7 @@ public void writeToParcel(Parcel dest, int flags) { 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 void setSection(int section) { 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 e87007152ce3..dd6e4b31cef8 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 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 @@ Long getCreationTimestamp(File file) { 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 46c454723773..bdd6a18b8aed 100644 --- a/app/src/main/java/com/owncloud/android/utils/FilesSyncHelper.java +++ b/app/src/main/java/com/owncloud/android/utils/FilesSyncHelper.java @@ -46,7 +46,6 @@ 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 @@ private static void insertAllDBEntriesForSyncedFolder(SyncedFolder syncedFolder) 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 FileVisitResult visitFile(Path path, BasicFileAttributes attrs) { 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; @@ -185,11 +196,10 @@ public static void restartJobsIfNeeded(final UploadsStorageManager uploadsStorag for (OCUpload failedUpload : failedUploads) { accountExists = false; - if(!failedUpload.isWhileChargingOnly()){ + if (!failedUpload.isWhileChargingOnly()) { whileChargingOnly = false; } - if(!failedUpload.isUseWifiOnly()) - { + if (!failedUpload.isUseWifiOnly()) { useWifiOnly = false; } @@ -207,22 +217,21 @@ public static void restartJobsIfNeeded(final UploadsStorageManager uploadsStorag } 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 14dc2f0d9687..5c0da7dce134 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 @@ + + + + + + + + + + + + + + + + 原始文件将会被… 依据日期存储在子文件夹內 使用子文件夹 + 排除隐藏 + 排除隐藏文件或目录 子文件夹选项 添加端对端加密到该客户端 许可证 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 92692302e4ab..38d80e06fb78 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -361,6 +361,8 @@ 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 082fc028f7eb..f4b504a1cc84 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 @@ private SyncedFolderDisplayItem create(String folderName, boolean enabled) { 2, MediaFolderType.IMAGE, false, - SubFolderRule.YEAR_MONTH); + SubFolderRule.YEAR_MONTH, + true); } }