ReportSection.swift 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. //
  2. // ReportSection.swift
  3. // Mastodon
  4. //
  5. // Created by ihugo on 2021/4/20.
  6. //
  7. import Combine
  8. import CoreData
  9. import CoreDataStack
  10. import Foundation
  11. import MastodonSDK
  12. import UIKit
  13. import os.log
  14. import MastodonAsset
  15. import MastodonCore
  16. import MastodonUI
  17. import MastodonLocalization
  18. enum ReportSection: Equatable, Hashable {
  19. case main
  20. }
  21. extension ReportSection {
  22. struct Configuration {
  23. let authContext: AuthContext
  24. }
  25. static func diffableDataSource(
  26. tableView: UITableView,
  27. context: AppContext,
  28. configuration: Configuration
  29. ) -> UITableViewDiffableDataSource<ReportSection, ReportItem> {
  30. tableView.register(ReportHeadlineTableViewCell.self, forCellReuseIdentifier: String(describing: ReportHeadlineTableViewCell.self))
  31. tableView.register(ReportStatusTableViewCell.self, forCellReuseIdentifier: String(describing: ReportStatusTableViewCell.self))
  32. tableView.register(ReportCommentTableViewCell.self, forCellReuseIdentifier: String(describing: ReportCommentTableViewCell.self))
  33. tableView.register(ReportResultActionTableViewCell.self, forCellReuseIdentifier: String(describing: ReportResultActionTableViewCell.self))
  34. tableView.register(TimelineBottomLoaderTableViewCell.self, forCellReuseIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self))
  35. return UITableViewDiffableDataSource(tableView: tableView) { tableView, indexPath, item -> UITableViewCell? in
  36. switch item {
  37. case .header(let headerContext):
  38. let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: ReportHeadlineTableViewCell.self), for: indexPath) as! ReportHeadlineTableViewCell
  39. cell.primaryLabel.text = headerContext.primaryLabelText
  40. cell.secondaryLabel.text = headerContext.secondaryLabelText
  41. return cell
  42. case .status(let record):
  43. let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: ReportStatusTableViewCell.self), for: indexPath) as! ReportStatusTableViewCell
  44. context.managedObjectContext.performAndWait {
  45. guard let status = record.object(in: context.managedObjectContext) else { return }
  46. configure(
  47. context: context,
  48. tableView: tableView,
  49. cell: cell,
  50. viewModel: .init(value: status),
  51. configuration: configuration
  52. )
  53. }
  54. return cell
  55. case .comment(let commentContext):
  56. let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: ReportCommentTableViewCell.self), for: indexPath) as! ReportCommentTableViewCell
  57. cell.commentTextView.text = commentContext.comment
  58. NotificationCenter.default.publisher(for: UITextView.textDidChangeNotification, object: cell.commentTextView)
  59. .receive(on: DispatchQueue.main)
  60. .sink { [weak cell] notification in
  61. guard let cell = cell else { return }
  62. commentContext.comment = cell.commentTextView.text
  63. // fix shadow get animation issue when cell height changes
  64. UIView.performWithoutAnimation {
  65. tableView.beginUpdates()
  66. tableView.endUpdates()
  67. }
  68. }
  69. .store(in: &cell.disposeBag)
  70. return cell
  71. case .result(let record):
  72. let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: ReportResultActionTableViewCell.self), for: indexPath) as! ReportResultActionTableViewCell
  73. context.managedObjectContext.performAndWait {
  74. guard let user = record.object(in: context.managedObjectContext) else { return }
  75. cell.avatarImageView.configure(configuration: .init(url: user.avatarImageURL()))
  76. }
  77. return cell
  78. case .bottomLoader:
  79. let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self), for: indexPath) as! TimelineBottomLoaderTableViewCell
  80. cell.activityIndicatorView.startAnimating()
  81. return cell
  82. }
  83. }
  84. }
  85. }
  86. extension ReportSection {
  87. static func configure(
  88. context: AppContext,
  89. tableView: UITableView,
  90. cell: ReportStatusTableViewCell,
  91. viewModel: ReportStatusTableViewCell.ViewModel,
  92. configuration: Configuration
  93. ) {
  94. StatusSection.setupStatusPollDataSource(
  95. context: context,
  96. authContext: configuration.authContext,
  97. statusView: cell.statusView
  98. )
  99. cell.statusView.viewModel.authContext = configuration.authContext
  100. cell.configure(
  101. tableView: tableView,
  102. viewModel: viewModel
  103. )
  104. }
  105. }