// // LNIMOfficialMessageViewController.swift // Lanu // // Created by OneeChan on 2025/12/10. // import Foundation import UIKit import SnapKit extension UIView { func pushToOfficialMessage(uid: String) { let vc = LNIMOfficialMessageViewController(uid: uid) navigationController?.pushViewController(vc, animated: true) } } class LNIMOfficialMessageViewController: LNViewController { private let viewModel: LNIMChatViewModel private let tableView = UITableView() init(uid: String) { viewModel = LNIMChatViewModel(userId: LNIMOfficialIds.officialMessage.rawValue) super.init(nibName: nil, bundle: nil) } override func viewDidLoad() { super.viewDidLoad() setupViews() LNEventDeliver.addObserver(self) loadData() } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) viewModel.cleanUnread() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } } extension LNIMOfficialMessageViewController { private func loadData() { viewModel.loadNextPage { [weak self] success, isFirst in guard let self else { return } guard success else { return } let oldHeight = tableView.contentSize.height tableView.reloadData() if isFirst { tableView.scrollToBottom(animated: false) } else { tableView.layoutIfNeeded() let newOffset = tableView.contentSize.height - oldHeight tableView.scrollRectToVisible( .init(x: 0, y: newOffset, width: tableView.bounds.width, height: tableView.bounds.height), animated: false) } } } } extension LNIMOfficialMessageViewController: LNIMChatViewModelNotify { func onIMMessageDataChanged(viewModel: LNIMChatViewModel, index: Int, type: LNIMChatDataSourceChangeType, toBottom: Bool) { guard viewModel.userId == self.viewModel.userId else { return } switch type { case .insert: tableView.reloadData() case .delete: tableView.reloadData() case .reload: tableView.reloadRows(at: [.init(row: index, section: 0)], with: .fade) } if toBottom { tableView.scrollToBottom() } } func onIMMessageDatasChanged(viewModel: LNIMChatViewModel, indexs: [IndexPath], type: LNIMChatDataSourceChangeType, toBottom: Bool) { guard viewModel.userId == self.viewModel.userId else { return } switch type { case .insert: tableView.reloadData() case .delete: tableView.reloadData() case .reload: tableView.reloadRows(at: indexs, with: .fade) } if toBottom { tableView.scrollToBottom() } } } extension LNIMOfficialMessageViewController: UITableViewDataSource, UITableViewDelegate { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { viewModel.allMessage.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let data = viewModel.allMessage[indexPath.row] switch data.type { case .system: let cell = tableView.dequeueReusableCell(withIdentifier: LNIMChatSystemMessageCell.className, for: indexPath) as! LNIMChatSystemMessageCell cell.update(data) return cell case .official: if let message: LNIMOfficialMessage = data.decodeCustomMessage() { let cell = tableView.dequeueReusableCell(withIdentifier: LNIMOfficialMessageCell.className, for: indexPath) as! LNIMOfficialMessageCell cell.update(message) return cell } default : break } return tableView.dequeueReusableCell(withIdentifier: LNIMChatUnknownMessageCell.className, for: indexPath) } func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { guard scrollView == tableView else { return } if tableView.contentOffset.y <= 0 { loadData() } } func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) { guard scrollView == tableView else { return } if tableView.contentOffset.y <= 0 { loadData() } } } extension LNIMOfficialMessageViewController { private func setupViews() { view.backgroundColor = .primary_1 title = viewModel.userId == LNIMOfficialIds.officialMessage.rawValue ? .init(key: "A00091") : .init(key: "A00099") tableView.backgroundColor = .clear tableView.separatorStyle = .none tableView.allowsSelection = false tableView.register(LNIMOfficialMessageCell.self, forCellReuseIdentifier: LNIMOfficialMessageCell.className) tableView.register(LNIMChatSystemMessageCell.self, forCellReuseIdentifier: LNIMChatSystemMessageCell.className) tableView.register(LNIMChatUnknownMessageCell.self, forCellReuseIdentifier: LNIMChatUnknownMessageCell.className) tableView.dataSource = self tableView.delegate = self view.addSubview(tableView) tableView.snp.makeConstraints { make in make.horizontalEdges.equalToSuperview() make.top.equalToSuperview() make.bottom.equalTo(view.safeAreaLayoutGuide.snp.bottom) } } }