diff --git a/app/schemas/com.nextcloud.client.database.NextcloudDatabase/74.json b/app/schemas/com.nextcloud.client.database.NextcloudDatabase/74.json
new file mode 100644
index 000000000000..d37b3654d96b
--- /dev/null
+++ b/app/schemas/com.nextcloud.client.database.NextcloudDatabase/74.json
@@ -0,0 +1,1161 @@
+{
+ "formatVersion": 1,
+ "database": {
+ "version": 74,
+ "identityHash": "7e73c045ac6d52d6c7c1626eefbc21e9",
+ "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)",
+ "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
+ }
+ ],
+ "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, `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, `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": "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": "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)",
+ "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
+ }
+ ],
+ "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, '7e73c045ac6d52d6c7c1626eefbc21e9')"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/app/src/androidTest/java/com/owncloud/android/datamodel/OCCapabilityIT.kt b/app/src/androidTest/java/com/owncloud/android/datamodel/OCCapabilityIT.kt
index 7487fb404ba7..251be9ecd086 100644
--- a/app/src/androidTest/java/com/owncloud/android/datamodel/OCCapabilityIT.kt
+++ b/app/src/androidTest/java/com/owncloud/android/datamodel/OCCapabilityIT.kt
@@ -37,6 +37,7 @@ class OCCapabilityIT : AbstractIT() {
capability.etag = "123"
capability.userStatus = CapabilityBooleanType.TRUE
capability.userStatusSupportsEmoji = CapabilityBooleanType.TRUE
+ capability.dropAccount = CapabilityBooleanType.TRUE
fileDataStorageManager.saveCapabilities(capability)
@@ -45,5 +46,6 @@ class OCCapabilityIT : AbstractIT() {
assertEquals(capability.etag, newCapability.etag)
assertEquals(capability.userStatus, newCapability.userStatus)
assertEquals(capability.userStatusSupportsEmoji, newCapability.userStatusSupportsEmoji)
+ assertEquals(capability.dropAccount, newCapability.dropAccount)
}
}
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 556acc642266..6f36f9a10914 100644
--- a/app/src/main/java/com/nextcloud/client/database/NextcloudDatabase.kt
+++ b/app/src/main/java/com/nextcloud/client/database/NextcloudDatabase.kt
@@ -40,8 +40,8 @@ import com.nextcloud.client.database.entity.ShareEntity
import com.nextcloud.client.database.entity.SyncedFolderEntity
import com.nextcloud.client.database.entity.UploadEntity
import com.nextcloud.client.database.entity.VirtualEntity
+import com.nextcloud.client.database.migrations.DatabaseMigrationUtil
import com.nextcloud.client.database.migrations.Migration67to68
-import com.nextcloud.client.database.migrations.Migration70to71
import com.nextcloud.client.database.migrations.RoomMigration
import com.nextcloud.client.database.migrations.addLegacyMigrations
import com.owncloud.android.db.ProviderMeta
@@ -64,8 +64,10 @@ import com.owncloud.android.db.ProviderMeta
AutoMigration(from = 66, to = 67),
AutoMigration(from = 68, to = 69),
AutoMigration(from = 69, to = 70),
+ AutoMigration(from = 70, to = 71, spec = DatabaseMigrationUtil.ResetCapabilitiesPostMigration::class),
AutoMigration(from = 71, to = 72),
- AutoMigration(from = 72, to = 73)
+ AutoMigration(from = 72, to = 73),
+ AutoMigration(from = 73, to = 74, spec = DatabaseMigrationUtil.ResetCapabilitiesPostMigration::class)
],
exportSchema = true
)
@@ -95,7 +97,6 @@ abstract class NextcloudDatabase : RoomDatabase() {
.addLegacyMigrations(clock, context)
.addMigrations(RoomMigration())
.addMigrations(Migration67to68())
- .addMigrations(Migration70to71())
.fallbackToDestructiveMigration()
.build()
}
diff --git a/app/src/main/java/com/nextcloud/client/database/entity/CapabilityEntity.kt b/app/src/main/java/com/nextcloud/client/database/entity/CapabilityEntity.kt
index 50b5ad8efa0d..910fba051786 100644
--- a/app/src/main/java/com/nextcloud/client/database/entity/CapabilityEntity.kt
+++ b/app/src/main/java/com/nextcloud/client/database/entity/CapabilityEntity.kt
@@ -129,5 +129,7 @@ data class CapabilityEntity(
@ColumnInfo(name = ProviderTableMeta.CAPABILITIES_FILES_LOCKING_VERSION)
val filesLockingVersion: String?,
@ColumnInfo(name = ProviderTableMeta.CAPABILITIES_GROUPFOLDERS)
- val groupfolders: Int?
+ val groupfolders: Int?,
+ @ColumnInfo(name = ProviderTableMeta.CAPABILITIES_DROP_ACCOUNT)
+ val dropAccount: Int?
)
diff --git a/app/src/main/java/com/nextcloud/client/database/migrations/DatabaseMigrationUtil.kt b/app/src/main/java/com/nextcloud/client/database/migrations/DatabaseMigrationUtil.kt
index 96d3379e1eeb..90f497a616b0 100644
--- a/app/src/main/java/com/nextcloud/client/database/migrations/DatabaseMigrationUtil.kt
+++ b/app/src/main/java/com/nextcloud/client/database/migrations/DatabaseMigrationUtil.kt
@@ -22,6 +22,7 @@
package com.nextcloud.client.database.migrations
+import androidx.room.migration.AutoMigrationSpec
import androidx.sqlite.db.SupportSQLiteDatabase
object DatabaseMigrationUtil {
@@ -102,4 +103,14 @@ object DatabaseMigrationUtil {
database.execSQL("DROP TABLE $tableName")
database.execSQL("ALTER TABLE $newTableTempName RENAME TO $tableName")
}
+
+ /**
+ * Room AutoMigrationSpec to reset capabilities post migration.
+ */
+ class ResetCapabilitiesPostMigration : AutoMigrationSpec {
+ override fun onPostMigrate(db: SupportSQLiteDatabase) {
+ resetCapabilities(db)
+ super.onPostMigrate(db)
+ }
+ }
}
diff --git a/app/src/main/java/com/nextcloud/client/database/migrations/Migration70to71.kt b/app/src/main/java/com/nextcloud/client/database/migrations/Migration70to71.kt
deleted file mode 100644
index caa3078346d9..000000000000
--- a/app/src/main/java/com/nextcloud/client/database/migrations/Migration70to71.kt
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Nextcloud Android client application
- *
- * @author Álvaro Brey
- * Copyright (C) 2023 Álvaro Brey
- * Copyright (C) 2023 Nextcloud GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with this program. If not, see .
- *
- */
-
-package com.nextcloud.client.database.migrations
-
-import androidx.room.migration.Migration
-import androidx.sqlite.db.SupportSQLiteDatabase
-
-/**
- * Migration from version 70 to 71.
- *
- * resets capabilities to show groupfolder
- */
-@Suppress("MagicNumber")
-class Migration70to71 : Migration(70, 71) {
- override fun migrate(database: SupportSQLiteDatabase) {
- DatabaseMigrationUtil.resetCapabilities(database)
- }
-}
diff --git a/app/src/main/java/com/nextcloud/client/di/ComponentsModule.java b/app/src/main/java/com/nextcloud/client/di/ComponentsModule.java
index 24200fd83ed5..82f9c8738108 100644
--- a/app/src/main/java/com/nextcloud/client/di/ComponentsModule.java
+++ b/app/src/main/java/com/nextcloud/client/di/ComponentsModule.java
@@ -81,7 +81,7 @@
import com.owncloud.android.ui.activity.UploadFilesActivity;
import com.owncloud.android.ui.activity.UploadListActivity;
import com.owncloud.android.ui.activity.UserInfoActivity;
-import com.owncloud.android.ui.dialog.AccountRemovalConfirmationDialog;
+import com.owncloud.android.ui.dialog.AccountRemovalDialog;
import com.owncloud.android.ui.dialog.ChooseRichDocumentsTemplateDialogFragment;
import com.owncloud.android.ui.dialog.ChooseTemplateDialogFragment;
import com.owncloud.android.ui.dialog.ConfirmationDialogFragment;
@@ -270,7 +270,7 @@ abstract class ComponentsModule {
abstract ChooseTemplateDialogFragment chooseTemplateDialogFragment();
@ContributesAndroidInjector
- abstract AccountRemovalConfirmationDialog accountRemovalConfirmationDialog();
+ abstract AccountRemovalDialog accountRemovalDialog();
@ContributesAndroidInjector
abstract ChooseRichDocumentsTemplateDialogFragment chooseRichDocumentsTemplateDialogFragment();
diff --git a/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java b/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java
index e7867b917650..40b7f345bbbd 100644
--- a/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java
+++ b/app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java
@@ -1947,6 +1947,7 @@ private ContentValues createContentValues(String accountName, OCCapability capab
contentValues.put(ProviderTableMeta.CAPABILITIES_FILES_LOCKING_VERSION,
capability.getFilesLockingVersion());
contentValues.put(ProviderTableMeta.CAPABILITIES_GROUPFOLDERS, capability.getGroupfolders().getValue());
+ contentValues.put(ProviderTableMeta.CAPABILITIES_DROP_ACCOUNT, capability.getDropAccount().getValue());
return contentValues;
}
@@ -2103,6 +2104,7 @@ private OCCapability createCapabilityInstance(Cursor cursor) {
capability.setFilesLockingVersion(
getString(cursor, ProviderTableMeta.CAPABILITIES_FILES_LOCKING_VERSION));
capability.setGroupfolders(getBoolean(cursor, ProviderTableMeta.CAPABILITIES_GROUPFOLDERS));
+ capability.setDropAccount(getBoolean(cursor, ProviderTableMeta.CAPABILITIES_DROP_ACCOUNT));
}
return capability;
}
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 e1c207e47ba1..abd1a2b7bbf1 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 = 73;
+ public static final int DB_VERSION = 74;
private ProviderMeta() {
// No instance
@@ -259,6 +259,7 @@ static public class ProviderTableMeta implements BaseColumns {
public static final String CAPABILITIES_USER_STATUS = "user_status";
public static final String CAPABILITIES_USER_STATUS_SUPPORTS_EMOJI = "user_status_supports_emoji";
public static final String CAPABILITIES_GROUPFOLDERS = "groupfolders";
+ public static final String CAPABILITIES_DROP_ACCOUNT = "drop_account";
//Columns of Uploads table
public static final String UPLOADS_LOCAL_PATH = "local_path";
diff --git a/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java
index 9e37e03e0e00..6f303f040c5f 100644
--- a/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java
+++ b/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java
@@ -527,7 +527,7 @@ private void onNavigationItemClicked(final MenuItem menuItem) {
menuItem.setChecked(false);
final Optional optionalUser = getUser();
if (optionalUser.isPresent()) {
- UserInfoActivity.openAccountRemovalConfirmationDialog(optionalUser.get(), getSupportFragmentManager());
+ UserInfoActivity.openAccountRemovalDialog(optionalUser.get(), getSupportFragmentManager());
}
} else if (itemId == R.id.nav_shared) {
startSharedSearch(menuItem);
diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java
index 94b294a83375..08284dc37614 100644
--- a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java
+++ b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java
@@ -58,7 +58,7 @@
import com.owncloud.android.services.OperationsService;
import com.owncloud.android.ui.adapter.UserListAdapter;
import com.owncloud.android.ui.adapter.UserListItem;
-import com.owncloud.android.ui.dialog.AccountRemovalConfirmationDialog;
+import com.owncloud.android.ui.dialog.AccountRemovalDialog;
import com.owncloud.android.ui.events.AccountRemovedEvent;
import com.owncloud.android.ui.helpers.FileOperationsHelper;
@@ -470,9 +470,8 @@ private void performAccountRemoval(User user) {
}
}
- public static void openAccountRemovalConfirmationDialog(User user, FragmentManager fragmentManager) {
- AccountRemovalConfirmationDialog dialog =
- AccountRemovalConfirmationDialog.newInstance(user);
+ public static void openAccountRemovalDialog(User user, FragmentManager fragmentManager) {
+ AccountRemovalDialog dialog = AccountRemovalDialog.newInstance(user);
dialog.show(fragmentManager, "dialog");
}
@@ -509,7 +508,7 @@ public void onOptionItemClicked(User user, View view) {
if (itemId == R.id.action_open_account) {
accountClicked(user.hashCode());
} else if (itemId == R.id.action_delete_account) {
- openAccountRemovalConfirmationDialog(user, getSupportFragmentManager());
+ openAccountRemovalDialog(user, getSupportFragmentManager());
} else {
openAccount(user);
}
diff --git a/app/src/main/java/com/owncloud/android/ui/activity/UserInfoActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/UserInfoActivity.java
index 760a843d30cd..b6c28daaeadb 100644
--- a/app/src/main/java/com/owncloud/android/ui/activity/UserInfoActivity.java
+++ b/app/src/main/java/com/owncloud/android/ui/activity/UserInfoActivity.java
@@ -56,7 +56,7 @@
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.lib.resources.users.GetUserInfoRemoteOperation;
-import com.owncloud.android.ui.dialog.AccountRemovalConfirmationDialog;
+import com.owncloud.android.ui.dialog.AccountRemovalDialog;
import com.owncloud.android.ui.events.TokenPushEvent;
import com.owncloud.android.utils.DisplayUtils;
import com.owncloud.android.utils.PushUtils;
@@ -173,7 +173,7 @@ public boolean onOptionsItemSelected(MenuItem item) {
} else if (itemId == R.id.action_open_account) {
accountClicked(user.hashCode());
} else if (itemId == R.id.action_delete_account) {
- openAccountRemovalConfirmationDialog(user, getSupportFragmentManager());
+ openAccountRemovalDialog(user, getSupportFragmentManager());
} else {
retval = super.onOptionsItemSelected(item);
}
@@ -302,8 +302,8 @@ private void addToListIfNeeded(List info, @DrawableRes int
}
}
- public static void openAccountRemovalConfirmationDialog(User user, FragmentManager fragmentManager) {
- AccountRemovalConfirmationDialog dialog = AccountRemovalConfirmationDialog.newInstance(user);
+ public static void openAccountRemovalDialog(User user, FragmentManager fragmentManager) {
+ AccountRemovalDialog dialog = AccountRemovalDialog.newInstance(user);
dialog.show(fragmentManager, "dialog");
}
diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/AccountRemovalConfirmationDialog.kt b/app/src/main/java/com/owncloud/android/ui/dialog/AccountRemovalConfirmationDialog.kt
deleted file mode 100644
index a32e818abe43..000000000000
--- a/app/src/main/java/com/owncloud/android/ui/dialog/AccountRemovalConfirmationDialog.kt
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Nextcloud Android client application
- *
- * @author Tobias Kaminsky
- * Copyright (C) 2020 Tobias Kaminsky
- * Copyright (C) 2020 Nextcloud GmbH
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-package com.owncloud.android.ui.dialog
-
-import android.app.Dialog
-import android.content.DialogInterface
-import android.os.Build
-import android.os.Bundle
-import androidx.appcompat.app.AlertDialog
-import androidx.fragment.app.DialogFragment
-import com.google.android.material.button.MaterialButton
-import com.google.android.material.dialog.MaterialAlertDialogBuilder
-import com.nextcloud.client.account.User
-import com.nextcloud.client.di.Injectable
-import com.nextcloud.client.jobs.BackgroundJobManager
-import com.owncloud.android.R
-import com.owncloud.android.utils.theme.ViewThemeUtils
-import javax.inject.Inject
-
-class AccountRemovalConfirmationDialog : DialogFragment(), Injectable {
- @JvmField
- @Inject
- var backgroundJobManager: BackgroundJobManager? = null
-
- @JvmField
- @Inject
- var viewThemeUtils: ViewThemeUtils? = null
-
- private var user: User? = null
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
-
- user = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
- requireArguments().getParcelable(KEY_USER, User::class.java)
- } else {
- @Suppress("DEPRECATION")
- requireArguments().getParcelable(KEY_USER)
- }
- }
-
- override fun onStart() {
- super.onStart()
-
- val alertDialog = dialog as AlertDialog?
-
- if (alertDialog != null) {
- val positiveButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE) as MaterialButton
- viewThemeUtils?.material?.colorMaterialButtonPrimaryTonal(positiveButton)
-
- val negativeButton = alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE) as MaterialButton
- viewThemeUtils?.material?.colorMaterialButtonPrimaryBorderless(negativeButton)
- }
- }
-
- override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
- val builder = MaterialAlertDialogBuilder(requireActivity())
- .setTitle(R.string.delete_account)
- .setMessage(resources.getString(R.string.delete_account_warning, user!!.accountName))
- .setIcon(R.drawable.ic_warning)
- .setPositiveButton(R.string.common_ok) { _: DialogInterface?, _: Int ->
- backgroundJobManager?.startAccountRemovalJob(
- user!!.accountName,
- false
- )
- }
- .setNegativeButton(R.string.common_cancel, null)
-
- viewThemeUtils?.dialog?.colorMaterialAlertDialogBackground(requireActivity(), builder)
-
- return builder.create()
- }
-
- companion object {
-
- private const val KEY_USER = "USER"
-
- @JvmStatic
- fun newInstance(user: User?): AccountRemovalConfirmationDialog {
- val bundle = Bundle()
- bundle.putParcelable(KEY_USER, user)
- val dialog = AccountRemovalConfirmationDialog()
- dialog.arguments = bundle
- return dialog
- }
- }
-}
diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/AccountRemovalDialog.kt b/app/src/main/java/com/owncloud/android/ui/dialog/AccountRemovalDialog.kt
new file mode 100644
index 000000000000..8498dbf7d11d
--- /dev/null
+++ b/app/src/main/java/com/owncloud/android/ui/dialog/AccountRemovalDialog.kt
@@ -0,0 +1,194 @@
+/*
+ * Nextcloud Android client application
+ *
+ * @author ZetaTom
+ * @author Tobias Kaminsky
+ * Copyright (C) 2023 ZetaTom
+ * Copyright (C) 2020 Tobias Kaminsky
+ * Copyright (C) 2020 Nextcloud GmbH
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package com.owncloud.android.ui.dialog
+
+import android.app.Dialog
+import android.graphics.drawable.Drawable
+import android.os.Bundle
+import android.view.View
+import androidx.appcompat.app.AlertDialog
+import androidx.fragment.app.DialogFragment
+import com.google.android.material.button.MaterialButton
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import com.nextcloud.client.account.User
+import com.nextcloud.client.account.UserAccountManager
+import com.nextcloud.client.di.Injectable
+import com.nextcloud.client.jobs.BackgroundJobManager
+import com.nextcloud.utils.extensions.getParcelableArgument
+import com.owncloud.android.R
+import com.owncloud.android.databinding.AccountRemovalDialogBinding
+import com.owncloud.android.datamodel.FileDataStorageManager
+import com.owncloud.android.utils.DisplayUtils
+import com.owncloud.android.utils.DisplayUtils.AvatarGenerationListener
+import com.owncloud.android.utils.theme.ViewThemeUtils
+import javax.inject.Inject
+
+class AccountRemovalDialog : DialogFragment(), AvatarGenerationListener, Injectable {
+
+ @Inject
+ lateinit var backgroundJobManager: BackgroundJobManager
+
+ @Inject
+ lateinit var viewThemeUtils: ViewThemeUtils
+
+ private var user: User? = null
+ private lateinit var alertDialog: AlertDialog
+ private var _binding: AccountRemovalDialogBinding? = null
+ private val binding get() = _binding!!
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ user = requireArguments().getParcelableArgument(KEY_USER, User::class.java)
+ }
+
+ override fun onStart() {
+ super.onStart()
+
+ // disable positive button and apply theming
+ alertDialog = dialog as AlertDialog
+ alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = false
+
+ viewThemeUtils.platform.themeRadioButton(binding.radioLocalRemove)
+ viewThemeUtils.platform.themeRadioButton(binding.radioRequestDeletion)
+ viewThemeUtils.material.colorMaterialButtonPrimaryTonal(
+ alertDialog.getButton(AlertDialog.BUTTON_POSITIVE) as MaterialButton
+ )
+ viewThemeUtils.material.colorMaterialButtonPrimaryBorderless(
+ alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE) as MaterialButton
+ )
+
+ binding.userName.text = UserAccountManager.getDisplayName(user)
+ binding.account.text = user?.let { DisplayUtils.convertIdn(it.accountName, false) }
+ }
+
+ override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
+ _binding = AccountRemovalDialogBinding.inflate(layoutInflater)
+
+ // start avatar generation
+ setAvatar()
+
+ // hide second option when plug-in isn't installed
+ if (hasDropAccount()) {
+ binding.requestDeletion.visibility = View.VISIBLE
+ }
+
+ val builder =
+ MaterialAlertDialogBuilder(requireActivity())
+ .setTitle(R.string.delete_account)
+ .setView(binding.root)
+ .setNegativeButton(R.string.common_cancel) { _, _ -> }
+ .setPositiveButton(R.string.delete_account) { _, _ -> removeAccount() }
+
+ // allow selection by clicking on list element
+ binding.localRemove.setOnClickListener {
+ binding.radioLocalRemove.performClick()
+ }
+ binding.requestDeletion.setOnClickListener {
+ binding.radioRequestDeletion.performClick()
+ }
+
+ // set listeners for custom radio button list
+ binding.radioLocalRemove.setOnClickListener {
+ binding.radioRequestDeletion.isChecked = false
+ alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).apply {
+ text = getText(R.string.delete_account)
+ isEnabled = true
+ }
+ }
+ binding.radioRequestDeletion.setOnClickListener {
+ binding.radioLocalRemove.isChecked = false
+ alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).apply {
+ text = getString(R.string.request_account_deletion_button)
+ isEnabled = true
+ }
+ }
+
+ viewThemeUtils.dialog.colorMaterialAlertDialogBackground(requireActivity(), builder)
+
+ return builder.create()
+ }
+
+ /**
+ * Get value of `drop-account` capability.
+ */
+ private fun hasDropAccount(): Boolean {
+ val capability = FileDataStorageManager(user, context?.contentResolver).getCapability(user)
+ return capability.dropAccount.isTrue
+ }
+
+ /**
+ * Start removal of account. Depending on which option is checked, either a browser will open to request deletion,
+ * or the local account will be removed immediately.
+ */
+ private fun removeAccount() {
+ user?.let { user ->
+ if (binding.radioRequestDeletion.isChecked) {
+ DisplayUtils.startLinkIntent(activity, user.server.uri.toString() + DROP_ACCOUNT_URI)
+ } else {
+ backgroundJobManager.startAccountRemovalJob(user.accountName, false)
+ }
+ }
+ }
+
+ /**
+ * Start avatar generation.
+ */
+ private fun setAvatar() {
+ try {
+ val imageView = binding.userIcon
+ imageView.tag = user!!.accountName
+ DisplayUtils.setAvatar(
+ user!!,
+ this,
+ resources.getDimension(R.dimen.list_item_avatar_icon_radius),
+ resources,
+ imageView,
+ context
+ )
+ } catch (_: Exception) {
+ }
+ }
+
+ override fun avatarGenerated(avatarDrawable: Drawable?, callContext: Any?) {
+ avatarDrawable?.let {
+ binding.userIcon.setImageDrawable(it)
+ }
+ }
+
+ override fun shouldCallGeneratedCallback(tag: String?, callContext: Any?): Boolean {
+ return binding.userIcon.tag == tag
+ }
+
+ companion object {
+ private const val KEY_USER = "USER"
+ private const val DROP_ACCOUNT_URI = "/settings/user/drop_account"
+
+ @JvmStatic
+ fun newInstance(user: User) = AccountRemovalDialog().apply {
+ arguments = Bundle().apply {
+ putParcelable(KEY_USER, user)
+ }
+ }
+ }
+}
diff --git a/app/src/main/res/layout/account_removal_dialog.xml b/app/src/main/res/layout/account_removal_dialog.xml
new file mode 100644
index 000000000000..913d19cbdff4
--- /dev/null
+++ b/app/src/main/res/layout/account_removal_dialog.xml
@@ -0,0 +1,154 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 1441895eeda7..3e91ba7bc3f1 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -129,8 +129,12 @@
Skip
Copy
About
+ Remove local account
+ Remove account from device and delete all local files
+ Request account deletion
+ Request deletion
+ Request permanent deletion of account by service provider
Remove account
- Remove account %s and delete all local files?\n\nDeletion cannot be undone.
Avatar
Active user
Upload from…
diff --git a/settings.gradle b/settings.gradle
index 367bea707464..5c2438e2ad80 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -8,3 +8,9 @@ include ':appscan'
// substitute module('com.github.nextcloud.android-common:ui') using project(':ui')
// }
//}
+
+//includeBuild('../android-library') {
+// dependencySubstitution {
+// substitute module('com.github.nextcloud:android-library') using project(':library')
+// }
+//}