From a316729cfd722a8c59a3107b04384e7ec363640f Mon Sep 17 00:00:00 2001 From: Erik Everson <32311723+ErikEverson@users.noreply.github.com> Date: Thu, 24 Oct 2024 16:18:59 -0600 Subject: [PATCH] Updated to allow for TAK chatting (#29) --- .../DittoChatPackage/Data/DittoService.swift | 41 ++--- Sources/DittoChatPackage/Models/Message.swift | 153 +++++++++++++++++- .../RoomsListScreen/RoomsListScreen.swift | 16 ++ .../RoomsListScreen/RoomsListScreenVM.swift | 4 +- .../Utilities/StringKeys.swift | 17 ++ 5 files changed, 211 insertions(+), 20 deletions(-) diff --git a/Sources/DittoChatPackage/Data/DittoService.swift b/Sources/DittoChatPackage/Data/DittoService.swift index 9bf2fc1..529a95a 100644 --- a/Sources/DittoChatPackage/Data/DittoService.swift +++ b/Sources/DittoChatPackage/Data/DittoService.swift @@ -263,13 +263,9 @@ extension DittoService { return } - try! ditto.store.collection(room.messagesId) - .upsert([ - createdOnKey: DateFormatter.isoDate.string(from: Date()), - roomIdKey: room.id, - textKey: text, - userIdKey: userId - ] as [String: Any?] ) + let message = Message(roomId: room.id, message: text, userName: userId, userId: userId).docDictionary() + + try! ditto.store.collection(room.messagesId).upsert(message) } func saveEditedTextMessage(_ message: Message, in room: Room) { @@ -318,15 +314,14 @@ extension DittoService { // create new message doc with thumbnail attachment let docId = UUID().uuidString - do { - try ditto.store[room.messagesId].upsert([ - dbIdKey: docId, - createdOnKey: nowDate, - roomIdKey: room.id, - userIdKey: userId, - thumbnailImageTokenKey: thumbAttachment, - ]) + var message = Message(roomId: room.id, userName: userId, userId: userId).docDictionary() + message.updateValue(thumbAttachment, forKey: thumbnailImageTokenKey) + message.updateValue(docId, forKey: dbIdKey) + + + do { + try ditto.store[room.messagesId].upsert(message) try await cleanupTmpStorage(tmpStorage.deleteDirectory) } catch { throw error @@ -534,9 +529,8 @@ extension DittoService { } private func createDefaultPublicRoom() { - // Only create default Public room if user does not yet exist, i.e. first launch - if privateStore.currentUserId != nil { -// if allPublicRooms.count > 0 { + // TODO: Replace with a first launch value instead that is specific for this use case + if allPublicRooms.count > 2 { return } @@ -550,6 +544,17 @@ extension DittoService { createdOnKey: DateFormatter.isoDate.string(from: Date()), isPrivateKey: false ] as [String: Any?] ) + + // Create default Public room with pre-configured id, messagesId + try! ditto.store.collection(publicRoomsCollectionId) + .upsert([ + dbIdKey: publicTAKKey, + nameKey: publicTAKRoomTitleKey, + collectionIdKey: publicRoomsCollectionId, + messagesIdKey: publicTAKMessagesIdKey, + createdOnKey: DateFormatter.isoDate.string(from: Date()), + isPrivateKey: false + ] as [String: Any?] ) } } diff --git a/Sources/DittoChatPackage/Models/Message.swift b/Sources/DittoChatPackage/Models/Message.swift index d3df7c2..b436982 100644 --- a/Sources/DittoChatPackage/Models/Message.swift +++ b/Sources/DittoChatPackage/Models/Message.swift @@ -27,6 +27,21 @@ struct Message: Identifiable, Equatable { var archivedMessage: String? var isArchived: Bool + //TAK specific values + var authorCs: String + var authorId: String + var authorLoc: String + var authorType: String + var msg: String + var parent: String + var pks: String + var room: String + var schver: Int + var takUid: String + var timeMs: Date + + var hasBeenConverted: Bool? + var isImageMessage: Bool { thumbnailImageToken != nil || largeImageToken != nil } @@ -43,6 +58,65 @@ extension Message { self.thumbnailImageToken = document[thumbnailImageTokenKey].attachmentToken self.archivedMessage = document[archivedMessageKey].string self.isArchived = document[isArchivedKey].bool ?? false + + // TAK related values + self.authorCs = document[authorCsKey].stringValue + self.authorId = document[authorIdKey].stringValue + self.authorLoc = document[authorLocKey].stringValue + self.authorType = document[authorTypeKey].stringValue + self.msg = document[msgKey].stringValue + self.parent = document[parentKey].stringValue + self.pks = document[pksKey].stringValue + self.room = document[roomKey].stringValue + self.roomId = document[roomIdKey].stringValue + self.schver = document[schverKey].intValue + self.takUid = document[takUidKey].stringValue + self.timeMs = Date(timeIntervalSince1970: document[timeMsKey].doubleValue / 1000) + self.hasBeenConverted = document[hasBeenConvertedKey].bool + + if let hasBeenConverted, hasBeenConverted == true { + return + } + + self.convertToDittoChat() + } + + func convertToDittoChat() { + let message = Message( + id: self.id, + createdOn: self.timeMs, + roomId: self.roomId, + text: self.msg, + userId: self.authorCs, + largeImageToken: self.largeImageToken, + thumbnailImageToken: self.thumbnailImageToken, + archivedMessage: self.archivedMessage, + isArchived: self.isArchived, + authorCs: self.authorCs, + authorId: self.authorId, + authorLoc: self.authorLoc, + authorType: self.authorType, + msg: self.msg, + parent: self.parent, + pks: self.pks, + room: self.room, + schver: self.schver, + takUid: self.takUid, + timeMs: self.timeMs, + hasBeenConverted: true + ).docDictionary() + + // Update the currently existing TAK chat message with a Ditto Chat compatable one + Task { + try? await DittoInstance.shared.ditto.store.execute( + query: """ + INSERT INTO chat + DOCUMENTS (:message) + ON ID CONFLICT DO UPDATE + """, + arguments: ["message": message] + ) + } } } @@ -56,7 +130,18 @@ extension Message { largeImageToken: DittoAttachmentToken? = nil, thumbnailImageToken: DittoAttachmentToken? = nil, archivedMessage: String? = nil, - isArchived: Bool = false + isArchived: Bool = false, + authorCs: String? = nil, + authorId: String? = nil, + authorLoc: String? = nil, + authorType: String? = nil, + msg: String? = nil, + parent: String? = nil, + pks: String? = nil, + room: String? = nil, + schver: Int? = nil, + takUid: String? = nil, + timeMs: Date? = nil ) { self.id = id ?? UUID().uuidString self.createdOn = createdOn ?? Date() @@ -67,6 +152,60 @@ extension Message { self.thumbnailImageToken = thumbnailImageToken self.archivedMessage = archivedMessage self.isArchived = isArchived + + self.authorCs = authorCs ?? "" + self.authorId = authorId ?? "" + self.authorLoc = authorLoc ?? "" + self.authorType = authorType ?? "" + self.msg = msg ?? "" + self.parent = parent ?? "" + self.pks = pks ?? "" + self.room = room ?? "" + self.schver = schver ?? .zero + self.takUid = takUid ?? "" + self.timeMs = timeMs ?? Date() + + } + + // Used for creating new chat types for upload + init( + id: String? = nil, + createdOn: Date? = nil, + roomId: String, + message: String = "", + userName: String, + userId: String, + largeImageToken: DittoAttachmentToken? = nil, + thumbnailImageToken: DittoAttachmentToken? = nil, + archivedMessage: String? = nil, + isArchived: Bool = false, + parent: String = "RootContactGroup", + pks: String = "", + room: String = "Ditto", + schver: Int = 1, + hasBeenConverted: Bool = true + ) { + self.id = id ?? UUID().uuidString + self.createdOn = createdOn ?? Date() + self.roomId = roomId + self.text = message + self.userId = userId + self.largeImageToken = largeImageToken + self.thumbnailImageToken = thumbnailImageToken + self.archivedMessage = archivedMessage + self.isArchived = isArchived + + self.authorCs = userName + self.authorId = userId + self.authorLoc = "" + self.authorType = "" + self.msg = message + self.parent = parent + self.pks = pks + self.room = room + self.schver = schver + self.takUid = userId + self.timeMs = createdOn ?? Date() } } @@ -82,6 +221,18 @@ extension Message { thumbnailImageTokenKey: thumbnailImageToken, archivedMessageKey: archivedMessage, isArchivedKey: isArchived, + authorCsKey: authorCs, + authorIdKey: authorId, + authorLocKey: authorLoc, + authorTypeKey: authorType, + msgKey: msg, + parentKey: parent, + pksKey: pks, + roomKey: room, + schverKey: schver, + takUidKey: takUid, + timeMsKey: (timeMs.timeIntervalSince1970 * 1000), + hasBeenConvertedKey: hasBeenConverted, ] } } diff --git a/Sources/DittoChatPackage/Screens/RoomsListScreen/RoomsListScreen.swift b/Sources/DittoChatPackage/Screens/RoomsListScreen/RoomsListScreen.swift index 48dce0b..1e7657d 100644 --- a/Sources/DittoChatPackage/Screens/RoomsListScreen/RoomsListScreen.swift +++ b/Sources/DittoChatPackage/Screens/RoomsListScreen/RoomsListScreen.swift @@ -31,6 +31,22 @@ public struct RoomsListScreen: View { #endif } } + if let defaultTAKPublicRoom = viewModel.defaultTAKPublicRoom { + Section(takPublicRoomTitleKey) { + NavigationLink(destination: ChatScreen(room: defaultTAKPublicRoom)) { + RoomsListRowItem(room: defaultTAKPublicRoom) + } + #if !os(tvOS) + .swipeActions(edge: .leading, allowsFullSwipe: true) { + Button(action: { + viewModel.toggleSubscriptionFor(room: defaultTAKPublicRoom) + }, label: { + Text("Sub") + }) + } + #endif + } + } Section( viewModel.publicRooms.count > 0 ? publicRoomsTitleKey : "" ) { ForEach(viewModel.publicRooms) { room in NavigationLink(destination: ChatScreen(room: room)) { diff --git a/Sources/DittoChatPackage/Screens/RoomsListScreen/RoomsListScreenVM.swift b/Sources/DittoChatPackage/Screens/RoomsListScreen/RoomsListScreenVM.swift index bc813aa..097a0eb 100644 --- a/Sources/DittoChatPackage/Screens/RoomsListScreen/RoomsListScreenVM.swift +++ b/Sources/DittoChatPackage/Screens/RoomsListScreen/RoomsListScreenVM.swift @@ -17,6 +17,7 @@ class RoomsListScreenVM: ObservableObject { @Published var publicRooms: [Room] = [] @Published var privateRooms: [Room] = [] @Published var defaultPublicRoom: Room? + @Published var defaultTAKPublicRoom: Room? @Published var currentUser: ChatUser? init() { @@ -27,8 +28,9 @@ class RoomsListScreenVM: ObservableObject { .receive(on: DispatchQueue.main) .map { [weak self] rooms in self?.defaultPublicRoom = rooms.first(where: { $0.id == publicKey }) + self?.defaultTAKPublicRoom = rooms.first(where: { $0.id == publicTAKKey }) // remove default public room; it's presented by itself in 1st list section - return rooms.filter { $0.id != publicKey } + return rooms.filter { $0.id != publicKey || $0.id != publicTAKKey } } .assign(to: &$publicRooms) diff --git a/Sources/DittoChatPackage/Utilities/StringKeys.swift b/Sources/DittoChatPackage/Utilities/StringKeys.swift index 2f06f49..842deca 100644 --- a/Sources/DittoChatPackage/Utilities/StringKeys.swift +++ b/Sources/DittoChatPackage/Utilities/StringKeys.swift @@ -35,7 +35,9 @@ let messagesKey = "messages" let nameKey = "name" let privateRoomsKey = "privateRooms" let publicKey = "public" +let publicTAKKey = "ChatContact-Ditto" let publicMessagesIdKey = "1440174b9330e430b46da939f0b04a34a40e10ac8073671156da174fef1ffaef" +let publicTAKMessagesIdKey = "chat" let publicRoomsCollectionId = "rooms" let roomIdKey = "roomId" let subscriptionsKey = "subscriptions" @@ -44,6 +46,19 @@ let thumbnailImageTokenKey = "thumbnailImageToken" let timestampKey = "timestamp" let userIdKey = "userId" let usersKey = "users" +let isTAKEnabledKey = "isTAKEnabled" +let authorCsKey = "authorCs" +let authorIdKey = "authorId" +let authorLocKey = "authorLoc" +let authorTypeKey = "authorType" +let msgKey = "msg" +let parentKey = "parent" +let pksKey = "pks" +let roomKey = "room" +let schverKey = "schver" +let takUidKey = "takUid" +let timeMsKey = "timeMs" +let hasBeenConvertedKey = "hasBeenConverted" // MARK: UI Keys @@ -69,10 +84,12 @@ let messageTitleKey = "Message" let messagesTitleKey = "Messages" let newRoomTitleKey = "New Room" let openPublicRoomTitleKey = "Open Public Room" +let takPublicRoomTitleKey = "TAK Public Room" let privateTitleKey = "Private" let privateRoomsTitleKey = "Private Rooms" let profileTitleKey = "Profile" let publicRoomTitleKey = "Public Room" +let publicTAKRoomTitleKey = "Public TAK Room" let publicRoomsTitleKey = "Public Rooms" let restoreTitleKey = "RESTORE" let saveChangesTitleKey = "Save Changes"