Make the remote settings hook usable within the app extensions. (#4342)

This commit is contained in:
Doug
2025-07-22 17:09:53 +01:00
committed by GitHub
parent 82c659f3da
commit 5e165be8c3
20 changed files with 245 additions and 139 deletions
@@ -702,6 +702,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
tearDownUserSession()
AppSettings.resetSessionSpecificSettings()
appHooks.remoteSettingsHook.reset(appSettings)
// Reset analytics
ServiceLocator.shared.analytics.optOut()
@@ -20,6 +20,7 @@ protocol CommonSettingsProtocol {
var enableKeyShareOnInvite: Bool { get }
var hideQuietNotificationAlerts: Bool { get }
var threadsEnabled: Bool { get }
var bugReportRageshakeURL: RemotePreference<RageshakeConfiguration> { get }
}
/// Store Element specific app settings.
@@ -252,7 +253,6 @@ final class AppSettings {
// MARK: - Bug report
let bugReportRageshakeURL: ConfigurableSetting<RageshakeConfiguration> = .init(Secrets.rageshakeURL.map { .url(URL(string: $0)!) } ?? .disabled) // swiftlint:disable:this force_unwrapping
let bugReportSentryURL: URL? = Secrets.sentryDSN.map { URL(string: $0)! } // swiftlint:disable:this force_unwrapping
let bugReportSentryRustURL: URL? = Secrets.sentryRustDSN.map { URL(string: $0)! } // swiftlint:disable:this force_unwrapping
/// The name allocated by the bug report server
@@ -375,6 +375,8 @@ final class AppSettings {
@UserPreference(key: UserDefaultsKeys.threadsEnabled, defaultValue: false, storageType: .userDefaults(store))
var threadsEnabled
let bugReportRageshakeURL: RemotePreference<RageshakeConfiguration> = .init(Secrets.rageshakeURL.map { .url(URL(string: $0)!) } ?? .disabled) // swiftlint:disable:this force_unwrapping
}
extension AppSettings: CommonSettingsProtocol { }
@@ -1,35 +0,0 @@
//
// Copyright 2025 New Vector Ltd.
//
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
// Please see LICENSE files in the repository root for full details.
//
import Combine
/// A setting that can be instantiated with an initial value, overridden and reset back again,
/// automatically publishing the changes for downstream subscribers to react to.
///
/// Unlike ``UserPreference``, this type of setting isn't settable by the user, nor is the
/// override persisted between app launches.
struct ConfigurableSetting<T: Equatable> {
private let initialValue: T
private let subject: CurrentValueSubject<T, Never>
var publisher: CurrentValuePublisher<T, Never> { subject.asCurrentValuePublisher() }
var isOverridden: Bool { subject.value != initialValue }
init(_ initialValue: T) {
self.initialValue = initialValue
subject = .init(initialValue)
}
func override(_ value: T) {
subject.send(value)
}
func reset() {
if isOverridden {
subject.send(initialValue)
}
}
}
@@ -0,0 +1,16 @@
//
// Copyright 2025 New Vector Ltd.
//
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
// Please see LICENSE files in the repository root for full details.
//
import Foundation
/// A type that represents how rageshakes are collected by the app.
enum RageshakeConfiguration: Equatable, Codable {
/// Rageshakes should be sent to the provided URL
case url(URL)
/// Rageshakes are disabled.
case disabled
}
@@ -0,0 +1,35 @@
//
// Copyright 2025 New Vector Ltd.
//
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
// Please see LICENSE files in the repository root for full details.
//
import Combine
/// A setting that can be instantiated with a default value, remotely overridden and reset back
/// to the default, automatically publishing the changes for downstream subscribers to react to.
///
/// Unlike ``UserPreference``, this type of setting isn't settable by the user, nor is the
/// remote value persisted between app launches.
struct RemotePreference<T: Equatable> {
private let defaultValue: T
private let subject: CurrentValueSubject<T, Never>
var publisher: CurrentValuePublisher<T, Never> { subject.asCurrentValuePublisher() }
var isRemotelyConfigured: Bool { subject.value != defaultValue }
init(_ defaultValue: T) {
self.defaultValue = defaultValue
subject = .init(defaultValue)
}
func applyRemoteValue(_ value: T) {
subject.send(value)
}
func reset() {
if isRemotelyConfigured {
subject.send(defaultValue)
}
}
}