More Observation

This commit is contained in:
Thomas Ricouard 2023-09-16 18:58:13 +02:00
parent 54839953cd
commit fa38511e2f
33 changed files with 67 additions and 63 deletions

View file

@ -20,10 +20,10 @@ struct IceCubesApp: App {
@StateObject private var currentAccount = CurrentAccount.shared
@StateObject private var userPreferences = UserPreferences.shared
@StateObject private var pushNotificationsService = PushNotificationsService.shared
@StateObject private var watcher = StreamWatcher()
@State private var watcher = StreamWatcher()
@StateObject private var quickLook = QuickLook()
@StateObject private var theme = Theme.shared
@StateObject private var sidebarRouterPath = RouterPath()
@State private var sidebarRouterPath = RouterPath()
@State private var selectedTab: Tab = .timeline
@State private var popToRootTab: Tab = .other
@ -50,7 +50,7 @@ struct IceCubesApp: App {
.environmentObject(currentInstance)
.environmentObject(userPreferences)
.environmentObject(theme)
.environmentObject(watcher)
.environment(watcher)
.environmentObject(pushNotificationsService)
.environment(\.isSupporter, isSupporter)
.fullScreenCover(item: $quickLook.url, content: { url in

View file

@ -14,7 +14,7 @@ extension View {
private struct SafariRouter: ViewModifier {
@EnvironmentObject private var theme: Theme
@EnvironmentObject private var preferences: UserPreferences
@EnvironmentObject private var routerPath: RouterPath
@Environment(RouterPath.self) private var routerPath
@State private var safariManager = InAppSafariManager()

View file

@ -9,13 +9,13 @@ struct SideBarView<Content: View>: View {
@Environment(AppAccountsManager.self) private var appAccounts
@EnvironmentObject private var currentAccount: CurrentAccount
@EnvironmentObject private var theme: Theme
@EnvironmentObject private var watcher: StreamWatcher
@Environment(StreamWatcher.self) private var watcher
@EnvironmentObject private var userPreferences: UserPreferences
@Binding var selectedTab: Tab
@Binding var popToRootTab: Tab
var tabs: [Tab]
@ObservedObject var routerPath = RouterPath()
@State var routerPath = RouterPath()
@ViewBuilder var content: () -> Content
private func badgeFor(tab: Tab) -> Int {

View file

@ -12,7 +12,7 @@ struct ExploreTab: View {
@EnvironmentObject private var preferences: UserPreferences
@EnvironmentObject private var currentAccount: CurrentAccount
@Environment(Client.self) private var client
@StateObject private var routerPath = RouterPath()
@State private var routerPath = RouterPath()
@Binding var popToRootTab: Tab
var body: some View {
@ -35,7 +35,7 @@ struct ExploreTab: View {
}
}
.withSafariRouter()
.environmentObject(routerPath)
.environment(routerPath)
.onChange(of: $popToRootTab.wrappedValue) { oldValue, newValue in
if newValue == .explore {
routerPath.path = []

View file

@ -10,11 +10,11 @@ import SwiftUI
struct MessagesTab: View {
@EnvironmentObject private var theme: Theme
@EnvironmentObject private var watcher: StreamWatcher
@Environment(StreamWatcher.self) private var watcher
@Environment(Client.self) private var client
@EnvironmentObject private var currentAccount: CurrentAccount
@Environment(AppAccountsManager.self) private var appAccount
@StateObject private var routerPath = RouterPath()
@State private var routerPath = RouterPath()
@Binding var popToRootTab: Tab
var body: some View {
@ -44,6 +44,6 @@ struct MessagesTab: View {
routerPath.client = client
}
.withSafariRouter()
.environmentObject(routerPath)
.environment(routerPath)
}
}

View file

@ -13,12 +13,12 @@ struct NotificationsTab: View {
@EnvironmentObject private var theme: Theme
@Environment(Client.self) private var client
@EnvironmentObject private var watcher: StreamWatcher
@Environment(StreamWatcher.self) private var watcher
@Environment(AppAccountsManager.self) private var appAccount
@EnvironmentObject private var currentAccount: CurrentAccount
@EnvironmentObject private var userPreferences: UserPreferences
@EnvironmentObject private var pushNotificationsService: PushNotificationsService
@StateObject private var routerPath = RouterPath()
@State private var routerPath = RouterPath()
@Binding var popToRootTab: Tab
let lockedType: Models.Notification.NotificationType?
@ -54,7 +54,7 @@ struct NotificationsTab: View {
}
}
.withSafariRouter()
.environmentObject(routerPath)
.environment(routerPath)
.onChange(of: $popToRootTab.wrappedValue) { oldValue, newValue in
if newValue == .notifications {
routerPath.path = []

View file

@ -13,7 +13,7 @@ struct ProfileTab: View {
@EnvironmentObject private var theme: Theme
@Environment(Client.self) private var client
@EnvironmentObject private var currentAccount: CurrentAccount
@StateObject private var routerPath = RouterPath()
@State private var routerPath = RouterPath()
@Binding var popToRootTab: Tab
var body: some View {
@ -41,6 +41,6 @@ struct ProfileTab: View {
routerPath.client = client
}
.withSafariRouter()
.environmentObject(routerPath)
.environment(routerPath)
}
}

View file

@ -3,7 +3,7 @@ import Env
import SwiftUI
struct AboutView: View {
@EnvironmentObject private var routerPath: RouterPath
@Environment(RouterPath.self) private var routerPath
@EnvironmentObject private var theme: Theme
let versionNumber: String

View file

@ -19,8 +19,7 @@ struct SettingsTabs: View {
@Environment(AppAccountsManager.self) private var appAccountsManager
@EnvironmentObject private var theme: Theme
@StateObject private var routerPath = RouterPath()
@State private var routerPath = RouterPath()
@State private var addAccountSheetPresented = false
@State private var isEditingAccount = false
@State private var cachedRemoved = false
@ -67,7 +66,7 @@ struct SettingsTabs: View {
}
}
.withSafariRouter()
.environmentObject(routerPath)
.environment(routerPath)
.onChange(of: $popToRootTab.wrappedValue) { oldValue, newValue in
if newValue == .notifications {
routerPath.path = []

View file

@ -13,7 +13,7 @@ struct TimelineTab: View {
@EnvironmentObject private var currentAccount: CurrentAccount
@EnvironmentObject private var preferences: UserPreferences
@Environment(Client.self) private var client
@StateObject private var routerPath = RouterPath()
@State private var routerPath = RouterPath()
@Binding var popToRootTab: Tab
@State private var didAppear: Bool = false
@ -90,7 +90,7 @@ struct TimelineTab: View {
}
}
.withSafariRouter()
.environmentObject(routerPath)
.environment(routerPath)
}
@ViewBuilder

View file

@ -4,7 +4,7 @@ import SwiftUI
public struct AccountDetailContextMenu: View {
@Environment(Client.self) private var client
@EnvironmentObject private var routerPath: RouterPath
@Environment(RouterPath.self) private var routerPath
@EnvironmentObject private var currentInstance: CurrentInstance
@EnvironmentObject private var preferences: UserPreferences

View file

@ -13,7 +13,7 @@ struct AccountDetailHeaderView: View {
@EnvironmentObject private var theme: Theme
@EnvironmentObject private var quickLook: QuickLook
@EnvironmentObject private var routerPath: RouterPath
@Environment(RouterPath.self) private var routerPath
@EnvironmentObject private var currentAccount: CurrentAccount
@Environment(\.redactionReasons) private var reasons
@Environment(\.isSupporter) private var isSupporter: Bool

View file

@ -11,13 +11,13 @@ public struct AccountDetailView: View {
@Environment(\.openURL) private var openURL
@Environment(\.redactionReasons) private var reasons
@EnvironmentObject private var watcher: StreamWatcher
@Environment(StreamWatcher.self) private var watcher
@EnvironmentObject private var currentAccount: CurrentAccount
@EnvironmentObject private var currentInstance: CurrentInstance
@EnvironmentObject private var preferences: UserPreferences
@EnvironmentObject private var theme: Theme
@Environment(Client.self) private var client
@EnvironmentObject private var routerPath: RouterPath
@Environment(RouterPath.self) private var routerPath
@State private var viewModel: AccountDetailViewModel
@State private var isCurrentUser: Bool = false

View file

@ -23,7 +23,7 @@ import Observation
public struct AccountsListRow: View {
@EnvironmentObject private var theme: Theme
@EnvironmentObject private var currentAccount: CurrentAccount
@EnvironmentObject private var routerPath: RouterPath
@Environment(RouterPath.self) private var routerPath
@Environment(Client.self) private var client
@State var viewModel: AccountsListRowViewModel

View file

@ -5,7 +5,7 @@ import SwiftUI
public struct AppAccountView: View {
@EnvironmentObject private var theme: Theme
@EnvironmentObject private var routerPath: RouterPath
@Environment(RouterPath.self) private var routerPath
@Environment(AppAccountsManager.self) private var appAccounts
@EnvironmentObject private var preferences: UserPreferences

View file

@ -8,7 +8,7 @@ public struct AppAccountsSelectorView: View {
@Environment(AppAccountsManager.self) private var appAccounts
@EnvironmentObject private var theme: Theme
@ObservedObject var routerPath: RouterPath
var routerPath: RouterPath
@State private var accountsViewModel: [AppAccountViewModel] = []
@State private var isPresented: Bool = false

View file

@ -11,11 +11,11 @@ public struct ConversationDetailView: View {
}
@EnvironmentObject private var quickLook: QuickLook
@EnvironmentObject private var routerPath: RouterPath
@Environment(RouterPath.self) private var routerPath
@EnvironmentObject private var currentAccount: CurrentAccount
@Environment(Client.self) private var client
@EnvironmentObject private var theme: Theme
@EnvironmentObject private var watcher: StreamWatcher
@Environment(StreamWatcher.self) private var watcher
@StateObject private var viewModel: ConversationDetailViewModel

View file

@ -7,7 +7,7 @@ import SwiftUI
struct ConversationMessageView: View {
@EnvironmentObject private var quickLook: QuickLook
@EnvironmentObject private var routerPath: RouterPath
@Environment(RouterPath.self) private var routerPath
@EnvironmentObject private var currentAccount: CurrentAccount
@Environment(Client.self) private var client
@EnvironmentObject private var theme: Theme

View file

@ -7,7 +7,7 @@ import SwiftUI
struct ConversationsListRow: View {
@Environment(Client.self) private var client
@EnvironmentObject private var routerPath: RouterPath
@Environment(RouterPath.self) private var routerPath
@EnvironmentObject private var theme: Theme
@EnvironmentObject private var currentAccount: CurrentAccount

View file

@ -7,8 +7,8 @@ import SwiftUI
public struct ConversationsListView: View {
@EnvironmentObject private var preferences: UserPreferences
@EnvironmentObject private var routerPath: RouterPath
@EnvironmentObject private var watcher: StreamWatcher
@Environment(RouterPath.self) private var routerPath
@Environment(StreamWatcher.self) private var watcher
@Environment(Client.self) private var client
@EnvironmentObject private var theme: Theme

View file

@ -24,7 +24,7 @@ public extension View {
@MainActor
public struct StatusEditorToolbarItem: ToolbarContent {
@EnvironmentObject private var routerPath: RouterPath
@Environment(RouterPath.self) private var routerPath
let visibility: Models.Visibility

View file

@ -3,7 +3,7 @@ import Models
import SwiftUI
public struct TagRowView: View {
@EnvironmentObject private var routerPath: RouterPath
@Environment(RouterPath.self) private var routerPath
let tag: Tag

View file

@ -3,6 +3,7 @@ import Foundation
import Models
import Network
import SwiftUI
import Observation
public enum RouterDestination: Hashable {
case accountDetail(id: String)
@ -69,12 +70,12 @@ public enum SheetDestination: Identifiable {
}
@MainActor
public class RouterPath: ObservableObject {
@Observable public class RouterPath {
public var client: Client?
public var urlHandler: ((URL) -> OpenURLAction.Result)?
@Published public var path: [RouterDestination] = []
@Published public var presentedSheet: SheetDestination?
public var path: [RouterDestination] = []
public var presentedSheet: SheetDestination?
public init() {}

View file

@ -2,9 +2,10 @@ import Combine
import Foundation
import Models
import Network
import Observation
@MainActor
public class StreamWatcher: ObservableObject {
@Observable public class StreamWatcher {
private var client: Client?
private var task: URLSessionWebSocketTask?
private var watchedStreams: [Stream] = []
@ -21,9 +22,9 @@ public class StreamWatcher: ObservableObject {
case direct
}
@Published public var events: [any StreamEvent] = []
@Published public var unreadNotificationsCount: Int = 0
@Published public var latestEvent: (any StreamEvent)?
public var events: [any StreamEvent] = []
public var unreadNotificationsCount: Int = 0
public var latestEvent: (any StreamEvent)?
public init() {
decoder.keyDecodingStrategy = .convertFromSnakeCase

View file

@ -10,7 +10,7 @@ import SwiftUI
public struct ExploreView: View {
@EnvironmentObject private var theme: Theme
@Environment(Client.self) private var client
@EnvironmentObject private var routerPath: RouterPath
@Environment(RouterPath.self) private var routerPath
@StateObject private var viewModel = ExploreViewModel()

View file

@ -8,9 +8,9 @@ import SwiftUI
public struct NotificationsListView: View {
@Environment(\.scenePhase) private var scenePhase
@EnvironmentObject private var theme: Theme
@EnvironmentObject private var watcher: StreamWatcher
@Environment(StreamWatcher.self) private var watcher
@Environment(Client.self) private var client
@EnvironmentObject private var routerPath: RouterPath
@Environment(RouterPath.self) private var routerPath
@EnvironmentObject private var account: CurrentAccount
@StateObject private var viewModel = NotificationsViewModel()

View file

@ -8,9 +8,9 @@ import SwiftUI
public struct StatusDetailView: View {
@EnvironmentObject private var theme: Theme
@EnvironmentObject private var currentAccount: CurrentAccount
@EnvironmentObject private var watcher: StreamWatcher
@Environment(StreamWatcher.self) private var watcher
@Environment(Client.self) private var client
@EnvironmentObject private var routerPath: RouterPath
@Environment(RouterPath.self) private var routerPath
@StateObject private var viewModel: StatusDetailViewModel

View file

@ -17,7 +17,7 @@ public struct StatusEditorView: View {
@EnvironmentObject private var theme: Theme
@Environment(Client.self) private var client
@EnvironmentObject private var currentAccount: CurrentAccount
@EnvironmentObject private var routerPath: RouterPath
@Environment(RouterPath.self) private var routerPath
@Environment(\.dismiss) private var dismiss
@StateObject private var viewModel: StatusEditorViewModel

View file

@ -1,6 +1,7 @@
import Combine
import Models
import SwiftUI
import Observation
public enum StatusesState {
public enum PagingState {
@ -13,7 +14,7 @@ public enum StatusesState {
}
@MainActor
public protocol StatusesFetcher: ObservableObject {
public protocol StatusesFetcher {
var statusesState: StatusesState { get }
func fetchNewestStatuses() async
func fetchNextPage() async

View file

@ -8,7 +8,7 @@ import SwiftUI
public struct StatusesListView<Fetcher>: View where Fetcher: StatusesFetcher {
@EnvironmentObject private var theme: Theme
@ObservedObject private var fetcher: Fetcher
@State private var fetcher: Fetcher
// Whether this status is on a remote local timeline (many actions are unavailable if so)
private let isRemote: Bool
private let routerPath: RouterPath
@ -19,7 +19,7 @@ public struct StatusesListView<Fetcher>: View where Fetcher: StatusesFetcher {
routerPath: RouterPath,
isRemote: Bool = false)
{
self.fetcher = fetcher
_fetcher = .init(initialValue: fetcher)
self.isRemote = isRemote
self.client = client
self.routerPath = routerPath

View file

@ -2,8 +2,9 @@ import Models
import Nuke
import SwiftUI
import UIKit
import Observation
final class TimelinePrefetcher: NSObject, ObservableObject, UICollectionViewDataSourcePrefetching {
@Observable final class TimelinePrefetcher: NSObject, UICollectionViewDataSourcePrefetching {
private let prefetcher = ImagePrefetcher()
weak var viewModel: TimelineViewModel?

View file

@ -15,12 +15,12 @@ public struct TimelineView: View {
@Environment(\.scenePhase) private var scenePhase
@EnvironmentObject private var theme: Theme
@EnvironmentObject private var account: CurrentAccount
@EnvironmentObject private var watcher: StreamWatcher
@Environment(StreamWatcher.self) private var watcher
@Environment(Client.self) private var client
@EnvironmentObject private var routerPath: RouterPath
@Environment(RouterPath.self) private var routerPath
@StateObject private var viewModel = TimelineViewModel()
@StateObject private var prefetcher = TimelinePrefetcher()
@State private var viewModel = TimelineViewModel()
@State private var prefetcher = TimelinePrefetcher()
@State private var wasBackgrounded: Bool = false
@State private var collectionView: UICollectionView?

View file

@ -3,12 +3,13 @@ import Models
import Network
import Status
import SwiftUI
import Observation
@MainActor
class TimelineViewModel: ObservableObject {
@Published var scrollToIndex: Int?
@Published var statusesState: StatusesState = .loading
@Published var timeline: TimelineFilter = .federated {
@Observable class TimelineViewModel {
var scrollToIndex: Int?
var statusesState: StatusesState = .loading
var timeline: TimelineFilter = .federated {
didSet {
timelineTask?.cancel()
timelineTask = Task {
@ -39,7 +40,7 @@ class TimelineViewModel: ObservableObject {
private var timelineTask: Task<Void, Never>?
@Published var tag: Tag?
var tag: Tag?
var tagGroup: TagGroup? {
if case let .tagGroup(group) = timeline {