LNIMOfficialMessageViewController.swift 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. //
  2. // LNIMOfficialMessageViewController.swift
  3. // Lanu
  4. //
  5. // Created by OneeChan on 2025/12/10.
  6. //
  7. import Foundation
  8. import UIKit
  9. import SnapKit
  10. extension UIView {
  11. func pushToOfficialMessage(uid: String) {
  12. let vc = LNIMOfficialMessageViewController(uid: uid)
  13. navigationController?.pushViewController(vc, animated: true)
  14. }
  15. }
  16. class LNIMOfficialMessageViewController: LNViewController {
  17. private let viewModel: LNIMChatViewModel
  18. private let tableView = UITableView()
  19. init(uid: String) {
  20. viewModel = LNIMChatViewModel(userId: LNIMOfficialIds.officialMessage.rawValue)
  21. super.init(nibName: nil, bundle: nil)
  22. }
  23. override func viewDidLoad() {
  24. super.viewDidLoad()
  25. setupViews()
  26. LNEventDeliver.addObserver(self)
  27. loadData()
  28. }
  29. override func viewWillDisappear(_ animated: Bool) {
  30. super.viewWillDisappear(animated)
  31. viewModel.cleanUnread()
  32. }
  33. required init?(coder: NSCoder) {
  34. fatalError("init(coder:) has not been implemented")
  35. }
  36. }
  37. extension LNIMOfficialMessageViewController {
  38. private func loadData() {
  39. viewModel.loadNextPage { [weak self] success, isFirst in
  40. guard let self else { return }
  41. guard success else { return }
  42. let oldHeight = tableView.contentSize.height
  43. tableView.reloadData()
  44. if isFirst {
  45. tableView.scrollToBottom(animated: false)
  46. } else {
  47. tableView.layoutIfNeeded()
  48. let newOffset = tableView.contentSize.height - oldHeight
  49. tableView.scrollRectToVisible(
  50. .init(x: 0, y: newOffset,
  51. width: tableView.bounds.width,
  52. height: tableView.bounds.height),
  53. animated: false)
  54. }
  55. }
  56. }
  57. }
  58. extension LNIMOfficialMessageViewController: LNIMChatViewModelNotify {
  59. func onIMMessageDataChanged(viewModel: LNIMChatViewModel, index: Int, type: LNIMChatDataSourceChangeType, toBottom: Bool) {
  60. guard viewModel.userId == self.viewModel.userId else { return }
  61. switch type {
  62. case .insert: tableView.reloadData()
  63. case .delete: tableView.reloadData()
  64. case .reload: tableView.reloadRows(at: [.init(row: index, section: 0)], with: .fade)
  65. }
  66. if toBottom {
  67. tableView.scrollToBottom()
  68. }
  69. }
  70. func onIMMessageDatasChanged(viewModel: LNIMChatViewModel, indexs: [IndexPath], type: LNIMChatDataSourceChangeType, toBottom: Bool) {
  71. guard viewModel.userId == self.viewModel.userId else { return }
  72. switch type {
  73. case .insert: tableView.reloadData()
  74. case .delete: tableView.reloadData()
  75. case .reload: tableView.reloadRows(at: indexs, with: .fade)
  76. }
  77. if toBottom {
  78. tableView.scrollToBottom()
  79. }
  80. }
  81. }
  82. extension LNIMOfficialMessageViewController: UITableViewDataSource, UITableViewDelegate {
  83. func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
  84. viewModel.allMessage.count
  85. }
  86. func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
  87. let data = viewModel.allMessage[indexPath.row]
  88. switch data.type {
  89. case .system:
  90. let cell = tableView.dequeueReusableCell(withIdentifier: LNIMChatSystemMessageCell.className, for: indexPath) as! LNIMChatSystemMessageCell
  91. cell.update(data)
  92. return cell
  93. case .official:
  94. if let message: LNIMOfficialMessage = data.decodeCustomMessage() {
  95. let cell = tableView.dequeueReusableCell(withIdentifier: LNIMOfficialMessageCell.className, for: indexPath) as! LNIMOfficialMessageCell
  96. cell.update(message)
  97. return cell
  98. }
  99. default :
  100. break
  101. }
  102. return tableView.dequeueReusableCell(withIdentifier: LNIMChatUnknownMessageCell.className, for: indexPath)
  103. }
  104. func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
  105. guard scrollView == tableView else { return }
  106. if tableView.contentOffset.y <= 0 {
  107. loadData()
  108. }
  109. }
  110. func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
  111. guard scrollView == tableView else { return }
  112. if tableView.contentOffset.y <= 0 {
  113. loadData()
  114. }
  115. }
  116. }
  117. extension LNIMOfficialMessageViewController {
  118. private func setupViews() {
  119. view.backgroundColor = .primary_1
  120. title = viewModel.userId == LNIMOfficialIds.officialMessage.rawValue ? .init(key: "A00091") : .init(key: "A00099")
  121. tableView.backgroundColor = .clear
  122. tableView.separatorStyle = .none
  123. tableView.allowsSelection = false
  124. tableView.register(LNIMOfficialMessageCell.self, forCellReuseIdentifier: LNIMOfficialMessageCell.className)
  125. tableView.register(LNIMChatSystemMessageCell.self, forCellReuseIdentifier: LNIMChatSystemMessageCell.className)
  126. tableView.register(LNIMChatUnknownMessageCell.self, forCellReuseIdentifier: LNIMChatUnknownMessageCell.className)
  127. tableView.dataSource = self
  128. tableView.delegate = self
  129. view.addSubview(tableView)
  130. tableView.snp.makeConstraints { make in
  131. make.horizontalEdges.equalToSuperview()
  132. make.top.equalToSuperview()
  133. make.bottom.equalTo(view.safeAreaLayoutGuide.snp.bottom)
  134. }
  135. }
  136. }