ConferenceRouteStore.swift 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. //
  2. // ConferenceRoute.swift
  3. // TUIRoomKit
  4. //
  5. // Created by aby on 2024/6/19.
  6. //
  7. import Combine
  8. protocol Route: ActionDispatcher {
  9. func initializeRoute(viewController: UIViewController, rootRoute: ConferenceRoute)
  10. func uninitialize()
  11. func pushTo(route: ConferenceRoute)
  12. func present(route: ConferenceRoute)
  13. func dismiss(animated: Bool)
  14. func pop()
  15. func popTo(route: ConferenceRoute)
  16. func pop(route: ConferenceRoute)
  17. func showContactView(delegate: ContactViewSelectDelegate, participants: ConferenceParticipants)
  18. }
  19. private let currentRouteActionSelector = Selector(keyPath: \ConferenceRouteState.currentRouteAction)
  20. class ConferenceRouter: NSObject {
  21. override init() {
  22. super.init()
  23. }
  24. // MARK: - private property.
  25. private var cancellableSet = Set<AnyCancellable>()
  26. private weak var navigationController: UINavigationController?
  27. private weak var rootViewController: UIViewController?
  28. private weak var navigationControllerDelegate: UINavigationControllerDelegate?
  29. private let store: Store<ConferenceRouteState, Void> = {
  30. let store = Store.init(initialState: ConferenceRouteState(), reducers: [routeReducer])
  31. #if DEBUG
  32. store.register(interceptor: PrintRouteInterceptor())
  33. #endif
  34. return store
  35. }()
  36. }
  37. extension ConferenceRouter: Route {
  38. func initializeRoute(viewController: UIViewController, rootRoute: ConferenceRoute) {
  39. guard self.rootViewController == nil else { return }
  40. self.rootViewController = viewController
  41. if let nav = viewController.navigationController {
  42. self.navigationController = nav
  43. if nav.delegate == nil {
  44. nav.delegate = self
  45. } else {
  46. self.navigationControllerDelegate = nav.delegate
  47. nav.delegate = self
  48. }
  49. } else {
  50. let navigationController = UINavigationController.init(rootViewController: viewController)
  51. self.navigationController = navigationController
  52. }
  53. store.dispatch(action: ConferenceNavigationAction.navigate(payload: ConferenceNavigation.presented(route: rootRoute)))
  54. let navigationPublisher = store.select(currentRouteActionSelector)
  55. subscribe(to: navigationPublisher)
  56. }
  57. func pushTo(route: ConferenceRoute) {
  58. store.dispatch(action: ConferenceNavigationAction.navigate(payload: .push(route: route)))
  59. }
  60. func present(route: ConferenceRoute) {
  61. store.dispatch(action: ConferenceNavigationAction.navigate(payload: .present(route: route)))
  62. }
  63. func dismiss(animated: Bool) {
  64. guard let viewController = self.navigationController?.topViewController ?? self.navigationController else { return }
  65. if let presentedViewController = viewController.presentedViewController {
  66. presentedViewController.dismiss(animated: animated) {
  67. [weak self] in
  68. guard let self = self else { return }
  69. if let rootVC = self.rootViewController {
  70. let viewRoute = ConferenceRoute.init(viewController: rootVC)
  71. self.store.dispatch(action: ConferenceNavigationAction.navigate(payload: ConferenceNavigation.presented(route: viewRoute)))
  72. }
  73. }
  74. }
  75. }
  76. func pop() {
  77. self.navigationController?.popViewController(animated: true)
  78. }
  79. func popTo(route: ConferenceRoute) {
  80. guard let viewControllers = self.navigationController?.viewControllers else { return }
  81. if let targetVC = viewControllers.first(where: { viewController in
  82. let iterateRoute = ConferenceRoute(viewController: viewController)
  83. return iterateRoute == route
  84. }) {
  85. self.navigationController?.popToViewController(targetVC, animated: false)
  86. }
  87. }
  88. func pop(route: ConferenceRoute) {
  89. guard var viewControllers = self.navigationController?.viewControllers else { return }
  90. if let index = viewControllers.firstIndex(where: { viewController in
  91. let iterateRoute = ConferenceRoute(viewController: viewController)
  92. return iterateRoute == route
  93. }) {
  94. viewControllers.remove(at: index)
  95. self.navigationController?.viewControllers = viewControllers
  96. }
  97. }
  98. func uninitialize() {
  99. if let delegate = self.navigationControllerDelegate {
  100. self.navigationController?.delegate = delegate
  101. }
  102. }
  103. func showContactView(delegate: ContactViewSelectDelegate, participants: ConferenceParticipants) {
  104. let selectParams = MemberSelectParams(participants: participants, delegate: delegate)
  105. store.dispatch(action: ConferenceNavigationAction.navigate(payload: .push(route: .selectMember(memberSelectParams: selectParams))))
  106. RoomKitReport.reportData(.metricsConferenceAttendee)
  107. }
  108. func dispatch(action: Action) {
  109. store.dispatch(action: action)
  110. }
  111. }
  112. extension ConferenceRouter {
  113. var viewController: UIViewController? {
  114. return navigationController ?? rootViewController
  115. }
  116. }
  117. extension ConferenceRouter {
  118. private func subscribe(to navigationPublisher: AnyPublisher<ConferenceNavigation, Never>) {
  119. navigationPublisher
  120. .receive(on: RunLoop.main)
  121. .removeDuplicates()
  122. .sink { [weak self] action in
  123. guard let self = self else { return }
  124. self.respond(to: action)
  125. }
  126. .store(in: &cancellableSet)
  127. }
  128. private func respond(to action: ConferenceNavigation) {
  129. switch action {
  130. case let .present(route: route):
  131. present(viewRoute: route)
  132. case let .push(route: route):
  133. push(viewRoute: route)
  134. case .presented:
  135. break
  136. }
  137. }
  138. private func present(viewRoute: ConferenceRoute) {
  139. guard let viewController = self.navigationController?.topViewController ?? self.navigationController else { return }
  140. if viewController.presentedViewController != nil {
  141. self.dismiss(animated: false)
  142. }
  143. var animated: Bool = true
  144. if case .invitation = viewRoute {
  145. animated = false
  146. }
  147. viewController.present(viewRoute.viewController, animated: animated) { [weak self] in
  148. guard let self = self else { return }
  149. self.store.dispatch(action: ConferenceNavigationAction.navigate(payload: ConferenceNavigation.presented(route: viewRoute)))
  150. }
  151. }
  152. private func push(viewRoute: ConferenceRoute) {
  153. guard let navigationController = self.navigationController else { return }
  154. navigationController.pushViewController(viewRoute.viewController, animated: true)
  155. }
  156. }
  157. extension ConferenceRouter {
  158. func toggleNavigationBar(for view: ConferenceRoute, animated: Bool, navigationController: UINavigationController) {
  159. if view.hideNavigationBar() {
  160. hideNavigationBar(navigationController: navigationController, animated: animated)
  161. }
  162. else {
  163. showNavigationBar(navigationController: navigationController, animated: animated)
  164. }
  165. }
  166. func hideNavigationBar(navigationController: UINavigationController, animated: Bool) {
  167. if animated {
  168. navigationController.transitionCoordinator?.animate(alongsideTransition: {
  169. context in
  170. navigationController.setNavigationBarHidden(true, animated: true)
  171. })
  172. }
  173. else {
  174. navigationController.setNavigationBarHidden(true, animated: false)
  175. }
  176. }
  177. func showNavigationBar(navigationController: UINavigationController, animated: Bool) {
  178. if navigationController.isNavigationBarHidden {
  179. if animated {
  180. navigationController.transitionCoordinator?.animate(alongsideTransition: {
  181. context in
  182. navigationController.setNavigationBarHidden(false, animated: true)
  183. })
  184. }
  185. else {
  186. navigationController.setNavigationBarHidden(false, animated: false)
  187. }
  188. }
  189. }
  190. }
  191. extension ConferenceRouter: UINavigationControllerDelegate {
  192. /// Animate the navigation bar display with view controller transition.
  193. func navigationController(
  194. _ navigationController: UINavigationController,
  195. willShow viewController: UIViewController,
  196. animated: Bool) {
  197. let destRoute = ConferenceRoute.init(viewController: viewController)
  198. guard destRoute != .none else { return }
  199. toggleNavigationBar(for: destRoute, animated: animated, navigationController: navigationController)
  200. }
  201. /// Trigger a `ConferenceNavigationAction` event according to the destination view type.
  202. func navigationController(
  203. _ navigationController: UINavigationController,
  204. didShow viewController: UIViewController,
  205. animated: Bool) {
  206. let destRoute = ConferenceRoute.init(viewController: viewController)
  207. guard destRoute != .none else { return }
  208. self.store.dispatch(action: ConferenceNavigationAction.navigate(payload: ConferenceNavigation.presented(route: destRoute)))
  209. }
  210. }