diff --git a/Modules/Sources/ChatFeature/Scenes/ChatRoomList/ChatRoomListViewController.swift b/Modules/Sources/ChatFeature/Scenes/ChatRoomList/ChatRoomListViewController.swift index c3935dd..939b57c 100644 --- a/Modules/Sources/ChatFeature/Scenes/ChatRoomList/ChatRoomListViewController.swift +++ b/Modules/Sources/ChatFeature/Scenes/ChatRoomList/ChatRoomListViewController.swift @@ -1,8 +1,9 @@ import Core +import SwiftUI import UIKit public final class ChatRoomListViewController: UIViewController, ChatRoomListView, - DependencyInjectable, UICollectionViewDelegate + DependencyInjectable { // MARK: - DependencyInjectable @@ -22,16 +23,7 @@ public final class ChatRoomListViewController: UIViewController, ChatRoomListVie // MARK: - ChatRoomListView public func show(chatRooms: [ChatRoomList.ChatRoom]) { - self.chatRooms = chatRooms - } - - // MARK: - UICollectionViewDelegate - - public func collectionView( - _ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath - ) { - collectionView.deselectItem(at: indexPath, animated: true) - dependency.presenter.didSelectChatRoom(chatRoomId: chatRooms[indexPath.item].id) + self.state.chatRooms = chatRooms } // MARK: - Override @@ -46,19 +38,19 @@ public final class ChatRoomListViewController: UIViewController, ChatRoomListVie }), menu: nil) - chatRoomList.view.translatesAutoresizingMaskIntoConstraints = false - view.addSubview(chatRoomList.view) + hostringController.view.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(hostringController.view) NSLayoutConstraint.activate([ - chatRoomList.view.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), - chatRoomList.view.leadingAnchor.constraint( + hostringController.view.topAnchor.constraint( + equalTo: view.safeAreaLayoutGuide.topAnchor), + hostringController.view.leadingAnchor.constraint( equalTo: view.safeAreaLayoutGuide.leadingAnchor), - chatRoomList.view.trailingAnchor.constraint( + hostringController.view.trailingAnchor.constraint( equalTo: view.safeAreaLayoutGuide.trailingAnchor), - chatRoomList.view.bottomAnchor.constraint( + hostringController.view.bottomAnchor.constraint( equalTo: view.safeAreaLayoutGuide.bottomAnchor), ]) - updateChatRoomListView() dependency.presenter.viewDidLoad() } @@ -90,55 +82,11 @@ public final class ChatRoomListViewController: UIViewController, ChatRoomListVie private var dependency: Dependency! - private var chatRooms: [ChatRoomList.ChatRoom] = [] { - didSet { updateChatRoomListView() } - } + private let state = ChatRoomListViewSwiftUIState() - private lazy var chatRoomList: - ( - view: UICollectionView, - dataSource: UICollectionViewDiffableDataSource - ) = { - let config = UICollectionLayoutListConfiguration(appearance: .plain) - let layout = UICollectionViewCompositionalLayout.list(using: config) - let view = UICollectionView(frame: .zero, collectionViewLayout: layout) - view.delegate = self - - let cellRegistration = UICollectionView - .CellRegistration { - cell, indexPath, room in - var content = cell.defaultContentConfiguration() - content.text = room.name - content.textProperties.font = .boldSystemFont(ofSize: 17) - content.secondaryText = "\(room.updatedAt) (\(room.userCount) users)" - cell.contentConfiguration = content - cell.accessories.removeAll() - if room.unreadCount > 0 { - cell.accessories.append(.label(text: "\((room.unreadCount))")) - } - cell.accessories.append(.disclosureIndicator()) - } - - let dataSource = UICollectionViewDiffableDataSource( - collectionView: view, - cellProvider: { collectionView, indexPath, item -> UICollectionViewCell? in - collectionView.dequeueConfiguredReusableCell( - using: cellRegistration, for: indexPath, item: item) - }) - - return (view, dataSource) - }() - - private enum Section { - case main - } - - private func updateChatRoomListView() { - var snapshot = NSDiffableDataSourceSnapshot() - snapshot.appendSections([.main]) - snapshot.appendItems(chatRooms, toSection: .main) - chatRoomList.dataSource.apply(snapshot, animatingDifferences: true) - } + private lazy var hostringController = UIHostingController( + rootView: ChatRoomListViewSwiftUIView(state: state, presentation: dependency.presenter) + ) } // MARK: - Preview diff --git a/Modules/Sources/ChatFeature/Scenes/ChatRoomList/ChatRoomListViewSwiftUIView.swift b/Modules/Sources/ChatFeature/Scenes/ChatRoomList/ChatRoomListViewSwiftUIView.swift new file mode 100644 index 0000000..1b1d072 --- /dev/null +++ b/Modules/Sources/ChatFeature/Scenes/ChatRoomList/ChatRoomListViewSwiftUIView.swift @@ -0,0 +1,63 @@ +import SwiftUI + +class ChatRoomListViewSwiftUIState: ObservableObject { + @Published var chatRooms: [ChatRoomList.ChatRoom] + + init(chatRooms: [ChatRoomList.ChatRoom] = []) { + self.chatRooms = chatRooms + } +} + +struct ChatRoomListViewSwiftUIView: View { + @ObservedObject var state: ChatRoomListViewSwiftUIState + weak var presentation: ChatRoomListPresentation? + + init(state: ChatRoomListViewSwiftUIState, presentation: ChatRoomListPresentation? = nil) { + self.state = state + self.presentation = presentation + } + + var body: some View { + List(state.chatRooms, id: \.id) { chatRoom in + Button( + action: { presentation?.didSelectChatRoom(chatRoomId: chatRoom.id) }, + label: { + HStack(alignment: .center, spacing: 8) { + VStack(alignment: .leading, spacing: 4) { + Text("\(chatRoom.name)") + .font(.headline) + Text( + "\(dateFormatter.string(from: chatRoom.updatedAt)) (\(chatRoom.userCount) users)" + ) + .font(.caption) + } + Spacer() + if chatRoom.unreadCount > 0 { + Text("\(chatRoom.unreadCount)") + .foregroundColor(.secondary) + } + Image(systemName: "chevron.right") + .foregroundColor(.secondary) + } + } + ) + }.listStyle(.plain) + } + + private let dateFormatter = ISO8601DateFormatter() +} + +struct ChatRoomListViewSwiftUIView_Previews: PreviewProvider { + static var previews: some View { + ChatRoomListViewSwiftUIView( + state: .init( + chatRooms: (1...10).map { + .init( + id: $0, name: "Room \($0)", userCount: 1 + $0, unreadCount: $0 - 1, + updatedAt: .init()) + } + ) + ) + .previewLayout(.device) + } +} diff --git a/Modules/Sources/ChatUseCase/SubscribeChatRoomsUseCase.swift b/Modules/Sources/ChatUseCase/SubscribeChatRoomsUseCase.swift index 89bc5c4..7c324c2 100644 --- a/Modules/Sources/ChatUseCase/SubscribeChatRoomsUseCase.swift +++ b/Modules/Sources/ChatUseCase/SubscribeChatRoomsUseCase.swift @@ -7,7 +7,7 @@ public typealias SubscribeChatRoomsUseCase = AnyPublisherUseCase< > public struct SubscribeChatRoomsUseCaseOutput: Equatable { - public struct ChatRoom: Hashable { + public struct ChatRoom: Hashable, Identifiable { public let id: Int public let name: String public let userCount: Int