Run SwiftFormat.

This commit is contained in:
Doug
2026-05-27 14:38:50 +01:00
committed by Doug
parent 5138e05e47
commit fa67713726
573 changed files with 2426 additions and 2426 deletions
@@ -29,7 +29,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
private let appHooks: AppHooks
private let bugReportService: BugReportServiceProtocol
private let elementCallService: ElementCallServiceProtocol
/// Common background task to continue long-running tasks in the background.
private var backgroundTask: UIBackgroundTaskIdentifier?
@@ -60,13 +60,13 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
let windowManager: SecureWindowManagerProtocol
let notificationManager: NotificationManagerProtocol
private let appRouteURLParser: AppRouteURLParser
private var storedAppRoute: AppRoute?
@Consumable private var storedInlineReply: (roomID: String, message: String)?
@Consumable private var storedRoomsToAwait: Set<String>?
init(appDelegate: AppDelegate) {
let appHooks = AppHooks()
appHooks.setUp()
@@ -115,9 +115,9 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
navigationRootCoordinator = NavigationRootCoordinator()
stateMachine = AppCoordinatorStateMachine()
navigationRootCoordinator.setRootCoordinator(SplashScreenCoordinator())
let keychainController = KeychainController(service: .sessions,
accessGroup: InfoPlistReader.main.keychainAccessGroupIdentifier)
userSessionStore = UserSessionStore(keychainController: keychainController,
@@ -160,9 +160,9 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
wipeUserData(includingSettings: true)
}
appSettings.lastVersionLaunched = currentVersion.description
setupStateMachine()
observeApplicationState()
observeAppLockChanges()
@@ -213,13 +213,13 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
stateMachine.processEvent(.startWithExistingSession)
}
func toPresentable() -> AnyView {
AnyView(navigationRootCoordinator.toPresentable()
.environment(\.analyticsService, analyticsService)
.onReceive(appSettings.$appAppearance) { [weak self] appAppearance in
guard let self else { return }
windowManager.windows.forEach { window in
// Unfortunately .preferredColorScheme doesn't propagate properly throughout the app when changed
window.overrideUserInterfaceStyle = appAppearance.interfaceStyle
@@ -267,7 +267,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
storedAppRoute = appRoute
}
}
func handleDeepLink(_ url: URL, isExternalURL: Bool, windowType: SecondaryWindowType?) -> Bool {
// Parse into an AppRoute to redirect these in a type safe way.
@@ -382,7 +382,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
func unregisterForRemoteNotifications() {
UIApplication.shared.unregisterForRemoteNotifications()
}
func shouldDisplayInAppNotification(content: UNNotificationContent) -> Bool {
guard let roomID = content.roomID else {
return true
@@ -542,7 +542,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
}
}
}
/// Clears the keychain, app support directory etc ready for a fresh use.
/// - Parameter includingSettings: Whether to additionally wipe the user's app settings too.
private func wipeUserData(includingSettings: Bool = false) {
@@ -608,7 +608,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
presentSplashScreen()
case (.restoringSession, .createdUserSession, .signedIn):
setupUserSession(isNewLogin: false)
case (.signingOut, .signOut, .signingOut):
// We can ignore signOut when already in the process of signing out,
// such as the SDK sending an authError due to token invalidation.
@@ -696,7 +696,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
await processInlineReply(roomID: storedInlineReply.roomID, replyText: storedInlineReply.message)
}
}
private func startAuthenticationSoftLogout() {
guard let userSession else {
fatalError("User session not setup")
@@ -799,7 +799,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
await runPostSessionSetupTasks()
}
}
private func logout(isSoft: Bool) {
guard let userSession else {
fatalError("User session not setup")
@@ -841,7 +841,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
analyticsService.resetConsentState()
stateMachine.processEvent(.completedSigningOut)
hideLoadingIndicator()
}
}
@@ -852,7 +852,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
userSession = nil
userSessionFlowCoordinator = nil
notificationManager.setUserSession(nil)
}
@@ -882,10 +882,10 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
elementCallService.setClientProxy(userSession.clientProxy)
}
private func configureNotificationManager() {
notificationManager.setUserSession(userSession)
appDelegateObserver = appDelegate.callbacks
.receive(on: DispatchQueue.main)
.sink { [weak self] callback in
@@ -940,7 +940,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
stopSync(isBackgroundTask: false)
userSessionFlowCoordinator?.stop()
// Allow for everything to deallocate properly
Task {
await userSession.clientProxy.clearCaches()
@@ -959,7 +959,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
#else
options.enabled = appSettings.analyticsConsentState == .optedIn
#endif
options.dsn = bugReportSentryURL.absoluteString
// Matches android, at least for now.
@@ -997,7 +997,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
options.sampleRate = 1.0
options.tracesSampleRate = 1.0
options.configureProfiling = { $0.sessionSampleRate = 1.0 }
// This callback is only executed once during the entire run of the program to avoid
// multiple callbacks if there are multiple crash events to send (see method documentation)
options.onLastRunStatusDetermined = { status, event in
@@ -1056,9 +1056,9 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
private func showLoginErrorToast() {
userIndicatorController.submitIndicator(UserIndicator(title: "Failed logging in"))
}
// MARK: - Application State
private func stopSync(isBackgroundTask: Bool, completion: (() -> Void)? = nil) {
if isBackgroundTask, UIApplication.shared.applicationState == .active {
// Attempt to stop the background task sync loop cleanly, only if the app not already running
@@ -1070,7 +1070,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
clientProxyObserver = nil
}
}
private func startSync() {
guard let userSession else { return }
@@ -1103,7 +1103,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
}
}
}
private func observeApplicationState() {
NotificationCenter.default.addObserver(self,
selector: #selector(applicationWillResignActive),
@@ -1123,7 +1123,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
selector: #selector(applicationDidBecomeActive),
name: UIApplication.didBecomeActiveNotification,
object: nil)
NotificationCenter.default.addObserver(self,
selector: #selector(applicationWillTerminate),
name: UIApplication.willTerminateNotification,
@@ -1133,18 +1133,18 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
name: UIContentSizeCategory.didChangeNotification,
object: nil)
}
@objc
private func didChangeContentSizeCategory() {
AttributedStringBuilder.invalidateCaches()
}
@objc
private func applicationWillTerminate() {
MXLog.info("Application will terminate")
stopSync(isBackgroundTask: false)
}
@objc
private func applicationDidEnterBackground() {
MXLog.info("Application did enter background")
@@ -20,14 +20,14 @@ class AppCoordinatorStateMachine {
case softLogout
/// Opening an existing session.
case restoringSession
/// User session started
case signedIn
/// Processing a sign out request
case signingOut(isSoft: Bool, disableAppLock: Bool)
}
/// Events that can be triggered on the AppCoordinator state machine
enum Event: EventType {
/// Start the `AppCoordinator` by showing authentication.
@@ -41,7 +41,7 @@ class AppCoordinatorStateMachine {
/// A session has been created.
case createdUserSession
/// Request sign out.
case signOut(isSoft: Bool, disableAppLock: Bool)
/// Request the soft logout screen.
@@ -63,7 +63,7 @@ class AppCoordinatorStateMachine {
stateMachine = StateMachine(state: .initial)
configure()
}
private func configure() {
stateMachine.addRoutes(event: .startWithAuthentication, transitions: [.initial => .signedOut])
stateMachine.addRoutes(event: .createdUserSession, transitions: [.signedOut => .signedIn,
@@ -71,13 +71,13 @@ class AppCoordinatorStateMachine {
stateMachine.addRoutes(event: .startWithExistingSession, transitions: [.initial => .restoringSession])
stateMachine.addRoutes(event: .createdUserSession, transitions: [.restoringSession => .signedIn])
stateMachine.addRoutes(event: .failedRestoringSession, transitions: [.restoringSession => .signedOut])
stateMachine.addRoutes(event: .completedSigningOut, transitions: [.signingOut(isSoft: false, disableAppLock: false) => .signedOut,
.signingOut(isSoft: false, disableAppLock: true) => .signedOut])
stateMachine.addRoutes(event: .showSoftLogout, transitions: [.signingOut(isSoft: true, disableAppLock: false) => .softLogout])
stateMachine.addRoutes(event: .clearCache, transitions: [.signedIn => .initial])
// Transitions with associated values need to be handled through `addRouteMapping`
stateMachine.addRouteMapping { event, fromState, _ in
switch (fromState, event) {
@@ -87,7 +87,7 @@ class AppCoordinatorStateMachine {
return nil
}
}
addTransitionHandler { context in
if let event = context.event {
MXLog.info("Transitioning from `\(context.fromState)` to `\(context.toState)` with event `\(event)`")
@@ -24,7 +24,7 @@ final class AppDelegate: NSObject, UIApplicationDelegate {
configuration.delegateClass = SceneDelegate.self
return configuration
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
NSTextAttachment.registerViewProviderClass(PillAttachmentViewProvider.self, forFileType: InfoPlistReader.main.pillsUTType)
return true
@@ -17,12 +17,12 @@ class AppMediator: AppMediatorProtocol {
self.windowManager = windowManager
self.networkMonitor = networkMonitor
}
/// UIApplication.State won't update if we store this e.g. in the constructor
private var application: UIApplication {
UIApplication.shared
}
var appState: UIApplication.State {
switch application.applicationState {
case .active:
@@ -39,7 +39,7 @@ class AppMediator: AppMediatorProtocol {
func beginBackgroundTask(expirationHandler handler: (() -> Void)?) -> UIBackgroundTaskIdentifier {
application.beginBackgroundTask(expirationHandler: handler)
}
func endBackgroundTask(_ identifier: UIBackgroundTaskIdentifier) {
application.endBackgroundTask(identifier)
}
@@ -18,7 +18,7 @@ protocol AppMediatorProtocol {
var appState: UIApplication.State { get }
func beginBackgroundTask(expirationHandler handler: (() -> Void)?) -> UIBackgroundTaskIdentifier
func endBackgroundTask(_ identifier: UIBackgroundTaskIdentifier)
func open(_ url: URL)
@@ -16,7 +16,7 @@ struct Application: App {
@Environment(\.dismissWindow) private var dismissWindow
private var appCoordinator: AppCoordinatorProtocol!
init() {
if ProcessInfo.isRunningUITests {
appCoordinator = UITestsAppCoordinator(appDelegate: appDelegate)
@@ -30,7 +30,7 @@ struct Application: App {
SceneDelegate.windowManager = appCoordinator.windowManager
}
var body: some Scene {
WindowGroup(id: SceneDelegate.mainSceneID) {
appCoordinator.toPresentable()
@@ -114,7 +114,7 @@ struct Application: App {
openURLInSystemBrowser(url)
}
}
/// Hide the status bar so it doesn't interfere with the screenshot tests
private var shouldHideStatusBar: Bool {
ProcessInfo.isRunningUITests
@@ -17,9 +17,9 @@ protocol CoordinatorProtocol: AnyObject {
extension CoordinatorProtocol {
func start() { }
func stop() { }
func toPresentable() -> AnyView {
AnyView(Text("View not configured"))
}
@@ -44,7 +44,7 @@ struct CommonFlowParameters {
var windowManager: WindowManagerProtocol {
appMediator.windowManager
}
var ongoingCallRoomIDPublisher: CurrentValuePublisher<String?, Never> {
elementCallService.ongoingCallRoomIDPublisher
}
@@ -13,7 +13,7 @@ import SwiftUI
/// into a single navigation stack on compact layouts
@Observable class NavigationSplitCoordinator: CoordinatorProtocol, CustomStringConvertible {
fileprivate let placeholderModule: NavigationModule
fileprivate var sidebarModule: NavigationModule? {
didSet {
if let oldValue {
@@ -105,7 +105,7 @@ import SwiftUI
var compactLayoutRootCoordinator: (any CoordinatorProtocol)? {
compactLayoutRootModule?.coordinator
}
var compactLayoutStackModules: [NavigationModule] {
get {
getCompactStackModules()
@@ -114,7 +114,7 @@ import SwiftUI
setCompactStackModules(newValue)
}
}
private func getCompactStackModules() -> [NavigationModule] {
// Start building the new compact layout navigation stack
var stackModules: [NavigationModule] = []
@@ -123,23 +123,23 @@ import SwiftUI
if let sidebarNavigationStackCoordinator = sidebarModule?.coordinator as? NavigationStackCoordinator {
stackModules.append(contentsOf: sidebarNavigationStackCoordinator.stackModules)
}
// If the detail is a stackCoordinator then push its root and children to the compact layout stack
if let detailNavigationStackCoordinator = detailModule?.coordinator as? NavigationStackCoordinator {
if let detailRootCoordinator = detailNavigationStackCoordinator.rootModule {
stackModules.append(detailRootCoordinator)
}
stackModules.append(contentsOf: detailNavigationStackCoordinator.stackModules)
} else if let detailModule { // Otherwise just push it entirely
stackModules.append(detailModule)
}
return stackModules
}
private func setCompactStackModules(_ modules: [NavigationModule]) {
guard compactLayoutStackModules != modules else { return }
let diffs = modules.difference(from: compactLayoutStackModules)
diffs.forEach { change in
switch change {
@@ -150,7 +150,7 @@ import SwiftUI
}
}
}
var compactLayoutStackCoordinators: [any CoordinatorProtocol] {
compactLayoutStackModules.compactMap(\.coordinator)
}
@@ -175,10 +175,10 @@ import SwiftUI
if sidebarModule?.coordinator === coordinator {
fatalError("Cannot use the same coordinator more than once")
}
var transaction = Transaction()
transaction.disablesAnimations = !animated
withTransaction(transaction) {
sidebarModule = NavigationModule(coordinator, dismissalCallback: dismissalCallback)
}
@@ -198,10 +198,10 @@ import SwiftUI
if detailModule?.coordinator === coordinator {
fatalError("Cannot use the same coordinator more than once")
}
var transaction = Transaction()
transaction.disablesAnimations = !animated
withTransaction(transaction) {
detailModule = NavigationModule(coordinator, dismissalCallback: dismissalCallback)
}
@@ -221,10 +221,10 @@ import SwiftUI
if sheetModule?.coordinator === coordinator {
fatalError("Cannot use the same coordinator more than once")
}
var transaction = Transaction()
transaction.disablesAnimations = !animated
withTransaction(transaction) {
sheetModule = NavigationModule(coordinator, dismissalCallback: dismissalCallback)
}
@@ -244,15 +244,15 @@ import SwiftUI
if fullScreenCoverModule?.coordinator === coordinator {
fatalError("Cannot use the same coordinator more than once")
}
var transaction = Transaction()
transaction.disablesAnimations = !animated
withTransaction(transaction) {
fullScreenCoverModule = NavigationModule(coordinator, dismissalCallback: dismissalCallback)
}
}
// MARK: - CoordinatorProtocol
func toPresentable() -> AnyView {
@@ -264,7 +264,7 @@ import SwiftUI
}
// MARK: - CustomStringConvertible
var description: String {
switch (sidebarModule?.coordinator, detailModule?.coordinator) {
case (.some(let sidebarCoordinator), .some(let detailCoordinator)):
@@ -533,10 +533,10 @@ private struct NavigationSplitCoordinatorView: View {
}
popToRoot(animated: false)
var transaction = Transaction()
transaction.disablesAnimations = !animated
withTransaction(transaction) {
rootModule = NavigationModule(coordinator, dismissalCallback: dismissalCallback)
}
@@ -550,7 +550,7 @@ private struct NavigationSplitCoordinatorView: View {
func push(_ coordinator: any CoordinatorProtocol, animated: Bool = true, dismissalCallback: (() -> Void)? = nil) {
var transaction = Transaction()
transaction.disablesAnimations = !animated
withTransaction(transaction) {
stackModules.append(NavigationModule(coordinator, dismissalCallback: dismissalCallback))
}
@@ -562,10 +562,10 @@ private struct NavigationSplitCoordinatorView: View {
guard !stackModules.isEmpty else {
return
}
var transaction = Transaction()
transaction.disablesAnimations = !animated
withTransaction(transaction) {
stackModules.removeAll()
}
@@ -576,7 +576,7 @@ private struct NavigationSplitCoordinatorView: View {
func pop(animated: Bool = true) {
var transaction = Transaction()
transaction.disablesAnimations = !animated
withTransaction(transaction) {
_ = stackModules.popLast()
}
@@ -617,15 +617,15 @@ private struct NavigationSplitCoordinatorView: View {
if sheetModule?.coordinator === coordinator {
fatalError("Cannot use the same coordinator more than once")
}
var transaction = Transaction()
transaction.disablesAnimations = !animated
withTransaction(transaction) {
sheetModule = NavigationModule(coordinator, dismissalCallback: dismissalCallback)
}
}
// periphery:ignore - might be useful to have
/// Present a fullscreen cover on top of the stack. If this NavigationStackCoordinator is embedded within a NavigationSplitCoordinator
/// then the presentation will be proxied to the split
@@ -647,10 +647,10 @@ private struct NavigationSplitCoordinatorView: View {
if fullScreenCoverModule?.coordinator === coordinator {
fatalError("Cannot use the same coordinator more than once")
}
var transaction = Transaction()
transaction.disablesAnimations = !animated
withTransaction(transaction) {
fullScreenCoverModule = NavigationModule(coordinator, dismissalCallback: dismissalCallback)
}
@@ -77,15 +77,15 @@ import SwiftUI
if sheetModule?.coordinator === coordinator {
fatalError("Cannot use the same coordinator more than once")
}
var transaction = Transaction()
transaction.disablesAnimations = !animated
withTransaction(transaction) {
sheetModule = NavigationModule(coordinator, dismissalCallback: dismissalCallback)
}
}
// MARK: - CoordinatorProtocol
func toPresentable() -> AnyView {
@@ -57,7 +57,7 @@ import SwiftUI
var id: ObjectIdentifier {
module.id
}
@MainActor var coordinator: CoordinatorProtocol? {
module.coordinator
}
@@ -137,10 +137,10 @@ import SwiftUI
if sheetModule?.coordinator === coordinator {
fatalError("Cannot use the same coordinator more than once")
}
var transaction = Transaction()
transaction.disablesAnimations = !animated
withTransaction(transaction) {
sheetModule = NavigationModule(coordinator, dismissalCallback: dismissalCallback)
}
@@ -183,10 +183,10 @@ import SwiftUI
if fullScreenCoverModule?.coordinator === coordinator {
fatalError("Cannot use the same coordinator more than once")
}
var transaction = Transaction()
transaction.disablesAnimations = !animated
withTransaction(transaction) {
fullScreenCoverModule = NavigationModule(coordinator, dismissalCallback: dismissalCallback)
}
@@ -234,10 +234,10 @@ import SwiftUI
if overlayModule?.coordinator === coordinator {
fatalError("Cannot use the same coordinator more than once")
}
var transaction = Transaction()
transaction.disablesAnimations = !animated
withTransaction(transaction) {
overlayPresentationMode = presentationMode
overlayModule = NavigationModule(coordinator, dismissalCallback: dismissalCallback)
@@ -13,7 +13,7 @@ enum AppAppearance: CaseIterable, Codable {
case system
case dark
case light
var interfaceStyle: UIUserInterfaceStyle {
switch self {
case .light:
@@ -17,7 +17,7 @@ import SwiftUI
protocol CommonSettingsProtocol: AnyObject, Sendable {
var lastNotificationBootTime: TimeInterval? { get set }
var selectedNotificationTone: NotificationTone? { get set }
var logLevel: LogLevel { get }
var traceLogPacks: Set<TraceLogPack> { get }
var bugReportRageshakeURL: RemotePreference<RageshakeConfiguration> { get }
@@ -95,7 +95,7 @@ final class AppSettings: @unchecked Sendable {
}
static let suiteName: String = InfoPlistReader.main.appGroupIdentifier
/// UserDefaults to be used on reads and writes.
private let store: UserDefaultsProtocol
@@ -174,7 +174,7 @@ final class AppSettings: @unchecked Sendable {
/// deleted between runs so should clear data in the shared container and keychain.
@UserPreference
var lastVersionLaunched: String?
/// The Set of room identifiers of invites that the user already saw in the invites list.
/// This Set is being used to implement badges for unread invites.
@UserPreference
@@ -196,7 +196,7 @@ final class AppSettings: @unchecked Sendable {
/// The task identifier used for background app refresh. Also used in main target's the Info.plist
let backgroundAppRefreshTaskIdentifier = "io.element.elementx.background.refresh"
/// A URL where users can go read more about the app.
private(set) var websiteURL: URL = "https://element.io"
/// A URL that contains the app's logo that may be used when showing content in a web view.
@@ -217,7 +217,7 @@ final class AppSettings: @unchecked Sendable {
private(set) var identityPinningViolationDetailsURL: URL = "https://element.io/help#encryption18"
/// A URL describing how history sharing works
private(set) var historySharingDetailsURL: URL = "https://element.io/en/help#e2ee-history-sharing"
/// Any domains that Element web may be hosted on - used for handling links.
private(set) var elementWebHosts = ["app.element.io", "staging.element.io", "develop.element.io"]
/// The domain that account provisioning links will be hosted on - used for handling the links.
@@ -279,13 +279,13 @@ final class AppSettings: @unchecked Sendable {
@UserPreference
var enableNotifications: Bool
@UserPreference
var enableInAppNotifications: Bool
@UserPreference
var hideQuietNotificationAlerts: Bool
/// Tag describing which set of device specific rules a pusher executes.
@UserPreference
var pusherProfileTag: String?
@@ -293,13 +293,13 @@ final class AppSettings: @unchecked Sendable {
/// The device's last boot time as recorded by the NSE.
@UserPreference
var lastNotificationBootTime: TimeInterval?
/// The sound played when delivering noisy notifications. If nil, use the ElementX default
@UserPreference
var selectedNotificationTone: NotificationTone?
// MARK: - Logging
@UserPreference
var logLevel: LogLevel
@@ -369,14 +369,14 @@ final class AppSettings: @unchecked Sendable {
@UserPreference
var optimizeMediaUploads: Bool
@UserPreference
var voiceMessagePlaybackSpeed: AudioPlaybackSpeed
/// Whether or not to show a warning on the media caption composer so the user knows
/// that captions might not be visible to users who are using other Matrix clients.
let shouldShowMediaCaptionWarning = true
// MARK: - Element Call
#if IS_MAIN_APP
@@ -434,13 +434,13 @@ final class AppSettings: @unchecked Sendable {
@UserPreference
var focusEventOnNotificationTap: Bool
@UserPreference
var linkPreviewsEnabled: Bool
@UserPreference
var jumpToReadMarkerEnabled: Bool
@UserPreference
var linkNewDeviceEnabled: Bool
@@ -452,11 +452,11 @@ final class AppSettings: @unchecked Sendable {
@UserPreference
var developerOptionsEnabled: Bool
init(store: UserDefaultsProtocol) {
// UserDefaults to be used on reads and writes.
self.store = store
_lastVersionLaunched = UserPreference(key: .lastVersionLaunched, storage: store)
_seenInvites = UserPreference(key: .seenInvites, defaultValue: [], storage: store)
_hasSeenNewSoundBanner = UserPreference(key: .hasSeenNewSoundBanner, defaultValue: true, storage: store)
@@ -19,7 +19,7 @@ class RemotePreference<T: Equatable> {
var publisher: CurrentValuePublisher<T, Never> {
subject.asCurrentValuePublisher()
}
var isRemotelyConfigured: Bool {
subject.value != defaultValue
}
@@ -27,7 +27,7 @@ final class UserPreference<T: Codable> {
private var remoteKey: String {
"\(Self.remotePrefix)\(key)"
}
private var keyedStorage: any KeyedStorage<T>
private let defaultValue: T
private let subject: PassthroughSubject<T, Never> = .init()
@@ -84,7 +84,7 @@ final class UserPreference<T: Codable> {
}
}
}
var projectedValue: AnyPublisher<T, Never> {
subject
.prepend(wrappedValue)
@@ -97,7 +97,7 @@ final class UserPreference<T: Codable> {
extension UserPreference {
convenience init(key: any PreferenceKeyable, defaultValue: T, storage backingStorage: UserDefaultsProtocol, mode: Mode = .localOverRemote) {
let storage: any KeyedStorage<T> = UserDefaultsStorage(userDefaults: backingStorage)
self.init(key: key, defaultValue: defaultValue, keyedStorage: storage, mode: mode)
}
@@ -9,36 +9,36 @@ import Foundation
public final class VolatileUserDefaults: UserDefaultsProtocol, Sendable {
private let lock = NSLock()
private nonisolated(unsafe) var _storage: [String: Any]
public private(set) var storage: [String: Any] {
get { lock.withLock { _storage } }
set { lock.withLock { _storage = newValue } }
}
public init(initialValues: [String: Any] = [:]) {
lock.lock()
defer { lock.unlock() }
_storage = initialValues
}
public func data(forKey key: String) -> Data? {
storage[key] as? Data
}
public func object(forKey key: String) -> Any? {
storage[key]
}
public func removeObject(forKey key: String) {
storage.removeValue(forKey: key)
}
public func set(_ value: Any?, forKey key: String) {
storage[key] = value
}
public func reset() {
storage = [:]
}
@@ -30,7 +30,7 @@ class WindowManager: SecureWindowManagerProtocol {
}
}
}
var windows: [UIWindow] {
[mainWindow, overlayWindow, globalSearchWindow, alternateWindow]
}