mirror of
https://github.com/metabolist/metatext.git
synced 2024-11-25 17:50:59 +00:00
Refactoring
This commit is contained in:
parent
4c1f0e2452
commit
182ecb5b91
8 changed files with 58 additions and 55 deletions
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 }
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue