From 02f25d6b37279b5ef23475a88c2fd1ffcad45821 Mon Sep 17 00:00:00 2001
From: Dariusz Rybicki <dariusz@elixxir.io>
Date: Tue, 6 Dec 2022 11:39:42 +0100
Subject: [PATCH] Display usernames on chat screen

---
 .../Sources/ChatFeature/ChatComponent.swift   | 18 ++++++----
 .../Sources/ChatFeature/ChatView.swift        | 11 ++++++
 .../ChatFeatureTests/ChatComponentTests.swift | 34 +++++++++++++++++++
 3 files changed, 56 insertions(+), 7 deletions(-)

diff --git a/Examples/xx-messenger/Sources/ChatFeature/ChatComponent.swift b/Examples/xx-messenger/Sources/ChatFeature/ChatComponent.swift
index 66585edd..def3f14c 100644
--- a/Examples/xx-messenger/Sources/ChatFeature/ChatComponent.swift
+++ b/Examples/xx-messenger/Sources/ChatFeature/ChatComponent.swift
@@ -19,6 +19,7 @@ public struct ChatComponent: ReducerProtocol {
         id: Int64,
         date: Date,
         senderId: Data,
+        senderName: String?,
         text: String,
         status: XXModels.Message.Status,
         fileTransfer: XXModels.FileTransfer? = nil
@@ -26,6 +27,7 @@ public struct ChatComponent: ReducerProtocol {
         self.id = id
         self.date = date
         self.senderId = senderId
+        self.senderName = senderName
         self.text = text
         self.status = status
         self.fileTransfer = fileTransfer
@@ -34,6 +36,7 @@ public struct ChatComponent: ReducerProtocol {
       public var id: Int64
       public var date: Date
       public var senderId: Data
+      public var senderName: String?
       public var text: String
       public var status: XXModels.Message.Status
       public var fileTransfer: XXModels.FileTransfer?
@@ -120,20 +123,21 @@ public struct ChatComponent: ReducerProtocol {
           let messagesQuery = XXModels.Message.Query(chat: queryChat)
           return Publishers.CombineLatest3(
             try db().fetchMessagesPublisher(messagesQuery),
-            receivedFileTransfersPublisher,
-            sentFileTransfersPublisher
+            try db().fetchContactsPublisher(.init()),
+            Publishers.CombineLatest(
+              receivedFileTransfersPublisher,
+              sentFileTransfersPublisher
+            ).map(+)
           )
-          .map { messages, receivedFileTransfers, sentFileTransfers in
-            (messages, receivedFileTransfers + sentFileTransfers)
-          }
           .assertNoFailure()
-          .map { messages, fileTransfers in
-            messages.compactMap { message in
+          .map { messages, contacts, fileTransfers -> [State.Message] in
+            messages.compactMap { message -> State.Message? in
               guard let id = message.id else { return nil }
               return State.Message(
                 id: id,
                 date: message.date,
                 senderId: message.senderId,
+                senderName: contacts.first { $0.id == message.senderId }?.username,
                 text: message.text,
                 status: message.status,
                 fileTransfer: fileTransfers.first { $0.id == message.fileTransferId }
diff --git a/Examples/xx-messenger/Sources/ChatFeature/ChatView.swift b/Examples/xx-messenger/Sources/ChatFeature/ChatView.swift
index ac0d0884..a7272385 100644
--- a/Examples/xx-messenger/Sources/ChatFeature/ChatView.swift
+++ b/Examples/xx-messenger/Sources/ChatFeature/ChatView.swift
@@ -147,6 +147,13 @@ public struct ChatView: View {
 
     var body: some View {
       VStack {
+        if let sender = message.senderName {
+          Text(sender)
+            .foregroundColor(.secondary)
+            .font(.footnote)
+            .frame(maxWidth: .infinity, alignment: alignment)
+        }
+
         Text("\(message.date.formatted()), \(statusText)")
           .foregroundColor(.secondary)
           .font(.footnote)
@@ -216,6 +223,7 @@ public struct ChatView_Previews: PreviewProvider {
               id: 1,
               date: Date(),
               senderId: "contact-id".data(using: .utf8)!,
+              senderName: "Contact",
               text: "Hello!",
               status: .received
             ),
@@ -223,6 +231,7 @@ public struct ChatView_Previews: PreviewProvider {
               id: 2,
               date: Date(),
               senderId: "my-contact-id".data(using: .utf8)!,
+              senderName: "Me",
               text: "Hi!",
               status: .sent
             ),
@@ -230,6 +239,7 @@ public struct ChatView_Previews: PreviewProvider {
               id: 3,
               date: Date(),
               senderId: "contact-id".data(using: .utf8)!,
+              senderName: "Contact",
               text: "",
               status: .received,
               fileTransfer: .init(
@@ -245,6 +255,7 @@ public struct ChatView_Previews: PreviewProvider {
               id: 4,
               date: Date(),
               senderId: "my-contact-id".data(using: .utf8)!,
+              senderName: "Me",
               text: "",
               status: .sent,
               fileTransfer: .init(
diff --git a/Examples/xx-messenger/Tests/ChatFeatureTests/ChatComponentTests.swift b/Examples/xx-messenger/Tests/ChatFeatureTests/ChatComponentTests.swift
index fb77001c..ba7ed237 100644
--- a/Examples/xx-messenger/Tests/ChatFeatureTests/ChatComponentTests.swift
+++ b/Examples/xx-messenger/Tests/ChatFeatureTests/ChatComponentTests.swift
@@ -22,6 +22,8 @@ final class ChatComponentTests: XCTestCase {
     let messagesPublisher = PassthroughSubject<[XXModels.Message], Error>()
     var didFetchFileTransfersWithQuery: [XXModels.FileTransfer.Query] = []
     let fileTransfersPublisher = PassthroughSubject<[XXModels.FileTransfer], Error>()
+    var didFetchContactsWithQuery: [XXModels.Contact.Query] = []
+    let contactsPublisher = PassthroughSubject<[XXModels.Contact], Error>()
 
     store.dependencies.app.mainQueue = .immediate
     store.dependencies.app.bgQueue = .immediate
@@ -40,6 +42,10 @@ final class ChatComponentTests: XCTestCase {
         didFetchMessagesWithQuery.append(query)
         return messagesPublisher.eraseToAnyPublisher()
       }
+      db.fetchContactsPublisher.run = { query in
+        didFetchContactsWithQuery.append(query)
+        return contactsPublisher.eraseToAnyPublisher()
+      }
       db.fetchFileTransfersPublisher.run = { query in
         didFetchFileTransfersWithQuery.append(query)
         return fileTransfersPublisher.eraseToAnyPublisher()
@@ -58,6 +64,9 @@ final class ChatComponentTests: XCTestCase {
       .init(contactId: contactId, isIncoming: true),
       .init(contactId: myContactId, isIncoming: false),
     ])
+    XCTAssertNoDifference(didFetchContactsWithQuery, [
+      .init(),
+    ])
 
     let receivedFileTransfer = FileTransfer(
       id: "file-transfer-1-id".data(using: .utf8)!,
@@ -111,12 +120,17 @@ final class ChatComponentTests: XCTestCase {
       receivedFileTransfer,
       sentFileTransfer,
     ])
+    contactsPublisher.send([
+      .init(id: myContactId, username: "My username"),
+      .init(id: contactId, username: "Contact username"),
+    ])
 
     let expectedMessages = IdentifiedArrayOf<ChatComponent.State.Message>(uniqueElements: [
       .init(
         id: 1,
         date: Date(timeIntervalSince1970: 1),
         senderId: contactId,
+        senderName: "Contact username",
         text: "Message 1",
         status: .received,
         fileTransfer: receivedFileTransfer
@@ -125,6 +139,7 @@ final class ChatComponentTests: XCTestCase {
         id: 2,
         date: Date(timeIntervalSince1970: 2),
         senderId: myContactId,
+        senderName: "My username",
         text: "Message 2",
         status: .sent,
         fileTransfer: sentFileTransfer
@@ -137,6 +152,7 @@ final class ChatComponentTests: XCTestCase {
 
     messagesPublisher.send(completion: .finished)
     fileTransfersPublisher.send(completion: .finished)
+    contactsPublisher.send(completion: .finished)
   }
 
   func testStartGroupChat() {
@@ -152,6 +168,8 @@ final class ChatComponentTests: XCTestCase {
 
     var didFetchMessagesWithQuery: [XXModels.Message.Query] = []
     let messagesPublisher = PassthroughSubject<[XXModels.Message], Error>()
+    var didFetchContactsWithQuery: [XXModels.Contact.Query] = []
+    let contactsPublisher = PassthroughSubject<[XXModels.Contact], Error>()
 
     store.dependencies.app.mainQueue = .immediate
     store.dependencies.app.bgQueue = .immediate
@@ -170,6 +188,10 @@ final class ChatComponentTests: XCTestCase {
         didFetchMessagesWithQuery.append(query)
         return messagesPublisher.eraseToAnyPublisher()
       }
+      db.fetchContactsPublisher.run = { query in
+        didFetchContactsWithQuery.append(query)
+        return contactsPublisher.eraseToAnyPublisher()
+      }
       return db
     }
 
@@ -180,6 +202,9 @@ final class ChatComponentTests: XCTestCase {
     XCTAssertNoDifference(didFetchMessagesWithQuery, [
       .init(chat: .group(groupId))
     ])
+    XCTAssertNoDifference(didFetchContactsWithQuery, [
+      .init(),
+    ])
 
     messagesPublisher.send([
       .init(
@@ -213,12 +238,18 @@ final class ChatComponentTests: XCTestCase {
         text: "Message 2"
       ),
     ])
+    contactsPublisher.send([
+      .init(id: myContactId, username: "My username"),
+      .init(id: firstMemberId, username: "First username"),
+      .init(id: secondMemberId, username: "Second username"),
+    ])
 
     let expectedMessages = IdentifiedArrayOf<ChatComponent.State.Message>(uniqueElements: [
       .init(
         id: 0,
         date: Date(timeIntervalSince1970: 0),
         senderId: myContactId,
+        senderName: "My username",
         text: "Message 0",
         status: .sent
       ),
@@ -226,6 +257,7 @@ final class ChatComponentTests: XCTestCase {
         id: 1,
         date: Date(timeIntervalSince1970: 1),
         senderId: firstMemberId,
+        senderName: "First username",
         text: "Message 1",
         status: .received
       ),
@@ -233,6 +265,7 @@ final class ChatComponentTests: XCTestCase {
         id: 2,
         date: Date(timeIntervalSince1970: 2),
         senderId: secondMemberId,
+        senderName: "Second username",
         text: "Message 2",
         status: .received
       ),
@@ -243,6 +276,7 @@ final class ChatComponentTests: XCTestCase {
     }
 
     messagesPublisher.send(completion: .finished)
+    contactsPublisher.send(completion: .finished)
   }
 
   func testStartFailure() {
-- 
GitLab