From feef7d794de2b8d2a667630335112c97015e7fad Mon Sep 17 00:00:00 2001 From: Justin Mazzocchi <2831158+jzzocc@users.noreply.github.com> Date: Tue, 6 Oct 2020 17:31:29 -0700 Subject: [PATCH] Refactoring --- View Controllers/ProfileViewController.swift | 4 +- View Controllers/TableViewController.swift | 58 ++++++++++++------- .../ViewModels/CollectionItemsViewModel.swift | 30 +++++----- .../ViewModels/CollectionViewModel.swift | 2 +- .../ViewModels/Entities/NavigationEvent.swift | 36 ------------ .../ViewModels/NavigationViewModel.swift | 4 +- .../Sources/ViewModels/ProfileViewModel.swift | 14 ++--- Views/TableView.swift | 3 +- 8 files changed, 68 insertions(+), 83 deletions(-) delete mode 100644 ViewModels/Sources/ViewModels/Entities/NavigationEvent.swift diff --git a/View Controllers/ProfileViewController.swift b/View Controllers/ProfileViewController.swift index 6702596..97f220d 100644 --- a/View Controllers/ProfileViewController.swift +++ b/View Controllers/ProfileViewController.swift @@ -8,10 +8,10 @@ final class ProfileViewController: TableViewController { private let viewModel: ProfileViewModel private var cancellables = Set() - required init(viewModel: ProfileViewModel) { + required init(viewModel: ProfileViewModel, identification: Identification) { self.viewModel = viewModel - super.init(viewModel: viewModel) + super.init(viewModel: viewModel, identification: identification) } override func viewDidLoad() { diff --git a/View Controllers/TableViewController.swift b/View Controllers/TableViewController.swift index ab8ae3e..663ddb3 100644 --- a/View Controllers/TableViewController.swift +++ b/View Controllers/TableViewController.swift @@ -7,6 +7,7 @@ import ViewModels class TableViewController: UITableViewController { private let viewModel: CollectionViewModel + private let identification: Identification private let loadingTableFooterView = LoadingTableFooterView() private let webfingerIndicatorView = WebfingerIndicatorView() private var cancellables = Set() @@ -37,8 +38,9 @@ class TableViewController: UITableViewController { } }() - init(viewModel: CollectionViewModel) { + init(viewModel: CollectionViewModel, identification: Identification) { self.viewModel = viewModel + self.identification = identification super.init(style: .plain) } @@ -183,25 +185,9 @@ private extension TableViewController { viewModel.sections.sink { [weak self] in self?.update(items: $0) }.store(in: &cancellables) - viewModel.navigationEvents.receive(on: DispatchQueue.main).sink { [weak self] in - guard let self = self else { return } - - switch $0 { - case let .share(url): - self.share(url: url) - case let .collectionNavigation(viewModel): - self.show(TableViewController(viewModel: viewModel), sender: self) - case let .profileNavigation(viewModel): - self.show(ProfileViewController(viewModel: viewModel), sender: self) - case let .urlNavigation(url): - self.present(SFSafariViewController(url: url), animated: true) - case .webfingerStart: - self.webfingerIndicatorView.startAnimating() - case .webfingerEnd: - self.webfingerIndicatorView.stopAnimating() - } - } - .store(in: &cancellables) + viewModel.events.receive(on: DispatchQueue.main) + .sink { [weak self] in self?.handle(event: $0) } + .store(in: &cancellables) viewModel.loading.receive(on: RunLoop.main).sink { [weak self] in guard let self = self else { return } @@ -246,6 +232,38 @@ private extension TableViewController { } } + func handle(event: CollectionItemEvent) { + switch event { + case .ignorableOutput: + break + case let .share(url): + share(url: url) + case let.navigation(navigation): + switch navigation { + case let .collection(collectionService): + show(TableViewController( + viewModel: CollectionItemsViewModel( + collectionService: collectionService, + identification: identification), + identification: identification), + sender: self) + case let .profile(profileService): + show(ProfileViewController( + viewModel: ProfileViewModel( + profileService: profileService, + identification: identification), + identification: identification), + sender: self) + case let .url(url): + present(SFSafariViewController(url: url), animated: true) + case .webfingerStart: + webfingerIndicatorView.startAnimating() + case .webfingerEnd: + webfingerIndicatorView.stopAnimating() + } + } + } + func share(url: URL) { let activityViewController = UIActivityViewController(activityItems: [url], applicationActivities: nil) diff --git a/ViewModels/Sources/ViewModels/CollectionItemsViewModel.swift b/ViewModels/Sources/ViewModels/CollectionItemsViewModel.swift index 3fa48e7..92f411e 100644 --- a/ViewModels/Sources/ViewModels/CollectionItemsViewModel.swift +++ b/ViewModels/Sources/ViewModels/CollectionItemsViewModel.swift @@ -12,15 +12,17 @@ final public class CollectionItemsViewModel: ObservableObject { private let items = CurrentValueSubject<[[CollectionItem]], Never>([]) private let collectionService: CollectionService + private let identification: Identification private var viewModelCache = [CollectionItem: (viewModel: CollectionItemViewModel, events: AnyCancellable)]() - private let navigationEventsSubject = PassthroughSubject() + private let eventsSubject = PassthroughSubject() private let loadingSubject = PassthroughSubject() private var topVisibleIndexPath = IndexPath(item: 0, section: 0) private var lastSelectedLoadMore: LoadMore? private var cancellables = Set() - init(collectionService: CollectionService) { + public init(collectionService: CollectionService, identification: Identification) { self.collectionService = collectionService + self.identification = identification collectionService.sections .handleEvents(receiveOutput: { [weak self] in self?.process(items: $0) }) @@ -46,7 +48,7 @@ extension CollectionItemsViewModel: CollectionViewModel { public var loading: AnyPublisher { loadingSubject.eraseToAnyPublisher() } - public var navigationEvents: AnyPublisher { navigationEventsSubject.eraseToAnyPublisher() } + public var events: AnyPublisher { eventsSubject.eraseToAnyPublisher() } public func request(maxId: String? = nil, minId: String? = nil) { collectionService.request(maxId: maxId, minId: minId) @@ -64,20 +66,18 @@ extension CollectionItemsViewModel: CollectionViewModel { switch item { case let .status(status, _): - navigationEventsSubject.send( - .collectionNavigation( - CollectionItemsViewModel( - collectionService: collectionService - .navigationService - .contextService(id: status.displayStatus.id)))) + eventsSubject.send( + .navigation(.collection(collectionService + .navigationService + .contextService(id: status.displayStatus.id)))) case let .loadMore(loadMore): lastSelectedLoadMore = loadMore (viewModel(indexPath: indexPath) as? LoadMoreViewModel)?.loadMore() case let .account(account): - navigationEventsSubject.send( - .profileNavigation( - ProfileViewModel( - profileService: collectionService.navigationService.profileService(account: account)))) + eventsSubject.send( + .navigation(.profile(collectionService + .navigationService + .profileService(account: account)))) } } @@ -142,9 +142,9 @@ extension CollectionItemsViewModel: CollectionViewModel { private extension CollectionItemsViewModel { func cache(viewModel: CollectionItemViewModel, forItem item: CollectionItem) { - viewModelCache[item] = (viewModel, viewModel.events.flatMap { $0.compactMap(NavigationEvent.init) } + viewModelCache[item] = (viewModel, viewModel.events.flatMap { $0 } .assignErrorsToAlertItem(to: \.alertItem, on: self) - .sink { [weak self] in self?.navigationEventsSubject.send($0) }) + .sink { [weak self] in self?.eventsSubject.send($0) }) } func process(items: [[CollectionItem]]) { diff --git a/ViewModels/Sources/ViewModels/CollectionViewModel.swift b/ViewModels/Sources/ViewModels/CollectionViewModel.swift index 5af1b69..884daa9 100644 --- a/ViewModels/Sources/ViewModels/CollectionViewModel.swift +++ b/ViewModels/Sources/ViewModels/CollectionViewModel.swift @@ -8,7 +8,7 @@ public protocol CollectionViewModel { var title: AnyPublisher { get } var alertItems: AnyPublisher { get } var loading: AnyPublisher { get } - var navigationEvents: AnyPublisher { get } + var events: AnyPublisher { get } var nextPageMaxId: String? { get } var maintainScrollPositionOfItem: CollectionItemIdentifier? { get } func request(maxId: String?, minId: String?) diff --git a/ViewModels/Sources/ViewModels/Entities/NavigationEvent.swift b/ViewModels/Sources/ViewModels/Entities/NavigationEvent.swift deleted file mode 100644 index b804457..0000000 --- a/ViewModels/Sources/ViewModels/Entities/NavigationEvent.swift +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright © 2020 Metabolist. All rights reserved. - -import Foundation - -public enum NavigationEvent { - case collectionNavigation(CollectionViewModel) - case profileNavigation(ProfileViewModel) - case urlNavigation(URL) - case share(URL) - case webfingerStart - case webfingerEnd -} - -extension NavigationEvent { - public init?(_ event: CollectionItemEvent) { - switch event { - case .ignorableOutput: - return nil - case let .navigation(item): - switch item { - case let .url(url): - self = .urlNavigation(url) - case let .collection(statusListService): - self = .collectionNavigation(CollectionItemsViewModel(collectionService: statusListService)) - case let .profile(profileService): - self = .profileNavigation(ProfileViewModel(profileService: profileService)) - case .webfingerStart: - self = .webfingerStart - case .webfingerEnd: - self = .webfingerEnd - } - case let .share(url): - self = .share(url) - } - } -} diff --git a/ViewModels/Sources/ViewModels/NavigationViewModel.swift b/ViewModels/Sources/ViewModels/NavigationViewModel.swift index 6b656b4..87d99cc 100644 --- a/ViewModels/Sources/ViewModels/NavigationViewModel.swift +++ b/ViewModels/Sources/ViewModels/NavigationViewModel.swift @@ -91,7 +91,9 @@ public extension NavigationViewModel { } func viewModel(timeline: Timeline) -> CollectionItemsViewModel { - CollectionItemsViewModel(collectionService: identification.service.service(timeline: timeline)) + CollectionItemsViewModel( + collectionService: identification.service.service(timeline: timeline), + identification: identification) } } diff --git a/ViewModels/Sources/ViewModels/ProfileViewModel.swift b/ViewModels/Sources/ViewModels/ProfileViewModel.swift index ac7a5d4..e43cc94 100644 --- a/ViewModels/Sources/ViewModels/ProfileViewModel.swift +++ b/ViewModels/Sources/ViewModels/ProfileViewModel.swift @@ -14,11 +14,13 @@ final public class ProfileViewModel { private let collectionViewModel: CurrentValueSubject private var cancellables = Set() - init(profileService: ProfileService) { + public init(profileService: ProfileService, identification: Identification) { self.profileService = profileService collectionViewModel = CurrentValueSubject( - CollectionItemsViewModel(collectionService: profileService.timelineService(profileCollection: .statuses))) + CollectionItemsViewModel( + collectionService: profileService.timelineService(profileCollection: .statuses), + identification: identification)) profileService.accountServicePublisher .map(AccountViewModel.init(accountService:)) @@ -27,7 +29,7 @@ final public class ProfileViewModel { $collection.dropFirst() .map(profileService.timelineService(profileCollection:)) - .map(CollectionItemsViewModel.init(collectionService:)) + .map { CollectionItemsViewModel(collectionService: $0, identification: identification) } .sink { [weak self] in guard let self = self else { return } @@ -55,14 +57,12 @@ extension ProfileViewModel: CollectionViewModel { collectionViewModel.flatMap(\.loading).eraseToAnyPublisher() } - public var navigationEvents: AnyPublisher { + public var events: AnyPublisher { $accountViewModel.compactMap { $0 } .flatMap(\.events) .flatMap { $0 } - .map(NavigationEvent.init) - .compactMap { $0 } .assignErrorsToAlertItem(to: \.alertItem, on: self) - .merge(with: collectionViewModel.flatMap(\.navigationEvents)) + .merge(with: collectionViewModel.flatMap(\.events)) .eraseToAnyPublisher() } diff --git a/Views/TableView.swift b/Views/TableView.swift index 6df605d..9d5fda3 100644 --- a/Views/TableView.swift +++ b/Views/TableView.swift @@ -4,10 +4,11 @@ import SwiftUI import ViewModels struct TableView: UIViewControllerRepresentable { + @EnvironmentObject var identification: Identification let viewModel: CollectionViewModel func makeUIViewController(context: Context) -> TableViewController { - TableViewController(viewModel: viewModel) + TableViewController(viewModel: viewModel, identification: identification) } func updateUIViewController(_ uiViewController: TableViewController, context: Context) {