Refactoring

This commit is contained in:
Justin Mazzocchi 2020-09-09 15:48:56 -07:00
parent 4c1f0e2452
commit 182ecb5b91
No known key found for this signature in database
GPG key ID: E223E6937AAFB01C
8 changed files with 58 additions and 55 deletions

View file

@ -47,7 +47,7 @@ public extension RootViewModel {
} }
public extension Identification { public extension Identification {
static let preview = RootViewModel.preview.identification! static let preview = RootViewModel.preview.navigationViewModel!.identification
} }
// swiftlint:enable force_try // swiftlint:enable force_try

View file

@ -5,7 +5,7 @@ import Foundation
import ServiceLayer import ServiceLayer
public final class Identification: ObservableObject { public final class Identification: ObservableObject {
@Published private(set) var identity: Identity @Published private(set) public var identity: Identity
let service: IdentityService let service: IdentityService
init(identity: Identity, observation: AnyPublisher<Identity, Never>, service: IdentityService) { init(identity: Identity, observation: AnyPublisher<Identity, Never>, service: IdentityService) {

View file

@ -5,24 +5,7 @@ import Foundation
import ServiceLayer import ServiceLayer
public final class RootViewModel: ObservableObject { public final class RootViewModel: ObservableObject {
@Published public private(set) var identification: Identification? { @Published public private(set) var navigationViewModel: TabNavigationViewModel?
didSet {
guard let identification = identification else { return }
identification.service.updateLastUse()
.sink { _ in } receiveValue: { _ in }
.store(in: &cancellables)
userNotificationService.isAuthorized()
.filter { $0 }
.zip(registerForRemoteNotifications())
.filter { identification.identity.lastRegisteredDeviceToken != $1 }
.map { ($1, identification.identity.pushSubscriptionAlerts) }
.flatMap(identification.service.createPushSubscription(deviceToken:alerts:))
.sink { _ in } receiveValue: { _ in }
.store(in: &cancellables)
}
}
@Published private var mostRecentlyUsedIdentityID: UUID? @Published private var mostRecentlyUsedIdentityID: UUID?
private let environment: AppEnvironment private let environment: AppEnvironment
@ -74,10 +57,12 @@ public extension RootViewModel {
private extension RootViewModel { private extension RootViewModel {
func identitySelected(id: UUID?, immediate: Bool) { func identitySelected(id: UUID?, immediate: Bool) {
navigationViewModel?.presentingSecondaryNavigation = false
guard guard
let id = id, let id = id,
let identityService = try? allIdentitiesService.identityService(id: id) else { let identityService = try? allIdentitiesService.identityService(id: id) else {
identification = nil navigationViewModel = nil
return return
} }
@ -93,13 +78,30 @@ private extension RootViewModel {
.share() .share()
observation observation
.filter { [weak self] in $0.id != self?.identification?.identity.id } .filter { [weak self] in $0.id != self?.navigationViewModel?.identification.identity.id }
.map { .map { [weak self] in
Identification( let identification = Identification(
identity: $0, identity: $0,
observation: observation.eraseToAnyPublisher(), observation: observation.eraseToAnyPublisher(),
service: identityService) service: identityService)
if let self = self {
identification.service.updateLastUse()
.sink { _ in } receiveValue: { _ in }
.store(in: &self.cancellables)
self.userNotificationService.isAuthorized()
.filter { $0 }
.zip(self.registerForRemoteNotifications())
.filter { identification.identity.lastRegisteredDeviceToken != $1 }
.map { ($1, identification.identity.pushSubscriptionAlerts) }
.flatMap(identification.service.createPushSubscription(deviceToken:alerts:))
.sink { _ in } receiveValue: { _ in }
.store(in: &self.cancellables)
}
return TabNavigationViewModel(identification: identification)
} }
.assign(to: &$identification) .assign(to: &$navigationViewModel)
} }
} }

View file

@ -6,7 +6,7 @@ import Mastodon
import ServiceLayer import ServiceLayer
public final class TabNavigationViewModel: ObservableObject { public final class TabNavigationViewModel: ObservableObject {
@Published public private(set) var identity: Identity public let identification: Identification
@Published public private(set) var recentIdentities = [Identity]() @Published public private(set) var recentIdentities = [Identity]()
@Published public var timeline: Timeline @Published public var timeline: Timeline
@Published public private(set) var timelinesAndLists: [Timeline] @Published public private(set) var timelinesAndLists: [Timeline]
@ -14,18 +14,19 @@ public final class TabNavigationViewModel: ObservableObject {
@Published public var alertItem: AlertItem? @Published public var alertItem: AlertItem?
public var selectedTab: Tab? = .timelines public var selectedTab: Tab? = .timelines
private let identification: Identification
private var cancellables = Set<AnyCancellable>() private var cancellables = Set<AnyCancellable>()
public init(identification: Identification) { public init(identification: Identification) {
self.identification = identification self.identification = identification
identity = identification.identity
timeline = identification.service.isAuthorized ? .home : .local timeline = identification.service.isAuthorized ? .home : .local
timelinesAndLists = identification.service.isAuthorized timelinesAndLists = identification.service.isAuthorized
? Timeline.authenticatedDefaults ? Timeline.authenticatedDefaults
: Timeline.unauthenticatedDefaults : Timeline.unauthenticatedDefaults
identification.$identity.dropFirst().assign(to: &$identity) identification.$identity
.sink { [weak self] _ in self?.objectWillChange.send() }
.store(in: &cancellables)
identification.service.recentIdentitiesObservation() identification.service.recentIdentitiesObservation()
.assignErrorsToAlertItem(to: \.alertItem, on: self) .assignErrorsToAlertItem(to: \.alertItem, on: self)
.assign(to: &$recentIdentities) .assign(to: &$recentIdentities)
@ -51,9 +52,9 @@ public extension TabNavigationViewModel {
var timelineSubtitle: String { var timelineSubtitle: String {
switch timeline { switch timeline {
case .home, .list: case .home, .list:
return identity.handle return identification.identity.handle
case .local, .federated, .tag: case .local, .federated, .tag:
return identity.instance?.uri ?? "" return identification.identity.instance?.uri ?? ""
} }
} }
@ -72,7 +73,7 @@ public extension TabNavigationViewModel {
.sink { _ in } .sink { _ in }
.store(in: &cancellables) .store(in: &cancellables)
if identity.preferences.useServerPostingReadingPreferences { if identification.identity.preferences.useServerPostingReadingPreferences {
identification.service.refreshServerPreferences() identification.service.refreshServerPreferences()
.assignErrorsToAlertItem(to: \.alertItem, on: self) .assignErrorsToAlertItem(to: \.alertItem, on: self)
.sink { _ in } .sink { _ in }

View file

@ -5,7 +5,7 @@ import ViewModels
struct ListsView: View { struct ListsView: View {
@StateObject var viewModel: ListsViewModel @StateObject var viewModel: ListsViewModel
@EnvironmentObject var tabNavigationViewModel: TabNavigationViewModel @EnvironmentObject var rootViewModel: RootViewModel
@State private var newListTitle = "" @State private var newListTitle = ""
var body: some View { var body: some View {
@ -28,8 +28,8 @@ struct ListsView: View {
Section { Section {
ForEach(viewModel.lists) { list in ForEach(viewModel.lists) { list in
Button(list.title) { Button(list.title) {
tabNavigationViewModel.timeline = .list(list) rootViewModel.navigationViewModel?.timeline = .list(list)
tabNavigationViewModel.presentingSecondaryNavigation = false rootViewModel.navigationViewModel?.presentingSecondaryNavigation = false
} }
} }
.onDelete { .onDelete {

View file

@ -7,11 +7,9 @@ struct RootView: View {
@StateObject var viewModel: RootViewModel @StateObject var viewModel: RootViewModel
var body: some View { var body: some View {
if let identification = viewModel.identification { if let navigationViewModel = viewModel.navigationViewModel {
TabNavigationView() TabNavigationView(viewModel: navigationViewModel)
.id(UUID()) .id(navigationViewModel.identification.identity.id)
.environmentObject(identification)
.environmentObject(TabNavigationViewModel(identification: identification))
.environmentObject(viewModel) .environmentObject(viewModel)
.transition(.opacity) .transition(.opacity)
} else { } else {

View file

@ -5,8 +5,9 @@ import SwiftUI
import ViewModels import ViewModels
struct SecondaryNavigationView: View { struct SecondaryNavigationView: View {
@ObservedObject var viewModel: TabNavigationViewModel
@EnvironmentObject var identification: Identification @EnvironmentObject var identification: Identification
@EnvironmentObject var tabNavigationViewModel: TabNavigationViewModel @EnvironmentObject var rootViewModel: RootViewModel
@Environment(\.displayScale) var displayScale: CGFloat @Environment(\.displayScale) var displayScale: CGFloat
var body: some View { var body: some View {
@ -17,25 +18,25 @@ struct SecondaryNavigationView: View {
destination: IdentitiesView(viewModel: .init(identification: identification)), destination: IdentitiesView(viewModel: .init(identification: identification)),
label: { label: {
HStack { HStack {
KFImage(tabNavigationViewModel.identity.image, KFImage(identification.identity.image,
options: .downsampled(dimension: 50, scaleFactor: displayScale)) options: .downsampled(dimension: 50, scaleFactor: displayScale))
VStack(alignment: .leading) { VStack(alignment: .leading) {
if tabNavigationViewModel.identity.authenticated { if identification.identity.authenticated {
if let account = tabNavigationViewModel.identity.account { if let account = identification.identity.account {
CustomEmojiText( CustomEmojiText(
text: account.displayName, text: account.displayName,
emoji: account.emojis, emoji: account.emojis,
textStyle: .headline) textStyle: .headline)
} }
Text(tabNavigationViewModel.identity.handle) Text(identification.identity.handle)
.font(.subheadline) .font(.subheadline)
.foregroundColor(.secondary) .foregroundColor(.secondary)
.lineLimit(1) .lineLimit(1)
.minimumScaleFactor(0.5) .minimumScaleFactor(0.5)
} else { } else {
Text(tabNavigationViewModel.identity.handle) Text(identification.identity.handle)
.font(.headline) .font(.headline)
if let instance = tabNavigationViewModel.identity.instance { if let instance = identification.identity.instance {
Text(instance.uri) Text(instance.uri)
.font(.subheadline) .font(.subheadline)
.foregroundColor(.secondary) .foregroundColor(.secondary)
@ -68,7 +69,7 @@ struct SecondaryNavigationView: View {
.toolbar { .toolbar {
ToolbarItem(placement: .cancellationAction) { ToolbarItem(placement: .cancellationAction) {
Button { Button {
tabNavigationViewModel.presentingSecondaryNavigation = false viewModel.presentingSecondaryNavigation = false
} label: { } label: {
Image(systemName: "xmark.circle.fill") Image(systemName: "xmark.circle.fill")
} }
@ -84,9 +85,9 @@ import PreviewViewModels
struct SecondaryNavigationView_Previews: PreviewProvider { struct SecondaryNavigationView_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
SecondaryNavigationView() SecondaryNavigationView(viewModel: TabNavigationViewModel(identification: .preview))
.environmentObject(Identification.preview) .environmentObject(Identification.preview)
.environmentObject(TabNavigationViewModel(identification: .preview)) .environmentObject(RootViewModel.preview)
} }
} }
#endif #endif

View file

@ -6,7 +6,7 @@ import SwiftUI
import ViewModels import ViewModels
struct TabNavigationView: View { struct TabNavigationView: View {
@EnvironmentObject var viewModel: TabNavigationViewModel @ObservedObject var viewModel: TabNavigationViewModel
@EnvironmentObject var rootViewModel: RootViewModel @EnvironmentObject var rootViewModel: RootViewModel
@Environment(\.displayScale) var displayScale: CGFloat @Environment(\.displayScale) var displayScale: CGFloat
@ -24,8 +24,10 @@ struct TabNavigationView: View {
.tag(tab) .tag(tab)
} }
} }
.environmentObject(viewModel.identification)
.sheet(isPresented: $viewModel.presentingSecondaryNavigation) { .sheet(isPresented: $viewModel.presentingSecondaryNavigation) {
SecondaryNavigationView() SecondaryNavigationView(viewModel: viewModel)
.environmentObject(viewModel.identification)
.environmentObject(viewModel) .environmentObject(viewModel)
.environmentObject(rootViewModel) .environmentObject(rootViewModel)
} }
@ -81,7 +83,7 @@ private extension TabNavigationView {
Button { Button {
viewModel.presentingSecondaryNavigation.toggle() viewModel.presentingSecondaryNavigation.toggle()
} label: { } label: {
KFImage(viewModel.identity.image, KFImage(viewModel.identification.identity.image,
options: .downsampled(dimension: 28, scaleFactor: displayScale)) options: .downsampled(dimension: 28, scaleFactor: displayScale))
.placeholder { Image(systemName: "gear") } .placeholder { Image(systemName: "gear") }
.renderingMode(.original) .renderingMode(.original)
@ -156,9 +158,8 @@ import PreviewViewModels
struct TabNavigation_Previews: PreviewProvider { struct TabNavigation_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
TabNavigationView() TabNavigationView(viewModel: TabNavigationViewModel(identification: .preview))
.environmentObject(Identification.preview) .environmentObject(Identification.preview)
.environmentObject(TabNavigationViewModel(identification: .preview))
.environmentObject(RootViewModel.preview) .environmentObject(RootViewModel.preview)
} }
} }