@ -0,0 +1,832 @@ | |||||
{ | |||||
"formatVersion": 1, | |||||
"database": { | |||||
"version": 4, | |||||
"identityHash": "334fa594d108afe37ea079b4e2081e38", | |||||
"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, `port` INTEGER NOT NULL, `starttls` INTEGER NOT NULL, `user` TEXT NOT NULL, `password` TEXT NOT NULL, `primary` INTEGER NOT NULL, `synchronize` INTEGER NOT NULL, `store_sent` INTEGER NOT NULL, `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": "port", | |||||
"columnName": "port", | |||||
"affinity": "INTEGER", | |||||
"notNull": true | |||||
}, | |||||
{ | |||||
"fieldPath": "starttls", | |||||
"columnName": "starttls", | |||||
"affinity": "INTEGER", | |||||
"notNull": true | |||||
}, | |||||
{ | |||||
"fieldPath": "user", | |||||
"columnName": "user", | |||||
"affinity": "TEXT", | |||||
"notNull": true | |||||
}, | |||||
{ | |||||
"fieldPath": "password", | |||||
"columnName": "password", | |||||
"affinity": "TEXT", | |||||
"notNull": true | |||||
}, | |||||
{ | |||||
"fieldPath": "primary", | |||||
"columnName": "primary", | |||||
"affinity": "INTEGER", | |||||
"notNull": true | |||||
}, | |||||
{ | |||||
"fieldPath": "synchronize", | |||||
"columnName": "synchronize", | |||||
"affinity": "INTEGER", | |||||
"notNull": true | |||||
}, | |||||
{ | |||||
"fieldPath": "store_sent", | |||||
"columnName": "store_sent", | |||||
"affinity": "INTEGER", | |||||
"notNull": true | |||||
}, | |||||
{ | |||||
"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`)" | |||||
} | |||||
], | |||||
"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, `host` TEXT NOT NULL, `port` INTEGER NOT NULL, `user` TEXT NOT NULL, `password` TEXT NOT NULL, `primary` INTEGER NOT NULL, `synchronize` INTEGER NOT NULL, `store_sent` INTEGER NOT NULL, `poll_interval` INTEGER NOT NULL, `seen_until` INTEGER, `state` TEXT, `error` TEXT)", | |||||
"fields": [ | |||||
{ | |||||
"fieldPath": "id", | |||||
"columnName": "id", | |||||
"affinity": "INTEGER", | |||||
"notNull": false | |||||
}, | |||||
{ | |||||
"fieldPath": "name", | |||||
"columnName": "name", | |||||
"affinity": "TEXT", | |||||
"notNull": false | |||||
}, | |||||
{ | |||||
"fieldPath": "host", | |||||
"columnName": "host", | |||||
"affinity": "TEXT", | |||||
"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": "primary", | |||||
"columnName": "primary", | |||||
"affinity": "INTEGER", | |||||
"notNull": true | |||||
}, | |||||
{ | |||||
"fieldPath": "synchronize", | |||||
"columnName": "synchronize", | |||||
"affinity": "INTEGER", | |||||
"notNull": true | |||||
}, | |||||
{ | |||||
"fieldPath": "store_sent", | |||||
"columnName": "store_sent", | |||||
"affinity": "INTEGER", | |||||
"notNull": true | |||||
}, | |||||
{ | |||||
"fieldPath": "poll_interval", | |||||
"columnName": "poll_interval", | |||||
"affinity": "INTEGER", | |||||
"notNull": true | |||||
}, | |||||
{ | |||||
"fieldPath": "seen_until", | |||||
"columnName": "seen_until", | |||||
"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": [], | |||||
"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, `synchronize` INTEGER NOT NULL, `after` INTEGER NOT NULL, `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": "synchronize", | |||||
"columnName": "synchronize", | |||||
"affinity": "INTEGER", | |||||
"notNull": true | |||||
}, | |||||
{ | |||||
"fieldPath": "after", | |||||
"columnName": "after", | |||||
"affinity": "INTEGER", | |||||
"notNull": true | |||||
}, | |||||
{ | |||||
"fieldPath": "state", | |||||
"columnName": "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`)" | |||||
} | |||||
], | |||||
"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, `folder` INTEGER NOT NULL, `identity` INTEGER, `replying` INTEGER, `uid` INTEGER, `msgid` TEXT, `references` TEXT, `inreplyto` TEXT, `thread` TEXT, `from` TEXT, `to` TEXT, `cc` TEXT, `bcc` TEXT, `reply` TEXT, `subject` TEXT, `sent` INTEGER, `received` INTEGER NOT NULL, `stored` INTEGER NOT NULL, `seen` INTEGER NOT NULL, `ui_seen` INTEGER NOT NULL, `ui_hide` INTEGER NOT NULL, `error` TEXT, 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 CASCADE , FOREIGN KEY(`replying`) 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": "identity", | |||||
"columnName": "identity", | |||||
"affinity": "INTEGER", | |||||
"notNull": false | |||||
}, | |||||
{ | |||||
"fieldPath": "replying", | |||||
"columnName": "replying", | |||||
"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": "inreplyto", | |||||
"columnName": "inreplyto", | |||||
"affinity": "TEXT", | |||||
"notNull": false | |||||
}, | |||||
{ | |||||
"fieldPath": "thread", | |||||
"columnName": "thread", | |||||
"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": "subject", | |||||
"columnName": "subject", | |||||
"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": "ui_seen", | |||||
"columnName": "ui_seen", | |||||
"affinity": "INTEGER", | |||||
"notNull": true | |||||
}, | |||||
{ | |||||
"fieldPath": "ui_hide", | |||||
"columnName": "ui_hide", | |||||
"affinity": "INTEGER", | |||||
"notNull": true | |||||
}, | |||||
{ | |||||
"fieldPath": "error", | |||||
"columnName": "error", | |||||
"affinity": "TEXT", | |||||
"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_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_hide", | |||||
"unique": false, | |||||
"columnNames": [ | |||||
"ui_hide" | |||||
], | |||||
"createSql": "CREATE INDEX `index_message_ui_hide` ON `${TABLE_NAME}` (`ui_hide`)" | |||||
} | |||||
], | |||||
"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": "CASCADE", | |||||
"onUpdate": "NO ACTION", | |||||
"columns": [ | |||||
"identity" | |||||
], | |||||
"referencedColumns": [ | |||||
"id" | |||||
] | |||||
}, | |||||
{ | |||||
"table": "message", | |||||
"onDelete": "CASCADE", | |||||
"onUpdate": "NO ACTION", | |||||
"columns": [ | |||||
"replying" | |||||
], | |||||
"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, `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": "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`)" | |||||
} | |||||
], | |||||
"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 NOT NULL, `name` TEXT NOT NULL, `args` TEXT NOT NULL, `created` INTEGER NOT NULL, 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": true | |||||
}, | |||||
{ | |||||
"fieldPath": "name", | |||||
"columnName": "name", | |||||
"affinity": "TEXT", | |||||
"notNull": true | |||||
}, | |||||
{ | |||||
"fieldPath": "args", | |||||
"columnName": "args", | |||||
"affinity": "TEXT", | |||||
"notNull": true | |||||
}, | |||||
{ | |||||
"fieldPath": "created", | |||||
"columnName": "created", | |||||
"affinity": "INTEGER", | |||||
"notNull": true | |||||
} | |||||
], | |||||
"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": [] | |||||
} | |||||
], | |||||
"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, \"334fa594d108afe37ea079b4e2081e38\")" | |||||
] | |||||
} | |||||
} |
@ -0,0 +1,168 @@ | |||||
package eu.faircode.email; | |||||
/* | |||||
This file is part of FairEmail. | |||||
FairEmail is free software: you can redistribute it and/or modify | |||||
it under the terms of the GNU General Public License as published by | |||||
the Free Software Foundation, either version 3 of the License, or | |||||
(at your option) any later version. | |||||
NetGuard 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 General Public License for more details. | |||||
You should have received a copy of the GNU General Public License | |||||
along with NetGuard. If not, see <http://www.gnu.org/licenses/>. | |||||
Copyright 2018 by Marcel Bokhorst (M66B) | |||||
*/ | |||||
import android.content.Context; | |||||
import android.util.Log; | |||||
import android.view.LayoutInflater; | |||||
import android.view.View; | |||||
import android.view.ViewGroup; | |||||
import android.widget.TextView; | |||||
import java.text.Collator; | |||||
import java.util.ArrayList; | |||||
import java.util.Collections; | |||||
import java.util.Comparator; | |||||
import java.util.List; | |||||
import java.util.Locale; | |||||
import androidx.annotation.NonNull; | |||||
import androidx.recyclerview.widget.DiffUtil; | |||||
import androidx.recyclerview.widget.ListUpdateCallback; | |||||
import androidx.recyclerview.widget.RecyclerView; | |||||
public class AdapterAnswer extends RecyclerView.Adapter<AdapterAnswer.ViewHolder> { | |||||
private Context context; | |||||
private List<EntityAnswer> all = new ArrayList<>(); | |||||
private List<EntityAnswer> filtered = new ArrayList<>(); | |||||
public class ViewHolder extends RecyclerView.ViewHolder { | |||||
View itemView; | |||||
TextView tvName; | |||||
ViewHolder(View itemView) { | |||||
super(itemView); | |||||
this.itemView = itemView; | |||||
tvName = itemView.findViewById(R.id.tvName); | |||||
} | |||||
private void bindTo(EntityAnswer answer) { | |||||
tvName.setText(answer.name); | |||||
} | |||||
} | |||||
AdapterAnswer(Context context) { | |||||
this.context = context; | |||||
setHasStableIds(true); | |||||
} | |||||
public void set(@NonNull List<EntityAnswer> answers) { | |||||
Log.i(Helper.TAG, "Set answers=" + answers.size()); | |||||
final Collator collator = Collator.getInstance(Locale.getDefault()); | |||||
collator.setStrength(Collator.SECONDARY); // Case insensitive, process accents etc | |||||
Collections.sort(answers, new Comparator<EntityAnswer>() { | |||||
@Override | |||||
public int compare(EntityAnswer a1, EntityAnswer a2) { | |||||
return collator.compare(a1.name, a2.name); | |||||
} | |||||
}); | |||||
all.clear(); | |||||
all.addAll(answers); | |||||
DiffUtil.DiffResult diff = DiffUtil.calculateDiff(new MessageDiffCallback(filtered, all)); | |||||
filtered.clear(); | |||||
filtered.addAll(all); | |||||
diff.dispatchUpdatesTo(new ListUpdateCallback() { | |||||
@Override | |||||
public void onInserted(int position, int count) { | |||||
Log.i(Helper.TAG, "Inserted @" + position + " #" + count); | |||||
} | |||||
@Override | |||||
public void onRemoved(int position, int count) { | |||||
Log.i(Helper.TAG, "Removed @" + position + " #" + count); | |||||
} | |||||
@Override | |||||
public void onMoved(int fromPosition, int toPosition) { | |||||
Log.i(Helper.TAG, "Moved " + fromPosition + ">" + toPosition); | |||||
} | |||||
@Override | |||||
public void onChanged(int position, int count, Object payload) { | |||||
Log.i(Helper.TAG, "Changed @" + position + " #" + count); | |||||
} | |||||
}); | |||||
diff.dispatchUpdatesTo(this); | |||||
} | |||||
private class MessageDiffCallback extends DiffUtil.Callback { | |||||
private List<EntityAnswer> prev; | |||||
private List<EntityAnswer> next; | |||||
MessageDiffCallback(List<EntityAnswer> prev, List<EntityAnswer> next) { | |||||
this.prev = prev; | |||||
this.next = next; | |||||
} | |||||
@Override | |||||
public int getOldListSize() { | |||||
return prev.size(); | |||||
} | |||||
@Override | |||||
public int getNewListSize() { | |||||
return next.size(); | |||||
} | |||||
@Override | |||||
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) { | |||||
EntityAnswer a1 = prev.get(oldItemPosition); | |||||
EntityAnswer a2 = next.get(newItemPosition); | |||||
return a1.id.equals(a2.id); | |||||
} | |||||
@Override | |||||
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { | |||||
EntityAnswer a1 = prev.get(oldItemPosition); | |||||
EntityAnswer a2 = next.get(newItemPosition); | |||||
return a1.equals(a2); | |||||
} | |||||
} | |||||
@Override | |||||
public long getItemId(int position) { | |||||
return filtered.get(position).id; | |||||
} | |||||
@Override | |||||
public int getItemCount() { | |||||
return filtered.size(); | |||||
} | |||||
@Override | |||||
@NonNull | |||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { | |||||
return new ViewHolder(LayoutInflater.from(context).inflate(R.layout.item_folder, parent, false)); | |||||
} | |||||
@Override | |||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) { | |||||
EntityAnswer answer = filtered.get(position); | |||||
holder.bindTo(answer); | |||||
} | |||||
} |
@ -0,0 +1,46 @@ | |||||
package eu.faircode.email; | |||||
/* | |||||
This file is part of FairEmail. | |||||
FairEmail is free software: you can redistribute it and/or modify | |||||
it under the terms of the GNU General Public License as published by | |||||
the Free Software Foundation, either version 3 of the License, or | |||||
(at your option) any later version. | |||||
NetGuard 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 General Public License for more details. | |||||
You should have received a copy of the GNU General Public License | |||||
along with NetGuard. If not, see <http://www.gnu.org/licenses/>. | |||||
Copyright 2018 by Marcel Bokhorst (M66B) | |||||
*/ | |||||
import java.util.List; | |||||
import androidx.lifecycle.LiveData; | |||||
import androidx.room.Dao; | |||||
import androidx.room.Insert; | |||||
import androidx.room.Query; | |||||
import androidx.room.Update; | |||||
@Dao | |||||
public interface DaoAnswer { | |||||
@Query("SELECT * FROM answer") | |||||
LiveData<List<EntityAnswer>> liveAnswers(); | |||||
@Query("SELECT * FROM answer WHERE id = :id") | |||||
LiveData<EntityAnswer> liveAnswer(long id); | |||||
@Insert | |||||
long insertAnswer(EntityAnswer answer); | |||||
@Update | |||||
int updateAnswer(EntityAnswer answer); | |||||
@Query("DELETE FROM answer WHERE id = :id") | |||||
void deleteAnswer(long id); | |||||
} |
@ -0,0 +1,58 @@ | |||||
package eu.faircode.email; | |||||
/* | |||||
This file is part of FairEmail. | |||||
FairEmail is free software: you can redistribute it and/or modify | |||||
it under the terms of the GNU General Public License as published by | |||||
the Free Software Foundation, either version 3 of the License, or | |||||
(at your option) any later version. | |||||
NetGuard 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 General Public License for more details. | |||||
You should have received a copy of the GNU General Public License | |||||
along with NetGuard. If not, see <http://www.gnu.org/licenses/>. | |||||
Copyright 2018 by Marcel Bokhorst (M66B) | |||||
*/ | |||||
import java.io.Serializable; | |||||
import androidx.annotation.NonNull; | |||||
import androidx.room.Entity; | |||||
import androidx.room.PrimaryKey; | |||||
// https://developer.android.com/training/data-storage/room/defining-data | |||||
@Entity( | |||||
tableName = EntityAnswer.TABLE_NAME, | |||||
foreignKeys = { | |||||
}, | |||||
indices = { | |||||
} | |||||
) | |||||
public class EntityAnswer implements Serializable { | |||||
static final String TABLE_NAME = "answer"; | |||||
@PrimaryKey(autoGenerate = true) | |||||
public Long id; | |||||
@NonNull | |||||
public String name; | |||||
@NonNull | |||||
public String text; | |||||
@Override | |||||
public boolean equals(Object obj) { | |||||
if (obj instanceof EntityAnswer) { | |||||
EntityAnswer other = (EntityAnswer) obj; | |||||
return (this.name.equals(other.name) && | |||||
this.text.equals(other.text) | |||||
); | |||||
} | |||||
return false; | |||||
} | |||||
} |
@ -0,0 +1,75 @@ | |||||
package eu.faircode.email; | |||||
/* | |||||
This file is part of FairEmail. | |||||
FairEmail is free software: you can redistribute it and/or modify | |||||
it under the terms of the GNU General Public License as published by | |||||
the Free Software Foundation, either version 3 of the License, or | |||||
(at your option) any later version. | |||||
NetGuard 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 General Public License for more details. | |||||
You should have received a copy of the GNU General Public License | |||||
along with NetGuard. If not, see <http://www.gnu.org/licenses/>. | |||||
Copyright 2018 by Marcel Bokhorst (M66B) | |||||
*/ | |||||
import android.os.Bundle; | |||||
import android.view.LayoutInflater; | |||||
import android.view.View; | |||||
import android.view.ViewGroup; | |||||
import android.widget.ProgressBar; | |||||
import android.widget.TextView; | |||||
import androidx.annotation.NonNull; | |||||
import androidx.annotation.Nullable; | |||||
import androidx.constraintlayout.widget.Group; | |||||
import androidx.lifecycle.Observer; | |||||
public class FragmentAnswer extends FragmentEx { | |||||
private ViewGroup view; | |||||
private TextView etName; | |||||
private TextView etText; | |||||
private ProgressBar pbWait; | |||||
private Group grpReady; | |||||
@Override | |||||
@Nullable | |||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { | |||||
view = (ViewGroup) inflater.inflate(R.layout.fragment_answer, container, false); | |||||
// Get controls | |||||
etName = view.findViewById(R.id.etName); | |||||
etText = view.findViewById(R.id.etText); | |||||
pbWait = view.findViewById(R.id.pbWait); | |||||
grpReady = view.findViewById(R.id.grpReady); | |||||
grpReady.setVisibility(View.GONE); | |||||
pbWait.setVisibility(View.VISIBLE); | |||||
return view; | |||||
} | |||||
@Override | |||||
public void onActivityCreated(@Nullable final Bundle savedInstanceState) { | |||||
super.onActivityCreated(savedInstanceState); | |||||
// Get arguments | |||||
Bundle args = getArguments(); | |||||
long id = (args == null ? -1 : args.getLong("id")); | |||||
DB.getInstance(getContext()).answer().liveAnswer(id).observe(getViewLifecycleOwner(), new Observer<EntityAnswer>() { | |||||
@Override | |||||
public void onChanged(EntityAnswer entityAnswer) { | |||||
pbWait.setVisibility(View.GONE); | |||||
grpReady.setVisibility(View.VISIBLE); | |||||
} | |||||
}); | |||||
} | |||||
} |
@ -0,0 +1,100 @@ | |||||
package eu.faircode.email; | |||||
/* | |||||
This file is part of FairEmail. | |||||
FairEmail is free software: you can redistribute it and/or modify | |||||
it under the terms of the GNU General Public License as published by | |||||
the Free Software Foundation, either version 3 of the License, or | |||||
(at your option) any later version. | |||||
NetGuard 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 General Public License for more details. | |||||
You should have received a copy of the GNU General Public License | |||||
along with NetGuard. If not, see <http://www.gnu.org/licenses/>. | |||||
Copyright 2018 by Marcel Bokhorst (M66B) | |||||
*/ | |||||
import android.os.Bundle; | |||||
import android.view.LayoutInflater; | |||||
import android.view.View; | |||||
import android.view.ViewGroup; | |||||
import android.widget.ProgressBar; | |||||
import com.google.android.material.floatingactionbutton.FloatingActionButton; | |||||
import java.util.List; | |||||
import androidx.annotation.NonNull; | |||||
import androidx.annotation.Nullable; | |||||
import androidx.constraintlayout.widget.Group; | |||||
import androidx.fragment.app.FragmentTransaction; | |||||
import androidx.lifecycle.Observer; | |||||
import androidx.recyclerview.widget.LinearLayoutManager; | |||||
import androidx.recyclerview.widget.RecyclerView; | |||||
public class FragmentAnswers extends FragmentEx { | |||||
private RecyclerView rvAnswer; | |||||
private ProgressBar pbWait; | |||||
private Group grpReady; | |||||
private FloatingActionButton fab; | |||||
private AdapterAnswer adapter; | |||||
@Override | |||||
@Nullable | |||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { | |||||
View view = inflater.inflate(R.layout.fragment_answers, container, false); | |||||
setHasOptionsMenu(true); | |||||
// Get controls | |||||
rvAnswer = view.findViewById(R.id.rvAnswer); | |||||
pbWait = view.findViewById(R.id.pbWait); | |||||
grpReady = view.findViewById(R.id.grpReady); | |||||
fab = view.findViewById(R.id.fab); | |||||
// Wire controls | |||||
rvAnswer.setHasFixedSize(false); | |||||
LinearLayoutManager llm = new LinearLayoutManager(getContext()); | |||||
rvAnswer.setLayoutManager(llm); | |||||
adapter = new AdapterAnswer(getContext()); | |||||
rvAnswer.setAdapter(adapter); | |||||
fab.setOnClickListener(new View.OnClickListener() { | |||||
@Override | |||||
public void onClick(View view) { | |||||
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction(); | |||||
fragmentTransaction.replace(R.id.content_frame, new FragmentAnswer()).addToBackStack("answer"); | |||||
fragmentTransaction.commit(); | |||||
} | |||||
}); | |||||
// Initialize | |||||
grpReady.setVisibility(View.GONE); | |||||
pbWait.setVisibility(View.VISIBLE); | |||||
return view; | |||||
} | |||||
@Override | |||||
public void onActivityCreated(@Nullable Bundle savedInstanceState) { | |||||
super.onActivityCreated(savedInstanceState); | |||||
DB db = DB.getInstance(getContext()); | |||||
db.answer().liveAnswers().observe(getViewLifecycleOwner(), new Observer<List<EntityAnswer>>() { | |||||
@Override | |||||
public void onChanged(List<EntityAnswer> answers) { | |||||
adapter.set(answers); | |||||
pbWait.setVisibility(View.GONE); | |||||
grpReady.setVisibility(View.VISIBLE); | |||||
} | |||||
}); | |||||
} | |||||
} |
@ -0,0 +1,69 @@ | |||||
<?xml version="1.0" encoding="utf-8"?> | |||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" | |||||
xmlns:app="http://schemas.android.com/apk/res-auto" | |||||
android:layout_width="match_parent" | |||||
android:layout_height="match_parent"> | |||||
<EditText | |||||
android:id="@+id/etName" | |||||
android:layout_width="match_parent" | |||||
android:layout_height="wrap_content" | |||||
android:layout_marginEnd="6dp" | |||||
android:layout_marginStart="6dp" | |||||
android:background="@null" | |||||
android:hint="@string/title_body_hint" | |||||
android:inputType="textCapSentences" | |||||
android:textAppearance="@style/TextAppearance.AppCompat.Small" | |||||
app:layout_constraintStart_toStartOf="parent" | |||||
app:layout_constraintTop_toTopOf="parent" /> | |||||
<View | |||||
android:id="@+id/vSeparator" | |||||
android:layout_width="match_parent" | |||||
android:layout_height="1dp" | |||||
android:layout_marginTop="6dp" | |||||
android:background="?attr/colorSeparator" | |||||
app:layout_constraintStart_toStartOf="parent" | |||||
app:layout_constraintTop_toBottomOf="@+id/etName" /> | |||||
<ScrollView | |||||
android:id="@+id/scroll" | |||||
android:layout_width="match_parent" | |||||
android:layout_height="0dp" | |||||
android:layout_marginEnd="6dp" | |||||
android:layout_marginStart="6dp" | |||||
android:fillViewport="true" | |||||
android:orientation="vertical" | |||||
app:layout_constraintBottom_toBottomOf="parent" | |||||
app:layout_constraintStart_toStartOf="parent" | |||||
app:layout_constraintTop_toBottomOf="@id/vSeparator"> | |||||
<EditText | |||||
android:id="@+id/etText" | |||||
android:layout_width="match_parent" | |||||
android:layout_height="wrap_content" | |||||
android:background="@null" | |||||
android:fontFamily="monospace" | |||||
android:gravity="top" | |||||
android:hint="@string/title_body_hint" | |||||
android:inputType="textCapSentences|textMultiLine" | |||||
android:textAppearance="@style/TextAppearance.AppCompat.Small" /> | |||||
</ScrollView> | |||||
<ProgressBar | |||||
android:id="@+id/pbWait" | |||||
style="@style/Base.Widget.AppCompat.ProgressBar" | |||||
android:layout_width="wrap_content" | |||||
android:layout_height="wrap_content" | |||||
android:indeterminate="true" | |||||
app:layout_constraintBottom_toBottomOf="parent" | |||||
app:layout_constraintEnd_toEndOf="parent" | |||||
app:layout_constraintStart_toStartOf="parent" | |||||
app:layout_constraintTop_toTopOf="parent" /> | |||||
<androidx.constraintlayout.widget.Group | |||||
android:id="@+id/grpReady" | |||||
android:layout_width="0dp" | |||||
android:layout_height="0dp" | |||||
app:constraint_referenced_ids="etName,vSeparator,scroll" /> | |||||
</androidx.constraintlayout.widget.ConstraintLayout> |
@ -0,0 +1,48 @@ | |||||
<?xml version="1.0" encoding="utf-8"?> | |||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" | |||||
xmlns:app="http://schemas.android.com/apk/res-auto" | |||||
xmlns:tools="http://schemas.android.com/tools" | |||||
android:layout_width="match_parent" | |||||
android:layout_height="match_parent" | |||||
tools:context=".ActivityView"> | |||||
<androidx.recyclerview.widget.RecyclerView | |||||
android:id="@+id/rvAnswer" | |||||
android:layout_width="0dp" | |||||
android:layout_height="0dp" | |||||
android:scrollbarStyle="outsideOverlay" | |||||
android:scrollbars="vertical" | |||||
app:layout_constraintBottom_toBottomOf="parent" | |||||
app:layout_constraintEnd_toEndOf="parent" | |||||
app:layout_constraintStart_toStartOf="parent" | |||||
app:layout_constraintTop_toTopOf="parent" /> | |||||
<ProgressBar | |||||
android:id="@+id/pbWait" | |||||
style="@style/Base.Widget.AppCompat.ProgressBar" | |||||
android:layout_width="wrap_content" | |||||
android:layout_height="wrap_content" | |||||
android:indeterminate="true" | |||||
app:layout_constraintBottom_toBottomOf="parent" | |||||
app:layout_constraintEnd_toEndOf="parent" | |||||
app:layout_constraintStart_toStartOf="parent" | |||||
app:layout_constraintTop_toTopOf="parent" /> | |||||
<com.google.android.material.floatingactionbutton.FloatingActionButton | |||||
android:id="@+id/fab" | |||||
android:layout_width="wrap_content" | |||||
android:layout_height="wrap_content" | |||||
android:layout_gravity="end|bottom" | |||||
android:layout_margin="16dp" | |||||
android:src="@drawable/baseline_add_24" | |||||
android:tint="@color/colorActionForeground" | |||||
app:backgroundTint="?attr/colorAccent" | |||||
app:layout_constraintBottom_toBottomOf="parent" | |||||
app:layout_constraintEnd_toEndOf="parent" /> | |||||
<androidx.constraintlayout.widget.Group | |||||
android:id="@+id/grpReady" | |||||
android:layout_width="0dp" | |||||
android:layout_height="0dp" | |||||
app:constraint_referenced_ids="rvAnswer" /> | |||||
</androidx.constraintlayout.widget.ConstraintLayout> |
@ -0,0 +1,20 @@ | |||||
<?xml version="1.0" encoding="utf-8"?> | |||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" | |||||
xmlns:app="http://schemas.android.com/apk/res-auto" | |||||
android:layout_width="match_parent" | |||||
android:layout_height="wrap_content"> | |||||
<TextView | |||||
android:id="@+id/tvName" | |||||
android:layout_width="0dp" | |||||
android:layout_height="wrap_content" | |||||
android:layout_marginEnd="6dp" | |||||
android:layout_marginStart="6dp" | |||||
android:ellipsize="end" | |||||
android:maxLines="1" | |||||
android:text="Name" | |||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium" | |||||
app:layout_constraintEnd_toStartOf="@+id/tvSize" | |||||
app:layout_constraintStart_toStartOf="parent" | |||||
app:layout_constraintTop_toTopOf="parent" /> | |||||
</androidx.constraintlayout.widget.ConstraintLayout> |