diff --git a/chat-iOS/Model/Room.swift b/chat-iOS/Model/Room.swift index a8027d4..cd9db7d 100644 --- a/chat-iOS/Model/Room.swift +++ b/chat-iOS/Model/Room.swift @@ -4,10 +4,13 @@ // // Created by 戸高新也 on 2020/07/04. // +import Firebase struct Room: Codable { let name: String? let thumbnailImageURL: String? let members: [String] let message: String + @DocumentID var id: String? + @ServerTimestamp var updateAt: Timestamp? } diff --git a/chat-iOS/Views/Chats/ChatsViewBuilder.swift b/chat-iOS/Views/Chats/ChatsViewBuilder.swift index c00a20e..7efce0c 100644 --- a/chat-iOS/Views/Chats/ChatsViewBuilder.swift +++ b/chat-iOS/Views/Chats/ChatsViewBuilder.swift @@ -8,12 +8,12 @@ import UIKit struct ChatsViewBuilder { - static func create() -> UIViewController { + static func create(withRoomId roomId: String, withRoomName roomName: String) -> UIViewController { guard let chatsViewController = ChatsViewController.loadFromStoryboard() as? ChatsViewController else { fatalError("fatal: Failed to initialize the ChatsViewController") } let model = ChatsViewModel() - let presenter = ChatsViewPresenter(model: model) + let presenter = ChatsViewPresenter(model: model, withRoomId: roomId, withRoomName: roomName) chatsViewController.inject(with: presenter) return chatsViewController } diff --git a/chat-iOS/Views/Chats/ChatsViewController.swift b/chat-iOS/Views/Chats/ChatsViewController.swift index aca0a03..573760f 100644 --- a/chat-iOS/Views/Chats/ChatsViewController.swift +++ b/chat-iOS/Views/Chats/ChatsViewController.swift @@ -19,7 +19,7 @@ final class ChatsViewController: UIViewController, UICollectionViewDelegateFlowL @IBOutlet weak var sendButton: UIButton! var transScripts: [Transcript] = Array() - + let chatsCellID = "chatsCellID" override func viewDidLoad() { diff --git a/chat-iOS/Views/Chats/ChatsViewPresenter.swift b/chat-iOS/Views/Chats/ChatsViewPresenter.swift index d81630c..723d63f 100644 --- a/chat-iOS/Views/Chats/ChatsViewPresenter.swift +++ b/chat-iOS/Views/Chats/ChatsViewPresenter.swift @@ -20,9 +20,13 @@ protocol ChatsViewPresenterOutput: class { final class ChatsViewPresenter: ChatsViewPresenterProtocol, ChatsViewModelOutput { weak var view: ChatsViewPresenterOutput! private var model: ChatsViewModelProtocol + private var roomId: String + private var roomName: String - init(model: ChatsViewModelProtocol) { + init(model: ChatsViewModelProtocol, withRoomId roomId: String, withRoomName roomName: String) { self.model = model + self.roomId = roomId + self.roomName = roomName self.model.presenter = self } diff --git a/chat-iOS/Views/MainTabBar/MainTabBarViewController.swift b/chat-iOS/Views/MainTabBar/MainTabBarViewController.swift index ad3a78c..99936b7 100644 --- a/chat-iOS/Views/MainTabBar/MainTabBarViewController.swift +++ b/chat-iOS/Views/MainTabBar/MainTabBarViewController.swift @@ -21,10 +21,9 @@ final class MainTabBarViewController: UITabBarController { let userProfileVC = UserProfileViewBuilder.create() let userProfileNavigationController = UINavigationController(rootViewController: userProfileVC) - - //TODO:- ここはチャットセレクト画面に遷移すること - let chatsVC = ChatsViewBuilder.create() - let chatsNavigationController = UINavigationController(rootViewController: chatsVC) + + let selectChatVC = SelectChatViewBuilder.create() + let chatsNavigationController = UINavigationController(rootViewController: selectChatVC) //TODO:- iOS12以下の場合の画像を用意すること if #available(iOS 13.0, *) { @@ -35,7 +34,7 @@ final class MainTabBarViewController: UITabBarController { let userProfileTabBarItemSelectedImage = UIImage(systemName: "person.circle.fill") userProfileVC.tabBarItem = UITabBarItem(title: nil, image: userProfileTabBarItemImage, selectedImage: userProfileTabBarItemSelectedImage) - chatsVC.tabBarItem = UITabBarItem(title: nil, image: chatsTabBarItemImage, selectedImage: chatsTabBarItemSelectedImage) + selectChatVC.tabBarItem = UITabBarItem(title: nil, image: chatsTabBarItemImage, selectedImage: chatsTabBarItemSelectedImage) } else { // Fallback on earlier versions } diff --git a/chat-iOS/Views/SelectChat/SelectChatBuilder.swift b/chat-iOS/Views/SelectChat/SelectChatBuilder.swift new file mode 100644 index 0000000..d517bf4 --- /dev/null +++ b/chat-iOS/Views/SelectChat/SelectChatBuilder.swift @@ -0,0 +1,20 @@ +// +// SelectChatBuilder.swift +// chat-iOS +// +// Created by 松木周 on 2020/07/15. +// + +import UIKit + +struct SelectChatViewBuilder { + static func create() -> UIViewController { + guard let selectChatViewController = SelectChatViewController.loadFromStoryboard() as? SelectChatViewController else { + fatalError("fatal: Failed to initialize the ChatsViewController") + } + let model = SelectChatModel() + let presenter = SelectChatViewPresenter(model: model) + selectChatViewController.inject(with: presenter) + return selectChatViewController + } +} diff --git a/chat-iOS/Views/SelectChat/SelectChatModel.swift b/chat-iOS/Views/SelectChat/SelectChatModel.swift new file mode 100644 index 0000000..b1ef192 --- /dev/null +++ b/chat-iOS/Views/SelectChat/SelectChatModel.swift @@ -0,0 +1,67 @@ +// +// SelectChatModel.swift +// chat-iOS +// +// Created by 松木周 on 2020/07/15. +// + +import Firebase + +protocol SelectChatModelProtocol { + var presenter: SelectChatModelOutput! { get set } + func setUpFirestore() + func fetchCurrentChatRoom() +} + +protocol SelectChatModelOutput: class { + func successFetchCurrentChatRooms(currentChatRooms rooms: [Room]) + func onError(error: Error?) +} + +final class SelectChatModel: SelectChatModelProtocol { + + weak var presenter: SelectChatModelOutput! + private var firestore: Firestore! + private var listener: ListenerRegistration? + + init() { + self.setUpFirestore() + } + + deinit { + listener?.remove() + } + + func setUpFirestore() { + self.firestore = Firestore.firestore() + let settings = FirestoreSettings() + self.firestore.settings = settings + } + + func fetchCurrentChatRoom() { + + guard let curretnUserId = Auth.auth().currentUser?.uid else { return } + + self.listener = self.firestore.collection("rooms").whereField("members", arrayContains: curretnUserId).addSnapshotListener { [weak self] (documentSnapshot, error) in + + if let error = error { + self?.presenter.onError(error: error) + return + } + + guard let documents = documentSnapshot?.documents else { + print("The document doesn't exist.") + return + } + + let rooms = documents.compactMap { queryDocumentSnapshot -> Room? in + return try? queryDocumentSnapshot.data(as: Room.self) + } + + self?.presenter.successFetchCurrentChatRooms(currentChatRooms: rooms) + } + + } + +} + diff --git a/chat-iOS/Views/SelectChat/SelectChatTableViewCell.swift b/chat-iOS/Views/SelectChat/SelectChatTableViewCell.swift new file mode 100644 index 0000000..59d05c1 --- /dev/null +++ b/chat-iOS/Views/SelectChat/SelectChatTableViewCell.swift @@ -0,0 +1,34 @@ +// +// SelectChatTableViewCell.swift +// chat-iOS +// +// Created by 松木周 on 2020/07/15. +// + +import UIKit + +class SelectChatTableViewCell: UITableViewCell { + + @IBOutlet weak var userProfileImageView: UIImageView! + @IBOutlet weak var userNameLabel: UILabel! + @IBOutlet weak var lastMessageLabel: UILabel! + @IBOutlet weak var lastMessageTimeLabel: UILabel! + + override func awakeFromNib() { + super.awakeFromNib() + // Initialization code + } + + override func setSelected(_ selected: Bool, animated: Bool) { + super.setSelected(selected, animated: animated) + + // Configure the view for the selected state + } + + func generateCell(withRoom room: Room) { + userNameLabel.text = room.name + lastMessageLabel.text = room.name + //TODO:- Storageから画像を取得して表示する + } + +} diff --git a/chat-iOS/Views/SelectChat/SelectChatTableViewCell.xib b/chat-iOS/Views/SelectChat/SelectChatTableViewCell.xib new file mode 100644 index 0000000..876d957 --- /dev/null +++ b/chat-iOS/Views/SelectChat/SelectChatTableViewCell.xib @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/chat-iOS/Views/SelectChat/SelectChatViewController.swift b/chat-iOS/Views/SelectChat/SelectChatViewController.swift new file mode 100644 index 0000000..c2e24cb --- /dev/null +++ b/chat-iOS/Views/SelectChat/SelectChatViewController.swift @@ -0,0 +1,91 @@ +// +// SelectChatViewController.swift +// chat-iOS +// +// Created by 松木周 on 2020/07/15. +// + +import UIKit + +class SelectChatViewController: UIViewController { + + @IBOutlet weak var selectChatTableView: UITableView! + + private let reuseCellId = "SelectChatTableViewCell" + private var currentChatRooms: [Room] = [] + private var presenter: SelectChatViewPresenterProtocol! + + override func viewDidLoad() { + super.viewDidLoad() + + setupSelectChatTableView() + self.presenter.didLoadViewController() + } + + func inject(with presenter: SelectChatViewPresenterProtocol) { + + self.presenter = presenter + self.presenter.view = self + + } + + func setupSelectChatTableView() { + + self.selectChatTableView.delegate = self + self.selectChatTableView.dataSource = self + self.selectChatTableView.register(UINib(nibName: reuseCellId, bundle: nil), forCellReuseIdentifier: reuseCellId) + self.selectChatTableView.tableFooterView = UIView() + + } + +} + +extension SelectChatViewController: UITableViewDelegate { + + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + tableView.deselectRow(at: indexPath, animated: true) + let selectedRoom = currentChatRooms[indexPath.row] + self.presenter.didTapTableViewCell(selectedRoom: selectedRoom) + } + +} + +extension SelectChatViewController: UITableViewDataSource { + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return currentChatRooms.count + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: reuseCellId) as! SelectChatTableViewCell + cell.generateCell(withRoom: currentChatRooms[indexPath.row]) + return cell + } + +} + +extension SelectChatViewController: SelectChatViewPresenterOutput { + + func setCurrentChatUsers() { + self.currentChatRooms = self.presenter.currentChatRooms + self.selectChatTableView.reloadData() + } + + func showAlert(withMessage message: String) { + let alert = UIAlertController(title: "エラーが発生しました", message: message, preferredStyle: .alert) + let defaultAction: UIAlertAction = UIAlertAction(title: "OK", style: .default, handler: nil) + + alert.addAction(defaultAction) + present(alert, animated: false, completion: nil) + } + + func transitionToChatsViewController(selectedRoom room: Room) { + + guard let roomId = room.id else { return } + guard let roomName = room.name else { return } + let chatsViewController = ChatsViewBuilder.create(withRoomId: roomId, withRoomName: roomName) + self.navigationController?.pushViewController(chatsViewController, animated: true) + + } + +} diff --git a/chat-iOS/Views/SelectChat/SelectChatViewPresenter.swift b/chat-iOS/Views/SelectChat/SelectChatViewPresenter.swift new file mode 100644 index 0000000..594b98e --- /dev/null +++ b/chat-iOS/Views/SelectChat/SelectChatViewPresenter.swift @@ -0,0 +1,61 @@ +// +// SelectChatViewPresenter.swift +// chat-iOS +// +// Created by 松木周 on 2020/07/15. +// + +import Foundation + +protocol SelectChatViewPresenterProtocol { + var view: SelectChatViewPresenterOutput! { get set } + var currentChatRooms: [Room] { get } + func didLoadViewController() + func didTapTableViewCell(selectedRoom room: Room) +} + +protocol SelectChatViewPresenterOutput: class { + func setCurrentChatUsers() + func showAlert(withMessage message: String) + func transitionToChatsViewController(selectedRoom room: Room) +} + +final class SelectChatViewPresenter: SelectChatViewPresenterProtocol, SelectChatModelOutput { + + weak var view: SelectChatViewPresenterOutput! + private var model: SelectChatModelProtocol + + private(set) var _currentChatRooms: [Room] = [] + + init(model: SelectChatModelProtocol) { + self.model = model + self.model.presenter = self + } + + var currentChatRooms: [Room] { + return _currentChatRooms + } + + func didLoadViewController() { + self.model.fetchCurrentChatRoom() + } + + func successFetchCurrentChatRooms(currentChatRooms rooms: [Room]) { + self._currentChatRooms = rooms + self.view.setCurrentChatUsers() + } + + func onError(error: Error?) { + DispatchQueue.main.async { [weak self] in + let message = error?.localizedDescription ?? "チャット相手を取得できませんでした" + self?.view.showAlert(withMessage: message) + } + } + + func didTapTableViewCell(selectedRoom room: Room) { + DispatchQueue.main.async { [weak self] in + self?.view.transitionToChatsViewController(selectedRoom : room) + } + } + +} diff --git a/chat-iOS/Views/Storyboards/SelectChat.storyboard b/chat-iOS/Views/Storyboards/SelectChat.storyboard new file mode 100644 index 0000000..8f53afd --- /dev/null +++ b/chat-iOS/Views/Storyboards/SelectChat.storyboard @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +