Replace AppSettings with UserSettings from the UserSessionFlow and below.

Remove some redundant injections when passed alongside a user session too.

# Conflicts:
#	ElementX/Sources/Screens/PinnedEventsTimelineScreen/View/PinnedEventsTimelineScreen.swift
#	ElementX/Sources/Screens/Timeline/TimelineViewModel.swift
This commit is contained in:
Doug
2026-09-25 13:51:33 +01:00
committed by Stefan Ceriu
parent 54cc1cba60
commit fccad5fc30
117 changed files with 554 additions and 594 deletions
@@ -27,11 +27,11 @@ class OAuthAccountSettingsPresenter: NSObject {
init(accountURL: URL,
presentationAnchor: UIWindow,
appMediator: AppMediatorProtocol,
appSettings: AppSettings,
userSettings: UserSettings,
appHooks: AppHooks,
continuation: Continuation? = nil) {
self.accountURL = accountURL
redirectURL = appSettings.oAuthRedirectURL
redirectURL = userSettings.oAuthRedirectURL
self.presentationAnchor = presentationAnchor
self.appMediator = appMediator
self.appHooks = appHooks
@@ -10,7 +10,7 @@ import Combine
import SwiftUI
struct AdvancedSettingsScreenCoordinatorParameters {
let appSettings: AppSettings
let userSettings: UserSettings
let analytics: AnalyticsServiceProtocol
let clientProxy: ClientProxyProtocol
let userIndicatorController: UserIndicatorControllerProtocol
@@ -20,7 +20,7 @@ final class AdvancedSettingsScreenCoordinator: CoordinatorProtocol {
private var viewModel: AdvancedSettingsScreenViewModelProtocol
init(parameters: AdvancedSettingsScreenCoordinatorParameters) {
viewModel = AdvancedSettingsScreenViewModel(advancedSettings: parameters.appSettings,
viewModel = AdvancedSettingsScreenViewModel(advancedSettings: parameters.userSettings.app,
analytics: parameters.analytics,
clientProxy: parameters.clientProxy,
userIndicatorController: parameters.userIndicatorController)
@@ -48,7 +48,7 @@ class AdvancedSettingsScreenViewModel: AdvancedSettingsScreenViewModelType, Adva
override func process(viewAction: AdvancedSettingsScreenViewAction) {
switch viewAction {
case .optimizeMediaUploadsChanged:
// Note: Using a view action here as sinking the AppSettings publisher tracks the initial value.
// Note: Using a view action here as sinking the UserSettings publisher tracks the initial value.
analytics.trackInteraction(name: state.bindings.optimizeMediaUploads ? .MobileSettingsOptimizeMediaUploadsEnabled : .MobileSettingsOptimizeMediaUploadsDisabled)
case let .updateHideInviteAvatars(value):
hideInviteAvatarsTask = Task { [weak self] in await self?.updateHideInviteAvatars(value) }
@@ -160,13 +160,10 @@ private extension AppAppearance {
// MARK: - Previews
struct AdvancedSettingsScreen_Previews: PreviewProvider, TestablePreview {
static let viewModel = {
let appSettings = AppSettings.volatile()
return AdvancedSettingsScreenViewModel(advancedSettings: appSettings,
analytics: AnalyticsServiceMock(.init()),
clientProxy: ClientProxyMock(.init()),
userIndicatorController: UserIndicatorControllerMock())
}()
static let viewModel = AdvancedSettingsScreenViewModel(advancedSettings: AppSettings.volatile(),
analytics: AnalyticsServiceMock(.init()),
clientProxy: ClientProxyMock(.init()),
userIndicatorController: UserIndicatorControllerMock())
static var previews: some View {
ElementNavigationStack {
@@ -10,7 +10,7 @@ import Combine
import SwiftUI
struct AnalyticsSettingsScreenCoordinatorParameters {
let appSettings: AppSettings
let userSettings: UserSettings
let analytics: AnalyticsServiceProtocol
}
@@ -18,7 +18,7 @@ final class AnalyticsSettingsScreenCoordinator: CoordinatorProtocol {
private let viewModel: AnalyticsSettingsScreenViewModel
init(parameters: AnalyticsSettingsScreenCoordinatorParameters) {
viewModel = AnalyticsSettingsScreenViewModel(appSettings: parameters.appSettings,
viewModel = AnalyticsSettingsScreenViewModel(userSettings: parameters.userSettings,
analytics: parameters.analytics)
}
@@ -14,16 +14,16 @@ typealias AnalyticsSettingsScreenViewModelType = StateStoreViewModelV2<Analytics
class AnalyticsSettingsScreenViewModel: AnalyticsSettingsScreenViewModelType, AnalyticsSettingsScreenViewModelProtocol {
private let analytics: AnalyticsServiceProtocol
init(appSettings: AppSettings, analytics: AnalyticsServiceProtocol) {
init(userSettings: UserSettings, analytics: AnalyticsServiceProtocol) {
self.analytics = analytics
let strings = AnalyticsSettingsScreenStrings(termsURL: appSettings.analyticsTermsURL)
let strings = AnalyticsSettingsScreenStrings(termsURL: userSettings.analyticsTermsURL)
let bindings = AnalyticsSettingsScreenViewStateBindings(enableAnalytics: analytics.isEnabled)
let state = AnalyticsSettingsScreenViewState(strings: strings, bindings: bindings)
super.init(initialViewState: state)
appSettings.analyticsConsentStatePublisher
userSettings.analyticsConsentStatePublisher
.map { $0 == .optedIn }
.weakAssign(to: \.state.bindings.enableAnalytics, on: self)
.store(in: &cancellables)
@@ -39,8 +39,8 @@ struct AnalyticsSettingsScreen: View {
struct AnalyticsSettingsScreen_Previews: PreviewProvider, TestablePreview {
static var previews: some View {
let appSettings = AppSettings.volatile()
let viewModel = AnalyticsSettingsScreenViewModel(appSettings: appSettings,
let userSettings = UserSettings.volatile()
let viewModel = AnalyticsSettingsScreenViewModel(userSettings: userSettings,
analytics: AnalyticsServiceMock(.init()))
AnalyticsSettingsScreen(context: viewModel.context)
}
@@ -12,8 +12,8 @@ import SwiftUI
final class LegalInformationScreenCoordinator: CoordinatorProtocol {
private let viewModel: LegalInformationScreenViewModelProtocol
init(appSettings: AppSettings) {
viewModel = LegalInformationScreenViewModel(appSettings: appSettings)
init(userSettings: UserSettings) {
viewModel = LegalInformationScreenViewModel(userSettings: userSettings)
}
func toPresentable() -> AnyView {
@@ -12,9 +12,9 @@ import SwiftUI
typealias LegalInformationScreenViewModelType = StateStoreViewModelV2<LegalInformationScreenViewState, LegalInformationScreenViewAction>
class LegalInformationScreenViewModel: LegalInformationScreenViewModelType, LegalInformationScreenViewModelProtocol {
init(appSettings: AppSettings) {
super.init(initialViewState: LegalInformationScreenViewState(copyrightURL: appSettings.copyrightURL,
acceptableUseURL: appSettings.acceptableUseURL,
privacyURL: appSettings.privacyURL))
init(userSettings: UserSettings) {
super.init(initialViewState: LegalInformationScreenViewState(copyrightURL: userSettings.copyrightURL,
acceptableUseURL: userSettings.acceptableUseURL,
privacyURL: userSettings.privacyURL))
}
}
@@ -33,7 +33,7 @@ struct LegalInformationScreen: View {
// MARK: - Previews
struct LegalInformationScreen_Previews: PreviewProvider, TestablePreview {
static let viewModel = LegalInformationScreenViewModel(appSettings: .volatile())
static let viewModel = LegalInformationScreenViewModel(userSettings: .volatile())
static var previews: some View {
LegalInformationScreen(context: viewModel.context)
}
@@ -15,7 +15,7 @@ struct NotificationSettingsScreenCoordinatorParameters {
let userNotificationCenter: UserNotificationCenterProtocol
let userIndicatorController: UserIndicatorControllerProtocol
let isModallyPresented: Bool
let appSettings: AppSettings
let userSettings: UserSettings
}
enum NotificationSettingsScreenCoordinatorAction {
@@ -39,9 +39,9 @@ final class NotificationSettingsScreenCoordinator: CoordinatorProtocol {
init(parameters: NotificationSettingsScreenCoordinatorParameters) {
self.parameters = parameters
viewModel = NotificationSettingsScreenViewModel(appSettings: parameters.appSettings,
viewModel = NotificationSettingsScreenViewModel(userSettings: parameters.userSettings,
userNotificationCenter: parameters.userNotificationCenter,
notificationToneManager: NotificationToneManager(appSettings: parameters.appSettings),
notificationToneManager: NotificationToneManager(userSettings: parameters.userSettings),
notificationSettingsProxy: parameters.userSession.clientProxy.notificationSettings,
userIndicatorController: parameters.userIndicatorController,
isModallyPresented: parameters.isModallyPresented)
@@ -13,7 +13,7 @@ typealias NotificationSettingsScreenViewModelType = StateStoreViewModelV2<Notifi
class NotificationSettingsScreenViewModel: NotificationSettingsScreenViewModelType, NotificationSettingsScreenViewModelProtocol {
private var actionsSubject: PassthroughSubject<NotificationSettingsScreenViewModelAction, Never> = .init()
private let appSettings: AppSettings
private let userSettings: UserSettings
private let userNotificationCenter: UserNotificationCenterProtocol
private let notificationSettingsProxy: NotificationSettingsProxyProtocol
private let userIndicatorController: UserIndicatorControllerProtocol
@@ -25,34 +25,34 @@ class NotificationSettingsScreenViewModel: NotificationSettingsScreenViewModelTy
actionsSubject.eraseToAnyPublisher()
}
init(appSettings: AppSettings,
init(userSettings: UserSettings,
userNotificationCenter: UserNotificationCenterProtocol,
notificationToneManager: NotificationToneManagerProtocol,
notificationSettingsProxy: NotificationSettingsProxyProtocol,
userIndicatorController: UserIndicatorControllerProtocol,
isModallyPresented: Bool) {
self.appSettings = appSettings
self.userSettings = userSettings
self.userNotificationCenter = userNotificationCenter
self.notificationSettingsProxy = notificationSettingsProxy
self.userIndicatorController = userIndicatorController
notificationTonePreviewer = AudioPlayer()
self.notificationToneManager = notificationToneManager
let bindings = NotificationSettingsScreenViewStateBindings(enableNotifications: appSettings.enableNotifications,
showAllRoomListActivity: appSettings.showAllRoomListActivity)
let bindings = NotificationSettingsScreenViewStateBindings(enableNotifications: userSettings.enableNotifications,
showAllRoomListActivity: userSettings.showAllRoomListActivity)
super.init(initialViewState: NotificationSettingsScreenViewState(bindings: bindings,
isModallyPresented: isModallyPresented,
selectedAlertTone: appSettings.selectedNotificationTone ?? NotificationToneManager.defaultElementXMessageTone,
selectedAlertTone: userSettings.selectedNotificationTone ?? NotificationToneManager.defaultElementXMessageTone,
availableCustomTones: notificationToneManager.customTones(),
// macos lacks default sounds and its sandbox Sounds directory is immutable
customToneSelectionEnabled: !ProcessInfo.processInfo.isiOSAppOnMac))
// Listen for changes to AppSettings.
appSettings.enableNotificationsPublisher
// Listen for changes to UserSettings.
userSettings.enableNotificationsPublisher
.weakAssign(to: \.state.bindings.enableNotifications, on: self)
.store(in: &cancellables)
appSettings.selectedNotificationTonePublisher
userSettings.selectedNotificationTonePublisher
.map { $0 ?? NotificationToneManager.defaultElementXMessageTone }
.weakAssign(to: \.state.selectedAlertTone, on: self)
.store(in: &cancellables)
@@ -104,7 +104,7 @@ class NotificationSettingsScreenViewModel: NotificationSettingsScreenViewModelTy
}
Task { await enableInvitations(state.bindings.invitationsEnabled) }
case .showAllRoomListActivityChanged:
appSettings.showAllRoomListActivity = state.bindings.showAllRoomListActivity
userSettings.showAllRoomListActivity = state.bindings.showAllRoomListActivity
case .close:
actionsSubject.send(.close)
case .fixConfigurationMismatchTapped:
@@ -127,7 +127,7 @@ class NotificationSettingsScreenViewModel: NotificationSettingsScreenViewModelTy
}
func toggleNotifications() {
appSettings.enableNotifications.toggle()
userSettings.enableNotifications.toggle()
}
private func setupDidBecomeActiveSubscription() {
@@ -302,7 +302,7 @@ class NotificationSettingsScreenViewModel: NotificationSettingsScreenViewModelTy
try notificationToneManager.deleteCustomTone(tone)
if tone == state.selectedAlertTone {
appSettings.selectedNotificationTone = nil
userSettings.selectedNotificationTone = nil
}
} catch {
MXLog.error("Error deleting alert tone \(tone.label): \(error)")
@@ -261,7 +261,7 @@ struct NotificationSettingsScreen: View {
@available(iOS 26.0, *)
struct NotificationSettingsScreen_Previews: PreviewProvider, TestablePreview {
static let viewModel: NotificationSettingsScreenViewModel = {
let appSettings = AppSettings.volatile()
let userSettings = UserSettings.volatile()
let notificationCenter = UserNotificationCenterMock()
notificationCenter.authorizationStatusReturnValue = .notDetermined
let notificationSettingsProxy = NotificationSettingsProxyMock(with: .init())
@@ -278,7 +278,7 @@ struct NotificationSettingsScreen_Previews: PreviewProvider, TestablePreview {
let userSession = UserSessionMock(.init(clientProxy: ClientProxyMock(.init(userID: "John Doe"))))
var viewModel = NotificationSettingsScreenViewModel(appSettings: appSettings,
var viewModel = NotificationSettingsScreenViewModel(userSettings: userSettings,
userNotificationCenter: notificationCenter,
notificationToneManager: NotificationToneManagerMock(.init()),
notificationSettingsProxy: notificationSettingsProxy,
@@ -289,7 +289,7 @@ struct NotificationSettingsScreen_Previews: PreviewProvider, TestablePreview {
}()
static let viewModelConfigurationMismatch: NotificationSettingsScreenViewModel = {
let appSettings = AppSettings.volatile()
let userSettings = UserSettings.volatile()
let notificationCenter = UserNotificationCenterMock()
notificationCenter.authorizationStatusReturnValue = .notDetermined
let notificationSettingsProxy = NotificationSettingsProxyMock(with: .init())
@@ -308,7 +308,7 @@ struct NotificationSettingsScreen_Previews: PreviewProvider, TestablePreview {
let userSession = UserSessionMock(.init(clientProxy: ClientProxyMock(.init(userID: "John Doe"))))
var viewModel = NotificationSettingsScreenViewModel(appSettings: appSettings,
var viewModel = NotificationSettingsScreenViewModel(userSettings: userSettings,
userNotificationCenter: notificationCenter,
notificationToneManager: NotificationToneManagerMock(.init()),
notificationSettingsProxy: notificationSettingsProxy,
@@ -11,7 +11,7 @@ import SwiftUI
struct SettingsScreenCoordinatorParameters {
let userSession: UserSessionProtocol
let appSettings: AppSettings
let userSettings: UserSettings
let isBugReportServiceEnabled: Bool
let isInSecondaryWindow: Bool
let userIndicatorController: UserIndicatorControllerProtocol
@@ -51,7 +51,7 @@ final class SettingsScreenCoordinator: CoordinatorProtocol {
init(parameters: SettingsScreenCoordinatorParameters) {
viewModel = SettingsScreenViewModel(userSession: parameters.userSession,
appSettings: parameters.appSettings,
userSettings: parameters.userSettings,
isBugReportServiceEnabled: parameters.isBugReportServiceEnabled,
isInSecondaryWindow: parameters.isInSecondaryWindow,
userIndicatorController: parameters.userIndicatorController)
@@ -12,7 +12,7 @@ import SwiftUI
typealias SettingsScreenViewModelType = StateStoreViewModelV2<SettingsScreenViewState, SettingsScreenViewAction>
class SettingsScreenViewModel: SettingsScreenViewModelType, SettingsScreenViewModelProtocol {
private let appSettings: AppSettings
private let userSettings: UserSettings
private let clientProxy: ClientProxyProtocol
private let userIndicatorController: UserIndicatorControllerProtocol
@@ -22,26 +22,26 @@ class SettingsScreenViewModel: SettingsScreenViewModelType, SettingsScreenViewMo
actionsSubject.eraseToAnyPublisher()
}
init(userSession: UserSessionProtocol, appSettings: AppSettings, isBugReportServiceEnabled: Bool, isInSecondaryWindow: Bool, userIndicatorController: UserIndicatorControllerProtocol) {
self.appSettings = appSettings
init(userSession: UserSessionProtocol, userSettings: UserSettings, isBugReportServiceEnabled: Bool, isInSecondaryWindow: Bool, userIndicatorController: UserIndicatorControllerProtocol) {
self.userSettings = userSettings
clientProxy = userSession.clientProxy
self.userIndicatorController = userIndicatorController
super.init(initialViewState: .init(deviceID: userSession.clientProxy.deviceID,
userProfile: userSession.clientProxy.userProfilePublisher.value,
showLinkNewDeviceButton: appSettings.linkNewDeviceEnabled,
showLinkNewDeviceButton: userSettings.linkNewDeviceEnabled,
showAccountDeactivation: userSession.clientProxy.canDeactivateAccount,
showDeveloperOptions: appSettings.developerOptionsEnabled,
showAnalyticsSettings: appSettings.canPromptForAnalytics,
showDeveloperOptions: userSettings.developerOptionsEnabled,
showAnalyticsSettings: userSettings.canPromptForAnalytics,
isBugReportServiceEnabled: isBugReportServiceEnabled,
navigationBarVisibility: isInSecondaryWindow ? .hidden : .automatic),
mediaProvider: userSession.mediaProvider)
appSettings.developerOptionsEnabledPublisher
userSettings.developerOptionsEnabledPublisher
.weakAssign(to: \.state.showDeveloperOptions, on: self)
.store(in: &cancellables)
appSettings.linkNewDeviceEnabledPublisher
userSettings.linkNewDeviceEnabledPublisher
.weakAssign(to: \.state.showLinkNewDeviceButton, on: self)
.store(in: &cancellables)
@@ -138,7 +138,7 @@ class SettingsScreenViewModel: SettingsScreenViewModelType, SettingsScreenViewMo
case .labs:
actionsSubject.send(.labs)
case .enableDeveloperOptions:
appSettings.developerOptionsEnabled.toggle()
userSettings.developerOptionsEnabled.toggle()
case .developerOptions:
actionsSubject.send(.developerOptions)
case .deactivateAccount:
@@ -313,7 +313,7 @@ struct SettingsScreen_Previews: PreviewProvider, TestablePreview {
displayName: "Alice Liddell",
status: .mockFocussing))))
return SettingsScreenViewModel(userSession: userSession,
appSettings: .volatile(),
userSettings: .volatile(),
isBugReportServiceEnabled: isBugReportServiceEnabled,
isInSecondaryWindow: false,
userIndicatorController: UserIndicatorControllerMock())
@@ -145,7 +145,7 @@ struct UserDetailsEditScreen_Previews: PreviewProvider, TestablePreview {
canChangeDisplayName: canChangeProfile))))
return UserDetailsEditScreenViewModel(userSession: userSession,
mediaUploadingPreprocessor: .init(appSettings: .volatile()),
mediaUploadingPreprocessor: .init(userSettings: .volatile()),
userIndicatorController: UserIndicatorControllerMock())
}
}