mirror of
https://github.com/nextcloud/talk-android
synced 2025-06-19 11:39:42 +01:00
Merge pull request #4846 from nextcloud/event_conversations
Event conversations
This commit is contained in:
commit
52f58372b8
@ -0,0 +1,719 @@
|
|||||||
|
{
|
||||||
|
"formatVersion": 1,
|
||||||
|
"database": {
|
||||||
|
"version": 14,
|
||||||
|
"identityHash": "506abc931eb3b657cafe6ad1b25f635d",
|
||||||
|
"entities": [
|
||||||
|
{
|
||||||
|
"tableName": "User",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `userId` TEXT, `username` TEXT, `baseUrl` TEXT, `token` TEXT, `displayName` TEXT, `pushConfigurationState` TEXT, `capabilities` TEXT, `serverVersion` TEXT DEFAULT '', `clientCertificate` TEXT, `externalSignalingServer` TEXT, `current` INTEGER NOT NULL, `scheduledForDeletion` INTEGER NOT NULL)",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "userId",
|
||||||
|
"columnName": "userId",
|
||||||
|
"affinity": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "username",
|
||||||
|
"columnName": "username",
|
||||||
|
"affinity": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "baseUrl",
|
||||||
|
"columnName": "baseUrl",
|
||||||
|
"affinity": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "token",
|
||||||
|
"columnName": "token",
|
||||||
|
"affinity": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "displayName",
|
||||||
|
"columnName": "displayName",
|
||||||
|
"affinity": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "pushConfigurationState",
|
||||||
|
"columnName": "pushConfigurationState",
|
||||||
|
"affinity": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "capabilities",
|
||||||
|
"columnName": "capabilities",
|
||||||
|
"affinity": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "serverVersion",
|
||||||
|
"columnName": "serverVersion",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"defaultValue": "''"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "clientCertificate",
|
||||||
|
"columnName": "clientCertificate",
|
||||||
|
"affinity": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "externalSignalingServer",
|
||||||
|
"columnName": "externalSignalingServer",
|
||||||
|
"affinity": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "current",
|
||||||
|
"columnName": "current",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "scheduledForDeletion",
|
||||||
|
"columnName": "scheduledForDeletion",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": true,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "ArbitraryStorage",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountIdentifier` INTEGER NOT NULL, `key` TEXT NOT NULL, `object` TEXT, `value` TEXT, PRIMARY KEY(`accountIdentifier`, `key`))",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "accountIdentifier",
|
||||||
|
"columnName": "accountIdentifier",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "key",
|
||||||
|
"columnName": "key",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "storageObject",
|
||||||
|
"columnName": "object",
|
||||||
|
"affinity": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "value",
|
||||||
|
"columnName": "value",
|
||||||
|
"affinity": "TEXT"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"accountIdentifier",
|
||||||
|
"key"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "Conversations",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`internalId` TEXT NOT NULL, `accountId` INTEGER NOT NULL, `token` TEXT NOT NULL, `displayName` TEXT NOT NULL, `actorId` TEXT NOT NULL, `actorType` TEXT NOT NULL, `avatarVersion` TEXT NOT NULL, `callFlag` INTEGER NOT NULL, `callRecording` INTEGER NOT NULL, `callStartTime` INTEGER NOT NULL, `canDeleteConversation` INTEGER NOT NULL, `canLeaveConversation` INTEGER NOT NULL, `canStartCall` INTEGER NOT NULL, `description` TEXT NOT NULL, `hasCall` INTEGER NOT NULL, `hasPassword` INTEGER NOT NULL, `isCustomAvatar` INTEGER NOT NULL, `isFavorite` INTEGER NOT NULL, `lastActivity` INTEGER NOT NULL, `lastCommonReadMessage` INTEGER NOT NULL, `lastMessage` TEXT, `lastPing` INTEGER NOT NULL, `lastReadMessage` INTEGER NOT NULL, `lobbyState` TEXT NOT NULL, `lobbyTimer` INTEGER NOT NULL, `messageExpiration` INTEGER NOT NULL, `name` TEXT NOT NULL, `notificationCalls` INTEGER NOT NULL, `notificationLevel` TEXT NOT NULL, `objectType` TEXT NOT NULL, `objectId` TEXT NOT NULL, `participantType` TEXT NOT NULL, `permissions` INTEGER NOT NULL, `readOnly` TEXT NOT NULL, `recordingConsent` INTEGER NOT NULL, `remoteServer` TEXT, `remoteToken` TEXT, `sessionId` TEXT NOT NULL, `status` TEXT, `statusClearAt` INTEGER, `statusIcon` TEXT, `statusMessage` TEXT, `type` TEXT NOT NULL, `unreadMention` INTEGER NOT NULL, `unreadMentionDirect` INTEGER NOT NULL, `unreadMessages` INTEGER NOT NULL, `hasArchived` INTEGER NOT NULL, PRIMARY KEY(`internalId`), FOREIGN KEY(`accountId`) REFERENCES `User`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "internalId",
|
||||||
|
"columnName": "internalId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "accountId",
|
||||||
|
"columnName": "accountId",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "token",
|
||||||
|
"columnName": "token",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "displayName",
|
||||||
|
"columnName": "displayName",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "actorId",
|
||||||
|
"columnName": "actorId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "actorType",
|
||||||
|
"columnName": "actorType",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "avatarVersion",
|
||||||
|
"columnName": "avatarVersion",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "callFlag",
|
||||||
|
"columnName": "callFlag",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "callRecording",
|
||||||
|
"columnName": "callRecording",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "callStartTime",
|
||||||
|
"columnName": "callStartTime",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "canDeleteConversation",
|
||||||
|
"columnName": "canDeleteConversation",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "canLeaveConversation",
|
||||||
|
"columnName": "canLeaveConversation",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "canStartCall",
|
||||||
|
"columnName": "canStartCall",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "description",
|
||||||
|
"columnName": "description",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "hasCall",
|
||||||
|
"columnName": "hasCall",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "hasPassword",
|
||||||
|
"columnName": "hasPassword",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "hasCustomAvatar",
|
||||||
|
"columnName": "isCustomAvatar",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "favorite",
|
||||||
|
"columnName": "isFavorite",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastActivity",
|
||||||
|
"columnName": "lastActivity",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastCommonReadMessage",
|
||||||
|
"columnName": "lastCommonReadMessage",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastMessage",
|
||||||
|
"columnName": "lastMessage",
|
||||||
|
"affinity": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastPing",
|
||||||
|
"columnName": "lastPing",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastReadMessage",
|
||||||
|
"columnName": "lastReadMessage",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lobbyState",
|
||||||
|
"columnName": "lobbyState",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lobbyTimer",
|
||||||
|
"columnName": "lobbyTimer",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "messageExpiration",
|
||||||
|
"columnName": "messageExpiration",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "name",
|
||||||
|
"columnName": "name",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "notificationCalls",
|
||||||
|
"columnName": "notificationCalls",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "notificationLevel",
|
||||||
|
"columnName": "notificationLevel",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "objectType",
|
||||||
|
"columnName": "objectType",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "objectId",
|
||||||
|
"columnName": "objectId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "participantType",
|
||||||
|
"columnName": "participantType",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "permissions",
|
||||||
|
"columnName": "permissions",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "conversationReadOnlyState",
|
||||||
|
"columnName": "readOnly",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "recordingConsentRequired",
|
||||||
|
"columnName": "recordingConsent",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "remoteServer",
|
||||||
|
"columnName": "remoteServer",
|
||||||
|
"affinity": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "remoteToken",
|
||||||
|
"columnName": "remoteToken",
|
||||||
|
"affinity": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "sessionId",
|
||||||
|
"columnName": "sessionId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "status",
|
||||||
|
"columnName": "status",
|
||||||
|
"affinity": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "statusClearAt",
|
||||||
|
"columnName": "statusClearAt",
|
||||||
|
"affinity": "INTEGER"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "statusIcon",
|
||||||
|
"columnName": "statusIcon",
|
||||||
|
"affinity": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "statusMessage",
|
||||||
|
"columnName": "statusMessage",
|
||||||
|
"affinity": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "type",
|
||||||
|
"columnName": "type",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "unreadMention",
|
||||||
|
"columnName": "unreadMention",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "unreadMentionDirect",
|
||||||
|
"columnName": "unreadMentionDirect",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "unreadMessages",
|
||||||
|
"columnName": "unreadMessages",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "hasArchived",
|
||||||
|
"columnName": "hasArchived",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"internalId"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [
|
||||||
|
{
|
||||||
|
"name": "index_Conversations_accountId",
|
||||||
|
"unique": false,
|
||||||
|
"columnNames": [
|
||||||
|
"accountId"
|
||||||
|
],
|
||||||
|
"orders": [],
|
||||||
|
"createSql": "CREATE INDEX IF NOT EXISTS `index_Conversations_accountId` ON `${TABLE_NAME}` (`accountId`)"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"foreignKeys": [
|
||||||
|
{
|
||||||
|
"table": "User",
|
||||||
|
"onDelete": "CASCADE",
|
||||||
|
"onUpdate": "CASCADE",
|
||||||
|
"columns": [
|
||||||
|
"accountId"
|
||||||
|
],
|
||||||
|
"referencedColumns": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "ChatMessages",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`internalId` TEXT NOT NULL, `accountId` INTEGER NOT NULL, `token` TEXT NOT NULL, `id` INTEGER NOT NULL, `internalConversationId` TEXT NOT NULL, `actorDisplayName` TEXT NOT NULL, `message` TEXT NOT NULL, `actorId` TEXT NOT NULL, `actorType` TEXT NOT NULL, `deleted` INTEGER NOT NULL, `expirationTimestamp` INTEGER NOT NULL, `isReplyable` INTEGER NOT NULL, `isTemporary` INTEGER NOT NULL, `lastEditActorDisplayName` TEXT, `lastEditActorId` TEXT, `lastEditActorType` TEXT, `lastEditTimestamp` INTEGER, `markdown` INTEGER, `messageParameters` TEXT, `messageType` TEXT NOT NULL, `parent` INTEGER, `reactions` TEXT, `reactionsSelf` TEXT, `referenceId` TEXT, `sendingFailed` INTEGER NOT NULL, `silent` INTEGER NOT NULL, `systemMessage` TEXT NOT NULL, `timestamp` INTEGER NOT NULL, PRIMARY KEY(`internalId`), FOREIGN KEY(`internalConversationId`) REFERENCES `Conversations`(`internalId`) ON UPDATE CASCADE ON DELETE CASCADE )",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "internalId",
|
||||||
|
"columnName": "internalId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "accountId",
|
||||||
|
"columnName": "accountId",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "token",
|
||||||
|
"columnName": "token",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "internalConversationId",
|
||||||
|
"columnName": "internalConversationId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "actorDisplayName",
|
||||||
|
"columnName": "actorDisplayName",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "message",
|
||||||
|
"columnName": "message",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "actorId",
|
||||||
|
"columnName": "actorId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "actorType",
|
||||||
|
"columnName": "actorType",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "deleted",
|
||||||
|
"columnName": "deleted",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "expirationTimestamp",
|
||||||
|
"columnName": "expirationTimestamp",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "replyable",
|
||||||
|
"columnName": "isReplyable",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "isTemporary",
|
||||||
|
"columnName": "isTemporary",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastEditActorDisplayName",
|
||||||
|
"columnName": "lastEditActorDisplayName",
|
||||||
|
"affinity": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastEditActorId",
|
||||||
|
"columnName": "lastEditActorId",
|
||||||
|
"affinity": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastEditActorType",
|
||||||
|
"columnName": "lastEditActorType",
|
||||||
|
"affinity": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastEditTimestamp",
|
||||||
|
"columnName": "lastEditTimestamp",
|
||||||
|
"affinity": "INTEGER"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "renderMarkdown",
|
||||||
|
"columnName": "markdown",
|
||||||
|
"affinity": "INTEGER"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "messageParameters",
|
||||||
|
"columnName": "messageParameters",
|
||||||
|
"affinity": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "messageType",
|
||||||
|
"columnName": "messageType",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "parentMessageId",
|
||||||
|
"columnName": "parent",
|
||||||
|
"affinity": "INTEGER"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "reactions",
|
||||||
|
"columnName": "reactions",
|
||||||
|
"affinity": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "reactionsSelf",
|
||||||
|
"columnName": "reactionsSelf",
|
||||||
|
"affinity": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "referenceId",
|
||||||
|
"columnName": "referenceId",
|
||||||
|
"affinity": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "sendingFailed",
|
||||||
|
"columnName": "sendingFailed",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "silent",
|
||||||
|
"columnName": "silent",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "systemMessageType",
|
||||||
|
"columnName": "systemMessage",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "timestamp",
|
||||||
|
"columnName": "timestamp",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"internalId"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [
|
||||||
|
{
|
||||||
|
"name": "index_ChatMessages_internalId",
|
||||||
|
"unique": true,
|
||||||
|
"columnNames": [
|
||||||
|
"internalId"
|
||||||
|
],
|
||||||
|
"orders": [],
|
||||||
|
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_ChatMessages_internalId` ON `${TABLE_NAME}` (`internalId`)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "index_ChatMessages_internalConversationId",
|
||||||
|
"unique": false,
|
||||||
|
"columnNames": [
|
||||||
|
"internalConversationId"
|
||||||
|
],
|
||||||
|
"orders": [],
|
||||||
|
"createSql": "CREATE INDEX IF NOT EXISTS `index_ChatMessages_internalConversationId` ON `${TABLE_NAME}` (`internalConversationId`)"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"foreignKeys": [
|
||||||
|
{
|
||||||
|
"table": "Conversations",
|
||||||
|
"onDelete": "CASCADE",
|
||||||
|
"onUpdate": "CASCADE",
|
||||||
|
"columns": [
|
||||||
|
"internalConversationId"
|
||||||
|
],
|
||||||
|
"referencedColumns": [
|
||||||
|
"internalId"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "ChatBlocks",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `internalConversationId` TEXT NOT NULL, `accountId` INTEGER, `token` TEXT, `oldestMessageId` INTEGER NOT NULL, `newestMessageId` INTEGER NOT NULL, `hasHistory` INTEGER NOT NULL, FOREIGN KEY(`internalConversationId`) REFERENCES `Conversations`(`internalId`) ON UPDATE CASCADE ON DELETE CASCADE )",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "internalConversationId",
|
||||||
|
"columnName": "internalConversationId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "accountId",
|
||||||
|
"columnName": "accountId",
|
||||||
|
"affinity": "INTEGER"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "token",
|
||||||
|
"columnName": "token",
|
||||||
|
"affinity": "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "oldestMessageId",
|
||||||
|
"columnName": "oldestMessageId",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "newestMessageId",
|
||||||
|
"columnName": "newestMessageId",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "hasHistory",
|
||||||
|
"columnName": "hasHistory",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": true,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [
|
||||||
|
{
|
||||||
|
"name": "index_ChatBlocks_internalConversationId",
|
||||||
|
"unique": false,
|
||||||
|
"columnNames": [
|
||||||
|
"internalConversationId"
|
||||||
|
],
|
||||||
|
"orders": [],
|
||||||
|
"createSql": "CREATE INDEX IF NOT EXISTS `index_ChatBlocks_internalConversationId` ON `${TABLE_NAME}` (`internalConversationId`)"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"foreignKeys": [
|
||||||
|
{
|
||||||
|
"table": "Conversations",
|
||||||
|
"onDelete": "CASCADE",
|
||||||
|
"onUpdate": "CASCADE",
|
||||||
|
"columns": [
|
||||||
|
"internalConversationId"
|
||||||
|
],
|
||||||
|
"referencedColumns": [
|
||||||
|
"internalId"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"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, '506abc931eb3b657cafe6ad1b25f635d')"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
@ -215,6 +215,7 @@ class ChatBlocksDaoTest {
|
|||||||
lobbyState = ConversationEnums.LobbyState.LOBBY_STATE_MODERATORS_ONLY,
|
lobbyState = ConversationEnums.LobbyState.LOBBY_STATE_MODERATORS_ONLY,
|
||||||
lobbyTimer = 0,
|
lobbyTimer = 0,
|
||||||
objectType = ConversationEnums.ObjectType.FILE,
|
objectType = ConversationEnums.ObjectType.FILE,
|
||||||
|
objectId = "",
|
||||||
statusIcon = null,
|
statusIcon = null,
|
||||||
description = "",
|
description = "",
|
||||||
displayName = "",
|
displayName = "",
|
||||||
|
@ -211,6 +211,7 @@ class ChatMessagesDaoTest {
|
|||||||
lobbyState = ConversationEnums.LobbyState.LOBBY_STATE_MODERATORS_ONLY,
|
lobbyState = ConversationEnums.LobbyState.LOBBY_STATE_MODERATORS_ONLY,
|
||||||
lobbyTimer = 0,
|
lobbyTimer = 0,
|
||||||
objectType = ConversationEnums.ObjectType.FILE,
|
objectType = ConversationEnums.ObjectType.FILE,
|
||||||
|
objectId = "",
|
||||||
statusIcon = null,
|
statusIcon = null,
|
||||||
description = "",
|
description = "",
|
||||||
displayName = "",
|
displayName = "",
|
||||||
|
@ -38,12 +38,14 @@ import android.view.Gravity
|
|||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
import android.view.animation.AccelerateDecelerateInterpolator
|
import android.view.animation.AccelerateDecelerateInterpolator
|
||||||
import android.widget.AbsListView
|
import android.widget.AbsListView
|
||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import android.widget.PopupMenu
|
import android.widget.PopupMenu
|
||||||
|
import android.widget.PopupWindow
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.activity.OnBackPressedCallback
|
import androidx.activity.OnBackPressedCallback
|
||||||
@ -51,6 +53,7 @@ import androidx.activity.result.ActivityResult
|
|||||||
import androidx.activity.result.ActivityResultLauncher
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
import androidx.activity.result.PickVisualMediaRequest
|
import androidx.activity.result.PickVisualMediaRequest
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.appcompat.view.ContextThemeWrapper
|
import androidx.appcompat.view.ContextThemeWrapper
|
||||||
import androidx.cardview.widget.CardView
|
import androidx.cardview.widget.CardView
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
@ -82,6 +85,7 @@ import coil.request.CachePolicy
|
|||||||
import coil.request.ImageRequest
|
import coil.request.ImageRequest
|
||||||
import coil.target.Target
|
import coil.target.Target
|
||||||
import coil.transform.CircleCropTransformation
|
import coil.transform.CircleCropTransformation
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import com.nextcloud.android.common.ui.color.ColorUtil
|
import com.nextcloud.android.common.ui.color.ColorUtil
|
||||||
import com.nextcloud.android.common.ui.theme.utils.ColorRole
|
import com.nextcloud.android.common.ui.theme.utils.ColorRole
|
||||||
@ -127,6 +131,7 @@ import com.nextcloud.talk.databinding.ActivityChatBinding
|
|||||||
import com.nextcloud.talk.events.UserMentionClickEvent
|
import com.nextcloud.talk.events.UserMentionClickEvent
|
||||||
import com.nextcloud.talk.events.WebSocketCommunicationEvent
|
import com.nextcloud.talk.events.WebSocketCommunicationEvent
|
||||||
import com.nextcloud.talk.extensions.loadAvatarOrImagePreview
|
import com.nextcloud.talk.extensions.loadAvatarOrImagePreview
|
||||||
|
import com.nextcloud.talk.jobs.DeleteConversationWorker
|
||||||
import com.nextcloud.talk.jobs.DownloadFileToCacheWorker
|
import com.nextcloud.talk.jobs.DownloadFileToCacheWorker
|
||||||
import com.nextcloud.talk.jobs.ShareOperationWorker
|
import com.nextcloud.talk.jobs.ShareOperationWorker
|
||||||
import com.nextcloud.talk.jobs.UploadAndShareFilesWorker
|
import com.nextcloud.talk.jobs.UploadAndShareFilesWorker
|
||||||
@ -210,13 +215,18 @@ import java.io.File
|
|||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.net.HttpURLConnection
|
import java.net.HttpURLConnection
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
|
import java.time.Instant
|
||||||
|
import java.time.ZoneId
|
||||||
|
import java.time.ZonedDateTime
|
||||||
|
import java.time.format.DateTimeFormatter
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import java.util.concurrent.ExecutionException
|
import java.util.concurrent.ExecutionException
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlin.collections.set
|
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
import androidx.activity.result.contract.ActivityResultContracts.PickVisualMedia
|
import androidx.activity.result.contract.ActivityResultContracts.PickVisualMedia
|
||||||
|
import com.nextcloud.talk.conversationinfo.viewmodel.ConversationInfoViewModel
|
||||||
|
import com.nextcloud.talk.models.json.participants.Participant
|
||||||
|
|
||||||
@AutoInjector(NextcloudTalkApplication::class)
|
@AutoInjector(NextcloudTalkApplication::class)
|
||||||
class ChatActivity :
|
class ChatActivity :
|
||||||
@ -254,6 +264,8 @@ class ChatActivity :
|
|||||||
lateinit var networkMonitor: NetworkMonitor
|
lateinit var networkMonitor: NetworkMonitor
|
||||||
|
|
||||||
lateinit var chatViewModel: ChatViewModel
|
lateinit var chatViewModel: ChatViewModel
|
||||||
|
|
||||||
|
lateinit var conversationInfoViewModel: ConversationInfoViewModel
|
||||||
lateinit var messageInputViewModel: MessageInputViewModel
|
lateinit var messageInputViewModel: MessageInputViewModel
|
||||||
|
|
||||||
private val startSelectContactForResult = registerForActivityResult(
|
private val startSelectContactForResult = registerForActivityResult(
|
||||||
@ -324,6 +336,7 @@ class ChatActivity :
|
|||||||
|
|
||||||
private var conversationVoiceCallMenuItem: MenuItem? = null
|
private var conversationVoiceCallMenuItem: MenuItem? = null
|
||||||
private var conversationVideoMenuItem: MenuItem? = null
|
private var conversationVideoMenuItem: MenuItem? = null
|
||||||
|
private var eventConversationMenuItem: MenuItem? = null
|
||||||
|
|
||||||
var webSocketInstance: WebSocketInstance? = null
|
var webSocketInstance: WebSocketInstance? = null
|
||||||
var signalingMessageSender: SignalingMessageSender? = null
|
var signalingMessageSender: SignalingMessageSender? = null
|
||||||
@ -418,6 +431,8 @@ class ChatActivity :
|
|||||||
|
|
||||||
chatViewModel = ViewModelProvider(this, viewModelFactory)[ChatViewModel::class.java]
|
chatViewModel = ViewModelProvider(this, viewModelFactory)[ChatViewModel::class.java]
|
||||||
|
|
||||||
|
conversationInfoViewModel = ViewModelProvider(this, viewModelFactory)[ConversationInfoViewModel::class.java]
|
||||||
|
|
||||||
val urlForChatting = ApiUtils.getUrlForChat(chatApiVersion, conversationUser?.baseUrl, roomToken)
|
val urlForChatting = ApiUtils.getUrlForChat(chatApiVersion, conversationUser?.baseUrl, roomToken)
|
||||||
val credentials = ApiUtils.getCredentials(conversationUser!!.username, conversationUser!!.token)
|
val credentials = ApiUtils.getCredentials(conversationUser!!.username, conversationUser!!.token)
|
||||||
chatViewModel.initData(
|
chatViewModel.initData(
|
||||||
@ -567,6 +582,7 @@ class ChatActivity :
|
|||||||
participantPermissions = ParticipantPermissions(spreedCapabilities, currentConversation!!)
|
participantPermissions = ParticipantPermissions(spreedCapabilities, currentConversation!!)
|
||||||
|
|
||||||
invalidateOptionsMenu()
|
invalidateOptionsMenu()
|
||||||
|
isEventConversation()
|
||||||
checkShowCallButtons()
|
checkShowCallButtons()
|
||||||
checkLobbyState()
|
checkLobbyState()
|
||||||
updateRoomTimerHandler()
|
updateRoomTimerHandler()
|
||||||
@ -600,6 +616,7 @@ class ChatActivity :
|
|||||||
loadAvatarForStatusBar()
|
loadAvatarForStatusBar()
|
||||||
setupSwipeToReply()
|
setupSwipeToReply()
|
||||||
setActionBarTitle()
|
setActionBarTitle()
|
||||||
|
isEventConversation()
|
||||||
checkShowCallButtons()
|
checkShowCallButtons()
|
||||||
checkLobbyState()
|
checkLobbyState()
|
||||||
if (currentConversation?.type == ConversationEnums.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL &&
|
if (currentConversation?.type == ConversationEnums.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL &&
|
||||||
@ -1889,6 +1906,17 @@ class ChatActivity :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun isEventConversation() {
|
||||||
|
if (currentConversation?.objectType == ConversationEnums.ObjectType.EVENT) {
|
||||||
|
if (eventConversationMenuItem != null) {
|
||||||
|
eventConversationMenuItem?.icon?.alpha = FULLY_OPAQUE_INT
|
||||||
|
eventConversationMenuItem?.isEnabled = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
eventConversationMenuItem?.isEnabled = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun isReadOnlyConversation(): Boolean =
|
private fun isReadOnlyConversation(): Boolean =
|
||||||
currentConversation?.conversationReadOnlyState != null &&
|
currentConversation?.conversationReadOnlyState != null &&
|
||||||
currentConversation?.conversationReadOnlyState ==
|
currentConversation?.conversationReadOnlyState ==
|
||||||
@ -2849,12 +2877,19 @@ class ChatActivity :
|
|||||||
super.onCreateOptionsMenu(menu)
|
super.onCreateOptionsMenu(menu)
|
||||||
menuInflater.inflate(R.menu.menu_conversation, menu)
|
menuInflater.inflate(R.menu.menu_conversation, menu)
|
||||||
|
|
||||||
|
if (currentConversation?.objectType == ConversationEnums.ObjectType.EVENT) {
|
||||||
|
eventConversationMenuItem = menu.findItem(R.id.conversation_event)
|
||||||
|
} else {
|
||||||
|
menu.removeItem(R.id.conversation_event)
|
||||||
|
}
|
||||||
|
|
||||||
if (conversationUser?.userId == "?") {
|
if (conversationUser?.userId == "?") {
|
||||||
menu.removeItem(R.id.conversation_info)
|
menu.removeItem(R.id.conversation_info)
|
||||||
} else {
|
} else {
|
||||||
loadAvatarForStatusBar()
|
loadAvatarForStatusBar()
|
||||||
setActionBarTitle()
|
setActionBarTitle()
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2871,12 +2906,6 @@ class ChatActivity :
|
|||||||
searchItem.isVisible = CapabilitiesUtil.isUnifiedSearchAvailable(spreedCapabilities) &&
|
searchItem.isVisible = CapabilitiesUtil.isUnifiedSearchAvailable(spreedCapabilities) &&
|
||||||
currentConversation!!.remoteServer.isNullOrEmpty()
|
currentConversation!!.remoteServer.isNullOrEmpty()
|
||||||
|
|
||||||
if (currentConversation!!.remoteServer != null ||
|
|
||||||
!CapabilitiesUtil.isSharedItemsAvailable(spreedCapabilities)
|
|
||||||
) {
|
|
||||||
menu.removeItem(R.id.shared_items)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CapabilitiesUtil.isAbleToCall(spreedCapabilities)) {
|
if (CapabilitiesUtil.isAbleToCall(spreedCapabilities)) {
|
||||||
conversationVoiceCallMenuItem = menu.findItem(R.id.conversation_voice_call)
|
conversationVoiceCallMenuItem = menu.findItem(R.id.conversation_voice_call)
|
||||||
conversationVideoMenuItem = menu.findItem(R.id.conversation_video_call)
|
conversationVideoMenuItem = menu.findItem(R.id.conversation_video_call)
|
||||||
@ -2909,7 +2938,6 @@ class ChatActivity :
|
|||||||
menu.removeItem(R.id.conversation_voice_call)
|
menu.removeItem(R.id.conversation_voice_call)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2940,9 +2968,205 @@ class ChatActivity :
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
R.id.conversation_event -> {
|
||||||
|
val anchorView = findViewById<View>(R.id.conversation_event)
|
||||||
|
showPopupWindow(anchorView)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
else -> super.onOptionsItemSelected(item)
|
else -> super.onOptionsItemSelected(item)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun showPopupWindow(anchorView: View) {
|
||||||
|
val popupView = layoutInflater.inflate(R.layout.item_event_schedule, null)
|
||||||
|
|
||||||
|
val titleTextView = popupView.findViewById<TextView>(R.id.event_scheduled)
|
||||||
|
val subtitleTextView = popupView.findViewById<TextView>(R.id.meetingTime)
|
||||||
|
|
||||||
|
val popupWindow = PopupWindow(
|
||||||
|
popupView,
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
|
||||||
|
popupWindow.isOutsideTouchable = true
|
||||||
|
popupWindow.isFocusable = true
|
||||||
|
popupWindow.showAsDropDown(anchorView, 0, -anchorView.height)
|
||||||
|
|
||||||
|
val meetingStatus = showEventSchedule()
|
||||||
|
subtitleTextView.text = meetingStatus
|
||||||
|
|
||||||
|
deleteEventConversation(meetingStatus, popupWindow, popupView)
|
||||||
|
archiveEventConversation(meetingStatus, popupWindow, popupView)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun deleteEventConversation(meetingStatus: String, popupWindow: PopupWindow, popupView: View) {
|
||||||
|
val deleteConversation = popupView.findViewById<TextView>(R.id.delete_conversation)
|
||||||
|
if (meetingStatus == context.resources.getString(R.string.nc_meeting_ended) &&
|
||||||
|
currentConversation?.canDeleteConversation == true
|
||||||
|
) {
|
||||||
|
deleteConversation.visibility = View.VISIBLE
|
||||||
|
|
||||||
|
deleteConversation.setOnClickListener {
|
||||||
|
val dialogBuilder = MaterialAlertDialogBuilder(it.context)
|
||||||
|
.setIcon(
|
||||||
|
viewThemeUtils.dialog
|
||||||
|
.colorMaterialAlertDialogIcon(context, R.drawable.ic_delete_black_24dp)
|
||||||
|
)
|
||||||
|
.setTitle(R.string.nc_delete_call)
|
||||||
|
.setMessage(R.string.nc_delete_conversation_more)
|
||||||
|
.setPositiveButton(R.string.nc_delete) { _, _ ->
|
||||||
|
currentConversation?.let { conversation ->
|
||||||
|
deleteConversation(conversation)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.setNegativeButton(R.string.nc_cancel) { _, _ ->
|
||||||
|
}
|
||||||
|
|
||||||
|
viewThemeUtils.dialog
|
||||||
|
.colorMaterialAlertDialogBackground(it.context, dialogBuilder)
|
||||||
|
val dialog = dialogBuilder.show()
|
||||||
|
viewThemeUtils.platform.colorTextButtons(
|
||||||
|
dialog.getButton(AlertDialog.BUTTON_POSITIVE),
|
||||||
|
dialog.getButton(AlertDialog.BUTTON_NEGATIVE)
|
||||||
|
)
|
||||||
|
popupWindow.dismiss()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
deleteConversation.visibility = View.GONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun archiveEventConversation(meetingStatus: String, popupWindow: PopupWindow, popupView: View) {
|
||||||
|
val archiveConversation = popupView.findViewById<TextView>(R.id.archive_conversation)
|
||||||
|
val unarchiveConversation = popupView.findViewById<TextView>(R.id.unarchive_conversation)
|
||||||
|
if (meetingStatus == context.resources.getString(R.string.nc_meeting_ended) &&
|
||||||
|
(
|
||||||
|
Participant.ParticipantType.MODERATOR == currentConversation?.participantType ||
|
||||||
|
Participant.ParticipantType.OWNER == currentConversation?.participantType
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
if (currentConversation?.hasArchived == false) {
|
||||||
|
unarchiveConversation.visibility = View.GONE
|
||||||
|
archiveConversation.visibility = View.VISIBLE
|
||||||
|
archiveConversation.setOnClickListener {
|
||||||
|
this.lifecycleScope.launch {
|
||||||
|
conversationInfoViewModel.archiveConversation(conversationUser!!, currentConversation?.token!!)
|
||||||
|
Snackbar.make(
|
||||||
|
binding.root,
|
||||||
|
String.format(
|
||||||
|
context.resources.getString(R.string.archived_conversation),
|
||||||
|
currentConversation?.displayName
|
||||||
|
),
|
||||||
|
Snackbar.LENGTH_LONG
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
popupWindow.dismiss()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unarchiveConversation.visibility = View.VISIBLE
|
||||||
|
archiveConversation.visibility = View.GONE
|
||||||
|
unarchiveConversation.setOnClickListener {
|
||||||
|
this.lifecycleScope.launch {
|
||||||
|
conversationInfoViewModel.unarchiveConversation(
|
||||||
|
conversationUser!!,
|
||||||
|
currentConversation?.token!!
|
||||||
|
)
|
||||||
|
Snackbar.make(
|
||||||
|
binding.root,
|
||||||
|
String.format(
|
||||||
|
context.resources.getString(R.string.unarchived_conversation),
|
||||||
|
currentConversation?.displayName
|
||||||
|
),
|
||||||
|
Snackbar.LENGTH_LONG
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
popupWindow.dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
archiveConversation.visibility = View.GONE
|
||||||
|
unarchiveConversation.visibility = View.GONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun deleteConversation(conversation: ConversationModel) {
|
||||||
|
val data = Data.Builder()
|
||||||
|
data.putLong(
|
||||||
|
KEY_INTERNAL_USER_ID,
|
||||||
|
conversationUser?.id!!
|
||||||
|
)
|
||||||
|
data.putString(KEY_ROOM_TOKEN, conversation.token)
|
||||||
|
|
||||||
|
val deleteConversationWorker =
|
||||||
|
OneTimeWorkRequest.Builder(DeleteConversationWorker::class.java).setInputData(data.build()).build()
|
||||||
|
WorkManager.getInstance().enqueue(deleteConversationWorker)
|
||||||
|
|
||||||
|
WorkManager.getInstance(context).getWorkInfoByIdLiveData(deleteConversationWorker.id)
|
||||||
|
.observeForever { workInfo: WorkInfo? ->
|
||||||
|
if (workInfo != null) {
|
||||||
|
when (workInfo.state) {
|
||||||
|
WorkInfo.State.SUCCEEDED -> {
|
||||||
|
val successMessage = String.format(
|
||||||
|
context.resources.getString(R.string.deleted_conversation),
|
||||||
|
conversation.displayName
|
||||||
|
)
|
||||||
|
Snackbar.make(binding.root, successMessage, Snackbar.LENGTH_LONG).show()
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
WorkInfo.State.FAILED -> {
|
||||||
|
val errorMessage = context.resources.getString(R.string.nc_common_error_sorry)
|
||||||
|
Snackbar.make(binding.root, errorMessage, Snackbar.LENGTH_LONG).show()
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showEventSchedule(): String {
|
||||||
|
val meetingTimeStamp = currentConversation?.objectId ?: ""
|
||||||
|
val status = getMeetingSchedule(meetingTimeStamp)
|
||||||
|
return status
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getMeetingSchedule(meetingTimeStamp: String): String {
|
||||||
|
val timestamps = meetingTimeStamp.split("#")
|
||||||
|
if (timestamps.size != 2) return context.resources.getString(R.string.nc_invalid_time)
|
||||||
|
|
||||||
|
val startEpoch = timestamps[ZERO_INDEX].toLong()
|
||||||
|
val endEpoch = timestamps[ONE_INDEX].toLong()
|
||||||
|
|
||||||
|
val startDateTime = Instant.ofEpochSecond(startEpoch).atZone(ZoneId.systemDefault())
|
||||||
|
val endDateTime = Instant.ofEpochSecond(endEpoch).atZone(ZoneId.systemDefault())
|
||||||
|
val currentTime = ZonedDateTime.now(ZoneId.systemDefault())
|
||||||
|
|
||||||
|
return when {
|
||||||
|
currentTime.isBefore(startDateTime) -> {
|
||||||
|
val isToday = startDateTime.toLocalDate().isEqual(currentTime.toLocalDate())
|
||||||
|
val isTomorrow = startDateTime.toLocalDate().isEqual(currentTime.toLocalDate().plusDays(1))
|
||||||
|
when {
|
||||||
|
isToday -> String.format(
|
||||||
|
context.resources.getString(R.string.nc_today_meeting),
|
||||||
|
startDateTime.format(DateTimeFormatter.ofPattern("HH:mm"))
|
||||||
|
)
|
||||||
|
|
||||||
|
isTomorrow -> String.format(
|
||||||
|
context.resources.getString(R.string.nc_tomorrow_meeting),
|
||||||
|
startDateTime.format(DateTimeFormatter.ofPattern("HH:mm"))
|
||||||
|
)
|
||||||
|
else -> startDateTime.format(DateTimeFormatter.ofPattern("MMM d, yyyy, HH:mm"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
currentTime.isAfter(endDateTime) -> context.resources.getString(R.string.nc_meeting_ended)
|
||||||
|
else -> context.resources.getString(R.string.nc_ongoing_meeting)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun showSharedItems() {
|
private fun showSharedItems() {
|
||||||
val intent = Intent(this, SharedItemsActivity::class.java)
|
val intent = Intent(this, SharedItemsActivity::class.java)
|
||||||
intent.putExtra(KEY_CONVERSATION_NAME, currentConversation?.displayName)
|
intent.putExtra(KEY_CONVERSATION_NAME, currentConversation?.displayName)
|
||||||
@ -3800,5 +4024,7 @@ class ChatActivity :
|
|||||||
const val VOICE_MESSAGE_PLAY_ADD_THRESHOLD = 0.1
|
const val VOICE_MESSAGE_PLAY_ADD_THRESHOLD = 0.1
|
||||||
const val VOICE_MESSAGE_MARK_PLAYED_FACTOR = 20
|
const val VOICE_MESSAGE_MARK_PLAYED_FACTOR = 20
|
||||||
const val OUT_OF_OFFICE_ALPHA = 76
|
const val OUT_OF_OFFICE_ALPHA = 76
|
||||||
|
const val ZERO_INDEX = 0
|
||||||
|
const val ONE_INDEX = 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -185,6 +185,11 @@ class ConversationInfoEditActivity : BaseActivity() {
|
|||||||
binding.conversationDescription.isEnabled = false
|
binding.conversationDescription.isEnabled = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (conversation?.objectType == ConversationEnums.ObjectType.EVENT) {
|
||||||
|
binding.conversationName.isEnabled = false
|
||||||
|
binding.conversationDescription.isEnabled = false
|
||||||
|
}
|
||||||
|
|
||||||
loadConversationAvatar()
|
loadConversationAvatar()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -271,7 +276,9 @@ class ConversationInfoEditActivity : BaseActivity() {
|
|||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
if (item.itemId == R.id.save) {
|
if (item.itemId == R.id.save) {
|
||||||
saveConversationNameAndDescription()
|
if (conversation?.objectType != ConversationEnums.ObjectType.EVENT) {
|
||||||
|
saveConversationNameAndDescription()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -210,6 +210,7 @@ class ConversationsListActivity :
|
|||||||
private var conversationItemsWithHeader: MutableList<AbstractFlexibleItem<*>> = ArrayList()
|
private var conversationItemsWithHeader: MutableList<AbstractFlexibleItem<*>> = ArrayList()
|
||||||
private val searchableConversationItems: MutableList<AbstractFlexibleItem<*>> = ArrayList()
|
private val searchableConversationItems: MutableList<AbstractFlexibleItem<*>> = ArrayList()
|
||||||
private var filterableConversationItems: MutableList<AbstractFlexibleItem<*>> = ArrayList()
|
private var filterableConversationItems: MutableList<AbstractFlexibleItem<*>> = ArrayList()
|
||||||
|
private var nearFutureEventConversationItems: MutableList<AbstractFlexibleItem<*>> = ArrayList()
|
||||||
private var searchItem: MenuItem? = null
|
private var searchItem: MenuItem? = null
|
||||||
private var chooseAccountItem: MenuItem? = null
|
private var chooseAccountItem: MenuItem? = null
|
||||||
private var searchView: SearchView? = null
|
private var searchView: SearchView? = null
|
||||||
@ -519,16 +520,29 @@ class ConversationsListActivity :
|
|||||||
// Update Conversations
|
// Update Conversations
|
||||||
conversationItems.clear()
|
conversationItems.clear()
|
||||||
conversationItemsWithHeader.clear()
|
conversationItemsWithHeader.clear()
|
||||||
|
nearFutureEventConversationItems.clear()
|
||||||
|
|
||||||
for (conversation in list) {
|
for (conversation in list) {
|
||||||
|
if (!futureEvent(conversation)) {
|
||||||
|
addToNearFutureEventConversationItems(conversation)
|
||||||
|
}
|
||||||
addToConversationItems(conversation)
|
addToConversationItems(conversation)
|
||||||
}
|
}
|
||||||
|
|
||||||
sortConversations(conversationItems)
|
sortConversations(conversationItems)
|
||||||
sortConversations(conversationItemsWithHeader)
|
sortConversations(conversationItemsWithHeader)
|
||||||
|
sortConversations(nearFutureEventConversationItems)
|
||||||
|
|
||||||
// Filter Conversations
|
if (!hasFilterEnabled() && searchBehaviorSubject.value == false) {
|
||||||
if (!hasFilterEnabled()) filterableConversationItems = conversationItems
|
adapter?.updateDataSet(nearFutureEventConversationItems, false)
|
||||||
filterConversation()
|
} else {
|
||||||
adapter?.updateDataSet(filterableConversationItems, false)
|
// Filter Conversations
|
||||||
|
if (!hasFilterEnabled()) {
|
||||||
|
filterableConversationItems = conversationItems
|
||||||
|
}
|
||||||
|
filterConversation()
|
||||||
|
adapter?.updateDataSet(filterableConversationItems, false)
|
||||||
|
}
|
||||||
Handler().postDelayed({ checkToShowUnreadBubble() }, UNREAD_BUBBLE_DELAY.toLong())
|
Handler().postDelayed({ checkToShowUnreadBubble() }, UNREAD_BUBBLE_DELAY.toLong())
|
||||||
|
|
||||||
// Fetch Open Conversations
|
// Fetch Open Conversations
|
||||||
@ -550,6 +564,26 @@ class ConversationsListActivity :
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun futureEvent(conversation: ConversationModel): Boolean {
|
||||||
|
if (!conversation.objectId.contains("#")) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return conversation.objectType == ConversationEnums.ObjectType.EVENT &&
|
||||||
|
(conversation.objectId.split("#")[0].toLong() - (System.currentTimeMillis() / LONG_1000)) >
|
||||||
|
AGE_THRESHOLD_FOR_EVENT_CONVERSATIONS
|
||||||
|
}
|
||||||
|
|
||||||
|
fun showOnlyNearFutureEvents() {
|
||||||
|
sortConversations(nearFutureEventConversationItems)
|
||||||
|
adapter?.updateDataSet(nearFutureEventConversationItems, false)
|
||||||
|
adapter?.smoothScrollToPosition(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addToNearFutureEventConversationItems(conversation: ConversationModel) {
|
||||||
|
val conversationItem = ConversationItem(conversation, currentUser!!, this, null, viewThemeUtils)
|
||||||
|
nearFutureEventConversationItems.add(conversationItem)
|
||||||
|
}
|
||||||
|
|
||||||
fun filterConversation() {
|
fun filterConversation() {
|
||||||
val accountId = UserIdUtils.getIdForUser(currentUser)
|
val accountId = UserIdUtils.getIdForUser(currentUser)
|
||||||
filterState[FilterConversationFragment.UNREAD] = (
|
filterState[FilterConversationFragment.UNREAD] = (
|
||||||
@ -837,15 +871,19 @@ class ConversationsListActivity :
|
|||||||
|
|
||||||
override fun onMenuItemActionCollapse(item: MenuItem): Boolean {
|
override fun onMenuItemActionCollapse(item: MenuItem): Boolean {
|
||||||
adapter?.setHeadersShown(false)
|
adapter?.setHeadersShown(false)
|
||||||
|
searchBehaviorSubject.onNext(false)
|
||||||
if (!hasFilterEnabled()) filterableConversationItems = conversationItemsWithHeader
|
if (!hasFilterEnabled()) filterableConversationItems = conversationItemsWithHeader
|
||||||
adapter?.updateDataSet(filterableConversationItems, false)
|
if (!hasFilterEnabled()) {
|
||||||
|
adapter?.updateDataSet(nearFutureEventConversationItems, false)
|
||||||
|
} else {
|
||||||
|
filterableConversationItems = conversationItems
|
||||||
|
}
|
||||||
adapter?.hideAllHeaders()
|
adapter?.hideAllHeaders()
|
||||||
if (searchHelper != null) {
|
if (searchHelper != null) {
|
||||||
// cancel any pending searches
|
// cancel any pending searches
|
||||||
searchHelper!!.cancelSearch()
|
searchHelper!!.cancelSearch()
|
||||||
}
|
}
|
||||||
binding.swipeRefreshLayoutView.isRefreshing = false
|
binding.swipeRefreshLayoutView.isRefreshing = false
|
||||||
searchBehaviorSubject.onNext(false)
|
|
||||||
binding.swipeRefreshLayoutView.isEnabled = true
|
binding.swipeRefreshLayoutView.isEnabled = true
|
||||||
searchView!!.onActionViewCollapsed()
|
searchView!!.onActionViewCollapsed()
|
||||||
|
|
||||||
@ -2114,5 +2152,7 @@ class ConversationsListActivity :
|
|||||||
const val NOTIFICATION_WARNING_DATE_NOT_SET = 0L
|
const val NOTIFICATION_WARNING_DATE_NOT_SET = 0L
|
||||||
const val OFFSET_HEIGHT_DIVIDER: Int = 3
|
const val OFFSET_HEIGHT_DIVIDER: Int = 3
|
||||||
const val ROOM_TYPE_ONE_ONE = "1"
|
const val ROOM_TYPE_ONE_ONE = "1"
|
||||||
|
private const val AGE_THRESHOLD_FOR_EVENT_CONVERSATIONS: Long = 57600
|
||||||
|
const val LONG_1000: Long = 1000
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,7 @@ fun ConversationModel.asEntity() =
|
|||||||
unreadMention = unreadMention,
|
unreadMention = unreadMention,
|
||||||
lastMessage = lastMessage?.let { LoganSquare.serialize(lastMessage) },
|
lastMessage = lastMessage?.let { LoganSquare.serialize(lastMessage) },
|
||||||
objectType = objectType,
|
objectType = objectType,
|
||||||
|
objectId = objectId,
|
||||||
notificationLevel = notificationLevel,
|
notificationLevel = notificationLevel,
|
||||||
conversationReadOnlyState = conversationReadOnlyState,
|
conversationReadOnlyState = conversationReadOnlyState,
|
||||||
lobbyState = lobbyState,
|
lobbyState = lobbyState,
|
||||||
@ -85,6 +86,7 @@ fun ConversationEntity.asModel() =
|
|||||||
lastMessage = lastMessage?.let
|
lastMessage = lastMessage?.let
|
||||||
{ LoganSquare.parse(lastMessage, ChatMessageJson::class.java) },
|
{ LoganSquare.parse(lastMessage, ChatMessageJson::class.java) },
|
||||||
objectType = objectType,
|
objectType = objectType,
|
||||||
|
objectId = objectId,
|
||||||
notificationLevel = notificationLevel,
|
notificationLevel = notificationLevel,
|
||||||
conversationReadOnlyState = conversationReadOnlyState,
|
conversationReadOnlyState = conversationReadOnlyState,
|
||||||
lobbyState = lobbyState,
|
lobbyState = lobbyState,
|
||||||
@ -135,6 +137,7 @@ fun Conversation.asEntity(accountId: Long) =
|
|||||||
unreadMention = unreadMention,
|
unreadMention = unreadMention,
|
||||||
lastMessage = lastMessage?.let { LoganSquare.serialize(lastMessage) },
|
lastMessage = lastMessage?.let { LoganSquare.serialize(lastMessage) },
|
||||||
objectType = objectType,
|
objectType = objectType,
|
||||||
|
objectId = objectId,
|
||||||
notificationLevel = notificationLevel,
|
notificationLevel = notificationLevel,
|
||||||
conversationReadOnlyState = conversationReadOnlyState,
|
conversationReadOnlyState = conversationReadOnlyState,
|
||||||
lobbyState = lobbyState,
|
lobbyState = lobbyState,
|
||||||
|
@ -78,6 +78,7 @@ data class ConversationEntity(
|
|||||||
@ColumnInfo(name = "notificationCalls") var notificationCalls: Int = 0,
|
@ColumnInfo(name = "notificationCalls") var notificationCalls: Int = 0,
|
||||||
@ColumnInfo(name = "notificationLevel") var notificationLevel: ConversationEnums.NotificationLevel,
|
@ColumnInfo(name = "notificationLevel") var notificationLevel: ConversationEnums.NotificationLevel,
|
||||||
@ColumnInfo(name = "objectType") var objectType: ConversationEnums.ObjectType,
|
@ColumnInfo(name = "objectType") var objectType: ConversationEnums.ObjectType,
|
||||||
|
@ColumnInfo(name = "objectId") var objectId: String,
|
||||||
@ColumnInfo(name = "participantType") var participantType: Participant.ParticipantType,
|
@ColumnInfo(name = "participantType") var participantType: Participant.ParticipantType,
|
||||||
@ColumnInfo(name = "permissions") var permissions: Int = 0,
|
@ColumnInfo(name = "permissions") var permissions: Int = 0,
|
||||||
@ColumnInfo(name = "readOnly") var conversationReadOnlyState: ConversationEnums.ConversationReadOnlyState,
|
@ColumnInfo(name = "readOnly") var conversationReadOnlyState: ConversationEnums.ConversationReadOnlyState,
|
||||||
|
@ -55,6 +55,13 @@ object Migrations {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val MIGRATION_13_14 = object : Migration(13, 14) {
|
||||||
|
override fun migrate(db: SupportSQLiteDatabase) {
|
||||||
|
Log.i("Migrations", "Migrating 13 to 14")
|
||||||
|
addObjectId(db)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun migrateToRoom(db: SupportSQLiteDatabase) {
|
fun migrateToRoom(db: SupportSQLiteDatabase) {
|
||||||
db.execSQL(
|
db.execSQL(
|
||||||
"CREATE TABLE User_new (" +
|
"CREATE TABLE User_new (" +
|
||||||
@ -265,6 +272,17 @@ object Migrations {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun addObjectId(db: SupportSQLiteDatabase) {
|
||||||
|
try {
|
||||||
|
db.execSQL(
|
||||||
|
"ALTER TABLE Conversations " +
|
||||||
|
"ADD COLUMN objectId TEXT NOT NULL DEFAULT '';"
|
||||||
|
)
|
||||||
|
} catch (e: SQLException) {
|
||||||
|
Log.i("Migrations", "Something went wrong when adding column objectId to table Conversations")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun addTempMessagesSupport(db: SupportSQLiteDatabase) {
|
fun addTempMessagesSupport(db: SupportSQLiteDatabase) {
|
||||||
try {
|
try {
|
||||||
db.execSQL(
|
db.execSQL(
|
||||||
|
@ -49,9 +49,9 @@ import java.util.Locale
|
|||||||
ChatMessageEntity::class,
|
ChatMessageEntity::class,
|
||||||
ChatBlockEntity::class
|
ChatBlockEntity::class
|
||||||
],
|
],
|
||||||
version = 13,
|
version = 14,
|
||||||
autoMigrations = [
|
autoMigrations = [
|
||||||
AutoMigration(from = 9, to = 11)
|
AutoMigration(from = 9, to = 10)
|
||||||
],
|
],
|
||||||
exportSchema = true
|
exportSchema = true
|
||||||
)
|
)
|
||||||
@ -115,7 +115,8 @@ abstract class TalkDatabase : RoomDatabase() {
|
|||||||
Migrations.MIGRATION_8_9,
|
Migrations.MIGRATION_8_9,
|
||||||
Migrations.MIGRATION_10_11,
|
Migrations.MIGRATION_10_11,
|
||||||
Migrations.MIGRATION_11_12,
|
Migrations.MIGRATION_11_12,
|
||||||
Migrations.MIGRATION_12_13
|
Migrations.MIGRATION_12_13,
|
||||||
|
Migrations.MIGRATION_13_14
|
||||||
)
|
)
|
||||||
.allowMainThreadQueries()
|
.allowMainThreadQueries()
|
||||||
.addCallback(
|
.addCallback(
|
||||||
|
@ -33,6 +33,7 @@ class ConversationModel(
|
|||||||
var unreadMention: Boolean = false,
|
var unreadMention: Boolean = false,
|
||||||
var lastMessage: ChatMessageJson? = null,
|
var lastMessage: ChatMessageJson? = null,
|
||||||
var objectType: ConversationEnums.ObjectType,
|
var objectType: ConversationEnums.ObjectType,
|
||||||
|
var objectId: String = "",
|
||||||
var notificationLevel: ConversationEnums.NotificationLevel,
|
var notificationLevel: ConversationEnums.NotificationLevel,
|
||||||
var conversationReadOnlyState: ConversationEnums.ConversationReadOnlyState,
|
var conversationReadOnlyState: ConversationEnums.ConversationReadOnlyState,
|
||||||
var lobbyState: ConversationEnums.LobbyState,
|
var lobbyState: ConversationEnums.LobbyState,
|
||||||
@ -66,6 +67,7 @@ class ConversationModel(
|
|||||||
) {
|
) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@Suppress("LongMethod")
|
||||||
fun mapToConversationModel(conversation: Conversation, user: User): ConversationModel {
|
fun mapToConversationModel(conversation: Conversation, user: User): ConversationModel {
|
||||||
return ConversationModel(
|
return ConversationModel(
|
||||||
internalId = user.id!!.toString() + "@" + conversation.token,
|
internalId = user.id!!.toString() + "@" + conversation.token,
|
||||||
@ -88,6 +90,7 @@ class ConversationModel(
|
|||||||
unreadMention = conversation.unreadMention,
|
unreadMention = conversation.unreadMention,
|
||||||
lastMessage = conversation.lastMessage,
|
lastMessage = conversation.lastMessage,
|
||||||
objectType = conversation.objectType.let { ConversationEnums.ObjectType.valueOf(it.name) },
|
objectType = conversation.objectType.let { ConversationEnums.ObjectType.valueOf(it.name) },
|
||||||
|
objectId = conversation.objectId,
|
||||||
notificationLevel = conversation.notificationLevel.let {
|
notificationLevel = conversation.notificationLevel.let {
|
||||||
ConversationEnums.NotificationLevel.valueOf(
|
ConversationEnums.NotificationLevel.valueOf(
|
||||||
it.name
|
it.name
|
||||||
|
@ -79,6 +79,9 @@ data class Conversation(
|
|||||||
@JsonField(name = ["objectType"], typeConverter = ConversationObjectTypeConverter::class)
|
@JsonField(name = ["objectType"], typeConverter = ConversationObjectTypeConverter::class)
|
||||||
var objectType: ConversationEnums.ObjectType = ConversationEnums.ObjectType.DEFAULT,
|
var objectType: ConversationEnums.ObjectType = ConversationEnums.ObjectType.DEFAULT,
|
||||||
|
|
||||||
|
@JsonField(name = ["objectId"])
|
||||||
|
var objectId: String = "",
|
||||||
|
|
||||||
@JsonField(name = ["notificationLevel"], typeConverter = EnumNotificationLevelConverter::class)
|
@JsonField(name = ["notificationLevel"], typeConverter = EnumNotificationLevelConverter::class)
|
||||||
var notificationLevel: ConversationEnums.NotificationLevel = ConversationEnums.NotificationLevel.DEFAULT,
|
var notificationLevel: ConversationEnums.NotificationLevel = ConversationEnums.NotificationLevel.DEFAULT,
|
||||||
|
|
||||||
|
@ -43,6 +43,7 @@ class ConversationEnums {
|
|||||||
DEFAULT,
|
DEFAULT,
|
||||||
SHARE_PASSWORD,
|
SHARE_PASSWORD,
|
||||||
FILE,
|
FILE,
|
||||||
ROOM
|
ROOM,
|
||||||
|
EVENT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ class ConversationObjectTypeConverter : StringBasedTypeConverter<ConversationEnu
|
|||||||
"share:password" -> ConversationEnums.ObjectType.SHARE_PASSWORD
|
"share:password" -> ConversationEnums.ObjectType.SHARE_PASSWORD
|
||||||
"room" -> ConversationEnums.ObjectType.ROOM
|
"room" -> ConversationEnums.ObjectType.ROOM
|
||||||
"file" -> ConversationEnums.ObjectType.FILE
|
"file" -> ConversationEnums.ObjectType.FILE
|
||||||
|
"event" -> ConversationEnums.ObjectType.EVENT
|
||||||
else -> ConversationEnums.ObjectType.DEFAULT
|
else -> ConversationEnums.ObjectType.DEFAULT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -28,6 +29,7 @@ class ConversationObjectTypeConverter : StringBasedTypeConverter<ConversationEnu
|
|||||||
ConversationEnums.ObjectType.SHARE_PASSWORD -> "share:password"
|
ConversationEnums.ObjectType.SHARE_PASSWORD -> "share:password"
|
||||||
ConversationEnums.ObjectType.ROOM -> "room"
|
ConversationEnums.ObjectType.ROOM -> "room"
|
||||||
ConversationEnums.ObjectType.FILE -> "file"
|
ConversationEnums.ObjectType.FILE -> "file"
|
||||||
|
ConversationEnums.ObjectType.EVENT -> "event"
|
||||||
else -> ""
|
else -> ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
package com.nextcloud.talk.ui.dialog
|
package com.nextcloud.talk.ui.dialog
|
||||||
|
|
||||||
import android.app.Dialog
|
import android.app.Dialog
|
||||||
|
import android.content.DialogInterface
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
@ -99,6 +100,14 @@ class FilterConversationFragment : DialogFragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
binding.buttonClose.setOnClickListener {
|
binding.buttonClose.setOnClickListener {
|
||||||
|
val noFiltersActive = !(
|
||||||
|
filterState[MENTION] == true ||
|
||||||
|
filterState[UNREAD] == true ||
|
||||||
|
filterState[ARCHIVE] == true
|
||||||
|
)
|
||||||
|
if (noFiltersActive) {
|
||||||
|
(requireActivity() as ConversationsListActivity).showOnlyNearFutureEvents()
|
||||||
|
}
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -130,6 +139,18 @@ class FilterConversationFragment : DialogFragment() {
|
|||||||
(requireActivity() as ConversationsListActivity).filterConversation()
|
(requireActivity() as ConversationsListActivity).filterConversation()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onDismiss(dialog: DialogInterface) {
|
||||||
|
super.onDismiss(dialog)
|
||||||
|
val noFiltersActive = !(
|
||||||
|
filterState[MENTION] == true ||
|
||||||
|
filterState[UNREAD] == true ||
|
||||||
|
filterState[ARCHIVE] == true
|
||||||
|
)
|
||||||
|
if (noFiltersActive) {
|
||||||
|
(requireActivity() as ConversationsListActivity).showOnlyNearFutureEvents()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val FILTER_STATE_ARG = "FILTER_STATE_ARG"
|
private const val FILTER_STATE_ARG = "FILTER_STATE_ARG"
|
||||||
|
|
||||||
|
19
app/src/main/res/drawable/baseline_calendar_today_24.xml
Normal file
19
app/src/main/res/drawable/baseline_calendar_today_24.xml
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<!--
|
||||||
|
~ Nextcloud Talk - Android Client
|
||||||
|
~
|
||||||
|
~ SPDX-FileCopyrightText: 2025 Sowjanya Kota <sowjanya.kch@gmail.com>
|
||||||
|
~ SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
-->
|
||||||
|
|
||||||
|
<vector
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:height="20dp"
|
||||||
|
android:tint="#000000"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:width="20dp">
|
||||||
|
|
||||||
|
<path android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M20,3h-1L19,1h-2v2L7,3L7,1L5,1v2L4,3c-1.1,0 -2,0.9 -2,2v16c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,5c0,-1.1 -0.9,-2 -2,-2zM20,21L4,21L4,8h16v13z"/>
|
||||||
|
|
||||||
|
</vector>
|
60
app/src/main/res/layout/item_event_schedule.xml
Normal file
60
app/src/main/res/layout/item_event_schedule.xml
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?><!--
|
||||||
|
~ Nextcloud Talk - Android Client
|
||||||
|
~
|
||||||
|
~ SPDX-FileCopyrightText: 2025 Sowjanya Kota <sowjanya.kota@gmail.com>
|
||||||
|
~ SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
-->
|
||||||
|
|
||||||
|
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:background="@color/popup_menu_color">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/event_scheduled"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/nc_event_schedule"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textSize="18sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/meetingTime"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
|
android:textSize="16sp"
|
||||||
|
tools:text="Meeting at 8:00 pm"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/delete_conversation"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/nc_delete_call"
|
||||||
|
android:textColor="@android:color/holo_red_dark"
|
||||||
|
android:visibility = "gone"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:paddingTop="24dp"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/archive_conversation"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/archive_conversation"
|
||||||
|
android:visibility = "gone"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:paddingTop="24dp"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/unarchive_conversation"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/unarchive_conversation"
|
||||||
|
android:visibility = "gone"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:paddingTop="24dp"/>
|
||||||
|
</LinearLayout>
|
@ -8,36 +8,45 @@
|
|||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/conversation_event"
|
||||||
|
android:icon="@drawable/baseline_calendar_today_24"
|
||||||
|
android:orderInCategory="0"
|
||||||
|
android:title="@string/nc_event_conversation_menu"
|
||||||
|
app:showAsAction="ifRoom">
|
||||||
|
|
||||||
|
</item>
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/conversation_voice_call"
|
android:id="@+id/conversation_voice_call"
|
||||||
android:icon="@drawable/ic_call_white_24dp"
|
android:icon="@drawable/ic_call_white_24dp"
|
||||||
android:orderInCategory="0"
|
android:orderInCategory="1"
|
||||||
android:title="@string/nc_conversation_menu_voice_call"
|
android:title="@string/nc_conversation_menu_voice_call"
|
||||||
app:showAsAction="ifRoom" />
|
app:showAsAction="ifRoom" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/conversation_video_call"
|
android:id="@+id/conversation_video_call"
|
||||||
android:icon="@drawable/ic_videocam_white_24px"
|
android:icon="@drawable/ic_videocam_white_24px"
|
||||||
android:orderInCategory="1"
|
android:orderInCategory="2"
|
||||||
android:title="@string/nc_conversation_menu_video_call"
|
android:title="@string/nc_conversation_menu_video_call"
|
||||||
app:showAsAction="ifRoom" />
|
app:showAsAction="ifRoom" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/conversation_search"
|
android:id="@+id/conversation_search"
|
||||||
android:icon="@drawable/ic_search_white_24dp"
|
android:icon="@drawable/ic_search_white_24dp"
|
||||||
android:orderInCategory="2"
|
android:orderInCategory="3"
|
||||||
android:title="@string/nc_search"
|
android:title="@string/nc_search"
|
||||||
app:showAsAction="ifRoom" />
|
app:showAsAction="ifRoom" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/conversation_info"
|
android:id="@+id/conversation_info"
|
||||||
android:orderInCategory="3"
|
android:orderInCategory="4"
|
||||||
android:title="@string/nc_conversation_menu_conversation_info"
|
android:title="@string/nc_conversation_menu_conversation_info"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="never" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/shared_items"
|
android:id="@+id/shared_items"
|
||||||
android:orderInCategory="4"
|
android:orderInCategory="5"
|
||||||
android:title="@string/nc_shared_items"
|
android:title="@string/nc_shared_items"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="never" />
|
||||||
</menu>
|
</menu>
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
<color name="colorPrimaryDark">#006AA3</color>
|
<color name="colorPrimaryDark">#006AA3</color>
|
||||||
<color name="colorAccent">@color/colorPrimary</color>
|
<color name="colorAccent">@color/colorPrimary</color>
|
||||||
<color name="disabled_text">#ff6F6F6F</color>
|
<color name="disabled_text">#ff6F6F6F</color>
|
||||||
|
<color name="popup_menu_color">#FF37474F</color>
|
||||||
|
|
||||||
<!-- App bar -->
|
<!-- App bar -->
|
||||||
<color name="appbar">#1E1E1E</color>
|
<color name="appbar">#1E1E1E</color>
|
||||||
|
@ -13,6 +13,8 @@
|
|||||||
<color name="disabled_text">#ff888888</color>
|
<color name="disabled_text">#ff888888</color>
|
||||||
<color name="textColorOnPrimaryBackground">#ffffff</color> <!-- white/black depending on primary color -->
|
<color name="textColorOnPrimaryBackground">#ffffff</color> <!-- white/black depending on primary color -->
|
||||||
<color name="nc_login_text_color">#B3FFFFFF</color>
|
<color name="nc_login_text_color">#B3FFFFFF</color>
|
||||||
|
<color name="popup_menu_color">#FF607D8B</color>
|
||||||
|
|
||||||
|
|
||||||
<!-- App bar -->
|
<!-- App bar -->
|
||||||
<color name="appbar">@android:color/white</color>
|
<color name="appbar">@android:color/white</color>
|
||||||
|
@ -242,8 +242,14 @@ How to translate with transifex:
|
|||||||
<string name="nc_rename">Rename conversation</string>
|
<string name="nc_rename">Rename conversation</string>
|
||||||
<string name="nc_rename_confirm">Rename</string>
|
<string name="nc_rename_confirm">Rename</string>
|
||||||
<string name="nc_delete_call">Delete conversation</string>
|
<string name="nc_delete_call">Delete conversation</string>
|
||||||
|
<string name="nc_event_schedule">Schedule</string>
|
||||||
<string name="nc_delete">Delete</string>
|
<string name="nc_delete">Delete</string>
|
||||||
<string name="nc_delete_all">Delete all</string>
|
<string name="nc_delete_all">Delete all</string>
|
||||||
|
<string name="nc_ongoing_meeting">Ongoing meeting</string>
|
||||||
|
<string name="nc_meeting_ended">Meeting ended</string>
|
||||||
|
<string name="nc_invalid_time">Invalid time</string>
|
||||||
|
<string name="nc_today_meeting">Today at %1$s</string>
|
||||||
|
<string name="nc_tomorrow_meeting">Tomorrow at %1$s</string>
|
||||||
<string name="nc_delete_conversation_more">If you delete the conversation, it will also be deleted for all other participants.</string>
|
<string name="nc_delete_conversation_more">If you delete the conversation, it will also be deleted for all other participants.</string>
|
||||||
|
|
||||||
<string name="nc_new_conversation">New conversation</string>
|
<string name="nc_new_conversation">New conversation</string>
|
||||||
@ -403,6 +409,7 @@ How to translate with transifex:
|
|||||||
<string name="nc_date_header_today">Today</string>
|
<string name="nc_date_header_today">Today</string>
|
||||||
<string name="nc_conversation_menu_voice_call">Voice call</string>
|
<string name="nc_conversation_menu_voice_call">Voice call</string>
|
||||||
<string name="nc_conversation_menu_video_call">Video call</string>
|
<string name="nc_conversation_menu_video_call">Video call</string>
|
||||||
|
<string name="nc_event_conversation_menu">Event conversation menu</string>
|
||||||
<string name="nc_conversation_menu_conversation_info">Conversation info</string>
|
<string name="nc_conversation_menu_conversation_info">Conversation info</string>
|
||||||
<string name="nc_new_messages">Unread messages</string>
|
<string name="nc_new_messages">Unread messages</string>
|
||||||
<string name="nc_sent_a_gif" formatted="true">%1$s sent a GIF.</string>
|
<string name="nc_sent_a_gif" formatted="true">%1$s sent a GIF.</string>
|
||||||
@ -843,4 +850,5 @@ How to translate with transifex:
|
|||||||
<string name="no_conversations_archived">No archived conversations</string>
|
<string name="no_conversations_archived">No archived conversations</string>
|
||||||
<string name="archived_conversation">Archived %1$s</string>
|
<string name="archived_conversation">Archived %1$s</string>
|
||||||
<string name="unarchived_conversation">Unarchived %1$s</string>
|
<string name="unarchived_conversation">Unarchived %1$s</string>
|
||||||
|
<string name="conversation_archived">Conversation is archived</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
Loading…
Reference in New Issue
Block a user