見出し画像

19日目、メッセージング機能の続き

メッセージング機能の続きを今日も行っていきます。昨日はUIを作成したのでFirebase関連のことを今日は実装していきます。

1.Messageモデルの作成

メッセージは以下の要素を持ちます。

無題の図形描画

toIdは送る先、fromIdは差出人、profileImageUrlは送る先の人の画像、usernameも送る先の人、isFromCurrentUserは差出人は現在ログインしているユーザかと言うことを示します。

なので以下のようになります。

struct Message {
   let text: String
   let toId: String
   let fromId: String
   var timestamp: Date?
   let profileImageUrl: String
   let isFromCurrentUser: Bool
   let username: String
   
   var chatPartnerId: String { return isFromCurrentUser ? toId : fromId }
   
   init(dictionary: [String: Any]) {
       self.text = dictionary["text"] as? String ?? ""
       self.toId = dictionary["toId"] as? String ?? ""
       self.fromId = dictionary["fromId"] as? String ?? ""
       self.isFromCurrentUser = fromId == Auth.auth().currentUser?.uid
       self.profileImageUrl = dictionary["profileImageUrl"] as? String ?? ""
       self.username = dictionary["username"] as? String ?? ""
       
       if let timestamp = dictionary["timestamp"] as? Double {
           self.timestamp = Date(timeIntervalSince1970: timestamp)
       }
   }
}

次にメッセージをアップロードする処理を書いていきます。

2.メッセージングのDB処理

DBの構造

無題の図形描画-2

メッセージのアップロード

処理の流れは以下のようになっています。

無題の図形描画-3

    static func uploadMessage(_ message: String, to user: User, completion: ((Error?) -> Void)?) {
       guard let currentUid = Auth.auth().currentUser?.uid else { return }
       
       let data = ["text": message,
                   "fromId": currentUid,
                   "toId": user.uid,
                   "timestamp": Timestamp(date: Date()),
                   "username": user.username,
                   "profileImageUrl": user.profileImageUrl] as [String : Any]
       
       COLLECTION_MESSAGES.document(currentUid).collection(user.uid).addDocument(data: data) { _ in
           COLLECTION_MESSAGES.document(user.uid).collection(currentUid).addDocument(data: data, completion: completion)
           COLLECTION_MESSAGES.document(currentUid).collection("recent-messages").document(user.uid).setData(data)
           
           COLLECTION_MESSAGES.document(user.uid).collection("recent-messages").document(currentUid).setData(data)
       }
   }

最新のメッセージの取得

この機能はメッセージのリスト(conversationController)で呼び出される機能です。処理は以下のようになっています。

無題の図形描画-4

    static func fetchRecentMessages(completion: @escaping([Message]) -> Void) {
       guard let uid = Auth.auth().currentUser?.uid else { return }
       
       let query = COLLECTION_MESSAGES.document(uid).collection("recent-messages").order(by: "timestamp")
       
       query.addSnapshotListener { (snapshot, error) in
           guard let documentChanges = snapshot?.documentChanges else { return }
           let messages = documentChanges.map({ Message(dictionary: $0.document.data()) })
           completion(messages)
       }
   }

メッセージの取得

この機能はトーク画面(chatController)にて呼び出される機能です。処理は以下のようになっています。

無題の図形描画-5

    static func fetchMessages(forUser user: User, completion: @escaping([Message]) -> Void) {
       guard let currentUid = Auth.auth().currentUser?.uid else { return }
       var messages = [Message]()
       let query = COLLECTION_MESSAGES.document(currentUid).collection(user.uid).order(by: "timestamp")
       
       query.addSnapshotListener { (snapshot, error) in
           guard let documentChanges = snapshot?.documentChanges.filter({ $0.type == .added }) else { return }
           messages.append(contentsOf: documentChanges.map({ Message(dictionary: $0.document.data()) }))
           completion(messages)
       }
   }

これをそれぞれのコントローラにて呼び出します。

3.ViewModelの作成

このアプリはMVVM構造で作成しているので次にviewにデータを渡す際のviewModelの設定をしていきます。

import UIKit
struct MessageViewModel {
   private let message: Message
   
   var messageBackgroundColor: UIColor { return message.isFromCurrentUser ? .Orange : .white }
   
   var messageBorderWidth: CGFloat { return message.isFromCurrentUser ? 0 : 1.0 }
   
   var rightAnchorActive: Bool { return message.isFromCurrentUser  }
   
   var leftAnchorActive: Bool {  return !message.isFromCurrentUser }
   
   var shouldHideProfileImage: Bool { return message.isFromCurrentUser }
   
   var messageText: String { return message.text }
   
   var username: String { return message.username }
   
   var profileImageUrl: URL? { return URL(string: message.profileImageUrl) }
   
   var timestampString: String? {
       guard let date = message.timestamp else { return nil }
       let dateFormatter = DateFormatter()
       dateFormatter.dateFormat = "hh:mm a"
       return dateFormatter.string(from: date)
   }
   
   init(message: Message) {
       self.message = message
   }
}

これで一通り、メッセージ機能に必要な要素が揃いました。

いよいよ明日は、これらの要素を用いてメッセージ機能の実装を行っていきます!

いいなと思ったら応援しよう!