diff --git a/app/build.gradle b/app/build.gradle
index 825e6a125a..a33001308a 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -18,8 +18,8 @@ android {
applicationId "chat.rocket.android"
minSdkVersion versions.minSdk
targetSdkVersion versions.targetSdk
- versionCode 2067
- versionName "3.3.3"
+ versionCode 2068
+ versionName "3.4.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
multiDexEnabled true
@@ -204,4 +204,4 @@ task compileSdk(type: Exec) {
preBuild.dependsOn compileSdk
if (isPlay) {
apply plugin: 'com.google.gms.google-services'
-}
+}
\ No newline at end of file
diff --git a/app/schemas/chat.rocket.android.db.RCDatabase/10.json b/app/schemas/chat.rocket.android.db.RCDatabase/10.json
deleted file mode 100644
index a17af93dbf..0000000000
--- a/app/schemas/chat.rocket.android.db.RCDatabase/10.json
+++ /dev/null
@@ -1,1081 +0,0 @@
-{
- "formatVersion": 1,
- "database": {
- "version": 10,
- "identityHash": "db46c12dbb8747200288f48d5dc5558b",
- "entities": [
- {
- "tableName": "users",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `username` TEXT, `name` TEXT, `status` TEXT NOT NULL, `utcOffset` REAL, PRIMARY KEY(`id`))",
- "fields": [
- {
- "fieldPath": "id",
- "columnName": "id",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "username",
- "columnName": "username",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "name",
- "columnName": "name",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "status",
- "columnName": "status",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "utcOffset",
- "columnName": "utcOffset",
- "affinity": "REAL",
- "notNull": false
- }
- ],
- "primaryKey": {
- "columnNames": [
- "id"
- ],
- "autoGenerate": false
- },
- "indices": [
- {
- "name": "index_users_username",
- "unique": false,
- "columnNames": [
- "username"
- ],
- "createSql": "CREATE INDEX `index_users_username` ON `${TABLE_NAME}` (`username`)"
- }
- ],
- "foreignKeys": []
- },
- {
- "tableName": "chatrooms",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `subscriptionId` TEXT NOT NULL, `type` TEXT NOT NULL, `name` TEXT NOT NULL, `fullname` TEXT, `userId` TEXT, `ownerId` TEXT, `readonly` INTEGER, `isDefault` INTEGER, `favorite` INTEGER, `open` INTEGER NOT NULL, `alert` INTEGER NOT NULL, `unread` INTEGER NOT NULL, `userMentions` INTEGER, `groupMentions` INTEGER, `updatedAt` INTEGER, `timestamp` INTEGER, `lastSeen` INTEGER, `lastMessageText` TEXT, `lastMessageUserId` TEXT, `lastMessageTimestamp` INTEGER, `broadcast` INTEGER, PRIMARY KEY(`id`), FOREIGN KEY(`ownerId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`userId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`lastMessageUserId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
- "fields": [
- {
- "fieldPath": "id",
- "columnName": "id",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "subscriptionId",
- "columnName": "subscriptionId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "type",
- "columnName": "type",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "name",
- "columnName": "name",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "fullname",
- "columnName": "fullname",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "userId",
- "columnName": "userId",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "ownerId",
- "columnName": "ownerId",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "readonly",
- "columnName": "readonly",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "isDefault",
- "columnName": "isDefault",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "favorite",
- "columnName": "favorite",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "open",
- "columnName": "open",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "alert",
- "columnName": "alert",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "unread",
- "columnName": "unread",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "userMentions",
- "columnName": "userMentions",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "groupMentions",
- "columnName": "groupMentions",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "updatedAt",
- "columnName": "updatedAt",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "timestamp",
- "columnName": "timestamp",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "lastSeen",
- "columnName": "lastSeen",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "lastMessageText",
- "columnName": "lastMessageText",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "lastMessageUserId",
- "columnName": "lastMessageUserId",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "lastMessageTimestamp",
- "columnName": "lastMessageTimestamp",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "broadcast",
- "columnName": "broadcast",
- "affinity": "INTEGER",
- "notNull": false
- }
- ],
- "primaryKey": {
- "columnNames": [
- "id"
- ],
- "autoGenerate": false
- },
- "indices": [
- {
- "name": "index_chatrooms_userId",
- "unique": false,
- "columnNames": [
- "userId"
- ],
- "createSql": "CREATE INDEX `index_chatrooms_userId` ON `${TABLE_NAME}` (`userId`)"
- },
- {
- "name": "index_chatrooms_ownerId",
- "unique": false,
- "columnNames": [
- "ownerId"
- ],
- "createSql": "CREATE INDEX `index_chatrooms_ownerId` ON `${TABLE_NAME}` (`ownerId`)"
- },
- {
- "name": "index_chatrooms_subscriptionId",
- "unique": true,
- "columnNames": [
- "subscriptionId"
- ],
- "createSql": "CREATE UNIQUE INDEX `index_chatrooms_subscriptionId` ON `${TABLE_NAME}` (`subscriptionId`)"
- },
- {
- "name": "index_chatrooms_updatedAt",
- "unique": false,
- "columnNames": [
- "updatedAt"
- ],
- "createSql": "CREATE INDEX `index_chatrooms_updatedAt` ON `${TABLE_NAME}` (`updatedAt`)"
- },
- {
- "name": "index_chatrooms_lastMessageUserId",
- "unique": false,
- "columnNames": [
- "lastMessageUserId"
- ],
- "createSql": "CREATE INDEX `index_chatrooms_lastMessageUserId` ON `${TABLE_NAME}` (`lastMessageUserId`)"
- }
- ],
- "foreignKeys": [
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "ownerId"
- ],
- "referencedColumns": [
- "id"
- ]
- },
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "userId"
- ],
- "referencedColumns": [
- "id"
- ]
- },
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "lastMessageUserId"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "messages",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `roomId` TEXT NOT NULL, `message` TEXT NOT NULL, `timestamp` INTEGER NOT NULL, `senderId` TEXT, `updatedAt` INTEGER, `editedAt` INTEGER, `editedBy` TEXT, `senderAlias` TEXT, `avatar` TEXT, `type` TEXT, `groupable` INTEGER NOT NULL, `parseUrls` INTEGER NOT NULL, `pinned` INTEGER NOT NULL, `role` TEXT, `synced` INTEGER NOT NULL, `unread` INTEGER, PRIMARY KEY(`id`), FOREIGN KEY(`senderId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`editedBy`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
- "fields": [
- {
- "fieldPath": "id",
- "columnName": "id",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "roomId",
- "columnName": "roomId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "message",
- "columnName": "message",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "timestamp",
- "columnName": "timestamp",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "senderId",
- "columnName": "senderId",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "updatedAt",
- "columnName": "updatedAt",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "editedAt",
- "columnName": "editedAt",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "editedBy",
- "columnName": "editedBy",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "senderAlias",
- "columnName": "senderAlias",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "avatar",
- "columnName": "avatar",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "type",
- "columnName": "type",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "groupable",
- "columnName": "groupable",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "parseUrls",
- "columnName": "parseUrls",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "pinned",
- "columnName": "pinned",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "role",
- "columnName": "role",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "synced",
- "columnName": "synced",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "unread",
- "columnName": "unread",
- "affinity": "INTEGER",
- "notNull": false
- }
- ],
- "primaryKey": {
- "columnNames": [
- "id"
- ],
- "autoGenerate": false
- },
- "indices": [],
- "foreignKeys": [
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "senderId"
- ],
- "referencedColumns": [
- "id"
- ]
- },
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "editedBy"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "message_favorites",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`messageId` TEXT NOT NULL, `userId` TEXT NOT NULL, PRIMARY KEY(`messageId`, `userId`), FOREIGN KEY(`messageId`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`userId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
- "fields": [
- {
- "fieldPath": "messageId",
- "columnName": "messageId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "userId",
- "columnName": "userId",
- "affinity": "TEXT",
- "notNull": true
- }
- ],
- "primaryKey": {
- "columnNames": [
- "messageId",
- "userId"
- ],
- "autoGenerate": false
- },
- "indices": [],
- "foreignKeys": [
- {
- "table": "messages",
- "onDelete": "CASCADE",
- "onUpdate": "NO ACTION",
- "columns": [
- "messageId"
- ],
- "referencedColumns": [
- "id"
- ]
- },
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "userId"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "message_mentions",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`messageId` TEXT NOT NULL, `userId` TEXT NOT NULL, PRIMARY KEY(`messageId`, `userId`), FOREIGN KEY(`messageId`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`userId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
- "fields": [
- {
- "fieldPath": "messageId",
- "columnName": "messageId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "userId",
- "columnName": "userId",
- "affinity": "TEXT",
- "notNull": true
- }
- ],
- "primaryKey": {
- "columnNames": [
- "messageId",
- "userId"
- ],
- "autoGenerate": false
- },
- "indices": [],
- "foreignKeys": [
- {
- "table": "messages",
- "onDelete": "CASCADE",
- "onUpdate": "NO ACTION",
- "columns": [
- "messageId"
- ],
- "referencedColumns": [
- "id"
- ]
- },
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "userId"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "message_channels",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`messageId` TEXT NOT NULL, `roomId` TEXT NOT NULL, `roomName` TEXT, PRIMARY KEY(`messageId`, `roomId`), FOREIGN KEY(`messageId`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
- "fields": [
- {
- "fieldPath": "messageId",
- "columnName": "messageId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "roomId",
- "columnName": "roomId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "roomName",
- "columnName": "roomName",
- "affinity": "TEXT",
- "notNull": false
- }
- ],
- "primaryKey": {
- "columnNames": [
- "messageId",
- "roomId"
- ],
- "autoGenerate": false
- },
- "indices": [],
- "foreignKeys": [
- {
- "table": "messages",
- "onDelete": "CASCADE",
- "onUpdate": "NO ACTION",
- "columns": [
- "messageId"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "attachments",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` TEXT NOT NULL, `message_id` TEXT NOT NULL, `title` TEXT, `type` TEXT, `description` TEXT, `text` TEXT, `author_name` TEXT, `author_icon` TEXT, `author_link` TEXT, `thumb_url` TEXT, `color` TEXT, `fallback` TEXT, `title_link` TEXT, `title_link_download` INTEGER NOT NULL, `image_url` TEXT, `image_type` TEXT, `image_size` INTEGER, `video_url` TEXT, `video_type` TEXT, `video_size` INTEGER, `audio_url` TEXT, `audio_type` TEXT, `audio_size` INTEGER, `message_link` TEXT, `timestamp` INTEGER, `has_actions` INTEGER NOT NULL, `has_fields` INTEGER NOT NULL, `button_alignment` TEXT, PRIMARY KEY(`_id`), FOREIGN KEY(`message_id`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
- "fields": [
- {
- "fieldPath": "_id",
- "columnName": "_id",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "messageId",
- "columnName": "message_id",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "title",
- "columnName": "title",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "type",
- "columnName": "type",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "description",
- "columnName": "description",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "text",
- "columnName": "text",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "authorName",
- "columnName": "author_name",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "authorIcon",
- "columnName": "author_icon",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "authorLink",
- "columnName": "author_link",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "thumbUrl",
- "columnName": "thumb_url",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "color",
- "columnName": "color",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "fallback",
- "columnName": "fallback",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "titleLink",
- "columnName": "title_link",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "titleLinkDownload",
- "columnName": "title_link_download",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "imageUrl",
- "columnName": "image_url",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "imageType",
- "columnName": "image_type",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "imageSize",
- "columnName": "image_size",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "videoUrl",
- "columnName": "video_url",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "videoType",
- "columnName": "video_type",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "videoSize",
- "columnName": "video_size",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "audioUrl",
- "columnName": "audio_url",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "audioType",
- "columnName": "audio_type",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "audioSize",
- "columnName": "audio_size",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "messageLink",
- "columnName": "message_link",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "timestamp",
- "columnName": "timestamp",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "hasActions",
- "columnName": "has_actions",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "hasFields",
- "columnName": "has_fields",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "buttonAlignment",
- "columnName": "button_alignment",
- "affinity": "TEXT",
- "notNull": false
- }
- ],
- "primaryKey": {
- "columnNames": [
- "_id"
- ],
- "autoGenerate": false
- },
- "indices": [],
- "foreignKeys": [
- {
- "table": "messages",
- "onDelete": "CASCADE",
- "onUpdate": "NO ACTION",
- "columns": [
- "message_id"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "attachment_fields",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `attachmentId` TEXT NOT NULL, `title` TEXT NOT NULL, `value` TEXT NOT NULL, FOREIGN KEY(`attachmentId`) REFERENCES `attachments`(`_id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
- "fields": [
- {
- "fieldPath": "id",
- "columnName": "id",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "attachmentId",
- "columnName": "attachmentId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "title",
- "columnName": "title",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "value",
- "columnName": "value",
- "affinity": "TEXT",
- "notNull": true
- }
- ],
- "primaryKey": {
- "columnNames": [
- "id"
- ],
- "autoGenerate": true
- },
- "indices": [
- {
- "name": "index_attachment_fields_attachmentId",
- "unique": false,
- "columnNames": [
- "attachmentId"
- ],
- "createSql": "CREATE INDEX `index_attachment_fields_attachmentId` ON `${TABLE_NAME}` (`attachmentId`)"
- }
- ],
- "foreignKeys": [
- {
- "table": "attachments",
- "onDelete": "CASCADE",
- "onUpdate": "NO ACTION",
- "columns": [
- "attachmentId"
- ],
- "referencedColumns": [
- "_id"
- ]
- }
- ]
- },
- {
- "tableName": "attachment_action",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `attachmentId` TEXT NOT NULL, `type` TEXT NOT NULL, `text` TEXT, `url` TEXT, `isWebView` INTEGER, `webViewHeightRatio` TEXT, `imageUrl` TEXT, `message` TEXT, `isMessageInChatWindow` INTEGER, FOREIGN KEY(`attachmentId`) REFERENCES `attachments`(`_id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
- "fields": [
- {
- "fieldPath": "id",
- "columnName": "id",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "attachmentId",
- "columnName": "attachmentId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "type",
- "columnName": "type",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "text",
- "columnName": "text",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "url",
- "columnName": "url",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "isWebView",
- "columnName": "isWebView",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "webViewHeightRatio",
- "columnName": "webViewHeightRatio",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "imageUrl",
- "columnName": "imageUrl",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "message",
- "columnName": "message",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "isMessageInChatWindow",
- "columnName": "isMessageInChatWindow",
- "affinity": "INTEGER",
- "notNull": false
- }
- ],
- "primaryKey": {
- "columnNames": [
- "id"
- ],
- "autoGenerate": true
- },
- "indices": [
- {
- "name": "index_attachment_action_attachmentId",
- "unique": false,
- "columnNames": [
- "attachmentId"
- ],
- "createSql": "CREATE INDEX `index_attachment_action_attachmentId` ON `${TABLE_NAME}` (`attachmentId`)"
- }
- ],
- "foreignKeys": [
- {
- "table": "attachments",
- "onDelete": "CASCADE",
- "onUpdate": "NO ACTION",
- "columns": [
- "attachmentId"
- ],
- "referencedColumns": [
- "_id"
- ]
- }
- ]
- },
- {
- "tableName": "urls",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`urlId` INTEGER PRIMARY KEY AUTOINCREMENT, `messageId` TEXT NOT NULL, `url` TEXT NOT NULL, `hostname` TEXT, `title` TEXT, `description` TEXT, `imageUrl` TEXT, FOREIGN KEY(`messageId`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
- "fields": [
- {
- "fieldPath": "urlId",
- "columnName": "urlId",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "messageId",
- "columnName": "messageId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "url",
- "columnName": "url",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "hostname",
- "columnName": "hostname",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "title",
- "columnName": "title",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "description",
- "columnName": "description",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "imageUrl",
- "columnName": "imageUrl",
- "affinity": "TEXT",
- "notNull": false
- }
- ],
- "primaryKey": {
- "columnNames": [
- "urlId"
- ],
- "autoGenerate": true
- },
- "indices": [
- {
- "name": "index_urls_messageId",
- "unique": false,
- "columnNames": [
- "messageId"
- ],
- "createSql": "CREATE INDEX `index_urls_messageId` ON `${TABLE_NAME}` (`messageId`)"
- }
- ],
- "foreignKeys": [
- {
- "table": "messages",
- "onDelete": "CASCADE",
- "onUpdate": "NO ACTION",
- "columns": [
- "messageId"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "reactions",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`reaction` TEXT NOT NULL, `messageId` TEXT NOT NULL, `count` INTEGER NOT NULL, `usernames` TEXT NOT NULL, PRIMARY KEY(`reaction`), FOREIGN KEY(`messageId`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
- "fields": [
- {
- "fieldPath": "reaction",
- "columnName": "reaction",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "messageId",
- "columnName": "messageId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "count",
- "columnName": "count",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "usernames",
- "columnName": "usernames",
- "affinity": "TEXT",
- "notNull": true
- }
- ],
- "primaryKey": {
- "columnNames": [
- "reaction"
- ],
- "autoGenerate": false
- },
- "indices": [
- {
- "name": "index_reactions_messageId",
- "unique": false,
- "columnNames": [
- "messageId"
- ],
- "createSql": "CREATE INDEX `index_reactions_messageId` ON `${TABLE_NAME}` (`messageId`)"
- }
- ],
- "foreignKeys": [
- {
- "table": "messages",
- "onDelete": "CASCADE",
- "onUpdate": "NO ACTION",
- "columns": [
- "messageId"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "messages_sync",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`roomId` TEXT NOT NULL, `timestamp` INTEGER NOT NULL, PRIMARY KEY(`roomId`))",
- "fields": [
- {
- "fieldPath": "roomId",
- "columnName": "roomId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "timestamp",
- "columnName": "timestamp",
- "affinity": "INTEGER",
- "notNull": true
- }
- ],
- "primaryKey": {
- "columnNames": [
- "roomId"
- ],
- "autoGenerate": false
- },
- "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, \"db46c12dbb8747200288f48d5dc5558b\")"
- ]
- }
-}
\ No newline at end of file
diff --git a/app/schemas/chat.rocket.android.db.RCDatabase/12.json b/app/schemas/chat.rocket.android.db.RCDatabase/12.json
deleted file mode 100644
index 8b1da2129d..0000000000
--- a/app/schemas/chat.rocket.android.db.RCDatabase/12.json
+++ /dev/null
@@ -1,1111 +0,0 @@
-{
- "formatVersion": 1,
- "database": {
- "version": 12,
- "identityHash": "1984b5661945bd83607d9a7043ed87b0",
- "entities": [
- {
- "tableName": "users",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `username` TEXT, `name` TEXT, `status` TEXT NOT NULL, `utcOffset` REAL, PRIMARY KEY(`id`))",
- "fields": [
- {
- "fieldPath": "id",
- "columnName": "id",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "username",
- "columnName": "username",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "name",
- "columnName": "name",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "status",
- "columnName": "status",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "utcOffset",
- "columnName": "utcOffset",
- "affinity": "REAL",
- "notNull": false
- }
- ],
- "primaryKey": {
- "columnNames": [
- "id"
- ],
- "autoGenerate": false
- },
- "indices": [
- {
- "name": "index_users_username",
- "unique": false,
- "columnNames": [
- "username"
- ],
- "createSql": "CREATE INDEX `index_users_username` ON `${TABLE_NAME}` (`username`)"
- }
- ],
- "foreignKeys": []
- },
- {
- "tableName": "chatrooms",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `subscriptionId` TEXT NOT NULL, `type` TEXT NOT NULL, `name` TEXT NOT NULL, `fullname` TEXT, `userId` TEXT, `ownerId` TEXT, `readonly` INTEGER, `isDefault` INTEGER, `favorite` INTEGER, `topic` TEXT, `announcement` TEXT, `description` TEXT, `open` INTEGER NOT NULL, `alert` INTEGER NOT NULL, `unread` INTEGER NOT NULL, `userMentions` INTEGER, `groupMentions` INTEGER, `updatedAt` INTEGER, `timestamp` INTEGER, `lastSeen` INTEGER, `lastMessageText` TEXT, `lastMessageUserId` TEXT, `lastMessageTimestamp` INTEGER, `broadcast` INTEGER, `muted` TEXT, PRIMARY KEY(`id`), FOREIGN KEY(`ownerId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`userId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`lastMessageUserId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
- "fields": [
- {
- "fieldPath": "id",
- "columnName": "id",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "subscriptionId",
- "columnName": "subscriptionId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "type",
- "columnName": "type",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "name",
- "columnName": "name",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "fullname",
- "columnName": "fullname",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "userId",
- "columnName": "userId",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "ownerId",
- "columnName": "ownerId",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "readonly",
- "columnName": "readonly",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "isDefault",
- "columnName": "isDefault",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "favorite",
- "columnName": "favorite",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "topic",
- "columnName": "topic",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "announcement",
- "columnName": "announcement",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "description",
- "columnName": "description",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "open",
- "columnName": "open",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "alert",
- "columnName": "alert",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "unread",
- "columnName": "unread",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "userMentions",
- "columnName": "userMentions",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "groupMentions",
- "columnName": "groupMentions",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "updatedAt",
- "columnName": "updatedAt",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "timestamp",
- "columnName": "timestamp",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "lastSeen",
- "columnName": "lastSeen",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "lastMessageText",
- "columnName": "lastMessageText",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "lastMessageUserId",
- "columnName": "lastMessageUserId",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "lastMessageTimestamp",
- "columnName": "lastMessageTimestamp",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "broadcast",
- "columnName": "broadcast",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "muted",
- "columnName": "muted",
- "affinity": "TEXT",
- "notNull": false
- }
- ],
- "primaryKey": {
- "columnNames": [
- "id"
- ],
- "autoGenerate": false
- },
- "indices": [
- {
- "name": "index_chatrooms_userId",
- "unique": false,
- "columnNames": [
- "userId"
- ],
- "createSql": "CREATE INDEX `index_chatrooms_userId` ON `${TABLE_NAME}` (`userId`)"
- },
- {
- "name": "index_chatrooms_ownerId",
- "unique": false,
- "columnNames": [
- "ownerId"
- ],
- "createSql": "CREATE INDEX `index_chatrooms_ownerId` ON `${TABLE_NAME}` (`ownerId`)"
- },
- {
- "name": "index_chatrooms_subscriptionId",
- "unique": true,
- "columnNames": [
- "subscriptionId"
- ],
- "createSql": "CREATE UNIQUE INDEX `index_chatrooms_subscriptionId` ON `${TABLE_NAME}` (`subscriptionId`)"
- },
- {
- "name": "index_chatrooms_updatedAt",
- "unique": false,
- "columnNames": [
- "updatedAt"
- ],
- "createSql": "CREATE INDEX `index_chatrooms_updatedAt` ON `${TABLE_NAME}` (`updatedAt`)"
- },
- {
- "name": "index_chatrooms_lastMessageUserId",
- "unique": false,
- "columnNames": [
- "lastMessageUserId"
- ],
- "createSql": "CREATE INDEX `index_chatrooms_lastMessageUserId` ON `${TABLE_NAME}` (`lastMessageUserId`)"
- }
- ],
- "foreignKeys": [
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "ownerId"
- ],
- "referencedColumns": [
- "id"
- ]
- },
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "userId"
- ],
- "referencedColumns": [
- "id"
- ]
- },
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "lastMessageUserId"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "messages",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `roomId` TEXT NOT NULL, `message` TEXT NOT NULL, `timestamp` INTEGER NOT NULL, `senderId` TEXT, `updatedAt` INTEGER, `editedAt` INTEGER, `editedBy` TEXT, `senderAlias` TEXT, `avatar` TEXT, `type` TEXT, `groupable` INTEGER NOT NULL, `parseUrls` INTEGER NOT NULL, `pinned` INTEGER NOT NULL, `role` TEXT, `synced` INTEGER NOT NULL, `unread` INTEGER, PRIMARY KEY(`id`), FOREIGN KEY(`senderId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`editedBy`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
- "fields": [
- {
- "fieldPath": "id",
- "columnName": "id",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "roomId",
- "columnName": "roomId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "message",
- "columnName": "message",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "timestamp",
- "columnName": "timestamp",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "senderId",
- "columnName": "senderId",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "updatedAt",
- "columnName": "updatedAt",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "editedAt",
- "columnName": "editedAt",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "editedBy",
- "columnName": "editedBy",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "senderAlias",
- "columnName": "senderAlias",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "avatar",
- "columnName": "avatar",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "type",
- "columnName": "type",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "groupable",
- "columnName": "groupable",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "parseUrls",
- "columnName": "parseUrls",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "pinned",
- "columnName": "pinned",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "role",
- "columnName": "role",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "synced",
- "columnName": "synced",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "unread",
- "columnName": "unread",
- "affinity": "INTEGER",
- "notNull": false
- }
- ],
- "primaryKey": {
- "columnNames": [
- "id"
- ],
- "autoGenerate": false
- },
- "indices": [],
- "foreignKeys": [
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "senderId"
- ],
- "referencedColumns": [
- "id"
- ]
- },
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "editedBy"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "message_favorites",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`messageId` TEXT NOT NULL, `userId` TEXT NOT NULL, PRIMARY KEY(`messageId`, `userId`), FOREIGN KEY(`messageId`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`userId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
- "fields": [
- {
- "fieldPath": "messageId",
- "columnName": "messageId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "userId",
- "columnName": "userId",
- "affinity": "TEXT",
- "notNull": true
- }
- ],
- "primaryKey": {
- "columnNames": [
- "messageId",
- "userId"
- ],
- "autoGenerate": false
- },
- "indices": [],
- "foreignKeys": [
- {
- "table": "messages",
- "onDelete": "CASCADE",
- "onUpdate": "NO ACTION",
- "columns": [
- "messageId"
- ],
- "referencedColumns": [
- "id"
- ]
- },
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "userId"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "message_mentions",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`messageId` TEXT NOT NULL, `userId` TEXT NOT NULL, PRIMARY KEY(`messageId`, `userId`), FOREIGN KEY(`messageId`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`userId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
- "fields": [
- {
- "fieldPath": "messageId",
- "columnName": "messageId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "userId",
- "columnName": "userId",
- "affinity": "TEXT",
- "notNull": true
- }
- ],
- "primaryKey": {
- "columnNames": [
- "messageId",
- "userId"
- ],
- "autoGenerate": false
- },
- "indices": [],
- "foreignKeys": [
- {
- "table": "messages",
- "onDelete": "CASCADE",
- "onUpdate": "NO ACTION",
- "columns": [
- "messageId"
- ],
- "referencedColumns": [
- "id"
- ]
- },
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "userId"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "message_channels",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`messageId` TEXT NOT NULL, `roomId` TEXT NOT NULL, `roomName` TEXT, PRIMARY KEY(`messageId`, `roomId`), FOREIGN KEY(`messageId`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
- "fields": [
- {
- "fieldPath": "messageId",
- "columnName": "messageId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "roomId",
- "columnName": "roomId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "roomName",
- "columnName": "roomName",
- "affinity": "TEXT",
- "notNull": false
- }
- ],
- "primaryKey": {
- "columnNames": [
- "messageId",
- "roomId"
- ],
- "autoGenerate": false
- },
- "indices": [],
- "foreignKeys": [
- {
- "table": "messages",
- "onDelete": "CASCADE",
- "onUpdate": "NO ACTION",
- "columns": [
- "messageId"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "attachments",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` TEXT NOT NULL, `message_id` TEXT NOT NULL, `title` TEXT, `type` TEXT, `description` TEXT, `text` TEXT, `author_name` TEXT, `author_icon` TEXT, `author_link` TEXT, `thumb_url` TEXT, `color` TEXT, `fallback` TEXT, `title_link` TEXT, `title_link_download` INTEGER NOT NULL, `image_url` TEXT, `image_type` TEXT, `image_size` INTEGER, `video_url` TEXT, `video_type` TEXT, `video_size` INTEGER, `audio_url` TEXT, `audio_type` TEXT, `audio_size` INTEGER, `message_link` TEXT, `timestamp` INTEGER, `has_actions` INTEGER NOT NULL, `has_fields` INTEGER NOT NULL, `button_alignment` TEXT, PRIMARY KEY(`_id`), FOREIGN KEY(`message_id`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
- "fields": [
- {
- "fieldPath": "_id",
- "columnName": "_id",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "messageId",
- "columnName": "message_id",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "title",
- "columnName": "title",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "type",
- "columnName": "type",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "description",
- "columnName": "description",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "text",
- "columnName": "text",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "authorName",
- "columnName": "author_name",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "authorIcon",
- "columnName": "author_icon",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "authorLink",
- "columnName": "author_link",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "thumbUrl",
- "columnName": "thumb_url",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "color",
- "columnName": "color",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "fallback",
- "columnName": "fallback",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "titleLink",
- "columnName": "title_link",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "titleLinkDownload",
- "columnName": "title_link_download",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "imageUrl",
- "columnName": "image_url",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "imageType",
- "columnName": "image_type",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "imageSize",
- "columnName": "image_size",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "videoUrl",
- "columnName": "video_url",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "videoType",
- "columnName": "video_type",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "videoSize",
- "columnName": "video_size",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "audioUrl",
- "columnName": "audio_url",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "audioType",
- "columnName": "audio_type",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "audioSize",
- "columnName": "audio_size",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "messageLink",
- "columnName": "message_link",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "timestamp",
- "columnName": "timestamp",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "hasActions",
- "columnName": "has_actions",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "hasFields",
- "columnName": "has_fields",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "buttonAlignment",
- "columnName": "button_alignment",
- "affinity": "TEXT",
- "notNull": false
- }
- ],
- "primaryKey": {
- "columnNames": [
- "_id"
- ],
- "autoGenerate": false
- },
- "indices": [],
- "foreignKeys": [
- {
- "table": "messages",
- "onDelete": "CASCADE",
- "onUpdate": "NO ACTION",
- "columns": [
- "message_id"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "attachment_fields",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `attachmentId` TEXT NOT NULL, `title` TEXT NOT NULL, `value` TEXT NOT NULL, FOREIGN KEY(`attachmentId`) REFERENCES `attachments`(`_id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
- "fields": [
- {
- "fieldPath": "id",
- "columnName": "id",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "attachmentId",
- "columnName": "attachmentId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "title",
- "columnName": "title",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "value",
- "columnName": "value",
- "affinity": "TEXT",
- "notNull": true
- }
- ],
- "primaryKey": {
- "columnNames": [
- "id"
- ],
- "autoGenerate": true
- },
- "indices": [
- {
- "name": "index_attachment_fields_attachmentId",
- "unique": false,
- "columnNames": [
- "attachmentId"
- ],
- "createSql": "CREATE INDEX `index_attachment_fields_attachmentId` ON `${TABLE_NAME}` (`attachmentId`)"
- }
- ],
- "foreignKeys": [
- {
- "table": "attachments",
- "onDelete": "CASCADE",
- "onUpdate": "NO ACTION",
- "columns": [
- "attachmentId"
- ],
- "referencedColumns": [
- "_id"
- ]
- }
- ]
- },
- {
- "tableName": "attachment_action",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `attachmentId` TEXT NOT NULL, `type` TEXT NOT NULL, `text` TEXT, `url` TEXT, `isWebView` INTEGER, `webViewHeightRatio` TEXT, `imageUrl` TEXT, `message` TEXT, `isMessageInChatWindow` INTEGER, FOREIGN KEY(`attachmentId`) REFERENCES `attachments`(`_id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
- "fields": [
- {
- "fieldPath": "id",
- "columnName": "id",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "attachmentId",
- "columnName": "attachmentId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "type",
- "columnName": "type",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "text",
- "columnName": "text",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "url",
- "columnName": "url",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "isWebView",
- "columnName": "isWebView",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "webViewHeightRatio",
- "columnName": "webViewHeightRatio",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "imageUrl",
- "columnName": "imageUrl",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "message",
- "columnName": "message",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "isMessageInChatWindow",
- "columnName": "isMessageInChatWindow",
- "affinity": "INTEGER",
- "notNull": false
- }
- ],
- "primaryKey": {
- "columnNames": [
- "id"
- ],
- "autoGenerate": true
- },
- "indices": [
- {
- "name": "index_attachment_action_attachmentId",
- "unique": false,
- "columnNames": [
- "attachmentId"
- ],
- "createSql": "CREATE INDEX `index_attachment_action_attachmentId` ON `${TABLE_NAME}` (`attachmentId`)"
- }
- ],
- "foreignKeys": [
- {
- "table": "attachments",
- "onDelete": "CASCADE",
- "onUpdate": "NO ACTION",
- "columns": [
- "attachmentId"
- ],
- "referencedColumns": [
- "_id"
- ]
- }
- ]
- },
- {
- "tableName": "urls",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`urlId` INTEGER PRIMARY KEY AUTOINCREMENT, `messageId` TEXT NOT NULL, `url` TEXT NOT NULL, `hostname` TEXT, `title` TEXT, `description` TEXT, `imageUrl` TEXT, FOREIGN KEY(`messageId`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
- "fields": [
- {
- "fieldPath": "urlId",
- "columnName": "urlId",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "messageId",
- "columnName": "messageId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "url",
- "columnName": "url",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "hostname",
- "columnName": "hostname",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "title",
- "columnName": "title",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "description",
- "columnName": "description",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "imageUrl",
- "columnName": "imageUrl",
- "affinity": "TEXT",
- "notNull": false
- }
- ],
- "primaryKey": {
- "columnNames": [
- "urlId"
- ],
- "autoGenerate": true
- },
- "indices": [
- {
- "name": "index_urls_messageId",
- "unique": false,
- "columnNames": [
- "messageId"
- ],
- "createSql": "CREATE INDEX `index_urls_messageId` ON `${TABLE_NAME}` (`messageId`)"
- }
- ],
- "foreignKeys": [
- {
- "table": "messages",
- "onDelete": "CASCADE",
- "onUpdate": "NO ACTION",
- "columns": [
- "messageId"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "reactions",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`reaction` TEXT NOT NULL, `messageId` TEXT NOT NULL, `count` INTEGER NOT NULL, `usernames` TEXT NOT NULL, `names` TEXT NOT NULL, PRIMARY KEY(`reaction`), FOREIGN KEY(`messageId`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
- "fields": [
- {
- "fieldPath": "reaction",
- "columnName": "reaction",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "messageId",
- "columnName": "messageId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "count",
- "columnName": "count",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "usernames",
- "columnName": "usernames",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "names",
- "columnName": "names",
- "affinity": "TEXT",
- "notNull": true
- }
- ],
- "primaryKey": {
- "columnNames": [
- "reaction"
- ],
- "autoGenerate": false
- },
- "indices": [
- {
- "name": "index_reactions_messageId",
- "unique": false,
- "columnNames": [
- "messageId"
- ],
- "createSql": "CREATE INDEX `index_reactions_messageId` ON `${TABLE_NAME}` (`messageId`)"
- }
- ],
- "foreignKeys": [
- {
- "table": "messages",
- "onDelete": "CASCADE",
- "onUpdate": "NO ACTION",
- "columns": [
- "messageId"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "messages_sync",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`roomId` TEXT NOT NULL, `timestamp` INTEGER NOT NULL, PRIMARY KEY(`roomId`))",
- "fields": [
- {
- "fieldPath": "roomId",
- "columnName": "roomId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "timestamp",
- "columnName": "timestamp",
- "affinity": "INTEGER",
- "notNull": true
- }
- ],
- "primaryKey": {
- "columnNames": [
- "roomId"
- ],
- "autoGenerate": false
- },
- "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, \"1984b5661945bd83607d9a7043ed87b0\")"
- ]
- }
-}
\ No newline at end of file
diff --git a/app/schemas/chat.rocket.android.db.RCDatabase/11.json b/app/schemas/chat.rocket.android.db.RCDatabase/13.json
similarity index 96%
rename from app/schemas/chat.rocket.android.db.RCDatabase/11.json
rename to app/schemas/chat.rocket.android.db.RCDatabase/13.json
index 0d58ffcfba..5127d02b4c 100644
--- a/app/schemas/chat.rocket.android.db.RCDatabase/11.json
+++ b/app/schemas/chat.rocket.android.db.RCDatabase/13.json
@@ -1,8 +1,8 @@
{
"formatVersion": 1,
"database": {
- "version": 11,
- "identityHash": "1984b5661945bd83607d9a7043ed87b0",
+ "version": 13,
+ "identityHash": "3bef73b44ae4edf2a74b48fd68f2c599",
"entities": [
{
"tableName": "users",
@@ -59,7 +59,7 @@
},
{
"tableName": "chatrooms",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `subscriptionId` TEXT NOT NULL, `type` TEXT NOT NULL, `name` TEXT NOT NULL, `fullname` TEXT, `userId` TEXT, `ownerId` TEXT, `readonly` INTEGER, `isDefault` INTEGER, `favorite` INTEGER, `topic` TEXT, `announcement` TEXT, `description` TEXT, `open` INTEGER NOT NULL, `alert` INTEGER NOT NULL, `unread` INTEGER NOT NULL, `userMentions` INTEGER, `groupMentions` INTEGER, `updatedAt` INTEGER, `timestamp` INTEGER, `lastSeen` INTEGER, `lastMessageText` TEXT, `lastMessageUserId` TEXT, `lastMessageTimestamp` INTEGER, `broadcast` INTEGER, `muted` TEXT, PRIMARY KEY(`id`), FOREIGN KEY(`ownerId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`userId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`lastMessageUserId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `subscriptionId` TEXT NOT NULL, `parentId` TEXT, `type` TEXT NOT NULL, `name` TEXT NOT NULL, `fullname` TEXT, `userId` TEXT, `ownerId` TEXT, `readonly` INTEGER, `isDefault` INTEGER, `favorite` INTEGER, `topic` TEXT, `announcement` TEXT, `description` TEXT, `open` INTEGER NOT NULL, `alert` INTEGER NOT NULL, `unread` INTEGER NOT NULL, `userMentions` INTEGER, `groupMentions` INTEGER, `updatedAt` INTEGER, `timestamp` INTEGER, `lastSeen` INTEGER, `lastMessageText` TEXT, `lastMessageUserId` TEXT, `lastMessageTimestamp` INTEGER, `broadcast` INTEGER, `muted` TEXT, PRIMARY KEY(`id`), FOREIGN KEY(`ownerId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`userId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`lastMessageUserId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
"fields": [
{
"fieldPath": "id",
@@ -73,6 +73,12 @@
"affinity": "TEXT",
"notNull": true
},
+ {
+ "fieldPath": "parentId",
+ "columnName": "parentId",
+ "affinity": "TEXT",
+ "notNull": false
+ },
{
"fieldPath": "type",
"columnName": "type",
@@ -1105,7 +1111,7 @@
],
"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, \"1984b5661945bd83607d9a7043ed87b0\")"
+ "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"3bef73b44ae4edf2a74b48fd68f2c599\")"
]
}
}
\ No newline at end of file
diff --git a/app/schemas/chat.rocket.android.db.RCDatabase/3.json b/app/schemas/chat.rocket.android.db.RCDatabase/3.json
deleted file mode 100644
index 5b38241e5b..0000000000
--- a/app/schemas/chat.rocket.android.db.RCDatabase/3.json
+++ /dev/null
@@ -1,273 +0,0 @@
-{
- "formatVersion": 1,
- "database": {
- "version": 3,
- "identityHash": "06359a8c2943365dd094bc5dff210203",
- "entities": [
- {
- "tableName": "users",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `username` TEXT, `name` TEXT, `status` TEXT NOT NULL, `utcOffset` REAL, PRIMARY KEY(`id`))",
- "fields": [
- {
- "fieldPath": "id",
- "columnName": "id",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "username",
- "columnName": "username",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "name",
- "columnName": "name",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "status",
- "columnName": "status",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "utcOffset",
- "columnName": "utcOffset",
- "affinity": "REAL",
- "notNull": false
- }
- ],
- "primaryKey": {
- "columnNames": [
- "id"
- ],
- "autoGenerate": false
- },
- "indices": [
- {
- "name": "index_users_username",
- "unique": false,
- "columnNames": [
- "username"
- ],
- "createSql": "CREATE INDEX `index_users_username` ON `${TABLE_NAME}` (`username`)"
- }
- ],
- "foreignKeys": []
- },
- {
- "tableName": "chatrooms",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `subscriptionId` TEXT NOT NULL, `type` TEXT NOT NULL, `name` TEXT NOT NULL, `fullname` TEXT, `userId` TEXT, `ownerId` TEXT, `readonly` INTEGER, `isDefault` INTEGER, `favorite` INTEGER, `open` INTEGER NOT NULL, `alert` INTEGER NOT NULL, `unread` INTEGER NOT NULL, `userMentions` INTEGER, `groupMentions` INTEGER, `updatedAt` INTEGER, `timestamp` INTEGER, `lastSeen` INTEGER, `lastMessageText` TEXT, `lastMessageUserId` TEXT, `lastMessageTimestamp` INTEGER, PRIMARY KEY(`id`), FOREIGN KEY(`ownerId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`userId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`lastMessageUserId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
- "fields": [
- {
- "fieldPath": "id",
- "columnName": "id",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "subscriptionId",
- "columnName": "subscriptionId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "type",
- "columnName": "type",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "name",
- "columnName": "name",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "fullname",
- "columnName": "fullname",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "userId",
- "columnName": "userId",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "ownerId",
- "columnName": "ownerId",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "readonly",
- "columnName": "readonly",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "isDefault",
- "columnName": "isDefault",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "favorite",
- "columnName": "favorite",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "open",
- "columnName": "open",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "alert",
- "columnName": "alert",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "unread",
- "columnName": "unread",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "userMentions",
- "columnName": "userMentions",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "groupMentions",
- "columnName": "groupMentions",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "updatedAt",
- "columnName": "updatedAt",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "timestamp",
- "columnName": "timestamp",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "lastSeen",
- "columnName": "lastSeen",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "lastMessageText",
- "columnName": "lastMessageText",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "lastMessageUserId",
- "columnName": "lastMessageUserId",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "lastMessageTimestamp",
- "columnName": "lastMessageTimestamp",
- "affinity": "INTEGER",
- "notNull": false
- }
- ],
- "primaryKey": {
- "columnNames": [
- "id"
- ],
- "autoGenerate": false
- },
- "indices": [
- {
- "name": "index_chatrooms_userId",
- "unique": false,
- "columnNames": [
- "userId"
- ],
- "createSql": "CREATE INDEX `index_chatrooms_userId` ON `${TABLE_NAME}` (`userId`)"
- },
- {
- "name": "index_chatrooms_ownerId",
- "unique": false,
- "columnNames": [
- "ownerId"
- ],
- "createSql": "CREATE INDEX `index_chatrooms_ownerId` ON `${TABLE_NAME}` (`ownerId`)"
- },
- {
- "name": "index_chatrooms_subscriptionId",
- "unique": true,
- "columnNames": [
- "subscriptionId"
- ],
- "createSql": "CREATE UNIQUE INDEX `index_chatrooms_subscriptionId` ON `${TABLE_NAME}` (`subscriptionId`)"
- },
- {
- "name": "index_chatrooms_updatedAt",
- "unique": false,
- "columnNames": [
- "updatedAt"
- ],
- "createSql": "CREATE INDEX `index_chatrooms_updatedAt` ON `${TABLE_NAME}` (`updatedAt`)"
- }
- ],
- "foreignKeys": [
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "ownerId"
- ],
- "referencedColumns": [
- "id"
- ]
- },
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "userId"
- ],
- "referencedColumns": [
- "id"
- ]
- },
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "lastMessageUserId"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- }
- ],
- "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, \"06359a8c2943365dd094bc5dff210203\")"
- ]
- }
-}
\ No newline at end of file
diff --git a/app/schemas/chat.rocket.android.db.RCDatabase/4.json b/app/schemas/chat.rocket.android.db.RCDatabase/4.json
deleted file mode 100644
index e7485fd072..0000000000
--- a/app/schemas/chat.rocket.android.db.RCDatabase/4.json
+++ /dev/null
@@ -1,279 +0,0 @@
-{
- "formatVersion": 1,
- "database": {
- "version": 4,
- "identityHash": "e389d26bfb975f00c75dc6fc5d06d012",
- "entities": [
- {
- "tableName": "users",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `username` TEXT, `name` TEXT, `status` TEXT NOT NULL, `utcOffset` REAL, PRIMARY KEY(`id`))",
- "fields": [
- {
- "fieldPath": "id",
- "columnName": "id",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "username",
- "columnName": "username",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "name",
- "columnName": "name",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "status",
- "columnName": "status",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "utcOffset",
- "columnName": "utcOffset",
- "affinity": "REAL",
- "notNull": false
- }
- ],
- "primaryKey": {
- "columnNames": [
- "id"
- ],
- "autoGenerate": false
- },
- "indices": [
- {
- "name": "index_users_username",
- "unique": false,
- "columnNames": [
- "username"
- ],
- "createSql": "CREATE INDEX `index_users_username` ON `${TABLE_NAME}` (`username`)"
- }
- ],
- "foreignKeys": []
- },
- {
- "tableName": "chatrooms",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `subscriptionId` TEXT NOT NULL, `type` TEXT NOT NULL, `name` TEXT NOT NULL, `fullname` TEXT, `userId` TEXT, `ownerId` TEXT, `readonly` INTEGER, `isDefault` INTEGER, `favorite` INTEGER, `open` INTEGER NOT NULL, `alert` INTEGER NOT NULL, `unread` INTEGER NOT NULL, `userMentions` INTEGER, `groupMentions` INTEGER, `updatedAt` INTEGER, `timestamp` INTEGER, `lastSeen` INTEGER, `lastMessageText` TEXT, `lastMessageUserId` TEXT, `lastMessageTimestamp` INTEGER, `broadcast` INTEGER, PRIMARY KEY(`id`), FOREIGN KEY(`ownerId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`userId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`lastMessageUserId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
- "fields": [
- {
- "fieldPath": "id",
- "columnName": "id",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "subscriptionId",
- "columnName": "subscriptionId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "type",
- "columnName": "type",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "name",
- "columnName": "name",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "fullname",
- "columnName": "fullname",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "userId",
- "columnName": "userId",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "ownerId",
- "columnName": "ownerId",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "readonly",
- "columnName": "readonly",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "isDefault",
- "columnName": "isDefault",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "favorite",
- "columnName": "favorite",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "open",
- "columnName": "open",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "alert",
- "columnName": "alert",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "unread",
- "columnName": "unread",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "userMentions",
- "columnName": "userMentions",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "groupMentions",
- "columnName": "groupMentions",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "updatedAt",
- "columnName": "updatedAt",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "timestamp",
- "columnName": "timestamp",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "lastSeen",
- "columnName": "lastSeen",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "lastMessageText",
- "columnName": "lastMessageText",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "lastMessageUserId",
- "columnName": "lastMessageUserId",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "lastMessageTimestamp",
- "columnName": "lastMessageTimestamp",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "broadcast",
- "columnName": "broadcast",
- "affinity": "INTEGER",
- "notNull": false
- }
- ],
- "primaryKey": {
- "columnNames": [
- "id"
- ],
- "autoGenerate": false
- },
- "indices": [
- {
- "name": "index_chatrooms_userId",
- "unique": false,
- "columnNames": [
- "userId"
- ],
- "createSql": "CREATE INDEX `index_chatrooms_userId` ON `${TABLE_NAME}` (`userId`)"
- },
- {
- "name": "index_chatrooms_ownerId",
- "unique": false,
- "columnNames": [
- "ownerId"
- ],
- "createSql": "CREATE INDEX `index_chatrooms_ownerId` ON `${TABLE_NAME}` (`ownerId`)"
- },
- {
- "name": "index_chatrooms_subscriptionId",
- "unique": true,
- "columnNames": [
- "subscriptionId"
- ],
- "createSql": "CREATE UNIQUE INDEX `index_chatrooms_subscriptionId` ON `${TABLE_NAME}` (`subscriptionId`)"
- },
- {
- "name": "index_chatrooms_updatedAt",
- "unique": false,
- "columnNames": [
- "updatedAt"
- ],
- "createSql": "CREATE INDEX `index_chatrooms_updatedAt` ON `${TABLE_NAME}` (`updatedAt`)"
- }
- ],
- "foreignKeys": [
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "ownerId"
- ],
- "referencedColumns": [
- "id"
- ]
- },
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "userId"
- ],
- "referencedColumns": [
- "id"
- ]
- },
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "lastMessageUserId"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- }
- ],
- "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, \"e389d26bfb975f00c75dc6fc5d06d012\")"
- ]
- }
-}
\ No newline at end of file
diff --git a/app/schemas/chat.rocket.android.db.RCDatabase/5.json b/app/schemas/chat.rocket.android.db.RCDatabase/5.json
deleted file mode 100644
index d09c9f0ca7..0000000000
--- a/app/schemas/chat.rocket.android.db.RCDatabase/5.json
+++ /dev/null
@@ -1,287 +0,0 @@
-{
- "formatVersion": 1,
- "database": {
- "version": 5,
- "identityHash": "47a0c30e2696ae09bc86df16cc37279d",
- "entities": [
- {
- "tableName": "users",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `username` TEXT, `name` TEXT, `status` TEXT NOT NULL, `utcOffset` REAL, PRIMARY KEY(`id`))",
- "fields": [
- {
- "fieldPath": "id",
- "columnName": "id",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "username",
- "columnName": "username",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "name",
- "columnName": "name",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "status",
- "columnName": "status",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "utcOffset",
- "columnName": "utcOffset",
- "affinity": "REAL",
- "notNull": false
- }
- ],
- "primaryKey": {
- "columnNames": [
- "id"
- ],
- "autoGenerate": false
- },
- "indices": [
- {
- "name": "index_users_username",
- "unique": false,
- "columnNames": [
- "username"
- ],
- "createSql": "CREATE INDEX `index_users_username` ON `${TABLE_NAME}` (`username`)"
- }
- ],
- "foreignKeys": []
- },
- {
- "tableName": "chatrooms",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `subscriptionId` TEXT NOT NULL, `type` TEXT NOT NULL, `name` TEXT NOT NULL, `fullname` TEXT, `userId` TEXT, `ownerId` TEXT, `readonly` INTEGER, `isDefault` INTEGER, `favorite` INTEGER, `open` INTEGER NOT NULL, `alert` INTEGER NOT NULL, `unread` INTEGER NOT NULL, `userMentions` INTEGER, `groupMentions` INTEGER, `updatedAt` INTEGER, `timestamp` INTEGER, `lastSeen` INTEGER, `lastMessageText` TEXT, `lastMessageUserId` TEXT, `lastMessageTimestamp` INTEGER, `broadcast` INTEGER, PRIMARY KEY(`id`), FOREIGN KEY(`ownerId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`userId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`lastMessageUserId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
- "fields": [
- {
- "fieldPath": "id",
- "columnName": "id",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "subscriptionId",
- "columnName": "subscriptionId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "type",
- "columnName": "type",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "name",
- "columnName": "name",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "fullname",
- "columnName": "fullname",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "userId",
- "columnName": "userId",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "ownerId",
- "columnName": "ownerId",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "readonly",
- "columnName": "readonly",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "isDefault",
- "columnName": "isDefault",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "favorite",
- "columnName": "favorite",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "open",
- "columnName": "open",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "alert",
- "columnName": "alert",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "unread",
- "columnName": "unread",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "userMentions",
- "columnName": "userMentions",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "groupMentions",
- "columnName": "groupMentions",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "updatedAt",
- "columnName": "updatedAt",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "timestamp",
- "columnName": "timestamp",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "lastSeen",
- "columnName": "lastSeen",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "lastMessageText",
- "columnName": "lastMessageText",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "lastMessageUserId",
- "columnName": "lastMessageUserId",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "lastMessageTimestamp",
- "columnName": "lastMessageTimestamp",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "broadcast",
- "columnName": "broadcast",
- "affinity": "INTEGER",
- "notNull": false
- }
- ],
- "primaryKey": {
- "columnNames": [
- "id"
- ],
- "autoGenerate": false
- },
- "indices": [
- {
- "name": "index_chatrooms_userId",
- "unique": false,
- "columnNames": [
- "userId"
- ],
- "createSql": "CREATE INDEX `index_chatrooms_userId` ON `${TABLE_NAME}` (`userId`)"
- },
- {
- "name": "index_chatrooms_ownerId",
- "unique": false,
- "columnNames": [
- "ownerId"
- ],
- "createSql": "CREATE INDEX `index_chatrooms_ownerId` ON `${TABLE_NAME}` (`ownerId`)"
- },
- {
- "name": "index_chatrooms_subscriptionId",
- "unique": true,
- "columnNames": [
- "subscriptionId"
- ],
- "createSql": "CREATE UNIQUE INDEX `index_chatrooms_subscriptionId` ON `${TABLE_NAME}` (`subscriptionId`)"
- },
- {
- "name": "index_chatrooms_updatedAt",
- "unique": false,
- "columnNames": [
- "updatedAt"
- ],
- "createSql": "CREATE INDEX `index_chatrooms_updatedAt` ON `${TABLE_NAME}` (`updatedAt`)"
- },
- {
- "name": "index_chatrooms_lastMessageUserId",
- "unique": false,
- "columnNames": [
- "lastMessageUserId"
- ],
- "createSql": "CREATE INDEX `index_chatrooms_lastMessageUserId` ON `${TABLE_NAME}` (`lastMessageUserId`)"
- }
- ],
- "foreignKeys": [
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "ownerId"
- ],
- "referencedColumns": [
- "id"
- ]
- },
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "userId"
- ],
- "referencedColumns": [
- "id"
- ]
- },
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "lastMessageUserId"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- }
- ],
- "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, \"47a0c30e2696ae09bc86df16cc37279d\")"
- ]
- }
-}
\ No newline at end of file
diff --git a/app/schemas/chat.rocket.android.db.RCDatabase/6.json b/app/schemas/chat.rocket.android.db.RCDatabase/6.json
deleted file mode 100644
index b3f9e85a20..0000000000
--- a/app/schemas/chat.rocket.android.db.RCDatabase/6.json
+++ /dev/null
@@ -1,946 +0,0 @@
-{
- "formatVersion": 1,
- "database": {
- "version": 6,
- "identityHash": "03aec453cb4faec2d1357fdb673b151e",
- "entities": [
- {
- "tableName": "users",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `username` TEXT, `name` TEXT, `status` TEXT NOT NULL, `utcOffset` REAL, PRIMARY KEY(`id`))",
- "fields": [
- {
- "fieldPath": "id",
- "columnName": "id",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "username",
- "columnName": "username",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "name",
- "columnName": "name",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "status",
- "columnName": "status",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "utcOffset",
- "columnName": "utcOffset",
- "affinity": "REAL",
- "notNull": false
- }
- ],
- "primaryKey": {
- "columnNames": [
- "id"
- ],
- "autoGenerate": false
- },
- "indices": [
- {
- "name": "index_users_username",
- "unique": false,
- "columnNames": [
- "username"
- ],
- "createSql": "CREATE INDEX `index_users_username` ON `${TABLE_NAME}` (`username`)"
- }
- ],
- "foreignKeys": []
- },
- {
- "tableName": "chatrooms",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `subscriptionId` TEXT NOT NULL, `type` TEXT NOT NULL, `name` TEXT NOT NULL, `fullname` TEXT, `userId` TEXT, `ownerId` TEXT, `readonly` INTEGER, `isDefault` INTEGER, `favorite` INTEGER, `open` INTEGER NOT NULL, `alert` INTEGER NOT NULL, `unread` INTEGER NOT NULL, `userMentions` INTEGER, `groupMentions` INTEGER, `updatedAt` INTEGER, `timestamp` INTEGER, `lastSeen` INTEGER, `lastMessageText` TEXT, `lastMessageUserId` TEXT, `lastMessageTimestamp` INTEGER, `broadcast` INTEGER, PRIMARY KEY(`id`), FOREIGN KEY(`ownerId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`userId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`lastMessageUserId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
- "fields": [
- {
- "fieldPath": "id",
- "columnName": "id",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "subscriptionId",
- "columnName": "subscriptionId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "type",
- "columnName": "type",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "name",
- "columnName": "name",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "fullname",
- "columnName": "fullname",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "userId",
- "columnName": "userId",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "ownerId",
- "columnName": "ownerId",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "readonly",
- "columnName": "readonly",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "isDefault",
- "columnName": "isDefault",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "favorite",
- "columnName": "favorite",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "open",
- "columnName": "open",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "alert",
- "columnName": "alert",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "unread",
- "columnName": "unread",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "userMentions",
- "columnName": "userMentions",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "groupMentions",
- "columnName": "groupMentions",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "updatedAt",
- "columnName": "updatedAt",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "timestamp",
- "columnName": "timestamp",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "lastSeen",
- "columnName": "lastSeen",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "lastMessageText",
- "columnName": "lastMessageText",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "lastMessageUserId",
- "columnName": "lastMessageUserId",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "lastMessageTimestamp",
- "columnName": "lastMessageTimestamp",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "broadcast",
- "columnName": "broadcast",
- "affinity": "INTEGER",
- "notNull": false
- }
- ],
- "primaryKey": {
- "columnNames": [
- "id"
- ],
- "autoGenerate": false
- },
- "indices": [
- {
- "name": "index_chatrooms_userId",
- "unique": false,
- "columnNames": [
- "userId"
- ],
- "createSql": "CREATE INDEX `index_chatrooms_userId` ON `${TABLE_NAME}` (`userId`)"
- },
- {
- "name": "index_chatrooms_ownerId",
- "unique": false,
- "columnNames": [
- "ownerId"
- ],
- "createSql": "CREATE INDEX `index_chatrooms_ownerId` ON `${TABLE_NAME}` (`ownerId`)"
- },
- {
- "name": "index_chatrooms_subscriptionId",
- "unique": true,
- "columnNames": [
- "subscriptionId"
- ],
- "createSql": "CREATE UNIQUE INDEX `index_chatrooms_subscriptionId` ON `${TABLE_NAME}` (`subscriptionId`)"
- },
- {
- "name": "index_chatrooms_updatedAt",
- "unique": false,
- "columnNames": [
- "updatedAt"
- ],
- "createSql": "CREATE INDEX `index_chatrooms_updatedAt` ON `${TABLE_NAME}` (`updatedAt`)"
- },
- {
- "name": "index_chatrooms_lastMessageUserId",
- "unique": false,
- "columnNames": [
- "lastMessageUserId"
- ],
- "createSql": "CREATE INDEX `index_chatrooms_lastMessageUserId` ON `${TABLE_NAME}` (`lastMessageUserId`)"
- }
- ],
- "foreignKeys": [
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "ownerId"
- ],
- "referencedColumns": [
- "id"
- ]
- },
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "userId"
- ],
- "referencedColumns": [
- "id"
- ]
- },
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "lastMessageUserId"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "messages",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `roomId` TEXT NOT NULL, `message` TEXT NOT NULL, `timestamp` INTEGER NOT NULL, `senderId` TEXT, `updatedAt` INTEGER, `editedAt` INTEGER, `editedBy` TEXT, `senderAlias` TEXT, `avatar` TEXT, `type` TEXT, `groupable` INTEGER NOT NULL, `parseUrls` INTEGER NOT NULL, `pinned` INTEGER NOT NULL, `role` TEXT, PRIMARY KEY(`id`), FOREIGN KEY(`senderId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`editedBy`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
- "fields": [
- {
- "fieldPath": "id",
- "columnName": "id",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "roomId",
- "columnName": "roomId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "message",
- "columnName": "message",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "timestamp",
- "columnName": "timestamp",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "senderId",
- "columnName": "senderId",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "updatedAt",
- "columnName": "updatedAt",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "editedAt",
- "columnName": "editedAt",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "editedBy",
- "columnName": "editedBy",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "senderAlias",
- "columnName": "senderAlias",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "avatar",
- "columnName": "avatar",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "type",
- "columnName": "type",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "groupable",
- "columnName": "groupable",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "parseUrls",
- "columnName": "parseUrls",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "pinned",
- "columnName": "pinned",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "role",
- "columnName": "role",
- "affinity": "TEXT",
- "notNull": false
- }
- ],
- "primaryKey": {
- "columnNames": [
- "id"
- ],
- "autoGenerate": false
- },
- "indices": [],
- "foreignKeys": [
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "senderId"
- ],
- "referencedColumns": [
- "id"
- ]
- },
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "editedBy"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "message_favorites",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`messageId` TEXT NOT NULL, `userId` TEXT NOT NULL, PRIMARY KEY(`messageId`, `userId`), FOREIGN KEY(`messageId`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`userId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
- "fields": [
- {
- "fieldPath": "messageId",
- "columnName": "messageId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "userId",
- "columnName": "userId",
- "affinity": "TEXT",
- "notNull": true
- }
- ],
- "primaryKey": {
- "columnNames": [
- "messageId",
- "userId"
- ],
- "autoGenerate": false
- },
- "indices": [],
- "foreignKeys": [
- {
- "table": "messages",
- "onDelete": "CASCADE",
- "onUpdate": "NO ACTION",
- "columns": [
- "messageId"
- ],
- "referencedColumns": [
- "id"
- ]
- },
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "userId"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "message_mentions",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`messageId` TEXT NOT NULL, `userId` TEXT NOT NULL, PRIMARY KEY(`messageId`, `userId`), FOREIGN KEY(`messageId`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`userId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
- "fields": [
- {
- "fieldPath": "messageId",
- "columnName": "messageId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "userId",
- "columnName": "userId",
- "affinity": "TEXT",
- "notNull": true
- }
- ],
- "primaryKey": {
- "columnNames": [
- "messageId",
- "userId"
- ],
- "autoGenerate": false
- },
- "indices": [],
- "foreignKeys": [
- {
- "table": "messages",
- "onDelete": "CASCADE",
- "onUpdate": "NO ACTION",
- "columns": [
- "messageId"
- ],
- "referencedColumns": [
- "id"
- ]
- },
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "userId"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "message_channels",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`messageId` TEXT NOT NULL, `roomId` TEXT NOT NULL, `roomName` TEXT, PRIMARY KEY(`messageId`, `roomId`), FOREIGN KEY(`messageId`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
- "fields": [
- {
- "fieldPath": "messageId",
- "columnName": "messageId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "roomId",
- "columnName": "roomId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "roomName",
- "columnName": "roomName",
- "affinity": "TEXT",
- "notNull": false
- }
- ],
- "primaryKey": {
- "columnNames": [
- "messageId",
- "roomId"
- ],
- "autoGenerate": false
- },
- "indices": [],
- "foreignKeys": [
- {
- "table": "messages",
- "onDelete": "CASCADE",
- "onUpdate": "NO ACTION",
- "columns": [
- "messageId"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "attachments",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `message_id` TEXT NOT NULL, `title` TEXT, `type` TEXT, `description` TEXT, `text` TEXT, `author_name` TEXT, `author_icon` TEXT, `author_link` TEXT, `thumb_url` TEXT, `color` TEXT, `title_link` TEXT, `title_link_download` INTEGER NOT NULL, `image_url` TEXT, `image_type` TEXT, `image_size` INTEGER, `video_url` TEXT, `video_type` TEXT, `video_size` INTEGER, `audio_url` TEXT, `audio_type` TEXT, `audio_size` INTEGER, `message_link` TEXT, `timestamp` INTEGER, PRIMARY KEY(`id`), FOREIGN KEY(`message_id`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
- "fields": [
- {
- "fieldPath": "id",
- "columnName": "id",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "messageId",
- "columnName": "message_id",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "title",
- "columnName": "title",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "type",
- "columnName": "type",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "description",
- "columnName": "description",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "text",
- "columnName": "text",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "authorName",
- "columnName": "author_name",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "authorIcon",
- "columnName": "author_icon",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "authorLink",
- "columnName": "author_link",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "thumbUrl",
- "columnName": "thumb_url",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "color",
- "columnName": "color",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "titleLink",
- "columnName": "title_link",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "titleLinkDownload",
- "columnName": "title_link_download",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "imageUrl",
- "columnName": "image_url",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "imageType",
- "columnName": "image_type",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "imageSize",
- "columnName": "image_size",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "videoUrl",
- "columnName": "video_url",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "videoType",
- "columnName": "video_type",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "videoSize",
- "columnName": "video_size",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "audioUrl",
- "columnName": "audio_url",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "audioType",
- "columnName": "audio_type",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "audioSize",
- "columnName": "audio_size",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "messageLink",
- "columnName": "message_link",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "timestamp",
- "columnName": "timestamp",
- "affinity": "INTEGER",
- "notNull": false
- }
- ],
- "primaryKey": {
- "columnNames": [
- "id"
- ],
- "autoGenerate": false
- },
- "indices": [],
- "foreignKeys": [
- {
- "table": "messages",
- "onDelete": "CASCADE",
- "onUpdate": "NO ACTION",
- "columns": [
- "message_id"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "attachment_fields",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `attachmentId` TEXT NOT NULL, `title` TEXT NOT NULL, `value` TEXT NOT NULL, FOREIGN KEY(`attachmentId`) REFERENCES `attachments`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
- "fields": [
- {
- "fieldPath": "id",
- "columnName": "id",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "attachmentId",
- "columnName": "attachmentId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "title",
- "columnName": "title",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "value",
- "columnName": "value",
- "affinity": "TEXT",
- "notNull": true
- }
- ],
- "primaryKey": {
- "columnNames": [
- "id"
- ],
- "autoGenerate": true
- },
- "indices": [],
- "foreignKeys": [
- {
- "table": "attachments",
- "onDelete": "CASCADE",
- "onUpdate": "NO ACTION",
- "columns": [
- "attachmentId"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "urls",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `messageId` TEXT NOT NULL, `url` TEXT NOT NULL, `hostname` TEXT, `title` TEXT, `description` TEXT, `imageUrl` TEXT, FOREIGN KEY(`messageId`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
- "fields": [
- {
- "fieldPath": "id",
- "columnName": "id",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "messageId",
- "columnName": "messageId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "url",
- "columnName": "url",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "hostname",
- "columnName": "hostname",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "title",
- "columnName": "title",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "description",
- "columnName": "description",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "imageUrl",
- "columnName": "imageUrl",
- "affinity": "TEXT",
- "notNull": false
- }
- ],
- "primaryKey": {
- "columnNames": [
- "id"
- ],
- "autoGenerate": true
- },
- "indices": [
- {
- "name": "index_urls_messageId",
- "unique": false,
- "columnNames": [
- "messageId"
- ],
- "createSql": "CREATE INDEX `index_urls_messageId` ON `${TABLE_NAME}` (`messageId`)"
- }
- ],
- "foreignKeys": [
- {
- "table": "messages",
- "onDelete": "CASCADE",
- "onUpdate": "NO ACTION",
- "columns": [
- "messageId"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "reactions",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`reaction` TEXT NOT NULL, PRIMARY KEY(`reaction`))",
- "fields": [
- {
- "fieldPath": "reaction",
- "columnName": "reaction",
- "affinity": "TEXT",
- "notNull": true
- }
- ],
- "primaryKey": {
- "columnNames": [
- "reaction"
- ],
- "autoGenerate": false
- },
- "indices": [],
- "foreignKeys": []
- },
- {
- "tableName": "reactions_message_relations",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `reactionId` TEXT NOT NULL, `messageId` TEXT NOT NULL, `count` INTEGER NOT NULL, FOREIGN KEY(`reactionId`) REFERENCES `reactions`(`reaction`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`messageId`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
- "fields": [
- {
- "fieldPath": "id",
- "columnName": "id",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "reactionId",
- "columnName": "reactionId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "messageId",
- "columnName": "messageId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "count",
- "columnName": "count",
- "affinity": "INTEGER",
- "notNull": true
- }
- ],
- "primaryKey": {
- "columnNames": [
- "id"
- ],
- "autoGenerate": true
- },
- "indices": [
- {
- "name": "index_reactions_message_relations_messageId",
- "unique": false,
- "columnNames": [
- "messageId"
- ],
- "createSql": "CREATE INDEX `index_reactions_message_relations_messageId` ON `${TABLE_NAME}` (`messageId`)"
- }
- ],
- "foreignKeys": [
- {
- "table": "reactions",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "reactionId"
- ],
- "referencedColumns": [
- "reaction"
- ]
- },
- {
- "table": "messages",
- "onDelete": "CASCADE",
- "onUpdate": "NO ACTION",
- "columns": [
- "messageId"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- }
- ],
- "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, \"03aec453cb4faec2d1357fdb673b151e\")"
- ]
- }
-}
\ No newline at end of file
diff --git a/app/schemas/chat.rocket.android.db.RCDatabase/7.json b/app/schemas/chat.rocket.android.db.RCDatabase/7.json
deleted file mode 100644
index c0f12cf494..0000000000
--- a/app/schemas/chat.rocket.android.db.RCDatabase/7.json
+++ /dev/null
@@ -1,959 +0,0 @@
-{
- "formatVersion": 1,
- "database": {
- "version": 7,
- "identityHash": "4d5ac4ae382ddb3aa3850842253e89d2",
- "entities": [
- {
- "tableName": "users",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `username` TEXT, `name` TEXT, `status` TEXT NOT NULL, `utcOffset` REAL, PRIMARY KEY(`id`))",
- "fields": [
- {
- "fieldPath": "id",
- "columnName": "id",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "username",
- "columnName": "username",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "name",
- "columnName": "name",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "status",
- "columnName": "status",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "utcOffset",
- "columnName": "utcOffset",
- "affinity": "REAL",
- "notNull": false
- }
- ],
- "primaryKey": {
- "columnNames": [
- "id"
- ],
- "autoGenerate": false
- },
- "indices": [
- {
- "name": "index_users_username",
- "unique": false,
- "columnNames": [
- "username"
- ],
- "createSql": "CREATE INDEX `index_users_username` ON `${TABLE_NAME}` (`username`)"
- }
- ],
- "foreignKeys": []
- },
- {
- "tableName": "chatrooms",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `subscriptionId` TEXT NOT NULL, `type` TEXT NOT NULL, `name` TEXT NOT NULL, `fullname` TEXT, `userId` TEXT, `ownerId` TEXT, `readonly` INTEGER, `isDefault` INTEGER, `favorite` INTEGER, `open` INTEGER NOT NULL, `alert` INTEGER NOT NULL, `unread` INTEGER NOT NULL, `userMentions` INTEGER, `groupMentions` INTEGER, `updatedAt` INTEGER, `timestamp` INTEGER, `lastSeen` INTEGER, `lastMessageText` TEXT, `lastMessageUserId` TEXT, `lastMessageTimestamp` INTEGER, `broadcast` INTEGER, PRIMARY KEY(`id`), FOREIGN KEY(`ownerId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`userId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`lastMessageUserId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
- "fields": [
- {
- "fieldPath": "id",
- "columnName": "id",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "subscriptionId",
- "columnName": "subscriptionId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "type",
- "columnName": "type",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "name",
- "columnName": "name",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "fullname",
- "columnName": "fullname",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "userId",
- "columnName": "userId",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "ownerId",
- "columnName": "ownerId",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "readonly",
- "columnName": "readonly",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "isDefault",
- "columnName": "isDefault",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "favorite",
- "columnName": "favorite",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "open",
- "columnName": "open",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "alert",
- "columnName": "alert",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "unread",
- "columnName": "unread",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "userMentions",
- "columnName": "userMentions",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "groupMentions",
- "columnName": "groupMentions",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "updatedAt",
- "columnName": "updatedAt",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "timestamp",
- "columnName": "timestamp",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "lastSeen",
- "columnName": "lastSeen",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "lastMessageText",
- "columnName": "lastMessageText",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "lastMessageUserId",
- "columnName": "lastMessageUserId",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "lastMessageTimestamp",
- "columnName": "lastMessageTimestamp",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "broadcast",
- "columnName": "broadcast",
- "affinity": "INTEGER",
- "notNull": false
- }
- ],
- "primaryKey": {
- "columnNames": [
- "id"
- ],
- "autoGenerate": false
- },
- "indices": [
- {
- "name": "index_chatrooms_userId",
- "unique": false,
- "columnNames": [
- "userId"
- ],
- "createSql": "CREATE INDEX `index_chatrooms_userId` ON `${TABLE_NAME}` (`userId`)"
- },
- {
- "name": "index_chatrooms_ownerId",
- "unique": false,
- "columnNames": [
- "ownerId"
- ],
- "createSql": "CREATE INDEX `index_chatrooms_ownerId` ON `${TABLE_NAME}` (`ownerId`)"
- },
- {
- "name": "index_chatrooms_subscriptionId",
- "unique": true,
- "columnNames": [
- "subscriptionId"
- ],
- "createSql": "CREATE UNIQUE INDEX `index_chatrooms_subscriptionId` ON `${TABLE_NAME}` (`subscriptionId`)"
- },
- {
- "name": "index_chatrooms_updatedAt",
- "unique": false,
- "columnNames": [
- "updatedAt"
- ],
- "createSql": "CREATE INDEX `index_chatrooms_updatedAt` ON `${TABLE_NAME}` (`updatedAt`)"
- },
- {
- "name": "index_chatrooms_lastMessageUserId",
- "unique": false,
- "columnNames": [
- "lastMessageUserId"
- ],
- "createSql": "CREATE INDEX `index_chatrooms_lastMessageUserId` ON `${TABLE_NAME}` (`lastMessageUserId`)"
- }
- ],
- "foreignKeys": [
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "ownerId"
- ],
- "referencedColumns": [
- "id"
- ]
- },
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "userId"
- ],
- "referencedColumns": [
- "id"
- ]
- },
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "lastMessageUserId"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "messages",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `roomId` TEXT NOT NULL, `message` TEXT NOT NULL, `timestamp` INTEGER NOT NULL, `senderId` TEXT, `updatedAt` INTEGER, `editedAt` INTEGER, `editedBy` TEXT, `senderAlias` TEXT, `avatar` TEXT, `type` TEXT, `groupable` INTEGER NOT NULL, `parseUrls` INTEGER NOT NULL, `pinned` INTEGER NOT NULL, `role` TEXT, `synced` INTEGER NOT NULL, `unread` INTEGER, PRIMARY KEY(`id`), FOREIGN KEY(`senderId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`editedBy`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
- "fields": [
- {
- "fieldPath": "id",
- "columnName": "id",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "roomId",
- "columnName": "roomId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "message",
- "columnName": "message",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "timestamp",
- "columnName": "timestamp",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "senderId",
- "columnName": "senderId",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "updatedAt",
- "columnName": "updatedAt",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "editedAt",
- "columnName": "editedAt",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "editedBy",
- "columnName": "editedBy",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "senderAlias",
- "columnName": "senderAlias",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "avatar",
- "columnName": "avatar",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "type",
- "columnName": "type",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "groupable",
- "columnName": "groupable",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "parseUrls",
- "columnName": "parseUrls",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "pinned",
- "columnName": "pinned",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "role",
- "columnName": "role",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "synced",
- "columnName": "synced",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "unread",
- "columnName": "unread",
- "affinity": "INTEGER",
- "notNull": false
- }
- ],
- "primaryKey": {
- "columnNames": [
- "id"
- ],
- "autoGenerate": false
- },
- "indices": [],
- "foreignKeys": [
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "senderId"
- ],
- "referencedColumns": [
- "id"
- ]
- },
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "editedBy"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "message_favorites",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`messageId` TEXT NOT NULL, `userId` TEXT NOT NULL, PRIMARY KEY(`messageId`, `userId`), FOREIGN KEY(`messageId`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`userId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
- "fields": [
- {
- "fieldPath": "messageId",
- "columnName": "messageId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "userId",
- "columnName": "userId",
- "affinity": "TEXT",
- "notNull": true
- }
- ],
- "primaryKey": {
- "columnNames": [
- "messageId",
- "userId"
- ],
- "autoGenerate": false
- },
- "indices": [],
- "foreignKeys": [
- {
- "table": "messages",
- "onDelete": "CASCADE",
- "onUpdate": "NO ACTION",
- "columns": [
- "messageId"
- ],
- "referencedColumns": [
- "id"
- ]
- },
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "userId"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "message_mentions",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`messageId` TEXT NOT NULL, `userId` TEXT NOT NULL, PRIMARY KEY(`messageId`, `userId`), FOREIGN KEY(`messageId`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`userId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
- "fields": [
- {
- "fieldPath": "messageId",
- "columnName": "messageId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "userId",
- "columnName": "userId",
- "affinity": "TEXT",
- "notNull": true
- }
- ],
- "primaryKey": {
- "columnNames": [
- "messageId",
- "userId"
- ],
- "autoGenerate": false
- },
- "indices": [],
- "foreignKeys": [
- {
- "table": "messages",
- "onDelete": "CASCADE",
- "onUpdate": "NO ACTION",
- "columns": [
- "messageId"
- ],
- "referencedColumns": [
- "id"
- ]
- },
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "userId"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "message_channels",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`messageId` TEXT NOT NULL, `roomId` TEXT NOT NULL, `roomName` TEXT, PRIMARY KEY(`messageId`, `roomId`), FOREIGN KEY(`messageId`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
- "fields": [
- {
- "fieldPath": "messageId",
- "columnName": "messageId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "roomId",
- "columnName": "roomId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "roomName",
- "columnName": "roomName",
- "affinity": "TEXT",
- "notNull": false
- }
- ],
- "primaryKey": {
- "columnNames": [
- "messageId",
- "roomId"
- ],
- "autoGenerate": false
- },
- "indices": [],
- "foreignKeys": [
- {
- "table": "messages",
- "onDelete": "CASCADE",
- "onUpdate": "NO ACTION",
- "columns": [
- "messageId"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "attachments",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` TEXT NOT NULL, `message_id` TEXT NOT NULL, `title` TEXT, `type` TEXT, `description` TEXT, `text` TEXT, `author_name` TEXT, `author_icon` TEXT, `author_link` TEXT, `thumb_url` TEXT, `color` TEXT, `fallback` TEXT, `title_link` TEXT, `title_link_download` INTEGER NOT NULL, `image_url` TEXT, `image_type` TEXT, `image_size` INTEGER, `video_url` TEXT, `video_type` TEXT, `video_size` INTEGER, `audio_url` TEXT, `audio_type` TEXT, `audio_size` INTEGER, `message_link` TEXT, `timestamp` INTEGER, PRIMARY KEY(`_id`), FOREIGN KEY(`message_id`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
- "fields": [
- {
- "fieldPath": "_id",
- "columnName": "_id",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "messageId",
- "columnName": "message_id",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "title",
- "columnName": "title",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "type",
- "columnName": "type",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "description",
- "columnName": "description",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "text",
- "columnName": "text",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "authorName",
- "columnName": "author_name",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "authorIcon",
- "columnName": "author_icon",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "authorLink",
- "columnName": "author_link",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "thumbUrl",
- "columnName": "thumb_url",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "color",
- "columnName": "color",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "fallback",
- "columnName": "fallback",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "titleLink",
- "columnName": "title_link",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "titleLinkDownload",
- "columnName": "title_link_download",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "imageUrl",
- "columnName": "image_url",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "imageType",
- "columnName": "image_type",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "imageSize",
- "columnName": "image_size",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "videoUrl",
- "columnName": "video_url",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "videoType",
- "columnName": "video_type",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "videoSize",
- "columnName": "video_size",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "audioUrl",
- "columnName": "audio_url",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "audioType",
- "columnName": "audio_type",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "audioSize",
- "columnName": "audio_size",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "messageLink",
- "columnName": "message_link",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "timestamp",
- "columnName": "timestamp",
- "affinity": "INTEGER",
- "notNull": false
- }
- ],
- "primaryKey": {
- "columnNames": [
- "_id"
- ],
- "autoGenerate": false
- },
- "indices": [],
- "foreignKeys": [
- {
- "table": "messages",
- "onDelete": "CASCADE",
- "onUpdate": "NO ACTION",
- "columns": [
- "message_id"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "attachment_fields",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `attachmentId` TEXT NOT NULL, `title` TEXT NOT NULL, `value` TEXT NOT NULL, FOREIGN KEY(`attachmentId`) REFERENCES `attachments`(`_id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
- "fields": [
- {
- "fieldPath": "id",
- "columnName": "id",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "attachmentId",
- "columnName": "attachmentId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "title",
- "columnName": "title",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "value",
- "columnName": "value",
- "affinity": "TEXT",
- "notNull": true
- }
- ],
- "primaryKey": {
- "columnNames": [
- "id"
- ],
- "autoGenerate": true
- },
- "indices": [],
- "foreignKeys": [
- {
- "table": "attachments",
- "onDelete": "CASCADE",
- "onUpdate": "NO ACTION",
- "columns": [
- "attachmentId"
- ],
- "referencedColumns": [
- "_id"
- ]
- }
- ]
- },
- {
- "tableName": "urls",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`urlId` INTEGER PRIMARY KEY AUTOINCREMENT, `messageId` TEXT NOT NULL, `url` TEXT NOT NULL, `hostname` TEXT, `title` TEXT, `description` TEXT, `imageUrl` TEXT, FOREIGN KEY(`messageId`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
- "fields": [
- {
- "fieldPath": "urlId",
- "columnName": "urlId",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "messageId",
- "columnName": "messageId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "url",
- "columnName": "url",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "hostname",
- "columnName": "hostname",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "title",
- "columnName": "title",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "description",
- "columnName": "description",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "imageUrl",
- "columnName": "imageUrl",
- "affinity": "TEXT",
- "notNull": false
- }
- ],
- "primaryKey": {
- "columnNames": [
- "urlId"
- ],
- "autoGenerate": true
- },
- "indices": [
- {
- "name": "index_urls_messageId",
- "unique": false,
- "columnNames": [
- "messageId"
- ],
- "createSql": "CREATE INDEX `index_urls_messageId` ON `${TABLE_NAME}` (`messageId`)"
- }
- ],
- "foreignKeys": [
- {
- "table": "messages",
- "onDelete": "CASCADE",
- "onUpdate": "NO ACTION",
- "columns": [
- "messageId"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "reactions",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`reaction` TEXT NOT NULL, `messageId` TEXT NOT NULL, `count` INTEGER NOT NULL, `usernames` TEXT NOT NULL, PRIMARY KEY(`reaction`), FOREIGN KEY(`messageId`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
- "fields": [
- {
- "fieldPath": "reaction",
- "columnName": "reaction",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "messageId",
- "columnName": "messageId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "count",
- "columnName": "count",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "usernames",
- "columnName": "usernames",
- "affinity": "TEXT",
- "notNull": true
- }
- ],
- "primaryKey": {
- "columnNames": [
- "reaction"
- ],
- "autoGenerate": false
- },
- "indices": [
- {
- "name": "index_reactions_messageId",
- "unique": false,
- "columnNames": [
- "messageId"
- ],
- "createSql": "CREATE INDEX `index_reactions_messageId` ON `${TABLE_NAME}` (`messageId`)"
- }
- ],
- "foreignKeys": [
- {
- "table": "messages",
- "onDelete": "CASCADE",
- "onUpdate": "NO ACTION",
- "columns": [
- "messageId"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "messages_sync",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`roomId` TEXT NOT NULL, `timestamp` INTEGER NOT NULL, PRIMARY KEY(`roomId`))",
- "fields": [
- {
- "fieldPath": "roomId",
- "columnName": "roomId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "timestamp",
- "columnName": "timestamp",
- "affinity": "INTEGER",
- "notNull": true
- }
- ],
- "primaryKey": {
- "columnNames": [
- "roomId"
- ],
- "autoGenerate": false
- },
- "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, \"4d5ac4ae382ddb3aa3850842253e89d2\")"
- ]
- }
-}
\ No newline at end of file
diff --git a/app/schemas/chat.rocket.android.db.RCDatabase/8.json b/app/schemas/chat.rocket.android.db.RCDatabase/8.json
deleted file mode 100644
index 9874e166dc..0000000000
--- a/app/schemas/chat.rocket.android.db.RCDatabase/8.json
+++ /dev/null
@@ -1,1075 +0,0 @@
-{
- "formatVersion": 1,
- "database": {
- "version": 8,
- "identityHash": "48d41bd13698c29cc5e0810934187c0e",
- "entities": [
- {
- "tableName": "users",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `username` TEXT, `name` TEXT, `status` TEXT NOT NULL, `utcOffset` REAL, PRIMARY KEY(`id`))",
- "fields": [
- {
- "fieldPath": "id",
- "columnName": "id",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "username",
- "columnName": "username",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "name",
- "columnName": "name",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "status",
- "columnName": "status",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "utcOffset",
- "columnName": "utcOffset",
- "affinity": "REAL",
- "notNull": false
- }
- ],
- "primaryKey": {
- "columnNames": [
- "id"
- ],
- "autoGenerate": false
- },
- "indices": [
- {
- "name": "index_users_username",
- "unique": false,
- "columnNames": [
- "username"
- ],
- "createSql": "CREATE INDEX `index_users_username` ON `${TABLE_NAME}` (`username`)"
- }
- ],
- "foreignKeys": []
- },
- {
- "tableName": "chatrooms",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `subscriptionId` TEXT NOT NULL, `type` TEXT NOT NULL, `name` TEXT NOT NULL, `fullname` TEXT, `userId` TEXT, `ownerId` TEXT, `readonly` INTEGER, `isDefault` INTEGER, `favorite` INTEGER, `open` INTEGER NOT NULL, `alert` INTEGER NOT NULL, `unread` INTEGER NOT NULL, `userMentions` INTEGER, `groupMentions` INTEGER, `updatedAt` INTEGER, `timestamp` INTEGER, `lastSeen` INTEGER, `lastMessageText` TEXT, `lastMessageUserId` TEXT, `lastMessageTimestamp` INTEGER, `broadcast` INTEGER, PRIMARY KEY(`id`), FOREIGN KEY(`ownerId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`userId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`lastMessageUserId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
- "fields": [
- {
- "fieldPath": "id",
- "columnName": "id",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "subscriptionId",
- "columnName": "subscriptionId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "type",
- "columnName": "type",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "name",
- "columnName": "name",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "fullname",
- "columnName": "fullname",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "userId",
- "columnName": "userId",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "ownerId",
- "columnName": "ownerId",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "readonly",
- "columnName": "readonly",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "isDefault",
- "columnName": "isDefault",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "favorite",
- "columnName": "favorite",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "open",
- "columnName": "open",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "alert",
- "columnName": "alert",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "unread",
- "columnName": "unread",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "userMentions",
- "columnName": "userMentions",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "groupMentions",
- "columnName": "groupMentions",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "updatedAt",
- "columnName": "updatedAt",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "timestamp",
- "columnName": "timestamp",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "lastSeen",
- "columnName": "lastSeen",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "lastMessageText",
- "columnName": "lastMessageText",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "lastMessageUserId",
- "columnName": "lastMessageUserId",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "lastMessageTimestamp",
- "columnName": "lastMessageTimestamp",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "broadcast",
- "columnName": "broadcast",
- "affinity": "INTEGER",
- "notNull": false
- }
- ],
- "primaryKey": {
- "columnNames": [
- "id"
- ],
- "autoGenerate": false
- },
- "indices": [
- {
- "name": "index_chatrooms_userId",
- "unique": false,
- "columnNames": [
- "userId"
- ],
- "createSql": "CREATE INDEX `index_chatrooms_userId` ON `${TABLE_NAME}` (`userId`)"
- },
- {
- "name": "index_chatrooms_ownerId",
- "unique": false,
- "columnNames": [
- "ownerId"
- ],
- "createSql": "CREATE INDEX `index_chatrooms_ownerId` ON `${TABLE_NAME}` (`ownerId`)"
- },
- {
- "name": "index_chatrooms_subscriptionId",
- "unique": true,
- "columnNames": [
- "subscriptionId"
- ],
- "createSql": "CREATE UNIQUE INDEX `index_chatrooms_subscriptionId` ON `${TABLE_NAME}` (`subscriptionId`)"
- },
- {
- "name": "index_chatrooms_updatedAt",
- "unique": false,
- "columnNames": [
- "updatedAt"
- ],
- "createSql": "CREATE INDEX `index_chatrooms_updatedAt` ON `${TABLE_NAME}` (`updatedAt`)"
- },
- {
- "name": "index_chatrooms_lastMessageUserId",
- "unique": false,
- "columnNames": [
- "lastMessageUserId"
- ],
- "createSql": "CREATE INDEX `index_chatrooms_lastMessageUserId` ON `${TABLE_NAME}` (`lastMessageUserId`)"
- }
- ],
- "foreignKeys": [
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "ownerId"
- ],
- "referencedColumns": [
- "id"
- ]
- },
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "userId"
- ],
- "referencedColumns": [
- "id"
- ]
- },
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "lastMessageUserId"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "messages",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `roomId` TEXT NOT NULL, `message` TEXT NOT NULL, `timestamp` INTEGER NOT NULL, `senderId` TEXT, `updatedAt` INTEGER, `editedAt` INTEGER, `editedBy` TEXT, `senderAlias` TEXT, `avatar` TEXT, `type` TEXT, `groupable` INTEGER NOT NULL, `parseUrls` INTEGER NOT NULL, `pinned` INTEGER NOT NULL, `role` TEXT, `synced` INTEGER NOT NULL, `unread` INTEGER, PRIMARY KEY(`id`), FOREIGN KEY(`senderId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`editedBy`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
- "fields": [
- {
- "fieldPath": "id",
- "columnName": "id",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "roomId",
- "columnName": "roomId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "message",
- "columnName": "message",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "timestamp",
- "columnName": "timestamp",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "senderId",
- "columnName": "senderId",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "updatedAt",
- "columnName": "updatedAt",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "editedAt",
- "columnName": "editedAt",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "editedBy",
- "columnName": "editedBy",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "senderAlias",
- "columnName": "senderAlias",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "avatar",
- "columnName": "avatar",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "type",
- "columnName": "type",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "groupable",
- "columnName": "groupable",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "parseUrls",
- "columnName": "parseUrls",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "pinned",
- "columnName": "pinned",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "role",
- "columnName": "role",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "synced",
- "columnName": "synced",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "unread",
- "columnName": "unread",
- "affinity": "INTEGER",
- "notNull": false
- }
- ],
- "primaryKey": {
- "columnNames": [
- "id"
- ],
- "autoGenerate": false
- },
- "indices": [],
- "foreignKeys": [
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "senderId"
- ],
- "referencedColumns": [
- "id"
- ]
- },
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "editedBy"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "message_favorites",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`messageId` TEXT NOT NULL, `userId` TEXT NOT NULL, PRIMARY KEY(`messageId`, `userId`), FOREIGN KEY(`messageId`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`userId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
- "fields": [
- {
- "fieldPath": "messageId",
- "columnName": "messageId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "userId",
- "columnName": "userId",
- "affinity": "TEXT",
- "notNull": true
- }
- ],
- "primaryKey": {
- "columnNames": [
- "messageId",
- "userId"
- ],
- "autoGenerate": false
- },
- "indices": [],
- "foreignKeys": [
- {
- "table": "messages",
- "onDelete": "CASCADE",
- "onUpdate": "NO ACTION",
- "columns": [
- "messageId"
- ],
- "referencedColumns": [
- "id"
- ]
- },
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "userId"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "message_mentions",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`messageId` TEXT NOT NULL, `userId` TEXT NOT NULL, PRIMARY KEY(`messageId`, `userId`), FOREIGN KEY(`messageId`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`userId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
- "fields": [
- {
- "fieldPath": "messageId",
- "columnName": "messageId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "userId",
- "columnName": "userId",
- "affinity": "TEXT",
- "notNull": true
- }
- ],
- "primaryKey": {
- "columnNames": [
- "messageId",
- "userId"
- ],
- "autoGenerate": false
- },
- "indices": [],
- "foreignKeys": [
- {
- "table": "messages",
- "onDelete": "CASCADE",
- "onUpdate": "NO ACTION",
- "columns": [
- "messageId"
- ],
- "referencedColumns": [
- "id"
- ]
- },
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "userId"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "message_channels",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`messageId` TEXT NOT NULL, `roomId` TEXT NOT NULL, `roomName` TEXT, PRIMARY KEY(`messageId`, `roomId`), FOREIGN KEY(`messageId`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
- "fields": [
- {
- "fieldPath": "messageId",
- "columnName": "messageId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "roomId",
- "columnName": "roomId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "roomName",
- "columnName": "roomName",
- "affinity": "TEXT",
- "notNull": false
- }
- ],
- "primaryKey": {
- "columnNames": [
- "messageId",
- "roomId"
- ],
- "autoGenerate": false
- },
- "indices": [],
- "foreignKeys": [
- {
- "table": "messages",
- "onDelete": "CASCADE",
- "onUpdate": "NO ACTION",
- "columns": [
- "messageId"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "attachments",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` TEXT NOT NULL, `message_id` TEXT NOT NULL, `title` TEXT, `type` TEXT, `description` TEXT, `text` TEXT, `author_name` TEXT, `author_icon` TEXT, `author_link` TEXT, `thumb_url` TEXT, `color` TEXT, `fallback` TEXT, `title_link` TEXT, `title_link_download` INTEGER NOT NULL, `image_url` TEXT, `image_type` TEXT, `image_size` INTEGER, `video_url` TEXT, `video_type` TEXT, `video_size` INTEGER, `audio_url` TEXT, `audio_type` TEXT, `audio_size` INTEGER, `message_link` TEXT, `timestamp` INTEGER, `has_actions` INTEGER NOT NULL, `button_alignment` TEXT, PRIMARY KEY(`_id`), FOREIGN KEY(`message_id`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
- "fields": [
- {
- "fieldPath": "_id",
- "columnName": "_id",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "messageId",
- "columnName": "message_id",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "title",
- "columnName": "title",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "type",
- "columnName": "type",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "description",
- "columnName": "description",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "text",
- "columnName": "text",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "authorName",
- "columnName": "author_name",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "authorIcon",
- "columnName": "author_icon",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "authorLink",
- "columnName": "author_link",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "thumbUrl",
- "columnName": "thumb_url",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "color",
- "columnName": "color",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "fallback",
- "columnName": "fallback",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "titleLink",
- "columnName": "title_link",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "titleLinkDownload",
- "columnName": "title_link_download",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "imageUrl",
- "columnName": "image_url",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "imageType",
- "columnName": "image_type",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "imageSize",
- "columnName": "image_size",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "videoUrl",
- "columnName": "video_url",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "videoType",
- "columnName": "video_type",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "videoSize",
- "columnName": "video_size",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "audioUrl",
- "columnName": "audio_url",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "audioType",
- "columnName": "audio_type",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "audioSize",
- "columnName": "audio_size",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "messageLink",
- "columnName": "message_link",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "timestamp",
- "columnName": "timestamp",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "hasActions",
- "columnName": "has_actions",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "buttonAlignment",
- "columnName": "button_alignment",
- "affinity": "TEXT",
- "notNull": false
- }
- ],
- "primaryKey": {
- "columnNames": [
- "_id"
- ],
- "autoGenerate": false
- },
- "indices": [],
- "foreignKeys": [
- {
- "table": "messages",
- "onDelete": "CASCADE",
- "onUpdate": "NO ACTION",
- "columns": [
- "message_id"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "attachment_fields",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `attachmentId` TEXT NOT NULL, `title` TEXT NOT NULL, `value` TEXT NOT NULL, FOREIGN KEY(`attachmentId`) REFERENCES `attachments`(`_id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
- "fields": [
- {
- "fieldPath": "id",
- "columnName": "id",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "attachmentId",
- "columnName": "attachmentId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "title",
- "columnName": "title",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "value",
- "columnName": "value",
- "affinity": "TEXT",
- "notNull": true
- }
- ],
- "primaryKey": {
- "columnNames": [
- "id"
- ],
- "autoGenerate": true
- },
- "indices": [
- {
- "name": "index_attachment_fields_attachmentId",
- "unique": false,
- "columnNames": [
- "attachmentId"
- ],
- "createSql": "CREATE INDEX `index_attachment_fields_attachmentId` ON `${TABLE_NAME}` (`attachmentId`)"
- }
- ],
- "foreignKeys": [
- {
- "table": "attachments",
- "onDelete": "CASCADE",
- "onUpdate": "NO ACTION",
- "columns": [
- "attachmentId"
- ],
- "referencedColumns": [
- "_id"
- ]
- }
- ]
- },
- {
- "tableName": "attachment_action",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `attachmentId` TEXT NOT NULL, `type` TEXT NOT NULL, `text` TEXT, `url` TEXT, `isWebView` INTEGER, `webViewHeightRatio` TEXT, `imageUrl` TEXT, `message` TEXT, `isMessageInChatWindow` INTEGER, FOREIGN KEY(`attachmentId`) REFERENCES `attachments`(`_id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
- "fields": [
- {
- "fieldPath": "id",
- "columnName": "id",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "attachmentId",
- "columnName": "attachmentId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "type",
- "columnName": "type",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "text",
- "columnName": "text",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "url",
- "columnName": "url",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "isWebView",
- "columnName": "isWebView",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "webViewHeightRatio",
- "columnName": "webViewHeightRatio",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "imageUrl",
- "columnName": "imageUrl",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "message",
- "columnName": "message",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "isMessageInChatWindow",
- "columnName": "isMessageInChatWindow",
- "affinity": "INTEGER",
- "notNull": false
- }
- ],
- "primaryKey": {
- "columnNames": [
- "id"
- ],
- "autoGenerate": true
- },
- "indices": [
- {
- "name": "index_attachment_action_attachmentId",
- "unique": false,
- "columnNames": [
- "attachmentId"
- ],
- "createSql": "CREATE INDEX `index_attachment_action_attachmentId` ON `${TABLE_NAME}` (`attachmentId`)"
- }
- ],
- "foreignKeys": [
- {
- "table": "attachments",
- "onDelete": "CASCADE",
- "onUpdate": "NO ACTION",
- "columns": [
- "attachmentId"
- ],
- "referencedColumns": [
- "_id"
- ]
- }
- ]
- },
- {
- "tableName": "urls",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`urlId` INTEGER PRIMARY KEY AUTOINCREMENT, `messageId` TEXT NOT NULL, `url` TEXT NOT NULL, `hostname` TEXT, `title` TEXT, `description` TEXT, `imageUrl` TEXT, FOREIGN KEY(`messageId`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
- "fields": [
- {
- "fieldPath": "urlId",
- "columnName": "urlId",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "messageId",
- "columnName": "messageId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "url",
- "columnName": "url",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "hostname",
- "columnName": "hostname",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "title",
- "columnName": "title",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "description",
- "columnName": "description",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "imageUrl",
- "columnName": "imageUrl",
- "affinity": "TEXT",
- "notNull": false
- }
- ],
- "primaryKey": {
- "columnNames": [
- "urlId"
- ],
- "autoGenerate": true
- },
- "indices": [
- {
- "name": "index_urls_messageId",
- "unique": false,
- "columnNames": [
- "messageId"
- ],
- "createSql": "CREATE INDEX `index_urls_messageId` ON `${TABLE_NAME}` (`messageId`)"
- }
- ],
- "foreignKeys": [
- {
- "table": "messages",
- "onDelete": "CASCADE",
- "onUpdate": "NO ACTION",
- "columns": [
- "messageId"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "reactions",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`reaction` TEXT NOT NULL, `messageId` TEXT NOT NULL, `count` INTEGER NOT NULL, `usernames` TEXT NOT NULL, PRIMARY KEY(`reaction`), FOREIGN KEY(`messageId`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
- "fields": [
- {
- "fieldPath": "reaction",
- "columnName": "reaction",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "messageId",
- "columnName": "messageId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "count",
- "columnName": "count",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "usernames",
- "columnName": "usernames",
- "affinity": "TEXT",
- "notNull": true
- }
- ],
- "primaryKey": {
- "columnNames": [
- "reaction"
- ],
- "autoGenerate": false
- },
- "indices": [
- {
- "name": "index_reactions_messageId",
- "unique": false,
- "columnNames": [
- "messageId"
- ],
- "createSql": "CREATE INDEX `index_reactions_messageId` ON `${TABLE_NAME}` (`messageId`)"
- }
- ],
- "foreignKeys": [
- {
- "table": "messages",
- "onDelete": "CASCADE",
- "onUpdate": "NO ACTION",
- "columns": [
- "messageId"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "messages_sync",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`roomId` TEXT NOT NULL, `timestamp` INTEGER NOT NULL, PRIMARY KEY(`roomId`))",
- "fields": [
- {
- "fieldPath": "roomId",
- "columnName": "roomId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "timestamp",
- "columnName": "timestamp",
- "affinity": "INTEGER",
- "notNull": true
- }
- ],
- "primaryKey": {
- "columnNames": [
- "roomId"
- ],
- "autoGenerate": false
- },
- "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, \"48d41bd13698c29cc5e0810934187c0e\")"
- ]
- }
-}
\ No newline at end of file
diff --git a/app/schemas/chat.rocket.android.db.RCDatabase/9.json b/app/schemas/chat.rocket.android.db.RCDatabase/9.json
deleted file mode 100644
index 9724e557be..0000000000
--- a/app/schemas/chat.rocket.android.db.RCDatabase/9.json
+++ /dev/null
@@ -1,1081 +0,0 @@
-{
- "formatVersion": 1,
- "database": {
- "version": 9,
- "identityHash": "db46c12dbb8747200288f48d5dc5558b",
- "entities": [
- {
- "tableName": "users",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `username` TEXT, `name` TEXT, `status` TEXT NOT NULL, `utcOffset` REAL, PRIMARY KEY(`id`))",
- "fields": [
- {
- "fieldPath": "id",
- "columnName": "id",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "username",
- "columnName": "username",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "name",
- "columnName": "name",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "status",
- "columnName": "status",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "utcOffset",
- "columnName": "utcOffset",
- "affinity": "REAL",
- "notNull": false
- }
- ],
- "primaryKey": {
- "columnNames": [
- "id"
- ],
- "autoGenerate": false
- },
- "indices": [
- {
- "name": "index_users_username",
- "unique": false,
- "columnNames": [
- "username"
- ],
- "createSql": "CREATE INDEX `index_users_username` ON `${TABLE_NAME}` (`username`)"
- }
- ],
- "foreignKeys": []
- },
- {
- "tableName": "chatrooms",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `subscriptionId` TEXT NOT NULL, `type` TEXT NOT NULL, `name` TEXT NOT NULL, `fullname` TEXT, `userId` TEXT, `ownerId` TEXT, `readonly` INTEGER, `isDefault` INTEGER, `favorite` INTEGER, `open` INTEGER NOT NULL, `alert` INTEGER NOT NULL, `unread` INTEGER NOT NULL, `userMentions` INTEGER, `groupMentions` INTEGER, `updatedAt` INTEGER, `timestamp` INTEGER, `lastSeen` INTEGER, `lastMessageText` TEXT, `lastMessageUserId` TEXT, `lastMessageTimestamp` INTEGER, `broadcast` INTEGER, PRIMARY KEY(`id`), FOREIGN KEY(`ownerId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`userId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`lastMessageUserId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
- "fields": [
- {
- "fieldPath": "id",
- "columnName": "id",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "subscriptionId",
- "columnName": "subscriptionId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "type",
- "columnName": "type",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "name",
- "columnName": "name",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "fullname",
- "columnName": "fullname",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "userId",
- "columnName": "userId",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "ownerId",
- "columnName": "ownerId",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "readonly",
- "columnName": "readonly",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "isDefault",
- "columnName": "isDefault",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "favorite",
- "columnName": "favorite",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "open",
- "columnName": "open",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "alert",
- "columnName": "alert",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "unread",
- "columnName": "unread",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "userMentions",
- "columnName": "userMentions",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "groupMentions",
- "columnName": "groupMentions",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "updatedAt",
- "columnName": "updatedAt",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "timestamp",
- "columnName": "timestamp",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "lastSeen",
- "columnName": "lastSeen",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "lastMessageText",
- "columnName": "lastMessageText",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "lastMessageUserId",
- "columnName": "lastMessageUserId",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "lastMessageTimestamp",
- "columnName": "lastMessageTimestamp",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "broadcast",
- "columnName": "broadcast",
- "affinity": "INTEGER",
- "notNull": false
- }
- ],
- "primaryKey": {
- "columnNames": [
- "id"
- ],
- "autoGenerate": false
- },
- "indices": [
- {
- "name": "index_chatrooms_userId",
- "unique": false,
- "columnNames": [
- "userId"
- ],
- "createSql": "CREATE INDEX `index_chatrooms_userId` ON `${TABLE_NAME}` (`userId`)"
- },
- {
- "name": "index_chatrooms_ownerId",
- "unique": false,
- "columnNames": [
- "ownerId"
- ],
- "createSql": "CREATE INDEX `index_chatrooms_ownerId` ON `${TABLE_NAME}` (`ownerId`)"
- },
- {
- "name": "index_chatrooms_subscriptionId",
- "unique": true,
- "columnNames": [
- "subscriptionId"
- ],
- "createSql": "CREATE UNIQUE INDEX `index_chatrooms_subscriptionId` ON `${TABLE_NAME}` (`subscriptionId`)"
- },
- {
- "name": "index_chatrooms_updatedAt",
- "unique": false,
- "columnNames": [
- "updatedAt"
- ],
- "createSql": "CREATE INDEX `index_chatrooms_updatedAt` ON `${TABLE_NAME}` (`updatedAt`)"
- },
- {
- "name": "index_chatrooms_lastMessageUserId",
- "unique": false,
- "columnNames": [
- "lastMessageUserId"
- ],
- "createSql": "CREATE INDEX `index_chatrooms_lastMessageUserId` ON `${TABLE_NAME}` (`lastMessageUserId`)"
- }
- ],
- "foreignKeys": [
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "ownerId"
- ],
- "referencedColumns": [
- "id"
- ]
- },
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "userId"
- ],
- "referencedColumns": [
- "id"
- ]
- },
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "lastMessageUserId"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "messages",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `roomId` TEXT NOT NULL, `message` TEXT NOT NULL, `timestamp` INTEGER NOT NULL, `senderId` TEXT, `updatedAt` INTEGER, `editedAt` INTEGER, `editedBy` TEXT, `senderAlias` TEXT, `avatar` TEXT, `type` TEXT, `groupable` INTEGER NOT NULL, `parseUrls` INTEGER NOT NULL, `pinned` INTEGER NOT NULL, `role` TEXT, `synced` INTEGER NOT NULL, `unread` INTEGER, PRIMARY KEY(`id`), FOREIGN KEY(`senderId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`editedBy`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
- "fields": [
- {
- "fieldPath": "id",
- "columnName": "id",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "roomId",
- "columnName": "roomId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "message",
- "columnName": "message",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "timestamp",
- "columnName": "timestamp",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "senderId",
- "columnName": "senderId",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "updatedAt",
- "columnName": "updatedAt",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "editedAt",
- "columnName": "editedAt",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "editedBy",
- "columnName": "editedBy",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "senderAlias",
- "columnName": "senderAlias",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "avatar",
- "columnName": "avatar",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "type",
- "columnName": "type",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "groupable",
- "columnName": "groupable",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "parseUrls",
- "columnName": "parseUrls",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "pinned",
- "columnName": "pinned",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "role",
- "columnName": "role",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "synced",
- "columnName": "synced",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "unread",
- "columnName": "unread",
- "affinity": "INTEGER",
- "notNull": false
- }
- ],
- "primaryKey": {
- "columnNames": [
- "id"
- ],
- "autoGenerate": false
- },
- "indices": [],
- "foreignKeys": [
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "senderId"
- ],
- "referencedColumns": [
- "id"
- ]
- },
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "editedBy"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "message_favorites",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`messageId` TEXT NOT NULL, `userId` TEXT NOT NULL, PRIMARY KEY(`messageId`, `userId`), FOREIGN KEY(`messageId`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`userId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
- "fields": [
- {
- "fieldPath": "messageId",
- "columnName": "messageId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "userId",
- "columnName": "userId",
- "affinity": "TEXT",
- "notNull": true
- }
- ],
- "primaryKey": {
- "columnNames": [
- "messageId",
- "userId"
- ],
- "autoGenerate": false
- },
- "indices": [],
- "foreignKeys": [
- {
- "table": "messages",
- "onDelete": "CASCADE",
- "onUpdate": "NO ACTION",
- "columns": [
- "messageId"
- ],
- "referencedColumns": [
- "id"
- ]
- },
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "userId"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "message_mentions",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`messageId` TEXT NOT NULL, `userId` TEXT NOT NULL, PRIMARY KEY(`messageId`, `userId`), FOREIGN KEY(`messageId`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`userId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
- "fields": [
- {
- "fieldPath": "messageId",
- "columnName": "messageId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "userId",
- "columnName": "userId",
- "affinity": "TEXT",
- "notNull": true
- }
- ],
- "primaryKey": {
- "columnNames": [
- "messageId",
- "userId"
- ],
- "autoGenerate": false
- },
- "indices": [],
- "foreignKeys": [
- {
- "table": "messages",
- "onDelete": "CASCADE",
- "onUpdate": "NO ACTION",
- "columns": [
- "messageId"
- ],
- "referencedColumns": [
- "id"
- ]
- },
- {
- "table": "users",
- "onDelete": "NO ACTION",
- "onUpdate": "NO ACTION",
- "columns": [
- "userId"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "message_channels",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`messageId` TEXT NOT NULL, `roomId` TEXT NOT NULL, `roomName` TEXT, PRIMARY KEY(`messageId`, `roomId`), FOREIGN KEY(`messageId`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
- "fields": [
- {
- "fieldPath": "messageId",
- "columnName": "messageId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "roomId",
- "columnName": "roomId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "roomName",
- "columnName": "roomName",
- "affinity": "TEXT",
- "notNull": false
- }
- ],
- "primaryKey": {
- "columnNames": [
- "messageId",
- "roomId"
- ],
- "autoGenerate": false
- },
- "indices": [],
- "foreignKeys": [
- {
- "table": "messages",
- "onDelete": "CASCADE",
- "onUpdate": "NO ACTION",
- "columns": [
- "messageId"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "attachments",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` TEXT NOT NULL, `message_id` TEXT NOT NULL, `title` TEXT, `type` TEXT, `description` TEXT, `text` TEXT, `author_name` TEXT, `author_icon` TEXT, `author_link` TEXT, `thumb_url` TEXT, `color` TEXT, `fallback` TEXT, `title_link` TEXT, `title_link_download` INTEGER NOT NULL, `image_url` TEXT, `image_type` TEXT, `image_size` INTEGER, `video_url` TEXT, `video_type` TEXT, `video_size` INTEGER, `audio_url` TEXT, `audio_type` TEXT, `audio_size` INTEGER, `message_link` TEXT, `timestamp` INTEGER, `has_actions` INTEGER NOT NULL, `has_fields` INTEGER NOT NULL, `button_alignment` TEXT, PRIMARY KEY(`_id`), FOREIGN KEY(`message_id`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
- "fields": [
- {
- "fieldPath": "_id",
- "columnName": "_id",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "messageId",
- "columnName": "message_id",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "title",
- "columnName": "title",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "type",
- "columnName": "type",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "description",
- "columnName": "description",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "text",
- "columnName": "text",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "authorName",
- "columnName": "author_name",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "authorIcon",
- "columnName": "author_icon",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "authorLink",
- "columnName": "author_link",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "thumbUrl",
- "columnName": "thumb_url",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "color",
- "columnName": "color",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "fallback",
- "columnName": "fallback",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "titleLink",
- "columnName": "title_link",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "titleLinkDownload",
- "columnName": "title_link_download",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "imageUrl",
- "columnName": "image_url",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "imageType",
- "columnName": "image_type",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "imageSize",
- "columnName": "image_size",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "videoUrl",
- "columnName": "video_url",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "videoType",
- "columnName": "video_type",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "videoSize",
- "columnName": "video_size",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "audioUrl",
- "columnName": "audio_url",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "audioType",
- "columnName": "audio_type",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "audioSize",
- "columnName": "audio_size",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "messageLink",
- "columnName": "message_link",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "timestamp",
- "columnName": "timestamp",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "hasActions",
- "columnName": "has_actions",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "hasFields",
- "columnName": "has_fields",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "buttonAlignment",
- "columnName": "button_alignment",
- "affinity": "TEXT",
- "notNull": false
- }
- ],
- "primaryKey": {
- "columnNames": [
- "_id"
- ],
- "autoGenerate": false
- },
- "indices": [],
- "foreignKeys": [
- {
- "table": "messages",
- "onDelete": "CASCADE",
- "onUpdate": "NO ACTION",
- "columns": [
- "message_id"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "attachment_fields",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `attachmentId` TEXT NOT NULL, `title` TEXT NOT NULL, `value` TEXT NOT NULL, FOREIGN KEY(`attachmentId`) REFERENCES `attachments`(`_id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
- "fields": [
- {
- "fieldPath": "id",
- "columnName": "id",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "attachmentId",
- "columnName": "attachmentId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "title",
- "columnName": "title",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "value",
- "columnName": "value",
- "affinity": "TEXT",
- "notNull": true
- }
- ],
- "primaryKey": {
- "columnNames": [
- "id"
- ],
- "autoGenerate": true
- },
- "indices": [
- {
- "name": "index_attachment_fields_attachmentId",
- "unique": false,
- "columnNames": [
- "attachmentId"
- ],
- "createSql": "CREATE INDEX `index_attachment_fields_attachmentId` ON `${TABLE_NAME}` (`attachmentId`)"
- }
- ],
- "foreignKeys": [
- {
- "table": "attachments",
- "onDelete": "CASCADE",
- "onUpdate": "NO ACTION",
- "columns": [
- "attachmentId"
- ],
- "referencedColumns": [
- "_id"
- ]
- }
- ]
- },
- {
- "tableName": "attachment_action",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `attachmentId` TEXT NOT NULL, `type` TEXT NOT NULL, `text` TEXT, `url` TEXT, `isWebView` INTEGER, `webViewHeightRatio` TEXT, `imageUrl` TEXT, `message` TEXT, `isMessageInChatWindow` INTEGER, FOREIGN KEY(`attachmentId`) REFERENCES `attachments`(`_id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
- "fields": [
- {
- "fieldPath": "id",
- "columnName": "id",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "attachmentId",
- "columnName": "attachmentId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "type",
- "columnName": "type",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "text",
- "columnName": "text",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "url",
- "columnName": "url",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "isWebView",
- "columnName": "isWebView",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "webViewHeightRatio",
- "columnName": "webViewHeightRatio",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "imageUrl",
- "columnName": "imageUrl",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "message",
- "columnName": "message",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "isMessageInChatWindow",
- "columnName": "isMessageInChatWindow",
- "affinity": "INTEGER",
- "notNull": false
- }
- ],
- "primaryKey": {
- "columnNames": [
- "id"
- ],
- "autoGenerate": true
- },
- "indices": [
- {
- "name": "index_attachment_action_attachmentId",
- "unique": false,
- "columnNames": [
- "attachmentId"
- ],
- "createSql": "CREATE INDEX `index_attachment_action_attachmentId` ON `${TABLE_NAME}` (`attachmentId`)"
- }
- ],
- "foreignKeys": [
- {
- "table": "attachments",
- "onDelete": "CASCADE",
- "onUpdate": "NO ACTION",
- "columns": [
- "attachmentId"
- ],
- "referencedColumns": [
- "_id"
- ]
- }
- ]
- },
- {
- "tableName": "urls",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`urlId` INTEGER PRIMARY KEY AUTOINCREMENT, `messageId` TEXT NOT NULL, `url` TEXT NOT NULL, `hostname` TEXT, `title` TEXT, `description` TEXT, `imageUrl` TEXT, FOREIGN KEY(`messageId`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
- "fields": [
- {
- "fieldPath": "urlId",
- "columnName": "urlId",
- "affinity": "INTEGER",
- "notNull": false
- },
- {
- "fieldPath": "messageId",
- "columnName": "messageId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "url",
- "columnName": "url",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "hostname",
- "columnName": "hostname",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "title",
- "columnName": "title",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "description",
- "columnName": "description",
- "affinity": "TEXT",
- "notNull": false
- },
- {
- "fieldPath": "imageUrl",
- "columnName": "imageUrl",
- "affinity": "TEXT",
- "notNull": false
- }
- ],
- "primaryKey": {
- "columnNames": [
- "urlId"
- ],
- "autoGenerate": true
- },
- "indices": [
- {
- "name": "index_urls_messageId",
- "unique": false,
- "columnNames": [
- "messageId"
- ],
- "createSql": "CREATE INDEX `index_urls_messageId` ON `${TABLE_NAME}` (`messageId`)"
- }
- ],
- "foreignKeys": [
- {
- "table": "messages",
- "onDelete": "CASCADE",
- "onUpdate": "NO ACTION",
- "columns": [
- "messageId"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "reactions",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`reaction` TEXT NOT NULL, `messageId` TEXT NOT NULL, `count` INTEGER NOT NULL, `usernames` TEXT NOT NULL, PRIMARY KEY(`reaction`), FOREIGN KEY(`messageId`) REFERENCES `messages`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
- "fields": [
- {
- "fieldPath": "reaction",
- "columnName": "reaction",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "messageId",
- "columnName": "messageId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "count",
- "columnName": "count",
- "affinity": "INTEGER",
- "notNull": true
- },
- {
- "fieldPath": "usernames",
- "columnName": "usernames",
- "affinity": "TEXT",
- "notNull": true
- }
- ],
- "primaryKey": {
- "columnNames": [
- "reaction"
- ],
- "autoGenerate": false
- },
- "indices": [
- {
- "name": "index_reactions_messageId",
- "unique": false,
- "columnNames": [
- "messageId"
- ],
- "createSql": "CREATE INDEX `index_reactions_messageId` ON `${TABLE_NAME}` (`messageId`)"
- }
- ],
- "foreignKeys": [
- {
- "table": "messages",
- "onDelete": "CASCADE",
- "onUpdate": "NO ACTION",
- "columns": [
- "messageId"
- ],
- "referencedColumns": [
- "id"
- ]
- }
- ]
- },
- {
- "tableName": "messages_sync",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`roomId` TEXT NOT NULL, `timestamp` INTEGER NOT NULL, PRIMARY KEY(`roomId`))",
- "fields": [
- {
- "fieldPath": "roomId",
- "columnName": "roomId",
- "affinity": "TEXT",
- "notNull": true
- },
- {
- "fieldPath": "timestamp",
- "columnName": "timestamp",
- "affinity": "INTEGER",
- "notNull": true
- }
- ],
- "primaryKey": {
- "columnNames": [
- "roomId"
- ],
- "autoGenerate": false
- },
- "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, \"db46c12dbb8747200288f48d5dc5558b\")"
- ]
- }
-}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 3a342f59ae..9bb4177bb3 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -90,7 +90,7 @@
android:theme="@style/AppTheme"
android:windowSoftInputMode="adjustResize|stateAlwaysHidden" />
-
+
diff --git a/app/src/main/java/chat/rocket/android/about/di/AboutFragmentProvider.kt b/app/src/main/java/chat/rocket/android/about/di/AboutFragmentProvider.kt
deleted file mode 100644
index 9ad3f3eb50..0000000000
--- a/app/src/main/java/chat/rocket/android/about/di/AboutFragmentProvider.kt
+++ /dev/null
@@ -1,12 +0,0 @@
-package chat.rocket.android.about.di
-
-import chat.rocket.android.about.ui.AboutFragment
-import dagger.Module
-import dagger.android.ContributesAndroidInjector
-
-@Module
-abstract class AboutFragmentProvider {
-
- @ContributesAndroidInjector()
- abstract fun provideAboutFragment(): AboutFragment
-}
diff --git a/app/src/main/java/chat/rocket/android/about/ui/AboutFragment.kt b/app/src/main/java/chat/rocket/android/about/ui/AboutFragment.kt
deleted file mode 100644
index 08047eb1bc..0000000000
--- a/app/src/main/java/chat/rocket/android/about/ui/AboutFragment.kt
+++ /dev/null
@@ -1,66 +0,0 @@
-package chat.rocket.android.about.ui
-
-import android.os.Bundle
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import androidx.fragment.app.Fragment
-import chat.rocket.android.BuildConfig
-import chat.rocket.android.R
-import chat.rocket.android.analytics.AnalyticsManager
-import chat.rocket.android.analytics.event.ScreenViewEvent
-import chat.rocket.android.main.ui.MainActivity
-import dagger.android.support.AndroidSupportInjection
-import kotlinx.android.synthetic.main.app_bar.*
-import kotlinx.android.synthetic.main.fragment_about.*
-import javax.inject.Inject
-
-internal const val TAG_ABOUT_FRAGMENT = "AboutFragment"
-
-class AboutFragment : Fragment() {
- @Inject
- lateinit var analyticsManager: AnalyticsManager
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- AndroidSupportInjection.inject(this)
- }
-
- override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View? = inflater.inflate(R.layout.fragment_about, container, false)
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
- setupViews()
-
- analyticsManager.logScreenView(ScreenViewEvent.About)
- }
-
- override fun onResume() {
- super.onResume()
- setupToolbar()
- }
-
- private fun setupViews() {
- text_version_name.text = BuildConfig.VERSION_NAME
- text_build_number.text = getString(
- R.string.msg_build, BuildConfig.VERSION_CODE,
- BuildConfig.GIT_SHA, BuildConfig.FLAVOR
- )
- }
-
- private fun setupToolbar() {
- with((activity as MainActivity).toolbar) {
- title = getString(R.string.title_about)
- setNavigationIcon(R.drawable.ic_arrow_back_white_24dp)
- setNavigationOnClickListener { activity?.onBackPressed() }
- }
- }
-
- companion object {
- fun newInstance() = AboutFragment()
- }
-}
diff --git a/app/src/main/java/chat/rocket/android/analytics/Analytics.kt b/app/src/main/java/chat/rocket/android/analytics/Analytics.kt
index d1adf4ce95..90750184cb 100644
--- a/app/src/main/java/chat/rocket/android/analytics/Analytics.kt
+++ b/app/src/main/java/chat/rocket/android/analytics/Analytics.kt
@@ -10,7 +10,7 @@ interface Analytics {
* Logs the login event.
*
* @param event The [AuthenticationEvent] used to log in.
- * @param loginSucceeded True if successful logged in, false otherwise.
+ * @param loginSucceeded True if logged in successfully, false otherwise.
*/
fun logLogin(event: AuthenticationEvent, loginSucceeded: Boolean) {}
@@ -18,7 +18,7 @@ interface Analytics {
* Logs the sign up event.
*
* @param event The [AuthenticationEvent] used to sign up.
- * @param signUpSucceeded True if successful signed up, false otherwise.
+ * @param signUpSucceeded True if signed up successfully, false otherwise.
*/
fun logSignUp(event: AuthenticationEvent, signUpSucceeded: Boolean) {}
diff --git a/app/src/main/java/chat/rocket/android/analytics/event/ScreenViewEvent.kt b/app/src/main/java/chat/rocket/android/analytics/event/ScreenViewEvent.kt
index b96de69855..a1f6fc6f8a 100644
--- a/app/src/main/java/chat/rocket/android/analytics/event/ScreenViewEvent.kt
+++ b/app/src/main/java/chat/rocket/android/analytics/event/ScreenViewEvent.kt
@@ -27,4 +27,5 @@ sealed class ScreenViewEvent(val screenName: String) {
object Preferences : ScreenViewEvent("PreferencesFragment")
object Profile : ScreenViewEvent("ProfileFragment")
object Settings : ScreenViewEvent("SettingsFragment")
+ object Directory : ScreenViewEvent("DirectoryFragment")
}
diff --git a/app/src/main/java/chat/rocket/android/app/AppLifecycleObserver.kt b/app/src/main/java/chat/rocket/android/app/AppLifecycleObserver.kt
index 749fab04ff..c236f3a769 100644
--- a/app/src/main/java/chat/rocket/android/app/AppLifecycleObserver.kt
+++ b/app/src/main/java/chat/rocket/android/app/AppLifecycleObserver.kt
@@ -4,7 +4,7 @@ import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent
import chat.rocket.android.server.domain.GetCurrentServerInteractor
-import chat.rocket.android.server.infraestructure.ConnectionManagerFactory
+import chat.rocket.android.server.infrastructure.ConnectionManagerFactory
import chat.rocket.common.model.UserStatus
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
diff --git a/app/src/main/java/chat/rocket/android/app/DrawableHelper.kt b/app/src/main/java/chat/rocket/android/app/DrawableHelper.kt
index b808072efa..8b3220472c 100644
--- a/app/src/main/java/chat/rocket/android/app/DrawableHelper.kt
+++ b/app/src/main/java/chat/rocket/android/app/DrawableHelper.kt
@@ -1,8 +1,9 @@
import android.content.Context
import android.graphics.drawable.Drawable
+import android.view.View
+import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.DrawableCompat
-import android.widget.TextView
import chat.rocket.android.R
import chat.rocket.common.model.UserStatus
@@ -43,7 +44,7 @@ object DrawableHelper {
/**
* Tints an array of Drawable.
*
- * REMARK: you MUST always wrap the array of Drawable before tint it.
+ * REMARK: you MUST always wrap the array of Drawable before tinting it.
*
* @param drawables The array of Drawable to tint.
* @param context The context.
@@ -60,7 +61,7 @@ object DrawableHelper {
/**
* Tints a Drawable.
*
- * REMARK: you MUST always wrap the Drawable before tint it.
+ * REMARK: you MUST always wrap the Drawable before tinting it.
*
* @param drawable The Drawable to tint.
* @param context The context.
@@ -72,43 +73,74 @@ object DrawableHelper {
DrawableCompat.setTint(drawable, ContextCompat.getColor(context, resId))
/**
- * Compounds an array of Drawable (to appear to the left of the text) into an array of TextView.
+ * Compounds an array of Drawable (to appear on the start side of a text) into an array of TextView.
*
- * REMARK: the number of elements in both array of Drawable and EditText MUST be equal.
+ * REMARK: the number of elements in both arrays of Drawable and TextView MUST be equal.
*
* @param textView The array of TextView.
* @param drawables The array of Drawable.
- * @see compoundDrawable
+ * @see compoundStartDrawable
*/
fun compoundDrawables(textView: Array, drawables: Array) {
if (textView.size != drawables.size) {
return
} else {
for (i in textView.indices) {
- textView[i].setCompoundDrawablesWithIntrinsicBounds(drawables[i], null, null, null)
+ if (textView[i].resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_RTL) {
+ textView[i].setCompoundDrawablesWithIntrinsicBounds(null, null, drawables[i], null)
+ } else {
+ textView[i].setCompoundDrawablesWithIntrinsicBounds(drawables[i], null, null, null)
+ }
}
}
}
/**
- * Compounds a Drawable (to appear on the left side of a text) into a TextView.
+ * Compounds a Drawable (to appear on the start side of a text) into a TextView.
*
* @param textView The TextView.
* @param drawable The Drawable.
* @see compoundDrawables
*/
- fun compoundDrawable(textView: TextView, drawable: Drawable) =
- textView.setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null)
+ fun compoundStartDrawable(textView: TextView, drawable: Drawable) =
+ if (textView.resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_RTL) {
+ textView.setCompoundDrawablesWithIntrinsicBounds(null, null, drawable, null)
+ } else {
+ textView.setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null)
+ }
/**
- * Compounds a Drawable (to appear on the right side of a text) into a TextView.
+ * Compounds a Drawable (to appear on the end side of a text) into a TextView.
*
* @param textView The TextView.
* @param drawable The Drawable.
- * @see compoundDrawable
+ * @see compoundStartDrawable
*/
- fun compoundRightDrawable(textView: TextView, drawable: Drawable) =
- textView.setCompoundDrawablesWithIntrinsicBounds(null, null, drawable, null)
+ fun compoundEndDrawable(textView: TextView, drawable: Drawable) =
+ if (textView.resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_RTL) {
+ textView.setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null)
+ } else {
+ textView.setCompoundDrawablesWithIntrinsicBounds(null, null, drawable, null)
+ }
+
+ /**
+ * Compounds a Drawable (to appear on the start and end side of a text) into a TextView.
+ *
+ * @param textView The TextView.
+ * @param startDrawable The start Drawable.
+ * @param endDrawable The end Drawable.
+ * @see compoundStartDrawable
+ */
+ fun compoundStartAndEndDrawable(
+ textView: TextView,
+ startDrawable: Drawable,
+ endDrawable: Drawable
+ ) =
+ if (textView.resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_RTL) {
+ textView.setCompoundDrawablesWithIntrinsicBounds(endDrawable, null, startDrawable, null)
+ } else {
+ textView.setCompoundDrawablesWithIntrinsicBounds(startDrawable, null, endDrawable, null)
+ }
/**
* Returns the user status drawable.
@@ -126,4 +158,4 @@ object DrawableHelper {
else -> getDrawableFromId(R.drawable.ic_status_invisible_12dp, context)
}
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/chat/rocket/android/app/RocketChatApplication.kt b/app/src/main/java/chat/rocket/android/app/RocketChatApplication.kt
index 08279a74cd..5410d3d7f2 100644
--- a/app/src/main/java/chat/rocket/android/app/RocketChatApplication.kt
+++ b/app/src/main/java/chat/rocket/android/app/RocketChatApplication.kt
@@ -24,7 +24,7 @@ import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.domain.GetSettingsInteractor
import chat.rocket.android.server.domain.SITE_URL
import chat.rocket.android.server.domain.TokenRepository
-import chat.rocket.android.server.infraestructure.RocketChatClientFactory
+import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.util.retryIO
import chat.rocket.android.util.setupFabric
import chat.rocket.common.RocketChatException
@@ -115,7 +115,7 @@ class RocketChatApplication : Application(), HasActivityInjector, HasServiceInje
// TODO - remove this
checkCurrentServer()
- // TODO - FIXME - we need to proper inject the EmojiRepository and initialize it properly
+ // TODO - FIXME - we need to properly inject and initialize the EmojiRepository
loadEmojis()
}
@@ -176,7 +176,7 @@ class RocketChatApplication : Application(), HasActivityInjector, HasServiceInje
val currentServer = getCurrentServerInteractor.get()
currentServer?.let { server ->
GlobalScope.launch {
- val client = factory.create(server)
+ val client = factory.get(server)
EmojiRepository.setCurrentServerUrl(server)
val customEmojiList = mutableListOf()
try {
diff --git a/app/src/main/java/chat/rocket/android/authentication/infraestructure/SharedPreferencesMultiServerTokenRepository.kt b/app/src/main/java/chat/rocket/android/authentication/infrastructure/SharedPreferencesMultiServerTokenRepository.kt
similarity index 94%
rename from app/src/main/java/chat/rocket/android/authentication/infraestructure/SharedPreferencesMultiServerTokenRepository.kt
rename to app/src/main/java/chat/rocket/android/authentication/infrastructure/SharedPreferencesMultiServerTokenRepository.kt
index f4875cfdfe..23b9af7376 100644
--- a/app/src/main/java/chat/rocket/android/authentication/infraestructure/SharedPreferencesMultiServerTokenRepository.kt
+++ b/app/src/main/java/chat/rocket/android/authentication/infrastructure/SharedPreferencesMultiServerTokenRepository.kt
@@ -1,4 +1,4 @@
-package chat.rocket.android.authentication.infraestructure
+package chat.rocket.android.authentication.infrastructure
import chat.rocket.android.authentication.domain.model.TokenModel
import chat.rocket.android.dagger.scope.PerActivity
diff --git a/app/src/main/java/chat/rocket/android/authentication/infraestructure/SharedPreferencesTokenRepository.kt b/app/src/main/java/chat/rocket/android/authentication/infrastructure/SharedPreferencesTokenRepository.kt
similarity index 97%
rename from app/src/main/java/chat/rocket/android/authentication/infraestructure/SharedPreferencesTokenRepository.kt
rename to app/src/main/java/chat/rocket/android/authentication/infrastructure/SharedPreferencesTokenRepository.kt
index b2348662e1..cb7bead7be 100644
--- a/app/src/main/java/chat/rocket/android/authentication/infraestructure/SharedPreferencesTokenRepository.kt
+++ b/app/src/main/java/chat/rocket/android/authentication/infrastructure/SharedPreferencesTokenRepository.kt
@@ -1,4 +1,4 @@
-package chat.rocket.android.authentication.infraestructure
+package chat.rocket.android.authentication.infrastructure
import android.content.SharedPreferences
import androidx.core.content.edit
diff --git a/app/src/main/java/chat/rocket/android/authentication/login/presentation/LoginPresenter.kt b/app/src/main/java/chat/rocket/android/authentication/login/presentation/LoginPresenter.kt
index b560c1c034..d3be18ae94 100644
--- a/app/src/main/java/chat/rocket/android/authentication/login/presentation/LoginPresenter.kt
+++ b/app/src/main/java/chat/rocket/android/authentication/login/presentation/LoginPresenter.kt
@@ -15,8 +15,9 @@ import chat.rocket.android.server.domain.favicon
import chat.rocket.android.server.domain.isLdapAuthenticationEnabled
import chat.rocket.android.server.domain.isPasswordResetEnabled
import chat.rocket.android.server.domain.model.Account
+import chat.rocket.android.server.domain.siteName
import chat.rocket.android.server.domain.wideTile
-import chat.rocket.android.server.infraestructure.RocketChatClientFactory
+import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.android.util.extensions.isEmail
@@ -50,6 +51,7 @@ class LoginPresenter @Inject constructor(
) {
// TODO - we should validate the current server when opening the app, and have a nonnull get()
private var currentServer = serverInteractor.get()!!
+ private val token = tokenRepository.get(currentServer)
private lateinit var client: RocketChatClient
private lateinit var settings: PublicSettings
@@ -60,7 +62,7 @@ class LoginPresenter @Inject constructor(
private fun setupConnectionInfo(serverUrl: String) {
currentServer = serverUrl
- client = factory.create(currentServer)
+ client = factory.get(currentServer)
settings = settingsInteractor.get(currentServer)
}
@@ -140,8 +142,15 @@ class LoginPresenter @Inject constructor(
val logo = settings.wideTile()?.let {
currentServer.serverLogoUrl(it)
}
- val thumb = currentServer.avatarUrl(username)
- val account = Account(currentServer, icon, logo, username, thumb)
+ val thumb = currentServer.avatarUrl(username, token?.userId, token?.authToken)
+ val account = Account(
+ settings.siteName() ?: currentServer,
+ currentServer,
+ icon,
+ logo,
+ username,
+ thumb
+ )
saveAccountInteractor.save(account)
}
diff --git a/app/src/main/java/chat/rocket/android/authentication/loginoptions/presentation/LoginOptionsPresenter.kt b/app/src/main/java/chat/rocket/android/authentication/loginoptions/presentation/LoginOptionsPresenter.kt
index be36edab69..c9650cf273 100644
--- a/app/src/main/java/chat/rocket/android/authentication/loginoptions/presentation/LoginOptionsPresenter.kt
+++ b/app/src/main/java/chat/rocket/android/authentication/loginoptions/presentation/LoginOptionsPresenter.kt
@@ -14,8 +14,9 @@ import chat.rocket.android.server.domain.SaveCurrentServerInteractor
import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.domain.favicon
import chat.rocket.android.server.domain.model.Account
+import chat.rocket.android.server.domain.siteName
import chat.rocket.android.server.domain.wideTile
-import chat.rocket.android.server.infraestructure.RocketChatClientFactory
+import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.android.util.extensions.serverLogoUrl
@@ -54,6 +55,7 @@ class LoginOptionsPresenter @Inject constructor(
) {
// TODO - we should validate the current server when opening the app, and have a nonnull get()
private var currentServer = serverInteractor.get()!!
+ private val token = tokenRepository.get(currentServer)
private lateinit var client: RocketChatClient
private lateinit var settings: PublicSettings
private lateinit var credentialToken: String
@@ -169,7 +171,7 @@ class LoginOptionsPresenter @Inject constructor(
private fun setupConnectionInfo(serverUrl: String) {
currentServer = serverUrl
- client = factory.create(currentServer)
+ client = factory.get(currentServer)
settings = settingsInteractor.get(currentServer)
}
@@ -180,8 +182,15 @@ class LoginOptionsPresenter @Inject constructor(
val logo = settings.wideTile()?.let {
currentServer.serverLogoUrl(it)
}
- val thumb = currentServer.avatarUrl(username)
- val account = Account(currentServer, icon, logo, username, thumb)
+ val thumb = currentServer.avatarUrl(username, token?.userId, token?.authToken)
+ val account = Account(
+ settings.siteName() ?: currentServer,
+ currentServer,
+ icon,
+ logo,
+ username,
+ thumb
+ )
saveAccountInteractor.save(account)
}
diff --git a/app/src/main/java/chat/rocket/android/authentication/loginoptions/presentation/LoginOptionsView.kt b/app/src/main/java/chat/rocket/android/authentication/loginoptions/presentation/LoginOptionsView.kt
index 5364c7a0c4..45d6a2e748 100644
--- a/app/src/main/java/chat/rocket/android/authentication/loginoptions/presentation/LoginOptionsView.kt
+++ b/app/src/main/java/chat/rocket/android/authentication/loginoptions/presentation/LoginOptionsView.kt
@@ -25,18 +25,18 @@ interface LoginOptionsView : LoadingView, MessageView {
fun setupFacebookButtonListener(facebookOauthUrl: String, state: String)
/**
- * Shows the "login by Github" view if it is enabled by the server settings.
+ * Shows the "login by GitHub" view if it is enabled by the server settings.
*
- * REMARK: We must set up the Github button listener before enabling it
+ * REMARK: We must set up the GitHub button listener before enabling it
* [setupGithubButtonListener].
* @see [showAccountsView]
*/
fun enableLoginByGithub()
/**
- * Setups the Github button.
+ * Setups the GitHub button.
*
- * @param githubUrl The Github OAuth URL to authenticate with.
+ * @param githubUrl The GitHub OAuth URL to authenticate with.
* @param state A random string generated by the app, which you'll verify later
* (to protect against forgery attacks).
*/
@@ -61,36 +61,36 @@ interface LoginOptionsView : LoadingView, MessageView {
fun setupGoogleButtonListener(googleUrl: String, state: String)
/**
- * Shows the "login by Linkedin" view if it is enabled by the server settings.
+ * Shows the "login by LinkedIn" view if it is enabled by the server settings.
*
- * REMARK: We must set up the Linkedin button listener before enabling it
+ * REMARK: We must set up the LinkedIn button listener before enabling it
* [setupLinkedinButtonListener].
* @see [showAccountsView]
*/
fun enableLoginByLinkedin()
/**
- * Setups the Linkedin button.
+ * Setups the LinkedIn button.
*
- * @param linkedinUrl The Linkedin OAuth URL to authenticate with.
+ * @param linkedinUrl The LinkedIn OAuth URL to authenticate with.
* @param state A random string generated by the app, which you'll verify later
* (to protect against forgery attacks).
*/
fun setupLinkedinButtonListener(linkedinUrl: String, state: String)
/**
- * Shows the "login by Gitlab" view if it is enabled by the server settings.
+ * Shows the "login by GitLab" view if it is enabled by the server settings.
*
- * REMARK: We must set up the Gitlab button listener before enabling it
+ * REMARK: We must set up the GitLab button listener before enabling it
* [setupGitlabButtonListener].
* @see [showAccountsView]
*/
fun enableLoginByGitlab()
/**
- * Setups the Gitlab button.
+ * Setups the GitLab button.
*
- * @param gitlabUrl The Gitlab OAuth URL to authenticate with.
+ * @param gitlabUrl The GitLab OAuth URL to authenticate with.
* @param state A random string generated by the app, which you'll verify later
* (to protect against forgery attacks).
*/
@@ -99,7 +99,7 @@ interface LoginOptionsView : LoadingView, MessageView {
/**
* Shows the "login by WordPress" view if it is enabled by the server settings.
*
- * REMARK: We must set up the Gitlab button listener before enabling it [setupWordpressButtonListener].
+ * REMARK: We must set up the GitLab button listener before enabling it [setupWordpressButtonListener].
*/
fun enableLoginByWordpress()
diff --git a/app/src/main/java/chat/rocket/android/authentication/loginoptions/ui/LoginOptionsFragment.kt b/app/src/main/java/chat/rocket/android/authentication/loginoptions/ui/LoginOptionsFragment.kt
index 33bbb00593..d0d1abd971 100644
--- a/app/src/main/java/chat/rocket/android/authentication/loginoptions/ui/LoginOptionsFragment.kt
+++ b/app/src/main/java/chat/rocket/android/authentication/loginoptions/ui/LoginOptionsFragment.kt
@@ -1,5 +1,8 @@
package chat.rocket.android.authentication.loginoptions.ui
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.ValueAnimator
import android.app.Activity
import android.content.Intent
import android.graphics.PorterDuff
@@ -7,10 +10,13 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import android.view.animation.AlphaAnimation
+import android.view.animation.Animation
import android.widget.Button
import android.widget.LinearLayout
import androidx.appcompat.view.ContextThemeWrapper
import androidx.core.view.isVisible
+import androidx.core.view.marginTop
import androidx.fragment.app.Fragment
import chat.rocket.android.R
import chat.rocket.android.analytics.AnalyticsManager
@@ -28,6 +34,7 @@ import chat.rocket.android.webview.sso.ui.ssoWebViewIntent
import dagger.android.support.AndroidSupportInjection
import kotlinx.android.synthetic.main.app_bar.*
import kotlinx.android.synthetic.main.fragment_authentication_login_options.*
+import timber.log.Timber
import javax.inject.Inject
private const val SERVER_NAME = "server_name"
@@ -61,6 +68,8 @@ internal const val REQUEST_CODE_FOR_OAUTH = 1
internal const val REQUEST_CODE_FOR_CAS = 2
internal const val REQUEST_CODE_FOR_SAML = 3
+private const val DEFAULT_ANIMATION_DURATION = 400L
+
fun newInstance(
serverName: String,
state: String? = null,
@@ -238,7 +247,6 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView {
enableLoginByLinkedin()
}
-
if (gitlabOauthUrl != null && state != null) {
setupGitlabButtonListener(gitlabOauthUrl.toString(), state.toString())
enableLoginByGitlab()
@@ -390,11 +398,11 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView {
var isAccountsCollapsed = true
button_expand_collapse_accounts.setOnClickListener {
isAccountsCollapsed = if (isAccountsCollapsed) {
- button_expand_collapse_accounts.rotateBy(180F, 400)
+ button_expand_collapse_accounts.rotateBy(180F, DEFAULT_ANIMATION_DURATION)
expandAccountsView()
false
} else {
- button_expand_collapse_accounts.rotateBy(180F, 400)
+ button_expand_collapse_accounts.rotateBy(180F, DEFAULT_ANIMATION_DURATION)
collapseAccountsView()
true
}
@@ -532,17 +540,73 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView {
}
private fun expandAccountsView() {
- (0..accounts_container.childCount)
+ val buttons = (0..accounts_container.childCount)
.mapNotNull { accounts_container.getChildAt(it) as? Button }
.filter { it.isClickable && !it.isVisible }
- .forEach { it.isVisible = true }
+ val optionHeight = accounts_container.getChildAt(1).height +
+ accounts_container.getChildAt(1).marginTop
+ val collapsedHeight = accounts_container.height
+ val expandedHeight = collapsedHeight + optionHeight * buttons.size
+
+ with(ValueAnimator.ofInt(collapsedHeight, expandedHeight)) {
+ addUpdateListener {
+ val params = accounts_container.layoutParams
+ params.height = animatedValue as Int
+ accounts_container.layoutParams = params
+ }
+ addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationStart(animator: Animator) {
+ buttons.forEach {
+ it.isVisible = true
+ val anim = AlphaAnimation(0.0f, 1.0f)
+ anim.duration = DEFAULT_ANIMATION_DURATION
+ it.startAnimation(anim)
+ }
+ }
+ })
+ setDuration(DEFAULT_ANIMATION_DURATION).start()
+ }
}
private fun collapseAccountsView() {
- (0..accounts_container.childCount)
+ val buttons = (0..accounts_container.childCount)
.mapNotNull { accounts_container.getChildAt(it) as? Button }
.filter { it.isClickable && it.isVisible }
.drop(3)
- .forEach { it.isVisible = false }
+ val optionHeight = accounts_container.getChildAt(1).height +
+ accounts_container.getChildAt(1).marginTop
+ val expandedHeight = accounts_container.height
+ val collapsedHeight = expandedHeight - optionHeight * buttons.size
+
+ with(ValueAnimator.ofInt(expandedHeight, collapsedHeight)) {
+ addUpdateListener {
+ val params = accounts_container.layoutParams
+ params.height = animatedValue as Int
+ accounts_container.layoutParams = params
+ }
+ addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationStart(animator: Animator) {
+ buttons.forEach {
+ val anim = AlphaAnimation(1.0f, 0.0f)
+ anim.duration = DEFAULT_ANIMATION_DURATION
+ anim.setAnimationListener(object : Animation.AnimationListener {
+ override fun onAnimationStart(animation: Animation) {
+ Timber.d("Animation starts: $animation")
+ }
+
+ override fun onAnimationEnd(animation: Animation) {
+ it.isVisible = false
+ }
+
+ override fun onAnimationRepeat(animation: Animation) {
+ Timber.d("Animation repeats: $animation")
+ }
+ })
+ it.startAnimation(anim)
+ }
+ }
+ })
+ setDuration(DEFAULT_ANIMATION_DURATION).start()
+ }
}
}
diff --git a/app/src/main/java/chat/rocket/android/authentication/onboarding/presentation/OnBoardingPresenter.kt b/app/src/main/java/chat/rocket/android/authentication/onboarding/presentation/OnBoardingPresenter.kt
index 532c6f56d9..37979843ad 100644
--- a/app/src/main/java/chat/rocket/android/authentication/onboarding/presentation/OnBoardingPresenter.kt
+++ b/app/src/main/java/chat/rocket/android/authentication/onboarding/presentation/OnBoardingPresenter.kt
@@ -7,7 +7,7 @@ import chat.rocket.android.server.domain.GetAccountsInteractor
import chat.rocket.android.server.domain.GetSettingsInteractor
import chat.rocket.android.server.domain.RefreshSettingsInteractor
import chat.rocket.android.server.domain.SaveConnectingServerInteractor
-import chat.rocket.android.server.infraestructure.RocketChatClientFactory
+import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.server.presentation.CheckServerPresenter
import chat.rocket.android.util.extension.launchUI
import kotlinx.coroutines.Dispatchers
diff --git a/app/src/main/java/chat/rocket/android/authentication/registerusername/presentation/RegisterUsernamePresenter.kt b/app/src/main/java/chat/rocket/android/authentication/registerusername/presentation/RegisterUsernamePresenter.kt
index f50137136e..a5d21a8762 100644
--- a/app/src/main/java/chat/rocket/android/authentication/registerusername/presentation/RegisterUsernamePresenter.kt
+++ b/app/src/main/java/chat/rocket/android/authentication/registerusername/presentation/RegisterUsernamePresenter.kt
@@ -12,8 +12,9 @@ import chat.rocket.android.server.domain.SaveCurrentServerInteractor
import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.domain.favicon
import chat.rocket.android.server.domain.model.Account
+import chat.rocket.android.server.domain.siteName
import chat.rocket.android.server.domain.wideTile
-import chat.rocket.android.server.infraestructure.RocketChatClientFactory
+import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.android.util.extensions.serverLogoUrl
@@ -38,8 +39,9 @@ class RegisterUsernamePresenter @Inject constructor(
val settingsInteractor: GetSettingsInteractor
) {
private val currentServer = serverInteractor.get()!!
- private val client: RocketChatClient = factory.create(currentServer)
- private var settings: PublicSettings = settingsInteractor.get(serverInteractor.get()!!)
+ private val client: RocketChatClient = factory.get(currentServer)
+ private var settings: PublicSettings = settingsInteractor.get(currentServer)
+ private val token = tokenRepository.get(currentServer)
fun registerUsername(username: String, userId: String, authToken: String) {
launchUI(strategy) {
@@ -72,15 +74,22 @@ class RegisterUsernamePresenter @Inject constructor(
}
}
- private suspend fun saveAccount(username: String) {
+ private fun saveAccount(username: String) {
val icon = settings.favicon()?.let {
currentServer.serverLogoUrl(it)
}
val logo = settings.wideTile()?.let {
currentServer.serverLogoUrl(it)
}
- val thumb = currentServer.avatarUrl(username)
- val account = Account(currentServer, icon, logo, username, thumb)
+ val thumb = currentServer.avatarUrl(username, token?.userId, token?.authToken)
+ val account = Account(
+ settings.siteName() ?: currentServer,
+ currentServer,
+ icon,
+ logo,
+ username,
+ thumb
+ )
saveAccountInteractor.save(account)
}
}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/authentication/registerusername/ui/RegisterUsernameFragment.kt b/app/src/main/java/chat/rocket/android/authentication/registerusername/ui/RegisterUsernameFragment.kt
index 2ec6b49119..0ddd217bd4 100644
--- a/app/src/main/java/chat/rocket/android/authentication/registerusername/ui/RegisterUsernameFragment.kt
+++ b/app/src/main/java/chat/rocket/android/authentication/registerusername/ui/RegisterUsernameFragment.kt
@@ -140,7 +140,7 @@ class RegisterUsernameFragment : Fragment(), RegisterUsernameView {
val atDrawable = DrawableHelper.getDrawableFromId(R.drawable.ic_at_black_20dp, it)
DrawableHelper.wrapDrawable(atDrawable)
DrawableHelper.tintDrawable(atDrawable, it, R.color.colorDrawableTintGrey)
- DrawableHelper.compoundDrawable(text_username, atDrawable)
+ DrawableHelper.compoundStartDrawable(text_username, atDrawable)
}
}
diff --git a/app/src/main/java/chat/rocket/android/authentication/resetpassword/presentation/ResetPasswordPresenter.kt b/app/src/main/java/chat/rocket/android/authentication/resetpassword/presentation/ResetPasswordPresenter.kt
index ab750d4a42..c129db9f49 100644
--- a/app/src/main/java/chat/rocket/android/authentication/resetpassword/presentation/ResetPasswordPresenter.kt
+++ b/app/src/main/java/chat/rocket/android/authentication/resetpassword/presentation/ResetPasswordPresenter.kt
@@ -3,7 +3,7 @@ package chat.rocket.android.authentication.resetpassword.presentation
import chat.rocket.android.authentication.presentation.AuthenticationNavigator
import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.server.domain.GetConnectingServerInteractor
-import chat.rocket.android.server.infraestructure.RocketChatClientFactory
+import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.retryIO
import chat.rocket.common.RocketChatException
@@ -21,7 +21,7 @@ class ResetPasswordPresenter @Inject constructor(
serverInteractor: GetConnectingServerInteractor
) {
private val currentServer = serverInteractor.get()!!
- private val client: RocketChatClient = factory.create(currentServer)
+ private val client: RocketChatClient = factory.get(currentServer)
fun resetPassword(email: String) {
launchUI(strategy) {
diff --git a/app/src/main/java/chat/rocket/android/authentication/resetpassword/presentation/ResetPasswordView.kt b/app/src/main/java/chat/rocket/android/authentication/resetpassword/presentation/ResetPasswordView.kt
index 6dd2e51518..fb72f60f63 100644
--- a/app/src/main/java/chat/rocket/android/authentication/resetpassword/presentation/ResetPasswordView.kt
+++ b/app/src/main/java/chat/rocket/android/authentication/resetpassword/presentation/ResetPasswordView.kt
@@ -21,7 +21,7 @@ interface ResetPasswordView : LoadingView, MessageView {
fun enableButtonConnect()
/**
- * Disables the button to reset the password when the user entered an invalid email address
+ * Disables the button to reset the password when the user has entered an invalid email address
*/
fun disableButtonConnect()
}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/authentication/server/presentation/ServerPresenter.kt b/app/src/main/java/chat/rocket/android/authentication/server/presentation/ServerPresenter.kt
index 415ace7783..d6192390cc 100644
--- a/app/src/main/java/chat/rocket/android/authentication/server/presentation/ServerPresenter.kt
+++ b/app/src/main/java/chat/rocket/android/authentication/server/presentation/ServerPresenter.kt
@@ -8,7 +8,7 @@ import chat.rocket.android.server.domain.GetAccountsInteractor
import chat.rocket.android.server.domain.GetSettingsInteractor
import chat.rocket.android.server.domain.RefreshSettingsInteractor
import chat.rocket.android.server.domain.SaveConnectingServerInteractor
-import chat.rocket.android.server.infraestructure.RocketChatClientFactory
+import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.server.presentation.CheckServerPresenter
import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.extensions.isValidUrl
diff --git a/app/src/main/java/chat/rocket/android/authentication/server/presentation/VersionCheckView.kt b/app/src/main/java/chat/rocket/android/authentication/server/presentation/VersionCheckView.kt
index 89711b6e96..0b93cf0ac2 100644
--- a/app/src/main/java/chat/rocket/android/authentication/server/presentation/VersionCheckView.kt
+++ b/app/src/main/java/chat/rocket/android/authentication/server/presentation/VersionCheckView.kt
@@ -26,7 +26,7 @@ interface VersionCheckView {
fun versionOk() {}
/**
- * Alters the user this protocol is invalid. This is optional.
+ * Alters the user that this protocol is invalid. This is optional.
*/
fun errorInvalidProtocol() {}
diff --git a/app/src/main/java/chat/rocket/android/authentication/signup/presentation/SignupPresenter.kt b/app/src/main/java/chat/rocket/android/authentication/signup/presentation/SignupPresenter.kt
index 4d6b7d16f9..1633e36228 100644
--- a/app/src/main/java/chat/rocket/android/authentication/signup/presentation/SignupPresenter.kt
+++ b/app/src/main/java/chat/rocket/android/authentication/signup/presentation/SignupPresenter.kt
@@ -10,10 +10,12 @@ import chat.rocket.android.server.domain.GetSettingsInteractor
import chat.rocket.android.server.domain.PublicSettings
import chat.rocket.android.server.domain.SaveAccountInteractor
import chat.rocket.android.server.domain.SaveCurrentServerInteractor
+import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.domain.favicon
import chat.rocket.android.server.domain.model.Account
+import chat.rocket.android.server.domain.siteName
import chat.rocket.android.server.domain.wideTile
-import chat.rocket.android.server.infraestructure.RocketChatClientFactory
+import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.android.util.extensions.privacyPolicyUrl
@@ -38,13 +40,15 @@ class SignupPresenter @Inject constructor(
private val analyticsManager: AnalyticsManager,
private val factory: RocketChatClientFactory,
private val saveAccountInteractor: SaveAccountInteractor,
+ tokenRepository: TokenRepository,
settingsInteractor: GetSettingsInteractor
) {
private val currentServer = serverInteractor.get()!!
- private var settings: PublicSettings = settingsInteractor.get(serverInteractor.get()!!)
+ private var settings: PublicSettings = settingsInteractor.get(currentServer)
+ private val token = tokenRepository.get(currentServer)
fun signup(name: String, username: String, password: String, email: String) {
- val client = factory.create(currentServer)
+ val client = factory.get(currentServer)
launchUI(strategy) {
view.showLoading()
try {
@@ -98,8 +102,15 @@ class SignupPresenter @Inject constructor(
val logo = settings.wideTile()?.let {
currentServer.serverLogoUrl(it)
}
- val thumb = currentServer.avatarUrl(me.username!!)
- val account = Account(currentServer, icon, logo, me.username!!, thumb)
+ val thumb = currentServer.avatarUrl(me.username!!, token?.userId, token?.authToken)
+ val account = Account(
+ settings.siteName() ?: currentServer,
+ currentServer,
+ icon,
+ logo,
+ me.username!!,
+ thumb
+ )
saveAccountInteractor.save(account)
}
}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/authentication/twofactor/presentation/TwoFAPresenter.kt b/app/src/main/java/chat/rocket/android/authentication/twofactor/presentation/TwoFAPresenter.kt
index c4c6dbace0..a6e15b5ca9 100644
--- a/app/src/main/java/chat/rocket/android/authentication/twofactor/presentation/TwoFAPresenter.kt
+++ b/app/src/main/java/chat/rocket/android/authentication/twofactor/presentation/TwoFAPresenter.kt
@@ -13,8 +13,9 @@ import chat.rocket.android.server.domain.SaveCurrentServerInteractor
import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.domain.favicon
import chat.rocket.android.server.domain.model.Account
+import chat.rocket.android.server.domain.siteName
import chat.rocket.android.server.domain.wideTile
-import chat.rocket.android.server.infraestructure.RocketChatClientFactory
+import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.android.util.extensions.isEmail
@@ -43,7 +44,8 @@ class TwoFAPresenter @Inject constructor(
val settingsInteractor: GetSettingsInteractor
) {
private val currentServer = serverInteractor.get()!!
- private var settings: PublicSettings = settingsInteractor.get(serverInteractor.get()!!)
+ private var settings: PublicSettings = settingsInteractor.get(currentServer)
+ private val token = tokenRepository.get(currentServer)
fun authenticate(
usernameOrEmail: String,
@@ -51,7 +53,7 @@ class TwoFAPresenter @Inject constructor(
twoFactorAuthenticationCode: String
) {
launchUI(strategy) {
- val client = factory.create(currentServer)
+ val client = factory.get(currentServer)
view.showLoading()
try {
// The token is saved via the client TokenProvider
@@ -101,8 +103,15 @@ class TwoFAPresenter @Inject constructor(
val logo = settings.wideTile()?.let {
currentServer.serverLogoUrl(it)
}
- val thumb = currentServer.avatarUrl(me.username!!)
- val account = Account(currentServer, icon, logo, me.username!!, thumb)
+ val thumb = currentServer.avatarUrl(me.username!!, token?.userId, token?.authToken)
+ val account = Account(
+ settings.siteName() ?: currentServer,
+ currentServer,
+ icon,
+ logo,
+ me.username!!,
+ thumb
+ )
saveAccountInteractor.save(account)
}
}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/chatdetails/presentation/ChatDetailsPresenter.kt b/app/src/main/java/chat/rocket/android/chatdetails/presentation/ChatDetailsPresenter.kt
index ae8c3b8ea5..0e03a35c28 100644
--- a/app/src/main/java/chat/rocket/android/chatdetails/presentation/ChatDetailsPresenter.kt
+++ b/app/src/main/java/chat/rocket/android/chatdetails/presentation/ChatDetailsPresenter.kt
@@ -4,7 +4,7 @@ import chat.rocket.android.chatdetails.domain.ChatDetails
import chat.rocket.android.chatroom.presentation.ChatRoomNavigator
import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.server.domain.GetCurrentServerInteractor
-import chat.rocket.android.server.infraestructure.ConnectionManagerFactory
+import chat.rocket.android.server.infrastructure.ConnectionManagerFactory
import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.retryIO
import chat.rocket.common.RocketChatException
diff --git a/app/src/main/java/chat/rocket/android/chatdetails/ui/ChatDetailsFragment.kt b/app/src/main/java/chat/rocket/android/chatdetails/ui/ChatDetailsFragment.kt
index 87de3850e0..2e957adfb4 100644
--- a/app/src/main/java/chat/rocket/android/chatdetails/ui/ChatDetailsFragment.kt
+++ b/app/src/main/java/chat/rocket/android/chatdetails/ui/ChatDetailsFragment.kt
@@ -195,7 +195,7 @@ class ChatDetailsFragment : Fragment(), ChatDetailsView {
val wrappedDrawable = DrawableHelper.wrapDrawable(it)
val mutableDrawable = wrappedDrawable.mutate()
DrawableHelper.tintDrawable(mutableDrawable, context!!, R.color.colorPrimary)
- DrawableHelper.compoundDrawable(name, mutableDrawable)
+ DrawableHelper.compoundStartDrawable(name, mutableDrawable)
}
}
diff --git a/app/src/main/java/chat/rocket/android/chatdetails/ui/Menu.kt b/app/src/main/java/chat/rocket/android/chatdetails/ui/Menu.kt
index d1f9a58060..c8961173a1 100644
--- a/app/src/main/java/chat/rocket/android/chatdetails/ui/Menu.kt
+++ b/app/src/main/java/chat/rocket/android/chatdetails/ui/Menu.kt
@@ -13,7 +13,7 @@ internal fun ChatDetailsFragment.setupMenu(menu: Menu) {
with(settings.get(it)) {
if (isJitsiEnabled()) {
if (roomTypeOf(chatRoomType) !is RoomType.DirectMessage && !isJitsiEnabledForChannels()) {
- return
+ return@let
}
menu.add(
Menu.NONE,
diff --git a/app/src/main/java/chat/rocket/android/chatinformation/presentation/MessageInfoPresenter.kt b/app/src/main/java/chat/rocket/android/chatinformation/presentation/MessageInfoPresenter.kt
index 3f1ecc41f8..2b8b2b1d88 100644
--- a/app/src/main/java/chat/rocket/android/chatinformation/presentation/MessageInfoPresenter.kt
+++ b/app/src/main/java/chat/rocket/android/chatinformation/presentation/MessageInfoPresenter.kt
@@ -3,7 +3,7 @@ package chat.rocket.android.chatinformation.presentation
import chat.rocket.android.chatroom.uimodel.UiModelMapper
import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.server.domain.GetCurrentServerInteractor
-import chat.rocket.android.server.infraestructure.ConnectionManagerFactory
+import chat.rocket.android.server.infrastructure.ConnectionManagerFactory
import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.retryIO
import chat.rocket.common.RocketChatException
diff --git a/app/src/main/java/chat/rocket/android/chatinformation/ui/MessageInfoFragment.kt b/app/src/main/java/chat/rocket/android/chatinformation/ui/MessageInfoFragment.kt
index 8f6d881a6d..986f9f3ec1 100644
--- a/app/src/main/java/chat/rocket/android/chatinformation/ui/MessageInfoFragment.kt
+++ b/app/src/main/java/chat/rocket/android/chatinformation/ui/MessageInfoFragment.kt
@@ -42,7 +42,6 @@ class MessageInfoFragment : Fragment(), MessageInfoView {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
AndroidSupportInjection.inject(this)
- setHasOptionsMenu(true)
val bundle = arguments
if (bundle != null) {
@@ -50,6 +49,8 @@ class MessageInfoFragment : Fragment(), MessageInfoView {
} else {
requireNotNull(bundle) { "no arguments supplied when the fragment was instantiated" }
}
+
+ setHasOptionsMenu(true)
}
override fun onCreateView(
diff --git a/app/src/main/java/chat/rocket/android/chatroom/di/ChatRoomFragmentModule.kt b/app/src/main/java/chat/rocket/android/chatroom/di/ChatRoomFragmentModule.kt
index 260daba587..c14782ece9 100644
--- a/app/src/main/java/chat/rocket/android/chatroom/di/ChatRoomFragmentModule.kt
+++ b/app/src/main/java/chat/rocket/android/chatroom/di/ChatRoomFragmentModule.kt
@@ -56,6 +56,7 @@ class ChatRoomFragmentModule {
context: Application,
repository: SettingsRepository,
userInteractor: GetCurrentUserInteractor,
+ tokenRepository: TokenRepository,
@Named("currentServer") serverUrl: String,
permissionsInteractor: PermissionsInteractor
): RoomUiModelMapper {
@@ -63,6 +64,7 @@ class ChatRoomFragmentModule {
context,
repository.get(serverUrl),
userInteractor,
+ tokenRepository,
serverUrl,
permissionsInteractor
)
diff --git a/app/src/main/java/chat/rocket/android/chatroom/presentation/ChatRoomPresenter.kt b/app/src/main/java/chat/rocket/android/chatroom/presentation/ChatRoomPresenter.kt
index 324c337a37..cf856debd1 100644
--- a/app/src/main/java/chat/rocket/android/chatroom/presentation/ChatRoomPresenter.kt
+++ b/app/src/main/java/chat/rocket/android/chatroom/presentation/ChatRoomPresenter.kt
@@ -29,12 +29,13 @@ import chat.rocket.android.server.domain.JobSchedulerInteractor
import chat.rocket.android.server.domain.MessagesRepository
import chat.rocket.android.server.domain.PermissionsInteractor
import chat.rocket.android.server.domain.PublicSettings
+import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.domain.UsersRepository
import chat.rocket.android.server.domain.uploadMaxFileSize
import chat.rocket.android.server.domain.uploadMimeTypeFilter
import chat.rocket.android.server.domain.useRealName
-import chat.rocket.android.server.infraestructure.ConnectionManagerFactory
-import chat.rocket.android.server.infraestructure.state
+import chat.rocket.android.server.infrastructure.ConnectionManagerFactory
+import chat.rocket.android.server.infrastructure.state
import chat.rocket.android.util.extension.getByteArray
import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.extensions.avatarUrl
@@ -101,6 +102,7 @@ class ChatRoomPresenter @Inject constructor(
private val jobSchedulerInteractor: JobSchedulerInteractor,
private val messageHelper: MessageHelper,
private val dbManager: DatabaseManager,
+ tokenRepository: TokenRepository,
getSettingsInteractor: GetSettingsInteractor,
serverInteractor: GetCurrentServerInteractor,
factory: ConnectionManagerFactory
@@ -109,18 +111,21 @@ class ChatRoomPresenter @Inject constructor(
private val manager = factory.create(currentServer)
private val client = manager.client
private var settings: PublicSettings = getSettingsInteractor.get(serverInteractor.get()!!)
+ private val token = tokenRepository.get(currentServer)
private val currentLoggedUsername = userHelper.username()
private val messagesChannel = Channel()
private var chatRoomId: String? = null
private lateinit var chatRoomType: String
- private var chatIsBroadcast: Boolean = false
+ private lateinit var chatRoomName: String
+ private var isBroadcast: Boolean = false
private var chatRoles = emptyList()
private val stateChannel = Channel()
private var typingStatusSubscriptionId: String? = null
private var lastState = manager.state
private var typingStatusList = arrayListOf()
private val roomChangesChannel = Channel(Channel.CONFLATED)
+ private var lastMessageId: String? = null
private lateinit var draftKey: String
fun setupChatRoom(
@@ -132,47 +137,77 @@ class ChatRoomPresenter @Inject constructor(
draftKey = "${currentServer}_${LocalRepository.DRAFT_KEY}$roomId"
chatRoomId = roomId
chatRoomType = roomType
+ chatRoomName = roomName
+ chatRoles = emptyList()
+ var canModerate = isOwnerOrMod()
+
GlobalScope.launch(Dispatchers.IO + strategy.jobs) {
- try {
- chatRoles = if (roomTypeOf(roomType) !is RoomType.DirectMessage) {
- client.chatRoomRoles(roomType = roomTypeOf(roomType), roomName = roomName)
- } else {
- emptyList()
- }
- } catch (ex: Exception) {
- Timber.e(ex)
- chatRoles = emptyList()
- } finally {
- // User has at least an 'owner' or 'moderator' role.
- val canModerate = isOwnerOrMod()
- // Can post anyway if has the 'post-readonly' permission on server.
- val room = dbManager.getRoom(roomId)
- room?.let {
- chatIsBroadcast = it.chatRoom.broadcast ?: false
- val roomUiModel = roomMapper.map(it, true)
- launchUI(strategy) {
- view.onRoomUpdated(roomUiModel = roomUiModel.copy(
- broadcast = chatIsBroadcast,
+ // Can post anyway if has the 'post-readonly' permission on server.
+ val room = dbManager.getRoom(roomId)
+ room?.let {
+ isBroadcast = it.chatRoom.broadcast ?: false
+ val roomUiModel = roomMapper.map(it, true)
+ launchUI(strategy) {
+ view.onRoomUpdated(
+ roomUiModel = roomUiModel.copy(
+ broadcast = isBroadcast,
canModerate = canModerate,
writable = roomUiModel.writable || canModerate
- ))
- }
+ )
+ )
}
+ }
- loadMessages(roomId, roomType, clearDataSet = true)
- chatRoomMessage?.let { messageHelper.messageIdFromPermalink(it) }
- ?.let { messageId ->
- val name = messageHelper.roomNameFromPermalink(chatRoomMessage)
- citeMessage(
- name!!,
- messageHelper.roomTypeFromPermalink(chatRoomMessage)!!,
- messageId,
- true
- )
- }
- subscribeRoomChanges()
+ loadMessages(roomId, chatRoomType, clearDataSet = true)
+ loadActiveMembers(roomId, chatRoomType, filterSelfOut = true)
+
+ chatRoomMessage?.let { messageHelper.messageIdFromPermalink(it) }
+ ?.let { messageId ->
+ val name = messageHelper.roomNameFromPermalink(chatRoomMessage)
+ citeMessage(
+ name!!,
+ messageHelper.roomTypeFromPermalink(chatRoomMessage)!!,
+ messageId,
+ true
+ )
+ }
+
+
+ /*FIXME: Get chat role can cause unresponsive problems especially on slower connections
+ We are updating the room again after the first step so that initial messages
+ get loaded in and the system appears more responsive. Something should be
+ done to either fix the load in speed of moderator roles or store the
+ information locally*/
+ if (getChatRole()) {
+ canModerate = isOwnerOrMod()
+ if (canModerate) {
+ //FIXME: add this in when moderator page is actually created
+ //view.updateModeration()
+ }
+ }
+
+ subscribeRoomChanges()
+ }
+ }
+
+ private suspend fun getChatRole(): Boolean {
+ try {
+ if (roomTypeOf(chatRoomType) !is RoomType.DirectMessage) {
+ chatRoles = withContext(Dispatchers.IO + strategy.jobs) {
+ client.chatRoomRoles(
+ roomType = roomTypeOf(chatRoomType),
+ roomName = chatRoomName
+ )
+ }
+ return true
+ } else {
+ chatRoles = emptyList()
}
+ } catch (ex: Exception) {
+ Timber.e(ex)
+ chatRoles = emptyList()
}
+ return false
}
private suspend fun subscribeRoomChanges() {
@@ -181,7 +216,12 @@ class ChatRoomPresenter @Inject constructor(
manager.addRoomChannel(it, roomChangesChannel)
for (room in roomChangesChannel) {
dbManager.getRoom(room.id)?.let { chatRoom ->
- view.onRoomUpdated(roomMapper.map(chatRoom = chatRoom, showLastMessage = true))
+ view.onRoomUpdated(
+ roomMapper.map(
+ chatRoom = chatRoom,
+ showLastMessage = true
+ )
+ )
}
}
}
@@ -206,8 +246,8 @@ class ChatRoomPresenter @Inject constructor(
) {
this.chatRoomId = chatRoomId
this.chatRoomType = chatRoomType
- launchUI(strategy) {
- view.showLoading()
+
+ GlobalScope.launch(Dispatchers.IO + strategy.jobs) {
try {
if (offset == 0L) {
// FIXME - load just 50 messages from DB to speed up. We will reload from Network after that
@@ -215,11 +255,12 @@ class ChatRoomPresenter @Inject constructor(
val localMessages = messagesRepository.getRecentMessages(chatRoomId, 50)
val oldMessages = mapper.map(
localMessages, RoomUiModel(
- roles = chatRoles,
- // FIXME: Why are we fixing isRoom attribute to true here?
- isBroadcast = chatIsBroadcast, isRoom = true
- )
+ roles = chatRoles,
+ // FIXME: Why are we fixing isRoom attribute to true here?
+ isBroadcast = isBroadcast, isRoom = true
+ )
)
+ lastMessageId = localMessages.firstOrNull()?.id
val lastSyncDate = messagesRepository.getLastSyncDate(chatRoomId)
if (oldMessages.isNotEmpty() && lastSyncDate != null) {
view.showMessages(oldMessages, clearDataSet)
@@ -232,7 +273,7 @@ class ChatRoomPresenter @Inject constructor(
}
// TODO: For now we are marking the room as read if we can get the messages (I mean, no exception occurs)
- // but should mark only when the user see the first unread message.
+ // but should mark only when the user sees the first unread message.
markRoomAsRead(chatRoomId)
subscribeMessages(chatRoomId)
@@ -243,8 +284,6 @@ class ChatRoomPresenter @Inject constructor(
}.ifNull {
view.showGenericErrorMessage()
}
- } finally {
- view.hideLoading()
}
subscribeTypingStatus()
@@ -279,7 +318,7 @@ class ChatRoomPresenter @Inject constructor(
view.showMessages(
mapper.map(
messages,
- RoomUiModel(roles = chatRoles, isBroadcast = chatIsBroadcast, isRoom = true)
+ RoomUiModel(roles = chatRoles, isBroadcast = isBroadcast, isRoom = true)
),
clearDataSet
)
@@ -295,7 +334,7 @@ class ChatRoomPresenter @Inject constructor(
view.showSearchedMessages(
mapper.map(
messages,
- RoomUiModel(chatRoles, chatIsBroadcast, true)
+ RoomUiModel(chatRoles, isBroadcast, true)
)
)
} catch (ex: Exception) {
@@ -327,7 +366,11 @@ class ChatRoomPresenter @Inject constructor(
timestamp = Instant.now().toEpochMilli(),
sender = SimpleUser(user?.id, user?.username ?: username, user?.name),
attachments = null,
- avatar = currentServer.avatarUrl(username ?: ""),
+ avatar = currentServer.avatarUrl(
+ username!!,
+ token?.userId,
+ token?.authToken
+ ),
channels = null,
editedAt = null,
editedBy = null,
@@ -349,7 +392,7 @@ class ChatRoomPresenter @Inject constructor(
view.showNewMessage(
mapper.map(
newMessage,
- RoomUiModel(roles = chatRoles, isBroadcast = chatIsBroadcast)
+ RoomUiModel(roles = chatRoles, isBroadcast = isBroadcast)
), false
)
client.sendMessage(id, chatRoomId, text)
@@ -368,6 +411,7 @@ class ChatRoomPresenter @Inject constructor(
throw ex
}
}
+ lastMessageId = id
} else {
client.updateMessage(chatRoomId, messageId, text)
}
@@ -599,16 +643,21 @@ class ChatRoomPresenter @Inject constructor(
Timber.d("History: $messages")
if (messages.result.isNotEmpty()) {
- val models = mapper.map(messages.result, RoomUiModel(
- roles = chatRoles,
- isBroadcast = chatIsBroadcast,
- // FIXME: Why are we fixing isRoom attribute to true here?
- isRoom = true
- ))
+ val models = mapper.map(
+ messages.result, RoomUiModel(
+ roles = chatRoles,
+ isBroadcast = isBroadcast,
+ // FIXME: Why are we fixing isRoom attribute to true here?
+ isRoom = true
+ )
+ )
messagesRepository.saveAll(messages.result)
//if success - saving last synced time
//assume that BE returns ordered messages, the first message is the latest one
- messagesRepository.saveLastSyncDate(chatRoomId, messages.result.first().timestamp)
+ messagesRepository.saveLastSyncDate(
+ chatRoomId,
+ messages.result.first().timestamp
+ )
launchUI(strategy) {
view.showNewMessage(models, true)
@@ -685,9 +734,9 @@ class ChatRoomPresenter @Inject constructor(
replyMarkdown = "[ ]($currentServer/$chatRoomType/$room?msg=$id) $mention ",
quotedMessage = mapper.map(
message, RoomUiModel(
- roles = chatRoles,
- isBroadcast = chatIsBroadcast
- )
+ roles = chatRoles,
+ isBroadcast = isBroadcast
+ )
).last().preview?.message ?: ""
)
}
@@ -790,13 +839,15 @@ class ChatRoomPresenter @Inject constructor(
}
}
- fun loadActiveMembers(
+ suspend fun loadActiveMembers(
chatRoomId: String,
chatRoomType: String,
offset: Long = 0,
filterSelfOut: Boolean = false
) {
- launchUI(strategy) {
+ val activeUsers = mutableListOf()
+
+ withContext(Dispatchers.IO + strategy.jobs) {
try {
val members = retryIO("getMembers($chatRoomId, $chatRoomType, $offset)") {
client.getMembers(chatRoomId, roomTypeOf(chatRoomType), offset, 50).result
@@ -807,12 +858,12 @@ class ChatRoomPresenter @Inject constructor(
// Take at most the 100 most recent messages distinguished by user. Can return less.
val recentMessages = messagesRepository.getRecentMessages(chatRoomId, 100)
.filterNot { filterSelfOut && it.sender?.username == self }
- val activeUsers = mutableListOf()
recentMessages.forEach {
val sender = it.sender
val username = sender?.username ?: ""
val name = sender?.name ?: ""
- val avatarUrl = currentServer.avatarUrl(username)
+ val avatarUrl =
+ currentServer.avatarUrl(username, token?.userId, token?.authToken)
val found = members.firstOrNull { member -> member.username == username }
val status = if (found != null) found.status else UserStatus.Offline()
val searchList = mutableListOf(username, name)
@@ -833,7 +884,8 @@ class ChatRoomPresenter @Inject constructor(
activeUsers.addAll(others.map {
val username = it.username ?: ""
val name = it.name ?: ""
- val avatarUrl = currentServer.avatarUrl(username)
+ val avatarUrl =
+ currentServer.avatarUrl(username, token?.userId, token?.authToken)
val searchList = mutableListOf(username, name)
PeopleSuggestionUiModel(
avatarUrl,
@@ -846,11 +898,13 @@ class ChatRoomPresenter @Inject constructor(
)
})
- view.populatePeopleSuggestions(activeUsers)
} catch (e: RocketChatException) {
Timber.e(e)
}
}
+ launchUI(strategy) {
+ view.populatePeopleSuggestions(activeUsers)
+ }
}
fun spotlight(query: String, @AutoCompleteType type: Int, filterSelfOut: Boolean = false) {
@@ -869,7 +923,7 @@ class ChatRoomPresenter @Inject constructor(
val searchList = mutableListOf(username, name)
it.emails?.forEach { email -> searchList.add(email.address) }
PeopleSuggestionUiModel(
- currentServer.avatarUrl(username),
+ currentServer.avatarUrl(username, token?.userId, token?.authToken),
username, username, name, it.status, false, searchList
)
}.filterNot { filterSelfOut && self != null && self == it.text })
@@ -931,6 +985,7 @@ class ChatRoomPresenter @Inject constructor(
ChatRoom(
id = id,
subscriptionId = subscriptionId,
+ parentId = parentId,
type = roomTypeOf(type),
unread = unread,
broadcast = broadcast ?: false,
@@ -962,47 +1017,49 @@ class ChatRoomPresenter @Inject constructor(
}
// TODO: move this to new interactor or FetchChatRoomsInteractor?
- private suspend fun getChatRoomsAsync(name: String? = null): List = withContext(Dispatchers.IO) {
- retryDB("getAllSync()") {
- dbManager.chatRoomDao().getAllSync().filter {
- if (name == null) {
- return@filter true
- }
- it.chatRoom.name == name || it.chatRoom.fullname == name
- }.map {
- with(it.chatRoom) {
- ChatRoom(
- id = id,
- subscriptionId = subscriptionId,
- type = roomTypeOf(type),
- unread = unread,
- broadcast = broadcast ?: false,
- alert = alert,
- fullName = fullname,
- name = name ?: "",
- favorite = favorite ?: false,
- default = isDefault ?: false,
- readonly = readonly,
- open = open,
- lastMessage = null,
- archived = false,
- status = null,
- user = null,
- userMentions = userMentions,
- client = client,
- announcement = null,
- description = null,
- groupMentions = groupMentions,
- roles = null,
- topic = null,
- lastSeen = this.lastSeen,
- timestamp = timestamp,
- updatedAt = updatedAt
- )
+ private suspend fun getChatRoomsAsync(name: String? = null): List =
+ withContext(Dispatchers.IO) {
+ retryDB("getAllSync()") {
+ dbManager.chatRoomDao().getAllSync().filter {
+ if (name == null) {
+ return@filter true
+ }
+ it.chatRoom.name == name || it.chatRoom.fullname == name
+ }.map {
+ with(it.chatRoom) {
+ ChatRoom(
+ id = id,
+ subscriptionId = subscriptionId,
+ parentId = parentId,
+ type = roomTypeOf(type),
+ unread = unread,
+ broadcast = broadcast ?: false,
+ alert = alert,
+ fullName = fullname,
+ name = name ?: "",
+ favorite = favorite ?: false,
+ default = isDefault ?: false,
+ readonly = readonly,
+ open = open,
+ lastMessage = null,
+ archived = false,
+ status = null,
+ user = null,
+ userMentions = userMentions,
+ client = client,
+ announcement = null,
+ description = null,
+ groupMentions = groupMentions,
+ roles = null,
+ topic = null,
+ lastSeen = this.lastSeen,
+ timestamp = timestamp,
+ updatedAt = updatedAt
+ )
+ }
}
}
}
- }
fun joinChat(chatRoomId: String) {
launchUI(strategy) {
@@ -1011,7 +1068,8 @@ class ChatRoomPresenter @Inject constructor(
val canPost = permissions.canPostToReadOnlyChannels()
dbManager.getRoom(chatRoomId)?.let {
val roomUiModel = roomMapper.map(it, true).copy(
- writable = canPost)
+ writable = canPost
+ )
view.onJoined(roomUiModel = roomUiModel)
view.onRoomUpdated(roomUiModel = roomUiModel)
}
@@ -1098,6 +1156,31 @@ class ChatRoomPresenter @Inject constructor(
}
}
+ fun reactToLastMessage(text: String, roomId: String) {
+ launchUI(strategy) {
+ lastMessageId?.let { messageId ->
+ val emoji = text.substring(1).trimEnd()
+ if (emoji.length >= 2 && emoji.startsWith(":") && emoji.endsWith(":")) {
+ try {
+ retryIO("toggleEmoji($messageId, $emoji)") {
+ client.toggleReaction(messageId, emoji.removeSurrounding(":"))
+ }
+ logReactionEvent()
+ view.clearMessageComposition(true)
+ } catch (ex: RocketChatException) {
+ Timber.e(ex)
+ // emoji is not valid, post it
+ sendMessage(roomId, text, null)
+ }
+ } else {
+ sendMessage(roomId, text, null)
+ }
+ }.ifNull {
+ sendMessage(roomId, text, null)
+ }
+ }
+ }
+
private fun logReactionEvent() {
when {
roomTypeOf(chatRoomType) is RoomType.DirectMessage ->
@@ -1171,18 +1254,19 @@ class ChatRoomPresenter @Inject constructor(
sendMessage(roomId, text, null)
} else {
view.disableSendMessageButton()
- val command = text.split(" ")
- val name = command[0].substring(1)
+ val index = text.indexOf(" ")
+ var name = ""
var params = ""
- command.forEachIndexed { index, param ->
- if (index > 0) {
- params += "$param "
- }
+ if (index >= 1) {
+ name = text.substring(1, index)
+ params = text.substring(index + 1).trim()
}
val result = retryIO("runCommand($name, $params, $roomId)") {
client.runCommand(Command(name, params), roomId)
}
- if (!result) {
+ if (result) {
+ view.clearMessageComposition(true)
+ } else {
// failed, command is not valid so post it
sendMessage(roomId, text, null)
}
@@ -1260,7 +1344,7 @@ class ChatRoomPresenter @Inject constructor(
launchUI(strategy) {
val viewModelStreamedMessage = mapper.map(
streamedMessage, RoomUiModel(
- roles = chatRoles, isBroadcast = chatIsBroadcast, isRoom = true
+ roles = chatRoles, isBroadcast = isBroadcast, isRoom = true
)
)
val roomMessages = messagesRepository.getByRoomId(streamedMessage.roomId)
@@ -1295,6 +1379,7 @@ class ChatRoomPresenter @Inject constructor(
fun clearDraftMessage() {
localRepository.clear(draftKey)
}
+
/**
* Get unfinished message from local repository, when user left chat room without
* sending a message and now the user is back.
diff --git a/app/src/main/java/chat/rocket/android/chatroom/service/MessageService.kt b/app/src/main/java/chat/rocket/android/chatroom/service/MessageService.kt
index 14bdb6dbb7..53fbb16f2e 100644
--- a/app/src/main/java/chat/rocket/android/chatroom/service/MessageService.kt
+++ b/app/src/main/java/chat/rocket/android/chatroom/service/MessageService.kt
@@ -4,9 +4,9 @@ import android.app.job.JobParameters
import android.app.job.JobService
import chat.rocket.android.db.DatabaseManagerFactory
import chat.rocket.android.server.domain.GetAccountsInteractor
-import chat.rocket.android.server.infraestructure.ConnectionManagerFactory
-import chat.rocket.android.server.infraestructure.DatabaseMessageMapper
-import chat.rocket.android.server.infraestructure.DatabaseMessagesRepository
+import chat.rocket.android.server.infrastructure.ConnectionManagerFactory
+import chat.rocket.android.server.infrastructure.DatabaseMessageMapper
+import chat.rocket.android.server.infrastructure.DatabaseMessagesRepository
import chat.rocket.core.internal.rest.sendMessage
import chat.rocket.core.model.Message
import dagger.android.AndroidInjection
diff --git a/app/src/main/java/chat/rocket/android/chatroom/ui/ChatRoomActivity.kt b/app/src/main/java/chat/rocket/android/chatroom/ui/ChatRoomActivity.kt
index c881a45621..207a9f8a07 100644
--- a/app/src/main/java/chat/rocket/android/chatroom/ui/ChatRoomActivity.kt
+++ b/app/src/main/java/chat/rocket/android/chatroom/ui/ChatRoomActivity.kt
@@ -10,7 +10,7 @@ import androidx.fragment.app.Fragment
import chat.rocket.android.R
import chat.rocket.android.chatroom.presentation.ChatRoomNavigator
import chat.rocket.android.server.domain.GetCurrentServerInteractor
-import chat.rocket.android.server.infraestructure.ConnectionManagerFactory
+import chat.rocket.android.server.infrastructure.ConnectionManagerFactory
import chat.rocket.android.util.extensions.addFragment
import chat.rocket.android.util.extensions.textContent
import dagger.android.AndroidInjection
@@ -139,7 +139,7 @@ class ChatRoomActivity : AppCompatActivity(), HasSupportFragmentInjector {
}
fun setupExpandMoreForToolbar(listener: (View) -> Unit) {
- DrawableHelper.compoundRightDrawable(
+ DrawableHelper.compoundEndDrawable(
text_toolbar_title,
DrawableHelper.getDrawableFromId(R.drawable.ic_chatroom_toolbar_expand_more_20dp, this)
)
diff --git a/app/src/main/java/chat/rocket/android/chatroom/ui/ChatRoomFragment.kt b/app/src/main/java/chat/rocket/android/chatroom/ui/ChatRoomFragment.kt
index a597ebe238..9f60804723 100644
--- a/app/src/main/java/chat/rocket/android/chatroom/ui/ChatRoomFragment.kt
+++ b/app/src/main/java/chat/rocket/android/chatroom/ui/ChatRoomFragment.kt
@@ -5,6 +5,7 @@ import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Intent
+import android.content.pm.PackageManager
import android.graphics.drawable.Drawable
import android.net.Uri
import android.os.Bundle
@@ -28,14 +29,17 @@ import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.recyclerview.widget.DefaultItemAnimator
+import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import chat.rocket.android.R
import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.analytics.event.ScreenViewEvent
+import chat.rocket.android.chatroom.adapter.AttachmentViewHolder
import chat.rocket.android.chatroom.adapter.ChatRoomAdapter
import chat.rocket.android.chatroom.adapter.CommandSuggestionsAdapter
import chat.rocket.android.chatroom.adapter.EmojiSuggestionsAdapter
+import chat.rocket.android.chatroom.adapter.MessageViewHolder
import chat.rocket.android.chatroom.adapter.PEOPLE
import chat.rocket.android.chatroom.adapter.PeopleSuggestionsAdapter
import chat.rocket.android.chatroom.adapter.RoomSuggestionsAdapter
@@ -61,11 +65,16 @@ import chat.rocket.android.emoji.EmojiPickerPopup
import chat.rocket.android.emoji.EmojiReactionListener
import chat.rocket.android.emoji.internal.isCustom
import chat.rocket.android.helper.EndlessRecyclerViewScrollListener
-import chat.rocket.android.helper.ImageHelper
import chat.rocket.android.helper.KeyboardHelper
import chat.rocket.android.helper.MessageParser
+import chat.rocket.android.helper.AndroidPermissionsHelper
+import chat.rocket.android.helper.AndroidPermissionsHelper.getCameraPermission
+import chat.rocket.android.helper.AndroidPermissionsHelper.getWriteExternalStoragePermission
+import chat.rocket.android.helper.AndroidPermissionsHelper.hasCameraPermission
+import chat.rocket.android.helper.AndroidPermissionsHelper.hasWriteExternalStoragePermission
import chat.rocket.android.util.extension.asObservable
import chat.rocket.android.util.extension.createImageFile
+import chat.rocket.android.util.extension.orFalse
import chat.rocket.android.util.extensions.circularRevealOrUnreveal
import chat.rocket.android.util.extensions.clearLightStatusBar
import chat.rocket.android.util.extensions.fadeIn
@@ -81,6 +90,7 @@ import chat.rocket.common.model.RoomType
import chat.rocket.common.model.roomTypeOf
import chat.rocket.core.internal.realtime.socket.model.State
import com.bumptech.glide.Glide
+import com.google.android.material.snackbar.Snackbar
import dagger.android.support.AndroidSupportInjection
import io.reactivex.Observable
import io.reactivex.disposables.CompositeDisposable
@@ -149,7 +159,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
lateinit var analyticsManager: AnalyticsManager
@Inject
lateinit var navigator: ChatRoomNavigator
- private lateinit var adapter: ChatRoomAdapter
+ private lateinit var chatRoomAdapter: ChatRoomAdapter
internal lateinit var chatRoomId: String
private lateinit var chatRoomName: String
internal lateinit var chatRoomType: String
@@ -268,7 +278,6 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
AndroidSupportInjection.inject(this)
- setHasOptionsMenu(true)
arguments?.run {
chatRoomId = getString(BUNDLE_CHAT_ROOM_ID, "")
@@ -283,7 +292,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
}
?: requireNotNull(arguments) { "no arguments supplied when the fragment was instantiated" }
- adapter = ChatRoomAdapter(
+ chatRoomAdapter = ChatRoomAdapter(
roomId = chatRoomId,
roomType = chatRoomType,
roomName = chatRoomName,
@@ -292,6 +301,8 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
navigator = navigator,
analyticsManager = analyticsManager
)
+
+ setHasOptionsMenu(true)
}
override fun onCreateView(
@@ -380,7 +391,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
override fun showMessages(dataSet: List>, clearDataSet: Boolean) {
ui {
if (clearDataSet) {
- adapter.clearData()
+ chatRoomAdapter.clearData()
}
if (dataSet.isNotEmpty()) {
@@ -421,35 +432,22 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
}
}
- if (recycler_view.adapter == null) {
- recycler_view.adapter = adapter
- if (dataSet.size >= 30) {
- recycler_view.addOnScrollListener(endlessRecyclerViewScrollListener)
- }
- recycler_view.addOnLayoutChangeListener(layoutChangeListener)
- recycler_view.addOnScrollListener(onScrollListener)
-
- // Load just once, on the first page...
- presenter.loadActiveMembers(chatRoomId, chatRoomType, filterSelfOut = true)
- }
-
- val oldMessagesCount = adapter.itemCount
- adapter.appendData(dataSet)
+ val oldMessagesCount = chatRoomAdapter.itemCount
+ chatRoomAdapter.appendData(dataSet)
if (oldMessagesCount == 0 && dataSet.isNotEmpty()) {
recycler_view.scrollToPosition(0)
verticalScrollOffset.set(0)
}
- presenter.loadActiveMembers(chatRoomId, chatRoomType, filterSelfOut = true)
- empty_chat_view.isVisible = adapter.itemCount == 0
+ empty_chat_view.isVisible = chatRoomAdapter.itemCount == 0
dismissEmojiKeyboard()
}
}
override fun showSearchedMessages(dataSet: List>) {
recycler_view.removeOnScrollListener(endlessRecyclerViewScrollListener)
- adapter.clearData()
- adapter.prependData(dataSet)
- empty_chat_view.isVisible = adapter.itemCount == 0
+ chatRoomAdapter.clearData()
+ chatRoomAdapter.prependData(dataSet)
+ empty_chat_view.isVisible = chatRoomAdapter.itemCount == 0
dismissEmojiKeyboard()
}
@@ -460,21 +458,21 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
setupToolbar(roomUiModel.name.toString())
setupMessageComposer(roomUiModel)
isBroadcastChannel = roomUiModel.broadcast
- if (isBroadcastChannel && !roomUiModel.canModerate) {
- disableMenu = true
- activity?.invalidateOptionsMenu()
- }
+ isFavorite = roomUiModel.favorite.orFalse()
+ disableMenu = (roomUiModel.broadcast && !roomUiModel.canModerate)
+ activity?.invalidateOptionsMenu()
}
}
-
override fun sendMessage(text: String) {
ui {
if (!text.isBlank()) {
- if (!text.startsWith("/")) {
- presenter.sendMessage(chatRoomId, text, editingMessageId)
- } else {
+ if (text.startsWith("/")) {
presenter.runCommand(text, chatRoomId)
+ } else if (text.startsWith("+")) {
+ presenter.reactToLastMessage(text, chatRoomId)
+ } else {
+ presenter.sendMessage(chatRoomId, text, editingMessageId)
}
}
}
@@ -519,7 +517,6 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
}
}
-
override fun clearMessageComposition(deleteMessage: Boolean) {
ui {
citation = null
@@ -533,7 +530,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
override fun showNewMessage(message: List>, isMessageReceived: Boolean) {
ui {
- adapter.prependData(message)
+ chatRoomAdapter.prependData(message)
if (isMessageReceived && button_fab.isVisible) {
newMessageCount++
if (newMessageCount <= 99) {
@@ -546,7 +543,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
recycler_view.scrollToPosition(0)
}
verticalScrollOffset.set(0)
- empty_chat_view.isVisible = adapter.itemCount == 0
+ empty_chat_view.isVisible = chatRoomAdapter.itemCount == 0
dismissEmojiKeyboard()
}
}
@@ -556,9 +553,9 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
// TODO - investigate WHY we get a empty list here
if (message.isEmpty()) return@ui
- if (adapter.updateItem(message.last())) {
+ if (chatRoomAdapter.updateItem(message.last())) {
if (message.size > 1) {
- adapter.prependData(listOf(message.first()))
+ chatRoomAdapter.prependData(listOf(message.first()))
}
} else {
showNewMessage(message, true)
@@ -569,7 +566,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
override fun dispatchDeleteMessage(msgId: String) {
ui {
- adapter.removeItem(msgId)
+ chatRoomAdapter.removeItem(msgId)
}
}
@@ -596,45 +593,31 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
}
override fun showMessage(message: String) {
- ui {
- showToast(message)
- }
+ ui { showToast(message) }
}
override fun showMessage(resId: Int) {
- ui {
- showToast(resId)
- }
+ ui { showToast(resId) }
}
override fun showGenericErrorMessage() {
- ui {
- showMessage(getString(R.string.msg_generic_error))
- }
+ ui { showMessage(getString(R.string.msg_generic_error)) }
}
override fun populatePeopleSuggestions(members: List) {
- ui {
- suggestions_view.addItems("@", members)
- }
+ ui { suggestions_view.addItems("@", members) }
}
override fun populateRoomSuggestions(chatRooms: List) {
- ui {
- suggestions_view.addItems("#", chatRooms)
- }
+ ui { suggestions_view.addItems("#", chatRooms) }
}
override fun populateCommandSuggestions(commands: List) {
- ui {
- suggestions_view.addItems("/", commands)
- }
+ ui { suggestions_view.addItems("/", commands) }
}
override fun populateEmojiSuggestions(emojis: List) {
- ui {
- suggestions_view.addItems(":", emojis)
- }
+ ui { suggestions_view.addItems(":", emojis) }
}
override fun copyToClipboard(message: String) {
@@ -812,7 +795,56 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
presenter.loadMessages(chatRoomId, chatRoomType, page * 30L)
}
}
- recycler_view.addOnScrollListener(fabScrollListener)
+
+ with (recycler_view) {
+ adapter = chatRoomAdapter
+ addOnScrollListener(endlessRecyclerViewScrollListener)
+ addOnLayoutChangeListener(layoutChangeListener)
+ addOnScrollListener(onScrollListener)
+ addOnScrollListener(fabScrollListener)
+ }
+ if (!isReadOnly) {
+ val touchCallback: ItemTouchHelper.SimpleCallback =
+ object : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT) {
+ override fun onMove(
+ recyclerView: RecyclerView,
+ viewHolder: RecyclerView.ViewHolder,
+ target: RecyclerView.ViewHolder
+ ): Boolean {
+ return true
+ }
+
+ override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
+ var replyId: String? = null
+
+ when (viewHolder) {
+ is MessageViewHolder -> replyId = viewHolder.data?.messageId
+ is AttachmentViewHolder -> replyId = viewHolder.data?.messageId
+ }
+
+ replyId?.let {
+ citeMessage(chatRoomName, chatRoomType, it, true)
+ }
+
+ chatRoomAdapter.notifyItemChanged(viewHolder.adapterPosition)
+ }
+
+ override fun getSwipeDirs(
+ recyclerView: RecyclerView,
+ viewHolder: RecyclerView.ViewHolder
+ ): Int {
+ // Currently enable swipes for text and attachment messages only
+
+ if (viewHolder is MessageViewHolder || viewHolder is AttachmentViewHolder) {
+ return super.getSwipeDirs(recyclerView, viewHolder)
+ }
+
+ return 0
+ }
+ }
+
+ ItemTouchHelper(touchCallback).attachToRecyclerView(recycler_view)
+ }
}
private fun setupFab() {
@@ -903,8 +935,14 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
button_add_reaction_or_show_keyboard.setOnClickListener { toggleKeyboard() }
button_take_a_photo.setOnClickListener {
- dispatchTakePictureIntent()
-
+ // Check for camera permission
+ context?.let {
+ if (hasCameraPermission(it)) {
+ dispatchTakePictureIntent()
+ } else {
+ getCameraPermission(this)
+ }
+ }
handler.postDelayed({
hideAttachmentOptions()
}, 400)
@@ -922,11 +960,10 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
button_drawing.setOnClickListener {
activity?.let { fragmentActivity ->
- if (!ImageHelper.canWriteToExternalStorage(fragmentActivity)) {
- ImageHelper.checkWritingPermission(fragmentActivity)
+ if (!hasWriteExternalStoragePermission(fragmentActivity)) {
+ getWriteExternalStoragePermission(this)
} else {
- val intent = Intent(fragmentActivity, DrawingActivity::class.java)
- startActivityForResult(intent, REQUEST_CODE_FOR_DRAW)
+ dispatchDrawingIntent()
}
}
@@ -937,6 +974,11 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
}
}
+ private fun dispatchDrawingIntent() {
+ val intent = Intent(activity, DrawingActivity::class.java)
+ startActivityForResult(intent, REQUEST_CODE_FOR_DRAW)
+ }
+
private fun dispatchTakePictureIntent() {
Intent(MediaStore.ACTION_IMAGE_CAPTURE).also { takePictureIntent ->
// Create the File where the photo should go
@@ -957,6 +999,44 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
}
}
+ override fun onRequestPermissionsResult(
+ requestCode: Int,
+ permissions: Array,
+ grantResults: IntArray
+ ) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults)
+ when (requestCode) {
+ AndroidPermissionsHelper.CAMERA_CODE -> {
+ if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ // permission was granted
+ dispatchTakePictureIntent()
+ } else {
+ // permission denied
+ Snackbar.make(
+ root_layout,
+ R.string.msg_camera_permission_denied,
+ Snackbar.LENGTH_SHORT
+ ).show()
+ }
+ return
+ }
+ AndroidPermissionsHelper.WRITE_EXTERNAL_STORAGE_CODE -> {
+ if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ // permission was granted
+ dispatchDrawingIntent()
+ } else {
+ // permission denied
+ Snackbar.make(
+ root_layout,
+ R.string.msg_storage_permission_denied,
+ Snackbar.LENGTH_SHORT
+ ).show()
+ }
+ return
+ }
+ }
+ }
+
private fun getDraftMessage() {
val unfinishedMessage = presenter.getDraftUnfinishedMessage()
if (unfinishedMessage.isNotNullNorEmpty()) {
diff --git a/app/src/main/java/chat/rocket/android/chatroom/uimodel/UiModelMapper.kt b/app/src/main/java/chat/rocket/android/chatroom/uimodel/UiModelMapper.kt
index 3cdd187d40..4a1be35286 100644
--- a/app/src/main/java/chat/rocket/android/chatroom/uimodel/UiModelMapper.kt
+++ b/app/src/main/java/chat/rocket/android/chatroom/uimodel/UiModelMapper.kt
@@ -30,7 +30,7 @@ import chat.rocket.android.server.domain.baseUrl
import chat.rocket.android.server.domain.messageReadReceiptEnabled
import chat.rocket.android.server.domain.messageReadReceiptStoreUsers
import chat.rocket.android.server.domain.useRealName
-import chat.rocket.android.server.infraestructure.ConnectionManagerFactory
+import chat.rocket.android.server.infrastructure.ConnectionManagerFactory
import chat.rocket.android.util.extension.isImage
import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.android.util.extensions.ifNotNullNorEmpty
@@ -108,7 +108,7 @@ class UiModelMapper @Inject constructor(
readReceipts.forEach {
list.add(
ReadReceiptViewModel(
- avatar = baseUrl.avatarUrl(it.user.username ?: ""),
+ avatar = baseUrl.avatarUrl(it.user.username!!, token?.userId, token?.authToken),
name = userHelper.displayName(it.user),
time = DateTimeHelper.getTime(DateTimeHelper.getLocalDateTime(it.timestamp))
)
@@ -173,6 +173,7 @@ class UiModelMapper @Inject constructor(
ChatRoom(
id = id,
subscriptionId = subscriptionId,
+ parentId = parentId,
type = roomTypeOf(type),
unread = unread,
broadcast = broadcast ?: false,
@@ -527,7 +528,7 @@ class UiModelMapper @Inject constructor(
val username = message.sender?.username ?: "?"
return baseUrl.let {
- baseUrl.avatarUrl(username)
+ baseUrl.avatarUrl(username, token?.userId, token?.authToken)
}
}
diff --git a/app/src/main/java/chat/rocket/android/chatrooms/adapter/RoomUiModelMapper.kt b/app/src/main/java/chat/rocket/android/chatrooms/adapter/RoomUiModelMapper.kt
index 0dc298d137..739f4adbc6 100644
--- a/app/src/main/java/chat/rocket/android/chatrooms/adapter/RoomUiModelMapper.kt
+++ b/app/src/main/java/chat/rocket/android/chatrooms/adapter/RoomUiModelMapper.kt
@@ -8,11 +8,13 @@ import chat.rocket.android.db.model.ChatRoom
import chat.rocket.android.server.domain.GetCurrentUserInteractor
import chat.rocket.android.server.domain.PermissionsInteractor
import chat.rocket.android.server.domain.PublicSettings
+import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.domain.showLastMessage
import chat.rocket.android.server.domain.useRealName
import chat.rocket.android.server.domain.useSpecialCharsOnRoom
import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.android.util.extensions.date
+import chat.rocket.android.util.extensions.isNotNullNorEmpty
import chat.rocket.android.util.extensions.localDateTime
import chat.rocket.common.model.RoomType
import chat.rocket.common.model.User
@@ -26,10 +28,12 @@ class RoomUiModelMapper(
private val context: Application,
private val settings: PublicSettings,
private val userInteractor: GetCurrentUserInteractor,
+ private val tokenRepository: TokenRepository,
private val serverUrl: String,
private val permissions: PermissionsInteractor
) {
private val currentUser by lazy { userInteractor.get() }
+ private val token by lazy { tokenRepository.get(serverUrl) }
fun map(
rooms: List,
@@ -80,7 +84,7 @@ class RoomUiModelMapper(
private fun mapUser(user: User): RoomUiModel = with(user) {
val name = mapName(user.username!!, user.name)
val status = user.status
- val avatar = serverUrl.avatarUrl(user.username!!)
+ val avatar = serverUrl.avatarUrl(user.username!!, token?.userId, token?.authToken)
val username = user.username!!
RoomUiModel(
@@ -98,7 +102,7 @@ class RoomUiModelMapper(
id = id,
name = name!!,
type = type,
- avatar = serverUrl.avatarUrl(name!!, isGroupOrChannel = true),
+ avatar = serverUrl.avatarUrl(name!!, token?.userId, token?.authToken, isGroupOrChannel = true),
lastMessage = if (showLastMessage) {
mapLastMessage(
lastMessage?.sender?.id,
@@ -115,36 +119,40 @@ class RoomUiModelMapper(
)
}
- fun map(chatRoom: ChatRoom, showLastMessage: Boolean = true): RoomUiModel = with(chatRoom.chatRoom) {
- val isUnread = alert || unread > 0
- val type = roomTypeOf(type)
- val status = chatRoom.status?.let { userStatusOf(it) }
- val roomName = mapName(name, fullname)
- val favorite = favorite
- val timestamp = mapDate(lastMessageTimestamp ?: updatedAt)
- val avatar = if (type is RoomType.DirectMessage) {
- serverUrl.avatarUrl(name)
- } else {
- serverUrl.avatarUrl(name, isGroupOrChannel = true)
- }
- val unread = mapUnread(unread)
- val lastMessage = if (showLastMessage) {
- mapLastMessage(
+ fun map(chatRoom: ChatRoom, showLastMessage: Boolean = true): RoomUiModel =
+ with(chatRoom.chatRoom) {
+ val isUnread = alert || unread > 0
+ val type = roomTypeOf(type)
+ val status = chatRoom.status?.let { userStatusOf(it) }
+ val roomName = mapName(name, fullname)
+ val favorite = favorite
+ val timestamp = mapDate(lastMessageTimestamp ?: updatedAt)
+ val avatar =
+ if (type is RoomType.DirectMessage) {
+ serverUrl.avatarUrl(name, token?.userId, token?.authToken)
+ } else {
+ serverUrl.avatarUrl(name, token?.userId, token?.authToken, isGroupOrChannel = true)
+ }
+ val unread = mapUnread(unread)
+ val lastMessage = if (showLastMessage) {
+ mapLastMessage(
lastMessageUserId,
chatRoom.lastMessageUserName,
chatRoom.lastMessageUserFullName,
lastMessageText,
type is RoomType.DirectMessage
- )
- } else {
- null
- }
- val hasMentions = mapMentions(userMentions, groupMentions)
- val open = open
- val lastMessageMarkdown = lastMessage?.let { Markwon.markdown(context, it.toString()).toString() }
+ )
+ } else {
+ null
+ }
+ val hasMentions = mapMentions(userMentions, groupMentions)
+ val open = open
+ val lastMessageMarkdown =
+ lastMessage?.let { Markwon.markdown(context, it.toString()).toString() }
- RoomUiModel(
+ RoomUiModel(
id = id,
+ isDiscussion = parentId.isNotNullNorEmpty(),
name = roomName,
type = type,
avatar = avatar,
@@ -159,8 +167,8 @@ class RoomUiModelMapper(
username = if (type is RoomType.DirectMessage) name else null,
muted = muted.orEmpty(),
writable = isChannelWritable(muted)
- )
- }
+ )
+ }
private fun isChannelWritable(muted: List?): Boolean {
val canWriteToReadOnlyChannels = permissions.canPostToReadOnlyChannels()
@@ -169,7 +177,7 @@ class RoomUiModelMapper(
private fun roomType(type: String): String = with(context.resources) {
when (type) {
- RoomType.CHANNEL -> getString(R.string.header_channel)
+ RoomType.CHANNEL -> getString(R.string.msg_channels)
RoomType.PRIVATE_GROUP -> getString(R.string.header_private_groups)
RoomType.DIRECT_MESSAGE -> getString(R.string.header_direct_messages)
RoomType.LIVECHAT -> getString(R.string.header_live_chats)
diff --git a/app/src/main/java/chat/rocket/android/chatrooms/adapter/RoomViewHolder.kt b/app/src/main/java/chat/rocket/android/chatrooms/adapter/RoomViewHolder.kt
index 2317178adf..9a4da09a36 100644
--- a/app/src/main/java/chat/rocket/android/chatrooms/adapter/RoomViewHolder.kt
+++ b/app/src/main/java/chat/rocket/android/chatrooms/adapter/RoomViewHolder.kt
@@ -3,6 +3,7 @@ package chat.rocket.android.chatrooms.adapter
import android.content.res.Resources
import android.graphics.drawable.Drawable
import android.view.View
+import android.widget.TextView
import androidx.core.view.isGone
import androidx.core.view.isInvisible
import androidx.core.view.isVisible
@@ -11,14 +12,17 @@ import chat.rocket.android.chatrooms.adapter.model.RoomUiModel
import chat.rocket.android.util.extension.setTextViewAppearance
import chat.rocket.common.model.RoomType
import chat.rocket.common.model.UserStatus
+import com.bumptech.glide.Glide
+import com.bumptech.glide.load.resource.bitmap.RoundedCorners
+import com.bumptech.glide.request.RequestOptions
import kotlinx.android.synthetic.main.item_chat.view.*
-import kotlinx.android.synthetic.main.unread_messages_badge.view.*
class RoomViewHolder(itemView: View, private val listener: (RoomUiModel) -> Unit) :
ViewHolder(itemView) {
private val resources: Resources = itemView.resources
private val channelIcon: Drawable = resources.getDrawable(R.drawable.ic_hashtag_12dp, null)
private val groupIcon: Drawable = resources.getDrawable(R.drawable.ic_lock_12_dp, null)
+ private val discussionIcon: Drawable = resources.getDrawable(R.drawable.ic_discussion_20dp, null)
private val onlineIcon: Drawable = resources.getDrawable(R.drawable.ic_status_online_12dp, null)
private val awayIcon: Drawable = resources.getDrawable(R.drawable.ic_status_away_12dp, null)
private val busyIcon: Drawable = resources.getDrawable(R.drawable.ic_status_busy_12dp, null)
@@ -27,10 +31,16 @@ class RoomViewHolder(itemView: View, private val listener: (RoomUiModel) -> Unit
override fun bindViews(data: RoomItemHolder) {
val room = data.data
with(itemView) {
- image_avatar.setImageURI(room.avatar)
+ Glide.with(image_avatar.context)
+ .load(room.avatar)
+ .apply(RequestOptions.bitmapTransform(RoundedCorners(10)))
+ .into(image_avatar)
+
text_chat_name.text = room.name
- if (room.status != null && room.type is RoomType.DirectMessage) {
+ if (room.isDiscussion) {
+ image_chat_icon.setImageDrawable(discussionIcon)
+ } else if (room.status != null && room.type is RoomType.DirectMessage) {
image_chat_icon.setImageDrawable(getStatusDrawable(room.status))
} else {
image_chat_icon.setImageDrawable(getRoomDrawable(room.type))
@@ -51,6 +61,7 @@ class RoomViewHolder(itemView: View, private val listener: (RoomUiModel) -> Unit
}
if (room.alert) {
+ val text_total_unread_messages = text_total_unread_messages as TextView
if (room.unread == null) text_total_unread_messages.text = "!"
if (room.unread != null) text_total_unread_messages.text = room.unread
if (room.mentions) text_total_unread_messages.text = "@${room.unread}"
diff --git a/app/src/main/java/chat/rocket/android/chatrooms/adapter/model/RoomUiModel.kt b/app/src/main/java/chat/rocket/android/chatrooms/adapter/model/RoomUiModel.kt
index 8531d41a70..4b536b3d4f 100644
--- a/app/src/main/java/chat/rocket/android/chatrooms/adapter/model/RoomUiModel.kt
+++ b/app/src/main/java/chat/rocket/android/chatrooms/adapter/model/RoomUiModel.kt
@@ -5,6 +5,7 @@ import chat.rocket.common.model.UserStatus
data class RoomUiModel(
val id: String,
+ val isDiscussion: Boolean = false,
val type: RoomType,
val name: CharSequence,
val avatar: String,
diff --git a/app/src/main/java/chat/rocket/android/chatrooms/di/ChatRoomsFragmentModule.kt b/app/src/main/java/chat/rocket/android/chatrooms/di/ChatRoomsFragmentModule.kt
index f231837cd1..bea2578b3a 100644
--- a/app/src/main/java/chat/rocket/android/chatrooms/di/ChatRoomsFragmentModule.kt
+++ b/app/src/main/java/chat/rocket/android/chatrooms/di/ChatRoomsFragmentModule.kt
@@ -10,15 +10,14 @@ import chat.rocket.android.dagger.scope.PerFragment
import chat.rocket.android.db.ChatRoomDao
import chat.rocket.android.db.DatabaseManager
import chat.rocket.android.db.UserDao
-import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.server.domain.GetCurrentUserInteractor
import chat.rocket.android.server.domain.PermissionsInteractor
import chat.rocket.android.server.domain.PublicSettings
import chat.rocket.android.server.domain.SettingsRepository
import chat.rocket.android.server.domain.TokenRepository
-import chat.rocket.android.server.infraestructure.ConnectionManager
-import chat.rocket.android.server.infraestructure.ConnectionManagerFactory
-import chat.rocket.android.server.infraestructure.RocketChatClientFactory
+import chat.rocket.android.server.infrastructure.ConnectionManager
+import chat.rocket.android.server.infrastructure.ConnectionManagerFactory
+import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.core.RocketChatClient
import dagger.Module
import dagger.Provides
@@ -45,7 +44,7 @@ class ChatRoomsFragmentModule {
factory: RocketChatClientFactory,
@Named("currentServer") currentServer: String
): RocketChatClient {
- return factory.create(currentServer)
+ return factory.get(currentServer)
}
@Provides
@@ -87,12 +86,20 @@ class ChatRoomsFragmentModule {
@PerFragment
fun provideRoomMapper(
context: Application,
- repository: SettingsRepository,
+ settingsRepository: SettingsRepository,
userInteractor: GetCurrentUserInteractor,
+ tokenRepository: TokenRepository,
@Named("currentServer") serverUrl: String,
permissionsInteractor: PermissionsInteractor
): RoomUiModelMapper {
- return RoomUiModelMapper(context, repository.get(serverUrl), userInteractor, serverUrl, permissionsInteractor)
+ return RoomUiModelMapper(
+ context,
+ settingsRepository.get(serverUrl),
+ userInteractor,
+ tokenRepository,
+ serverUrl,
+ permissionsInteractor
+ )
}
@Provides
diff --git a/app/src/main/java/chat/rocket/android/chatrooms/infrastructure/ChatRoomsRepository.kt b/app/src/main/java/chat/rocket/android/chatrooms/infrastructure/ChatRoomsRepository.kt
index 41850a4cb1..96695c4039 100644
--- a/app/src/main/java/chat/rocket/android/chatrooms/infrastructure/ChatRoomsRepository.kt
+++ b/app/src/main/java/chat/rocket/android/chatrooms/infrastructure/ChatRoomsRepository.kt
@@ -15,6 +15,10 @@ class ChatRoomsRepository @Inject constructor(private val dao: ChatRoomDao) {
Order.GROUPED_ACTIVITY -> dao.getAllGrouped()
Order.NAME -> dao.getAllAlphabetically()
Order.GROUPED_NAME -> dao.getAllAlphabeticallyGrouped()
+ Order.UNREAD_ON_TOP_ACTIVITY -> dao.getAllUnread();
+ Order.UNREAD_ON_TOP_NAME -> dao.getAllAlphabeticallyUnread();
+ Order.UNREAD_ON_TOP_GROUPED_ACTIVITY -> dao.getAllGroupedUnread();
+ Order.UNREAD_ON_TOP_GROUPED_NAME -> dao.getAllAlphabeticallyGroupedUnread();
}
}
@@ -28,8 +32,16 @@ class ChatRoomsRepository @Inject constructor(private val dao: ChatRoomDao) {
GROUPED_ACTIVITY,
NAME,
GROUPED_NAME,
+ UNREAD_ON_TOP_ACTIVITY,
+ UNREAD_ON_TOP_NAME,
+ UNREAD_ON_TOP_GROUPED_ACTIVITY,
+ UNREAD_ON_TOP_GROUPED_NAME
}
}
fun ChatRoomsRepository.Order.isGrouped(): Boolean = this == ChatRoomsRepository.Order.GROUPED_ACTIVITY
- || this == ChatRoomsRepository.Order.GROUPED_NAME
\ No newline at end of file
+ || this == ChatRoomsRepository.Order.GROUPED_NAME
+
+fun ChatRoomsRepository.Order.isUnreadOnTop(): Boolean = this == ChatRoomsRepository.Order.UNREAD_ON_TOP_ACTIVITY
+ || this == ChatRoomsRepository.Order.UNREAD_ON_TOP_NAME
+
diff --git a/app/src/main/java/chat/rocket/android/chatrooms/presentation/ChatRoomsPresenter.kt b/app/src/main/java/chat/rocket/android/chatrooms/presentation/ChatRoomsPresenter.kt
index 4f1ee432d2..5646f96bb3 100644
--- a/app/src/main/java/chat/rocket/android/chatrooms/presentation/ChatRoomsPresenter.kt
+++ b/app/src/main/java/chat/rocket/android/chatrooms/presentation/ChatRoomsPresenter.kt
@@ -10,9 +10,11 @@ import chat.rocket.android.helper.UserHelper
import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.main.presentation.MainNavigator
import chat.rocket.android.server.domain.SettingsRepository
+import chat.rocket.android.server.domain.SortingAndGroupingInteractor
+import chat.rocket.android.server.domain.siteName
import chat.rocket.android.server.domain.useRealName
import chat.rocket.android.server.domain.useSpecialCharsOnRoom
-import chat.rocket.android.server.infraestructure.ConnectionManager
+import chat.rocket.android.server.infrastructure.ConnectionManager
import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.retryDB
import chat.rocket.android.util.retryIO
@@ -35,6 +37,7 @@ class ChatRoomsPresenter @Inject constructor(
private val strategy: CancelStrategy,
private val navigator: MainNavigator,
@Named("currentServer") private val currentServer: String,
+ private val sortingAndGroupingInteractor: SortingAndGroupingInteractor,
private val dbManager: DatabaseManager,
manager: ConnectionManager,
private val localRepository: LocalRepository,
@@ -44,29 +47,44 @@ class ChatRoomsPresenter @Inject constructor(
private val client = manager.client
private val settings = settingsRepository.get(currentServer)
+ fun toCreateChannel() = navigator.toCreateChannel()
+
+ fun toSettings() = navigator.toSettings()
+
+ fun toDirectory() = navigator.toDirectory()
+
+ fun getCurrentServerName() = view.setupToolbar(settings.siteName() ?: currentServer)
+
+ fun getSortingAndGroupingPreferences() {
+ with(sortingAndGroupingInteractor) {
+ view.setupSortingAndGrouping(
+ getSortByName(currentServer),
+ getUnreadOnTop(currentServer),
+ getGroupByType(currentServer),
+ getGroupByFavorites(currentServer)
+ )
+ }
+ }
+
fun loadChatRoom(roomId: String) {
launchUI(strategy) {
- view.showLoadingRoom("")
try {
val room = dbManager.getRoom(roomId)
if (room != null) {
loadChatRoom(room.chatRoom, true)
} else {
- Timber.d("Error loading channel")
+ Timber.e("Error loading channel")
view.showGenericErrorMessage()
}
} catch (ex: Exception) {
- Timber.d(ex, "Error loading channel")
+ Timber.e(ex, "Error loading channel")
view.showGenericErrorMessage()
- } finally {
- view.hideLoadingRoom()
}
}
}
fun loadChatRoom(chatRoom: RoomUiModel) {
launchUI(strategy) {
- view.showLoadingRoom(chatRoom.name)
try {
val room = retryDB("getRoom(${chatRoom.id}") { dbManager.getRoom(chatRoom.id) }
if (room != null) {
@@ -76,6 +94,7 @@ class ChatRoomsPresenter @Inject constructor(
val entity = ChatRoomEntity(
id = id,
subscriptionId = "",
+ parentId = null,
type = type.toString(),
name = username ?: name.toString(),
fullname = name.toString(),
@@ -86,10 +105,8 @@ class ChatRoomsPresenter @Inject constructor(
}
}
} catch (ex: Exception) {
- Timber.d(ex, "Error loading channel")
+ Timber.e(ex, "Error loading channel")
view.showGenericErrorMessage()
- } finally {
- view.hideLoadingRoom()
}
}
}
@@ -97,11 +114,12 @@ class ChatRoomsPresenter @Inject constructor(
suspend fun loadChatRoom(chatRoom: ChatRoomEntity, local: Boolean = false) {
with(chatRoom) {
val isDirectMessage = roomTypeOf(type) is RoomType.DirectMessage
- val roomName = if (settings.useSpecialCharsOnRoom() || (isDirectMessage && settings.useRealName())) {
- fullname ?: name
- } else {
- name
- }
+ val roomName =
+ if (settings.useSpecialCharsOnRoom() || (isDirectMessage && settings.useRealName())) {
+ fullname ?: name
+ } else {
+ name
+ }
val myself = getCurrentUser()
if (myself?.username == null) {
@@ -131,14 +149,14 @@ class ChatRoomsPresenter @Inject constructor(
}
navigator.toChatRoom(
- chatRoomId = id,
- chatRoomName = roomName,
- chatRoomType = type,
- isReadOnly = readonly ?: false,
- chatRoomLastSeen = lastSeen ?: -1,
- isSubscribed = open,
- isCreator = ownerId == myself.id || isDirectMessage,
- isFavorite = favorite ?: false
+ chatRoomId = id,
+ chatRoomName = roomName,
+ chatRoomType = type,
+ isReadOnly = readonly ?: false,
+ chatRoomLastSeen = lastSeen ?: -1,
+ isSubscribed = open,
+ isCreator = ownerId == myself.id || isDirectMessage,
+ isFavorite = favorite ?: false
)
}
}
diff --git a/app/src/main/java/chat/rocket/android/chatrooms/presentation/ChatRoomsView.kt b/app/src/main/java/chat/rocket/android/chatrooms/presentation/ChatRoomsView.kt
index 638abd4234..e40130f71f 100644
--- a/app/src/main/java/chat/rocket/android/chatrooms/presentation/ChatRoomsView.kt
+++ b/app/src/main/java/chat/rocket/android/chatrooms/presentation/ChatRoomsView.kt
@@ -4,7 +4,27 @@ import chat.rocket.android.core.behaviours.LoadingView
import chat.rocket.android.core.behaviours.MessageView
interface ChatRoomsView : LoadingView, MessageView {
- fun showLoadingRoom(name: CharSequence)
- fun hideLoadingRoom()
+ /**
+ * Setups the toolbar with the current logged in server name.
+ *
+ * @param serverName The current logged in server name to show on Toolbar.
+ */
+ fun setupToolbar(serverName: String)
+
+ /**
+ * Setups the sorting and grouping in the bases of the user preference for
+ * the current logged in server.
+ *
+ * @param isSortByName True if sorting by name, false otherwise.
+ * @param isUnreadOnTop True if grouping by unread on top, false otherwise.
+ * @param isGroupByType True if grouping by type , false otherwise.
+ * @param isGroupByFavorites True if grouping by favorites, false otherwise.
+ */
+ fun setupSortingAndGrouping(
+ isSortByName: Boolean,
+ isUnreadOnTop: Boolean,
+ isGroupByType: Boolean,
+ isGroupByFavorites: Boolean
+ )
}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/chatrooms/ui/ChatRoomsFragment.kt b/app/src/main/java/chat/rocket/android/chatrooms/ui/ChatRoomsFragment.kt
index 58f3355722..33bb481171 100644
--- a/app/src/main/java/chat/rocket/android/chatrooms/ui/ChatRoomsFragment.kt
+++ b/app/src/main/java/chat/rocket/android/chatrooms/ui/ChatRoomsFragment.kt
@@ -1,19 +1,15 @@
package chat.rocket.android.chatrooms.ui
-import androidx.appcompat.app.AlertDialog
-import android.app.ProgressDialog
import android.os.Bundle
-import android.os.Handler
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
-import android.widget.CheckBox
-import android.widget.RadioGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.SearchView
+import androidx.core.view.isGone
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
@@ -30,12 +26,9 @@ import chat.rocket.android.chatrooms.viewmodel.ChatRoomsViewModel
import chat.rocket.android.chatrooms.viewmodel.ChatRoomsViewModelFactory
import chat.rocket.android.chatrooms.viewmodel.LoadingState
import chat.rocket.android.chatrooms.viewmodel.Query
-import chat.rocket.android.helper.ChatRoomsSortOrder
-import chat.rocket.android.helper.Constants
-import chat.rocket.android.helper.SharedPreferenceHelper
+import chat.rocket.android.servers.ui.ServersBottomSheetFragment
+import chat.rocket.android.sortingandgrouping.ui.SortingAndGroupingBottomSheetFragment
import chat.rocket.android.util.extension.onQueryTextListener
-import chat.rocket.android.util.extensions.fadeIn
-import chat.rocket.android.util.extensions.fadeOut
import chat.rocket.android.util.extensions.ifNotNullNotEmpty
import chat.rocket.android.util.extensions.inflate
import chat.rocket.android.util.extensions.showToast
@@ -43,6 +36,7 @@ import chat.rocket.android.util.extensions.ui
import chat.rocket.android.widget.DividerItemDecoration
import chat.rocket.core.internal.realtime.socket.model.State
import dagger.android.support.AndroidSupportInjection
+import kotlinx.android.synthetic.main.app_bar_chat_rooms.*
import kotlinx.android.synthetic.main.fragment_chat_rooms.*
import timber.log.Timber
import javax.inject.Inject
@@ -51,46 +45,37 @@ internal const val TAG_CHAT_ROOMS_FRAGMENT = "ChatRoomsFragment"
private const val BUNDLE_CHAT_ROOM_ID = "BUNDLE_CHAT_ROOM_ID"
-class ChatRoomsFragment : Fragment(), ChatRoomsView {
- @Inject
- lateinit var presenter: ChatRoomsPresenter
- @Inject
- lateinit var factory: ChatRoomsViewModelFactory
- @Inject
- lateinit var analyticsManager: AnalyticsManager
+fun newInstance(chatRoomId: String?): Fragment = ChatRoomsFragment().apply {
+ arguments = Bundle(1).apply {
+ putString(BUNDLE_CHAT_ROOM_ID, chatRoomId)
+ }
+}
+class ChatRoomsFragment : Fragment(), ChatRoomsView {
+ @Inject lateinit var presenter: ChatRoomsPresenter
+ @Inject lateinit var factory: ChatRoomsViewModelFactory
+ @Inject lateinit var analyticsManager: AnalyticsManager
private lateinit var viewModel: ChatRoomsViewModel
-
- private var searchView: SearchView? = null
- private var sortView: MenuItem? = null
- private val handler = Handler()
private var chatRoomId: String? = null
- private var progressDialog: ProgressDialog? = null
-
- companion object {
- fun newInstance(chatRoomId: String? = null): ChatRoomsFragment = ChatRoomsFragment().apply {
- arguments = Bundle(1).apply {
- putString(BUNDLE_CHAT_ROOM_ID, chatRoomId)
- }
- }
- }
+ private var isSortByName = false
+ private var isUnreadOnTop = false
+ private var isGroupByType = false
+ private var isGroupByFavorites = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
AndroidSupportInjection.inject(this)
- setHasOptionsMenu(true)
+
arguments?.run {
chatRoomId = getString(BUNDLE_CHAT_ROOM_ID)
- chatRoomId.ifNotNullNotEmpty { roomId ->
- presenter.loadChatRoom(roomId)
+
+ chatRoomId.ifNotNullNotEmpty {
+ presenter.loadChatRoom(it)
chatRoomId = null
}
}
- }
- override fun onDestroy() {
- handler.removeCallbacks(dismissStatus)
- super.onDestroy()
+ setHasOptionsMenu(true)
}
override fun onCreateView(
@@ -102,62 +87,48 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
+ with(presenter) {
+ getCurrentServerName()
+ getSortingAndGroupingPreferences()
+ }
+
viewModel = ViewModelProviders.of(this, factory).get(ChatRoomsViewModel::class.java)
subscribeUi()
-
- setupToolbar()
+ setupListeners()
analyticsManager.logScreenView(ScreenViewEvent.ChatRooms)
}
- private fun subscribeUi() {
- ui {
- val adapter = RoomsAdapter { room ->
- presenter.loadChatRoom(room)
+ override fun setupToolbar(serverName: String) {
+ with((activity as AppCompatActivity)) {
+ with(toolbar) {
+ setSupportActionBar(this)
+ supportActionBar?.setDisplayShowTitleEnabled(false)
+ setNavigationOnClickListener { presenter.toSettings() }
}
+ }
+ text_server_name.text = serverName
+ }
- recycler_view.layoutManager = LinearLayoutManager(it)
- recycler_view.addItemDecoration(
- DividerItemDecoration(
- it,
- resources.getDimensionPixelSize(R.dimen.divider_item_decorator_bound_start),
- resources.getDimensionPixelSize(R.dimen.divider_item_decorator_bound_end)
- )
+ override fun setupSortingAndGrouping(
+ isSortByName: Boolean,
+ isUnreadOnTop: Boolean,
+ isGroupByType: Boolean,
+ isGroupByFavorites: Boolean
+ ) {
+ this.isSortByName = isSortByName
+ this.isUnreadOnTop = isUnreadOnTop
+ this.isGroupByType = isGroupByType
+ this.isGroupByFavorites = isGroupByFavorites
+
+ if (isSortByName) {
+ text_sort_by.text =
+ getString(R.string.msg_sort_by_placeholder, getString(R.string.msg_sort_by_name).toLowerCase())
+ } else {
+ text_sort_by.text = getString(
+ R.string.msg_sort_by_placeholder,
+ getString(R.string.msg_sort_by_activity).toLowerCase()
)
- recycler_view.itemAnimator = DefaultItemAnimator()
-
- viewModel.getChatRooms().observe(viewLifecycleOwner, Observer { rooms ->
- rooms?.let {
- Timber.d("Got items: $it")
- adapter.values = it
- if (recycler_view.adapter != adapter) {
- recycler_view.adapter = adapter
- }
- if (rooms.isNotEmpty()) {
- text_no_data_to_display.isVisible = false
- }
- }
- })
-
- viewModel.loadingState.observe(viewLifecycleOwner, Observer { state ->
- when (state) {
- is LoadingState.Loading -> if (state.count == 0L) showLoading()
- is LoadingState.Loaded -> {
- hideLoading()
- if (state.count == 0L) showNoChatRoomsToDisplay()
- }
- is LoadingState.Error -> {
- hideLoading()
- showGenericErrorMessage()
- }
- }
- })
-
- viewModel.getStatus().observe(viewLifecycleOwner, Observer { status ->
- status?.let { showConnectionState(status) }
- })
-
- updateSort()
}
}
@@ -165,120 +136,42 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
super.onCreateOptionsMenu(menu, inflater)
inflater.inflate(R.menu.chatrooms, menu)
- sortView = menu.findItem(R.id.action_sort)
+ val searchMenuItem = menu.findItem(R.id.action_search)
+ val searchView = searchMenuItem?.actionView as SearchView
- val searchItem = menu.findItem(R.id.action_search)
- searchView = searchItem?.actionView as? SearchView
- searchView?.setIconifiedByDefault(false)
- searchView?.maxWidth = Integer.MAX_VALUE
- searchView?.onQueryTextListener { queryChatRoomsByName(it) }
+ with(searchView) {
+ setIconifiedByDefault(false)
+ maxWidth = Integer.MAX_VALUE
+ onQueryTextListener { queryChatRoomsByName(it) }
+ }
- val expandListener = object : MenuItem.OnActionExpandListener {
+ searchMenuItem.setOnActionExpandListener(object : MenuItem.OnActionExpandListener {
override fun onMenuItemActionCollapse(item: MenuItem): Boolean {
- // Simply setting sortView to visible won't work, so we invalidate the options
- // to recreate the entire menu...
- viewModel.showLastMessage = true
+ // We need to show all the menu items here by invalidating the options to recreate the entire menu.
activity?.invalidateOptionsMenu()
queryChatRoomsByName(null)
+ hideDirectoryView()
return true
}
override fun onMenuItemActionExpand(item: MenuItem): Boolean {
- viewModel.showLastMessage = false
- sortView?.isVisible = false
+ // We need to hide the all the menu items here.
+ menu.findItem(R.id.action_new_channel).isVisible = false
+ showDirectoryView()
return true
}
- }
- searchItem?.setOnActionExpandListener(expandListener)
+ })
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
- // TODO - simplify this
- R.id.action_sort -> {
- val dialogLayout = layoutInflater.inflate(R.layout.chatroom_sort_dialog, null)
- val sortType = SharedPreferenceHelper.getInt(
- Constants.CHATROOM_SORT_TYPE_KEY,
- ChatRoomsSortOrder.ACTIVITY
- )
- val groupByType =
- SharedPreferenceHelper.getBoolean(Constants.CHATROOM_GROUP_BY_TYPE_KEY, false)
-
- val radioGroup = dialogLayout.findViewById(R.id.radio_group_sort)
- val groupByTypeCheckBox =
- dialogLayout.findViewById(R.id.checkbox_group_by_type)
-
- radioGroup.check(
- when (sortType) {
- 0 -> R.id.radio_sort_alphabetical
- else -> R.id.radio_sort_activity
- }
- )
- radioGroup.setOnCheckedChangeListener { _, checkedId ->
- run {
- SharedPreferenceHelper.putInt(
- Constants.CHATROOM_SORT_TYPE_KEY, when (checkedId) {
- R.id.radio_sort_alphabetical -> 0
- R.id.radio_sort_activity -> 1
- else -> 1
- }
- )
- }
- }
-
- groupByTypeCheckBox.isChecked = groupByType
- groupByTypeCheckBox.setOnCheckedChangeListener { _, isChecked ->
- SharedPreferenceHelper.putBoolean(
- Constants.CHATROOM_GROUP_BY_TYPE_KEY,
- isChecked
- )
- }
-
- context?.let {
- AlertDialog.Builder(it)
- .setTitle(R.string.dialog_sort_title)
- .setView(dialogLayout)
- .setPositiveButton(R.string.msg_sort) { dialog, _ ->
- invalidateQueryOnSearch()
- updateSort()
- dialog.dismiss()
- }.show()
- }
- }
+ R.id.action_new_channel -> presenter.toCreateChannel()
}
return super.onOptionsItemSelected(item)
}
- private fun updateSort() {
- val sortType = SharedPreferenceHelper.getInt(
- Constants.CHATROOM_SORT_TYPE_KEY,
- ChatRoomsSortOrder.ACTIVITY
- )
- val grouped = SharedPreferenceHelper.getBoolean(Constants.CHATROOM_GROUP_BY_TYPE_KEY, false)
-
- val query = when (sortType) {
- ChatRoomsSortOrder.ALPHABETICAL -> {
- Query.ByName(grouped)
- }
- ChatRoomsSortOrder.ACTIVITY -> {
- Query.ByActivity(grouped)
- }
- else -> Query.ByActivity()
- }
-
- viewModel.setQuery(query)
- }
-
- private fun invalidateQueryOnSearch() {
- searchView?.let {
- if (!searchView!!.isIconified) {
- queryChatRoomsByName(searchView!!.query.toString())
- }
- }
- }
-
private fun showNoChatRoomsToDisplay() {
- ui { text_no_data_to_display.isVisible = true }
+// ui { text_no_data_to_display.isVisible = true }
}
override fun showLoading() {
@@ -303,55 +196,147 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
override fun showGenericErrorMessage() = showMessage(getString(R.string.msg_generic_error))
- override fun showLoadingRoom(name: CharSequence) {
- ui {
- progressDialog = ProgressDialog.show(activity, "Rocket.Chat", "Loading room $name")
- }
- }
-
- override fun hideLoadingRoom() {
- progressDialog?.dismiss()
- }
-
private fun showConnectionState(state: State) {
Timber.d("Got new state: $state")
+// ui {
+// text_connection_status.fadeIn()
+// handler.removeCallbacks(dismissStatus)
+// text_connection_status.text = when (state) {
+// is State.Connected -> {
+// handler.postDelayed(dismissStatus, 2000)
+// getString(R.string.status_connected)
+// }
+// is State.Disconnected -> getString(R.string.status_disconnected)
+// is State.Connecting -> getString(R.string.status_connecting)
+// is State.Authenticating -> getString(R.string.status_authenticating)
+// is State.Disconnecting -> getString(R.string.status_disconnecting)
+// is State.Waiting -> getString(R.string.status_waiting, state.seconds)
+// else -> {
+// handler.postDelayed(dismissStatus, 500)
+// ""
+// }
+// }
+// }
+ }
+
+ private fun subscribeUi() {
ui {
- text_connection_status.fadeIn()
- handler.removeCallbacks(dismissStatus)
- text_connection_status.text = when (state) {
- is State.Connected -> {
- handler.postDelayed(dismissStatus, 2000)
- getString(R.string.status_connected)
+ val adapter = RoomsAdapter { room ->
+ presenter.loadChatRoom(room)
+ }
+
+ with(recycler_view) {
+ layoutManager = LinearLayoutManager(it)
+ addItemDecoration(
+ DividerItemDecoration(
+ it,
+ resources.getDimensionPixelSize(R.dimen.divider_item_decorator_bound_start),
+ resources.getDimensionPixelSize(R.dimen.divider_item_decorator_bound_end)
+ )
+ )
+ itemAnimator = DefaultItemAnimator()
+ }
+
+ viewModel.getChatRooms().observe(viewLifecycleOwner, Observer { rooms ->
+ rooms?.let {
+ adapter.values = it
+ if (recycler_view.adapter != adapter) {
+ recycler_view.adapter = adapter
+ }
+ if (rooms.isNotEmpty()) {
+// text_no_data_to_display.isVisible = false
+ }
}
- is State.Disconnected -> getString(R.string.status_disconnected)
- is State.Connecting -> getString(R.string.status_connecting)
- is State.Authenticating -> getString(R.string.status_authenticating)
- is State.Disconnecting -> getString(R.string.status_disconnecting)
- is State.Waiting -> getString(R.string.status_waiting, state.seconds)
- else -> {
- handler.postDelayed(dismissStatus, 500)
- ""
+ })
+
+ viewModel.loadingState.observe(viewLifecycleOwner, Observer { state ->
+ when (state) {
+ is LoadingState.Loading -> if (state.count == 0L) showLoading()
+ is LoadingState.Loaded -> {
+ hideLoading()
+ if (state.count == 0L) showNoChatRoomsToDisplay()
+ }
+ is LoadingState.Error -> {
+ hideLoading()
+ showGenericErrorMessage()
+ }
}
- }
+ })
+
+ viewModel.getStatus().observe(viewLifecycleOwner, Observer { status ->
+ status?.let { showConnectionState(status) }
+ })
+
+ showAllChats()
}
}
- private val dismissStatus = {
- if (text_connection_status != null) {
- text_connection_status.fadeOut()
+ private fun setupListeners() {
+ text_server_name.setOnClickListener {
+ ServersBottomSheetFragment().show(
+ activity?.supportFragmentManager,
+ chat.rocket.android.servers.ui.TAG
+ )
+ }
+
+ text_sort_by.setOnClickListener {
+ SortingAndGroupingBottomSheetFragment().show(
+ activity?.supportFragmentManager,
+ chat.rocket.android.sortingandgrouping.ui.TAG
+ )
+ }
+
+ text_directory.setOnClickListener { presenter.toDirectory() }
+ }
+
+ fun sortChatRoomsList(
+ isSortByName: Boolean,
+ isUnreadOnTop: Boolean,
+ isGroupByType: Boolean,
+ isGroupByFavorites: Boolean
+ ) {
+ this.isSortByName = isSortByName
+ this.isUnreadOnTop = isUnreadOnTop
+ this.isGroupByType = isGroupByType
+ this.isGroupByFavorites = isGroupByFavorites
+
+ if (isSortByName) {
+ viewModel.setQuery(Query.ByName(isGroupByType, isUnreadOnTop))
+ changeSortByTitle(getString(R.string.msg_sort_by_name))
+ } else {
+ viewModel.setQuery(Query.ByActivity(isGroupByType, isUnreadOnTop))
+ changeSortByTitle(getString(R.string.msg_sort_by_activity))
}
}
- private fun setupToolbar() {
- (activity as AppCompatActivity?)?.supportActionBar?.title = getString(R.string.title_chats)
+ private fun changeSortByTitle(text: String) {
+ text_sort_by.text = getString(R.string.msg_sort_by_placeholder, text.toLowerCase())
}
private fun queryChatRoomsByName(name: String?): Boolean {
if (name.isNullOrEmpty()) {
- updateSort()
+ showAllChats()
} else {
- viewModel.setQuery(Query.Search(name!!))
+ viewModel.setQuery(Query.Search(name))
}
return true
}
+
+ private fun showAllChats() {
+ if (isSortByName) {
+ viewModel.setQuery(Query.ByName(isGroupByType, isUnreadOnTop))
+ } else {
+ viewModel.setQuery(Query.ByActivity(isGroupByType, isUnreadOnTop))
+ }
+ }
+
+ private fun showDirectoryView() {
+ text_directory.isVisible = true
+ text_sort_by.isGone = true
+ }
+
+ private fun hideDirectoryView() {
+ text_directory.isGone = true
+ text_sort_by.isVisible = true
+ }
}
diff --git a/app/src/main/java/chat/rocket/android/chatrooms/viewmodel/ChatRoomsViewModel.kt b/app/src/main/java/chat/rocket/android/chatrooms/viewmodel/ChatRoomsViewModel.kt
index 6f4532e7a2..c5c0952894 100644
--- a/app/src/main/java/chat/rocket/android/chatrooms/viewmodel/ChatRoomsViewModel.kt
+++ b/app/src/main/java/chat/rocket/android/chatrooms/viewmodel/ChatRoomsViewModel.kt
@@ -9,7 +9,7 @@ import chat.rocket.android.chatrooms.adapter.LoadingItemHolder
import chat.rocket.android.chatrooms.adapter.RoomUiModelMapper
import chat.rocket.android.chatrooms.domain.FetchChatRoomsInteractor
import chat.rocket.android.chatrooms.infrastructure.ChatRoomsRepository
-import chat.rocket.android.server.infraestructure.ConnectionManager
+import chat.rocket.android.server.infrastructure.ConnectionManager
import chat.rocket.android.util.livedata.transform
import chat.rocket.android.util.livedata.wrap
import chat.rocket.android.util.retryIO
@@ -140,8 +140,10 @@ sealed class LoadingState {
}
sealed class Query {
- data class ByActivity(val grouped: Boolean = false) : Query()
- data class ByName(val grouped: Boolean = false) : Query()
+
+ data class ByActivity(val grouped: Boolean = false, val unreadOnTop: Boolean = false) : Query()
+ data class ByName(val grouped: Boolean = false, val unreadOnTop: Boolean = false ) : Query()
+
data class Search(val query: String) : Query()
}
@@ -155,22 +157,44 @@ fun Query.isGrouped(): Boolean {
}
}
+fun Query.isUnreadOnTop(): Boolean {
+ return when(this) {
+ is Query.Search -> false
+ is Query.ByName -> unreadOnTop
+ is Query.ByActivity -> unreadOnTop
+ }
+}
+
fun Query.asSortingOrder(): ChatRoomsRepository.Order {
return when(this) {
is Query.ByName -> {
- if (grouped) {
+ if (grouped && !unreadOnTop) {
ChatRoomsRepository.Order.GROUPED_NAME
- } else {
+ }
+ else if(unreadOnTop && !grouped){
+ ChatRoomsRepository.Order.UNREAD_ON_TOP_NAME
+ }
+ else if(unreadOnTop && grouped){
+ ChatRoomsRepository.Order.UNREAD_ON_TOP_GROUPED_NAME
+ }
+ else {
ChatRoomsRepository.Order.NAME
}
}
is Query.ByActivity -> {
- if (grouped) {
+ if (grouped && !unreadOnTop) {
ChatRoomsRepository.Order.GROUPED_ACTIVITY
- } else {
+ }
+ else if(unreadOnTop && !grouped){
+ ChatRoomsRepository.Order.UNREAD_ON_TOP_ACTIVITY
+ }
+ else if(unreadOnTop && grouped){
+ ChatRoomsRepository.Order.UNREAD_ON_TOP_GROUPED_ACTIVITY
+ }
+ else {
ChatRoomsRepository.Order.ACTIVITY
}
}
else -> throw IllegalArgumentException("Should be ByName or ByActivity")
}
-}
+}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/chatrooms/viewmodel/ChatRoomsViewModelFactory.kt b/app/src/main/java/chat/rocket/android/chatrooms/viewmodel/ChatRoomsViewModelFactory.kt
index db5c6ccce3..77edce808c 100644
--- a/app/src/main/java/chat/rocket/android/chatrooms/viewmodel/ChatRoomsViewModelFactory.kt
+++ b/app/src/main/java/chat/rocket/android/chatrooms/viewmodel/ChatRoomsViewModelFactory.kt
@@ -5,7 +5,7 @@ import androidx.lifecycle.ViewModelProvider
import chat.rocket.android.chatrooms.adapter.RoomUiModelMapper
import chat.rocket.android.chatrooms.domain.FetchChatRoomsInteractor
import chat.rocket.android.chatrooms.infrastructure.ChatRoomsRepository
-import chat.rocket.android.server.infraestructure.ConnectionManager
+import chat.rocket.android.server.infrastructure.ConnectionManager
import javax.inject.Inject
class ChatRoomsViewModelFactory @Inject constructor(
diff --git a/app/src/main/java/chat/rocket/android/core/behaviours/AppLanguageView.kt b/app/src/main/java/chat/rocket/android/core/behaviours/AppLanguageView.kt
new file mode 100644
index 0000000000..56044e8f12
--- /dev/null
+++ b/app/src/main/java/chat/rocket/android/core/behaviours/AppLanguageView.kt
@@ -0,0 +1,12 @@
+package chat.rocket.android.core.behaviours
+
+interface AppLanguageView {
+
+ /**
+ * Updates the app language
+ *
+ * @param language The app language to be updated.
+ * @param country Opcional. The country code to be updated.
+ */
+ fun updateLanguage(language: String, country: String? = null)
+}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/createchannel/presentation/CreateChannelPresenter.kt b/app/src/main/java/chat/rocket/android/createchannel/presentation/CreateChannelPresenter.kt
index 354aaa1f3d..fd031ddedd 100644
--- a/app/src/main/java/chat/rocket/android/createchannel/presentation/CreateChannelPresenter.kt
+++ b/app/src/main/java/chat/rocket/android/createchannel/presentation/CreateChannelPresenter.kt
@@ -4,7 +4,7 @@ import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.main.presentation.MainNavigator
import chat.rocket.android.members.uimodel.MemberUiModelMapper
import chat.rocket.android.server.domain.GetCurrentServerInteractor
-import chat.rocket.android.server.infraestructure.RocketChatClientFactory
+import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI
import chat.rocket.common.RocketChatException
import chat.rocket.common.model.RoomType
@@ -22,7 +22,7 @@ class CreateChannelPresenter @Inject constructor(
val serverInteractor: GetCurrentServerInteractor,
val factory: RocketChatClientFactory
) {
- private val client: RocketChatClient = factory.create(serverInteractor.get()!!)
+ private val client: RocketChatClient = factory.get(serverInteractor.get()!!)
fun createChannel(
roomType: RoomType,
@@ -35,7 +35,6 @@ class CreateChannelPresenter @Inject constructor(
view.disableUserInput()
try {
client.createChannel(roomType, channelName, usersList, readOnly)
- view.prepareToShowChatList()
view.showChannelCreatedSuccessfullyMessage()
toChatList()
} catch (exception: RocketChatException) {
diff --git a/app/src/main/java/chat/rocket/android/createchannel/presentation/CreateChannelView.kt b/app/src/main/java/chat/rocket/android/createchannel/presentation/CreateChannelView.kt
index eb29f5f0cd..463fb760ba 100644
--- a/app/src/main/java/chat/rocket/android/createchannel/presentation/CreateChannelView.kt
+++ b/app/src/main/java/chat/rocket/android/createchannel/presentation/CreateChannelView.kt
@@ -28,12 +28,6 @@ interface CreateChannelView : LoadingView, MessageView {
*/
fun hideSuggestionViewInProgress()
- /**
- * Shows the navigation drawer with the chat item checked before showing the chat list.
- * This function is invoked after successfully created the channel.
- */
- fun prepareToShowChatList()
-
/**
* Shows a message that a channel was successfully created.
*/
diff --git a/app/src/main/java/chat/rocket/android/createchannel/ui/CreateChannelFragment.kt b/app/src/main/java/chat/rocket/android/createchannel/ui/CreateChannelFragment.kt
index 57f60a6f18..4baf9af6ab 100644
--- a/app/src/main/java/chat/rocket/android/createchannel/ui/CreateChannelFragment.kt
+++ b/app/src/main/java/chat/rocket/android/createchannel/ui/CreateChannelFragment.kt
@@ -9,7 +9,6 @@ import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.view.ActionMode
import androidx.core.view.isVisible
-import androidx.core.view.postDelayed
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
@@ -19,7 +18,6 @@ import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.analytics.event.ScreenViewEvent
import chat.rocket.android.createchannel.presentation.CreateChannelPresenter
import chat.rocket.android.createchannel.presentation.CreateChannelView
-import chat.rocket.android.main.ui.MainActivity
import chat.rocket.android.members.adapter.MembersAdapter
import chat.rocket.android.members.uimodel.MemberUiModel
import chat.rocket.android.util.extension.asObservable
@@ -32,17 +30,18 @@ import com.google.android.material.chip.Chip
import dagger.android.support.AndroidSupportInjection
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
+import kotlinx.android.synthetic.main.app_bar.*
import kotlinx.android.synthetic.main.fragment_create_channel.*
import java.util.concurrent.TimeUnit
import javax.inject.Inject
internal const val TAG_CREATE_CHANNEL_FRAGMENT = "CreateChannelFragment"
+fun newInstance() = CreateChannelFragment()
+
class CreateChannelFragment : Fragment(), CreateChannelView, ActionMode.Callback {
- @Inject
- lateinit var createChannelPresenter: CreateChannelPresenter
- @Inject
- lateinit var analyticsManager: AnalyticsManager
+ @Inject lateinit var presenter: CreateChannelPresenter
+ @Inject lateinit var analyticsManager: AnalyticsManager
private var actionMode: ActionMode? = null
private val adapter: MembersAdapter = MembersAdapter {
it.username?.run { processSelectedMember(this) }
@@ -52,10 +51,6 @@ class CreateChannelFragment : Fragment(), CreateChannelView, ActionMode.Callback
private var isChannelReadOnly: Boolean = false
private var memberList = arrayListOf()
- companion object {
- fun newInstance() = CreateChannelFragment()
- }
-
override fun onCreate(savedInstanceState: Bundle?) {
AndroidSupportInjection.inject(this)
super.onCreate(savedInstanceState)
@@ -93,7 +88,7 @@ class CreateChannelFragment : Fragment(), CreateChannelView, ActionMode.Callback
override fun onActionItemClicked(mode: ActionMode, menuItem: MenuItem): Boolean {
return when (menuItem.itemId) {
R.id.action_create_channel -> {
- createChannelPresenter.createChannel(
+ presenter.createChannel(
roomTypeOf(channelType),
text_channel_name.text.toString(),
memberList,
@@ -165,17 +160,6 @@ class CreateChannelFragment : Fragment(), CreateChannelView, ActionMode.Callback
view_member_suggestion_loading.isVisible = false
}
- override fun prepareToShowChatList() {
- with(activity as MainActivity) {
- setCheckedNavDrawerItem(R.id.menu_action_chats)
- openDrawer()
- getDrawerLayout().postDelayed(1000) {
- closeDrawer()
- createChannelPresenter.toChatList()
- }
- }
- }
-
override fun showChannelCreatedSuccessfullyMessage() {
showMessage(getString(R.string.msg_channel_created_successfully))
}
@@ -191,8 +175,14 @@ class CreateChannelFragment : Fragment(), CreateChannelView, ActionMode.Callback
}
private fun setupToolBar() {
- (activity as AppCompatActivity?)?.supportActionBar?.title =
- getString(R.string.title_create_channel)
+ with((activity as AppCompatActivity)) {
+ with(toolbar) {
+ setSupportActionBar(this)
+ title = getString(R.string.title_create_channel)
+ setNavigationIcon(R.drawable.ic_arrow_back_white_24dp)
+ setNavigationOnClickListener { activity?.onBackPressed() }
+ }
+ }
}
private fun setupViewListeners() {
@@ -247,7 +237,7 @@ class CreateChannelFragment : Fragment(), CreateChannelView, ActionMode.Callback
.filter { t -> t.isNotBlank() }
.subscribe {
if (it.length >= 3) {
- createChannelPresenter.searchUser(it.toString())
+ presenter.searchUser(it.toString())
} else {
view_member_suggestion.isVisible = false
}
diff --git a/app/src/main/java/chat/rocket/android/dagger/AppComponent.kt b/app/src/main/java/chat/rocket/android/dagger/AppComponent.kt
index 1812840193..e9963c8da5 100644
--- a/app/src/main/java/chat/rocket/android/dagger/AppComponent.kt
+++ b/app/src/main/java/chat/rocket/android/dagger/AppComponent.kt
@@ -14,9 +14,15 @@ import dagger.android.support.AndroidSupportInjectionModule
import javax.inject.Singleton
@Singleton
-@Component(modules = [AndroidSupportInjectionModule::class,
- AppModule::class, ActivityBuilder::class, ServiceBuilder::class, ReceiverBuilder::class,
- AndroidWorkerInjectionModule::class])
+@Component(
+ modules = [
+ AndroidSupportInjectionModule::class,
+ AppModule::class,
+ ActivityBuilder::class,
+ ServiceBuilder::class,
+ ReceiverBuilder::class,
+ AndroidWorkerInjectionModule::class]
+)
interface AppComponent {
@Component.Builder
diff --git a/app/src/main/java/chat/rocket/android/dagger/module/ActivityBuilder.kt b/app/src/main/java/chat/rocket/android/dagger/module/ActivityBuilder.kt
index bea265f32d..2893e634dd 100644
--- a/app/src/main/java/chat/rocket/android/dagger/module/ActivityBuilder.kt
+++ b/app/src/main/java/chat/rocket/android/dagger/module/ActivityBuilder.kt
@@ -1,6 +1,5 @@
package chat.rocket.android.dagger.module
-import chat.rocket.android.about.di.AboutFragmentProvider
import chat.rocket.android.authentication.di.AuthenticationModule
import chat.rocket.android.authentication.login.di.LoginFragmentProvider
import chat.rocket.android.authentication.loginoptions.di.LoginOptionsFragmentProvider
@@ -20,6 +19,7 @@ import chat.rocket.android.chatroom.ui.ChatRoomActivity
import chat.rocket.android.chatrooms.di.ChatRoomsFragmentProvider
import chat.rocket.android.createchannel.di.CreateChannelProvider
import chat.rocket.android.dagger.scope.PerActivity
+import chat.rocket.android.directory.di.DirectoryFragmentProvider
import chat.rocket.android.draw.main.di.DrawModule
import chat.rocket.android.draw.main.ui.DrawingActivity
import chat.rocket.android.favoritemessages.di.FavoriteMessagesFragmentProvider
@@ -29,13 +29,14 @@ import chat.rocket.android.main.ui.MainActivity
import chat.rocket.android.members.di.MembersFragmentProvider
import chat.rocket.android.mentions.di.MentionsFragmentProvider
import chat.rocket.android.pinnedmessages.di.PinnedMessagesFragmentProvider
-import chat.rocket.android.preferences.di.PreferencesFragmentProvider
import chat.rocket.android.profile.di.ProfileFragmentProvider
import chat.rocket.android.server.di.ChangeServerModule
import chat.rocket.android.server.ui.ChangeServerActivity
+import chat.rocket.android.servers.di.ServersBottomSheetFragmentProvider
import chat.rocket.android.settings.di.SettingsFragmentProvider
import chat.rocket.android.settings.password.di.PasswordFragmentProvider
import chat.rocket.android.settings.password.ui.PasswordActivity
+import chat.rocket.android.sortingandgrouping.di.SortingAndGroupingBottomSheetFragmentProvider
import chat.rocket.android.userdetails.di.UserDetailsFragmentProvider
import chat.rocket.android.videoconference.di.VideoConferenceModule
import chat.rocket.android.videoconference.ui.VideoConferenceActivity
@@ -65,12 +66,13 @@ abstract class ActivityBuilder {
@ContributesAndroidInjector(
modules = [MainModule::class,
ChatRoomsFragmentProvider::class,
+ ServersBottomSheetFragmentProvider::class,
+ SortingAndGroupingBottomSheetFragmentProvider::class,
CreateChannelProvider::class,
ProfileFragmentProvider::class,
SettingsFragmentProvider::class,
- AboutFragmentProvider::class,
- PreferencesFragmentProvider::class,
- AdminPanelWebViewFragmentProvider::class
+ AdminPanelWebViewFragmentProvider::class,
+ DirectoryFragmentProvider::class
]
)
abstract fun bindMainActivity(): MainActivity
diff --git a/app/src/main/java/chat/rocket/android/dagger/module/AppModule.kt b/app/src/main/java/chat/rocket/android/dagger/module/AppModule.kt
index c06b4c4cf9..536192cd8d 100644
--- a/app/src/main/java/chat/rocket/android/dagger/module/AppModule.kt
+++ b/app/src/main/java/chat/rocket/android/dagger/module/AppModule.kt
@@ -12,8 +12,8 @@ import chat.rocket.android.R
import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.analytics.AnswersAnalytics
import chat.rocket.android.analytics.GoogleAnalyticsForFirebase
-import chat.rocket.android.authentication.infraestructure.SharedPreferencesMultiServerTokenRepository
-import chat.rocket.android.authentication.infraestructure.SharedPreferencesTokenRepository
+import chat.rocket.android.authentication.infrastructure.SharedPreferencesMultiServerTokenRepository
+import chat.rocket.android.authentication.infrastructure.SharedPreferencesTokenRepository
import chat.rocket.android.chatroom.service.MessageService
import chat.rocket.android.dagger.qualifier.ForAuthentication
import chat.rocket.android.dagger.qualifier.ForMessages
@@ -27,37 +27,41 @@ import chat.rocket.android.push.PushManager
import chat.rocket.android.server.domain.AccountsRepository
import chat.rocket.android.server.domain.AnalyticsTrackingInteractor
import chat.rocket.android.server.domain.AnalyticsTrackingRepository
+import chat.rocket.android.server.domain.BasicAuthRepository
import chat.rocket.android.server.domain.ChatRoomsRepository
import chat.rocket.android.server.domain.CurrentServerRepository
import chat.rocket.android.server.domain.GetAccountInteractor
import chat.rocket.android.server.domain.GetAccountsInteractor
+import chat.rocket.android.server.domain.GetBasicAuthInteractor
import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.domain.GetSettingsInteractor
import chat.rocket.android.server.domain.JobSchedulerInteractor
import chat.rocket.android.server.domain.MessagesRepository
import chat.rocket.android.server.domain.MultiServerTokenRepository
import chat.rocket.android.server.domain.PermissionsRepository
+import chat.rocket.android.server.domain.SaveBasicAuthInteractor
import chat.rocket.android.server.domain.SettingsRepository
+import chat.rocket.android.server.domain.SortingAndGroupingRepository
import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.domain.UsersRepository
-import chat.rocket.android.server.domain.BasicAuthRepository
-import chat.rocket.android.server.domain.GetBasicAuthInteractor
-import chat.rocket.android.server.domain.SaveBasicAuthInteractor
-import chat.rocket.android.server.infraestructure.SharedPrefsBasicAuthRepository
-import chat.rocket.android.server.infraestructure.DatabaseMessageMapper
-import chat.rocket.android.server.infraestructure.DatabaseMessagesRepository
-import chat.rocket.android.server.infraestructure.JobSchedulerInteractorImpl
-import chat.rocket.android.server.infraestructure.MemoryChatRoomsRepository
-import chat.rocket.android.server.infraestructure.MemoryUsersRepository
-import chat.rocket.android.server.infraestructure.SharedPreferencesAccountsRepository
-import chat.rocket.android.server.infraestructure.SharedPreferencesPermissionsRepository
-import chat.rocket.android.server.infraestructure.SharedPreferencesSettingsRepository
-import chat.rocket.android.server.infraestructure.SharedPrefsAnalyticsTrackingRepository
-import chat.rocket.android.server.infraestructure.SharedPrefsConnectingServerRepository
-import chat.rocket.android.server.infraestructure.SharedPrefsCurrentServerRepository
+import chat.rocket.android.server.infrastructure.CurrentLanguageRepository
+import chat.rocket.android.server.infrastructure.SharedPrefsCurrentLanguageRepository
+import chat.rocket.android.server.infrastructure.DatabaseMessageMapper
+import chat.rocket.android.server.infrastructure.DatabaseMessagesRepository
+import chat.rocket.android.server.infrastructure.JobSchedulerInteractorImpl
+import chat.rocket.android.server.infrastructure.MemoryChatRoomsRepository
+import chat.rocket.android.server.infrastructure.MemoryUsersRepository
+import chat.rocket.android.server.infrastructure.SharedPreferencesAccountsRepository
+import chat.rocket.android.server.infrastructure.SharedPreferencesPermissionsRepository
+import chat.rocket.android.server.infrastructure.SharedPreferencesSettingsRepository
+import chat.rocket.android.server.infrastructure.SharedPrefsAnalyticsTrackingRepository
+import chat.rocket.android.server.infrastructure.SharedPrefsBasicAuthRepository
+import chat.rocket.android.server.infrastructure.SharedPrefsConnectingServerRepository
+import chat.rocket.android.server.infrastructure.SharedPrefsCurrentServerRepository
+import chat.rocket.android.server.infrastructure.SharedPrefsSortingAndGroupingRepository
import chat.rocket.android.util.AppJsonAdapterFactory
-import chat.rocket.android.util.HttpLoggingInterceptor
import chat.rocket.android.util.BasicAuthenticatorInterceptor
+import chat.rocket.android.util.HttpLoggingInterceptor
import chat.rocket.android.util.TimberLogger
import chat.rocket.common.internal.FallbackSealedClassJsonAdapter
import chat.rocket.common.internal.ISO8601Date
@@ -123,7 +127,10 @@ class AppModule {
@Provides
@Singleton
- fun provideOkHttpClient(logger: HttpLoggingInterceptor, basicAuthenticator: BasicAuthenticatorInterceptor): OkHttpClient {
+ fun provideOkHttpClient(
+ logger: HttpLoggingInterceptor,
+ basicAuthenticator: BasicAuthenticatorInterceptor
+ ): OkHttpClient {
return OkHttpClient.Builder()
.addInterceptor(logger)
.addInterceptor(basicAuthenticator)
@@ -170,7 +177,6 @@ class AppModule {
fun provideSharedPreferences(context: Application) =
context.getSharedPreferences("rocket.chat", Context.MODE_PRIVATE)
-
@Provides
@ForMessages
fun provideMessagesSharedPreferences(context: Application) =
@@ -194,12 +200,24 @@ class AppModule {
return SharedPrefsAnalyticsTrackingRepository(prefs)
}
+ @Provides
+ @Singleton
+ fun provideSortingAndGroupingRepository(prefs: SharedPreferences): SortingAndGroupingRepository {
+ return SharedPrefsSortingAndGroupingRepository(prefs)
+ }
+
@Provides
@ForAuthentication
fun provideConnectingServerRepository(prefs: SharedPreferences): CurrentServerRepository {
return SharedPrefsConnectingServerRepository(prefs)
}
+ @Provides
+ @Singleton
+ fun provideCurrentLanguageRepository(prefs: SharedPreferences): CurrentLanguageRepository {
+ return SharedPrefsCurrentLanguageRepository(prefs)
+ }
+
@Provides
@Singleton
fun provideSettingsRepository(localRepository: LocalRepository): SettingsRepository {
@@ -293,10 +311,10 @@ class AppModule {
@Provides
@Singleton
- fun provideBasicAuthRepository (
+ fun provideBasicAuthRepository(
preferences: SharedPreferences,
moshi: Moshi
- ): BasicAuthRepository =
+ ): BasicAuthRepository =
SharedPrefsBasicAuthRepository(preferences, moshi)
@Provides
diff --git a/app/src/main/java/chat/rocket/android/dagger/module/LocalModule.kt b/app/src/main/java/chat/rocket/android/dagger/module/LocalModule.kt
index e6e08f148e..26df5c5f4c 100644
--- a/app/src/main/java/chat/rocket/android/dagger/module/LocalModule.kt
+++ b/app/src/main/java/chat/rocket/android/dagger/module/LocalModule.kt
@@ -6,7 +6,7 @@ import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.infrastructure.SharedPreferencesLocalRepository
import chat.rocket.android.server.domain.CurrentServerRepository
import chat.rocket.android.server.domain.GetCurrentServerInteractor
-import chat.rocket.android.server.infraestructure.SharedPrefsCurrentServerRepository
+import chat.rocket.android.server.infrastructure.SharedPrefsCurrentServerRepository
import chat.rocket.android.util.AppJsonAdapterFactory
import chat.rocket.android.util.TimberLogger
import chat.rocket.common.internal.FallbackSealedClassJsonAdapter
diff --git a/app/src/main/java/chat/rocket/android/db/ChatRoomDao.kt b/app/src/main/java/chat/rocket/android/db/ChatRoomDao.kt
index 11bc281296..6b95702243 100644
--- a/app/src/main/java/chat/rocket/android/db/ChatRoomDao.kt
+++ b/app/src/main/java/chat/rocket/android/db/ChatRoomDao.kt
@@ -65,11 +65,59 @@ abstract class ChatRoomDao : BaseDao {
""")
abstract fun getAllGrouped(): LiveData>
+ @Transaction
+ @Query("""
+ $BASE_QUERY
+ $FILTER_NOT_OPENED
+ ORDER BY
+ $UNREAD,
+ CASE
+ WHEN lastMessageTimeStamp IS NOT NULL THEN lastMessageTimeStamp
+ ELSE updatedAt
+ END DESC
+ """)
+ abstract fun getAllUnread(): LiveData>
+
+ @Transaction
+ @Query("""
+ $BASE_QUERY
+ $FILTER_NOT_OPENED
+ ORDER BY
+ $UNREAD,
+ name COLLATE NOCASE
+ """)
+ abstract fun getAllAlphabeticallyUnread(): LiveData>
+
@Transaction
@Query("""
$BASE_QUERY
$FILTER_NOT_OPENED
- ORDER BY name
+ ORDER BY
+ $TYPE_ORDER,
+ $UNREAD,
+ name COLLATE NOCASE
+ """)
+ abstract fun getAllAlphabeticallyGroupedUnread(): LiveData>
+
+ @Transaction
+ @Query("""
+ $BASE_QUERY
+ $FILTER_NOT_OPENED
+ ORDER BY
+ $TYPE_ORDER,
+ $UNREAD,
+ CASE
+ WHEN lastMessageTimeStamp IS NOT NULL THEN lastMessageTimeStamp
+ ELSE updatedAt
+ END DESC
+ """)
+ abstract fun getAllGroupedUnread(): LiveData>
+
+ @Transaction
+ @Query("""
+ $BASE_QUERY
+ $FILTER_NOT_OPENED
+ ORDER BY name COLLATE NOCASE
""")
abstract fun getAllAlphabetically(): LiveData>
@@ -79,7 +127,7 @@ abstract class ChatRoomDao : BaseDao {
$FILTER_NOT_OPENED
ORDER BY
$TYPE_ORDER,
- name
+ name COLLATE NOCASE
""")
abstract fun getAllAlphabeticallyGrouped(): LiveData>
@@ -139,5 +187,11 @@ abstract class ChatRoomDao : BaseDao {
ELSE 5
END
"""
+ const val UNREAD = """
+ CASE
+ WHEN alert OR unread > 0 THEN 1
+ ELSE 2
+ END
+ """
}
}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/db/DatabaseManager.kt b/app/src/main/java/chat/rocket/android/db/DatabaseManager.kt
index 0dffbf8f16..8363352372 100644
--- a/app/src/main/java/chat/rocket/android/db/DatabaseManager.kt
+++ b/app/src/main/java/chat/rocket/android/db/DatabaseManager.kt
@@ -1,6 +1,7 @@
package chat.rocket.android.db
import android.app.Application
+import androidx.core.net.toUri
import chat.rocket.android.R
import chat.rocket.android.db.model.BaseMessageEntity
import chat.rocket.android.db.model.BaseUserEntity
@@ -15,6 +16,7 @@ import chat.rocket.android.db.model.UrlEntity
import chat.rocket.android.db.model.UserEntity
import chat.rocket.android.db.model.UserStatus
import chat.rocket.android.db.model.asEntity
+import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.android.util.extensions.exhaustive
import chat.rocket.android.util.extensions.removeTrailingSlash
import chat.rocket.android.util.extensions.toEntity
@@ -23,6 +25,7 @@ import chat.rocket.android.util.retryDB
import chat.rocket.common.model.BaseRoom
import chat.rocket.common.model.RoomType
import chat.rocket.common.model.SimpleUser
+import chat.rocket.common.model.Token
import chat.rocket.common.model.User
import chat.rocket.core.internal.model.Subscription
import chat.rocket.core.internal.realtime.socket.model.StreamMessage
@@ -32,6 +35,7 @@ import chat.rocket.core.model.Message
import chat.rocket.core.model.Myself
import chat.rocket.core.model.Room
import chat.rocket.core.model.userId
+import com.facebook.drawee.backends.pipeline.Fresco
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.channels.Channel
@@ -48,8 +52,7 @@ import kotlin.collections.component2
import kotlin.collections.set
import kotlin.system.measureTimeMillis
-class DatabaseManager(val context: Application, val serverUrl: String) {
-
+class DatabaseManager(val context: Application, val serverUrl: String, val token: Token) {
private val database: RCDatabase = androidx.room.Room.databaseBuilder(
context,
RCDatabase::class.java, serverUrl.databaseName()
@@ -58,23 +61,23 @@ class DatabaseManager(val context: Application, val serverUrl: String) {
.build()
private val dbContext = newSingleThreadContext("$serverUrl-db-context")
private val dbManagerContext = newSingleThreadContext("$serverUrl-db-manager-context")
-
private val writeChannel = Channel(Channel.UNLIMITED)
private var dbJob: Job? = null
-
private val insertSubs = HashMap()
private val insertRooms = HashMap()
private val updateSubs = LinkedHashMap()
private val updateRooms = LinkedHashMap()
- fun chatRoomDao(): ChatRoomDao = database.chatRoomDao()
- fun userDao(): UserDao = database.userDao()
- fun messageDao(): MessageDao = database.messageDao()
-
init {
start()
}
+ fun chatRoomDao(): ChatRoomDao = database.chatRoomDao()
+
+ fun userDao(): UserDao = database.userDao()
+
+ fun messageDao(): MessageDao = database.messageDao()
+
fun start() {
dbJob?.cancel()
dbJob = GlobalScope.launch(dbContext) {
@@ -138,7 +141,7 @@ class DatabaseManager(val context: Application, val serverUrl: String) {
}
/*
- * Creates a list of data base operations
+ * Creates a list of database operations
*/
fun processChatRoomsBatch(batch: List>) {
GlobalScope.launch(dbManagerContext) {
@@ -189,6 +192,20 @@ class DatabaseManager(val context: Application, val serverUrl: String) {
status = myself.status?.toString() ?: user.status
) ?: myself.asUser().toEntity()
+ if (myself.avatarOrigin != null && myself.active == null &&
+ myself.name == null && myself.username == null
+ ) {
+ user?.username?.let {
+ Fresco.getImagePipeline().evictFromCache(
+ serverUrl.avatarUrl(
+ it,
+ token.userId,
+ token.authToken
+ ).toUri()
+ )
+ }
+ }
+
Timber.d("UPDATING SELF: $entity")
entity?.let { sendOperation(Operation.UpsertUser(it)) }
}
@@ -472,6 +489,7 @@ class DatabaseManager(val context: Application, val serverUrl: String) {
return ChatRoomEntity(
id = room.id,
subscriptionId = subscription.id,
+ parentId = subscription.parentId,
type = room.type.toString(),
name = room.name ?: subscription.name
?: throw NullPointerException(), // this should be filtered on the SDK
@@ -513,6 +531,7 @@ class DatabaseManager(val context: Application, val serverUrl: String) {
return ChatRoomEntity(
id = id,
subscriptionId = subscriptionId,
+ parentId = parentId,
type = type.toString(),
name = name,
fullname = fullName,
diff --git a/app/src/main/java/chat/rocket/android/db/DatabaseManagerFactory.kt b/app/src/main/java/chat/rocket/android/db/DatabaseManagerFactory.kt
index 19a67975f6..08e3936de7 100644
--- a/app/src/main/java/chat/rocket/android/db/DatabaseManagerFactory.kt
+++ b/app/src/main/java/chat/rocket/android/db/DatabaseManagerFactory.kt
@@ -1,12 +1,16 @@
package chat.rocket.android.db
import android.app.Application
+import chat.rocket.android.server.domain.TokenRepository
import timber.log.Timber
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
-class DatabaseManagerFactory @Inject constructor(private val context: Application) {
+class DatabaseManagerFactory @Inject constructor(
+ private val context: Application,
+ private val tokenRepository: TokenRepository
+) {
private val cache = HashMap()
fun create(serverUrl: String): DatabaseManager {
@@ -15,9 +19,10 @@ class DatabaseManagerFactory @Inject constructor(private val context: Applicatio
return it
}
- Timber.d("Returning FRESH database for $serverUrl")
- val db = DatabaseManager(context, serverUrl)
- cache[serverUrl] = db
- return db
+ Timber.d("Returning fresh database for $serverUrl")
+ with(DatabaseManager(context, serverUrl, tokenRepository.get(serverUrl)!!)) {
+ cache[serverUrl] = this
+ return this
+ }
}
}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/db/RCDatabase.kt b/app/src/main/java/chat/rocket/android/db/RCDatabase.kt
index 96084c7ff6..78178a34a6 100644
--- a/app/src/main/java/chat/rocket/android/db/RCDatabase.kt
+++ b/app/src/main/java/chat/rocket/android/db/RCDatabase.kt
@@ -32,7 +32,7 @@ import chat.rocket.android.emoji.internal.db.StringListConverter
ReactionEntity::class,
MessagesSync::class
],
- version = 12,
+ version = 13,
exportSchema = true
)
@TypeConverters(StringListConverter::class)
diff --git a/app/src/main/java/chat/rocket/android/db/model/ChatRoomEntity.kt b/app/src/main/java/chat/rocket/android/db/model/ChatRoomEntity.kt
index f3d0aed820..e709003705 100644
--- a/app/src/main/java/chat/rocket/android/db/model/ChatRoomEntity.kt
+++ b/app/src/main/java/chat/rocket/android/db/model/ChatRoomEntity.kt
@@ -26,6 +26,7 @@ import chat.rocket.android.emoji.internal.db.StringListConverter
data class ChatRoomEntity(
@PrimaryKey var id: String,
var subscriptionId: String,
+ var parentId: String?,
var type: String,
var name: String,
var fullname: String? = null,
diff --git a/app/src/main/java/chat/rocket/android/directory/adapter/DirectoryAdapter.kt b/app/src/main/java/chat/rocket/android/directory/adapter/DirectoryAdapter.kt
new file mode 100644
index 0000000000..44e6aacda7
--- /dev/null
+++ b/app/src/main/java/chat/rocket/android/directory/adapter/DirectoryAdapter.kt
@@ -0,0 +1,108 @@
+package chat.rocket.android.directory.adapter
+
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import chat.rocket.android.R
+import chat.rocket.android.directory.uimodel.DirectoryUiModel
+import chat.rocket.android.util.extensions.inflate
+
+private const val VIEW_TYPE_CHANNELS = 0
+private const val VIEW_TYPE_USERS = 1
+private const val VIEW_TYPE_GLOBAL_USERS = 2
+
+class DirectoryAdapter(private val selector: Selector) :
+ RecyclerView.Adapter() {
+ private var isSortByChannels: Boolean = true
+ private var isSearchForGlobalUsers: Boolean = true
+ private var dataSet: List = ArrayList()
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder =
+ when (viewType) {
+ VIEW_TYPE_CHANNELS -> DirectoryChannelViewHolder(
+ parent.inflate(R.layout.item_directory_channel)
+ )
+ VIEW_TYPE_USERS -> DirectoryUsersViewHolder(
+ parent.inflate(R.layout.item_directory_user)
+ )
+ VIEW_TYPE_GLOBAL_USERS -> DirectoryGlobalUsersViewHolder(
+ parent.inflate(R.layout.item_directory_user)
+ )
+ else -> throw IllegalStateException("viewType must be either VIEW_TYPE_CHANNELS, VIEW_TYPE_USERS or VIEW_TYPE_GLOBAL_USERS")
+ }
+
+ override fun getItemCount(): Int = dataSet.size
+
+ override fun getItemViewType(position: Int): Int {
+ return if (isSortByChannels) {
+ VIEW_TYPE_CHANNELS
+ } else {
+ if (isSearchForGlobalUsers) {
+ VIEW_TYPE_GLOBAL_USERS
+ } else {
+ VIEW_TYPE_USERS
+ }
+ }
+ }
+
+ override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) =
+ when (holder) {
+ is DirectoryChannelViewHolder -> bindDirectoryChannelViewHolder(holder, position)
+ is DirectoryUsersViewHolder -> bindDirectoryUsersViewHolder(holder, position)
+ is DirectoryGlobalUsersViewHolder -> bindDirectoryGlobalUsersViewHolder(
+ holder,
+ position
+ )
+ else -> throw IllegalStateException("Unable to bind ViewHolder. ViewHolder must be either DirectoryChannelViewHolder, DirectoryUsersViewHolder or DirectoryGlobalUsersViewHolder")
+ }
+
+ private fun bindDirectoryChannelViewHolder(holder: DirectoryChannelViewHolder, position: Int) {
+ with(dataSet[position]) {
+ holder.bind(this)
+ holder.itemView.setOnClickListener { selector.onChannelSelected(id, name) }
+ }
+ }
+
+ private fun bindDirectoryUsersViewHolder(holder: DirectoryUsersViewHolder, position: Int) {
+ with(dataSet[position]) {
+ holder.bind(this)
+ holder.itemView.setOnClickListener { selector.onUserSelected(username, name) }
+ }
+ }
+
+ private fun bindDirectoryGlobalUsersViewHolder(
+ holder: DirectoryGlobalUsersViewHolder,
+ position: Int
+ ) {
+ with(dataSet[position]) {
+ holder.bind(this)
+ holder.itemView.setOnClickListener { selector.onGlobalUserSelected(username, name) }
+ }
+ }
+
+ fun clearData() {
+ dataSet = emptyList()
+ notifyDataSetChanged()
+ }
+
+ fun setSorting(isSortByChannels: Boolean, isSearchForGlobalUsers: Boolean) {
+ this.isSortByChannels = isSortByChannels
+ this.isSearchForGlobalUsers = isSearchForGlobalUsers
+ }
+
+ fun prependData(dataSet: List) {
+ this.dataSet = dataSet
+ notifyItemRangeInserted(0, dataSet.size)
+ }
+
+ fun appendData(dataSet: List) {
+ val previousDataSetSize = this.dataSet.size
+ this.dataSet += dataSet
+ notifyItemRangeInserted(previousDataSetSize, dataSet.size)
+ }
+}
+
+interface Selector {
+ fun onChannelSelected(channelId: String, channelName: String)
+ fun onUserSelected(username: String, name: String)
+ fun onGlobalUserSelected(username: String, name: String)
+}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/directory/adapter/DirectoryChannelViewHolder.kt b/app/src/main/java/chat/rocket/android/directory/adapter/DirectoryChannelViewHolder.kt
new file mode 100644
index 0000000000..1156008b9e
--- /dev/null
+++ b/app/src/main/java/chat/rocket/android/directory/adapter/DirectoryChannelViewHolder.kt
@@ -0,0 +1,17 @@
+package chat.rocket.android.directory.adapter
+
+import android.view.View
+import androidx.recyclerview.widget.RecyclerView
+import chat.rocket.android.directory.uimodel.DirectoryUiModel
+import com.bumptech.glide.Glide
+import kotlinx.android.synthetic.main.item_directory_channel.view.*
+
+class DirectoryChannelViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
+
+ fun bind(directoryChannelUiModel: DirectoryUiModel) = with(itemView) {
+ Glide.with(image_avatar).load(directoryChannelUiModel.channelAvatarUri).into(image_avatar)
+ text_channel_name.text = directoryChannelUiModel.name
+ text_channel_description.text = directoryChannelUiModel.description
+ text_channel_total_members.text = directoryChannelUiModel.totalMembers
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/directory/adapter/DirectoryGlobalUsersViewHolder.kt b/app/src/main/java/chat/rocket/android/directory/adapter/DirectoryGlobalUsersViewHolder.kt
new file mode 100644
index 0000000000..57c19fb952
--- /dev/null
+++ b/app/src/main/java/chat/rocket/android/directory/adapter/DirectoryGlobalUsersViewHolder.kt
@@ -0,0 +1,21 @@
+package chat.rocket.android.directory.adapter
+
+import android.view.View
+import androidx.core.view.isVisible
+import androidx.recyclerview.widget.RecyclerView
+import chat.rocket.android.directory.uimodel.DirectoryUiModel
+import com.bumptech.glide.Glide
+import kotlinx.android.synthetic.main.item_directory_user.view.*
+
+class DirectoryGlobalUsersViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
+
+ fun bind(directoryChannelUiModel: DirectoryUiModel) = with(itemView) {
+ Glide.with(image_avatar).load(directoryChannelUiModel.userAvatarUri).into(image_avatar)
+ text_user_name.text = directoryChannelUiModel.name
+ text_user_username.text = directoryChannelUiModel.username
+ with(text_server_url) {
+ text = directoryChannelUiModel.serverUrl
+ isVisible = true
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/directory/adapter/DirectoryUsersViewHolder.kt b/app/src/main/java/chat/rocket/android/directory/adapter/DirectoryUsersViewHolder.kt
new file mode 100644
index 0000000000..e2351a16cb
--- /dev/null
+++ b/app/src/main/java/chat/rocket/android/directory/adapter/DirectoryUsersViewHolder.kt
@@ -0,0 +1,18 @@
+package chat.rocket.android.directory.adapter
+
+import android.view.View
+import androidx.core.view.isGone
+import androidx.recyclerview.widget.RecyclerView
+import chat.rocket.android.directory.uimodel.DirectoryUiModel
+import com.bumptech.glide.Glide
+import kotlinx.android.synthetic.main.item_directory_user.view.*
+
+class DirectoryUsersViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
+
+ fun bind(directoryChannelUiModel: DirectoryUiModel) = with(itemView) {
+ Glide.with(image_avatar).load(directoryChannelUiModel.userAvatarUri).into(image_avatar)
+ text_user_name.text = directoryChannelUiModel.name
+ text_user_username.text = directoryChannelUiModel.username
+ text_server_url.isGone = true
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/directory/di/DirectoryFragmentModule.kt b/app/src/main/java/chat/rocket/android/directory/di/DirectoryFragmentModule.kt
new file mode 100644
index 0000000000..75e71e55aa
--- /dev/null
+++ b/app/src/main/java/chat/rocket/android/directory/di/DirectoryFragmentModule.kt
@@ -0,0 +1,15 @@
+package chat.rocket.android.directory.di
+
+import chat.rocket.android.dagger.scope.PerFragment
+import chat.rocket.android.directory.presentation.DirectoryView
+import chat.rocket.android.directory.ui.DirectoryFragment
+import dagger.Module
+import dagger.Provides
+
+@Module
+class DirectoryFragmentModule {
+
+ @Provides
+ @PerFragment
+ fun directoryView(frag: DirectoryFragment): DirectoryView = frag
+}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/directory/di/DirectoryFragmentProvider.kt b/app/src/main/java/chat/rocket/android/directory/di/DirectoryFragmentProvider.kt
new file mode 100644
index 0000000000..38ad5bb288
--- /dev/null
+++ b/app/src/main/java/chat/rocket/android/directory/di/DirectoryFragmentProvider.kt
@@ -0,0 +1,15 @@
+package chat.rocket.android.directory.di
+
+import chat.rocket.android.dagger.scope.PerFragment
+import chat.rocket.android.directory.ui.DirectoryFragment
+import dagger.Module
+import dagger.android.ContributesAndroidInjector
+
+@Module
+abstract class DirectoryFragmentProvider {
+
+ @ContributesAndroidInjector(modules = [DirectoryFragmentModule::class])
+ @PerFragment
+ abstract fun provideDirectoryFragment(): DirectoryFragment
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/directory/presentation/DirectoryPresenter.kt b/app/src/main/java/chat/rocket/android/directory/presentation/DirectoryPresenter.kt
new file mode 100644
index 0000000000..8063e6c897
--- /dev/null
+++ b/app/src/main/java/chat/rocket/android/directory/presentation/DirectoryPresenter.kt
@@ -0,0 +1,189 @@
+package chat.rocket.android.directory.presentation
+
+import chat.rocket.android.chatrooms.domain.FetchChatRoomsInteractor
+import chat.rocket.android.core.lifecycle.CancelStrategy
+import chat.rocket.android.db.DatabaseManager
+import chat.rocket.android.db.model.ChatRoomEntity
+import chat.rocket.android.directory.uimodel.DirectoryUiModelMapper
+import chat.rocket.android.helper.UserHelper
+import chat.rocket.android.main.presentation.MainNavigator
+import chat.rocket.android.server.infrastructure.RocketChatClientFactory
+import chat.rocket.android.util.extension.launchUI
+import chat.rocket.common.model.RoomType
+import chat.rocket.common.model.roomTypeOf
+import chat.rocket.common.util.ifNull
+import chat.rocket.core.RocketChatClient
+import chat.rocket.core.internal.rest.DirectoryRequestType
+import chat.rocket.core.internal.rest.DirectoryWorkspaceType
+import chat.rocket.core.internal.rest.createDirectMessage
+import chat.rocket.core.internal.rest.directory
+import chat.rocket.core.internal.rest.getInfo
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+import timber.log.Timber
+import javax.inject.Inject
+import javax.inject.Named
+
+class DirectoryPresenter @Inject constructor(
+ private val view: DirectoryView,
+ private val navigator: MainNavigator,
+ private val strategy: CancelStrategy,
+ @Named("currentServer") private val currentServer: String,
+ private val dbManager: DatabaseManager,
+ private val userHelper: UserHelper,
+ val factory: RocketChatClientFactory,
+ private val mapper: DirectoryUiModelMapper
+) {
+ private val client: RocketChatClient = factory.get(currentServer)
+ private var offset: Long = 0
+
+ fun loadAllDirectoryChannels(query: String? = null) {
+ launchUI(strategy) {
+ try {
+ view.showLoading()
+ val directoryResult = client.directory(
+ text = query,
+ directoryRequestType = DirectoryRequestType.Channels(),
+ offset = offset,
+ count = 60
+ )
+ val directoryUiModels = mapper.mapToUiModelList(directoryResult.result)
+ view.showChannels(directoryUiModels)
+ offset += 1 * 60L
+ } catch (exception: Exception) {
+ exception.message?.let {
+ view.showMessage(it)
+ }.ifNull {
+ view.showGenericErrorMessage()
+ }
+ } finally {
+ view.hideLoading()
+ }
+ }
+ }
+
+ fun loadAllDirectoryUsers(isSearchForGlobalUsers: Boolean, query: String? = null) {
+ launchUI(strategy) {
+ try {
+ view.showLoading()
+ val directoryResult = client.directory(
+ text = query,
+ directoryRequestType = DirectoryRequestType.Users(),
+ directoryWorkspaceType = if (isSearchForGlobalUsers) {
+ DirectoryWorkspaceType.All()
+ } else {
+ DirectoryWorkspaceType.Local()
+ },
+ offset = offset,
+ count = 60
+ )
+ val directoryUiModels = mapper.mapToUiModelList(directoryResult.result)
+ view.showUsers(directoryUiModels)
+ offset += 1 * 60L
+ } catch (exception: Exception) {
+ exception.message?.let {
+ view.showMessage(it)
+ }.ifNull {
+ view.showGenericErrorMessage()
+ }
+ } finally {
+ view.hideLoading()
+ }
+ }
+ }
+
+ fun updateSorting(
+ isSortByChannels: Boolean,
+ isSearchForGlobalUsers: Boolean,
+ query: String? = null
+ ) {
+ resetOffset()
+ if (isSortByChannels) {
+ loadAllDirectoryChannels(query)
+ } else {
+ loadAllDirectoryUsers(isSearchForGlobalUsers, query)
+ }
+ }
+
+ fun toChannel(channelId: String, name: String) {
+ launchUI(strategy) {
+ try {
+ view.showLoading()
+ withContext(Dispatchers.Default) {
+ val chatRoom = client.getInfo(channelId, name, roomTypeOf(RoomType.CHANNEL))
+ navigator.toChatRoom(
+ chatRoomId = channelId,
+ chatRoomName = name,
+ chatRoomType = RoomType.CHANNEL,
+ isReadOnly = chatRoom.readonly,
+ chatRoomLastSeen = -1,
+ isSubscribed = false,
+ isCreator = false,
+ isFavorite = false
+ )
+
+ }
+ } catch (ex: Exception) {
+ Timber.e(ex)
+ ex.message?.let {
+ view.showMessage(it)
+ }.ifNull {
+ view.showGenericErrorMessage()
+ }
+ } finally {
+ view.hideLoading()
+ }
+ }
+ }
+
+ fun tiDirectMessage(username: String, name: String) {
+ launchUI(strategy) {
+ try {
+ view.showLoading()
+
+ withContext(Dispatchers.Default) {
+ val directMessage = client.createDirectMessage(username)
+
+ val chatRoomEntity = ChatRoomEntity(
+ id = directMessage.id,
+ parentId = null,
+ name = username,
+ description = null,
+ type = RoomType.DIRECT_MESSAGE,
+ fullname = name,
+ subscriptionId = "",
+ updatedAt = directMessage.updatedAt
+ )
+
+ dbManager.insertOrReplaceRoom(chatRoomEntity)
+
+ FetchChatRoomsInteractor(client, dbManager).refreshChatRooms()
+
+ navigator.toChatRoom(
+ chatRoomId = chatRoomEntity.id,
+ chatRoomName = chatRoomEntity.name,
+ chatRoomType = chatRoomEntity.type,
+ isReadOnly = false,
+ chatRoomLastSeen = -1,
+ isSubscribed = chatRoomEntity.open,
+ isCreator = true,
+ isFavorite = false
+ )
+ }
+ } catch (ex: Exception) {
+ Timber.e(ex)
+ ex.message?.let {
+ view.showMessage(it)
+ }.ifNull {
+ view.showGenericErrorMessage()
+ }
+ } finally {
+ view.hideLoading()
+ }
+ }
+ }
+
+ private fun resetOffset() {
+ offset = 0
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/directory/presentation/DirectoryView.kt b/app/src/main/java/chat/rocket/android/directory/presentation/DirectoryView.kt
new file mode 100644
index 0000000000..9b7d03ee92
--- /dev/null
+++ b/app/src/main/java/chat/rocket/android/directory/presentation/DirectoryView.kt
@@ -0,0 +1,22 @@
+package chat.rocket.android.directory.presentation
+
+import chat.rocket.android.core.behaviours.LoadingView
+import chat.rocket.android.core.behaviours.MessageView
+import chat.rocket.android.directory.uimodel.DirectoryUiModel
+
+interface DirectoryView : MessageView, LoadingView {
+
+ /**
+ * Shows the list of directory channels.
+ *
+ * @param dataSet The data set to show.
+ */
+ fun showChannels(dataSet: List)
+
+ /**
+ * Shows the list of directory users.
+ *
+ * @param dataSet The data set to show.
+ */
+ fun showUsers(dataSet: List)
+}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/directory/ui/DirectoryFragment.kt b/app/src/main/java/chat/rocket/android/directory/ui/DirectoryFragment.kt
new file mode 100644
index 0000000000..5df73e7c99
--- /dev/null
+++ b/app/src/main/java/chat/rocket/android/directory/ui/DirectoryFragment.kt
@@ -0,0 +1,250 @@
+package chat.rocket.android.directory.ui
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.Menu
+import android.view.MenuInflater
+import android.view.MenuItem
+import android.view.View
+import android.view.ViewGroup
+import androidx.appcompat.app.AppCompatActivity
+import androidx.appcompat.widget.SearchView
+import androidx.core.view.isVisible
+import androidx.fragment.app.Fragment
+import androidx.recyclerview.widget.DividerItemDecoration
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import chat.rocket.android.R
+import chat.rocket.android.analytics.AnalyticsManager
+import chat.rocket.android.analytics.event.ScreenViewEvent
+import chat.rocket.android.directory.adapter.DirectoryAdapter
+import chat.rocket.android.directory.adapter.Selector
+import chat.rocket.android.directory.presentation.DirectoryPresenter
+import chat.rocket.android.directory.presentation.DirectoryView
+import chat.rocket.android.directory.uimodel.DirectoryUiModel
+import chat.rocket.android.helper.EndlessRecyclerViewScrollListener
+import chat.rocket.android.util.extension.onQueryTextListener
+import chat.rocket.android.util.extensions.inflate
+import chat.rocket.android.util.extensions.isNotNullNorBlank
+import chat.rocket.android.util.extensions.showToast
+import chat.rocket.android.util.extensions.ui
+import dagger.android.support.AndroidSupportInjection
+import kotlinx.android.synthetic.main.app_bar.*
+import kotlinx.android.synthetic.main.fragment_directory.*
+import kotlinx.android.synthetic.main.fragment_settings.view_loading
+import javax.inject.Inject
+
+internal const val TAG_DIRECTORY_FRAGMENT = "DirectoryFragment"
+
+fun newInstance(): Fragment = DirectoryFragment()
+
+class DirectoryFragment : Fragment(), DirectoryView {
+ @Inject lateinit var analyticsManager: AnalyticsManager
+ @Inject lateinit var presenter: DirectoryPresenter
+ private var isSortByChannels: Boolean = true
+ private var isSearchForGlobalUsers: Boolean = false
+ private val linearLayoutManager = LinearLayoutManager(context)
+ private val directoryAdapter = DirectoryAdapter(object : Selector {
+ override fun onChannelSelected(channelId: String, channelName: String) {
+ presenter.toChannel(channelId, channelName)
+ }
+ override fun onUserSelected(username: String, name: String) {
+ presenter.tiDirectMessage(username, name)
+ }
+ override fun onGlobalUserSelected(username: String, name: String) {
+ presenter.tiDirectMessage(username, name)
+ }
+ })
+ private val hashtagDrawable by lazy {
+ DrawableHelper.getDrawableFromId(R.drawable.ic_hashtag_16dp, text_sort_by.context)
+ }
+ private val userDrawable by lazy {
+ DrawableHelper.getDrawableFromId(R.drawable.ic_user_16dp, text_sort_by.context)
+ }
+ private val arrowDownDrawable by lazy {
+ DrawableHelper.getDrawableFromId(R.drawable.ic_arrow_down, text_sort_by.context)
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ AndroidSupportInjection.inject(this)
+ setHasOptionsMenu(true)
+ }
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? = container?.inflate(R.layout.fragment_directory)
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ setupToolbar()
+ setupRecyclerView()
+ setupListeners()
+ presenter.loadAllDirectoryChannels()
+ analyticsManager.logScreenView(ScreenViewEvent.Directory)
+ }
+
+ override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
+ super.onCreateOptionsMenu(menu, inflater)
+ inflater.inflate(R.menu.directory, menu)
+
+ val searchMenuItem = menu.findItem(R.id.action_search)
+ val searchView = searchMenuItem?.actionView as SearchView
+
+ with(searchView) {
+ setIconifiedByDefault(false)
+ maxWidth = Integer.MAX_VALUE
+ onQueryTextListener { updateSorting(isSortByChannels, isSearchForGlobalUsers, it) }
+ }
+
+ searchMenuItem.setOnActionExpandListener(object : MenuItem.OnActionExpandListener {
+ override fun onMenuItemActionCollapse(item: MenuItem): Boolean {
+ updateSorting(isSortByChannels, isSearchForGlobalUsers, reload = true)
+ return true
+ }
+
+ override fun onMenuItemActionExpand(item: MenuItem): Boolean {
+ return true
+ }
+ })
+
+ }
+
+
+ override fun showChannels(dataSet: List) {
+ ui {
+ if (directoryAdapter.itemCount == 0) {
+ directoryAdapter.prependData(dataSet)
+ if (dataSet.size >= 60) {
+ recycler_view.addOnScrollListener(object :
+ EndlessRecyclerViewScrollListener(linearLayoutManager) {
+ override fun onLoadMore(
+ page: Int,
+ totalItemsCount: Int,
+ recyclerView: RecyclerView
+ ) {
+ presenter.loadAllDirectoryChannels()
+ }
+ })
+ }
+ } else {
+ directoryAdapter.appendData(dataSet)
+ }
+ }
+ }
+
+ override fun showUsers(dataSet: List) {
+ ui {
+ if (directoryAdapter.itemCount == 0) {
+ directoryAdapter.prependData(dataSet)
+ if (dataSet.size >= 60) {
+ recycler_view.addOnScrollListener(object :
+ EndlessRecyclerViewScrollListener(linearLayoutManager) {
+ override fun onLoadMore(
+ page: Int,
+ totalItemsCount: Int,
+ recyclerView: RecyclerView
+ ) {
+ presenter.loadAllDirectoryUsers(isSearchForGlobalUsers)
+ }
+ })
+ }
+ } else {
+ directoryAdapter.appendData(dataSet)
+ }
+ }
+ }
+
+ override fun showMessage(resId: Int) {
+ ui { showToast(resId) }
+ }
+
+ override fun showMessage(message: String) {
+ ui { showToast(message) }
+ }
+
+ override fun showGenericErrorMessage() = showMessage(getString(R.string.msg_generic_error))
+
+ override fun showLoading() {
+ view_loading.isVisible = true
+ }
+
+ override fun hideLoading() {
+ view_loading.isVisible = false
+ }
+
+ fun updateSorting(
+ isSortByChannels: Boolean,
+ isSearchForGlobalUsers: Boolean,
+ query: String? = null,
+ reload: Boolean = false
+ ) {
+ if (query.isNotNullNorBlank() || reload) {
+ directoryAdapter.clearData()
+ presenter.updateSorting(isSortByChannels, isSearchForGlobalUsers, query)
+ }
+
+ if (this.isSortByChannels != isSortByChannels ||
+ this.isSearchForGlobalUsers != isSearchForGlobalUsers
+ ) {
+ this.isSortByChannels = isSortByChannels
+ this.isSearchForGlobalUsers = isSearchForGlobalUsers
+ updateSortByTitle()
+ with(directoryAdapter) {
+ clearData()
+ setSorting(isSortByChannels, isSearchForGlobalUsers)
+ }
+ presenter.updateSorting(isSortByChannels, isSearchForGlobalUsers, query)
+ }
+ }
+
+ private fun setupToolbar() {
+ with((activity as AppCompatActivity)) {
+ with(toolbar) {
+ setSupportActionBar(this)
+ title = getString(R.string.msg_directory)
+ setNavigationIcon(R.drawable.ic_arrow_back_white_24dp)
+ setNavigationOnClickListener { activity?.onBackPressed() }
+ }
+ }
+ }
+
+ private fun setupRecyclerView() {
+ ui {
+ with(recycler_view) {
+ layoutManager = linearLayoutManager
+ addItemDecoration(DividerItemDecoration(it, DividerItemDecoration.HORIZONTAL))
+ adapter = directoryAdapter
+ }
+ }
+ }
+
+ private fun setupListeners() {
+ text_sort_by.setOnClickListener {
+ activity?.supportFragmentManager?.let {
+ showDirectorySortingBottomSheetFragment(isSortByChannels, isSearchForGlobalUsers, it)
+ }
+ }
+ }
+
+
+ private fun updateSortByTitle() {
+ if (isSortByChannels) {
+ text_sort_by.text = getString(R.string.msg_channels)
+ DrawableHelper.compoundStartAndEndDrawable(
+ text_sort_by,
+ hashtagDrawable,
+ arrowDownDrawable
+ )
+ } else {
+ text_sort_by.text = getString(R.string.msg_users)
+ DrawableHelper.compoundStartAndEndDrawable(
+ text_sort_by,
+ userDrawable,
+ arrowDownDrawable
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/directory/ui/DirectorySortingBottomSheetFragment.kt b/app/src/main/java/chat/rocket/android/directory/ui/DirectorySortingBottomSheetFragment.kt
new file mode 100644
index 0000000000..31ca732f3a
--- /dev/null
+++ b/app/src/main/java/chat/rocket/android/directory/ui/DirectorySortingBottomSheetFragment.kt
@@ -0,0 +1,123 @@
+package chat.rocket.android.directory.ui
+
+import DrawableHelper
+import android.content.DialogInterface
+import android.graphics.drawable.Drawable
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.TextView
+import androidx.fragment.app.FragmentManager
+import chat.rocket.android.R
+import com.google.android.material.bottomsheet.BottomSheetDialogFragment
+import kotlinx.android.synthetic.main.bottom_sheet_fragment_directory_sorting.*
+
+fun showDirectorySortingBottomSheetFragment(
+ isSortByChannels: Boolean,
+ isSearchForGlobalUsers: Boolean,
+ supportFragmentManager: FragmentManager
+) = DirectorySortingBottomSheetFragment().apply {
+ arguments = Bundle(2).apply {
+ putBoolean(BUNDLE_IS_SORT_BY_CHANNELS, isSortByChannels)
+ putBoolean(BUNDLE_IS_SEARCH_FOR_GLOBAL_USERS, isSearchForGlobalUsers)
+ }
+}.show(supportFragmentManager, TAG)
+
+internal const val TAG = "DirectorySortingBottomSheetFragment"
+
+private const val BUNDLE_IS_SORT_BY_CHANNELS = "is_sort_by_channels"
+private const val BUNDLE_IS_SEARCH_FOR_GLOBAL_USERS = "is_search_for_global_users"
+
+class DirectorySortingBottomSheetFragment : BottomSheetDialogFragment() {
+ private var isSortByChannels = true
+ private var isSearchForGlobalUsers = false
+ private val hashtagDrawable by lazy {
+ DrawableHelper.getDrawableFromId(R.drawable.ic_hashtag_16dp, requireContext())
+ }
+ private val userDrawable by lazy {
+ DrawableHelper.getDrawableFromId(R.drawable.ic_user_16dp, requireContext())
+ }
+ private val checkDrawable by lazy {
+ DrawableHelper.getDrawableFromId(R.drawable.ic_check, requireContext())
+ }
+ private val directoryFragment by lazy {
+ activity?.supportFragmentManager?.findFragmentByTag(TAG_DIRECTORY_FRAGMENT) as DirectoryFragment
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ arguments?.run {
+ isSortByChannels = getBoolean(BUNDLE_IS_SORT_BY_CHANNELS)
+ isSearchForGlobalUsers = getBoolean(BUNDLE_IS_SEARCH_FOR_GLOBAL_USERS)
+ }
+ ?: requireNotNull(arguments) { "no arguments supplied when the bottom sheet fragment was instantiated" }
+ }
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? =
+ inflater.inflate(R.layout.bottom_sheet_fragment_directory_sorting, container, false)
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ setupView()
+ setupListeners()
+ }
+
+ override fun onCancel(dialog: DialogInterface?) {
+ super.onCancel(dialog)
+ }
+
+ private fun setupView() {
+ if (isSortByChannels) {
+ checkSelection(text_channels, hashtagDrawable)
+ } else {
+ checkSelection(text_users, userDrawable)
+ }
+
+ switch_global_users.isChecked = isSearchForGlobalUsers
+ }
+
+ private fun setupListeners() {
+ text_channels.setOnClickListener {
+ checkSelection(text_channels, hashtagDrawable)
+ uncheckSelection(text_users, userDrawable)
+ isSortByChannels = true
+ directoryFragment.updateSorting(isSortByChannels, isSearchForGlobalUsers)
+ }
+
+ text_users.setOnClickListener {
+ checkSelection(text_users, userDrawable)
+ uncheckSelection(text_channels, hashtagDrawable)
+ isSortByChannels = false
+ directoryFragment.updateSorting(isSortByChannels, isSearchForGlobalUsers)
+ }
+
+ switch_global_users.setOnCheckedChangeListener { _, isChecked ->
+ isSearchForGlobalUsers = isChecked
+ directoryFragment.updateSorting(isSortByChannels, isSearchForGlobalUsers)
+ }
+ }
+
+ private fun checkSelection(textView: TextView, startDrawable: Drawable) {
+ context?.let {
+ DrawableHelper.compoundStartAndEndDrawable(
+ textView,
+ startDrawable,
+ checkDrawable
+ )
+ }
+ }
+
+ private fun uncheckSelection(textView: TextView, startDrawable: Drawable) {
+ context?.let {
+ DrawableHelper.compoundStartDrawable(
+ textView,
+ startDrawable
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/directory/uimodel/DirectoryUiModel.kt b/app/src/main/java/chat/rocket/android/directory/uimodel/DirectoryUiModel.kt
new file mode 100644
index 0000000000..df586f9dcd
--- /dev/null
+++ b/app/src/main/java/chat/rocket/android/directory/uimodel/DirectoryUiModel.kt
@@ -0,0 +1,35 @@
+package chat.rocket.android.directory.uimodel
+
+import chat.rocket.android.util.extensions.avatarUrl
+import chat.rocket.common.model.Token
+import chat.rocket.core.model.DirectoryResult
+
+class DirectoryUiModel(
+ private val directoryResult: DirectoryResult,
+ private val baseUrl: String?,
+ private val token: Token?
+) {
+ val id: String = directoryResult.id
+ val channelAvatarUri: String?
+ val userAvatarUri: String?
+ val name: String = directoryResult.name
+ val username: String = "@${directoryResult.username}"
+ val serverUrl: String = "" // TODO
+ val description: String = "" // TODO
+ val totalMembers: String = "" // TODO
+
+ init {
+ channelAvatarUri = getChannelAvatar()
+ userAvatarUri = getUserAvatar()
+ }
+
+ private fun getChannelAvatar(): String? {
+ return baseUrl?.avatarUrl(name, token?.userId, token?.authToken, isGroupOrChannel = true)
+ }
+
+ private fun getUserAvatar(): String? {
+ return directoryResult.username?.let {
+ baseUrl?.avatarUrl(it, token?.userId, token?.authToken)
+ }
+ }
+}
diff --git a/app/src/main/java/chat/rocket/android/directory/uimodel/DirectoryUiModelMapper.kt b/app/src/main/java/chat/rocket/android/directory/uimodel/DirectoryUiModelMapper.kt
new file mode 100644
index 0000000000..47564b9120
--- /dev/null
+++ b/app/src/main/java/chat/rocket/android/directory/uimodel/DirectoryUiModelMapper.kt
@@ -0,0 +1,23 @@
+package chat.rocket.android.directory.uimodel
+
+import chat.rocket.android.server.domain.GetSettingsInteractor
+import chat.rocket.android.server.domain.TokenRepository
+import chat.rocket.android.server.domain.baseUrl
+import chat.rocket.core.model.DirectoryResult
+import chat.rocket.core.model.Value
+import javax.inject.Inject
+import javax.inject.Named
+
+class DirectoryUiModelMapper @Inject constructor(
+ getSettingsInteractor: GetSettingsInteractor,
+ @Named("currentServer") private val currentServer: String,
+ tokenRepository: TokenRepository
+) {
+ private var settings: Map> = getSettingsInteractor.get(currentServer)
+ private val baseUrl = settings.baseUrl()
+ private val token = tokenRepository.get(currentServer)
+
+ fun mapToUiModelList(directoryList: List): List {
+ return directoryList.map { DirectoryUiModel(it, baseUrl, token) }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/favoritemessages/presentation/FavoriteMessagesPresenter.kt b/app/src/main/java/chat/rocket/android/favoritemessages/presentation/FavoriteMessagesPresenter.kt
index 3d6a655dea..3f13d09d89 100644
--- a/app/src/main/java/chat/rocket/android/favoritemessages/presentation/FavoriteMessagesPresenter.kt
+++ b/app/src/main/java/chat/rocket/android/favoritemessages/presentation/FavoriteMessagesPresenter.kt
@@ -3,9 +3,8 @@ package chat.rocket.android.favoritemessages.presentation
import chat.rocket.android.chatroom.uimodel.UiModelMapper
import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.db.DatabaseManager
-import chat.rocket.android.server.infraestructure.RocketChatClientFactory
+import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI
-import chat.rocket.android.util.retryDB
import chat.rocket.common.RocketChatException
import chat.rocket.common.model.roomTypeOf
import chat.rocket.common.util.ifNull
@@ -23,7 +22,7 @@ class FavoriteMessagesPresenter @Inject constructor(
private val mapper: UiModelMapper,
val factory: RocketChatClientFactory
) {
- private val client: RocketChatClient = factory.create(currentServer)
+ private val client: RocketChatClient = factory.get(currentServer)
private var offset: Int = 0
/**
diff --git a/app/src/main/java/chat/rocket/android/files/presentation/FilesPresenter.kt b/app/src/main/java/chat/rocket/android/files/presentation/FilesPresenter.kt
index 38275e4015..be0bb30f61 100644
--- a/app/src/main/java/chat/rocket/android/files/presentation/FilesPresenter.kt
+++ b/app/src/main/java/chat/rocket/android/files/presentation/FilesPresenter.kt
@@ -5,9 +5,8 @@ import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.db.DatabaseManager
import chat.rocket.android.files.uimodel.FileUiModel
import chat.rocket.android.files.uimodel.FileUiModelMapper
-import chat.rocket.android.server.infraestructure.RocketChatClientFactory
+import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI
-import chat.rocket.android.util.retryDB
import chat.rocket.common.RocketChatException
import chat.rocket.common.model.roomTypeOf
import chat.rocket.common.util.ifNull
@@ -25,7 +24,7 @@ class FilesPresenter @Inject constructor(
private val mapper: FileUiModelMapper,
val factory: RocketChatClientFactory
) {
- private val client: RocketChatClient = factory.create(currentServer)
+ private val client: RocketChatClient = factory.get(currentServer)
private var offset: Int = 0
/**
diff --git a/app/src/main/java/chat/rocket/android/helper/AndroidPermissionsHelper.kt b/app/src/main/java/chat/rocket/android/helper/AndroidPermissionsHelper.kt
index 8effca8c56..8b12ba0908 100644
--- a/app/src/main/java/chat/rocket/android/helper/AndroidPermissionsHelper.kt
+++ b/app/src/main/java/chat/rocket/android/helper/AndroidPermissionsHelper.kt
@@ -1,23 +1,60 @@
package chat.rocket.android.helper
+import android.Manifest
import android.app.Activity
import android.content.Context
import android.content.pm.PackageManager
+import android.view.ContextThemeWrapper
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
+import androidx.fragment.app.Fragment
object AndroidPermissionsHelper {
const val WRITE_EXTERNAL_STORAGE_CODE = 1
+ const val CAMERA_CODE = 2
- fun checkPermission(context: Context, permission: String): Boolean {
+ private fun checkPermission(context: Context, permission: String): Boolean {
return ContextCompat.checkSelfPermission(
context,
permission
) == PackageManager.PERMISSION_GRANTED
}
- fun requestPermission(context: Activity, permission: String, requestCode: Int) {
+ private fun requestPermission(context: Activity, permission: String, requestCode: Int) {
ActivityCompat.requestPermissions(context, arrayOf(permission), requestCode)
}
+
+ fun hasCameraPermission(context: Context): Boolean {
+ return checkPermission(context, Manifest.permission.CAMERA)
+ }
+
+ fun getCameraPermission(fragment: Fragment) {
+ fragment.requestPermissions(
+ arrayOf(Manifest.permission.CAMERA),
+ CAMERA_CODE
+ )
+ }
+
+ fun hasWriteExternalStoragePermission(context: Context): Boolean {
+ return checkPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE)
+ }
+
+ fun getWriteExternalStoragePermission(fragment: Fragment) {
+ fragment.requestPermissions(
+ arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
+ WRITE_EXTERNAL_STORAGE_CODE
+ )
+ }
+
+ fun checkWritingPermission(context: Context) {
+ if (context is ContextThemeWrapper) {
+ val activity = if (context.baseContext is Activity) context.baseContext as Activity else context as Activity
+ requestPermission(
+ activity,
+ Manifest.permission.WRITE_EXTERNAL_STORAGE,
+ WRITE_EXTERNAL_STORAGE_CODE
+ )
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/helper/Constants.kt b/app/src/main/java/chat/rocket/android/helper/Constants.kt
deleted file mode 100644
index 7dbeb08ec2..0000000000
--- a/app/src/main/java/chat/rocket/android/helper/Constants.kt
+++ /dev/null
@@ -1,18 +0,0 @@
-package chat.rocket.android.helper
-
-object Constants {
- const val CHATROOM_SORT_TYPE_KEY: String = "chatroom_sort_type"
- const val CHATROOM_GROUP_BY_TYPE_KEY: String = "chatroom_group_by_type"
- const val CHATROOM_GROUP_FAVOURITES_KEY: String = "chatroom_group_favourites"
-
- //Used to sort chat rooms
- const val CHATROOM_CHANNEL = 0
- const val CHATROOM_PRIVATE_GROUP = 1
- const val CHATROOM_DM = 2
- const val CHATROOM_LIVE_CHAT = 3
-}
-
-object ChatRoomsSortOrder {
- const val ALPHABETICAL: Int = 0
- const val ACTIVITY: Int = 1
-}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/helper/ImageHelper.kt b/app/src/main/java/chat/rocket/android/helper/ImageHelper.kt
index 0d48ed25d5..5fe5944860 100644
--- a/app/src/main/java/chat/rocket/android/helper/ImageHelper.kt
+++ b/app/src/main/java/chat/rocket/android/helper/ImageHelper.kt
@@ -1,7 +1,5 @@
package chat.rocket.android.helper
-import android.Manifest
-import android.app.Activity
import android.content.Context
import android.graphics.Color
import android.graphics.Typeface
@@ -9,7 +7,6 @@ import android.media.MediaScannerConnection
import android.os.Environment
import android.text.TextUtils
import android.util.TypedValue
-import android.view.ContextThemeWrapper
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
@@ -18,6 +15,8 @@ import androidx.appcompat.widget.Toolbar
import androidx.core.net.toUri
import androidx.core.view.setPadding
import chat.rocket.android.R
+import chat.rocket.android.helper.AndroidPermissionsHelper.checkWritingPermission
+import chat.rocket.android.helper.AndroidPermissionsHelper.hasWriteExternalStoragePermission
import com.facebook.binaryresource.FileBinaryResource
import com.facebook.cache.common.CacheKey
import com.facebook.imageformat.ImageFormatChecker
@@ -117,7 +116,7 @@ object ImageHelper {
}
private fun saveImage(context: Context): Boolean {
- if (!canWriteToExternalStorage(context)) {
+ if (!hasWriteExternalStoragePermission(context)) {
checkWritingPermission(context)
return false
}
@@ -152,22 +151,4 @@ object ImageHelper {
}
return true
}
-
- fun canWriteToExternalStorage(context: Context): Boolean {
- return AndroidPermissionsHelper.checkPermission(
- context,
- Manifest.permission.WRITE_EXTERNAL_STORAGE
- )
- }
-
- fun checkWritingPermission(context: Context) {
- if (context is ContextThemeWrapper) {
- val activity = if (context.baseContext is Activity) context.baseContext as Activity else context as Activity
- AndroidPermissionsHelper.requestPermission(
- activity,
- Manifest.permission.WRITE_EXTERNAL_STORAGE,
- AndroidPermissionsHelper.WRITE_EXTERNAL_STORAGE_CODE
- )
- }
- }
}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/helper/JitsiHelper.kt b/app/src/main/java/chat/rocket/android/helper/JitsiHelper.kt
index b123cfe547..37a746d471 100644
--- a/app/src/main/java/chat/rocket/android/helper/JitsiHelper.kt
+++ b/app/src/main/java/chat/rocket/android/helper/JitsiHelper.kt
@@ -3,7 +3,7 @@ package chat.rocket.android.helper
object JitsiHelper {
/**
- * Returns the for the Jitsi video conferencing URL.
+ * Returns the Jitsi video conferencing URL.
*
* @param isSecureProtocol True if using SSL, false otherwise - from the public settings.
* @param domain The Jitsi domain - from public settings.
diff --git a/app/src/main/java/chat/rocket/android/helper/MessageParser.kt b/app/src/main/java/chat/rocket/android/helper/MessageParser.kt
index bdfad6bcc5..655691eabf 100644
--- a/app/src/main/java/chat/rocket/android/helper/MessageParser.kt
+++ b/app/src/main/java/chat/rocket/android/helper/MessageParser.kt
@@ -94,10 +94,16 @@ class MessageParser @Inject constructor(
}
private fun getMention(user: SimpleUser): String {
+ user.id?.let {
+ if (SYSTEM_MENTIONS.contains(it)) {
+ return "@$it"
+ }
+ }
+
return if (settings.useRealName()) {
- user.name ?: "@${user.username}"
+ user.name ?: user.username.orEmpty()
} else {
- "@${user.username}"
+ user.username.orEmpty()
}
}
@@ -527,5 +533,7 @@ class MessageParser @Inject constructor(
*/
private val WEB_URL = Pattern.compile(
"($WEB_URL_WITH_PROTOCOL|$WEB_URL_WITHOUT_PROTOCOL)")
+
+ private val SYSTEM_MENTIONS = arrayOf("all", "here")
}
}
diff --git a/app/src/main/java/chat/rocket/android/helper/OauthHelper.kt b/app/src/main/java/chat/rocket/android/helper/OauthHelper.kt
index 241529214e..952dab1454 100644
--- a/app/src/main/java/chat/rocket/android/helper/OauthHelper.kt
+++ b/app/src/main/java/chat/rocket/android/helper/OauthHelper.kt
@@ -15,11 +15,11 @@ object OauthHelper {
"\"isCordova\":true}").encodeToBase64()
/**
- * Returns the Github Oauth URL.
+ * Returns the GitHub Oauth URL.
*
* @param clientId The GitHub client ID.
* @param state An unguessable random string used to protect against forgery attacks.
- * @return The Github Oauth URL.
+ * @return The GitHub Oauth URL.
*/
fun getGithubOauthUrl(clientId: String, state: String): String {
return "https://github.com/login/oauth/authorize" +
@@ -46,12 +46,12 @@ object OauthHelper {
}
/**
- * Returns the Linkedin Oauth URL.
+ * Returns the LinkedIn Oauth URL.
*
- * @param clientId The Linkedin client ID.
+ * @param clientId The LinkedIn client ID.
* @param serverUrl The server URL.
* @param state An unguessable random string used to protect against forgery attacks.
- * @return The Linkedin Oauth URL.
+ * @return The LinkedIn Oauth URL.
*/
fun getLinkedinOauthUrl(clientId: String, serverUrl: String, state: String): String {
return "https://linkedin.com/oauth/v2/authorization" +
@@ -62,13 +62,13 @@ object OauthHelper {
}
/**
- * Returns the Gitlab Oauth URL.
+ * Returns the GitLab Oauth URL.
*
- * @param host The Gitlab host.
- * @param clientId The Gitlab client ID.
+ * @param host The GitLab host.
+ * @param clientId The GitLab client ID.
* @param serverUrl The server URL.
* @param state An unguessable random string used to protect against forgery attacks.
- * @return The Gitlab Oauth URL.
+ * @return The GitLab Oauth URL.
*/
fun getGitlabOauthUrl(
host: String? = "https://gitlab.com",
diff --git a/app/src/main/java/chat/rocket/android/helper/SharedPreferenceHelper.kt b/app/src/main/java/chat/rocket/android/helper/SharedPreferenceHelper.kt
deleted file mode 100644
index 61e789af81..0000000000
--- a/app/src/main/java/chat/rocket/android/helper/SharedPreferenceHelper.kt
+++ /dev/null
@@ -1,48 +0,0 @@
-package chat.rocket.android.helper
-
-import android.content.SharedPreferences
-import android.preference.PreferenceManager
-import chat.rocket.android.app.RocketChatApplication
-
-object SharedPreferenceHelper {
- private var sharedPreferences: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(RocketChatApplication.getAppContext())
- private var editor: SharedPreferences.Editor? = sharedPreferences.edit()
-
- //Add more methods for other types if needed
-
- fun putInt(key: String, value: Int) {
- editor!!.putInt(key, value).apply()
- }
-
- fun getInt(key: String, defaultValue: Int): Int {
- return sharedPreferences.getInt(key, defaultValue)
- }
-
- fun putLong(key: String, value: Long) {
- editor!!.putLong(key, value).apply()
- }
-
- fun getLong(key: String, defaultValue: Long): Long {
- return sharedPreferences.getLong(key, defaultValue)
- }
-
- fun putString(key: String, value: String) {
- editor!!.putString(key, value).apply()
- }
-
- fun getString(key: String, defaultValue: String): String? {
- return sharedPreferences.getString(key, defaultValue)
- }
-
- fun putBoolean(key: String, value: Boolean) {
- editor!!.putBoolean(key, value).apply()
- }
-
- fun getBoolean(key: String, defaultValue: Boolean): Boolean {
- return sharedPreferences.getBoolean(key, defaultValue)
- }
-
- fun remove(key: String) {
- editor!!.remove(key).apply()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/helper/UserHelper.kt b/app/src/main/java/chat/rocket/android/helper/UserHelper.kt
index 90e9ede0e2..06d5289e73 100644
--- a/app/src/main/java/chat/rocket/android/helper/UserHelper.kt
+++ b/app/src/main/java/chat/rocket/android/helper/UserHelper.kt
@@ -24,6 +24,24 @@ class UserHelper @Inject constructor(
*/
fun username(): String? = localRepository.get(LocalRepository.CURRENT_USERNAME_KEY, null)
+ /**
+ * Return the name for the current logged [User].
+ */
+ fun name(): String? = user()?.name
+
+ /**
+ * Return the display name for the given [user].
+ * If setting 'Use_Real_Name' is true then the real name will be given, otherwise the username
+ * without the '@' is yielded.
+ */
+ fun displayName(user: User) = getCurrentServerInteractor.get()?.let {
+ if (settingsRepository.get(it).useRealName()) {
+ user.name
+ } else {
+ user.username
+ }
+ }
+
/**
* Return the display name for the given [user].
* If setting 'Use_Real_Name' is true then the real name will be given, otherwise the username
diff --git a/app/src/main/java/chat/rocket/android/main/adapter/AccountViewHolder.kt b/app/src/main/java/chat/rocket/android/main/adapter/AccountViewHolder.kt
deleted file mode 100644
index 6c9e79dc4a..0000000000
--- a/app/src/main/java/chat/rocket/android/main/adapter/AccountViewHolder.kt
+++ /dev/null
@@ -1,17 +0,0 @@
-package chat.rocket.android.main.adapter
-
-import androidx.recyclerview.widget.RecyclerView
-import android.view.View
-import chat.rocket.android.server.domain.model.Account
-import kotlinx.android.synthetic.main.item_account.view.*
-
-class AccountViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
-
- fun bind(account: Account) {
- with(itemView) {
- server_logo.setImageURI(account.serverLogo)
- text_server_url.text = account.serverUrl
- text_username.text = account.userName
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/main/adapter/AccountsAdapter.kt b/app/src/main/java/chat/rocket/android/main/adapter/AccountsAdapter.kt
deleted file mode 100644
index d3b8683263..0000000000
--- a/app/src/main/java/chat/rocket/android/main/adapter/AccountsAdapter.kt
+++ /dev/null
@@ -1,68 +0,0 @@
-package chat.rocket.android.main.adapter
-
-import androidx.recyclerview.widget.RecyclerView
-import android.view.ViewGroup
-import chat.rocket.android.R
-import chat.rocket.android.server.domain.model.Account
-import chat.rocket.android.util.extensions.inflate
-import chat.rocket.common.model.UserStatus
-
-private const val VIEW_TYPE_CHANGE_STATUS = 0
-private const val VIEW_TYPE_ACCOUNT = 1
-private const val VIEW_TYPE_ADD_ACCOUNT = 2
-
-class AccountsAdapter(
- private val accounts: List,
- private val selector: Selector
-) : RecyclerView.Adapter() {
-
- override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
- return when (viewType) {
- VIEW_TYPE_CHANGE_STATUS -> StatusViewHolder(parent.inflate(R.layout.item_change_status))
- VIEW_TYPE_ACCOUNT -> AccountViewHolder(parent.inflate(R.layout.item_account))
- else -> AddAccountViewHolder(parent.inflate(R.layout.item_add_account))
- }
- }
-
- override fun getItemCount() = accounts.size + 2
-
- override fun getItemViewType(position: Int): Int {
- return when {
- position == 0 -> VIEW_TYPE_CHANGE_STATUS
- position <= accounts.size -> VIEW_TYPE_ACCOUNT
- else -> VIEW_TYPE_ADD_ACCOUNT
- }
- }
-
- override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
- when (holder) {
- is StatusViewHolder -> bindStatusViewHolder(holder)
- is AccountViewHolder -> bindAccountViewHolder(holder, position)
- is AddAccountViewHolder -> bindAddAccountViewHolder(holder)
- }
- }
-
- private fun bindStatusViewHolder(holder: StatusViewHolder) {
- holder.bind { userStatus -> selector.onStatusSelected(userStatus) }
- }
-
- private fun bindAccountViewHolder(holder: AccountViewHolder, position: Int) {
- val account = accounts[position - 1]
- holder.bind(account)
- holder.itemView.setOnClickListener {
- selector.onAccountSelected(account.serverUrl)
- }
- }
-
- private fun bindAddAccountViewHolder(holder: AddAccountViewHolder) {
- holder.itemView.setOnClickListener {
- selector.onAddedAccountSelected()
- }
- }
-}
-
-interface Selector {
- fun onStatusSelected(userStatus: UserStatus)
- fun onAccountSelected(serverUrl: String)
- fun onAddedAccountSelected()
-}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/main/adapter/AddAccountViewHolder.kt b/app/src/main/java/chat/rocket/android/main/adapter/AddAccountViewHolder.kt
deleted file mode 100644
index 4660dadb12..0000000000
--- a/app/src/main/java/chat/rocket/android/main/adapter/AddAccountViewHolder.kt
+++ /dev/null
@@ -1,6 +0,0 @@
-package chat.rocket.android.main.adapter
-
-import androidx.recyclerview.widget.RecyclerView
-import android.view.View
-
-class AddAccountViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/main/adapter/StatusViewHolder.kt b/app/src/main/java/chat/rocket/android/main/adapter/StatusViewHolder.kt
deleted file mode 100644
index 86fae29681..0000000000
--- a/app/src/main/java/chat/rocket/android/main/adapter/StatusViewHolder.kt
+++ /dev/null
@@ -1,18 +0,0 @@
-package chat.rocket.android.main.adapter
-
-import androidx.recyclerview.widget.RecyclerView
-import android.view.View
-import chat.rocket.common.model.UserStatus
-import kotlinx.android.synthetic.main.item_change_status.view.*
-
-class StatusViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
-
- fun bind(listener: (UserStatus) -> Unit) {
- with(itemView) {
- text_online.setOnClickListener { listener(UserStatus.Online()) }
- text_away.setOnClickListener { listener(UserStatus.Away()) }
- text_busy.setOnClickListener { listener(UserStatus.Busy()) }
- text_invisible.setOnClickListener { listener(UserStatus.Offline()) }
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/main/di/MainModule.kt b/app/src/main/java/chat/rocket/android/main/di/MainModule.kt
index 91ae6a7ad4..ab8819e171 100644
--- a/app/src/main/java/chat/rocket/android/main/di/MainModule.kt
+++ b/app/src/main/java/chat/rocket/android/main/di/MainModule.kt
@@ -1,10 +1,10 @@
package chat.rocket.android.main.di
import androidx.lifecycle.LifecycleOwner
+import chat.rocket.android.core.behaviours.AppLanguageView
import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.dagger.scope.PerActivity
import chat.rocket.android.main.presentation.MainNavigator
-import chat.rocket.android.main.presentation.MainView
import chat.rocket.android.main.ui.MainActivity
import dagger.Module
import dagger.Provides
@@ -15,14 +15,17 @@ class MainModule {
@Provides
@PerActivity
- fun provideJob() = Job()
+ fun provideMainNavigator(activity: MainActivity) = MainNavigator(activity)
@Provides
@PerActivity
- fun provideMainNavigator(activity: MainActivity) = MainNavigator(activity)
+ fun appLanguageView(activity: MainActivity): AppLanguageView {
+ return activity
+ }
@Provides
- fun provideMainView(activity: MainActivity): MainView = activity
+ @PerActivity
+ fun provideJob() = Job()
@Provides
fun provideLifecycleOwner(activity: MainActivity): LifecycleOwner = activity
diff --git a/app/src/main/java/chat/rocket/android/main/presentation/MainNavigator.kt b/app/src/main/java/chat/rocket/android/main/presentation/MainNavigator.kt
index c149448922..49b8da299f 100644
--- a/app/src/main/java/chat/rocket/android/main/presentation/MainNavigator.kt
+++ b/app/src/main/java/chat/rocket/android/main/presentation/MainNavigator.kt
@@ -3,51 +3,60 @@ package chat.rocket.android.main.presentation
import chat.rocket.android.R
import chat.rocket.android.authentication.ui.newServerIntent
import chat.rocket.android.chatroom.ui.chatRoomIntent
-import chat.rocket.android.chatrooms.ui.ChatRoomsFragment
import chat.rocket.android.chatrooms.ui.TAG_CHAT_ROOMS_FRAGMENT
-import chat.rocket.android.createchannel.ui.CreateChannelFragment
import chat.rocket.android.createchannel.ui.TAG_CREATE_CHANNEL_FRAGMENT
+import chat.rocket.android.directory.ui.TAG_DIRECTORY_FRAGMENT
import chat.rocket.android.main.ui.MainActivity
-import chat.rocket.android.profile.ui.ProfileFragment
import chat.rocket.android.profile.ui.TAG_PROFILE_FRAGMENT
import chat.rocket.android.server.ui.changeServerIntent
-import chat.rocket.android.settings.ui.SettingsFragment
import chat.rocket.android.settings.ui.TAG_SETTINGS_FRAGMENT
import chat.rocket.android.util.extensions.addFragment
-import chat.rocket.android.webview.adminpanel.ui.AdminPanelWebViewFragment
+import chat.rocket.android.util.extensions.addFragmentBackStack
+import chat.rocket.android.webview.adminpanel.ui.TAG_ADMIN_PANEL_WEB_VIEW_FRAGMENT
+import chat.rocket.android.webview.ui.webViewIntent
class MainNavigator(internal val activity: MainActivity) {
fun toChatList(chatRoomId: String? = null) {
activity.addFragment(TAG_CHAT_ROOMS_FRAGMENT, R.id.fragment_container) {
- ChatRoomsFragment.newInstance(chatRoomId)
+ chat.rocket.android.chatrooms.ui.newInstance(chatRoomId)
}
}
- fun toCreateChannel() {
- activity.addFragment(TAG_CREATE_CHANNEL_FRAGMENT, R.id.fragment_container) {
- CreateChannelFragment.newInstance()
+ fun toSettings() {
+ activity.addFragmentBackStack(TAG_SETTINGS_FRAGMENT, R.id.fragment_container) {
+ chat.rocket.android.settings.ui.newInstance()
}
}
- fun toUserProfile() {
- activity.addFragment(TAG_PROFILE_FRAGMENT, R.id.fragment_container) {
- ProfileFragment.newInstance()
+ fun toDirectory() {
+ activity.addFragmentBackStack(TAG_DIRECTORY_FRAGMENT, R.id.fragment_container) {
+ chat.rocket.android.directory.ui.newInstance()
}
}
- fun toSettings() {
- activity.addFragment(TAG_SETTINGS_FRAGMENT, R.id.fragment_container) {
- SettingsFragment.newInstance()
+ fun toCreateChannel() {
+ activity.addFragmentBackStack(TAG_CREATE_CHANNEL_FRAGMENT, R.id.fragment_container) {
+ chat.rocket.android.createchannel.ui.newInstance()
+ }
+ }
+
+ fun toProfile() {
+ activity.addFragmentBackStack(TAG_PROFILE_FRAGMENT, R.id.fragment_container) {
+ chat.rocket.android.profile.ui.newInstance()
}
}
fun toAdminPanel(webPageUrl: String, userToken: String) {
- activity.addFragment("AdminPanelWebViewFragment", R.id.fragment_container) {
- AdminPanelWebViewFragment.newInstance(webPageUrl, userToken)
+ activity.addFragmentBackStack(TAG_ADMIN_PANEL_WEB_VIEW_FRAGMENT, R.id.fragment_container) {
+ chat.rocket.android.webview.adminpanel.ui.newInstance(webPageUrl, userToken)
}
}
+ fun toLicense(licenseUrl: String, licenseTitle: String) {
+ activity.startActivity(activity.webViewIntent(licenseUrl, licenseTitle))
+ }
+
fun toChatRoom(
chatRoomId: String,
chatRoomName: String,
diff --git a/app/src/main/java/chat/rocket/android/main/presentation/MainPresenter.kt b/app/src/main/java/chat/rocket/android/main/presentation/MainPresenter.kt
index d192b466b1..f0732314fd 100644
--- a/app/src/main/java/chat/rocket/android/main/presentation/MainPresenter.kt
+++ b/app/src/main/java/chat/rocket/android/main/presentation/MainPresenter.kt
@@ -1,244 +1,47 @@
package chat.rocket.android.main.presentation
-import android.content.Context
-import chat.rocket.android.core.lifecycle.CancelStrategy
-import chat.rocket.android.db.DatabaseManagerFactory
-import chat.rocket.android.emoji.Emoji
-import chat.rocket.android.emoji.EmojiRepository
-import chat.rocket.android.emoji.Fitzpatrick
-import chat.rocket.android.emoji.internal.EmojiCategory
-import chat.rocket.android.infrastructure.LocalRepository
-import chat.rocket.android.main.uimodel.NavHeaderUiModel
-import chat.rocket.android.main.uimodel.NavHeaderUiModelMapper
+import chat.rocket.android.core.behaviours.AppLanguageView
import chat.rocket.android.push.GroupedPush
-import chat.rocket.android.server.domain.GetAccountsInteractor
-import chat.rocket.android.server.domain.GetCurrentServerInteractor
-import chat.rocket.android.server.domain.GetSettingsInteractor
-import chat.rocket.android.server.domain.PublicSettings
-import chat.rocket.android.server.domain.RefreshSettingsInteractor
+import chat.rocket.android.server.domain.GetCurrentLanguageInteractor
import chat.rocket.android.server.domain.RefreshPermissionsInteractor
-import chat.rocket.android.server.domain.RemoveAccountInteractor
-import chat.rocket.android.server.domain.SaveAccountInteractor
-import chat.rocket.android.server.domain.TokenRepository
-import chat.rocket.android.server.domain.favicon
-import chat.rocket.android.server.domain.model.Account
-import chat.rocket.android.server.infraestructure.ConnectionManagerFactory
-import chat.rocket.android.server.infraestructure.RocketChatClientFactory
-import chat.rocket.android.server.presentation.CheckServerPresenter
-import chat.rocket.android.util.extension.launchUI
-import chat.rocket.android.util.extensions.adminPanelUrl
-import chat.rocket.android.util.extensions.serverLogoUrl
-import chat.rocket.android.util.retryIO
-import chat.rocket.common.RocketChatAuthException
-import chat.rocket.common.RocketChatException
-import chat.rocket.common.model.UserStatus
-import chat.rocket.common.util.ifNull
-import chat.rocket.core.RocketChatClient
-import chat.rocket.core.internal.rest.getCustomEmojis
-import chat.rocket.core.internal.rest.me
-import chat.rocket.core.model.Myself
-import kotlinx.coroutines.channels.Channel
-import timber.log.Timber
+import chat.rocket.android.server.domain.RefreshSettingsInteractor
+import chat.rocket.android.server.infrastructure.ConnectionManagerFactory
import javax.inject.Inject
+import javax.inject.Named
class MainPresenter @Inject constructor(
- private val view: MainView,
- private val strategy: CancelStrategy,
- private val navigator: MainNavigator,
- private val tokenRepository: TokenRepository,
+ @Named("currentServer") private val currentServerUrl: String,
+ private val mainNavigator: MainNavigator,
+ private val appLanguageView: AppLanguageView,
private val refreshSettingsInteractor: RefreshSettingsInteractor,
private val refreshPermissionsInteractor: RefreshPermissionsInteractor,
- private val navHeaderMapper: NavHeaderUiModelMapper,
- private val saveAccountInteractor: SaveAccountInteractor,
- private val getAccountsInteractor: GetAccountsInteractor,
- private val groupedPush: GroupedPush,
- serverInteractor: GetCurrentServerInteractor,
- localRepository: LocalRepository,
- removeAccountInteractor: RemoveAccountInteractor,
- factory: RocketChatClientFactory,
- dbManagerFactory: DatabaseManagerFactory,
- getSettingsInteractor: GetSettingsInteractor,
- managerFactory: ConnectionManagerFactory
-) : CheckServerPresenter(
- strategy = strategy,
- factory = factory,
- serverInteractor = serverInteractor,
- localRepository = localRepository,
- removeAccountInteractor = removeAccountInteractor,
- tokenRepository = tokenRepository,
- managerFactory = managerFactory,
- dbManagerFactory = dbManagerFactory,
- tokenView = view,
- navigator = navigator
+ private val connectionManagerFactory: ConnectionManagerFactory,
+ private var getLanguageInteractor: GetCurrentLanguageInteractor,
+ private val groupedPush: GroupedPush
) {
- private val currentServer = serverInteractor.get()!!
- private val manager = managerFactory.create(currentServer)
- private val client: RocketChatClient = factory.create(currentServer)
- private var settings: PublicSettings = getSettingsInteractor.get(serverInteractor.get()!!)
- private val userDataChannel = Channel()
-
- fun toChatList(chatRoomId: String? = null) = navigator.toChatList(chatRoomId)
-
- fun toUserProfile() = navigator.toUserProfile()
-
- fun toSettings() = navigator.toSettings()
-
- fun toAdminPanel() = tokenRepository.get(currentServer)?.let {
- navigator.toAdminPanel(currentServer.adminPanelUrl(), it.authToken)
- }
-
- fun toCreateChannel() = navigator.toCreateChannel()
-
- fun loadServerAccounts() {
- launchUI(strategy) {
- try {
- view.setupServerAccountList(getAccountsInteractor.get())
- } catch (ex: Exception) {
- when (ex) {
- is RocketChatAuthException -> logout()
- else -> {
- Timber.d(ex, "Error loading serve accounts")
- ex.message?.let {
- view.showMessage(it)
- }.ifNull {
- view.showGenericErrorMessage()
- }
- }
- }
- }
- }
- }
-
- fun loadCurrentInfo() {
- setupConnectionInfo(currentServer)
- checkServerInfo(currentServer)
- launchUI(strategy) {
- try {
- val me = retryIO("me") { client.me() }
- val model = navHeaderMapper.mapToUiModel(me)
- saveAccount(model)
- view.setupUserAccountInfo(model)
- } catch (ex: Exception) {
- when (ex) {
- is RocketChatAuthException -> logout()
- else -> {
- Timber.d(ex, "Error loading my information for navheader")
- ex.message?.let {
- view.showMessage(it)
- }.ifNull {
- view.showGenericErrorMessage()
- }
- }
- }
- }
- subscribeMyselfUpdates()
- }
- }
-
- /**
- * Load all emojis for the current server. Simple emojis are always the same for every server,
- * but custom emojis vary according to the its url.
- */
- fun loadEmojis() {
- launchUI(strategy) {
- EmojiRepository.setCurrentServerUrl(currentServer)
- val customEmojiList = mutableListOf()
- try {
- for (customEmoji in retryIO("getCustomEmojis()") { client.getCustomEmojis() }) {
- customEmojiList.add(Emoji(
- shortname = ":${customEmoji.name}:",
- category = EmojiCategory.CUSTOM.name,
- url = "$currentServer/emoji-custom/${customEmoji.name}.${customEmoji.extension}",
- count = 0,
- fitzpatrick = Fitzpatrick.Default.type,
- keywords = customEmoji.aliases,
- shortnameAlternates = customEmoji.aliases,
- siblings = mutableListOf(),
- unicode = "",
- isDefault = true
- ))
- }
-
- EmojiRepository.load(view as Context, customEmojis = customEmojiList)
- } catch (ex: RocketChatException) {
- Timber.e(ex)
- EmojiRepository.load(view as Context)
- }
- }
- }
-
- fun logout() {
- setupConnectionInfo(currentServer)
- super.logout(userDataChannel)
- }
fun connect() {
- refreshSettingsInteractor.refreshAsync(currentServer)
- refreshPermissionsInteractor.refreshAsync(currentServer)
- manager.connect()
- }
-
- fun disconnect() {
- setupConnectionInfo(currentServer)
- super.disconnect(userDataChannel)
- }
-
- fun changeServer(serverUrl: String) {
- if (currentServer != serverUrl) {
- navigator.switchOrAddNewServer(serverUrl)
- } else {
- view.closeServerSelection()
- }
- }
-
- fun addNewServer() {
- navigator.toServerScreen()
+ refreshSettingsInteractor.refreshAsync(currentServerUrl)
+ refreshPermissionsInteractor.refreshAsync(currentServerUrl)
+ connectionManagerFactory.create(currentServerUrl).connect()
}
- fun changeDefaultStatus(userStatus: UserStatus) {
- launchUI(strategy) {
- try {
- manager.setDefaultStatus(userStatus)
- view.showUserStatus(userStatus)
- } catch (ex: RocketChatException) {
- ex.message?.let {
- view.showMessage(it)
- }.ifNull {
- view.showGenericErrorMessage()
- }
- }
- }
- }
-
- private fun saveAccount(uiModel: NavHeaderUiModel) {
- val icon = settings.favicon()?.let {
- currentServer.serverLogoUrl(it)
- }
- val account = Account(
- currentServer,
- icon,
- uiModel.serverLogo,
- uiModel.userDisplayName!!,
- uiModel.userAvatar
- )
- saveAccountInteractor.save(account)
- }
+ fun clearNotificationsForChatRoom(chatRoomId: String?) {
+ if (chatRoomId == null) return
- private suspend fun subscribeMyselfUpdates() {
- manager.addUserDataChannel(userDataChannel)
- for (myself in userDataChannel) {
- updateMyself(myself)
+ groupedPush.hostToPushMessageList[currentServerUrl].let { list ->
+ list?.removeAll { it.info.roomId == chatRoomId }
}
}
- private fun updateMyself(myself: Myself) =
- view.setupUserAccountInfo(navHeaderMapper.mapToUiModel(myself))
+ fun showChatList(chatRoomId: String? = null) = mainNavigator.toChatList(chatRoomId)
- fun clearNotificationsForChatroom(chatRoomId: String?) {
- if (chatRoomId == null) return
- groupedPush.hostToPushMessageList[currentServer]?.let { list ->
- list.removeAll { it.info.roomId == chatRoomId }
+ fun getAppLanguage() {
+ with(getLanguageInteractor) {
+ getLanguage()?.let { language ->
+ appLanguageView.updateLanguage(language, getCountry())
+ }
}
}
-}
+}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/main/presentation/MainView.kt b/app/src/main/java/chat/rocket/android/main/presentation/MainView.kt
deleted file mode 100644
index 2047f21bf8..0000000000
--- a/app/src/main/java/chat/rocket/android/main/presentation/MainView.kt
+++ /dev/null
@@ -1,38 +0,0 @@
-package chat.rocket.android.main.presentation
-
-import chat.rocket.android.authentication.server.presentation.VersionCheckView
-import chat.rocket.android.core.behaviours.MessageView
-import chat.rocket.android.main.uimodel.NavHeaderUiModel
-import chat.rocket.android.server.domain.model.Account
-import chat.rocket.android.server.presentation.TokenView
-import chat.rocket.common.model.UserStatus
-
-interface MainView : MessageView, VersionCheckView, TokenView {
-
- /**
- * Shows the current user status.
- *
- * @see [UserStatus]
- */
- fun showUserStatus(userStatus: UserStatus)
-
- /**
- * Setups the user account info (displayed in the nav. header)
- *
- * @param uiModel The [NavHeaderUiModel].
- */
- fun setupUserAccountInfo(uiModel: NavHeaderUiModel)
-
- /**
- * Setups the server account list.
- *
- * @param serverAccountList The list of server accounts.
- */
- fun setupServerAccountList(serverAccountList: List)
-
- fun closeServerSelection()
-
- fun showProgress()
-
- fun hideProgress()
-}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/main/ui/MainActivity.kt b/app/src/main/java/chat/rocket/android/main/ui/MainActivity.kt
index b7b9476740..1dde86a3e4 100644
--- a/app/src/main/java/chat/rocket/android/main/ui/MainActivity.kt
+++ b/app/src/main/java/chat/rocket/android/main/ui/MainActivity.kt
@@ -1,282 +1,85 @@
package chat.rocket.android.main.ui
-import DrawableHelper
import android.app.Activity
-import androidx.appcompat.app.AlertDialog
-import android.app.ProgressDialog
+import android.app.NotificationManager
+import android.content.Context
+import android.content.res.Configuration
+import android.os.Build
import android.os.Bundle
-import androidx.annotation.IdRes
+import android.os.LocaleList
import androidx.appcompat.app.AppCompatActivity
-import androidx.core.view.GravityCompat
-import androidx.drawerlayout.widget.DrawerLayout
import androidx.fragment.app.Fragment
-import androidx.recyclerview.widget.LinearLayoutManager
-import chat.rocket.android.BuildConfig
import chat.rocket.android.R
-import chat.rocket.android.chatrooms.ui.ChatRoomsFragment
-import chat.rocket.android.main.adapter.AccountsAdapter
-import chat.rocket.android.main.adapter.Selector
+import chat.rocket.android.core.behaviours.AppLanguageView
import chat.rocket.android.main.presentation.MainPresenter
-import chat.rocket.android.main.presentation.MainView
-import chat.rocket.android.main.uimodel.NavHeaderUiModel
import chat.rocket.android.push.refreshPushToken
-import chat.rocket.android.server.domain.PermissionsInteractor
-import chat.rocket.android.server.domain.model.Account
import chat.rocket.android.server.ui.INTENT_CHAT_ROOM_ID
-import chat.rocket.android.util.extensions.fadeIn
-import chat.rocket.android.util.extensions.fadeOut
-import chat.rocket.android.util.extensions.rotateBy
-import chat.rocket.android.util.extensions.showToast
-import chat.rocket.android.util.invalidateFirebaseToken
-import chat.rocket.common.model.UserStatus
import dagger.android.AndroidInjection
import dagger.android.AndroidInjector
import dagger.android.DispatchingAndroidInjector
import dagger.android.HasActivityInjector
import dagger.android.support.HasSupportFragmentInjector
-import kotlinx.android.synthetic.main.activity_main.*
-import kotlinx.android.synthetic.main.app_bar.*
-import kotlinx.android.synthetic.main.nav_header.view.*
+import java.util.*
import javax.inject.Inject
-import android.app.NotificationManager
-import android.content.Context
-
-private const val CURRENT_STATE = "current_state"
-
-class MainActivity : AppCompatActivity(), MainView, HasActivityInjector,
- HasSupportFragmentInjector {
+class MainActivity : AppCompatActivity(), HasActivityInjector,
+ HasSupportFragmentInjector, AppLanguageView {
@Inject
lateinit var activityDispatchingAndroidInjector: DispatchingAndroidInjector
@Inject
lateinit var fragmentDispatchingAndroidInjector: DispatchingAndroidInjector
@Inject
lateinit var presenter: MainPresenter
- @Inject
- lateinit var permissions: PermissionsInteractor
- private var isFragmentAdded: Boolean = false
- private var expanded = false
- private val headerLayout by lazy { view_navigation.getHeaderView(0) }
- private var chatRoomId: String? = null
- private var progressDialog: ProgressDialog? = null
override fun onCreate(savedInstanceState: Bundle?) {
AndroidInjection.inject(this)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
-
refreshPushToken()
- chatRoomId = intent.getStringExtra(INTENT_CHAT_ROOM_ID)
- presenter.clearNotificationsForChatroom(chatRoomId)
- presenter.connect()
- presenter.loadServerAccounts()
- presenter.loadCurrentInfo()
- presenter.loadEmojis()
- setupToolbar()
- setupNavigationView()
- }
-
- override fun onSaveInstanceState(outState: Bundle?) {
- super.onSaveInstanceState(outState)
- outState?.putBoolean(CURRENT_STATE, isFragmentAdded)
- }
-
- override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
- super.onRestoreInstanceState(savedInstanceState)
- isFragmentAdded = savedInstanceState?.getBoolean(CURRENT_STATE) ?: false
+ with(presenter) {
+ connect()
+ getAppLanguage()
+ intent.getStringExtra(INTENT_CHAT_ROOM_ID).let {
+ clearNotificationsForChatRoom(it)
+ showChatList(it)
+ }
+ }
}
override fun onResume() {
super.onResume()
- if (!isFragmentAdded) {
- presenter.toChatList(chatRoomId)
- isFragmentAdded = true
- }
- val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE)
- as NotificationManager
- notificationManager.cancelAll()
- }
-
- override fun onDestroy() {
- super.onDestroy()
- if (isFinishing) {
- presenter.disconnect()
- }
+ clearAppNotifications()
}
- override fun onBackPressed() {
- if (drawer_layout.isDrawerOpen(GravityCompat.START)) {
- closeDrawer()
- } else {
- supportFragmentManager.findFragmentById(R.id.fragment_container)?.let {
- if (it !is ChatRoomsFragment && supportFragmentManager.backStackEntryCount == 0) {
- presenter.toChatList(chatRoomId)
- setCheckedNavDrawerItem(R.id.menu_action_chats)
- } else {
- super.onBackPressed()
- }
- }
- }
- }
-
- override fun activityInjector(): AndroidInjector = activityDispatchingAndroidInjector
+ override fun activityInjector(): AndroidInjector =
+ activityDispatchingAndroidInjector
override fun supportFragmentInjector(): AndroidInjector =
fragmentDispatchingAndroidInjector
-
- override fun showUserStatus(userStatus: UserStatus) {
- headerLayout.apply {
- image_user_status.setImageDrawable(
- DrawableHelper.getUserStatusDrawable(userStatus, this.context)
- )
- }
- }
-
- override fun setupUserAccountInfo(uiModel: NavHeaderUiModel) {
- with(headerLayout) {
- with(uiModel) {
- if (userStatus != null) {
- image_user_status.setImageDrawable(
- DrawableHelper.getUserStatusDrawable(userStatus, context)
- )
- }
- if (userDisplayName != null) {
- text_user_name.text = userDisplayName
- }
- if (userAvatar != null) {
- setAvatar(userAvatar)
- }
- if (serverLogo != null) {
- server_logo.setImageURI(serverLogo)
- }
- text_server_url.text = uiModel.serverUrl
- }
- }
- }
-
- override fun setupServerAccountList(serverAccountList: List) {
- accounts_list.layoutManager = LinearLayoutManager(this)
- accounts_list.adapter = AccountsAdapter(serverAccountList, object : Selector {
- override fun onStatusSelected(userStatus: UserStatus) {
- presenter.changeDefaultStatus(userStatus)
- }
-
- override fun onAccountSelected(serverUrl: String) {
- presenter.changeServer(serverUrl)
- }
-
- override fun onAddedAccountSelected() {
- presenter.addNewServer()
- }
- })
-
- headerLayout.account_container.setOnClickListener {
- it.image_account_expand.rotateBy(180f)
- if (expanded) {
- accounts_list.fadeOut()
- } else {
- accounts_list.fadeIn()
- }
- expanded = !expanded
- }
-
- headerLayout.image_avatar.setOnClickListener {
- view_navigation.menu.findItem(R.id.menu_action_profile).isChecked = true
- presenter.toUserProfile()
- drawer_layout.closeDrawer(GravityCompat.START)
+ override fun updateLanguage(language: String, country: String?) {
+ val locale: Locale = if (country != null) {
+ Locale(language, country)
+ } else {
+ Locale(language)
}
- }
-
-
- override fun closeServerSelection() {
- view_navigation.getHeaderView(0).account_container.performClick()
- }
-
- override fun alertNotRecommendedVersion() {
- AlertDialog.Builder(this)
- .setMessage(
- getString(
- R.string.msg_ver_not_recommended,
- BuildConfig.RECOMMENDED_SERVER_VERSION
- )
- )
- .setPositiveButton(android.R.string.ok, null)
- .create()
- .show()
- }
-
- override fun blockAndAlertNotRequiredVersion() {
- AlertDialog.Builder(this)
- .setMessage(
- getString(
- R.string.msg_ver_not_minimum,
- BuildConfig.REQUIRED_SERVER_VERSION
- )
- )
- .setOnDismissListener { presenter.logout() }
- .setPositiveButton(android.R.string.ok, null)
- .create()
- .show()
- }
-
- override fun invalidateToken(token: String) = invalidateFirebaseToken(token)
-
- override fun showMessage(resId: Int) = showToast(resId)
- override fun showMessage(message: String) = showToast(message)
+ Locale.setDefault(locale)
- override fun showGenericErrorMessage() = showMessage(getString(R.string.msg_generic_error))
+ val config = Configuration()
- private fun setupToolbar() {
- setSupportActionBar(toolbar)
- }
-
- fun setupNavigationView() {
- with (view_navigation.menu) {
- clear()
- setupMenu(this)
- }
-
- view_navigation.setNavigationItemSelectedListener {
- it.isChecked = true
- closeDrawer()
- onNavDrawerItemSelected(it)
- true
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ config.locales = LocaleList(locale)
+ } else {
+ config.locale = locale
}
- toolbar.setNavigationIcon(R.drawable.ic_menu_white_24dp)
- toolbar.setNavigationOnClickListener { openDrawer() }
- }
-
- fun showLogoutDialog() {
- val builder = AlertDialog.Builder(this)
- builder.setTitle(R.string.title_are_you_sure)
- .setPositiveButton(R.string.action_logout) { _, _ -> presenter.logout()}
- .setNegativeButton(android.R.string.no) { dialog, _ -> dialog.cancel() }
- .create()
- .show()
- }
-
- fun setAvatar(avatarUrl: String) {
- headerLayout.image_avatar.setImageURI(avatarUrl)
- }
-
- fun getDrawerLayout(): DrawerLayout = drawer_layout
-
- fun openDrawer() = drawer_layout.openDrawer(GravityCompat.START)
-
- fun closeDrawer() = drawer_layout.closeDrawer(GravityCompat.START)
-
- fun setCheckedNavDrawerItem(@IdRes item: Int) = view_navigation.setCheckedItem(item)
-
- override fun showProgress() {
- progressDialog = ProgressDialog.show(this, getString(R.string.app_name), getString(R.string.msg_log_out), true, false)
+ // TODO We need to check out a better way to use createConfigurationContext
+ // instead of updateConfiguration here since it is deprecated.
+ resources.updateConfiguration(config, resources.displayMetrics)
}
- override fun hideProgress() {
- progressDialog?.dismiss()
- progressDialog = null
- }
+ private fun clearAppNotifications() =
+ (getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).cancelAll()
}
diff --git a/app/src/main/java/chat/rocket/android/main/ui/Menu.kt b/app/src/main/java/chat/rocket/android/main/ui/Menu.kt
deleted file mode 100644
index d0cdf4ca92..0000000000
--- a/app/src/main/java/chat/rocket/android/main/ui/Menu.kt
+++ /dev/null
@@ -1,69 +0,0 @@
-package chat.rocket.android.main.ui
-
-import android.view.Menu
-import android.view.MenuItem
-import chat.rocket.android.R
-
-internal fun MainActivity.setupMenu(menu: Menu) {
- with(menu) {
- add(
- R.id.menu_section_one,
- R.id.menu_action_chats,
- Menu.NONE,
- R.string.title_chats
- ).setIcon(R.drawable.ic_chat_bubble_black_24dp)
- .isChecked = true
-
- add(
- R.id.menu_section_one,
- R.id.menu_action_create_channel,
- Menu.NONE,
- R.string.action_create_channel
- ).setIcon(R.drawable.ic_create_black_24dp)
-
- add(
- R.id.menu_section_two,
- R.id.menu_action_profile,
- Menu.NONE,
- R.string.title_profile
- ).setIcon(R.drawable.ic_person_black_20dp)
-
- add(
- R.id.menu_section_two,
- R.id.menu_action_settings,
- Menu.NONE,
- R.string.title_settings
- ).setIcon(R.drawable.ic_settings_black_24dp)
-
- if (permissions.canSeeTheAdminPanel()) {
- add(
- R.id.menu_section_two,
- R.id.menu_action_admin_panel,
- Menu.NONE,
- R.string.title_admin_panel
- ).setIcon(R.drawable.ic_settings_black_24dp)
- }
-
- add(
- R.id.menu_section_three,
- R.id.menu_action_logout,
- Menu.NONE,
- R.string.action_logout
- ).setIcon(R.drawable.ic_logout_black_24dp)
-
- setGroupCheckable(R.id.menu_section_one, true, true)
- setGroupCheckable(R.id.menu_section_two, true, true)
- setGroupCheckable(R.id.menu_section_three, true, true)
- }
-}
-
-internal fun MainActivity.onNavDrawerItemSelected(menuItem: MenuItem) {
- when (menuItem.itemId) {
- R.id.menu_action_chats-> presenter.toChatList()
- R.id.menu_action_create_channel -> presenter.toCreateChannel()
- R.id.menu_action_profile -> presenter.toUserProfile()
- R.id.menu_action_settings -> presenter.toSettings()
- R.id.menu_action_admin_panel -> presenter.toAdminPanel()
- R.id.menu_action_logout -> showLogoutDialog()
- }
-}
diff --git a/app/src/main/java/chat/rocket/android/main/uimodel/NavHeaderUiModel.kt b/app/src/main/java/chat/rocket/android/main/uimodel/NavHeaderUiModel.kt
deleted file mode 100644
index 1b616dfc15..0000000000
--- a/app/src/main/java/chat/rocket/android/main/uimodel/NavHeaderUiModel.kt
+++ /dev/null
@@ -1,11 +0,0 @@
-package chat.rocket.android.main.uimodel
-
-import chat.rocket.common.model.UserStatus
-
-data class NavHeaderUiModel(
- val userDisplayName: String?,
- val userStatus: UserStatus?,
- val userAvatar: String?,
- val serverUrl: String,
- val serverLogo: String?
-)
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/main/uimodel/NavHeaderUiModelMapper.kt b/app/src/main/java/chat/rocket/android/main/uimodel/NavHeaderUiModelMapper.kt
deleted file mode 100644
index 6a25e76f99..0000000000
--- a/app/src/main/java/chat/rocket/android/main/uimodel/NavHeaderUiModelMapper.kt
+++ /dev/null
@@ -1,32 +0,0 @@
-package chat.rocket.android.main.uimodel
-
-import chat.rocket.android.server.domain.*
-import chat.rocket.android.util.extensions.avatarUrl
-import chat.rocket.android.util.extensions.serverLogoUrl
-import chat.rocket.core.model.Myself
-import javax.inject.Inject
-
-class NavHeaderUiModelMapper @Inject constructor(
- serverInteractor: GetCurrentServerInteractor,
- getSettingsInteractor: GetSettingsInteractor
-) {
- private val currentServer = serverInteractor.get()!!
- private var settings: PublicSettings = getSettingsInteractor.get(currentServer)
-
- fun mapToUiModel(me: Myself): NavHeaderUiModel {
- val displayName = mapDisplayName(me)
- val status = me.status
- val avatar = me.username?.let { currentServer.avatarUrl(it) }
- val image = settings.wideTile() ?: settings.faviconLarge()
- val logo = image?.let { currentServer.serverLogoUrl(it) }
-
- return NavHeaderUiModel(displayName, status, avatar, currentServer, logo)
- }
-
- private fun mapDisplayName(me: Myself): String? {
- val username = me.username
- val realName = me.name
- val senderName = if (settings.useRealName()) realName else username
- return senderName ?: username
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/members/adapter/MembersAdapter.kt b/app/src/main/java/chat/rocket/android/members/adapter/MembersAdapter.kt
index a8dbdcc8cd..68095d2768 100644
--- a/app/src/main/java/chat/rocket/android/members/adapter/MembersAdapter.kt
+++ b/app/src/main/java/chat/rocket/android/members/adapter/MembersAdapter.kt
@@ -15,10 +15,10 @@ class MembersAdapter(
) : RecyclerView.Adapter() {
private var dataSet: List = ArrayList()
- override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MembersAdapter.ViewHolder =
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder =
ViewHolder(parent.inflate(R.layout.item_member))
- override fun onBindViewHolder(holder: MembersAdapter.ViewHolder, position: Int) =
+ override fun onBindViewHolder(holder: ViewHolder, position: Int) =
holder.bind(dataSet[position], listener)
override fun getItemCount(): Int = dataSet.size
diff --git a/app/src/main/java/chat/rocket/android/members/presentation/MembersPresenter.kt b/app/src/main/java/chat/rocket/android/members/presentation/MembersPresenter.kt
index 882648bad2..94e0858f75 100644
--- a/app/src/main/java/chat/rocket/android/members/presentation/MembersPresenter.kt
+++ b/app/src/main/java/chat/rocket/android/members/presentation/MembersPresenter.kt
@@ -6,7 +6,7 @@ import chat.rocket.android.db.DatabaseManager
import chat.rocket.android.helper.UserHelper
import chat.rocket.android.members.uimodel.MemberUiModel
import chat.rocket.android.members.uimodel.MemberUiModelMapper
-import chat.rocket.android.server.infraestructure.RocketChatClientFactory
+import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI
import chat.rocket.common.RocketChatException
import chat.rocket.common.model.roomTypeOf
@@ -27,7 +27,7 @@ class MembersPresenter @Inject constructor(
val factory: RocketChatClientFactory,
private val userHelper: UserHelper
) {
- private val client: RocketChatClient = factory.create(currentServer)
+ private val client: RocketChatClient = factory.get(currentServer)
private var offset: Long = 0
/**
diff --git a/app/src/main/java/chat/rocket/android/members/ui/MembersFragment.kt b/app/src/main/java/chat/rocket/android/members/ui/MembersFragment.kt
index 261f6eab7d..5c57bd98f1 100644
--- a/app/src/main/java/chat/rocket/android/members/ui/MembersFragment.kt
+++ b/app/src/main/java/chat/rocket/android/members/ui/MembersFragment.kt
@@ -102,15 +102,11 @@ class MembersFragment : Fragment(), MembersView {
}
override fun showMessage(resId: Int) {
- ui {
- showToast(resId)
- }
+ ui { showToast(resId) }
}
override fun showMessage(message: String) {
- ui {
- showToast(message)
- }
+ ui { showToast(message) }
}
override fun showGenericErrorMessage() = showMessage(getString(R.string.msg_generic_error))
diff --git a/app/src/main/java/chat/rocket/android/members/uimodel/MemberUiModel.kt b/app/src/main/java/chat/rocket/android/members/uimodel/MemberUiModel.kt
index 1487578230..16e78b8096 100644
--- a/app/src/main/java/chat/rocket/android/members/uimodel/MemberUiModel.kt
+++ b/app/src/main/java/chat/rocket/android/members/uimodel/MemberUiModel.kt
@@ -2,6 +2,7 @@ package chat.rocket.android.members.uimodel
import chat.rocket.android.server.domain.useRealName
import chat.rocket.android.util.extensions.avatarUrl
+import chat.rocket.common.model.Token
import chat.rocket.common.model.User
import chat.rocket.common.model.UserStatus
import chat.rocket.core.model.Value
@@ -9,7 +10,8 @@ import chat.rocket.core.model.Value
class MemberUiModel(
private val member: User,
private val settings: Map>,
- private val baseUrl: String?
+ private val baseUrl: String?,
+ private val token: Token?
) {
val userId: String = member.id
val avatarUri: String?
@@ -33,7 +35,7 @@ class MemberUiModel(
private fun getUserAvatar(): String? {
val username = member.username ?: "?"
return baseUrl?.let {
- baseUrl.avatarUrl(username, format = "png")
+ baseUrl.avatarUrl(username, token?.userId, token?.authToken, format = "png")
}
}
diff --git a/app/src/main/java/chat/rocket/android/members/uimodel/MemberUiModelMapper.kt b/app/src/main/java/chat/rocket/android/members/uimodel/MemberUiModelMapper.kt
index 6cf69f12cb..587aa02ca3 100644
--- a/app/src/main/java/chat/rocket/android/members/uimodel/MemberUiModelMapper.kt
+++ b/app/src/main/java/chat/rocket/android/members/uimodel/MemberUiModelMapper.kt
@@ -2,19 +2,24 @@ package chat.rocket.android.members.uimodel
import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.domain.GetSettingsInteractor
+import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.domain.baseUrl
import chat.rocket.common.model.User
import chat.rocket.core.model.Value
import javax.inject.Inject
+import javax.inject.Named
class MemberUiModelMapper @Inject constructor(
serverInteractor: GetCurrentServerInteractor,
- getSettingsInteractor: GetSettingsInteractor
+ getSettingsInteractor: GetSettingsInteractor,
+ @Named("currentServer") private val currentServer: String,
+ tokenRepository: TokenRepository
) {
private var settings: Map> = getSettingsInteractor.get(serverInteractor.get()!!)
private val baseUrl = settings.baseUrl()
+ private val token = tokenRepository.get(currentServer)
fun mapToUiModelList(memberList: List): List {
- return memberList.map { MemberUiModel(it, settings, baseUrl) }
+ return memberList.map { MemberUiModel(it, settings, baseUrl, token) }
}
}
diff --git a/app/src/main/java/chat/rocket/android/mentions/presentention/MentionsPresenter.kt b/app/src/main/java/chat/rocket/android/mentions/presentention/MentionsPresenter.kt
index aa21f438ff..c985522a67 100644
--- a/app/src/main/java/chat/rocket/android/mentions/presentention/MentionsPresenter.kt
+++ b/app/src/main/java/chat/rocket/android/mentions/presentention/MentionsPresenter.kt
@@ -2,7 +2,7 @@ package chat.rocket.android.mentions.presentention
import chat.rocket.android.chatroom.uimodel.UiModelMapper
import chat.rocket.android.core.lifecycle.CancelStrategy
-import chat.rocket.android.server.infraestructure.RocketChatClientFactory
+import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI
import chat.rocket.common.RocketChatException
import chat.rocket.common.util.ifNull
@@ -18,7 +18,7 @@ class MentionsPresenter @Inject constructor(
private val mapper: UiModelMapper,
val factory: RocketChatClientFactory
) {
- private val client = factory.create(currentServer)
+ private val client = factory.get(currentServer)
private var offset: Long = 0
/**
diff --git a/app/src/main/java/chat/rocket/android/pinnedmessages/presentation/PinnedMessagesPresenter.kt b/app/src/main/java/chat/rocket/android/pinnedmessages/presentation/PinnedMessagesPresenter.kt
index fa9f4020ee..d5b030f49a 100644
--- a/app/src/main/java/chat/rocket/android/pinnedmessages/presentation/PinnedMessagesPresenter.kt
+++ b/app/src/main/java/chat/rocket/android/pinnedmessages/presentation/PinnedMessagesPresenter.kt
@@ -3,9 +3,8 @@ package chat.rocket.android.pinnedmessages.presentation
import chat.rocket.android.chatroom.uimodel.UiModelMapper
import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.db.DatabaseManager
-import chat.rocket.android.server.infraestructure.RocketChatClientFactory
+import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI
-import chat.rocket.android.util.retryDB
import chat.rocket.common.RocketChatException
import chat.rocket.common.model.roomTypeOf
import chat.rocket.common.util.ifNull
@@ -23,7 +22,7 @@ class PinnedMessagesPresenter @Inject constructor(
private val mapper: UiModelMapper,
val factory: RocketChatClientFactory
) {
- private val client: RocketChatClient = factory.create(currentServer)
+ private val client: RocketChatClient = factory.get(currentServer)
private var offset: Int = 0
/**
diff --git a/app/src/main/java/chat/rocket/android/preferences/di/PreferencesFragmentModule.kt b/app/src/main/java/chat/rocket/android/preferences/di/PreferencesFragmentModule.kt
deleted file mode 100644
index 218a2f9a4c..0000000000
--- a/app/src/main/java/chat/rocket/android/preferences/di/PreferencesFragmentModule.kt
+++ /dev/null
@@ -1,17 +0,0 @@
-package chat.rocket.android.preferences.di
-
-import chat.rocket.android.dagger.scope.PerFragment
-import chat.rocket.android.preferences.presentation.PreferencesView
-import chat.rocket.android.preferences.ui.PreferencesFragment
-import dagger.Module
-import dagger.Provides
-
-@Module
-class PreferencesFragmentModule {
-
- @Provides
- @PerFragment
- fun preferencesView(frag: PreferencesFragment): PreferencesView {
- return frag
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/preferences/di/PreferencesFragmentProvider.kt b/app/src/main/java/chat/rocket/android/preferences/di/PreferencesFragmentProvider.kt
deleted file mode 100644
index 083beb6768..0000000000
--- a/app/src/main/java/chat/rocket/android/preferences/di/PreferencesFragmentProvider.kt
+++ /dev/null
@@ -1,14 +0,0 @@
-package chat.rocket.android.preferences.di
-
-import chat.rocket.android.dagger.scope.PerFragment
-import chat.rocket.android.preferences.ui.PreferencesFragment
-import dagger.Module
-import dagger.android.ContributesAndroidInjector
-
-@Module
-abstract class PreferencesFragmentProvider {
-
- @ContributesAndroidInjector(modules = [PreferencesFragmentModule::class])
- @PerFragment
- abstract fun providePreferencesFragment(): PreferencesFragment
-}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/preferences/presentation/PreferencesPresenter.kt b/app/src/main/java/chat/rocket/android/preferences/presentation/PreferencesPresenter.kt
deleted file mode 100644
index 38eba6e6db..0000000000
--- a/app/src/main/java/chat/rocket/android/preferences/presentation/PreferencesPresenter.kt
+++ /dev/null
@@ -1,22 +0,0 @@
-package chat.rocket.android.preferences.presentation
-
-import chat.rocket.android.server.domain.AnalyticsTrackingInteractor
-import javax.inject.Inject
-
-class PreferencesPresenter @Inject constructor(
- private val view: PreferencesView,
- private val analyticsTrackingInteractor: AnalyticsTrackingInteractor
-) {
-
- fun loadAnalyticsTrackingInformation() {
- view.setupAnalyticsTrackingView(analyticsTrackingInteractor.get())
- }
-
- fun enableAnalyticsTracking() {
- analyticsTrackingInteractor.save(true)
- }
-
- fun disableAnalyticsTracking() {
- analyticsTrackingInteractor.save(false)
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/preferences/presentation/PreferencesView.kt b/app/src/main/java/chat/rocket/android/preferences/presentation/PreferencesView.kt
deleted file mode 100644
index 6c3d4248ec..0000000000
--- a/app/src/main/java/chat/rocket/android/preferences/presentation/PreferencesView.kt
+++ /dev/null
@@ -1,11 +0,0 @@
-package chat.rocket.android.preferences.presentation
-
-interface PreferencesView {
-
- /**
- * Setups the analytics tracking view.
- *
- * @param isAnalyticsTrackingEnabled Whether the analytics tracking is enabled
- */
- fun setupAnalyticsTrackingView(isAnalyticsTrackingEnabled: Boolean)
-}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/preferences/ui/PreferencesFragment.kt b/app/src/main/java/chat/rocket/android/preferences/ui/PreferencesFragment.kt
deleted file mode 100644
index dcf3b136e4..0000000000
--- a/app/src/main/java/chat/rocket/android/preferences/ui/PreferencesFragment.kt
+++ /dev/null
@@ -1,96 +0,0 @@
-package chat.rocket.android.preferences.ui
-
-import android.os.Bundle
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import androidx.fragment.app.Fragment
-import chat.rocket.android.BuildConfig
-import chat.rocket.android.R
-import chat.rocket.android.analytics.AnalyticsManager
-import chat.rocket.android.analytics.event.ScreenViewEvent
-import chat.rocket.android.main.ui.MainActivity
-import chat.rocket.android.preferences.presentation.PreferencesPresenter
-import chat.rocket.android.preferences.presentation.PreferencesView
-import dagger.android.support.AndroidSupportInjection
-import kotlinx.android.synthetic.main.app_bar.*
-import kotlinx.android.synthetic.main.fragment_preferences.*
-import javax.inject.Inject
-
-internal const val TAG_PREFERENCES_FRAGMENT = "PreferencesFragment"
-
-class PreferencesFragment : Fragment(), PreferencesView {
- @Inject
- lateinit var presenter: PreferencesPresenter
- @Inject
- lateinit var analyticsManager: AnalyticsManager
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- AndroidSupportInjection.inject(this)
- }
-
- override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View? = inflater.inflate(R.layout.fragment_preferences, container, false)
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
- setupListeners()
- presenter.loadAnalyticsTrackingInformation()
-
- analyticsManager.logScreenView(ScreenViewEvent.Preferences)
- }
-
- override fun onResume() {
- setupToolbar()
- super.onResume()
- }
-
- override fun setupAnalyticsTrackingView(isAnalyticsTrackingEnabled: Boolean) {
- if (BuildConfig.FLAVOR == "foss") {
- switch_analytics_tracking.isChecked = false
- switch_analytics_tracking.isEnabled = false
- text_analytics_tracking_description.text =
- getString(R.string.msg_not_applicable_since_it_is_a_foss_version)
- return
- }
-
- if (isAnalyticsTrackingEnabled) {
- text_analytics_tracking_description.text =
- getString(R.string.msg_send_analytics_tracking)
- } else {
- text_analytics_tracking_description.text =
- getString(R.string.msg_do_not_send_analytics_tracking)
- }
- switch_analytics_tracking.isChecked = isAnalyticsTrackingEnabled
- }
-
- private fun setupToolbar() {
- with((activity as MainActivity).toolbar) {
- title = getString(R.string.title_preferences)
- setNavigationIcon(R.drawable.ic_arrow_back_white_24dp)
- setNavigationOnClickListener { activity?.onBackPressed() }
- }
- }
-
- private fun setupListeners() {
- switch_analytics_tracking.setOnCheckedChangeListener { _, isChecked ->
- if (isChecked) {
- text_analytics_tracking_description.text =
- getString(R.string.msg_send_analytics_tracking)
- presenter.enableAnalyticsTracking()
- } else {
- text_analytics_tracking_description.text =
- getString(R.string.msg_do_not_send_analytics_tracking)
- presenter.disableAnalyticsTracking()
- }
- }
- }
-
- companion object {
- fun newInstance() = PreferencesFragment()
- }
-}
diff --git a/app/src/main/java/chat/rocket/android/profile/presentation/ProfilePresenter.kt b/app/src/main/java/chat/rocket/android/profile/presentation/ProfilePresenter.kt
index 826dbdaa86..8212c88323 100644
--- a/app/src/main/java/chat/rocket/android/profile/presentation/ProfilePresenter.kt
+++ b/app/src/main/java/chat/rocket/android/profile/presentation/ProfilePresenter.kt
@@ -11,24 +11,23 @@ import chat.rocket.android.main.presentation.MainNavigator
import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.domain.RemoveAccountInteractor
import chat.rocket.android.server.domain.TokenRepository
-import chat.rocket.android.server.infraestructure.ConnectionManagerFactory
-import chat.rocket.android.server.infraestructure.RocketChatClientFactory
+import chat.rocket.android.server.infrastructure.ConnectionManagerFactory
+import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.server.presentation.CheckServerPresenter
import chat.rocket.android.util.extension.compressImageAndGetByteArray
-import chat.rocket.android.util.extension.gethash
import chat.rocket.android.util.extension.launchUI
-import chat.rocket.android.util.extension.toHex
import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.android.util.retryIO
import chat.rocket.common.RocketChatException
+import chat.rocket.common.model.UserStatus
+import chat.rocket.common.model.userStatusOf
import chat.rocket.common.util.ifNull
import chat.rocket.core.RocketChatClient
-import chat.rocket.core.internal.rest.deleteOwnAccount
+import chat.rocket.core.internal.realtime.setDefaultStatus
+import chat.rocket.core.internal.rest.me
import chat.rocket.core.internal.rest.resetAvatar
import chat.rocket.core.internal.rest.setAvatar
import chat.rocket.core.internal.rest.updateProfile
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.withContext
import java.util.*
import javax.inject.Inject
@@ -56,18 +55,24 @@ class ProfilePresenter @Inject constructor(
navigator = navigator
) {
private val serverUrl = serverInteractor.get()!!
- private val client: RocketChatClient = factory.create(serverUrl)
+ private val client: RocketChatClient = factory.get(serverUrl)
private val user = userHelper.user()
+ private val token = tokenRepository.get(serverUrl)
fun loadUserProfile() {
launchUI(strategy) {
view.showLoading()
try {
+ val me = retryIO(description = "serverInfo", times = 5) {
+ client.me()
+ }
+
view.showProfile(
- serverUrl.avatarUrl(user?.username ?: ""),
- user?.name ?: "",
- user?.username ?: "",
- user?.emails?.getOrNull(0)?.address ?: ""
+ me.status.toString(),
+ serverUrl.avatarUrl(me.username!!, token?.userId, token?.authToken),
+ me.name ?: "",
+ me.username ?: "",
+ me.emails?.getOrNull(0)?.address ?: ""
)
} catch (exception: RocketChatException) {
view.showMessage(exception)
@@ -82,10 +87,18 @@ class ProfilePresenter @Inject constructor(
view.showLoading()
try {
user?.id?.let { id ->
- retryIO { client.updateProfile(userId = id, email = email, name = name, username = username) }
+ retryIO {
+ client.updateProfile(
+ userId = id,
+ email = email,
+ name = name,
+ username = username
+ )
+ }
view.showProfileUpdateSuccessfullyMessage()
view.showProfile(
- serverUrl.avatarUrl(user.username ?: ""),
+ user.status.toString(),
+ serverUrl.avatarUrl(user.username!!, token?.userId, token?.authToken),
name,
username,
email
@@ -115,7 +128,15 @@ class ProfilePresenter @Inject constructor(
uriInteractor.getInputStream(uri)
}
}
- user?.username?.let { view.reloadUserAvatar(serverUrl.avatarUrl(it)) }
+ user?.username?.let {
+ view.reloadUserAvatar(
+ serverUrl.avatarUrl(
+ it,
+ token?.userId,
+ token?.authToken
+ )
+ )
+ }
} catch (exception: RocketChatException) {
exception.message?.let {
view.showMessage(it)
@@ -143,7 +164,15 @@ class ProfilePresenter @Inject constructor(
}
}
- user?.username?.let { view.reloadUserAvatar(serverUrl.avatarUrl(it)) }
+ user?.username?.let {
+ view.reloadUserAvatar(
+ serverUrl.avatarUrl(
+ it,
+ token?.userId,
+ token?.authToken
+ )
+ )
+ }
} catch (exception: RocketChatException) {
exception.message?.let {
view.showMessage(it)
@@ -163,7 +192,15 @@ class ProfilePresenter @Inject constructor(
user?.id?.let { id ->
retryIO { client.resetAvatar(id) }
}
- user?.username?.let { view.reloadUserAvatar(serverUrl.avatarUrl(it)) }
+ user?.username?.let {
+ view.reloadUserAvatar(
+ serverUrl.avatarUrl(
+ it,
+ token?.userId,
+ token?.authToken
+ )
+ )
+ }
} catch (exception: RocketChatException) {
exception.message?.let {
view.showMessage(it)
@@ -176,26 +213,17 @@ class ProfilePresenter @Inject constructor(
}
}
- fun deleteAccount(password: String) {
+ fun updateStatus(status: UserStatus) {
launchUI(strategy) {
- view.showLoading()
try {
- withContext(Dispatchers.Default) {
- // REMARK: Backend API is only working with a lowercase hash.
- // https://github.com/RocketChat/Rocket.Chat/issues/12573
- retryIO { client.deleteOwnAccount(password.gethash().toHex().toLowerCase()) }
- setupConnectionInfo(serverUrl)
- logout(null)
- }
- } catch (exception: Exception) {
+ client.setDefaultStatus(status)
+ } catch (exception: RocketChatException) {
exception.message?.let {
view.showMessage(it)
}.ifNull {
view.showGenericErrorMessage()
}
- } finally {
- view.hideLoading()
}
}
}
-}
+}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/profile/presentation/ProfileView.kt b/app/src/main/java/chat/rocket/android/profile/presentation/ProfileView.kt
index 86c8f97620..0ac7abffa5 100644
--- a/app/src/main/java/chat/rocket/android/profile/presentation/ProfileView.kt
+++ b/app/src/main/java/chat/rocket/android/profile/presentation/ProfileView.kt
@@ -9,12 +9,19 @@ interface ProfileView : TokenView, LoadingView, MessageView {
/**
* Shows the user profile.
*
+ * @param status The user status.
* @param avatarUrl The user avatar URL.
* @param name The user display name.
* @param username The user username.
* @param email The user email.
*/
- fun showProfile(avatarUrl: String, name: String, username: String, email: String?)
+ fun showProfile(
+ status: String,
+ avatarUrl: String,
+ name: String,
+ username: String,
+ email: String?
+ )
/**
* Reloads the user avatar (after successfully updating it).
diff --git a/app/src/main/java/chat/rocket/android/profile/ui/ProfileFragment.kt b/app/src/main/java/chat/rocket/android/profile/ui/ProfileFragment.kt
index 2eeff8b2c1..a8d337c7d7 100644
--- a/app/src/main/java/chat/rocket/android/profile/ui/ProfileFragment.kt
+++ b/app/src/main/java/chat/rocket/android/profile/ui/ProfileFragment.kt
@@ -2,8 +2,8 @@ package chat.rocket.android.profile.ui
import DrawableHelper
import android.app.Activity
-import androidx.appcompat.app.AlertDialog
import android.content.Intent
+import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.os.Build
import android.os.Bundle
@@ -12,8 +12,8 @@ import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
-import android.view.MenuInflater
-import android.widget.EditText
+import android.widget.RadioGroup
+import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.view.ActionMode
import androidx.core.net.toUri
@@ -22,6 +22,9 @@ import androidx.fragment.app.Fragment
import chat.rocket.android.R
import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.analytics.event.ScreenViewEvent
+import chat.rocket.android.helper.AndroidPermissionsHelper
+import chat.rocket.android.helper.AndroidPermissionsHelper.getCameraPermission
+import chat.rocket.android.helper.AndroidPermissionsHelper.hasCameraPermission
import chat.rocket.android.main.ui.MainActivity
import chat.rocket.android.profile.presentation.ProfilePresenter
import chat.rocket.android.profile.presentation.ProfileView
@@ -33,12 +36,18 @@ import chat.rocket.android.util.extensions.showToast
import chat.rocket.android.util.extensions.textContent
import chat.rocket.android.util.extensions.ui
import chat.rocket.android.util.invalidateFirebaseToken
+import chat.rocket.common.model.UserStatus
+import chat.rocket.common.model.userStatusOf
import com.facebook.drawee.backends.pipeline.Fresco
+import com.google.android.material.snackbar.Snackbar
import dagger.android.support.AndroidSupportInjection
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.Observables
+import kotlinx.android.synthetic.main.app_bar.*
import kotlinx.android.synthetic.main.avatar_profile.*
import kotlinx.android.synthetic.main.fragment_profile.*
+import kotlinx.android.synthetic.main.fragment_profile.view_dim
+import kotlinx.android.synthetic.main.fragment_profile.view_loading
import kotlinx.android.synthetic.main.update_avatar_options.*
import javax.inject.Inject
@@ -47,24 +56,23 @@ internal const val TAG_PROFILE_FRAGMENT = "ProfileFragment"
private const val REQUEST_CODE_FOR_PERFORM_SAF = 1
private const val REQUEST_CODE_FOR_PERFORM_CAMERA = 2
+fun newInstance() = ProfileFragment()
+
class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
@Inject
lateinit var presenter: ProfilePresenter
@Inject
lateinit var analyticsManager: AnalyticsManager
+ private var currentStatus = ""
private var currentName = ""
private var currentUsername = ""
private var currentEmail = ""
private var actionMode: ActionMode? = null
private val editTextsDisposable = CompositeDisposable()
- companion object {
- fun newInstance() = ProfileFragment()
- }
-
override fun onCreate(savedInstanceState: Bundle?) {
- AndroidSupportInjection.inject(this)
super.onCreate(savedInstanceState)
+ AndroidSupportInjection.inject(this)
setHasOptionsMenu(true)
}
@@ -78,11 +86,12 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
super.onViewCreated(view, savedInstanceState)
setupToolbar()
- setupListeners()
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
tintEditTextDrawableStart()
}
+
presenter.loadUserProfile()
+ setupListeners()
subscribeEditTexts()
analyticsManager.logScreenView(ScreenViewEvent.Profile)
@@ -112,25 +121,21 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
super.onPrepareOptionsMenu(menu)
}
- override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
- super.onCreateOptionsMenu(menu, inflater)
- inflater.inflate(R.menu.profile, menu)
- }
-
- override fun onOptionsItemSelected(item: MenuItem): Boolean {
- when (item.itemId) {
- R.id.action_delete_account -> showDeleteAccountDialog()
- }
- return true
- }
-
- override fun showProfile(avatarUrl: String, name: String, username: String, email: String?) {
+ override fun showProfile(
+ status: String,
+ avatarUrl: String,
+ name: String,
+ username: String,
+ email: String?
+ ) {
ui {
+ text_status.text = getString(R.string.status, status.capitalize())
image_avatar.setImageURI(avatarUrl)
text_name.textContent = name
text_username.textContent = username
text_email.textContent = email ?: ""
+ currentStatus = status
currentName = name
currentUsername = username
currentEmail = email ?: ""
@@ -142,11 +147,10 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
override fun reloadUserAvatar(avatarUrl: String) {
Fresco.getImagePipeline().evictFromCache(avatarUrl.toUri())
image_avatar.setImageURI(avatarUrl)
- (activity as MainActivity).setAvatar(avatarUrl)
}
override fun showProfileUpdateSuccessfullyMessage() {
- showMessage(getString(R.string.msg_profile_update_successfully))
+ showMessage(getString(R.string.msg_profile_updated_successfully))
}
override fun invalidateToken(token: String) = invalidateFirebaseToken(token)
@@ -205,10 +209,19 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
}
private fun setupToolbar() {
- (activity as AppCompatActivity?)?.supportActionBar?.title = getString(R.string.title_profile)
+ with((activity as AppCompatActivity)) {
+ with(toolbar) {
+ setSupportActionBar(this)
+ title = getString(R.string.title_profile)
+ setNavigationIcon(R.drawable.ic_arrow_back_white_24dp)
+ setNavigationOnClickListener { activity?.onBackPressed() }
+ }
+ }
}
private fun setupListeners() {
+ text_status.setOnClickListener { showStatusDialog(currentStatus) }
+
image_avatar.setOnClickListener { showUpdateAvatarOptions() }
view_dim.setOnClickListener { hideUpdateAvatarOptions() }
@@ -219,7 +232,13 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
}
button_take_a_photo.setOnClickListener {
- dispatchTakePicture(REQUEST_CODE_FOR_PERFORM_CAMERA)
+ context?.let {
+ if (hasCameraPermission(it)) {
+ dispatchTakePicture(REQUEST_CODE_FOR_PERFORM_CAMERA)
+ } else {
+ getCameraPermission(this)
+ }
+ }
hideUpdateAvatarOptions()
}
@@ -263,8 +282,8 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
text_email.asObservable()
) { text_name, text_username, text_email ->
return@combineLatest (text_name.toString() != currentName ||
- text_username.toString() != currentUsername ||
- text_email.toString() != currentEmail)
+ text_username.toString() != currentUsername ||
+ text_email.toString() != currentEmail)
}.subscribe { isValid ->
activity?.invalidateOptionsMenu()
if (isValid) {
@@ -293,15 +312,62 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
}
}
- fun showDeleteAccountDialog() {
+ private fun showStatusDialog(currentStatus: String) {
+ val dialogLayout = layoutInflater.inflate(R.layout.dialog_status, null)
+ val radioGroup = dialogLayout.findViewById(R.id.radio_group_status)
+
+ radioGroup.check(
+ when (userStatusOf(currentStatus)) {
+ is UserStatus.Online -> R.id.radio_button_online
+ is UserStatus.Away -> R.id.radio_button_away
+ is UserStatus.Busy -> R.id.radio_button_busy
+ else -> R.id.radio_button_invisible
+ }
+ )
+
+ var newStatus: UserStatus = userStatusOf(currentStatus)
+ radioGroup.setOnCheckedChangeListener { _, checkId ->
+ when (checkId) {
+ R.id.radio_button_online -> newStatus = UserStatus.Online()
+ R.id.radio_button_away -> newStatus = UserStatus.Away()
+ R.id.radio_button_busy -> newStatus = UserStatus.Busy()
+ else -> newStatus = UserStatus.Offline()
+ }
+ }
+
context?.let {
- val passwordEText = EditText(context);
- val mDialogView = LayoutInflater.from(it).inflate(R.layout.item_account_delete, null)
- val mBuilder = AlertDialog.Builder(it)
+ AlertDialog.Builder(it)
+ .setView(dialogLayout)
+ .setPositiveButton(R.string.msg_change_status) { dialog, _ ->
+ presenter.updateStatus(newStatus)
+ text_status.text = getString(R.string.status, newStatus.toString().capitalize())
+ this.currentStatus = newStatus.toString()
+ dialog.dismiss()
+ }.show()
+ }
+ }
- mBuilder.setView(mDialogView).setPositiveButton(R.string.action_delete_account) { _, _ ->
- presenter.deleteAccount(passwordEText.text.toString())
- }.setNegativeButton(android.R.string.no) { dialog, _ -> dialog.cancel() }.create().show()
+ override fun onRequestPermissionsResult(
+ requestCode: Int,
+ permissions: Array,
+ grantResults: IntArray
+ ) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults)
+ when (requestCode) {
+ AndroidPermissionsHelper.CAMERA_CODE -> {
+ if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ // permission was granted
+ dispatchTakePicture(REQUEST_CODE_FOR_PERFORM_CAMERA)
+ } else {
+ // permission denied
+ Snackbar.make(
+ relative_layout,
+ R.string.msg_camera_permission_denied,
+ Snackbar.LENGTH_SHORT
+ ).show()
+ }
+ return
+ }
}
}
}
diff --git a/app/src/main/java/chat/rocket/android/push/DirectReplyReceiver.kt b/app/src/main/java/chat/rocket/android/push/DirectReplyReceiver.kt
index 8e2f9754b0..6fa3170c2c 100644
--- a/app/src/main/java/chat/rocket/android/push/DirectReplyReceiver.kt
+++ b/app/src/main/java/chat/rocket/android/push/DirectReplyReceiver.kt
@@ -7,7 +7,7 @@ import android.content.Intent
import androidx.core.app.RemoteInput
import android.widget.Toast
import chat.rocket.android.R
-import chat.rocket.android.server.infraestructure.ConnectionManagerFactory
+import chat.rocket.android.server.infrastructure.ConnectionManagerFactory
import chat.rocket.common.RocketChatException
import chat.rocket.core.internal.rest.sendMessage
import dagger.android.AndroidInjection
diff --git a/app/src/main/java/chat/rocket/android/server/domain/GetCurrentLanguageInteractor.kt b/app/src/main/java/chat/rocket/android/server/domain/GetCurrentLanguageInteractor.kt
new file mode 100644
index 0000000000..e0e475df05
--- /dev/null
+++ b/app/src/main/java/chat/rocket/android/server/domain/GetCurrentLanguageInteractor.kt
@@ -0,0 +1,12 @@
+package chat.rocket.android.server.domain
+
+import chat.rocket.android.server.infrastructure.CurrentLanguageRepository
+import javax.inject.Inject
+
+class GetCurrentLanguageInteractor @Inject constructor(
+ private val repository: CurrentLanguageRepository
+) {
+
+ fun getLanguage(): String? = repository.getLanguage()
+ fun getCountry(): String? = repository.getCountry()
+}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/server/domain/PermissionsInteractor.kt b/app/src/main/java/chat/rocket/android/server/domain/PermissionsInteractor.kt
index c04c0f8124..0b90b6460e 100644
--- a/app/src/main/java/chat/rocket/android/server/domain/PermissionsInteractor.kt
+++ b/app/src/main/java/chat/rocket/android/server/domain/PermissionsInteractor.kt
@@ -69,7 +69,7 @@ class PermissionsInteractor @Inject constructor(
}
- fun canSeeTheAdminPanel(): Boolean {
+ fun isAdministrationEnabled(): Boolean {
currentServerUrl()?.let { serverUrl ->
val viewStatistics =
permissionsRepository.get(serverUrl, VIEW_STATISTICS)
diff --git a/app/src/main/java/chat/rocket/android/server/domain/RefreshPermissionsInteractor.kt b/app/src/main/java/chat/rocket/android/server/domain/RefreshPermissionsInteractor.kt
index e1f1571923..feaa110ba8 100644
--- a/app/src/main/java/chat/rocket/android/server/domain/RefreshPermissionsInteractor.kt
+++ b/app/src/main/java/chat/rocket/android/server/domain/RefreshPermissionsInteractor.kt
@@ -1,6 +1,6 @@
package chat.rocket.android.server.domain
-import chat.rocket.android.server.infraestructure.RocketChatClientFactory
+import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.util.retryIO
import chat.rocket.core.internal.rest.permissions
import kotlinx.coroutines.Dispatchers
@@ -20,7 +20,7 @@ class RefreshPermissionsInteractor @Inject constructor(
fun refreshAsync(server: String) {
GlobalScope.launch(Dispatchers.IO) {
try {
- factory.create(server).let { client ->
+ factory.get(server).let { client ->
val permissions = retryIO(
description = "permissions",
times = 5,
diff --git a/app/src/main/java/chat/rocket/android/server/domain/RefreshSettingsInteractor.kt b/app/src/main/java/chat/rocket/android/server/domain/RefreshSettingsInteractor.kt
index 348fe84120..d50536767a 100644
--- a/app/src/main/java/chat/rocket/android/server/domain/RefreshSettingsInteractor.kt
+++ b/app/src/main/java/chat/rocket/android/server/domain/RefreshSettingsInteractor.kt
@@ -1,6 +1,6 @@
package chat.rocket.android.server.domain
-import chat.rocket.android.server.infraestructure.RocketChatClientFactory
+import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.util.retryIO
import chat.rocket.core.internal.rest.settings
import kotlinx.coroutines.Dispatchers
@@ -74,7 +74,7 @@ class RefreshSettingsInteractor @Inject constructor(
suspend fun refresh(server: String) {
withContext(Dispatchers.IO) {
- factory.create(server).let { client ->
+ factory.get(server).let { client ->
val settings = retryIO(
description = "settings",
times = 5,
diff --git a/app/src/main/java/chat/rocket/android/server/domain/SaveCurrentLanguageInteractor.kt b/app/src/main/java/chat/rocket/android/server/domain/SaveCurrentLanguageInteractor.kt
new file mode 100644
index 0000000000..3bff12f8de
--- /dev/null
+++ b/app/src/main/java/chat/rocket/android/server/domain/SaveCurrentLanguageInteractor.kt
@@ -0,0 +1,10 @@
+package chat.rocket.android.server.domain
+
+import chat.rocket.android.server.infrastructure.CurrentLanguageRepository
+import javax.inject.Inject
+
+class SaveCurrentLanguageInteractor @Inject constructor(
+ private val repository: CurrentLanguageRepository
+) {
+ fun save(language: String, country: String?) = repository.save(language, country)
+}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/server/domain/SortingAndGroupingInteractor.kt b/app/src/main/java/chat/rocket/android/server/domain/SortingAndGroupingInteractor.kt
new file mode 100644
index 0000000000..ada5d45250
--- /dev/null
+++ b/app/src/main/java/chat/rocket/android/server/domain/SortingAndGroupingInteractor.kt
@@ -0,0 +1,32 @@
+package chat.rocket.android.server.domain
+
+import javax.inject.Inject
+
+class SortingAndGroupingInteractor @Inject constructor(val repository: SortingAndGroupingRepository) {
+
+ fun save(
+ currentServerUrl: String,
+ isSortByName: Boolean,
+ isUnreadOnTop: Boolean,
+ isGroupByType: Boolean,
+ isGroupByFavorites: Boolean
+ ) = repository.save(
+ currentServerUrl,
+ isSortByName,
+ isUnreadOnTop,
+ isGroupByType,
+ isGroupByFavorites
+ )
+
+ fun getSortByName(currentServerUrl: String): Boolean =
+ repository.getSortByName(currentServerUrl)
+
+ fun getUnreadOnTop(currentServerUrl: String): Boolean =
+ repository.getUnreadOnTop(currentServerUrl)
+
+ fun getGroupByType(currentServerUrl: String): Boolean =
+ repository.getGroupByType(currentServerUrl)
+
+ fun getGroupByFavorites(currentServerUrl: String): Boolean =
+ repository.getGroupByFavorites(currentServerUrl)
+}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/server/domain/SortingAndGroupingRepository.kt b/app/src/main/java/chat/rocket/android/server/domain/SortingAndGroupingRepository.kt
new file mode 100644
index 0000000000..2977e47758
--- /dev/null
+++ b/app/src/main/java/chat/rocket/android/server/domain/SortingAndGroupingRepository.kt
@@ -0,0 +1,20 @@
+package chat.rocket.android.server.domain
+
+interface SortingAndGroupingRepository {
+
+ fun save(
+ currentServerUrl: String,
+ isSortByName: Boolean,
+ isUnreadOnTop: Boolean,
+ isGroupByType: Boolean,
+ isGroupByFavorites: Boolean
+ )
+
+ fun getSortByName(currentServerUrl: String): Boolean
+
+ fun getUnreadOnTop(currentServerUrl: String): Boolean
+
+ fun getGroupByType(currentServerUrl: String): Boolean
+
+ fun getGroupByFavorites(currentServerUrl: String): Boolean
+}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/server/domain/model/Account.kt b/app/src/main/java/chat/rocket/android/server/domain/model/Account.kt
index 143eaced55..ebb4c0d328 100644
--- a/app/src/main/java/chat/rocket/android/server/domain/model/Account.kt
+++ b/app/src/main/java/chat/rocket/android/server/domain/model/Account.kt
@@ -4,6 +4,7 @@ import se.ansman.kotshi.JsonSerializable
@JsonSerializable
data class Account(
+ val serverName: String?,
val serverUrl: String,
val serverLogo: String?,
val serverBg: String?,
diff --git a/app/src/main/java/chat/rocket/android/server/infraestructure/ConnectionManager.kt b/app/src/main/java/chat/rocket/android/server/infrastructure/ConnectionManager.kt
similarity index 99%
rename from app/src/main/java/chat/rocket/android/server/infraestructure/ConnectionManager.kt
rename to app/src/main/java/chat/rocket/android/server/infrastructure/ConnectionManager.kt
index 070b270987..e2d7e1b745 100644
--- a/app/src/main/java/chat/rocket/android/server/infraestructure/ConnectionManager.kt
+++ b/app/src/main/java/chat/rocket/android/server/infrastructure/ConnectionManager.kt
@@ -1,4 +1,4 @@
-package chat.rocket.android.server.infraestructure
+package chat.rocket.android.server.infrastructure
import androidx.lifecycle.MutableLiveData
import chat.rocket.android.db.DatabaseManager
diff --git a/app/src/main/java/chat/rocket/android/server/infraestructure/ConnectionManagerFactory.kt b/app/src/main/java/chat/rocket/android/server/infrastructure/ConnectionManagerFactory.kt
similarity index 78%
rename from app/src/main/java/chat/rocket/android/server/infraestructure/ConnectionManagerFactory.kt
rename to app/src/main/java/chat/rocket/android/server/infrastructure/ConnectionManagerFactory.kt
index d1f04094ee..b4d32e63ea 100644
--- a/app/src/main/java/chat/rocket/android/server/infraestructure/ConnectionManagerFactory.kt
+++ b/app/src/main/java/chat/rocket/android/server/infrastructure/ConnectionManagerFactory.kt
@@ -1,7 +1,6 @@
-package chat.rocket.android.server.infraestructure
+package chat.rocket.android.server.infrastructure
import chat.rocket.android.db.DatabaseManagerFactory
-import chat.rocket.android.infrastructure.LocalRepository
import timber.log.Timber
import javax.inject.Inject
import javax.inject.Singleton
@@ -20,7 +19,7 @@ class ConnectionManagerFactory @Inject constructor(
}
Timber.d("Returning FRESH Manager for: $url")
- val manager = ConnectionManager(factory.create(url), dbFactory.create(url))
+ val manager = ConnectionManager(factory.get(url), dbFactory.create(url))
cache[url] = manager
return manager
}
diff --git a/app/src/main/java/chat/rocket/android/server/infrastructure/CurrentLanguageRepository.kt b/app/src/main/java/chat/rocket/android/server/infrastructure/CurrentLanguageRepository.kt
new file mode 100644
index 0000000000..e877579234
--- /dev/null
+++ b/app/src/main/java/chat/rocket/android/server/infrastructure/CurrentLanguageRepository.kt
@@ -0,0 +1,8 @@
+package chat.rocket.android.server.infrastructure
+
+interface CurrentLanguageRepository {
+
+ fun save(language: String, country: String? = null)
+ fun getLanguage(): String?
+ fun getCountry(): String?
+}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/server/infraestructure/DatabaseMessageMapper.kt b/app/src/main/java/chat/rocket/android/server/infrastructure/DatabaseMessageMapper.kt
similarity index 99%
rename from app/src/main/java/chat/rocket/android/server/infraestructure/DatabaseMessageMapper.kt
rename to app/src/main/java/chat/rocket/android/server/infrastructure/DatabaseMessageMapper.kt
index 75eb8ea8fe..4ba37af7c3 100644
--- a/app/src/main/java/chat/rocket/android/server/infraestructure/DatabaseMessageMapper.kt
+++ b/app/src/main/java/chat/rocket/android/server/infrastructure/DatabaseMessageMapper.kt
@@ -1,4 +1,4 @@
-package chat.rocket.android.server.infraestructure
+package chat.rocket.android.server.infrastructure
import chat.rocket.android.db.DatabaseManager
import chat.rocket.android.db.model.*
diff --git a/app/src/main/java/chat/rocket/android/server/infraestructure/DatabaseMessagesRepository.kt b/app/src/main/java/chat/rocket/android/server/infrastructure/DatabaseMessagesRepository.kt
similarity index 98%
rename from app/src/main/java/chat/rocket/android/server/infraestructure/DatabaseMessagesRepository.kt
rename to app/src/main/java/chat/rocket/android/server/infrastructure/DatabaseMessagesRepository.kt
index 144fe5f8d8..959f2c4aca 100644
--- a/app/src/main/java/chat/rocket/android/server/infraestructure/DatabaseMessagesRepository.kt
+++ b/app/src/main/java/chat/rocket/android/server/infrastructure/DatabaseMessagesRepository.kt
@@ -1,4 +1,4 @@
-package chat.rocket.android.server.infraestructure
+package chat.rocket.android.server.infrastructure
import chat.rocket.android.db.DatabaseManager
import chat.rocket.android.db.Operation
diff --git a/app/src/main/java/chat/rocket/android/server/infraestructure/JobSchedulerInteractorImpl.kt b/app/src/main/java/chat/rocket/android/server/infrastructure/JobSchedulerInteractorImpl.kt
similarity index 91%
rename from app/src/main/java/chat/rocket/android/server/infraestructure/JobSchedulerInteractorImpl.kt
rename to app/src/main/java/chat/rocket/android/server/infrastructure/JobSchedulerInteractorImpl.kt
index 809d1efb2b..f590008473 100644
--- a/app/src/main/java/chat/rocket/android/server/infraestructure/JobSchedulerInteractorImpl.kt
+++ b/app/src/main/java/chat/rocket/android/server/infrastructure/JobSchedulerInteractorImpl.kt
@@ -1,4 +1,4 @@
-package chat.rocket.android.server.infraestructure
+package chat.rocket.android.server.infrastructure
import android.app.job.JobInfo
import android.app.job.JobScheduler
diff --git a/app/src/main/java/chat/rocket/android/server/infraestructure/MemoryChatRoomsRepository.kt b/app/src/main/java/chat/rocket/android/server/infrastructure/MemoryChatRoomsRepository.kt
similarity index 90%
rename from app/src/main/java/chat/rocket/android/server/infraestructure/MemoryChatRoomsRepository.kt
rename to app/src/main/java/chat/rocket/android/server/infrastructure/MemoryChatRoomsRepository.kt
index 17f30b3e32..b2d92b44f9 100644
--- a/app/src/main/java/chat/rocket/android/server/infraestructure/MemoryChatRoomsRepository.kt
+++ b/app/src/main/java/chat/rocket/android/server/infrastructure/MemoryChatRoomsRepository.kt
@@ -1,4 +1,4 @@
-package chat.rocket.android.server.infraestructure
+package chat.rocket.android.server.infrastructure
import chat.rocket.android.server.domain.ChatRoomsRepository
import chat.rocket.core.model.ChatRoom
diff --git a/app/src/main/java/chat/rocket/android/server/infraestructure/MemoryUsersRepository.kt b/app/src/main/java/chat/rocket/android/server/infrastructure/MemoryUsersRepository.kt
similarity index 95%
rename from app/src/main/java/chat/rocket/android/server/infraestructure/MemoryUsersRepository.kt
rename to app/src/main/java/chat/rocket/android/server/infrastructure/MemoryUsersRepository.kt
index a7287a404f..d8bac8001e 100644
--- a/app/src/main/java/chat/rocket/android/server/infraestructure/MemoryUsersRepository.kt
+++ b/app/src/main/java/chat/rocket/android/server/infrastructure/MemoryUsersRepository.kt
@@ -1,4 +1,4 @@
-package chat.rocket.android.server.infraestructure
+package chat.rocket.android.server.infrastructure
import chat.rocket.android.server.domain.UsersRepository
import chat.rocket.android.server.domain.UsersRepository.Query
diff --git a/app/src/main/java/chat/rocket/android/server/infraestructure/RocketChatClientFactory.kt b/app/src/main/java/chat/rocket/android/server/infrastructure/RocketChatClientFactory.kt
similarity index 92%
rename from app/src/main/java/chat/rocket/android/server/infraestructure/RocketChatClientFactory.kt
rename to app/src/main/java/chat/rocket/android/server/infrastructure/RocketChatClientFactory.kt
index 3f0bb6ce77..0c5ab18cbb 100644
--- a/app/src/main/java/chat/rocket/android/server/infraestructure/RocketChatClientFactory.kt
+++ b/app/src/main/java/chat/rocket/android/server/infrastructure/RocketChatClientFactory.kt
@@ -1,4 +1,4 @@
-package chat.rocket.android.server.infraestructure
+package chat.rocket.android.server.infrastructure
import android.os.Build
import chat.rocket.android.BuildConfig
@@ -18,7 +18,7 @@ class RocketChatClientFactory @Inject constructor(
) {
private val cache = HashMap()
- fun create(url: String): RocketChatClient {
+ fun get(url: String): RocketChatClient {
cache[url]?.let {
Timber.d("Returning CACHED client for: $url")
return it
diff --git a/app/src/main/java/chat/rocket/android/server/infraestructure/SharedPreferencesAccountsRepository.kt b/app/src/main/java/chat/rocket/android/server/infrastructure/SharedPreferencesAccountsRepository.kt
similarity index 96%
rename from app/src/main/java/chat/rocket/android/server/infraestructure/SharedPreferencesAccountsRepository.kt
rename to app/src/main/java/chat/rocket/android/server/infrastructure/SharedPreferencesAccountsRepository.kt
index 2765210eda..86f84a64b1 100644
--- a/app/src/main/java/chat/rocket/android/server/infraestructure/SharedPreferencesAccountsRepository.kt
+++ b/app/src/main/java/chat/rocket/android/server/infrastructure/SharedPreferencesAccountsRepository.kt
@@ -1,4 +1,4 @@
-package chat.rocket.android.server.infraestructure
+package chat.rocket.android.server.infrastructure
import android.content.SharedPreferences
import androidx.core.content.edit
diff --git a/app/src/main/java/chat/rocket/android/server/infraestructure/SharedPreferencesPermissionsRepository.kt b/app/src/main/java/chat/rocket/android/server/infrastructure/SharedPreferencesPermissionsRepository.kt
similarity index 95%
rename from app/src/main/java/chat/rocket/android/server/infraestructure/SharedPreferencesPermissionsRepository.kt
rename to app/src/main/java/chat/rocket/android/server/infrastructure/SharedPreferencesPermissionsRepository.kt
index 946f9f44fc..3341c2a1e1 100644
--- a/app/src/main/java/chat/rocket/android/server/infraestructure/SharedPreferencesPermissionsRepository.kt
+++ b/app/src/main/java/chat/rocket/android/server/infrastructure/SharedPreferencesPermissionsRepository.kt
@@ -1,4 +1,4 @@
-package chat.rocket.android.server.infraestructure
+package chat.rocket.android.server.infrastructure
import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.server.domain.PermissionsRepository
diff --git a/app/src/main/java/chat/rocket/android/server/infraestructure/SharedPreferencesSettingsRepository.kt b/app/src/main/java/chat/rocket/android/server/infrastructure/SharedPreferencesSettingsRepository.kt
similarity index 96%
rename from app/src/main/java/chat/rocket/android/server/infraestructure/SharedPreferencesSettingsRepository.kt
rename to app/src/main/java/chat/rocket/android/server/infrastructure/SharedPreferencesSettingsRepository.kt
index 9826b2d3fd..5b7969b61e 100644
--- a/app/src/main/java/chat/rocket/android/server/infraestructure/SharedPreferencesSettingsRepository.kt
+++ b/app/src/main/java/chat/rocket/android/server/infrastructure/SharedPreferencesSettingsRepository.kt
@@ -1,4 +1,4 @@
-package chat.rocket.android.server.infraestructure
+package chat.rocket.android.server.infrastructure
import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.infrastructure.LocalRepository.Companion.SETTINGS_KEY
diff --git a/app/src/main/java/chat/rocket/android/server/infraestructure/SharedPrefsAnalyticsTrackingRepository.kt b/app/src/main/java/chat/rocket/android/server/infrastructure/SharedPrefsAnalyticsTrackingRepository.kt
similarity index 91%
rename from app/src/main/java/chat/rocket/android/server/infraestructure/SharedPrefsAnalyticsTrackingRepository.kt
rename to app/src/main/java/chat/rocket/android/server/infrastructure/SharedPrefsAnalyticsTrackingRepository.kt
index 6856f7ff73..2408de857c 100644
--- a/app/src/main/java/chat/rocket/android/server/infraestructure/SharedPrefsAnalyticsTrackingRepository.kt
+++ b/app/src/main/java/chat/rocket/android/server/infrastructure/SharedPrefsAnalyticsTrackingRepository.kt
@@ -1,4 +1,4 @@
-package chat.rocket.android.server.infraestructure
+package chat.rocket.android.server.infrastructure
import android.content.SharedPreferences
import chat.rocket.android.server.domain.AnalyticsTrackingRepository
diff --git a/app/src/main/java/chat/rocket/android/server/infraestructure/SharedPrefsBasicAuthRepository.kt b/app/src/main/java/chat/rocket/android/server/infrastructure/SharedPrefsBasicAuthRepository.kt
similarity index 96%
rename from app/src/main/java/chat/rocket/android/server/infraestructure/SharedPrefsBasicAuthRepository.kt
rename to app/src/main/java/chat/rocket/android/server/infrastructure/SharedPrefsBasicAuthRepository.kt
index 6c586200db..fd35c8df50 100644
--- a/app/src/main/java/chat/rocket/android/server/infraestructure/SharedPrefsBasicAuthRepository.kt
+++ b/app/src/main/java/chat/rocket/android/server/infrastructure/SharedPrefsBasicAuthRepository.kt
@@ -1,4 +1,4 @@
-package chat.rocket.android.server.infraestructure
+package chat.rocket.android.server.infrastructure
import android.content.SharedPreferences
import androidx.core.content.edit
diff --git a/app/src/main/java/chat/rocket/android/server/infraestructure/SharedPrefsConnectingServerRepository.kt b/app/src/main/java/chat/rocket/android/server/infrastructure/SharedPrefsConnectingServerRepository.kt
similarity index 92%
rename from app/src/main/java/chat/rocket/android/server/infraestructure/SharedPrefsConnectingServerRepository.kt
rename to app/src/main/java/chat/rocket/android/server/infrastructure/SharedPrefsConnectingServerRepository.kt
index bf8b3a6ffa..f4e90a4e3a 100644
--- a/app/src/main/java/chat/rocket/android/server/infraestructure/SharedPrefsConnectingServerRepository.kt
+++ b/app/src/main/java/chat/rocket/android/server/infrastructure/SharedPrefsConnectingServerRepository.kt
@@ -1,4 +1,4 @@
-package chat.rocket.android.server.infraestructure
+package chat.rocket.android.server.infrastructure
import android.content.SharedPreferences
import chat.rocket.android.server.domain.CurrentServerRepository
diff --git a/app/src/main/java/chat/rocket/android/server/infrastructure/SharedPrefsCurrentLanguageRepository.kt b/app/src/main/java/chat/rocket/android/server/infrastructure/SharedPrefsCurrentLanguageRepository.kt
new file mode 100644
index 0000000000..06224302e7
--- /dev/null
+++ b/app/src/main/java/chat/rocket/android/server/infrastructure/SharedPrefsCurrentLanguageRepository.kt
@@ -0,0 +1,26 @@
+package chat.rocket.android.server.infrastructure
+
+import android.content.SharedPreferences
+import java.util.*
+
+private const val CURRENT_LANGUAGE = "current_language"
+private const val CURRENT_LANGUAGE_COUNTRY = "current_language_country"
+
+class SharedPrefsCurrentLanguageRepository(private val preferences: SharedPreferences) :
+ CurrentLanguageRepository {
+
+ override fun save(language: String, country: String?) {
+ with(preferences) {
+ edit().putString(CURRENT_LANGUAGE, language).apply()
+ edit().putString(CURRENT_LANGUAGE_COUNTRY, country).apply()
+ }
+ }
+
+ override fun getLanguage(): String? {
+ return preferences.getString(CURRENT_LANGUAGE, Locale.getDefault().language)
+ }
+
+ override fun getCountry(): String? {
+ return preferences.getString(CURRENT_LANGUAGE_COUNTRY, Locale.getDefault().country)
+ }
+}
diff --git a/app/src/main/java/chat/rocket/android/server/infraestructure/SharedPrefsCurrentServerRepository.kt b/app/src/main/java/chat/rocket/android/server/infrastructure/SharedPrefsCurrentServerRepository.kt
similarity index 92%
rename from app/src/main/java/chat/rocket/android/server/infraestructure/SharedPrefsCurrentServerRepository.kt
rename to app/src/main/java/chat/rocket/android/server/infrastructure/SharedPrefsCurrentServerRepository.kt
index 8967865dcf..449801ce1a 100644
--- a/app/src/main/java/chat/rocket/android/server/infraestructure/SharedPrefsCurrentServerRepository.kt
+++ b/app/src/main/java/chat/rocket/android/server/infrastructure/SharedPrefsCurrentServerRepository.kt
@@ -1,4 +1,4 @@
-package chat.rocket.android.server.infraestructure
+package chat.rocket.android.server.infrastructure
import android.content.SharedPreferences
import chat.rocket.android.server.domain.CurrentServerRepository
diff --git a/app/src/main/java/chat/rocket/android/server/infrastructure/SharedPrefsSortingAndGroupingRepository.kt b/app/src/main/java/chat/rocket/android/server/infrastructure/SharedPrefsSortingAndGroupingRepository.kt
new file mode 100644
index 0000000000..91aecd17bd
--- /dev/null
+++ b/app/src/main/java/chat/rocket/android/server/infrastructure/SharedPrefsSortingAndGroupingRepository.kt
@@ -0,0 +1,39 @@
+package chat.rocket.android.server.infrastructure
+
+import android.content.SharedPreferences
+import chat.rocket.android.server.domain.SortingAndGroupingRepository
+
+private const val SORT_BY_NAME_KEY = "SORT_BY_NAME_KEY"
+private const val UNREAD_ON_TOP_KEY = "UNREAD_ON_TOP_KEY"
+private const val GROUP_BY_TYPE_KEY = "GROUP_BY_TYPE_KEY"
+private const val GROUP_BY_FAVORITES_KEY = "GROUP_BY_FAVORITES_KEY"
+
+class SharedPrefsSortingAndGroupingRepository(private val preferences: SharedPreferences) :
+ SortingAndGroupingRepository {
+
+ override fun save(
+ currentServerUrl: String,
+ isSortByName: Boolean,
+ isUnreadOnTop: Boolean,
+ isGroupByType: Boolean,
+ isGroupByFavorites: Boolean
+ ) {
+ preferences.edit().putBoolean(SORT_BY_NAME_KEY + currentServerUrl, isSortByName).apply()
+ preferences.edit().putBoolean(UNREAD_ON_TOP_KEY + currentServerUrl, isUnreadOnTop).apply()
+ preferences.edit().putBoolean(GROUP_BY_TYPE_KEY + currentServerUrl, isGroupByType).apply()
+ preferences.edit().putBoolean(GROUP_BY_FAVORITES_KEY + currentServerUrl, isGroupByFavorites)
+ .apply()
+ }
+
+ override fun getSortByName(currentServerUrl: String): Boolean =
+ preferences.getBoolean(SORT_BY_NAME_KEY + currentServerUrl, false)
+
+ override fun getUnreadOnTop(currentServerUrl: String): Boolean =
+ preferences.getBoolean(UNREAD_ON_TOP_KEY + currentServerUrl, false)
+
+ override fun getGroupByType(currentServerUrl: String): Boolean =
+ preferences.getBoolean(GROUP_BY_TYPE_KEY + currentServerUrl, false)
+
+ override fun getGroupByFavorites(currentServerUrl: String): Boolean =
+ preferences.getBoolean(GROUP_BY_FAVORITES_KEY + currentServerUrl, false)
+}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/server/presentation/ChangeServerPresenter.kt b/app/src/main/java/chat/rocket/android/server/presentation/ChangeServerPresenter.kt
index dbfc912a3f..cbe8718e37 100644
--- a/app/src/main/java/chat/rocket/android/server/presentation/ChangeServerPresenter.kt
+++ b/app/src/main/java/chat/rocket/android/server/presentation/ChangeServerPresenter.kt
@@ -9,7 +9,7 @@ import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.domain.SaveCurrentServerInteractor
import chat.rocket.android.server.domain.SettingsRepository
import chat.rocket.android.server.domain.TokenRepository
-import chat.rocket.android.server.infraestructure.ConnectionManagerFactory
+import chat.rocket.android.server.infrastructure.ConnectionManagerFactory
import chat.rocket.android.util.extension.launchUI
import chat.rocket.common.util.ifNull
import javax.inject.Inject
diff --git a/app/src/main/java/chat/rocket/android/server/presentation/CheckServerPresenter.kt b/app/src/main/java/chat/rocket/android/server/presentation/CheckServerPresenter.kt
index d11c28819c..8b807ab39b 100644
--- a/app/src/main/java/chat/rocket/android/server/presentation/CheckServerPresenter.kt
+++ b/app/src/main/java/chat/rocket/android/server/presentation/CheckServerPresenter.kt
@@ -26,9 +26,9 @@ import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.domain.RemoveAccountInteractor
import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.domain.RefreshSettingsInteractor
-import chat.rocket.android.server.infraestructure.ConnectionManager
-import chat.rocket.android.server.infraestructure.ConnectionManagerFactory
-import chat.rocket.android.server.infraestructure.RocketChatClientFactory
+import chat.rocket.android.server.infrastructure.ConnectionManager
+import chat.rocket.android.server.infrastructure.ConnectionManagerFactory
+import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.util.VersionInfo
import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.extensions.casUrl
@@ -105,7 +105,7 @@ abstract class CheckServerPresenter constructor(
internal fun setupConnectionInfo(serverUrl: String) {
currentServer = serverUrl
- client = factory.create(serverUrl)
+ client = factory.get(serverUrl)
managerFactory?.create(serverUrl)?.let {
manager = it
}
@@ -452,7 +452,7 @@ abstract class CheckServerPresenter constructor(
/**
* Returns the OAuth client ID of a [serviceMap].
- * REMARK: This function works for common OAuth providers (Google, Facebook, Github and so on)
+ * REMARK: This function works for common OAuth providers (Google, Facebook, GitHub and so on)
* as well as custom OAuth.
*
* @param serviceMap The service map to get the OAuth client ID.
diff --git a/app/src/main/java/chat/rocket/android/servers/adapter/AddNewServerViewHolder.kt b/app/src/main/java/chat/rocket/android/servers/adapter/AddNewServerViewHolder.kt
new file mode 100644
index 0000000000..ee2c6fec7c
--- /dev/null
+++ b/app/src/main/java/chat/rocket/android/servers/adapter/AddNewServerViewHolder.kt
@@ -0,0 +1,6 @@
+package chat.rocket.android.servers.adapter
+
+import android.view.View
+import androidx.recyclerview.widget.RecyclerView
+
+class AddNewServerViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/servers/adapter/ServerViewHolder.kt b/app/src/main/java/chat/rocket/android/servers/adapter/ServerViewHolder.kt
new file mode 100644
index 0000000000..6ea75b314d
--- /dev/null
+++ b/app/src/main/java/chat/rocket/android/servers/adapter/ServerViewHolder.kt
@@ -0,0 +1,21 @@
+package chat.rocket.android.servers.adapter
+
+import android.view.View
+import androidx.core.view.isInvisible
+import androidx.recyclerview.widget.RecyclerView
+import chat.rocket.android.server.domain.model.Account
+import com.bumptech.glide.Glide
+import kotlinx.android.synthetic.main.item_server.view.*
+
+class ServerViewHolder(itemView: View, private val currentServerUrl: String) :
+ RecyclerView.ViewHolder(itemView) {
+
+ fun bind(account: Account) {
+ with(itemView) {
+ Glide.with(context).load(account.serverLogo).into(image_server)
+ text_server_name.text = account.serverName ?: account.serverUrl
+ text_server_url.text = account.serverUrl
+ image_check.isInvisible = currentServerUrl != account.serverUrl
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/servers/adapter/ServersAdapter.kt b/app/src/main/java/chat/rocket/android/servers/adapter/ServersAdapter.kt
new file mode 100644
index 0000000000..d71f540313
--- /dev/null
+++ b/app/src/main/java/chat/rocket/android/servers/adapter/ServersAdapter.kt
@@ -0,0 +1,57 @@
+package chat.rocket.android.servers.adapter
+
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import chat.rocket.android.R
+import chat.rocket.android.server.domain.model.Account
+import chat.rocket.android.util.extensions.inflate
+
+private const val VIEW_TYPE_SERVER = 0
+private const val VIEW_TYPE_ADD_NEW_SERVER = 1
+
+class ServersAdapter(
+ private val servers: List,
+ private val currentServerUrl: String,
+ private val selector: Selector
+) : RecyclerView.Adapter() {
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
+ return when (viewType) {
+ VIEW_TYPE_SERVER -> ServerViewHolder(
+ parent.inflate(R.layout.item_server), currentServerUrl
+ )
+ else -> AddNewServerViewHolder(parent.inflate(R.layout.item_add_new_server))
+ }
+ }
+
+ override fun getItemCount() = servers.size + 1
+
+ override fun getItemViewType(position: Int): Int {
+ return when {
+ position < servers.size -> VIEW_TYPE_SERVER
+ else -> VIEW_TYPE_ADD_NEW_SERVER
+ }
+ }
+
+ override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
+ when (holder) {
+ is ServerViewHolder -> bindServerViewHolder(holder, position)
+ is AddNewServerViewHolder -> bindAddNewServerViewHolder(holder)
+ }
+ }
+
+ private fun bindServerViewHolder(holder: ServerViewHolder, position: Int) {
+ val account = servers[position]
+ holder.bind(account)
+ holder.itemView.setOnClickListener { selector.onServerSelected(account.serverUrl) }
+ }
+
+ private fun bindAddNewServerViewHolder(holder: AddNewServerViewHolder) {
+ holder.itemView.setOnClickListener { selector.onAddNewServerSelected() }
+ }
+}
+
+interface Selector {
+ fun onServerSelected(serverUrl: String)
+ fun onAddNewServerSelected()
+}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/servers/di/ServersBottomSheetFragmentModule.kt b/app/src/main/java/chat/rocket/android/servers/di/ServersBottomSheetFragmentModule.kt
new file mode 100644
index 0000000000..64d1c91b36
--- /dev/null
+++ b/app/src/main/java/chat/rocket/android/servers/di/ServersBottomSheetFragmentModule.kt
@@ -0,0 +1,15 @@
+package chat.rocket.android.servers.di
+
+import chat.rocket.android.dagger.scope.PerFragment
+import chat.rocket.android.servers.presentation.ServersView
+import chat.rocket.android.servers.ui.ServersBottomSheetFragment
+import dagger.Module
+import dagger.Provides
+
+@Module
+class ServersBottomSheetFragmentModule {
+
+ @Provides
+ @PerFragment
+ fun serversView(frag: ServersBottomSheetFragment): ServersView = frag
+}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/servers/di/ServersBottomSheetFragmentProvider.kt b/app/src/main/java/chat/rocket/android/servers/di/ServersBottomSheetFragmentProvider.kt
new file mode 100644
index 0000000000..d7c9ca56ff
--- /dev/null
+++ b/app/src/main/java/chat/rocket/android/servers/di/ServersBottomSheetFragmentProvider.kt
@@ -0,0 +1,14 @@
+package chat.rocket.android.servers.di
+
+import chat.rocket.android.dagger.scope.PerFragment
+import chat.rocket.android.servers.ui.ServersBottomSheetFragment
+import dagger.Module
+import dagger.android.ContributesAndroidInjector
+
+@Module
+abstract class ServersBottomSheetFragmentProvider {
+
+ @ContributesAndroidInjector(modules = [ServersBottomSheetFragmentModule::class])
+ @PerFragment
+ abstract fun provideServersBottomSheetFragment(): ServersBottomSheetFragment
+}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/servers/presentation/ServersPresenter.kt b/app/src/main/java/chat/rocket/android/servers/presentation/ServersPresenter.kt
new file mode 100644
index 0000000000..b7768edf37
--- /dev/null
+++ b/app/src/main/java/chat/rocket/android/servers/presentation/ServersPresenter.kt
@@ -0,0 +1,47 @@
+package chat.rocket.android.servers.presentation
+
+import chat.rocket.android.core.lifecycle.CancelStrategy
+import chat.rocket.android.main.presentation.MainNavigator
+import chat.rocket.android.server.domain.GetAccountsInteractor
+import chat.rocket.android.util.extension.launchUI
+import chat.rocket.common.util.ifNull
+import timber.log.Timber
+import javax.inject.Inject
+import javax.inject.Named
+
+class ServersPresenter @Inject constructor(
+ private val view: ServersView,
+ private val navigator: MainNavigator,
+ private val strategy: CancelStrategy,
+ private val getAccountsInteractor: GetAccountsInteractor,
+ @Named("currentServer") private val currentServerUrl: String
+) {
+
+ fun getAllServers() {
+ launchUI(strategy) {
+ try {
+ view.showServerList(getAccountsInteractor.get(), currentServerUrl)
+ } catch (exception: Exception) {
+ Timber.e(exception, "Error loading servers")
+ exception.message?.let {
+ view.showMessage(it)
+ }.ifNull {
+ view.showGenericErrorMessage()
+ }
+ }
+ }
+ }
+
+ fun changeServer(serverUrl: String) {
+ if (currentServerUrl != serverUrl) {
+ navigator.switchOrAddNewServer(serverUrl)
+ } else {
+ view.hideServerView()
+ }
+ }
+
+ fun addNewServer() {
+ view.hideServerView()
+ navigator.toServerScreen()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/servers/presentation/ServersView.kt b/app/src/main/java/chat/rocket/android/servers/presentation/ServersView.kt
new file mode 100644
index 0000000000..742dca4b11
--- /dev/null
+++ b/app/src/main/java/chat/rocket/android/servers/presentation/ServersView.kt
@@ -0,0 +1,20 @@
+package chat.rocket.android.servers.presentation
+
+import chat.rocket.android.core.behaviours.MessageView
+import chat.rocket.android.server.domain.model.Account
+
+interface ServersView : MessageView {
+
+ /**
+ * Shows the server list.
+ *
+ * @param serverList The list of server to show.
+ * @param currentServerUrl The current logged in server url.
+ */
+ fun showServerList(serverList: List, currentServerUrl: String)
+
+ /**
+ * Hides the servers view.
+ */
+ fun hideServerView()
+}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/servers/ui/ServersBottomSheetFragment.kt b/app/src/main/java/chat/rocket/android/servers/ui/ServersBottomSheetFragment.kt
new file mode 100644
index 0000000000..717a113e04
--- /dev/null
+++ b/app/src/main/java/chat/rocket/android/servers/ui/ServersBottomSheetFragment.kt
@@ -0,0 +1,67 @@
+package chat.rocket.android.servers.ui
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.recyclerview.widget.LinearLayoutManager
+import chat.rocket.android.R
+import chat.rocket.android.server.domain.model.Account
+import chat.rocket.android.servers.adapter.Selector
+import chat.rocket.android.servers.adapter.ServersAdapter
+import chat.rocket.android.servers.presentation.ServersPresenter
+import chat.rocket.android.servers.presentation.ServersView
+import chat.rocket.android.util.extensions.showToast
+import com.google.android.material.bottomsheet.BottomSheetDialogFragment
+import dagger.android.support.AndroidSupportInjection
+import kotlinx.android.synthetic.main.bottom_sheet_fragment_servers.*
+import javax.inject.Inject
+
+const val TAG = "ServersBottomSheetFragment"
+
+class ServersBottomSheetFragment : BottomSheetDialogFragment(), ServersView {
+ @Inject
+ lateinit var presenter: ServersPresenter
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ AndroidSupportInjection.inject(this)
+ }
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? =
+ inflater.inflate(R.layout.bottom_sheet_fragment_servers, container, false)
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ presenter.getAllServers()
+ }
+
+ override fun showServerList(serverList: List, currentServerUrl: String) {
+ recycler_view.layoutManager = LinearLayoutManager(context)
+ recycler_view.adapter = ServersAdapter(serverList, currentServerUrl, object : Selector {
+ override fun onServerSelected(serverUrl: String) {
+ presenter.changeServer(serverUrl)
+ }
+
+ override fun onAddNewServerSelected() {
+ presenter.addNewServer()
+ }
+ })
+ }
+
+ override fun hideServerView() = dismiss()
+
+ override fun showMessage(resId: Int) {
+ showToast(resId)
+ }
+
+ override fun showMessage(message: String) {
+ showToast(message)
+ }
+
+ override fun showGenericErrorMessage() = showMessage(getString(R.string.msg_generic_error))
+}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/settings/di/SettingsFragmentModule.kt b/app/src/main/java/chat/rocket/android/settings/di/SettingsFragmentModule.kt
index beb4ba79b4..1928f7b7ef 100644
--- a/app/src/main/java/chat/rocket/android/settings/di/SettingsFragmentModule.kt
+++ b/app/src/main/java/chat/rocket/android/settings/di/SettingsFragmentModule.kt
@@ -1,13 +1,11 @@
package chat.rocket.android.settings.di
import androidx.lifecycle.LifecycleOwner
-import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.dagger.scope.PerFragment
import chat.rocket.android.settings.presentation.SettingsView
import chat.rocket.android.settings.ui.SettingsFragment
import dagger.Module
import dagger.Provides
-import kotlinx.coroutines.Job
@Module
class SettingsFragmentModule {
@@ -20,13 +18,7 @@ class SettingsFragmentModule {
@Provides
@PerFragment
- fun settingsLifecycleOwner(frag: SettingsFragment): LifecycleOwner {
- return frag
- }
-
- @Provides
- @PerFragment
- fun provideCancelStrategy(owner: LifecycleOwner, jobs: Job): CancelStrategy {
- return CancelStrategy(owner, jobs)
+ fun settingsLifecycleOwner(fragment: SettingsFragment): LifecycleOwner {
+ return fragment
}
}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/settings/di/SettingsFragmentProvider.kt b/app/src/main/java/chat/rocket/android/settings/di/SettingsFragmentProvider.kt
index 8d5ed61590..cfb74551a2 100644
--- a/app/src/main/java/chat/rocket/android/settings/di/SettingsFragmentProvider.kt
+++ b/app/src/main/java/chat/rocket/android/settings/di/SettingsFragmentProvider.kt
@@ -1,5 +1,6 @@
package chat.rocket.android.settings.di
+import chat.rocket.android.dagger.scope.PerFragment
import chat.rocket.android.settings.ui.SettingsFragment
import dagger.Module
import dagger.android.ContributesAndroidInjector
@@ -8,5 +9,6 @@ import dagger.android.ContributesAndroidInjector
abstract class SettingsFragmentProvider {
@ContributesAndroidInjector(modules = [SettingsFragmentModule::class])
+ @PerFragment
abstract fun provideSettingsFragment(): SettingsFragment
}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/settings/password/presentation/PasswordPresenter.kt b/app/src/main/java/chat/rocket/android/settings/password/presentation/PasswordPresenter.kt
index 2731855a45..e6d86c2ed7 100644
--- a/app/src/main/java/chat/rocket/android/settings/password/presentation/PasswordPresenter.kt
+++ b/app/src/main/java/chat/rocket/android/settings/password/presentation/PasswordPresenter.kt
@@ -4,11 +4,10 @@ import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.helper.UserHelper
import chat.rocket.android.server.domain.GetCurrentServerInteractor
-import chat.rocket.android.server.infraestructure.RocketChatClientFactory
+import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.retryIO
import chat.rocket.common.RocketChatException
-import chat.rocket.common.util.ifNull
import chat.rocket.core.RocketChatClient
import chat.rocket.core.internal.rest.updateProfile
import javax.inject.Inject
@@ -22,7 +21,7 @@ class PasswordPresenter @Inject constructor(
factory: RocketChatClientFactory
) {
private val serverUrl = serverInteractor.get()!!
- private val client: RocketChatClient = factory.create(serverUrl)
+ private val client: RocketChatClient = factory.get(serverUrl)
fun updatePassword(password: String) {
launchUI(strategy) {
diff --git a/app/src/main/java/chat/rocket/android/settings/presentation/SettingsPresenter.kt b/app/src/main/java/chat/rocket/android/settings/presentation/SettingsPresenter.kt
new file mode 100644
index 0000000000..c311b3e5f9
--- /dev/null
+++ b/app/src/main/java/chat/rocket/android/settings/presentation/SettingsPresenter.kt
@@ -0,0 +1,151 @@
+package chat.rocket.android.settings.presentation
+
+import android.content.Context
+import android.os.Build
+import chat.rocket.android.core.lifecycle.CancelStrategy
+import chat.rocket.android.db.DatabaseManagerFactory
+import chat.rocket.android.helper.UserHelper
+import chat.rocket.android.main.presentation.MainNavigator
+import chat.rocket.android.server.domain.AnalyticsTrackingInteractor
+import chat.rocket.android.server.domain.GetCurrentServerInteractor
+import chat.rocket.android.server.domain.PermissionsInteractor
+import chat.rocket.android.server.domain.RemoveAccountInteractor
+import chat.rocket.android.server.domain.SaveCurrentLanguageInteractor
+import chat.rocket.android.server.domain.TokenRepository
+import chat.rocket.android.server.infrastructure.ConnectionManagerFactory
+import chat.rocket.android.server.infrastructure.RocketChatClientFactory
+import chat.rocket.android.server.presentation.CheckServerPresenter
+import chat.rocket.android.util.extension.gethash
+import chat.rocket.android.util.extension.launchUI
+import chat.rocket.android.util.extension.toHex
+import chat.rocket.android.util.extensions.adminPanelUrl
+import chat.rocket.android.util.extensions.avatarUrl
+import chat.rocket.android.util.retryIO
+import chat.rocket.common.util.ifNull
+import chat.rocket.core.internal.rest.deleteOwnAccount
+import chat.rocket.core.internal.rest.me
+import chat.rocket.core.internal.rest.serverInfo
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+import timber.log.Timber
+import java.util.*
+import javax.inject.Inject
+import javax.inject.Named
+
+class SettingsPresenter @Inject constructor(
+ private val view: SettingsView,
+ private val strategy: CancelStrategy,
+ private val navigator: MainNavigator,
+ @Named("currentServer") private val currentServer: String,
+ private val userHelper: UserHelper,
+ private val analyticsTrackingInteractor: AnalyticsTrackingInteractor,
+ private val tokenRepository: TokenRepository,
+ private val permissions: PermissionsInteractor,
+ private val rocketChatClientFactory: RocketChatClientFactory,
+ private val saveLanguageInteractor: SaveCurrentLanguageInteractor,
+ getCurrentServerInteractor: GetCurrentServerInteractor,
+ removeAccountInteractor: RemoveAccountInteractor,
+ databaseManagerFactory: DatabaseManagerFactory,
+ connectionManagerFactory: ConnectionManagerFactory
+) : CheckServerPresenter(
+ strategy = strategy,
+ factory = rocketChatClientFactory,
+ serverInteractor = getCurrentServerInteractor,
+ removeAccountInteractor = removeAccountInteractor,
+ tokenRepository = tokenRepository,
+ dbManagerFactory = databaseManagerFactory,
+ managerFactory = connectionManagerFactory,
+ tokenView = view,
+ navigator = navigator
+) {
+ private val token = tokenRepository.get(currentServer)
+
+ fun setupView() {
+ launchUI(strategy) {
+ try {
+ val serverInfo = retryIO(description = "serverInfo", times = 5) {
+ rocketChatClientFactory.get(currentServer).serverInfo()
+ }
+
+ val me = retryIO(description = "serverInfo", times = 5) {
+ rocketChatClientFactory.get(currentServer).me()
+ }
+
+ userHelper.user()?.let { user ->
+ view.setupSettingsView(
+ currentServer.avatarUrl(me.username!!, token?.userId, token?.authToken),
+ userHelper.displayName(user) ?: me.username ?: "",
+ me.status.toString(),
+ permissions.isAdministrationEnabled(),
+ analyticsTrackingInteractor.get(),
+ true,
+ serverInfo.version
+ )
+ }
+ } catch (exception: Exception) {
+ Timber.d(exception, "Error getting server info")
+ exception.message?.let {
+ view.showMessage(it)
+ }.ifNull {
+ view.showGenericErrorMessage()
+ }
+ }
+ }
+ }
+
+ fun enableAnalyticsTracking(isEnabled: Boolean) {
+ analyticsTrackingInteractor.save(isEnabled)
+ }
+
+ fun logout() {
+ setupConnectionInfo(currentServer)
+ super.logout(null) // TODO null?
+ }
+
+ fun deleteAccount(password: String) {
+ launchUI(strategy) {
+ view.showLoading()
+ try {
+ withContext(Dispatchers.Default) {
+ // REMARK: Backend API is only working with a lowercase hash.
+ // https://github.com/RocketChat/Rocket.Chat/issues/12573
+ retryIO {
+ rocketChatClientFactory.get(currentServer)
+ .deleteOwnAccount(password.gethash().toHex().toLowerCase())
+ }
+ setupConnectionInfo(currentServer)
+ logout(null)
+ }
+ } catch (exception: Exception) {
+ exception.message?.let {
+ view.showMessage(it)
+ }.ifNull {
+ view.showGenericErrorMessage()
+ }
+ } finally {
+ view.hideLoading()
+ }
+ }
+ }
+
+ fun getCurrentLocale(context: Context): Locale {
+ return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ context.resources.configuration.locales.get(0)
+ } else {
+ context.resources.configuration.locale
+ }
+ }
+
+ fun saveLocale(language: String, country: String? = null) {
+ saveLanguageInteractor.save(language, country)
+ }
+
+ fun toProfile() = navigator.toProfile()
+
+ fun toAdmin() = tokenRepository.get(currentServer)?.let {
+ navigator.toAdminPanel(currentServer.adminPanelUrl(), it.authToken)
+ }
+
+ fun toLicense(licenseUrl: String, licenseTitle: String) =
+ navigator.toLicense(licenseUrl, licenseTitle)
+}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/settings/presentation/SettingsView.kt b/app/src/main/java/chat/rocket/android/settings/presentation/SettingsView.kt
index a62bb4f884..3fc3b8e413 100644
--- a/app/src/main/java/chat/rocket/android/settings/presentation/SettingsView.kt
+++ b/app/src/main/java/chat/rocket/android/settings/presentation/SettingsView.kt
@@ -1,3 +1,29 @@
package chat.rocket.android.settings.presentation
-interface SettingsView
+import chat.rocket.android.core.behaviours.LoadingView
+import chat.rocket.android.core.behaviours.MessageView
+import chat.rocket.android.server.presentation.TokenView
+
+interface SettingsView : TokenView, LoadingView, MessageView {
+
+ /**
+ * Setups the settings view.
+ *
+ * @param avatar The user avatar.
+ * @param displayName The user display name.
+ * @param status The user status.
+ * @param isAdministrationEnabled True if the administration is enabled, false otherwise.
+ * @param isAnalyticsTrackingEnabled True if the analytics tracking is enabled, false otherwise.
+ * @param isDeleteAccountEnabled True if the delete account is enabled, false otherwise.
+ * @param serverVersion The version of the current logged in server.
+ */
+ fun setupSettingsView(
+ avatar: String,
+ displayName: String,
+ status: String,
+ isAdministrationEnabled: Boolean,
+ isAnalyticsTrackingEnabled: Boolean,
+ isDeleteAccountEnabled: Boolean,
+ serverVersion: String
+ )
+}
diff --git a/app/src/main/java/chat/rocket/android/settings/ui/SettingsFragment.kt b/app/src/main/java/chat/rocket/android/settings/ui/SettingsFragment.kt
index 9daab340c1..ad66900c9d 100644
--- a/app/src/main/java/chat/rocket/android/settings/ui/SettingsFragment.kt
+++ b/app/src/main/java/chat/rocket/android/settings/ui/SettingsFragment.kt
@@ -7,35 +7,56 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
-import android.widget.AdapterView
+import android.widget.EditText
+import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.core.net.toUri
+import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
+import chat.rocket.android.BuildConfig
import chat.rocket.android.R
-import chat.rocket.android.about.ui.AboutFragment
-import chat.rocket.android.about.ui.TAG_ABOUT_FRAGMENT
import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.analytics.event.ScreenViewEvent
+import chat.rocket.android.core.behaviours.AppLanguageView
import chat.rocket.android.helper.TextHelper.getDeviceAndAppInformation
-import chat.rocket.android.main.ui.MainActivity
-import chat.rocket.android.preferences.ui.PreferencesFragment
-import chat.rocket.android.preferences.ui.TAG_PREFERENCES_FRAGMENT
-import chat.rocket.android.settings.password.ui.PasswordActivity
+import chat.rocket.android.settings.presentation.SettingsPresenter
import chat.rocket.android.settings.presentation.SettingsView
-import chat.rocket.android.util.extensions.addFragmentBackStack
import chat.rocket.android.util.extensions.inflate
import chat.rocket.android.util.extensions.showToast
-import chat.rocket.android.webview.ui.webViewIntent
+import chat.rocket.android.util.invalidateFirebaseToken
import dagger.android.support.AndroidSupportInjection
+import kotlinx.android.synthetic.main.app_bar.*
import kotlinx.android.synthetic.main.fragment_settings.*
import timber.log.Timber
import javax.inject.Inject
internal const val TAG_SETTINGS_FRAGMENT = "SettingsFragment"
-class SettingsFragment : Fragment(), SettingsView, AdapterView.OnItemClickListener {
+fun newInstance(): Fragment = SettingsFragment()
+
+class SettingsFragment : Fragment(), SettingsView, AppLanguageView {
@Inject
lateinit var analyticsManager: AnalyticsManager
+ @Inject
+ lateinit var presenter: SettingsPresenter
+ private val locales = arrayListOf(
+ "en",
+ "ar",
+ "de",
+ "es",
+ "fa",
+ "fr",
+ "hi,IN",
+ "it",
+ "ja",
+ "pt,BR",
+ "pt,PT",
+ "ru,RU",
+ "tr",
+ "uk",
+ "zh,CN",
+ "zh,TW"
+ )
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -51,86 +72,104 @@ class SettingsFragment : Fragment(), SettingsView, AdapterView.OnItemClickListen
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupToolbar()
- setupListView()
+ presenter.setupView()
analyticsManager.logScreenView(ScreenViewEvent.Settings)
}
- override fun onResume() {
- // FIXME - gambiarra ahead. will fix when moving to new androidx Navigation
- (activity as? MainActivity)?.setupNavigationView()
- super.onResume()
- }
+ override fun setupSettingsView(
+ avatar: String,
+ displayName: String,
+ status: String,
+ isAdministrationEnabled: Boolean,
+ isAnalyticsTrackingEnabled: Boolean,
+ isDeleteAccountEnabled: Boolean,
+ serverVersion: String
+ ) {
+ image_avatar.setImageURI(avatar)
- override fun onItemClick(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
- when (parent?.getItemAtPosition(position).toString()) {
- resources.getStringArray(R.array.settings_actions)[0] -> {
- (activity as AppCompatActivity).addFragmentBackStack(
- TAG_PREFERENCES_FRAGMENT,
- R.id.fragment_container
- ) {
- PreferencesFragment.newInstance()
- }
- }
+ text_display_name.text = displayName
- resources.getStringArray(R.array.settings_actions)[1] ->
- activity?.startActivity(Intent(activity, PasswordActivity::class.java))
+ text_status.text = status
- // TODO (https://github.com/RocketChat/Rocket.Chat.Android/pull/1918)
- resources.getStringArray(R.array.settings_actions)[2] -> showToast("Coming soon")
+ profile_container.setOnClickListener { presenter.toProfile() }
- resources.getStringArray(R.array.settings_actions)[3] -> shareApp()
+ text_contact_us.setOnClickListener { contactSupport() }
- resources.getStringArray(R.array.settings_actions)[4] -> showAppOnStore()
+ text_language.setOnClickListener { changeLanguage() }
- resources.getStringArray(R.array.settings_actions)[5] -> contactSupport()
+ text_review_this_app.setOnClickListener { showAppOnStore() }
- resources.getStringArray(R.array.settings_actions)[6] -> activity?.startActivity(
- context?.webViewIntent(
- getString(R.string.license_url),
- getString(R.string.title_licence)
- )
- )
+ text_share_this_app.setOnClickListener { shareApp() }
- resources.getStringArray(R.array.settings_actions)[7] -> {
- (activity as AppCompatActivity).addFragmentBackStack(
- TAG_ABOUT_FRAGMENT,
- R.id.fragment_container
- ) {
- AboutFragment.newInstance()
- }
+ text_license.setOnClickListener {
+ presenter.toLicense(getString(R.string.license_url), getString(R.string.title_license))
+ }
+
+ text_app_version.text = getString(R.string.msg_app_version, BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE)
+
+ text_server_version.text = getString(R.string.msg_server_version, serverVersion)
+
+ text_logout.setOnClickListener { showLogoutDialog() }
+
+ with(text_administration) {
+ isVisible = isAdministrationEnabled
+ setOnClickListener { presenter.toAdmin() }
+ }
+
+ with(switch_crash_report) {
+ isChecked = isAnalyticsTrackingEnabled
+ isEnabled = BuildConfig.FLAVOR == "play"
+ setOnCheckedChangeListener { _, isChecked ->
+ presenter.enableAnalyticsTracking(isChecked)
}
}
- }
- private fun showAppOnStore() {
- try {
- startActivity(Intent(Intent.ACTION_VIEW, getString(R.string.market_link).toUri()))
- } catch (error: ActivityNotFoundException) {
- startActivity(Intent(Intent.ACTION_VIEW, getString(R.string.play_store_link).toUri()))
+ with(text_delete_account) {
+ isVisible = isDeleteAccountEnabled
+ setOnClickListener { showDeleteAccountDialog() }
}
}
- private fun setupListView() {
- settings_list.onItemClickListener = this
+ override fun updateLanguage(language: String, country: String?) {
+ presenter.saveLocale(language, country)
+ activity?.recreate()
}
- private fun setupToolbar() {
- (activity as AppCompatActivity?)?.supportActionBar?.title = getString(R.string.title_settings)
+ override fun invalidateToken(token: String) = invalidateFirebaseToken(token)
+
+ override fun showLoading() {
+ view_loading.isVisible = true
}
- private fun shareApp() {
- with(Intent(Intent.ACTION_SEND)) {
- type = "text/plain"
- putExtra(Intent.EXTRA_SUBJECT, getString(R.string.msg_check_this_out))
- putExtra(Intent.EXTRA_TEXT, getString(R.string.play_store_link))
- startActivity(Intent.createChooser(this, getString(R.string.msg_share_using)))
+ override fun hideLoading() {
+ view_loading.isVisible = false
+ }
+
+ override fun showMessage(resId: Int) {
+ showToast(resId)
+ }
+
+ override fun showMessage(message: String) {
+ showToast(message)
+ }
+
+ override fun showGenericErrorMessage() = showMessage(getString(R.string.msg_generic_error))
+
+ private fun setupToolbar() {
+ with((activity as AppCompatActivity)) {
+ with(toolbar) {
+ setSupportActionBar(this)
+ title = getString(R.string.title_settings)
+ setNavigationIcon(R.drawable.ic_arrow_back_white_24dp)
+ setNavigationOnClickListener { activity?.onBackPressed() }
+ }
}
}
private fun contactSupport() {
val uriText = "mailto:${"support@rocket.chat"}" +
- "?subject=" + Uri.encode(getString(R.string.msg_android_app_support)) +
- "&body=" + Uri.encode(getDeviceAndAppInformation())
+ "?subject=" + Uri.encode(getString(R.string.msg_android_app_support)) +
+ "&body=" + Uri.encode(getDeviceAndAppInformation())
with(Intent(Intent.ACTION_SENDTO)) {
data = uriText.toUri()
@@ -142,7 +181,79 @@ class SettingsFragment : Fragment(), SettingsView, AdapterView.OnItemClickListen
}
}
- companion object {
- fun newInstance() = SettingsFragment()
+ private fun changeLanguage() {
+ context?.let {
+ val selectedLocale = presenter.getCurrentLocale(it)
+ var localeIndex = -1
+ locales.forEachIndexed { index, locale ->
+ val array = locale.split(",")
+ val language = array[0]
+ val country = if (array.size > 1) array[1] else ""
+ // If language and country are specified, return the respective locale, else return
+ // the first locale found if the language is as specified regardless of the country.
+ if (language == selectedLocale.language) {
+ if (country == selectedLocale.country) {
+ localeIndex = index
+ return@forEachIndexed
+ } else if (localeIndex == -1) {
+ localeIndex = index
+ }
+ }
+ }
+ AlertDialog.Builder(it)
+ .setTitle(R.string.title_choose_language)
+ .setSingleChoiceItems(
+ resources.getStringArray(R.array.languages), localeIndex
+ ) { dialog, option ->
+ val array = locales[option].split(",")
+ if (array.size > 1) {
+ updateLanguage(array[0], array[1])
+ } else {
+ updateLanguage(array[0])
+ }
+ dialog.dismiss()
+ }
+ .create()
+ .show()
+ }
+ }
+
+ private fun showAppOnStore() {
+ try {
+ startActivity(Intent(Intent.ACTION_VIEW, getString(R.string.market_link).toUri()))
+ } catch (error: ActivityNotFoundException) {
+ startActivity(Intent(Intent.ACTION_VIEW, getString(R.string.play_store_link).toUri()))
+ }
+ }
+
+ private fun shareApp() {
+ with(Intent(Intent.ACTION_SEND)) {
+ type = "text/plain"
+ putExtra(Intent.EXTRA_SUBJECT, getString(R.string.msg_check_this_out))
+ putExtra(Intent.EXTRA_TEXT, getString(R.string.play_store_link))
+ startActivity(Intent.createChooser(this, getString(R.string.msg_share_using)))
+ }
+ }
+
+ private fun showLogoutDialog() {
+ context?.let {
+ val builder = AlertDialog.Builder(it)
+ builder.setTitle(R.string.title_are_you_sure)
+ .setPositiveButton(R.string.action_logout) { _, _ -> presenter.logout() }
+ .setNegativeButton(android.R.string.no) { dialog, _ -> dialog.cancel() }
+ .create()
+ .show()
+ }
+ }
+
+ private fun showDeleteAccountDialog() {
+ context?.let {
+ AlertDialog.Builder(it)
+ .setView(LayoutInflater.from(it).inflate(R.layout.dialog_delete_account, null))
+ .setPositiveButton(R.string.msg_delete_account) { _, _ ->
+ presenter.deleteAccount(EditText(context).text.toString())
+ }.setNegativeButton(android.R.string.no) { dialog, _ -> dialog.cancel() }.create()
+ .show()
+ }
}
-}
+}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/sortingandgrouping/di/SortingAndGroupingBottomSheetFragmentModule.kt b/app/src/main/java/chat/rocket/android/sortingandgrouping/di/SortingAndGroupingBottomSheetFragmentModule.kt
new file mode 100644
index 0000000000..fced1df63e
--- /dev/null
+++ b/app/src/main/java/chat/rocket/android/sortingandgrouping/di/SortingAndGroupingBottomSheetFragmentModule.kt
@@ -0,0 +1,16 @@
+package chat.rocket.android.sortingandgrouping.di
+
+import chat.rocket.android.dagger.scope.PerFragment
+import chat.rocket.android.sortingandgrouping.presentation.SortingAndGroupingView
+import chat.rocket.android.sortingandgrouping.ui.SortingAndGroupingBottomSheetFragment
+import dagger.Module
+import dagger.Provides
+
+@Module
+class SortingAndGroupingBottomSheetFragmentModule {
+
+ @Provides
+ @PerFragment
+ fun sortingAndGroupingView(frag: SortingAndGroupingBottomSheetFragment): SortingAndGroupingView =
+ frag
+}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/sortingandgrouping/di/SortingAndGroupingBottomSheetFragmentProvider.kt b/app/src/main/java/chat/rocket/android/sortingandgrouping/di/SortingAndGroupingBottomSheetFragmentProvider.kt
new file mode 100644
index 0000000000..783812cef3
--- /dev/null
+++ b/app/src/main/java/chat/rocket/android/sortingandgrouping/di/SortingAndGroupingBottomSheetFragmentProvider.kt
@@ -0,0 +1,15 @@
+package chat.rocket.android.sortingandgrouping.di
+
+import chat.rocket.android.dagger.scope.PerFragment
+import chat.rocket.android.sortingandgrouping.ui.SortingAndGroupingBottomSheetFragment
+import dagger.Module
+import dagger.android.ContributesAndroidInjector
+
+@Module
+abstract class SortingAndGroupingBottomSheetFragmentProvider {
+
+ @ContributesAndroidInjector(modules = [SortingAndGroupingBottomSheetFragmentModule::class])
+ @PerFragment
+ abstract fun provideSortingAndGroupingBottomSheetFragment(): SortingAndGroupingBottomSheetFragment
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/sortingandgrouping/presentation/SortingAndGroupingPresenter.kt b/app/src/main/java/chat/rocket/android/sortingandgrouping/presentation/SortingAndGroupingPresenter.kt
new file mode 100644
index 0000000000..1dadf303b8
--- /dev/null
+++ b/app/src/main/java/chat/rocket/android/sortingandgrouping/presentation/SortingAndGroupingPresenter.kt
@@ -0,0 +1,38 @@
+package chat.rocket.android.sortingandgrouping.presentation
+
+import chat.rocket.android.server.domain.SortingAndGroupingInteractor
+import javax.inject.Inject
+import javax.inject.Named
+
+class SortingAndGroupingPresenter @Inject constructor(
+ private val view: SortingAndGroupingView,
+ private val sortingAndGroupingInteractor: SortingAndGroupingInteractor,
+ @Named("currentServer") private val currentServerUrl: String
+) {
+
+ fun getSortingAndGroupingPreferences() {
+ with(sortingAndGroupingInteractor) {
+ view.showSortingAndGroupingPreferences(
+ getSortByName(currentServerUrl),
+ getUnreadOnTop(currentServerUrl),
+ getGroupByType(currentServerUrl),
+ getGroupByFavorites(currentServerUrl)
+ )
+ }
+ }
+
+ fun saveSortingAndGroupingPreferences(
+ isSortByName: Boolean,
+ isUnreadOnTop: Boolean,
+ isGroupByType: Boolean,
+ isGroupByFavorites: Boolean
+ ) {
+ sortingAndGroupingInteractor.save(
+ currentServerUrl,
+ isSortByName,
+ isUnreadOnTop,
+ isGroupByType,
+ isGroupByFavorites
+ )
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/sortingandgrouping/presentation/SortingAndGroupingView.kt b/app/src/main/java/chat/rocket/android/sortingandgrouping/presentation/SortingAndGroupingView.kt
new file mode 100644
index 0000000000..c8627e22e7
--- /dev/null
+++ b/app/src/main/java/chat/rocket/android/sortingandgrouping/presentation/SortingAndGroupingView.kt
@@ -0,0 +1,19 @@
+package chat.rocket.android.sortingandgrouping.presentation
+
+interface SortingAndGroupingView {
+
+ /**
+ * Shows the sorting and grouping preferences for the current logged in server.
+ *
+ * @param isSortByName True if sorting by name, false otherwise.
+ * @param isUnreadOnTop True if grouping by unread on top, false otherwise.
+ * @param isGroupByType True if grouping by type , false otherwise.
+ * @param isGroupByFavorites True if grouping by favorites, false otherwise.
+ */
+ fun showSortingAndGroupingPreferences(
+ isSortByName: Boolean,
+ isUnreadOnTop: Boolean,
+ isGroupByType: Boolean,
+ isGroupByFavorites: Boolean
+ )
+}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/sortingandgrouping/ui/SortingAndGroupingBottomSheetFragment.kt b/app/src/main/java/chat/rocket/android/sortingandgrouping/ui/SortingAndGroupingBottomSheetFragment.kt
new file mode 100644
index 0000000000..4ab319310f
--- /dev/null
+++ b/app/src/main/java/chat/rocket/android/sortingandgrouping/ui/SortingAndGroupingBottomSheetFragment.kt
@@ -0,0 +1,173 @@
+package chat.rocket.android.sortingandgrouping.ui
+
+import DrawableHelper
+import android.content.DialogInterface
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.TextView
+import androidx.annotation.DrawableRes
+import chat.rocket.android.R
+import chat.rocket.android.chatrooms.ui.ChatRoomsFragment
+import chat.rocket.android.chatrooms.ui.TAG_CHAT_ROOMS_FRAGMENT
+import chat.rocket.android.sortingandgrouping.presentation.SortingAndGroupingPresenter
+import chat.rocket.android.sortingandgrouping.presentation.SortingAndGroupingView
+import com.google.android.material.bottomsheet.BottomSheetDialogFragment
+import dagger.android.support.AndroidSupportInjection
+import kotlinx.android.synthetic.main.bottom_sheet_fragment_sort_by.*
+import javax.inject.Inject
+
+const val TAG = "SortingAndGroupingBottomSheetFragment"
+
+class SortingAndGroupingBottomSheetFragment : BottomSheetDialogFragment(), SortingAndGroupingView {
+ @Inject
+ lateinit var presenter: SortingAndGroupingPresenter
+ private var isSortByName = false
+ private var isUnreadOnTop = false
+ private var isGroupByType = false
+ private var isGroupByFavorites = false
+ private val chatRoomFragment by lazy {
+ activity?.supportFragmentManager?.findFragmentByTag(TAG_CHAT_ROOMS_FRAGMENT) as ChatRoomsFragment
+ }
+ private val filterDrawable by lazy { R.drawable.ic_filter_20dp }
+ private val activityDrawable by lazy { R.drawable.ic_activity_20dp }
+ private val unreadOnTopDrawable by lazy { R.drawable.ic_unread_20dp }
+ private val groupByTypeDrawable by lazy { R.drawable.ic_group_by_type_20dp }
+ private val groupByFavoritesDrawable by lazy { R.drawable.ic_favorites_20dp }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ AndroidSupportInjection.inject(this)
+ }
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? =
+ inflater.inflate(R.layout.bottom_sheet_fragment_sort_by, container, false)
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ presenter.getSortingAndGroupingPreferences()
+ setupListeners()
+ }
+
+ override fun onCancel(dialog: DialogInterface?) {
+ super.onCancel(dialog)
+ presenter.saveSortingAndGroupingPreferences(
+ isSortByName,
+ isUnreadOnTop,
+ isGroupByType,
+ isGroupByFavorites
+ )
+ }
+
+ override fun showSortingAndGroupingPreferences(
+ isSortByName: Boolean,
+ isUnreadOnTop: Boolean,
+ isGroupByType: Boolean,
+ isGroupByFavorites: Boolean
+ ) {
+ this.isSortByName = isSortByName
+ this.isUnreadOnTop = isUnreadOnTop
+ this.isGroupByType = isGroupByType
+ this.isGroupByFavorites = isGroupByFavorites
+
+ if (isSortByName) {
+ changeSortByTitle(getString(R.string.msg_sort_by_name))
+ checkSelection(text_name, filterDrawable)
+ } else {
+ changeSortByTitle(getString(R.string.msg_sort_by_activity))
+ checkSelection(text_activity, activityDrawable)
+ }
+
+ if (isUnreadOnTop) checkSelection(text_unread_on_top, unreadOnTopDrawable)
+ if (isGroupByType) checkSelection(text_group_by_type, groupByTypeDrawable)
+ if (isGroupByFavorites) checkSelection(text_group_by_favorites, groupByFavoritesDrawable)
+ }
+
+ private fun setupListeners() {
+ text_name.setOnClickListener {
+ changeSortByTitle(getString(R.string.msg_sort_by_name))
+ checkSelection(text_name, filterDrawable)
+ uncheckSelection(text_activity, activityDrawable)
+ isSortByName = true
+ sortChatRoomsList()
+ }
+
+ text_activity.setOnClickListener {
+ changeSortByTitle(getString(R.string.msg_sort_by_activity))
+ checkSelection(text_activity, activityDrawable)
+ uncheckSelection(text_name, filterDrawable)
+ isSortByName = false
+ sortChatRoomsList()
+ }
+
+ text_unread_on_top.setOnClickListener {
+ isUnreadOnTop = if (isUnreadOnTop) {
+ uncheckSelection(text_unread_on_top, unreadOnTopDrawable)
+ false
+ } else {
+ checkSelection(text_unread_on_top, unreadOnTopDrawable)
+ true
+ }
+ sortChatRoomsList()
+ }
+
+ text_group_by_type.setOnClickListener {
+ isGroupByType = if (isGroupByType) {
+ uncheckSelection(text_group_by_type, groupByTypeDrawable)
+ false
+ } else {
+ checkSelection(text_group_by_type, groupByTypeDrawable)
+ true
+ }
+ sortChatRoomsList()
+ }
+
+ text_group_by_favorites.setOnClickListener {
+ isGroupByFavorites = if (isGroupByFavorites) {
+ uncheckSelection(text_group_by_favorites, groupByFavoritesDrawable)
+ false
+ } else {
+ checkSelection(text_group_by_favorites, groupByFavoritesDrawable)
+ true
+ }
+ sortChatRoomsList()
+ }
+ }
+
+ private fun changeSortByTitle(text: String) {
+ text_sort_by.text = getString(R.string.msg_sort_by_placeholder, text.toLowerCase())
+ }
+
+ private fun checkSelection(textView: TextView, @DrawableRes startDrawable: Int) {
+ context?.let {
+ DrawableHelper.compoundStartAndEndDrawable(
+ textView,
+ DrawableHelper.getDrawableFromId(startDrawable, it),
+ DrawableHelper.getDrawableFromId(R.drawable.ic_check, it)
+ )
+ }
+ }
+
+ private fun uncheckSelection(textView: TextView, @DrawableRes startDrawable: Int) {
+ context?.let {
+ DrawableHelper.compoundStartDrawable(
+ textView,
+ DrawableHelper.getDrawableFromId(startDrawable, it)
+ )
+ }
+ }
+
+ private fun sortChatRoomsList() {
+ chatRoomFragment.sortChatRoomsList(
+ isSortByName,
+ isUnreadOnTop,
+ isGroupByType,
+ isGroupByFavorites
+ )
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/chat/rocket/android/userdetails/presentation/UserDetailsPresenter.kt b/app/src/main/java/chat/rocket/android/userdetails/presentation/UserDetailsPresenter.kt
index c6aa059b4b..48d2776739 100644
--- a/app/src/main/java/chat/rocket/android/userdetails/presentation/UserDetailsPresenter.kt
+++ b/app/src/main/java/chat/rocket/android/userdetails/presentation/UserDetailsPresenter.kt
@@ -8,12 +8,14 @@ import chat.rocket.android.db.model.ChatRoomEntity
import chat.rocket.android.db.model.UserEntity
import chat.rocket.android.server.domain.CurrentServerRepository
import chat.rocket.android.server.domain.GetSettingsInteractor
+import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.domain.isJitsiEnabled
-import chat.rocket.android.server.infraestructure.ConnectionManagerFactory
+import chat.rocket.android.server.infrastructure.ConnectionManagerFactory
import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.android.util.retryIO
import chat.rocket.common.model.RoomType
+import chat.rocket.common.model.Token
import chat.rocket.common.util.ifNull
import chat.rocket.core.internal.rest.createDirectMessage
import kotlinx.coroutines.Dispatchers
@@ -26,6 +28,7 @@ class UserDetailsPresenter @Inject constructor(
private val dbManager: DatabaseManager,
private val strategy: CancelStrategy,
private val navigator: ChatRoomNavigator,
+ tokenRepository: TokenRepository,
settingsInteractor: GetSettingsInteractor,
serverInteractor: CurrentServerRepository,
factory: ConnectionManagerFactory
@@ -35,6 +38,7 @@ class UserDetailsPresenter @Inject constructor(
private val client = manager.client
private val interactor = FetchChatRoomsInteractor(client, dbManager)
private val settings = settingsInteractor.get(currentServer)
+ private val token = tokenRepository.get(currentServer)
private lateinit var userEntity: UserEntity
fun loadUserDetails(userId: String) {
@@ -43,25 +47,21 @@ class UserDetailsPresenter @Inject constructor(
view.showLoading()
dbManager.getUser(userId)?.let {
userEntity = it
- val avatarUrl =
- userEntity.username?.let { username -> currentServer.avatarUrl(avatar = username) }
+ val avatarUrl = userEntity.username?.let { username ->
+ currentServer.avatarUrl(username, token?.userId, token?.authToken)
+ }
val username = userEntity.username
val name = userEntity.name
- val utcOffset =
- userEntity.utcOffset // TODO Convert UTC and display like the mockup
+ val utcOffset = userEntity.utcOffset // FIXME Convert UTC
- if (avatarUrl != null && username != null && name != null && utcOffset != null) {
- view.showUserDetailsAndActions(
- avatarUrl = avatarUrl,
- name = name,
- username = username,
- status = userEntity.status,
- utcOffset = utcOffset.toString(),
- isVideoCallAllowed = settings.isJitsiEnabled()
- )
- } else {
- throw Exception()
- }
+ view.showUserDetailsAndActions(
+ avatarUrl = avatarUrl,
+ name = name,
+ username = username,
+ status = userEntity.status,
+ utcOffset = utcOffset.toString(),
+ isVideoCallAllowed = settings.isJitsiEnabled()
+ )
}
} catch (ex: Exception) {
Timber.e(ex)
@@ -89,6 +89,7 @@ class UserDetailsPresenter @Inject constructor(
val chatRoomEntity = ChatRoomEntity(
id = directMessage.id,
name = userEntity.username ?: userEntity.name.orEmpty(),
+ parentId = null,
description = null,
type = RoomType.DIRECT_MESSAGE,
fullname = userEntity.name,
diff --git a/app/src/main/java/chat/rocket/android/userdetails/presentation/UserDetailsView.kt b/app/src/main/java/chat/rocket/android/userdetails/presentation/UserDetailsView.kt
index a1cb70b6b7..aa8187abec 100644
--- a/app/src/main/java/chat/rocket/android/userdetails/presentation/UserDetailsView.kt
+++ b/app/src/main/java/chat/rocket/android/userdetails/presentation/UserDetailsView.kt
@@ -16,11 +16,11 @@ interface UserDetailsView : LoadingView, MessageView {
* @param isVideoCallAllowed True if the video call is allowed, false otherwise.
*/
fun showUserDetailsAndActions(
- avatarUrl: String,
- name: String,
- username: String,
- status: String,
- utcOffset: String,
+ avatarUrl: String?,
+ name: String?,
+ username: String?,
+ status: String?,
+ utcOffset: String?,
isVideoCallAllowed: Boolean
)
}
diff --git a/app/src/main/java/chat/rocket/android/userdetails/ui/UserDetailsFragment.kt b/app/src/main/java/chat/rocket/android/userdetails/ui/UserDetailsFragment.kt
index 7ec9463449..bfd829b88a 100644
--- a/app/src/main/java/chat/rocket/android/userdetails/ui/UserDetailsFragment.kt
+++ b/app/src/main/java/chat/rocket/android/userdetails/ui/UserDetailsFragment.kt
@@ -20,6 +20,7 @@ import chat.rocket.android.util.extensions.showToast
import chat.rocket.android.util.extensions.ui
import com.bumptech.glide.Glide
import com.bumptech.glide.load.MultiTransformation
+import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.load.resource.bitmap.CenterCrop
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
import com.bumptech.glide.request.RequestOptions
@@ -78,14 +79,17 @@ class UserDetailsFragment : Fragment(), UserDetailsView {
}
override fun showUserDetailsAndActions(
- avatarUrl: String,
- name: String,
- username: String,
- status: String,
- utcOffset: String,
+ avatarUrl: String?,
+ name: String?,
+ username: String?,
+ status: String?,
+ utcOffset: String?,
isVideoCallAllowed: Boolean
) {
- val requestBuilder = Glide.with(this).load(avatarUrl)
+ val requestBuilder = Glide.with(this)
+ .load(avatarUrl)
+ .apply(RequestOptions.skipMemoryCacheOf(true))
+ .apply(RequestOptions.diskCacheStrategyOf(DiskCacheStrategy.NONE))
requestBuilder.apply(
RequestOptions.bitmapTransform(MultiTransformation(BlurTransformation(), CenterCrop()))
@@ -94,19 +98,21 @@ class UserDetailsFragment : Fragment(), UserDetailsView {
requestBuilder.apply(RequestOptions.bitmapTransform(RoundedCorners(14)))
.into(image_avatar)
- text_name.text = name
- text_username.text = username
- text_description_status.text = status.substring(0, 1).toUpperCase() + status.substring(1)
- text_description_timezone.text = utcOffset
+ text_name.text = name ?: getString(R.string.msg_unknown)
+ text_username.text = username ?: getString(R.string.msg_unknown)
- // We should also setup the user details listeners.
- text_message.setOnClickListener { presenter.createDirectMessage(username) }
+ text_description_status.text = status?.capitalize() ?: getString(R.string.msg_unknown)
+
+ text_description_timezone.text = utcOffset ?: getString(R.string.msg_unknown)
+
+ text_video_call.isVisible = isVideoCallAllowed
- if (isVideoCallAllowed) {
- text_video_call.isVisible = true
- text_video_call.setOnClickListener { presenter.toVideoConference(username) }
- } else {
- text_video_call.isVisible = false
+ // We should also setup the user details listeners.
+ username?.run {
+ text_message.setOnClickListener { presenter.createDirectMessage(this) }
+ if (isVideoCallAllowed) {
+ text_video_call.setOnClickListener { presenter.toVideoConference(this) }
+ }
}
}
@@ -147,4 +153,4 @@ class UserDetailsFragment : Fragment(), UserDetailsView {
private fun setupListeners() {
image_arrow_back.setOnClickListener { activity?.onBackPressed() }
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/chat/rocket/android/util/extensions/RocketChatClient.kt b/app/src/main/java/chat/rocket/android/util/extensions/RocketChatClient.kt
index 41ba306134..69654be5e8 100644
--- a/app/src/main/java/chat/rocket/android/util/extensions/RocketChatClient.kt
+++ b/app/src/main/java/chat/rocket/android/util/extensions/RocketChatClient.kt
@@ -2,7 +2,7 @@ package chat.rocket.android.util.extensions
import chat.rocket.android.db.model.MessageEntity
import chat.rocket.android.server.domain.model.Account
-import chat.rocket.android.server.infraestructure.RocketChatClientFactory
+import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.util.retryIO
import chat.rocket.core.internal.rest.registerPushToken
import chat.rocket.core.model.Message
@@ -19,7 +19,7 @@ suspend fun RocketChatClientFactory.registerPushToken(
accounts.forEach { account ->
try {
retryIO(description = "register push token: ${account.serverUrl}") {
- create(account.serverUrl).registerPushToken(token)
+ get(account.serverUrl).registerPushToken(token)
}
} catch (ex: Exception) {
Timber.d(ex, "Error registering Push token for ${account.serverUrl}")
diff --git a/app/src/main/java/chat/rocket/android/util/extensions/String.kt b/app/src/main/java/chat/rocket/android/util/extensions/String.kt
index 9c950da7f8..78b2d9c846 100644
--- a/app/src/main/java/chat/rocket/android/util/extensions/String.kt
+++ b/app/src/main/java/chat/rocket/android/util/extensions/String.kt
@@ -21,13 +21,15 @@ fun String.sanitize(): String {
fun String.avatarUrl(
avatar: String,
+ userId: String?,
+ token: String?,
isGroupOrChannel: Boolean = false,
format: String = "jpeg"
): String {
return if (isGroupOrChannel) {
- "${removeTrailingSlash()}/avatar/%23${avatar.removeTrailingSlash()}?format=$format"
+ "${removeTrailingSlash()}/avatar/%23${avatar.removeTrailingSlash()}?format=$format&rc_uid=$userId&rc_token=$token"
} else {
- "${removeTrailingSlash()}/avatar/${avatar.removeTrailingSlash()}?format=$format"
+ "${removeTrailingSlash()}/avatar/${avatar.removeTrailingSlash()}?format=$format&rc_uid=$userId&rc_token=$token"
}
}
@@ -75,6 +77,8 @@ fun String.lowercaseUrl(): String? = HttpUrl.parse(this)?.run {
fun String?.isNotNullNorEmpty(): Boolean = this != null && this.isNotEmpty()
+fun String?.isNotNullNorBlank(): Boolean = this != null && this.isNotBlank()
+
inline fun String?.ifNotNullNotEmpty(block: (String) -> Unit) {
if (this != null && this.isNotEmpty()) {
block(this)
diff --git a/app/src/main/java/chat/rocket/android/videoconference/presenter/VideoConferencePresenter.kt b/app/src/main/java/chat/rocket/android/videoconference/presenter/VideoConferencePresenter.kt
index ce9233f651..b9d8aecfb5 100644
--- a/app/src/main/java/chat/rocket/android/videoconference/presenter/VideoConferencePresenter.kt
+++ b/app/src/main/java/chat/rocket/android/videoconference/presenter/VideoConferencePresenter.kt
@@ -6,7 +6,7 @@ import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.helper.JitsiHelper
import chat.rocket.android.helper.UserHelper
import chat.rocket.android.server.domain.*
-import chat.rocket.android.server.infraestructure.ConnectionManagerFactory
+import chat.rocket.android.server.infrastructure.ConnectionManagerFactory
import chat.rocket.android.util.extension.launchUI
import chat.rocket.common.model.RoomType
import chat.rocket.common.model.roomTypeOf
diff --git a/app/src/main/java/chat/rocket/android/videoconference/ui/VideoConferenceActivity.kt b/app/src/main/java/chat/rocket/android/videoconference/ui/VideoConferenceActivity.kt
index 6fed291e94..94e9a5704b 100644
--- a/app/src/main/java/chat/rocket/android/videoconference/ui/VideoConferenceActivity.kt
+++ b/app/src/main/java/chat/rocket/android/videoconference/ui/VideoConferenceActivity.kt
@@ -3,14 +3,15 @@ package chat.rocket.android.videoconference.ui
import android.content.Context
import android.content.Intent
import android.os.Bundle
-import androidx.core.os.bundleOf
import chat.rocket.android.videoconference.presenter.JitsiVideoConferenceView
import chat.rocket.android.videoconference.presenter.VideoConferencePresenter
import dagger.android.AndroidInjection
import org.jitsi.meet.sdk.JitsiMeetActivity
+import org.jitsi.meet.sdk.JitsiMeetConferenceOptions
import org.jitsi.meet.sdk.JitsiMeetView
import org.jitsi.meet.sdk.JitsiMeetViewListener
import timber.log.Timber
+import java.net.URL
import javax.inject.Inject
fun Context.videoConferenceIntent(chatRoomId: String, chatRoomType: String): Intent =
@@ -23,8 +24,7 @@ private const val INTENT_CHAT_ROOM_TYPE = "chat_room_type"
class VideoConferenceActivity : JitsiMeetActivity(), JitsiVideoConferenceView,
JitsiMeetViewListener {
- @Inject
- lateinit var presenter: VideoConferencePresenter
+ @Inject lateinit var presenter: VideoConferencePresenter
private lateinit var chatRoomId: String
private lateinit var chatRoomType: String
private var view: JitsiMeetView? = null
@@ -34,9 +34,7 @@ class VideoConferenceActivity : JitsiMeetActivity(), JitsiVideoConferenceView,
super.onCreate(savedInstanceState)
chatRoomId = intent.getStringExtra(INTENT_CHAT_ROOM_ID)
- requireNotNull(chatRoomId) { "no chat_room_id provided in Intent extras" }
chatRoomType = intent.getStringExtra(INTENT_CHAT_ROOM_TYPE)
- requireNotNull(chatRoomType) { "no chat_room_type provided in Intent extras" }
view = JitsiMeetView(this)
view?.listener = this
@@ -52,34 +50,24 @@ class VideoConferenceActivity : JitsiMeetActivity(), JitsiVideoConferenceView,
override fun onConferenceJoined(map: MutableMap?) =
logJitsiMeetViewState("Joined video conferencing", map)
- override fun onConferenceWillLeave(map: MutableMap?) =
- logJitsiMeetViewState("Leaving video conferencing", map)
-
- override fun onConferenceLeft(map: MutableMap?) {
- logJitsiMeetViewState("Left video conferencing", map)
+ override fun onConferenceTerminated(map: MutableMap?) {
+ map?.let {
+ if (it.containsKey("error")) {
+ logJitsiMeetViewState("Terminated video conferencing with error", map)
+ } else {
+ logJitsiMeetViewState("Terminated video conferencing", map)
+ }
+ }
finishJitsiVideoConference()
}
- override fun onLoadConfigError(map: MutableMap?) =
- logJitsiMeetViewState("Error loading video conference config", map)
-
- override fun onConferenceFailed(map: MutableMap?) =
- logJitsiMeetViewState("Video conference failed", map)
-
override fun startJitsiVideoConference(url: String, name: String?) {
- view?.loadURLObject(
- bundleOf(
- "config" to bundleOf(
- "startWithAudioMuted" to true,
- "startWithVideoMuted" to true
- ),
- "context" to bundleOf(
- "user" to bundleOf("name" to name),
- "iss" to "rocketchat-android"
- ),
- "url" to url
- )
- )
+ JitsiMeetConferenceOptions.Builder()
+ .setAudioMuted(true)
+ .setVideoMuted(true)
+ .setServerURL(URL(url))
+ .setAudioOnly(false)
+ .build().let { view?.join(it) }
}
override fun finishJitsiVideoConference() {
diff --git a/app/src/main/java/chat/rocket/android/webview/adminpanel/ui/AdminPanelWebViewFragment.kt b/app/src/main/java/chat/rocket/android/webview/adminpanel/ui/AdminPanelWebViewFragment.kt
index 268182fd7f..a94408177b 100644
--- a/app/src/main/java/chat/rocket/android/webview/adminpanel/ui/AdminPanelWebViewFragment.kt
+++ b/app/src/main/java/chat/rocket/android/webview/adminpanel/ui/AdminPanelWebViewFragment.kt
@@ -16,9 +16,17 @@ import dagger.android.support.DaggerFragment
import kotlinx.android.synthetic.main.fragment_admin_panel_web_view.*
import javax.inject.Inject
+internal const val TAG_ADMIN_PANEL_WEB_VIEW_FRAGMENT = "AdminPanelWebViewFragment"
private const val BUNDLE_WEB_PAGE_URL = "web_page_url"
private const val BUNDLE_USER_TOKEN = "user_token"
+fun newInstance(webPageUrl: String, userToken: String) = AdminPanelWebViewFragment().apply {
+ arguments = Bundle(2).apply {
+ putString(BUNDLE_WEB_PAGE_URL, webPageUrl)
+ putString(BUNDLE_USER_TOKEN, userToken)
+ }
+}
+
class AdminPanelWebViewFragment : DaggerFragment() {
private lateinit var webPageUrl: String
private lateinit var userToken: String
@@ -30,7 +38,8 @@ class AdminPanelWebViewFragment : DaggerFragment() {
arguments?.run {
webPageUrl = getString(BUNDLE_WEB_PAGE_URL, "")
userToken = getString(BUNDLE_USER_TOKEN, "")
- } ?: requireNotNull(arguments) { "no arguments supplied when the fragment was instantiated" }
+ }
+ ?: requireNotNull(arguments) { "no arguments supplied when the fragment was instantiated" }
}
override fun onCreateView(
@@ -49,7 +58,7 @@ class AdminPanelWebViewFragment : DaggerFragment() {
private fun setupToolbar() {
(activity as AppCompatActivity?)?.supportActionBar?.title =
- getString(R.string.title_admin_panel)
+ getString(R.string.title_admin_panel)
}
@SuppressLint("SetJavaScriptEnabled")
@@ -70,13 +79,4 @@ class AdminPanelWebViewFragment : DaggerFragment() {
}
web_view.loadUrl(webPageUrl)
}
-
- companion object {
- fun newInstance(webPageUrl: String, userToken: String) = AdminPanelWebViewFragment().apply {
- arguments = Bundle(2).apply {
- putString(BUNDLE_WEB_PAGE_URL, webPageUrl)
- putString(BUNDLE_USER_TOKEN, userToken)
- }
- }
- }
}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/bg_empty_user_avatar.xml b/app/src/main/res/drawable/bg_empty_user_avatar.xml
index 280bebb878..722144a73c 100644
--- a/app/src/main/res/drawable/bg_empty_user_avatar.xml
+++ b/app/src/main/res/drawable/bg_empty_user_avatar.xml
@@ -1,6 +1,15 @@
-
-
-
-
+
+
+
+
diff --git a/app/src/main/res/drawable/black_gradient.xml b/app/src/main/res/drawable/black_gradient.xml
deleted file mode 100644
index 98a5ebacf1..0000000000
--- a/app/src/main/res/drawable/black_gradient.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_action_message_info_outline_24dp.xml b/app/src/main/res/drawable/ic_action_message_info_outline_24dp.xml
index 45176fb957..91752eab05 100644
--- a/app/src/main/res/drawable/ic_action_message_info_outline_24dp.xml
+++ b/app/src/main/res/drawable/ic_action_message_info_outline_24dp.xml
@@ -1,7 +1,6 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_add_new_server_48dp.xml b/app/src/main/res/drawable/ic_add_new_server_48dp.xml
new file mode 100644
index 0000000000..8bf08b2bcb
--- /dev/null
+++ b/app/src/main/res/drawable/ic_add_new_server_48dp.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_app_name.xml b/app/src/main/res/drawable/ic_app_name.xml
index 803fc4452f..8fb8062f8c 100644
--- a/app/src/main/res/drawable/ic_app_name.xml
+++ b/app/src/main/res/drawable/ic_app_name.xml
@@ -1,14 +1,14 @@
+ android:width="832.0dp"
+ android:height="220.0dp"
+ android:viewportWidth="832.0"
+ android:viewportHeight="220.0">
+ android:translateY="220"
+ android:scaleX="0.1"
+ android:scaleY="-0.1">
diff --git a/app/src/main/res/drawable/ic_arrow_down.xml b/app/src/main/res/drawable/ic_arrow_down.xml
new file mode 100644
index 0000000000..c55b3be976
--- /dev/null
+++ b/app/src/main/res/drawable/ic_arrow_down.xml
@@ -0,0 +1,13 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_arrow_expand_20dp.xml b/app/src/main/res/drawable/ic_arrow_expand_20dp.xml
new file mode 100644
index 0000000000..b2a9234093
--- /dev/null
+++ b/app/src/main/res/drawable/ic_arrow_expand_20dp.xml
@@ -0,0 +1,13 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_camera.xml b/app/src/main/res/drawable/ic_camera.xml
deleted file mode 100644
index a37ceaf6ce..0000000000
--- a/app/src/main/res/drawable/ic_camera.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_camera_24dp.xml b/app/src/main/res/drawable/ic_camera_24dp.xml
new file mode 100644
index 0000000000..9f80789f6c
--- /dev/null
+++ b/app/src/main/res/drawable/ic_camera_24dp.xml
@@ -0,0 +1,12 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_chat_bubble_black_24dp.xml b/app/src/main/res/drawable/ic_chat_bubble_black_24dp.xml
deleted file mode 100644
index 3eeab8286d..0000000000
--- a/app/src/main/res/drawable/ic_chat_bubble_black_24dp.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/ic_check.xml b/app/src/main/res/drawable/ic_check.xml
new file mode 100644
index 0000000000..6046365a41
--- /dev/null
+++ b/app/src/main/res/drawable/ic_check.xml
@@ -0,0 +1,13 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_check_read_24dp.xml b/app/src/main/res/drawable/ic_check_read_24dp.xml
index 9855900a9b..76cd1135df 100644
--- a/app/src/main/res/drawable/ic_check_read_24dp.xml
+++ b/app/src/main/res/drawable/ic_check_read_24dp.xml
@@ -1,9 +1,9 @@
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
diff --git a/app/src/main/res/drawable/ic_check_unread_24dp.xml b/app/src/main/res/drawable/ic_check_unread_24dp.xml
index ccafe1c835..31bb59746c 100644
--- a/app/src/main/res/drawable/ic_check_unread_24dp.xml
+++ b/app/src/main/res/drawable/ic_check_unread_24dp.xml
@@ -1,7 +1,6 @@
-
-
diff --git a/app/src/main/res/drawable/ic_directory_48dp.xml b/app/src/main/res/drawable/ic_directory_48dp.xml
new file mode 100644
index 0000000000..07649a1dfa
--- /dev/null
+++ b/app/src/main/res/drawable/ic_directory_48dp.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_discussion_20dp.xml b/app/src/main/res/drawable/ic_discussion_20dp.xml
new file mode 100644
index 0000000000..2e41ab6867
--- /dev/null
+++ b/app/src/main/res/drawable/ic_discussion_20dp.xml
@@ -0,0 +1,13 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_favorites_20dp.xml b/app/src/main/res/drawable/ic_favorites_20dp.xml
new file mode 100644
index 0000000000..94c6c62039
--- /dev/null
+++ b/app/src/main/res/drawable/ic_favorites_20dp.xml
@@ -0,0 +1,13 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_filter_20dp.xml b/app/src/main/res/drawable/ic_filter_20dp.xml
new file mode 100644
index 0000000000..f92bb571b1
--- /dev/null
+++ b/app/src/main/res/drawable/ic_filter_20dp.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_group_by_type_20dp.xml b/app/src/main/res/drawable/ic_group_by_type_20dp.xml
new file mode 100644
index 0000000000..5cc3e55cbd
--- /dev/null
+++ b/app/src/main/res/drawable/ic_group_by_type_20dp.xml
@@ -0,0 +1,13 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_hashtag_16dp.xml b/app/src/main/res/drawable/ic_hashtag_16dp.xml
new file mode 100644
index 0000000000..db18661f34
--- /dev/null
+++ b/app/src/main/res/drawable/ic_hashtag_16dp.xml
@@ -0,0 +1,12 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_lock_12_dp.xml b/app/src/main/res/drawable/ic_lock_12_dp.xml
index 277c4c2206..ddebe566d4 100644
--- a/app/src/main/res/drawable/ic_lock_12_dp.xml
+++ b/app/src/main/res/drawable/ic_lock_12_dp.xml
@@ -3,14 +3,14 @@
android:height="12dp"
android:viewportWidth="12"
android:viewportHeight="12">
-
-
+
+
diff --git a/app/src/main/res/drawable/ic_logout_black_24dp.xml b/app/src/main/res/drawable/ic_logout_black_24dp.xml
deleted file mode 100644
index 30b1d97fa2..0000000000
--- a/app/src/main/res/drawable/ic_logout_black_24dp.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
diff --git a/app/src/main/res/drawable/ic_menu_white_24dp.xml b/app/src/main/res/drawable/ic_menu_white_24dp.xml
deleted file mode 100644
index cf37e2a393..0000000000
--- a/app/src/main/res/drawable/ic_menu_white_24dp.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/ic_navigation_24dp.xml b/app/src/main/res/drawable/ic_navigation_24dp.xml
new file mode 100644
index 0000000000..d8a8df3ac0
--- /dev/null
+++ b/app/src/main/res/drawable/ic_navigation_24dp.xml
@@ -0,0 +1,13 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_new_channel_24dp.xml b/app/src/main/res/drawable/ic_new_channel_24dp.xml
new file mode 100644
index 0000000000..cecbac4add
--- /dev/null
+++ b/app/src/main/res/drawable/ic_new_channel_24dp.xml
@@ -0,0 +1,13 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_send_24dp.xml b/app/src/main/res/drawable/ic_send_24dp.xml
index c8f25312b3..ab820d67a6 100644
--- a/app/src/main/res/drawable/ic_send_24dp.xml
+++ b/app/src/main/res/drawable/ic_send_24dp.xml
@@ -1,12 +1,12 @@
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_settings_black_24dp.xml b/app/src/main/res/drawable/ic_settings_black_24dp.xml
deleted file mode 100644
index ace746c40e..0000000000
--- a/app/src/main/res/drawable/ic_settings_black_24dp.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/ic_sort.xml b/app/src/main/res/drawable/ic_sort.xml
deleted file mode 100644
index 8f4129ed2a..0000000000
--- a/app/src/main/res/drawable/ic_sort.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/ic_unread_20dp.xml b/app/src/main/res/drawable/ic_unread_20dp.xml
new file mode 100644
index 0000000000..0bd793ec9d
--- /dev/null
+++ b/app/src/main/res/drawable/ic_unread_20dp.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_user_16dp.xml b/app/src/main/res/drawable/ic_user_16dp.xml
new file mode 100644
index 0000000000..e5be22cc64
--- /dev/null
+++ b/app/src/main/res/drawable/ic_user_16dp.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/image_dummy.xml b/app/src/main/res/drawable/image_dummy.xml
index 6eba190b78..ec0767e390 100644
--- a/app/src/main/res/drawable/image_dummy.xml
+++ b/app/src/main/res/drawable/image_dummy.xml
@@ -1,16 +1,16 @@
+ android:width="80dp"
+ android:height="45dp"
+ android:viewportWidth="80.0"
+ android:viewportHeight="45.0">
+ android:pathData="M0,0h80v45h-80z"
+ android:strokeColor="#00000000"
+ android:fillColor="#C3D1DA"
+ android:strokeWidth="1" />
+ android:pathData="M43.99,16.75C44.34,16.75 44.64,16.87 44.88,17.12C45.13,17.36 45.25,17.66 45.25,18.01L45.25,26.74C45.25,27.09 45.13,27.39 44.88,27.63C44.64,27.88 44.34,28 43.99,28L35.26,28C34.91,28 34.61,27.88 34.37,27.63C34.12,27.39 34,27.09 34,26.74L34,18.01C34,17.66 34.12,17.36 34.37,17.12C34.61,16.87 34.91,16.75 35.26,16.75L43.99,16.75ZM43.99,26.74L43.99,18.01L35.26,18.01L35.26,26.74L43.99,26.74ZM40.86,22.55L43.05,25.51L36.2,25.51L37.9,23.28L39.13,24.78L40.86,22.55Z"
+ android:strokeColor="#00000000"
+ android:fillColor="#5D8298"
+ android:strokeWidth="1" />
diff --git a/app/src/main/res/drawable/message_reply_button_bg.xml b/app/src/main/res/drawable/message_reply_button_bg.xml
index eda4b8f2bc..85a9bdb663 100644
--- a/app/src/main/res/drawable/message_reply_button_bg.xml
+++ b/app/src/main/res/drawable/message_reply_button_bg.xml
@@ -6,5 +6,7 @@
-
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/round_textview.xml b/app/src/main/res/drawable/round_textview.xml
index 2d5ad4a47c..f5f6c954de 100644
--- a/app/src/main/res/drawable/round_textview.xml
+++ b/app/src/main/res/drawable/round_textview.xml
@@ -1,10 +1,10 @@
-
+
-
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_add_members.xml b/app/src/main/res/layout/activity_add_members.xml
deleted file mode 100644
index 8cbeb10293..0000000000
--- a/app/src/main/res/layout/activity_add_members.xml
+++ /dev/null
@@ -1,82 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index c4dcd5eb30..d308f2af2f 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -1,48 +1,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+ tools:context=".main.ui.MainActivity" />
\ No newline at end of file
diff --git a/app/src/main/res/layout/app_bar.xml b/app/src/main/res/layout/app_bar.xml
index e0fff9af70..87845b60de 100644
--- a/app/src/main/res/layout/app_bar.xml
+++ b/app/src/main/res/layout/app_bar.xml
@@ -3,13 +3,13 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:background="@color/colorPrimary">
+ android:background="@color/colorPrimary"
+ android:theme="@style/Theme.AppCompat.Light.NoActionBar">
diff --git a/app/src/main/res/layout/app_bar_chat_rooms.xml b/app/src/main/res/layout/app_bar_chat_rooms.xml
new file mode 100644
index 0000000000..cc1317b32e
--- /dev/null
+++ b/app/src/main/res/layout/app_bar_chat_rooms.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/app_bar_password.xml b/app/src/main/res/layout/app_bar_password.xml
index 79b4de1cdf..8db44bba59 100644
--- a/app/src/main/res/layout/app_bar_password.xml
+++ b/app/src/main/res/layout/app_bar_password.xml
@@ -15,9 +15,11 @@
app:navigationIcon="?android:attr/homeAsUpIndicator"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:theme="@style/ActionModeStyle">
+
+
+ app:roundedCornerRadius="4dp" />
\ No newline at end of file
diff --git a/app/src/main/res/layout/bottom_sheet_fragment_directory_sorting.xml b/app/src/main/res/layout/bottom_sheet_fragment_directory_sorting.xml
new file mode 100644
index 0000000000..215b7cd1b3
--- /dev/null
+++ b/app/src/main/res/layout/bottom_sheet_fragment_directory_sorting.xml
@@ -0,0 +1,111 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/bottom_sheet_fragment_servers.xml b/app/src/main/res/layout/bottom_sheet_fragment_servers.xml
new file mode 100644
index 0000000000..e8ecff5af5
--- /dev/null
+++ b/app/src/main/res/layout/bottom_sheet_fragment_servers.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/bottom_sheet_fragment_sort_by.xml b/app/src/main/res/layout/bottom_sheet_fragment_sort_by.xml
new file mode 100644
index 0000000000..409ab42ae1
--- /dev/null
+++ b/app/src/main/res/layout/bottom_sheet_fragment_sort_by.xml
@@ -0,0 +1,109 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/chatroom_sort_dialog.xml b/app/src/main/res/layout/chatroom_sort_dialog.xml
deleted file mode 100644
index fc85aa8b79..0000000000
--- a/app/src/main/res/layout/chatroom_sort_dialog.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_account_delete.xml b/app/src/main/res/layout/dialog_delete_account.xml
similarity index 95%
rename from app/src/main/res/layout/item_account_delete.xml
rename to app/src/main/res/layout/dialog_delete_account.xml
index 9dafc0d9e8..2c60f9a6fc 100644
--- a/app/src/main/res/layout/item_account_delete.xml
+++ b/app/src/main/res/layout/dialog_delete_account.xml
@@ -1,7 +1,6 @@
diff --git a/app/src/main/res/layout/dialog_report.xml b/app/src/main/res/layout/dialog_report.xml
deleted file mode 100644
index c0ce689a98..0000000000
--- a/app/src/main/res/layout/dialog_report.xml
+++ /dev/null
@@ -1,129 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 1
-
-
diff --git a/app/src/main/res/layout/dialog_status.xml b/app/src/main/res/layout/dialog_status.xml
new file mode 100644
index 0000000000..03405d7f28
--- /dev/null
+++ b/app/src/main/res/layout/dialog_status.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/emoji_image_row_item.xml b/app/src/main/res/layout/emoji_image_row_item.xml
index 5aca146ac1..2fffc659a0 100644
--- a/app/src/main/res/layout/emoji_image_row_item.xml
+++ b/app/src/main/res/layout/emoji_image_row_item.xml
@@ -1,14 +1,9 @@
-
-
-
-
+ android:layout_gravity="center"
+ android:padding="8dp"
+ tools:src="@tools:sample/avatars" />
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_about.xml b/app/src/main/res/layout/fragment_about.xml
deleted file mode 100644
index 701020f089..0000000000
--- a/app/src/main/res/layout/fragment_about.xml
+++ /dev/null
@@ -1,62 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_authentication_log_in.xml b/app/src/main/res/layout/fragment_authentication_log_in.xml
index beb090c3ce..1af5755e61 100644
--- a/app/src/main/res/layout/fragment_authentication_log_in.xml
+++ b/app/src/main/res/layout/fragment_authentication_log_in.xml
@@ -54,7 +54,7 @@
android:id="@+id/button_forgot_your_password"
style="@style/Authentication.Button.Borderless"
android:layout_marginTop="10dp"
- android:text="@string/msg_forgot__your_password"
+ android:text="@string/msg_forgot_your_password"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
diff --git a/app/src/main/res/layout/fragment_authentication_on_boarding.xml b/app/src/main/res/layout/fragment_authentication_on_boarding.xml
index 5f609450ca..4cf9ab4697 100644
--- a/app/src/main/res/layout/fragment_authentication_on_boarding.xml
+++ b/app/src/main/res/layout/fragment_authentication_on_boarding.xml
@@ -25,6 +25,7 @@
android:id="@+id/text_on_boarding_title"
style="@style/Authentication.TextView.Headline"
android:layout_marginTop="32dp"
+ android:gravity="center"
android:text="@string/msg_welcome_to_rocket_chat"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
@@ -33,6 +34,7 @@
+ android:drawableStart="@drawable/ic_hashtag_black_12dp"
+ android:drawablePadding="@dimen/text_view_drawable_padding"
+ tools:text="important" />
-
-
-
-
+
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/layout_app_bar_chat_room" />
+ android:layout_height="42dp"
+ android:background="#54585E"
+ android:drawableEnd="@drawable/ic_group_by_type_20dp"
+ android:fontFamily="sans-serif-medium"
+ android:gravity="center_vertical"
+ android:paddingStart="@dimen/screen_edge_left_and_right_margins"
+ android:paddingEnd="@dimen/screen_edge_left_and_right_margins"
+ android:text="@string/msg_sort_by_placeholder"
+ android:textColor="#CBCED1"
+ android:textSize="14sp"
+ android:textStyle="normal"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/text_directory" />
-
+
+
-
+
+
diff --git a/app/src/main/res/layout/fragment_create_channel.xml b/app/src/main/res/layout/fragment_create_channel.xml
index 69097aa000..7e7249e9e8 100644
--- a/app/src/main/res/layout/fragment_create_channel.xml
+++ b/app/src/main/res/layout/fragment_create_channel.xml
@@ -4,10 +4,13 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_margin="16dp"
- android:focusableInTouchMode="true"
tools:context="createchannel.ui.CreateChannelFragment">
+
+
+ app:layout_constraintTop_toBottomOf="@+id/layout_app_bar" />
@@ -53,6 +60,8 @@
android:id="@+id/text_read_only"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_marginStart="16dp"
+
android:layout_marginTop="16dp"
android:text="@string/msg_ready_only_channel"
android:textColor="@color/colorPrimaryText"
@@ -64,6 +73,8 @@
android:id="@+id/text_read_only_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+
+ android:layout_marginStart="16dp"
android:text="@string/msg_ready_only_channel_description"
android:textColor="@color/colorSecondaryText"
android:textSize="12sp"
@@ -74,6 +85,8 @@
android:id="@+id/switch_read_only"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_marginEnd="16dp"
+
app:layout_constraintBottom_toBottomOf="@+id/text_read_only_description"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/text_read_only" />
@@ -81,7 +94,9 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_preferences.xml b/app/src/main/res/layout/fragment_preferences.xml
deleted file mode 100644
index df859fb237..0000000000
--- a/app/src/main/res/layout/fragment_preferences.xml
+++ /dev/null
@@ -1,52 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_profile.xml b/app/src/main/res/layout/fragment_profile.xml
index 9877aec9ec..70ba755078 100644
--- a/app/src/main/res/layout/fragment_profile.xml
+++ b/app/src/main/res/layout/fragment_profile.xml
@@ -8,9 +8,15 @@
android:focusableInTouchMode="true"
tools:context=".profile.ui.ProfileFragment">
+
+
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/layout_app_bar">
+
+
+
+
+
+
+
+
+
-
-
+
+
-
+ android:layout_height="0dp"
+ android:layout_below="@+id/layout_app_bar"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/layout_app_bar">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_user_details.xml b/app/src/main/res/layout/fragment_user_details.xml
index 8f78b7142e..5234df1d6c 100644
--- a/app/src/main/res/layout/fragment_user_details.xml
+++ b/app/src/main/res/layout/fragment_user_details.xml
@@ -95,7 +95,7 @@
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/screen_edge_left_and_right_margins"
android:layout_marginTop="20dp"
- android:text="@string/status"
+ android:text="@string/user_detail_status"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text_message" />
@@ -143,6 +143,6 @@
android:id="@+id/group_user_details"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- app:constraint_referenced_ids="image_blur, image_avatar, text_name, text_username, text_message, text_title_status, text_description_status, text_title_timezone, text_description_timezone" />
+ app:constraint_referenced_ids="image_blur, image_avatar, text_name, text_username, text_message, text_title_status, text_description_status, text_title_timezone, text_description_timezone, text_video_call" />
diff --git a/app/src/main/res/layout/item_account.xml b/app/src/main/res/layout/item_account.xml
deleted file mode 100644
index ed902d21a3..0000000000
--- a/app/src/main/res/layout/item_account.xml
+++ /dev/null
@@ -1,46 +0,0 @@
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_actions_attachment.xml b/app/src/main/res/layout/item_actions_attachment.xml
index be85d47aad..ecac02e795 100644
--- a/app/src/main/res/layout/item_actions_attachment.xml
+++ b/app/src/main/res/layout/item_actions_attachment.xml
@@ -24,7 +24,7 @@
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
- tools:text="This is a multiline chat message from Bertie that will take more than just one line of text. I have sure that everything is amazing!" />
+ tools:text="This is a multiline chat message from Bertie that will take more than just one line of text. I have made sure that everything is amazing!" />
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_add_new_server.xml b/app/src/main/res/layout/item_add_new_server.xml
new file mode 100644
index 0000000000..de8f1cf10b
--- /dev/null
+++ b/app/src/main/res/layout/item_add_new_server.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_change_status.xml b/app/src/main/res/layout/item_change_status.xml
deleted file mode 100644
index b7bf77079b..0000000000
--- a/app/src/main/res/layout/item_change_status.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_chat.xml b/app/src/main/res/layout/item_chat.xml
index febbd65fe6..541fcf66c3 100644
--- a/app/src/main/res/layout/item_chat.xml
+++ b/app/src/main/res/layout/item_chat.xml
@@ -8,21 +8,22 @@
android:paddingStart="@dimen/screen_edge_left_and_right_padding"
android:paddingTop="@dimen/chat_item_top_and_bottom_padding"
android:paddingEnd="@dimen/screen_edge_left_and_right_padding"
- android:paddingBottom="@dimen/chat_item_top_and_bottom_padding">
+ android:paddingBottom="@dimen/chat_item_top_and_bottom_padding"
+ tools:context=".chatrooms.adapter.RoomsAdapter">
-
+ tools:src="@tools:sample/avatars" />
+ tools:text="Filipe de Lima Brito: Type something that is very long and need at least two lines, or maybe even more" />
diff --git a/app/src/main/res/layout/item_chatroom_header.xml b/app/src/main/res/layout/item_chatroom_header.xml
index 7cdcc4f53d..3324ad081c 100644
--- a/app/src/main/res/layout/item_chatroom_header.xml
+++ b/app/src/main/res/layout/item_chatroom_header.xml
@@ -10,8 +10,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
- android:paddingEnd="@dimen/screen_edge_left_and_right_padding"
android:paddingStart="@dimen/screen_edge_left_and_right_padding"
- android:text="@string/chatroom_header" />
+ android:paddingEnd="@dimen/screen_edge_left_and_right_padding" />
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_directory_channel.xml b/app/src/main/res/layout/item_directory_channel.xml
new file mode 100644
index 0000000000..940f482635
--- /dev/null
+++ b/app/src/main/res/layout/item_directory_channel.xml
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_directory_user.xml b/app/src/main/res/layout/item_directory_user.xml
new file mode 100644
index 0000000000..7f73ec4cbc
--- /dev/null
+++ b/app/src/main/res/layout/item_directory_user.xml
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_message.xml b/app/src/main/res/layout/item_message.xml
index 9f1e708032..c9632ed562 100644
--- a/app/src/main/res/layout/item_message.xml
+++ b/app/src/main/res/layout/item_message.xml
@@ -156,7 +156,7 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/message_header"
app:layout_constraintTop_toBottomOf="@+id/message_header"
- tools:text="This is a multiline chat message from Bertie that will take more than just one line of text. I have sure that everything is amazing!" />
+ tools:text="This is a multiline chat message from Bertie that will take more than just one line of text. I have made sure that everything is amazing!" />