From 0c072fb980b8370f8d0cd548b0c03bf25a5baaef Mon Sep 17 00:00:00 2001 From: M66B Date: Thu, 6 Dec 2018 13:43:00 +0100 Subject: [PATCH] Delegate deletion of accounts, identities & folders --- app/schemas/eu.faircode.email.DB/18.json | 1196 +++++++++++++++++ .../eu/faircode/email/AdapterAccount.java | 3 +- .../java/eu/faircode/email/AdapterFolder.java | 2 +- .../eu/faircode/email/AdapterIdentity.java | 3 +- app/src/main/java/eu/faircode/email/DB.java | 11 +- .../java/eu/faircode/email/DaoAccount.java | 7 +- .../java/eu/faircode/email/DaoFolder.java | 12 +- .../java/eu/faircode/email/DaoIdentity.java | 7 +- .../java/eu/faircode/email/EntityAccount.java | 2 + .../java/eu/faircode/email/EntityFolder.java | 3 + .../eu/faircode/email/EntityIdentity.java | 2 + .../eu/faircode/email/FragmentAccount.java | 9 +- .../eu/faircode/email/FragmentFolder.java | 129 +- .../eu/faircode/email/FragmentIdentity.java | 9 +- .../eu/faircode/email/ServiceSynchronize.java | 28 +- app/src/main/res/layout/fragment_folder.xml | 4 +- app/src/main/res/layout/item_account.xml | 247 ++-- app/src/main/res/layout/item_folder.xml | 3 +- app/src/main/res/layout/item_identity.xml | 241 ++-- 19 files changed, 1553 insertions(+), 365 deletions(-) create mode 100644 app/schemas/eu.faircode.email.DB/18.json diff --git a/app/schemas/eu.faircode.email.DB/18.json b/app/schemas/eu.faircode.email.DB/18.json new file mode 100644 index 0000000000..0273d183c0 --- /dev/null +++ b/app/schemas/eu.faircode.email.DB/18.json @@ -0,0 +1,1196 @@ +{ + "formatVersion": 1, + "database": { + "version": 18, + "identityHash": "bfe22cbcb39739e6ce61ce3a2e2857d7", + "entities": [ + { + "tableName": "identity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `name` TEXT NOT NULL, `email` TEXT NOT NULL, `replyto` TEXT, `account` INTEGER NOT NULL, `host` TEXT NOT NULL, `starttls` INTEGER NOT NULL, `insecure` INTEGER NOT NULL, `port` INTEGER NOT NULL, `user` TEXT NOT NULL, `password` TEXT NOT NULL, `auth_type` INTEGER NOT NULL, `primary` INTEGER NOT NULL, `color` INTEGER, `signature` TEXT, `synchronize` INTEGER NOT NULL, `store_sent` INTEGER NOT NULL, `sent_folder` INTEGER, `tbd` INTEGER, `state` TEXT, `error` TEXT, FOREIGN KEY(`account`) REFERENCES `account`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "email", + "columnName": "email", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "replyto", + "columnName": "replyto", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "account", + "columnName": "account", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "host", + "columnName": "host", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "starttls", + "columnName": "starttls", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "insecure", + "columnName": "insecure", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "port", + "columnName": "port", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "user", + "columnName": "user", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "password", + "columnName": "password", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "auth_type", + "columnName": "auth_type", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "primary", + "columnName": "primary", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "color", + "columnName": "color", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "signature", + "columnName": "signature", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "synchronize", + "columnName": "synchronize", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "store_sent", + "columnName": "store_sent", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "sent_folder", + "columnName": "sent_folder", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "tbd", + "columnName": "tbd", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "state", + "columnName": "state", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "error", + "columnName": "error", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_identity_account", + "unique": false, + "columnNames": [ + "account" + ], + "createSql": "CREATE INDEX `index_identity_account` ON `${TABLE_NAME}` (`account`)" + }, + { + "name": "index_identity_account_email", + "unique": false, + "columnNames": [ + "account", + "email" + ], + "createSql": "CREATE INDEX `index_identity_account_email` ON `${TABLE_NAME}` (`account`, `email`)" + } + ], + "foreignKeys": [ + { + "table": "account", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "account" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "account", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `name` TEXT, `signature` TEXT, `host` TEXT NOT NULL, `starttls` INTEGER NOT NULL, `insecure` INTEGER NOT NULL, `port` INTEGER NOT NULL, `user` TEXT NOT NULL, `password` TEXT NOT NULL, `auth_type` INTEGER NOT NULL, `synchronize` INTEGER NOT NULL, `primary` INTEGER NOT NULL, `color` INTEGER, `notify` INTEGER NOT NULL, `poll_interval` INTEGER NOT NULL, `created` INTEGER, `tbd` INTEGER, `state` TEXT, `error` TEXT, `last_connected` INTEGER)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "signature", + "columnName": "signature", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "host", + "columnName": "host", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "starttls", + "columnName": "starttls", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "insecure", + "columnName": "insecure", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "port", + "columnName": "port", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "user", + "columnName": "user", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "password", + "columnName": "password", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "auth_type", + "columnName": "auth_type", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "synchronize", + "columnName": "synchronize", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "primary", + "columnName": "primary", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "color", + "columnName": "color", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "notify", + "columnName": "notify", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "poll_interval", + "columnName": "poll_interval", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "created", + "columnName": "created", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "tbd", + "columnName": "tbd", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "state", + "columnName": "state", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "error", + "columnName": "error", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "last_connected", + "columnName": "last_connected", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "folder", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `account` INTEGER, `name` TEXT NOT NULL, `type` TEXT NOT NULL, `level` INTEGER NOT NULL, `synchronize` INTEGER NOT NULL, `poll` INTEGER NOT NULL, `sync_days` INTEGER NOT NULL, `keep_days` INTEGER NOT NULL, `display` TEXT, `hide` INTEGER NOT NULL, `unified` INTEGER NOT NULL, `keywords` TEXT, `tbd` INTEGER, `state` TEXT, `sync_state` TEXT, `error` TEXT, FOREIGN KEY(`account`) REFERENCES `account`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "account", + "columnName": "account", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "level", + "columnName": "level", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "synchronize", + "columnName": "synchronize", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "poll", + "columnName": "poll", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "sync_days", + "columnName": "sync_days", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "keep_days", + "columnName": "keep_days", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "display", + "columnName": "display", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "hide", + "columnName": "hide", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "unified", + "columnName": "unified", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "keywords", + "columnName": "keywords", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "tbd", + "columnName": "tbd", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "state", + "columnName": "state", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "sync_state", + "columnName": "sync_state", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "error", + "columnName": "error", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_folder_account_name", + "unique": true, + "columnNames": [ + "account", + "name" + ], + "createSql": "CREATE UNIQUE INDEX `index_folder_account_name` ON `${TABLE_NAME}` (`account`, `name`)" + }, + { + "name": "index_folder_account", + "unique": false, + "columnNames": [ + "account" + ], + "createSql": "CREATE INDEX `index_folder_account` ON `${TABLE_NAME}` (`account`)" + }, + { + "name": "index_folder_name", + "unique": false, + "columnNames": [ + "name" + ], + "createSql": "CREATE INDEX `index_folder_name` ON `${TABLE_NAME}` (`name`)" + }, + { + "name": "index_folder_type", + "unique": false, + "columnNames": [ + "type" + ], + "createSql": "CREATE INDEX `index_folder_type` ON `${TABLE_NAME}` (`type`)" + }, + { + "name": "index_folder_unified", + "unique": false, + "columnNames": [ + "unified" + ], + "createSql": "CREATE INDEX `index_folder_unified` ON `${TABLE_NAME}` (`unified`)" + } + ], + "foreignKeys": [ + { + "table": "account", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "account" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "message", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `account` INTEGER NOT NULL, `folder` INTEGER NOT NULL, `identity` INTEGER, `extra` TEXT, `replying` INTEGER, `forwarding` INTEGER, `uid` INTEGER, `msgid` TEXT, `references` TEXT, `deliveredto` TEXT, `inreplyto` TEXT, `thread` TEXT, `avatar` TEXT, `from` TEXT, `to` TEXT, `cc` TEXT, `bcc` TEXT, `reply` TEXT, `headers` TEXT, `subject` TEXT, `size` INTEGER, `content` INTEGER NOT NULL, `preview` TEXT, `sent` INTEGER, `received` INTEGER NOT NULL, `stored` INTEGER NOT NULL, `seen` INTEGER NOT NULL, `answered` INTEGER NOT NULL, `flagged` INTEGER NOT NULL, `keywords` TEXT, `ui_seen` INTEGER NOT NULL, `ui_answered` INTEGER NOT NULL, `ui_flagged` INTEGER NOT NULL, `ui_hide` INTEGER NOT NULL, `ui_found` INTEGER NOT NULL, `ui_ignored` INTEGER NOT NULL, `ui_browsed` INTEGER NOT NULL, `error` TEXT, `last_attempt` INTEGER, FOREIGN KEY(`account`) REFERENCES `account`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`folder`) REFERENCES `folder`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`identity`) REFERENCES `identity`(`id`) ON UPDATE NO ACTION ON DELETE SET NULL , FOREIGN KEY(`replying`) REFERENCES `message`(`id`) ON UPDATE NO ACTION ON DELETE SET NULL , FOREIGN KEY(`forwarding`) REFERENCES `message`(`id`) ON UPDATE NO ACTION ON DELETE SET NULL )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "account", + "columnName": "account", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "folder", + "columnName": "folder", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "identity", + "columnName": "identity", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "extra", + "columnName": "extra", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "replying", + "columnName": "replying", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "forwarding", + "columnName": "forwarding", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "uid", + "columnName": "uid", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "msgid", + "columnName": "msgid", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "references", + "columnName": "references", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "deliveredto", + "columnName": "deliveredto", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "inreplyto", + "columnName": "inreplyto", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "thread", + "columnName": "thread", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "avatar", + "columnName": "avatar", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "from", + "columnName": "from", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "to", + "columnName": "to", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "cc", + "columnName": "cc", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "bcc", + "columnName": "bcc", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "reply", + "columnName": "reply", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "headers", + "columnName": "headers", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "size", + "columnName": "size", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "content", + "columnName": "content", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "preview", + "columnName": "preview", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "sent", + "columnName": "sent", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "received", + "columnName": "received", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "stored", + "columnName": "stored", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "seen", + "columnName": "seen", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "answered", + "columnName": "answered", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "flagged", + "columnName": "flagged", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "keywords", + "columnName": "keywords", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "ui_seen", + "columnName": "ui_seen", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "ui_answered", + "columnName": "ui_answered", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "ui_flagged", + "columnName": "ui_flagged", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "ui_hide", + "columnName": "ui_hide", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "ui_found", + "columnName": "ui_found", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "ui_ignored", + "columnName": "ui_ignored", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "ui_browsed", + "columnName": "ui_browsed", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "error", + "columnName": "error", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "last_attempt", + "columnName": "last_attempt", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_message_account", + "unique": false, + "columnNames": [ + "account" + ], + "createSql": "CREATE INDEX `index_message_account` ON `${TABLE_NAME}` (`account`)" + }, + { + "name": "index_message_folder", + "unique": false, + "columnNames": [ + "folder" + ], + "createSql": "CREATE INDEX `index_message_folder` ON `${TABLE_NAME}` (`folder`)" + }, + { + "name": "index_message_identity", + "unique": false, + "columnNames": [ + "identity" + ], + "createSql": "CREATE INDEX `index_message_identity` ON `${TABLE_NAME}` (`identity`)" + }, + { + "name": "index_message_replying", + "unique": false, + "columnNames": [ + "replying" + ], + "createSql": "CREATE INDEX `index_message_replying` ON `${TABLE_NAME}` (`replying`)" + }, + { + "name": "index_message_forwarding", + "unique": false, + "columnNames": [ + "forwarding" + ], + "createSql": "CREATE INDEX `index_message_forwarding` ON `${TABLE_NAME}` (`forwarding`)" + }, + { + "name": "index_message_folder_uid", + "unique": true, + "columnNames": [ + "folder", + "uid" + ], + "createSql": "CREATE UNIQUE INDEX `index_message_folder_uid` ON `${TABLE_NAME}` (`folder`, `uid`)" + }, + { + "name": "index_message_msgid_folder", + "unique": true, + "columnNames": [ + "msgid", + "folder" + ], + "createSql": "CREATE UNIQUE INDEX `index_message_msgid_folder` ON `${TABLE_NAME}` (`msgid`, `folder`)" + }, + { + "name": "index_message_thread", + "unique": false, + "columnNames": [ + "thread" + ], + "createSql": "CREATE INDEX `index_message_thread` ON `${TABLE_NAME}` (`thread`)" + }, + { + "name": "index_message_received", + "unique": false, + "columnNames": [ + "received" + ], + "createSql": "CREATE INDEX `index_message_received` ON `${TABLE_NAME}` (`received`)" + }, + { + "name": "index_message_ui_seen", + "unique": false, + "columnNames": [ + "ui_seen" + ], + "createSql": "CREATE INDEX `index_message_ui_seen` ON `${TABLE_NAME}` (`ui_seen`)" + }, + { + "name": "index_message_ui_flagged", + "unique": false, + "columnNames": [ + "ui_flagged" + ], + "createSql": "CREATE INDEX `index_message_ui_flagged` ON `${TABLE_NAME}` (`ui_flagged`)" + }, + { + "name": "index_message_ui_hide", + "unique": false, + "columnNames": [ + "ui_hide" + ], + "createSql": "CREATE INDEX `index_message_ui_hide` ON `${TABLE_NAME}` (`ui_hide`)" + }, + { + "name": "index_message_ui_found", + "unique": false, + "columnNames": [ + "ui_found" + ], + "createSql": "CREATE INDEX `index_message_ui_found` ON `${TABLE_NAME}` (`ui_found`)" + }, + { + "name": "index_message_ui_ignored", + "unique": false, + "columnNames": [ + "ui_ignored" + ], + "createSql": "CREATE INDEX `index_message_ui_ignored` ON `${TABLE_NAME}` (`ui_ignored`)" + }, + { + "name": "index_message_ui_browsed", + "unique": false, + "columnNames": [ + "ui_browsed" + ], + "createSql": "CREATE INDEX `index_message_ui_browsed` ON `${TABLE_NAME}` (`ui_browsed`)" + } + ], + "foreignKeys": [ + { + "table": "account", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "account" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "folder", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "folder" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "identity", + "onDelete": "SET NULL", + "onUpdate": "NO ACTION", + "columns": [ + "identity" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "message", + "onDelete": "SET NULL", + "onUpdate": "NO ACTION", + "columns": [ + "replying" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "message", + "onDelete": "SET NULL", + "onUpdate": "NO ACTION", + "columns": [ + "forwarding" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "attachment", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `message` INTEGER NOT NULL, `sequence` INTEGER NOT NULL, `name` TEXT, `type` TEXT NOT NULL, `cid` TEXT, `size` INTEGER, `progress` INTEGER, `available` INTEGER NOT NULL, FOREIGN KEY(`message`) REFERENCES `message`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "message", + "columnName": "message", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "sequence", + "columnName": "sequence", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "cid", + "columnName": "cid", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "size", + "columnName": "size", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "progress", + "columnName": "progress", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "available", + "columnName": "available", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_attachment_message", + "unique": false, + "columnNames": [ + "message" + ], + "createSql": "CREATE INDEX `index_attachment_message` ON `${TABLE_NAME}` (`message`)" + }, + { + "name": "index_attachment_message_sequence", + "unique": true, + "columnNames": [ + "message", + "sequence" + ], + "createSql": "CREATE UNIQUE INDEX `index_attachment_message_sequence` ON `${TABLE_NAME}` (`message`, `sequence`)" + }, + { + "name": "index_attachment_message_cid", + "unique": true, + "columnNames": [ + "message", + "cid" + ], + "createSql": "CREATE UNIQUE INDEX `index_attachment_message_cid` ON `${TABLE_NAME}` (`message`, `cid`)" + } + ], + "foreignKeys": [ + { + "table": "message", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "message" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "operation", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `folder` INTEGER NOT NULL, `message` INTEGER, `name` TEXT NOT NULL, `args` TEXT NOT NULL, `created` INTEGER NOT NULL, `error` TEXT, FOREIGN KEY(`folder`) REFERENCES `folder`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`message`) REFERENCES `message`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "folder", + "columnName": "folder", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "message", + "columnName": "message", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "args", + "columnName": "args", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "created", + "columnName": "created", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "error", + "columnName": "error", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_operation_folder", + "unique": false, + "columnNames": [ + "folder" + ], + "createSql": "CREATE INDEX `index_operation_folder` ON `${TABLE_NAME}` (`folder`)" + }, + { + "name": "index_operation_message", + "unique": false, + "columnNames": [ + "message" + ], + "createSql": "CREATE INDEX `index_operation_message` ON `${TABLE_NAME}` (`message`)" + } + ], + "foreignKeys": [ + { + "table": "folder", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "folder" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "message", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "message" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "answer", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `name` TEXT NOT NULL, `text` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "text", + "columnName": "text", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "log", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `time` INTEGER NOT NULL, `data` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "time", + "columnName": "time", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "data", + "columnName": "data", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_log_time", + "unique": false, + "columnNames": [ + "time" + ], + "createSql": "CREATE INDEX `index_log_time` ON `${TABLE_NAME}` (`time`)" + } + ], + "foreignKeys": [] + } + ], + "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, \"bfe22cbcb39739e6ce61ce3a2e2857d7\")" + ] + } +} \ No newline at end of file diff --git a/app/src/main/java/eu/faircode/email/AdapterAccount.java b/app/src/main/java/eu/faircode/email/AdapterAccount.java index 6a9e71a82a..5aabbc10d7 100644 --- a/app/src/main/java/eu/faircode/email/AdapterAccount.java +++ b/app/src/main/java/eu/faircode/email/AdapterAccount.java @@ -67,7 +67,7 @@ public class AdapterAccount extends RecyclerView.Adapter() { @Override - protected Void onLoad(Context context, Bundle args) throws Throwable { + protected Void onLoad(Context context, Bundle args) { long id = args.getLong("id"); long aid = args.getLong("account"); String name = args.getString("name"); @@ -144,61 +138,32 @@ public class FragmentFolder extends FragmentEx { if (keep_days < sync_days) keep_days = sync_days; - boolean reload = false; - EntityFolder folder; - - IMAPStore istore = null; + boolean reload; DB db = DB.getInstance(getContext()); try { db.beginTransaction(); - folder = db.folder().getFolder(id); + EntityFolder folder = db.folder().getFolder(id); - if (folder == null || !folder.name.equals(name)) { - EntityAccount account = db.account().getAccount(folder == null ? aid : folder.account); + if (folder == null) { + reload = true; + Log.i(Helper.TAG, "Creating folder=" + name); - Properties props = MessageHelper.getSessionProperties(account.auth_type, account.insecure); - Session isession = Session.getInstance(props, null); - istore = (IMAPStore) isession.getStore(account.starttls ? "imap" : "imaps"); - Helper.connect(context, istore, account); - char separator = istore.getDefaultFolder().getSeparator(); - - if (folder == null) { - Log.i(Helper.TAG, "Creating folder=" + name); - - IMAPFolder ifolder = (IMAPFolder) istore.getFolder(name); - if (ifolder.exists()) - throw new IllegalArgumentException(getString(R.string.title_folder_exists, name)); - ifolder.create(Folder.HOLDS_MESSAGES); - - EntityFolder create = new EntityFolder(); - create.account = aid; - create.name = name; - create.level = EntityFolder.getLevel(separator, name); - create.display = display; - create.hide = hide; - create.type = EntityFolder.USER; - create.unified = unified; - create.synchronize = synchronize; - create.poll = poll; - create.sync_days = sync_days; - create.keep_days = keep_days; - db.folder().insertFolder(create); - } else { - Log.i(Helper.TAG, "Renaming folder=" + name); - - IMAPFolder iold = (IMAPFolder) istore.getFolder(folder.name); - IMAPFolder ifolder = (IMAPFolder) istore.getFolder(name); - if (ifolder.exists()) - throw new IllegalArgumentException(getString(R.string.title_folder_exists, name)); - iold.renameTo(ifolder); - } - } - - if (folder != null) { - reload = (!folder.name.equals(name) || - !folder.synchronize.equals(synchronize) || - !folder.poll.equals(poll)); + EntityFolder create = new EntityFolder(); + create.account = aid; + create.name = name; + create.level = 0; + create.display = display; + create.hide = hide; + create.type = EntityFolder.USER; + create.unified = unified; + create.synchronize = synchronize; + create.poll = poll; + create.sync_days = sync_days; + create.keep_days = keep_days; + db.folder().insertFolder(create); + } else { + reload = (!folder.synchronize.equals(synchronize) || !folder.poll.equals(poll)); Calendar cal_keep = Calendar.getInstance(); cal_keep.add(Calendar.DAY_OF_MONTH, -keep_days); @@ -213,30 +178,25 @@ public class FragmentFolder extends FragmentEx { Log.i(Helper.TAG, "Updating folder=" + name); db.folder().setFolderProperties(id, - name, display, - hide, + name, display, unified, hide, synchronize, poll, - unified, sync_days, keep_days); db.message().deleteMessagesBefore(id, keep_time, true); if (!synchronize) db.folder().setFolderError(id, null); + + EntityOperation.sync(db, folder.id); } db.setTransactionSuccessful(); } finally { db.endTransaction(); - - if (istore != null) - istore.close(); } - if (folder == null || !folder.name.equals(name) || reload) + if (reload) ServiceSynchronize.reload(getContext(), "save folder"); - else - EntityOperation.sync(db, folder.id); return null; } @@ -308,34 +268,11 @@ public class FragmentFolder extends FragmentEx { new SimpleTask() { @Override - protected Void onLoad(Context context, Bundle args) throws Throwable { + protected Void onLoad(Context context, Bundle args) { long id = args.getLong("id"); - IMAPStore istore = null; DB db = DB.getInstance(getContext()); - try { - db.beginTransaction(); - - EntityFolder folder = db.folder().getFolder(id); - EntityAccount account = db.account().getAccount(folder.account); - - Properties props = MessageHelper.getSessionProperties(account.auth_type, account.insecure); - Session isession = Session.getInstance(props, null); - istore = (IMAPStore) isession.getStore(account.starttls ? "imap" : "imaps"); - Helper.connect(context, istore, account); - - IMAPFolder ifolder = (IMAPFolder) istore.getFolder(folder.name); - ifolder.delete(false); - - db.folder().deleteFolder(id); - - db.setTransactionSuccessful(); - } finally { - db.endTransaction(); - - if (istore != null) - istore.close(); - } + db.folder().setFolderTbd(id); ServiceSynchronize.reload(getContext(), "delete folder"); @@ -374,7 +311,7 @@ public class FragmentFolder extends FragmentEx { new SimpleTask() { @Override - protected EntityFolder onLoad(Context context, Bundle args) throws Throwable { + protected EntityFolder onLoad(Context context, Bundle args) { long id = args.getLong("id"); return DB.getInstance(context).folder().getFolder(id); } @@ -382,7 +319,7 @@ public class FragmentFolder extends FragmentEx { @Override protected void onLoaded(Bundle args, EntityFolder folder) { if (savedInstanceState == null) { - etRename.setText(folder == null ? null : folder.name); + etName.setText(folder == null ? null : folder.name); etDisplay.setText(folder == null ? null : (folder.display == null ? folder.name : folder.display)); etDisplay.setHint(folder == null ? null : folder.name); cbHide.setChecked(folder == null ? false : folder.hide); @@ -396,7 +333,7 @@ public class FragmentFolder extends FragmentEx { // Consider previous save as cancelled pbWait.setVisibility(View.GONE); Helper.setViewsEnabled(view, true); - etRename.setEnabled(folder == null || EntityFolder.USER.equals(folder.type)); + etName.setEnabled(folder == null); cbPoll.setEnabled(cbSynchronize.isChecked()); btnSave.setEnabled(true); } diff --git a/app/src/main/java/eu/faircode/email/FragmentIdentity.java b/app/src/main/java/eu/faircode/email/FragmentIdentity.java index 01960231f9..00d485aad9 100644 --- a/app/src/main/java/eu/faircode/email/FragmentIdentity.java +++ b/app/src/main/java/eu/faircode/email/FragmentIdentity.java @@ -752,11 +752,12 @@ public class FragmentIdentity extends FragmentEx { @Override protected Void onLoad(Context context, Bundle args) { long id = args.getLong("id"); + DB db = DB.getInstance(context); - EntityIdentity identity = db.identity().getIdentity(id); - db.identity().deleteIdentity(id); - if (identity.synchronize) - ServiceSynchronize.reload(getContext(), "delete identity"); + db.identity().setIdentityTbd(id); + + ServiceSynchronize.reload(getContext(), "delete identity"); + return null; } diff --git a/app/src/main/java/eu/faircode/email/ServiceSynchronize.java b/app/src/main/java/eu/faircode/email/ServiceSynchronize.java index 73e19e764e..9550d275d3 100644 --- a/app/src/main/java/eu/faircode/email/ServiceSynchronize.java +++ b/app/src/main/java/eu/faircode/email/ServiceSynchronize.java @@ -1796,7 +1796,13 @@ public class ServiceSynchronize extends LifecycleService { List names = new ArrayList<>(); for (EntityFolder folder : db.folder().getUserFolders(account.id)) - names.add(folder.name); + if (folder.tbd == null) + names.add(folder.name); + else { + IMAPFolder ifolder = (IMAPFolder) istore.getFolder(folder.name); + ifolder.delete(false); + db.folder().deleteFolder(folder.id); + } Log.i(Helper.TAG, "Local folder count=" + names.size()); Folder defaultFolder = istore.getDefaultFolder(); @@ -1835,10 +1841,11 @@ public class ServiceSynchronize extends LifecycleService { } } - Log.i(Helper.TAG, "Delete local folder=" + names.size()); + Log.i(Helper.TAG, "Create remote count=" + names.size()); for (String name : names) { - db.folder().deleteFolder(account.id, name); - Log.i(Helper.TAG, name + " deleted"); + Log.i(Helper.TAG, name + " create"); + IMAPFolder ifolder = (IMAPFolder) istore.getFolder(name); + ifolder.create(Folder.HOLDS_MESSAGES); } db.setTransactionSuccessful(); @@ -2318,9 +2325,6 @@ public class ServiceSynchronize extends LifecycleService { private boolean started = false; private int queued = 0; private long lastLost = 0; - PowerManager pm = getSystemService(PowerManager.class); - PowerManager.WakeLock wl = pm.newWakeLock( - PowerManager.PARTIAL_WAKE_LOCK, BuildConfig.APPLICATION_ID + ":manage"); private ExecutorService queue = Executors.newSingleThreadExecutor(Helper.backgroundThreadFactory); @Override @@ -2579,6 +2583,10 @@ public class ServiceSynchronize extends LifecycleService { queued++; queue.submit(new Runnable() { + PowerManager pm = getSystemService(PowerManager.class); + PowerManager.WakeLock wl = pm.newWakeLock( + PowerManager.PARTIAL_WAKE_LOCK, BuildConfig.APPLICATION_ID + ":manage"); + @Override public void run() { try { @@ -2590,6 +2598,12 @@ public class ServiceSynchronize extends LifecycleService { if (doStop) stop(); + DB db = DB.getInstance(ServiceSynchronize.this); + int accounts = db.account().deleteAccountsTbd(); + int identities = db.identity().deleteIdentitiesTbd(); + if (accounts > 0 || identities > 0) + Log.i(Helper.TAG, "Deleted accounts=" + accounts + " identities=" + identities); + if (doStart) start(); diff --git a/app/src/main/res/layout/fragment_folder.xml b/app/src/main/res/layout/fragment_folder.xml index 4eb791254b..2d9de27c58 100644 --- a/app/src/main/res/layout/fragment_folder.xml +++ b/app/src/main/res/layout/fragment_folder.xml @@ -24,7 +24,7 @@ app:layout_constraintTop_toTopOf="parent" /> + app:layout_constraintTop_toBottomOf="@id/etName" /> - - - - - - - - + android:background="?attr/drawableItemBackground"> - + - + - + - + - + - + - + - - \ No newline at end of file + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_folder.xml b/app/src/main/res/layout/item_folder.xml index a73ea567f2..dbdbfadaca 100644 --- a/app/src/main/res/layout/item_folder.xml +++ b/app/src/main/res/layout/item_folder.xml @@ -7,7 +7,8 @@ + android:layout_height="wrap_content" + android:background="?attr/drawableItemBackground"> - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + android:layout_height="wrap_content" + android:background="?attr/drawableItemBackground"> + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file