diff --git a/app/schemas/eu.faircode.email.DB/61.json b/app/schemas/eu.faircode.email.DB/61.json new file mode 100644 index 0000000000..283d4e8c25 --- /dev/null +++ b/app/schemas/eu.faircode.email.DB/61.json @@ -0,0 +1,1646 @@ +{ + "formatVersion": 1, + "database": { + "version": 61, + "identityHash": "6d10b7791db5802567286ff2684d07f9", + "entities": [ + { + "tableName": "identity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `name` TEXT NOT NULL, `email` TEXT NOT NULL, `account` INTEGER NOT NULL, `display` TEXT, `color` INTEGER, `signature` TEXT, `auth_type` 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, `realm` TEXT, `use_ip` INTEGER NOT NULL, `synchronize` INTEGER NOT NULL, `primary` INTEGER NOT NULL, `replyto` TEXT, `bcc` TEXT, `plain_only` INTEGER NOT NULL, `encrypt` INTEGER NOT NULL, `delivery_receipt` INTEGER NOT NULL, `read_receipt` INTEGER NOT NULL, `store_sent` INTEGER NOT NULL, `sent_folder` INTEGER, `tbd` INTEGER, `state` TEXT, `error` TEXT, `last_connected` INTEGER, 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": "account", + "columnName": "account", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "display", + "columnName": "display", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "color", + "columnName": "color", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "signature", + "columnName": "signature", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "auth_type", + "columnName": "auth_type", + "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": "realm", + "columnName": "realm", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "use_ip", + "columnName": "use_ip", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "synchronize", + "columnName": "synchronize", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "primary", + "columnName": "primary", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "replyto", + "columnName": "replyto", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "bcc", + "columnName": "bcc", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "plain_only", + "columnName": "plain_only", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "encrypt", + "columnName": "encrypt", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "delivery_receipt", + "columnName": "delivery_receipt", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "read_receipt", + "columnName": "read_receipt", + "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 + }, + { + "fieldPath": "last_connected", + "columnName": "last_connected", + "affinity": "INTEGER", + "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, `auth_type` INTEGER NOT NULL, `pop` 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, `realm` TEXT, `name` TEXT, `signature` TEXT, `color` INTEGER, `synchronize` INTEGER NOT NULL, `ondemand` INTEGER NOT NULL, `primary` INTEGER NOT NULL, `notify` INTEGER NOT NULL, `browse` INTEGER NOT NULL, `swipe_left` INTEGER, `swipe_right` INTEGER, `poll_interval` INTEGER NOT NULL, `prefix` TEXT, `created` INTEGER, `tbd` INTEGER, `state` TEXT, `error` TEXT, `last_connected` INTEGER)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "auth_type", + "columnName": "auth_type", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "pop", + "columnName": "pop", + "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": "realm", + "columnName": "realm", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "signature", + "columnName": "signature", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "color", + "columnName": "color", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "synchronize", + "columnName": "synchronize", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "ondemand", + "columnName": "ondemand", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "primary", + "columnName": "primary", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "notify", + "columnName": "notify", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "browse", + "columnName": "browse", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "swipe_left", + "columnName": "swipe_left", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "swipe_right", + "columnName": "swipe_right", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "poll_interval", + "columnName": "poll_interval", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "prefix", + "columnName": "prefix", + "affinity": "TEXT", + "notNull": false + }, + { + "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, `parent` INTEGER, `name` TEXT NOT NULL, `type` TEXT NOT NULL, `level` INTEGER NOT NULL, `synchronize` INTEGER NOT NULL, `poll` INTEGER NOT NULL, `download` INTEGER NOT NULL, `sync_days` INTEGER NOT NULL, `keep_days` INTEGER NOT NULL, `display` TEXT, `hide` INTEGER NOT NULL, `collapsed` INTEGER NOT NULL, `unified` INTEGER NOT NULL, `notify` INTEGER NOT NULL, `total` INTEGER, `keywords` TEXT, `initialize` INTEGER NOT NULL, `tbc` INTEGER, `tbd` INTEGER, `state` TEXT, `sync_state` TEXT, `error` TEXT, `last_sync` INTEGER, 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": "parent", + "columnName": "parent", + "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": "download", + "columnName": "download", + "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": "collapsed", + "columnName": "collapsed", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "unified", + "columnName": "unified", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "notify", + "columnName": "notify", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "total", + "columnName": "total", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "keywords", + "columnName": "keywords", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "initialize", + "columnName": "initialize", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "tbc", + "columnName": "tbc", + "affinity": "INTEGER", + "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 + }, + { + "fieldPath": "last_sync", + "columnName": "last_sync", + "affinity": "INTEGER", + "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, `sender` TEXT, `from` TEXT, `to` TEXT, `cc` TEXT, `bcc` TEXT, `reply` TEXT, `headers` TEXT, `raw` INTEGER, `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, `flags` TEXT, `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, `ui_snoozed` INTEGER, `warning` TEXT, `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": "sender", + "columnName": "sender", + "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": "raw", + "columnName": "raw", + "affinity": "INTEGER", + "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": "flags", + "columnName": "flags", + "affinity": "TEXT", + "notNull": false + }, + { + "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": "ui_snoozed", + "columnName": "ui_snoozed", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "warning", + "columnName": "warning", + "affinity": "TEXT", + "notNull": false + }, + { + "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_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_sender", + "unique": false, + "columnNames": [ + "sender" + ], + "createSql": "CREATE INDEX `index_message_sender` ON `${TABLE_NAME}` (`sender`)" + }, + { + "name": "index_message_received", + "unique": false, + "columnNames": [ + "received" + ], + "createSql": "CREATE INDEX `index_message_received` ON `${TABLE_NAME}` (`received`)" + }, + { + "name": "index_message_subject", + "unique": false, + "columnNames": [ + "subject" + ], + "createSql": "CREATE INDEX `index_message_subject` ON `${TABLE_NAME}` (`subject`)" + }, + { + "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`)" + }, + { + "name": "index_message_ui_snoozed", + "unique": false, + "columnNames": [ + "ui_snoozed" + ], + "createSql": "CREATE INDEX `index_message_ui_snoozed` ON `${TABLE_NAME}` (`ui_snoozed`)" + } + ], + "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, `disposition` TEXT, `cid` TEXT, `encryption` INTEGER, `size` INTEGER, `progress` INTEGER, `available` INTEGER NOT NULL, `error` TEXT, 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": "disposition", + "columnName": "disposition", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "cid", + "columnName": "cid", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "encryption", + "columnName": "encryption", + "affinity": "INTEGER", + "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 + }, + { + "fieldPath": "error", + "columnName": "error", + "affinity": "TEXT", + "notNull": false + } + ], + "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, `account` INTEGER, `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": "account", + "columnName": "account", + "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`)" + }, + { + "name": "index_operation_name", + "unique": false, + "columnNames": [ + "name" + ], + "createSql": "CREATE INDEX `index_operation_name` ON `${TABLE_NAME}` (`name`)" + } + ], + "foreignKeys": [ + { + "table": "folder", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "folder" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "message", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "message" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "contact", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `account` INTEGER NOT NULL, `type` INTEGER NOT NULL, `email` TEXT NOT NULL, `name` TEXT, `avatar` TEXT, `times_contacted` INTEGER NOT NULL, `first_contacted` INTEGER NOT NULL, `last_contacted` INTEGER NOT NULL, `state` INTEGER NOT NULL, 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": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "email", + "columnName": "email", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "avatar", + "columnName": "avatar", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "times_contacted", + "columnName": "times_contacted", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "first_contacted", + "columnName": "first_contacted", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "last_contacted", + "columnName": "last_contacted", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "state", + "columnName": "state", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_contact_account_type_email", + "unique": true, + "columnNames": [ + "account", + "type", + "email" + ], + "createSql": "CREATE UNIQUE INDEX `index_contact_account_type_email` ON `${TABLE_NAME}` (`account`, `type`, `email`)" + }, + { + "name": "index_contact_email", + "unique": false, + "columnNames": [ + "email" + ], + "createSql": "CREATE INDEX `index_contact_email` ON `${TABLE_NAME}` (`email`)" + }, + { + "name": "index_contact_name", + "unique": false, + "columnNames": [ + "name" + ], + "createSql": "CREATE INDEX `index_contact_name` ON `${TABLE_NAME}` (`name`)" + }, + { + "name": "index_contact_avatar", + "unique": false, + "columnNames": [ + "avatar" + ], + "createSql": "CREATE INDEX `index_contact_avatar` ON `${TABLE_NAME}` (`avatar`)" + }, + { + "name": "index_contact_times_contacted", + "unique": false, + "columnNames": [ + "times_contacted" + ], + "createSql": "CREATE INDEX `index_contact_times_contacted` ON `${TABLE_NAME}` (`times_contacted`)" + }, + { + "name": "index_contact_last_contacted", + "unique": false, + "columnNames": [ + "last_contacted" + ], + "createSql": "CREATE INDEX `index_contact_last_contacted` ON `${TABLE_NAME}` (`last_contacted`)" + }, + { + "name": "index_contact_state", + "unique": false, + "columnNames": [ + "state" + ], + "createSql": "CREATE INDEX `index_contact_state` ON `${TABLE_NAME}` (`state`)" + } + ], + "foreignKeys": [ + { + "table": "account", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "account" + ], + "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": "rule", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `folder` INTEGER NOT NULL, `name` TEXT NOT NULL, `order` INTEGER NOT NULL, `enabled` INTEGER NOT NULL, `stop` INTEGER NOT NULL, `condition` TEXT NOT NULL, `action` TEXT NOT NULL, FOREIGN KEY(`folder`) REFERENCES `folder`(`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": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "order", + "columnName": "order", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "enabled", + "columnName": "enabled", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "stop", + "columnName": "stop", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "condition", + "columnName": "condition", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "action", + "columnName": "action", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_rule_folder", + "unique": false, + "columnNames": [ + "folder" + ], + "createSql": "CREATE INDEX `index_rule_folder` ON `${TABLE_NAME}` (`folder`)" + }, + { + "name": "index_rule_order", + "unique": false, + "columnNames": [ + "order" + ], + "createSql": "CREATE INDEX `index_rule_order` ON `${TABLE_NAME}` (`order`)" + } + ], + "foreignKeys": [ + { + "table": "folder", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "folder" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "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, \"6d10b7791db5802567286ff2684d07f9\")" + ] + } +} \ No newline at end of file diff --git a/app/src/main/java/eu/faircode/email/AdapterFolder.java b/app/src/main/java/eu/faircode/email/AdapterFolder.java index 2cc7bf528f..32b3933ba8 100644 --- a/app/src/main/java/eu/faircode/email/AdapterFolder.java +++ b/app/src/main/java/eu/faircode/email/AdapterFolder.java @@ -64,24 +64,25 @@ public class AdapterFolder extends RecyclerView.Adapter all = new ArrayList<>(); - private List filtered = new ArrayList<>(); - private List collapsed = new ArrayList<>(); + private List items = new ArrayList<>(); private static NumberFormat nf = NumberFormat.getNumberInstance(); public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener { private View view; private View vwColor; - private ImageView ivExpander; - private View vwLevel; private ImageView ivState; + private View vwLevel; + private ImageView ivExpander; private ImageView ivNotify; private TextView tvName; private TextView tvMessages; @@ -109,9 +110,9 @@ public class AdapterFolder extends RecyclerView.Adapter 0 ? View.VISIBLE : View.INVISIBLE); - - if (account > 0) { - ViewGroup.LayoutParams lp = vwLevel.getLayoutParams(); - lp.width = (EntityFolder.USER.equals(folder.type) ? folder.level : 0) * dp12; - vwLevel.setLayoutParams(lp); - } - if (folder.sync_state == null || "requested".equals(folder.sync_state)) { if ("waiting".equals(folder.state)) ivState.setImageResource(R.drawable.baseline_hourglass_empty_24); @@ -189,14 +180,22 @@ public class AdapterFolder extends RecyclerView.Adapter 0 ? View.VISIBLE : View.INVISIBLE)); + ivNotify.setVisibility(folder.notify ? View.VISIBLE : View.GONE); if (folder.unseen > 0) tvName.setText(context.getString(R.string.title_name_count, - folder.getDisplayName(context), + folder.getDisplayName(context, parent), nf.format(folder.unseen))); else - tvName.setText(folder.getDisplayName(context)); + tvName.setText(folder.getDisplayName(context, parent)); tvName.setTypeface(null, folder.unseen > 0 ? Typeface.BOLD : Typeface.NORMAL); tvName.setTextColor(folder.unseen > 0 ? colorUnread : textColorSecondary); @@ -219,7 +218,7 @@ public class AdapterFolder extends RecyclerView.Adapter 0 && folder.unified ? View.VISIBLE : View.INVISIBLE); + ivUnified.setVisibility(account > 0 && folder.unified ? View.VISIBLE : View.GONE); if (account < 0) tvType.setText(folder.accountName); @@ -255,20 +254,30 @@ public class AdapterFolder extends RecyclerView.Adapter 0) { - DB db = DB.getInstance(context); - cowner.start(); - db.folder().liveFolders(folder.account, folder.id).observe(cowner, new Observer>() { - @Override - public void onChanged(List folders) { - childs.set(account, true, folders); - } - }); - } else - childs.set(account, true, new ArrayList()); + if (account > 0 && folder.childs > 0) { + if (folder.collapsed) { + rvChilds.setVisibility(View.GONE); + childs.set(account, folder, level + 1, new ArrayList()); + } else { + DB db = DB.getInstance(context); + cowner.start(); + rvChilds.setVisibility(View.VISIBLE); + childs.set(folder.account, folder, level + 1, properties.getChilds(folder.id)); + db.folder().liveFolders(folder.account, folder.id).observe(cowner, new Observer>() { + @Override + public void onChanged(List folders) { + if (folders == null) + folders = new ArrayList<>(); + properties.setChilds(folder.id, folders); + childs.set(account, folder, level + 1, folders); + } + }); + } + } else { + rvChilds.setVisibility(View.GONE); + childs.set(account, null, 0, new ArrayList()); + } } @Override @@ -277,24 +286,13 @@ public class AdapterFolder extends RecyclerView.Adapter() { + @Override + protected Void onExecute(Context context, Bundle args) { + long id = args.getLong("id"); + boolean collapsed = args.getBoolean("collapsed"); + + DB db = DB.getInstance(context); + db.folder().setFolderCollapsed(id, collapsed); + + return null; + } + + @Override + protected void onException(Bundle args, Throwable ex) { + Helper.unexpectedError(context, owner, ex); + } + }.execute(context, owner, args, "folder:collapse"); + } + @Override public boolean onLongClick(View v) { int pos = getAdapterPosition(); if (pos == RecyclerView.NO_POSITION) return false; - final TupleFolderEx folder = filtered.get(pos); + final TupleFolderEx folder = items.get(pos); if (folder.tbd != null) return false; @@ -504,10 +526,11 @@ public class AdapterFolder extends RecyclerView.Adapter folders) { + public void set(final long account, EntityFolder parent, int level, @NonNull List folders) { Log.i("Set account=" + account + " folders=" + folders.size()); this.account = account; + this.parent = parent; + this.level = level; final Collator collator = Collator.getInstance(Locale.getDefault()); collator.setStrength(Collator.SECONDARY); // Case insensitive, process accents etc @@ -569,18 +590,9 @@ public class AdapterFolder extends RecyclerView.Adapter shown = new ArrayList<>(); - for (EntityFolder folder : folders) - if (!folder.hide || showAll) - shown.add((TupleFolderEx) folder); - - DiffUtil.DiffResult diff = DiffUtil.calculateDiff(new DiffCallback(filtered, shown), false); - - filtered = shown; + items = folders; diff.dispatchUpdatesTo(new ListUpdateCallback() { @Override @@ -642,12 +654,12 @@ public class AdapterFolder extends RecyclerView.Adapter childs); + + List getChilds(long parent); + } } diff --git a/app/src/main/java/eu/faircode/email/Core.java b/app/src/main/java/eu/faircode/email/Core.java index a4763ef8ec..f6940f90b3 100644 --- a/app/src/main/java/eu/faircode/email/Core.java +++ b/app/src/main/java/eu/faircode/email/Core.java @@ -755,7 +755,6 @@ class Core { if (type != null) { names.remove(fullName); - int level = EntityFolder.getLevel(separator, fullName); String display = null; if (account.prefix != null && fullName.startsWith(account.prefix + separator)) display = fullName.substring(account.prefix.length() + 1); @@ -767,7 +766,6 @@ class Core { folder.name = fullName; folder.display = display; folder.type = (EntityFolder.SYSTEM.equals(type) ? type : EntityFolder.USER); - folder.level = level; folder.synchronize = false; folder.poll = ("imap.gmail.com".equals(account.host)); folder.sync_days = EntityFolder.DEFAULT_SYNC; @@ -791,8 +789,6 @@ class Core { } } - db.folder().setFolderLevel(folder.id, level); - // Compatibility if ("Inbox_sub".equals(folder.type)) db.folder().setFolderType(folder.id, EntityFolder.USER); diff --git a/app/src/main/java/eu/faircode/email/DB.java b/app/src/main/java/eu/faircode/email/DB.java index 09279591c9..51239b3db9 100644 --- a/app/src/main/java/eu/faircode/email/DB.java +++ b/app/src/main/java/eu/faircode/email/DB.java @@ -50,7 +50,7 @@ import io.requery.android.database.sqlite.RequerySQLiteOpenHelperFactory; // https://developer.android.com/topic/libraries/architecture/room.html @Database( - version = 60, + version = 61, entities = { EntityIdentity.class, EntityAccount.class, @@ -662,6 +662,13 @@ public abstract class DB extends RoomDatabase { db.execSQL("ALTER TABLE `folder` ADD COLUMN `parent` INTEGER"); } }) + .addMigrations(new Migration(60, 61) { + @Override + public void migrate(SupportSQLiteDatabase db) { + Log.i("DB migration from version " + startVersion + " to " + endVersion); + db.execSQL("ALTER TABLE `folder` ADD COLUMN `collapsed` INTEGER NOT NULL DEFAULT 0"); + } + }) .build(); } diff --git a/app/src/main/java/eu/faircode/email/DaoFolder.java b/app/src/main/java/eu/faircode/email/DaoFolder.java index 06c12dcd24..ae598012d0 100644 --- a/app/src/main/java/eu/faircode/email/DaoFolder.java +++ b/app/src/main/java/eu/faircode/email/DaoFolder.java @@ -159,12 +159,12 @@ public interface DaoFolder { @Query("UPDATE folder SET display = :display WHERE id = :id") int setFolderDisplay(long id, String display); - @Query("UPDATE folder SET level = :level WHERE id = :id") - int setFolderLevel(long id, int level); - @Query("UPDATE folder SET parent = :parent WHERE id = :id") int setFolderParent(long id, Long parent); + @Query("UPDATE folder SET collapsed = :collapsed WHERE id = :id") + int setFolderCollapsed(long id, boolean collapsed); + @Query("UPDATE folder" + " SET type = '" + EntityFolder.USER + "'" + " WHERE account = :account" + diff --git a/app/src/main/java/eu/faircode/email/EntityFolder.java b/app/src/main/java/eu/faircode/email/EntityFolder.java index beea912f74..aab1a2f561 100644 --- a/app/src/main/java/eu/faircode/email/EntityFolder.java +++ b/app/src/main/java/eu/faircode/email/EntityFolder.java @@ -69,7 +69,7 @@ public class EntityFolder implements Serializable { @NonNull public String type; @NonNull - public Integer level; + public Integer level = 0; // obsolete @NonNull public Boolean synchronize; @NonNull @@ -84,6 +84,8 @@ public class EntityFolder implements Serializable { @NonNull public Boolean hide = false; @NonNull + public Boolean collapsed = false; + @NonNull public Boolean unified = false; @NonNull public Boolean notify = false; @@ -200,6 +202,13 @@ public class EntityFolder implements Serializable { return (display == null ? Helper.localizeFolderName(context, name) : display); } + String getDisplayName(Context context, EntityFolder parent) { + String n = name; + if (parent != null && name.startsWith(parent.name)) + n = n.substring(parent.name.length() + 1); + return (display == null ? Helper.localizeFolderName(context, n) : display); + } + boolean isOutgoing() { return isOutgoing(this.type); } @@ -227,19 +236,6 @@ public class EntityFolder implements Serializable { return USER; } - static int getLevel(Character separator, String name) { - int level = 0; - if (separator != null) { - for (int i = 0; i < name.length(); i++) - if (name.charAt(i) == separator) - level++; - if (name.startsWith("INBOX" + separator)) - level--; - } - - return level; - } - String getParentName(Character separator) { if (separator == null) return null; @@ -250,7 +246,6 @@ public class EntityFolder implements Serializable { else return name.substring(0, p); } - } @Override @@ -261,7 +256,6 @@ public class EntityFolder implements Serializable { Objects.equals(this.account, other.account) && this.name.equals(other.name) && this.type.equals(other.type) && - this.level.equals(other.level) && this.synchronize.equals(other.synchronize) && this.poll.equals(other.poll) && this.download.equals(other.download) && @@ -269,6 +263,7 @@ public class EntityFolder implements Serializable { this.keep_days.equals(other.keep_days) && Objects.equals(this.display, other.display) && this.hide == other.hide && + this.collapsed == other.collapsed && this.unified == other.unified && this.notify == other.notify && Objects.equals(this.total, other.total) && @@ -292,7 +287,6 @@ public class EntityFolder implements Serializable { json.put("id", id); json.put("name", name); json.put("type", type); - json.put("level", level); json.put("synchronize", synchronize); json.put("poll", poll); json.put("download", download); @@ -300,6 +294,7 @@ public class EntityFolder implements Serializable { json.put("keep_days", keep_days); json.put("display", display); json.put("hide", hide); + json.put("collapsed", collapsed); json.put("unified", unified); json.put("notify", notify); return json; @@ -313,11 +308,6 @@ public class EntityFolder implements Serializable { folder.name = json.getString("name"); folder.type = json.getString("type"); - if (json.has("level")) - folder.level = json.getInt("level"); - else - folder.level = 0; - folder.synchronize = json.getBoolean("synchronize"); if (json.has("poll")) @@ -341,6 +331,8 @@ public class EntityFolder implements Serializable { if (json.has("hide")) folder.hide = json.getBoolean("hide"); + if (json.has("collapsed")) + folder.collapsed = json.getBoolean("collapsed"); folder.unified = json.getBoolean("unified"); diff --git a/app/src/main/java/eu/faircode/email/FragmentAccount.java b/app/src/main/java/eu/faircode/email/FragmentAccount.java index f7210f122a..e65a45d9fb 100644 --- a/app/src/main/java/eu/faircode/email/FragmentAccount.java +++ b/app/src/main/java/eu/faircode/email/FragmentAccount.java @@ -1013,7 +1013,6 @@ public class FragmentAccount extends FragmentBase { db.folder().setFoldersUser(account.id); for (EntityFolder folder : folders) { - folder.level = EntityFolder.getLevel(separator, folder.name); if (account.prefix != null && folder.name.startsWith(account.prefix + separator)) folder.display = folder.name.substring(account.prefix.length() + 1); @@ -1025,7 +1024,6 @@ public class FragmentAccount extends FragmentBase { } else { EntityLog.log(context, "Updated folder=" + folder.name + " type=" + folder.type); db.folder().setFolderType(existing.id, folder.type); - db.folder().setFolderLevel(existing.id, folder.level); } } diff --git a/app/src/main/java/eu/faircode/email/FragmentFolder.java b/app/src/main/java/eu/faircode/email/FragmentFolder.java index dfd612fa78..3c039e33a5 100644 --- a/app/src/main/java/eu/faircode/email/FragmentFolder.java +++ b/app/src/main/java/eu/faircode/email/FragmentFolder.java @@ -213,7 +213,6 @@ public class FragmentFolder extends FragmentBase { EntityFolder create = new EntityFolder(); create.account = aid; create.name = name; - create.level = 0; create.display = display; create.hide = hide; create.type = EntityFolder.USER; diff --git a/app/src/main/java/eu/faircode/email/FragmentFolders.java b/app/src/main/java/eu/faircode/email/FragmentFolders.java index a7e0e2fbea..fef4c75e5b 100644 --- a/app/src/main/java/eu/faircode/email/FragmentFolders.java +++ b/app/src/main/java/eu/faircode/email/FragmentFolders.java @@ -24,6 +24,7 @@ import android.content.Intent; import android.content.SharedPreferences; import android.graphics.Color; import android.os.Bundle; +import android.util.LongSparseArray; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; @@ -35,6 +36,7 @@ import android.widget.ImageButton; import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.google.android.material.snackbar.Snackbar; +import java.util.ArrayList; import java.util.List; import androidx.annotation.NonNull; @@ -65,7 +67,7 @@ public class FragmentFolders extends FragmentBase { private boolean searching = false; private AdapterFolder adapter; - private Boolean show_hidden = null; + private static LongSparseArray> parentChilds = new LongSparseArray<>(); @Override public void onCreate(Bundle savedInstanceState) { @@ -128,7 +130,18 @@ public class FragmentFolders extends FragmentBase { LinearLayoutManager llm = new LinearLayoutManager(getContext()); rvFolder.setLayoutManager(llm); - adapter = new AdapterFolder(getContext(), getViewLifecycleOwner()); + adapter = new AdapterFolder(getContext(), getViewLifecycleOwner(), new AdapterFolder.IProperties() { + @Override + public void setChilds(long parent, List childs) { + parentChilds.put(parent, childs); + } + + @Override + public List getChilds(long parent) { + List childs = parentChilds.get(parent); + return (childs == null ? new ArrayList() : childs); + } + }); rvFolder.setAdapter(adapter); fab.setOnClickListener(new View.OnClickListener() { @@ -188,22 +201,10 @@ public class FragmentFolders extends FragmentBase { return view; } - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - if (show_hidden != null) - outState.putBoolean("fair:show_hidden", show_hidden); - } - @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); - if (savedInstanceState != null) { - show_hidden = (Boolean) savedInstanceState.get("fair:show_hidden"); - getActivity().invalidateOptionsMenu(); - } - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext()); grpHintActions.setVisibility(prefs.getBoolean("folder_actions", false) ? View.GONE : View.VISIBLE); grpHintSync.setVisibility(prefs.getBoolean("folder_sync", false) ? View.GONE : View.VISIBLE); @@ -247,26 +248,7 @@ public class FragmentFolders extends FragmentBase { return; } - boolean has_hidden = false; - for (TupleFolderEx folder : folders) - if (folder.hide) { - has_hidden = true; - break; - } - - if (has_hidden) { - if (show_hidden == null) { - show_hidden = false; - getActivity().invalidateOptionsMenu(); - } - } else { - if (show_hidden != null) { - show_hidden = null; - getActivity().invalidateOptionsMenu(); - } - } - - adapter.set(account, show_hidden == null || show_hidden, folders); + adapter.set(account, null, 0, folders); pbWait.setVisibility(View.GONE); grpReady.setVisibility(View.VISIBLE); @@ -368,38 +350,4 @@ public class FragmentFolders extends FragmentBase { super.onCreateOptionsMenu(menu, inflater); } - - @Override - public void onPrepareOptionsMenu(Menu menu) { - menu.findItem(R.id.menu_search).setVisible(account < 0); - - MenuItem item = menu.findItem(R.id.menu_show_hidden); - if (show_hidden != null) { - item.setTitle(show_hidden ? R.string.title_hide_folders : R.string.title_show_folders); - item.setIcon(show_hidden ? R.drawable.baseline_visibility_off_24 : R.drawable.baseline_visibility_24); - } - item.setVisible(show_hidden != null); - - super.onPrepareOptionsMenu(menu); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.menu_show_hidden: - onMenuShowHidden(); - return true; - default: - return super.onOptionsItemSelected(item); - } - } - - private void onMenuShowHidden() { - if (show_hidden == null) - show_hidden = false; - else - show_hidden = !show_hidden; - getActivity().invalidateOptionsMenu(); - adapter.showHidden(show_hidden); - } } diff --git a/app/src/main/java/eu/faircode/email/FragmentQuickSetup.java b/app/src/main/java/eu/faircode/email/FragmentQuickSetup.java index 660eec913a..89ec414a4c 100644 --- a/app/src/main/java/eu/faircode/email/FragmentQuickSetup.java +++ b/app/src/main/java/eu/faircode/email/FragmentQuickSetup.java @@ -286,7 +286,6 @@ public class FragmentQuickSetup extends FragmentBase { EntityFolder folder = new EntityFolder(); folder.name = fullName; folder.type = type; - folder.level = EntityFolder.getLevel(separator, folder.name); folder.synchronize = (sync >= 0); folder.download = (sync < 0 ? true : EntityFolder.SYSTEM_FOLDER_DOWNLOAD.get(sync)); folder.sync_days = EntityFolder.DEFAULT_SYNC; diff --git a/app/src/main/java/eu/faircode/email/FragmentSetup.java b/app/src/main/java/eu/faircode/email/FragmentSetup.java index f689bcd572..fadae369f4 100644 --- a/app/src/main/java/eu/faircode/email/FragmentSetup.java +++ b/app/src/main/java/eu/faircode/email/FragmentSetup.java @@ -239,7 +239,6 @@ public class FragmentSetup extends FragmentBase { outbox = new EntityFolder(); outbox.name = "OUTBOX"; outbox.type = EntityFolder.OUTBOX; - outbox.level = 0; outbox.synchronize = false; outbox.sync_days = 0; outbox.keep_days = 0; diff --git a/app/src/main/res/layout/item_folder.xml b/app/src/main/res/layout/item_folder.xml index 4729e9928c..4dfff4dc3d 100644 --- a/app/src/main/res/layout/item_folder.xml +++ b/app/src/main/res/layout/item_folder.xml @@ -20,64 +20,61 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> + + + + - - - - - - diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 648b4221c5..e5c3c66c22 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -289,9 +289,7 @@ Folder name Display name - Hide hidden folders - Show hidden folders - Hide from list + Hide from menus Show in unified inbox Synchronize (receive messages) Check periodically instead of continuous synchronize