More observation

This commit is contained in:
Thomas Ricouard 2023-09-17 06:44:45 +02:00
parent fa38511e2f
commit d797dc6aa9
44 changed files with 101 additions and 100 deletions

View file

@ -112,12 +112,12 @@ extension View {
}
func withEnvironments() -> some View {
environmentObject(CurrentAccount.shared)
environment(CurrentAccount.shared)
.environmentObject(UserPreferences.shared)
.environmentObject(CurrentInstance.shared)
.environment(CurrentInstance.shared)
.environmentObject(Theme.shared)
.environment(AppAccountsManager.shared)
.environmentObject(PushNotificationsService.shared)
.environment(PushNotificationsService.shared)
.environment(AppAccountsManager.shared.currentClient)
}
}

View file

@ -16,10 +16,10 @@ struct IceCubesApp: App {
@Environment(\.scenePhase) private var scenePhase
@State private var appAccountsManager = AppAccountsManager.shared
@StateObject private var currentInstance = CurrentInstance.shared
@StateObject private var currentAccount = CurrentAccount.shared
@State private var currentInstance = CurrentInstance.shared
@State private var currentAccount = CurrentAccount.shared
@StateObject private var userPreferences = UserPreferences.shared
@StateObject private var pushNotificationsService = PushNotificationsService.shared
@State private var pushNotificationsService = PushNotificationsService.shared
@State private var watcher = StreamWatcher()
@StateObject private var quickLook = QuickLook()
@StateObject private var theme = Theme.shared
@ -46,12 +46,12 @@ struct IceCubesApp: App {
.environment(appAccountsManager)
.environment(appAccountsManager.currentClient)
.environmentObject(quickLook)
.environmentObject(currentAccount)
.environmentObject(currentInstance)
.environment(currentAccount)
.environment(currentInstance)
.environmentObject(userPreferences)
.environmentObject(theme)
.environment(watcher)
.environmentObject(pushNotificationsService)
.environment(pushNotificationsService)
.environment(\.isSupporter, isSupporter)
.fullScreenCover(item: $quickLook.url, content: { url in
QuickLookPreview(selectedURL: url, urls: quickLook.urls)

View file

@ -7,7 +7,7 @@ import SwiftUI
struct SideBarView<Content: View>: View {
@Environment(AppAccountsManager.self) private var appAccounts
@EnvironmentObject private var currentAccount: CurrentAccount
@Environment(CurrentAccount.self) private var currentAccount
@EnvironmentObject private var theme: Theme
@Environment(StreamWatcher.self) private var watcher
@EnvironmentObject private var userPreferences: UserPreferences

View file

@ -10,7 +10,7 @@ import SwiftUI
struct ExploreTab: View {
@EnvironmentObject private var theme: Theme
@EnvironmentObject private var preferences: UserPreferences
@EnvironmentObject private var currentAccount: CurrentAccount
@Environment(CurrentAccount.self) private var currentAccount
@Environment(Client.self) private var client
@State private var routerPath = RouterPath()
@Binding var popToRootTab: Tab

View file

@ -12,7 +12,7 @@ struct MessagesTab: View {
@EnvironmentObject private var theme: Theme
@Environment(StreamWatcher.self) private var watcher
@Environment(Client.self) private var client
@EnvironmentObject private var currentAccount: CurrentAccount
@Environment(CurrentAccount.self) private var currentAccount
@Environment(AppAccountsManager.self) private var appAccount
@State private var routerPath = RouterPath()
@Binding var popToRootTab: Tab

View file

@ -15,9 +15,9 @@ struct NotificationsTab: View {
@Environment(Client.self) private var client
@Environment(StreamWatcher.self) private var watcher
@Environment(AppAccountsManager.self) private var appAccount
@EnvironmentObject private var currentAccount: CurrentAccount
@Environment(CurrentAccount.self) private var currentAccount
@EnvironmentObject private var userPreferences: UserPreferences
@EnvironmentObject private var pushNotificationsService: PushNotificationsService
@Environment(PushNotificationsService.self) private var pushNotificationsService
@State private var routerPath = RouterPath()
@Binding var popToRootTab: Tab

View file

@ -12,7 +12,7 @@ struct ProfileTab: View {
@Environment(AppAccountsManager.self) private var appAccount
@EnvironmentObject private var theme: Theme
@Environment(Client.self) private var client
@EnvironmentObject private var currentAccount: CurrentAccount
@Environment(CurrentAccount.self) private var currentAccount
@State private var routerPath = RouterPath()
@Binding var popToRootTab: Tab

View file

@ -11,9 +11,9 @@ struct AccountSettingsView: View {
@Environment(\.dismiss) private var dismiss
@Environment(\.openURL) private var openURL
@EnvironmentObject private var pushNotifications: PushNotificationsService
@EnvironmentObject private var currentAccount: CurrentAccount
@EnvironmentObject private var currentInstance: CurrentInstance
@Environment(PushNotificationsService.self) private var pushNotifications
@Environment(CurrentAccount.self) private var currentAccount
@Environment(CurrentInstance.self) private var currentInstance
@EnvironmentObject private var theme: Theme
@Environment(AppAccountsManager.self) private var appAccountsManager
@Environment(Client.self) private var client

View file

@ -14,9 +14,9 @@ struct AddAccountView: View {
@Environment(\.scenePhase) private var scenePhase
@Environment(AppAccountsManager.self) private var appAccountsManager
@EnvironmentObject private var currentAccount: CurrentAccount
@EnvironmentObject private var currentInstance: CurrentInstance
@EnvironmentObject private var pushNotifications: PushNotificationsService
@Environment(CurrentAccount.self) private var currentAccount
@Environment(CurrentInstance.self) private var currentInstance
@Environment(PushNotificationsService.self) private var pushNotifications
@EnvironmentObject private var theme: Theme
@State private var instanceName: String = ""

View file

@ -10,7 +10,7 @@ import UserNotifications
struct PushNotificationsView: View {
@EnvironmentObject private var theme: Theme
@Environment(AppAccountsManager.self) private var appAccountsManager
@EnvironmentObject private var pushNotifications: PushNotificationsService
@Environment(PushNotificationsService.self) private var pushNotifications
@StateObject public var subscription: PushNotificationSubscriptionSettings

View file

@ -12,10 +12,10 @@ import Timeline
struct SettingsTabs: View {
@Environment(\.dismiss) private var dismiss
@EnvironmentObject private var pushNotifications: PushNotificationsService
@Environment(PushNotificationsService.self) private var pushNotifications
@EnvironmentObject private var preferences: UserPreferences
@Environment(Client.self) private var client
@EnvironmentObject private var currentInstance: CurrentInstance
@Environment(CurrentInstance.self) private var currentInstance
@Environment(AppAccountsManager.self) private var appAccountsManager
@EnvironmentObject private var theme: Theme

View file

@ -10,7 +10,7 @@ import Timeline
struct TimelineTab: View {
@Environment(AppAccountsManager.self) private var appAccount
@EnvironmentObject private var theme: Theme
@EnvironmentObject private var currentAccount: CurrentAccount
@Environment(CurrentAccount.self) private var currentAccount
@EnvironmentObject private var preferences: UserPreferences
@Environment(Client.self) private var client
@State private var routerPath = RouterPath()

View file

@ -30,9 +30,9 @@ class ShareViewController: UIViewController {
.environmentObject(UserPreferences.shared)
.environment(appAccountsManager)
.environment(client)
.environmentObject(account)
.environment(account)
.environmentObject(theme)
.environmentObject(instance)
.environment(instance)
.tint(theme.tintColor)
.preferredColorScheme(colorScheme == .light ? .light : .dark)
let childView = UIHostingController(rootView: view)

View file

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

View file

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

View file

@ -12,8 +12,8 @@ public struct AccountDetailView: View {
@Environment(\.redactionReasons) private var reasons
@Environment(StreamWatcher.self) private var watcher
@EnvironmentObject private var currentAccount: CurrentAccount
@EnvironmentObject private var currentInstance: CurrentInstance
@Environment(CurrentAccount.self) private var currentAccount
@Environment(CurrentInstance.self) private var currentInstance
@EnvironmentObject private var preferences: UserPreferences
@EnvironmentObject private var theme: Theme
@Environment(Client.self) private var client

View file

@ -22,7 +22,7 @@ import Observation
public struct AccountsListRow: View {
@EnvironmentObject private var theme: Theme
@EnvironmentObject private var currentAccount: CurrentAccount
@Environment(CurrentAccount.self) private var currentAccount
@Environment(RouterPath.self) private var routerPath
@Environment(Client.self) private var client
@ -118,7 +118,7 @@ public struct AccountsListRow: View {
.scrollContentBackground(.hidden)
.background(theme.primaryBackgroundColor)
.environmentObject(theme)
.environmentObject(currentAccount)
.environment(currentAccount)
.environment(client)
}
}

View file

@ -8,7 +8,7 @@ import SwiftUI
public struct AccountsListView: View {
@EnvironmentObject private var theme: Theme
@Environment(Client.self) private var client
@EnvironmentObject private var currentAccount: CurrentAccount
@Environment(CurrentAccount.self) private var currentAccount
@State private var viewModel: AccountsListViewModel
@State private var didAppear: Bool = false

View file

@ -8,7 +8,7 @@ struct EditFilterView: View {
@Environment(\.dismiss) private var dismiss
@EnvironmentObject private var theme: Theme
@EnvironmentObject private var account: CurrentAccount
@Environment(CurrentAccount.self) private var account
@Environment(Client.self) private var client
@State private var isSavingFilter: Bool = false

View file

@ -8,7 +8,7 @@ public struct FiltersListView: View {
@Environment(\.dismiss) private var dismiss
@EnvironmentObject private var theme: Theme
@EnvironmentObject private var account: CurrentAccount
@Environment(CurrentAccount.self) private var account
@Environment(Client.self) private var client
@State private var isLoading: Bool = true

View file

@ -4,7 +4,7 @@ import SwiftUI
public struct AppAccountsSelectorView: View {
@EnvironmentObject private var preferences: UserPreferences
@EnvironmentObject private var currentAccount: CurrentAccount
@Environment(CurrentAccount.self) private var currentAccount
@Environment(AppAccountsManager.self) private var appAccounts
@EnvironmentObject private var theme: Theme

View file

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

View file

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

View file

@ -9,7 +9,7 @@ struct ConversationsListRow: View {
@Environment(Client.self) private var client
@Environment(RouterPath.self) private var routerPath
@EnvironmentObject private var theme: Theme
@EnvironmentObject private var currentAccount: CurrentAccount
@Environment(CurrentAccount.self) private var currentAccount
@Binding var conversation: Conversation
@ObservedObject var viewModel: ConversationsListViewModel

View file

@ -3,7 +3,7 @@ import Models
import SwiftUI
public struct FollowRequestButtons: View {
@EnvironmentObject private var currentAccount: CurrentAccount
@Environment(CurrentAccount.self) private var currentAccount
let account: Account
let requestUpdated: (() -> Void)?

View file

@ -2,18 +2,19 @@ import Combine
import Foundation
import Models
import Network
import Observation
@MainActor
public class CurrentAccount: ObservableObject {
@Observable public class CurrentAccount {
private static var accountsCache: [String: Account] = [:]
@Published public private(set) var account: Account?
@Published public private(set) var lists: [List] = []
@Published public private(set) var tags: [Tag] = []
@Published public private(set) var followRequests: [Account] = []
@Published public private(set) var isUpdating: Bool = false
@Published public private(set) var updatingFollowRequestAccountIds = Set<String>()
@Published public private(set) var isLoadingAccount: Bool = false
public private(set) var account: Account?
public private(set) var lists: [List] = []
public private(set) var tags: [Tag] = []
public private(set) var followRequests: [Account] = []
public private(set) var isUpdating: Bool = false
public private(set) var updatingFollowRequestAccountIds = Set<String>()
public private(set) var isLoadingAccount: Bool = false
private var client: Client?

View file

@ -2,10 +2,11 @@ import Combine
import Foundation
import Models
import Network
import Observation
@MainActor
public class CurrentInstance: ObservableObject {
@Published public private(set) var instance: Instance?
@Observable public class CurrentInstance {
public private(set) var instance: Instance?
private var client: Client?

View file

@ -6,6 +6,7 @@ import Models
import Network
import SwiftUI
import UserNotifications
import Observation
extension UNNotificationResponse: @unchecked Sendable {}
extension UNUserNotificationCenter: @unchecked Sendable {}
@ -28,7 +29,7 @@ public struct HandledNotification: Equatable {
}
@MainActor
public class PushNotificationsService: NSObject, ObservableObject {
@Observable public class PushNotificationsService: NSObject {
enum Constants {
static let endpoint = "https://icecubesrelay.fly.dev"
static let keychainAuthKey = "notifications_auth_key"
@ -39,9 +40,9 @@ public class PushNotificationsService: NSObject, ObservableObject {
public private(set) var subscriptions: [PushNotificationSubscriptionSettings] = []
@Published public var pushToken: Data?
public var pushToken: Data?
@Published public var handledNotification: HandledNotification?
public var handledNotification: HandledNotification?
override init() {
super.init()

View file

@ -12,7 +12,7 @@ public struct ExploreView: View {
@Environment(Client.self) private var client
@Environment(RouterPath.self) private var routerPath
@StateObject private var viewModel = ExploreViewModel()
@State private var viewModel = ExploreViewModel()
public init() {}
@ -89,6 +89,11 @@ public struct ExploreView: View {
Text(scope.localizedString)
}
}
.onChange(of: viewModel.searchQuery) { oldValue, newValue in
if oldValue != newValue {
viewModel.search()
}
}
}
private var quickAccessView: some View {

View file

@ -1,10 +1,10 @@
import Combine
import Models
import Network
import SwiftUI
import Observation
@MainActor
class ExploreViewModel: ObservableObject {
@Observable class ExploreViewModel {
enum SearchScope: String, CaseIterable {
case all, people, hashtags, posts
@ -39,34 +39,25 @@ class ExploreViewModel: ObservableObject {
trendingLinks.isEmpty && trendingTags.isEmpty && trendingStatuses.isEmpty && suggestedAccounts.isEmpty
}
@Published var searchQuery = "" {
var searchQuery = "" {
didSet {
isSearching = true
}
}
@Published var results: [String: SearchResults] = [:]
@Published var isLoaded = false
@Published var isSearching = false
@Published var suggestedAccounts: [Account] = []
@Published var suggestedAccountsRelationShips: [Relationship] = []
@Published var trendingTags: [Tag] = []
@Published var trendingStatuses: [Status] = []
@Published var trendingLinks: [Card] = []
@Published var searchScope: SearchScope = .all
var results: [String: SearchResults] = [:]
var isLoaded = false
var isSearching = false
var suggestedAccounts: [Account] = []
var suggestedAccountsRelationShips: [Relationship] = []
var trendingTags: [Tag] = []
var trendingStatuses: [Status] = []
var trendingLinks: [Card] = []
var searchScope: SearchScope = .all
private var searchTask: Task<Void, Never>?
private var cancellables = Set<AnyCancellable>()
init() {
$searchQuery
.removeDuplicates()
.debounce(for: .milliseconds(250), scheduler: DispatchQueue.main)
.sink(receiveValue: { [weak self] _ in
self?.search()
})
.store(in: &cancellables)
}
init() { }
func fetchTrending() async {
guard let client else { return }
@ -112,6 +103,7 @@ class ExploreViewModel: ObservableObject {
searchTask = Task {
guard let client else { return }
do {
try await Task.sleep(for: .milliseconds(250))
var results: SearchResults = try await client.get(endpoint: Search.search(query: searchQuery,
type: nil,
offset: nil,

View file

@ -8,14 +8,14 @@ public struct ListAddAccountView: View {
@Environment(\.dismiss) private var dismiss
@Environment(Client.self) private var client
@EnvironmentObject private var theme: Theme
@EnvironmentObject private var currentAccount: CurrentAccount
@StateObject private var viewModel: ListAddAccountViewModel
@Environment(CurrentAccount.self) private var currentAccount
@State private var viewModel: ListAddAccountViewModel
@State private var isCreateListAlertPresented: Bool = false
@State private var createListTitle: String = ""
public init(account: Account) {
_viewModel = StateObject(wrappedValue: .init(account: account))
_viewModel = .init(initialValue: .init(account: account))
}
public var body: some View {

View file

@ -1,13 +1,14 @@
import Models
import Network
import SwiftUI
import Observation
@MainActor
class ListAddAccountViewModel: ObservableObject {
@Observable class ListAddAccountViewModel {
let account: Account
@Published var inLists: [Models.List] = []
@Published var isLoadingInfo: Bool = true
var inLists: [Models.List] = []
var isLoadingInfo: Bool = true
var client: Client?

View file

@ -11,7 +11,7 @@ public struct NotificationsListView: View {
@Environment(StreamWatcher.self) private var watcher
@Environment(Client.self) private var client
@Environment(RouterPath.self) private var routerPath
@EnvironmentObject private var account: CurrentAccount
@Environment(CurrentAccount.self) private var account
@StateObject private var viewModel = NotificationsViewModel()
let lockedType: Models.Notification.NotificationType?

View file

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

View file

@ -8,7 +8,7 @@ import SwiftUI
struct StatusEditorAccessoryView: View {
@EnvironmentObject private var preferences: UserPreferences
@EnvironmentObject private var theme: Theme
@EnvironmentObject private var currentInstance: CurrentInstance
@Environment(CurrentInstance.self) private var currentInstance
@Environment(\.colorScheme) private var colorScheme
@FocusState<Bool>.Binding var isSpoilerTextFocused: Bool

View file

@ -7,7 +7,7 @@ import SwiftUI
struct StatusEditorMediaEditView: View {
@Environment(\.dismiss) private var dismiss
@EnvironmentObject private var theme: Theme
@EnvironmentObject private var currentInstance: CurrentInstance
@Environment(CurrentInstance.self) private var currentInstance
@ObservedObject var viewModel: StatusEditorViewModel
let container: StatusEditorMediaContainer

View file

@ -7,7 +7,7 @@ import SwiftUI
struct StatusEditorMediaView: View {
@EnvironmentObject private var theme: Theme
@EnvironmentObject private var currentInstance: CurrentInstance
@Environment(CurrentInstance.self) private var currentInstance
@ObservedObject var viewModel: StatusEditorViewModel
@State private var editingContainer: StatusEditorMediaContainer?

View file

@ -12,7 +12,7 @@ struct StatusEditorPollView: View {
@State private var currentFocusIndex: Int = 0
@EnvironmentObject private var theme: Theme
@EnvironmentObject private var currentInstance: CurrentInstance
@Environment(CurrentInstance.self) private var currentInstance
@ObservedObject var viewModel: StatusEditorViewModel

View file

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

View file

@ -7,8 +7,8 @@ import SwiftUI
public struct StatusPollView: View {
@EnvironmentObject private var theme: Theme
@Environment(Client.self) private var client
@EnvironmentObject private var currentInstance: CurrentInstance
@EnvironmentObject private var currentAccount: CurrentAccount
@Environment(CurrentInstance.self) private var currentInstance
@Environment(CurrentAccount.self) private var currentAccount
@State private var viewModel: StatusPollViewModel

View file

@ -6,7 +6,7 @@ import SwiftUI
struct StatusRowActionsView: View {
@EnvironmentObject private var theme: Theme
@EnvironmentObject private var currentAccount: CurrentAccount
@Environment(CurrentAccount.self) private var currentAccount
@EnvironmentObject private var statusDataController: StatusDataController
@EnvironmentObject private var userPreferences: UserPreferences

View file

@ -10,8 +10,8 @@ struct StatusRowContextMenu: View {
@Environment(Client.self) private var client
@EnvironmentObject private var sceneDelegate: SceneDelegate
@EnvironmentObject private var preferences: UserPreferences
@EnvironmentObject private var account: CurrentAccount
@EnvironmentObject private var currentInstance: CurrentInstance
@Environment(CurrentAccount.self) private var account
@Environment(CurrentInstance.self) private var currentInstance
@EnvironmentObject private var statusDataController: StatusDataController
var viewModel: StatusRowViewModel
@ -87,8 +87,8 @@ struct StatusRowContextMenu: View {
.environment(\.isInCaptureMode, true)
.environmentObject(Theme.shared)
.environmentObject(preferences)
.environmentObject(account)
.environmentObject(currentInstance)
.environment(account)
.environment(currentInstance)
.environmentObject(SceneDelegate())
.environmentObject(QuickLook())
.environment(viewModel.client)

View file

@ -6,7 +6,7 @@ import SwiftUI
struct StatusRowSwipeView: View {
@EnvironmentObject private var theme: Theme
@EnvironmentObject private var preferences: UserPreferences
@EnvironmentObject private var currentAccount: CurrentAccount
@Environment(CurrentAccount.self) private var currentAccount
@EnvironmentObject private var statusDataController: StatusDataController
enum Mode {

View file

@ -14,7 +14,7 @@ public struct TimelineView: View {
@Environment(\.scenePhase) private var scenePhase
@EnvironmentObject private var theme: Theme
@EnvironmentObject private var account: CurrentAccount
@Environment(CurrentAccount.self) private var account
@Environment(StreamWatcher.self) private var watcher
@Environment(Client.self) private var client
@Environment(RouterPath.self) private var routerPath