mirror of
https://github.com/element-hq/element-x-ios.git
synced 2025-03-10 21:39:12 +00:00
Resetting the app after deletion and cleanup settings (#372)
* Fixes #361 - Reset everything if the app has been deleted since the last run * Cleaned up and renamed the ElementSettings to ApplicationSettings. Removed its singleton and moved it to the service locator. * Moved the ApplicationSettings to the Application folder * Merged together the BuildSettings and ApplicationSettings * Reset the UserDefaults too when resetting the application state * Rename ServiceLocator.applicationSettings to just settings * Fix indentation * Rename ApplicationSettings to AppSettings * Various tweaks following code review * Fix unit tests
This commit is contained in:
parent
5b90f37f2e
commit
6f974a4422
@ -40,6 +40,7 @@
|
||||
0F3F2FDD4021A25A0D57F801 /* MediaProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 885D8C42DD17625B5261BEFF /* MediaProvider.swift */; };
|
||||
0F9E38A75337D0146652ACAB /* BackgroundTaskTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DFCAA239095A116976E32C4 /* BackgroundTaskTests.swift */; };
|
||||
1281625B25371BE53D36CB3A /* SeparatorRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1ED7E89865201EE7D53E6DA /* SeparatorRoomTimelineItem.swift */; };
|
||||
12CCA59536EDD99A3272CF77 /* AppSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = AC3F82523D6F48B926D6AF68 /* AppSettings.swift */; };
|
||||
132D241B09F9044711FD70A5 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 91DE43B8815918E590912DDA /* InfoPlist.strings */; };
|
||||
13853973A5E24374FCEDE8A3 /* RedactedRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8F2A7A4E3F5060F52ACFFB0 /* RedactedRoomTimelineView.swift */; };
|
||||
13C77FDF17C4C6627CFFC205 /* RoomTimelineItemFactoryProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7D25A35764C7B3DB78954AB5 /* RoomTimelineItemFactoryProtocol.swift */; };
|
||||
@ -86,7 +87,6 @@
|
||||
28410F3DE89C2C44E4F75C92 /* MockBugReportService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0E7BF8F7BB1021F889C6483 /* MockBugReportService.swift */; };
|
||||
290FDB0FFDC2F1DDF660343E /* TestMeasurementParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C4048041C1A6B20CB97FD18 /* TestMeasurementParser.swift */; };
|
||||
297CD0A27C87B0C50FF192EE /* RoomTimelineViewFactoryProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEE384418EB1FEDFA62C9CD0 /* RoomTimelineViewFactoryProtocol.swift */; };
|
||||
29E20505F321071E8375F99B /* BuildSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 263B3B811C2B900F12C6F695 /* BuildSettings.swift */; };
|
||||
29EE1791E0AFA1ABB7F23D2F /* SwiftyBeaver in Frameworks */ = {isa = PBXBuildFile; productRef = A981A4CA233FB5C13B9CA690 /* SwiftyBeaver */; };
|
||||
2ABF11717C64054CEF2819A3 /* RoomTimelineController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F85164F9475FF2867F71AAA /* RoomTimelineController.swift */; };
|
||||
2B9AEEC12B1BBE5BD61D0F5E /* UserSessionFlowCoordinatorStateMachine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3429142FE11930422E7CC1A0 /* UserSessionFlowCoordinatorStateMachine.swift */; };
|
||||
@ -269,6 +269,7 @@
|
||||
91DFCB641FBA03EE2DA0189E /* FilePreviewScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FB27E1BE894F9F9F0134372 /* FilePreviewScreen.swift */; };
|
||||
9219640F4D980CFC5FE855AD /* target.yml in Resources */ = {isa = PBXBuildFile; fileRef = 536E72DCBEEC4A1FE66CFDCE /* target.yml */; };
|
||||
92B95779840CD749117B3615 /* EmojiMartStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38AE3617D7619EF30CDD229 /* EmojiMartStore.swift */; };
|
||||
9377D6BE1511E1529EA1662B /* AppSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = AC3F82523D6F48B926D6AF68 /* AppSettings.swift */; };
|
||||
93875ADD456142D20823ED24 /* ServerSelectionViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDAA4472821985BF868CC21C /* ServerSelectionViewModelTests.swift */; };
|
||||
93BA4A81B6D893271101F9F0 /* DTCoreText in Frameworks */ = {isa = PBXBuildFile; productRef = 531CE4334AC5CA8DFF6AEB84 /* DTCoreText */; };
|
||||
9462C62798F47E39DCC182D2 /* Application.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA89A2DD51B6BBE1DA55E263 /* Application.swift */; };
|
||||
@ -277,7 +278,6 @@
|
||||
964B9D2EC38C488C360CE0C9 /* HomeScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = B902EA6CD3296B0E10EE432B /* HomeScreen.swift */; };
|
||||
968A5B890004526AB58A217C /* AvatarSize.swift in Sources */ = {isa = PBXBuildFile; fileRef = E24B88AD3D1599E8CB1376E0 /* AvatarSize.swift */; };
|
||||
97189E495F0E47805D1868DB /* DTCoreText in Frameworks */ = {isa = PBXBuildFile; productRef = 527578916BD388A09F5A8036 /* DTCoreText */; };
|
||||
9738F894DB1BD383BE05767A /* ElementSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1027BB9A852F445B7623897F /* ElementSettings.swift */; };
|
||||
978BB24F2A5D31EE59EEC249 /* UserSessionProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F4134FEFE4EB55759017408 /* UserSessionProtocol.swift */; };
|
||||
97CECF91D68235F1D13598D7 /* AnalyticsConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D77B3D4950F1707E66E4A45A /* AnalyticsConfiguration.swift */; };
|
||||
981853650217B6C8ECDD998C /* NavigationRootCoordinatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F875D71347DC81EAE7687446 /* NavigationRootCoordinatorTests.swift */; };
|
||||
@ -369,7 +369,6 @@
|
||||
C8E82786DE1B6A400DA9BA25 /* RoomTimelineItemProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 289FA233E896FBC5956C67E0 /* RoomTimelineItemProperties.swift */; };
|
||||
C94A6048C654B01163AE1BF1 /* VideoPlayerViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5282B7A2DCD076AD2CF27F46 /* VideoPlayerViewModelProtocol.swift */; };
|
||||
CA45758F08DF42D41D8A4B29 /* FilePreviewViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF38B69D2C331A499276F400 /* FilePreviewViewModelTests.swift */; };
|
||||
CA9558C0B40C1EE2AD00124A /* BuildSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 263B3B811C2B900F12C6F695 /* BuildSettings.swift */; };
|
||||
CB137BFB3E083C33E398A6CB /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = 0DD568A494247444A4B56031 /* Kingfisher */; };
|
||||
CB326BAB54E9B68658909E36 /* Benchmark.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49EAD710A2C16EFF7C3EA16F /* Benchmark.swift */; };
|
||||
CB498F4E27AA0545DCEF0F6F /* DeviceKit in Frameworks */ = {isa = PBXBuildFile; productRef = 4003BC24B24C9E63D3304177 /* DeviceKit */; };
|
||||
@ -533,7 +532,6 @@
|
||||
0E8BDC092D817B68CD9040C5 /* UserSessionStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSessionStore.swift; sourceTree = "<group>"; };
|
||||
0EE9EAF0309A2A1D67D8FAF5 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = sv; path = sv.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||
0F52BF30D12BA3BD3D3DBB8F /* ServerSelectionViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerSelectionViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||
1027BB9A852F445B7623897F /* ElementSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElementSettings.swift; sourceTree = "<group>"; };
|
||||
1059E2AE7878CF7820592637 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
|
||||
105B2A8426404EF66F00CFDB /* RoomTimelineItemFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineItemFactory.swift; sourceTree = "<group>"; };
|
||||
105D16E7DB0CCE9526612BDD /* bn-IN */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "bn-IN"; path = "bn-IN.lproj/Localizable.strings"; sourceTree = "<group>"; };
|
||||
@ -583,7 +581,6 @@
|
||||
24F5530B2212862FA4BEFF2D /* HomeScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||
2583416C8974272ADBADDBE1 /* zh-TW */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "zh-TW"; path = "zh-TW.lproj/Localizable.stringsdict"; sourceTree = "<group>"; };
|
||||
25F7FE40EF7490A7E09D7BE6 /* NotificationItemProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationItemProxy.swift; sourceTree = "<group>"; };
|
||||
263B3B811C2B900F12C6F695 /* BuildSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BuildSettings.swift; sourceTree = "<group>"; };
|
||||
26C4D226FCD20BAC53F1E092 /* ml */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ml; path = ml.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
27A1AD6389A4659AF0CEAE62 /* NotificationServiceExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationServiceExtension.swift; sourceTree = "<group>"; };
|
||||
287FC98AF2664EAD79C0D902 /* UIDevice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIDevice.swift; sourceTree = "<group>"; };
|
||||
@ -836,6 +833,7 @@
|
||||
AAE73D571D4F9C36DD45255A /* BackgroundTaskServiceProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundTaskServiceProtocol.swift; sourceTree = "<group>"; };
|
||||
AB785716B9212C093704E767 /* EmojiPickerHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiPickerHeaderView.swift; sourceTree = "<group>"; };
|
||||
AB8E75B9CB6C78BE8D09B1AF /* OnboardingScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingScreen.swift; sourceTree = "<group>"; };
|
||||
AC3F82523D6F48B926D6AF68 /* AppSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSettings.swift; sourceTree = "<group>"; };
|
||||
ACA11F7F50A4A3887A18CA5A /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
ACB6C5E4950B6C9842F35A38 /* RoomTimelineViewProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineViewProvider.swift; sourceTree = "<group>"; };
|
||||
AD378D580A41E42560C60E9C /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
@ -1978,7 +1976,7 @@
|
||||
077D7C3BE199B6E5DDEC07EC /* AppCoordinatorStateMachine.swift */,
|
||||
C75EF87651B00A176AB08E97 /* AppDelegate.swift */,
|
||||
CA89A2DD51B6BBE1DA55E263 /* Application.swift */,
|
||||
263B3B811C2B900F12C6F695 /* BuildSettings.swift */,
|
||||
AC3F82523D6F48B926D6AF68 /* AppSettings.swift */,
|
||||
B251F5B4511D1CA0BA8361FE /* CoordinatorProtocol.swift */,
|
||||
57F95CADD0A5DBD76B990FCB /* ServiceLocator.swift */,
|
||||
780F74C73E826685A9DB289B /* Navigation */,
|
||||
@ -2075,7 +2073,6 @@
|
||||
E24B88AD3D1599E8CB1376E0 /* AvatarSize.swift */,
|
||||
49EAD710A2C16EFF7C3EA16F /* Benchmark.swift */,
|
||||
E5272BC4A60B6AD7553BACA1 /* BlurHashDecode.swift */,
|
||||
1027BB9A852F445B7623897F /* ElementSettings.swift */,
|
||||
12A626D74BBE9F4A60763B45 /* ImageAnonymizer.swift */,
|
||||
6A580295A56B55A856CC4084 /* InfoPlistReader.swift */,
|
||||
6AD1A853D605C2146B0DC028 /* MatrixEntityRegex.swift */,
|
||||
@ -2808,6 +2805,7 @@
|
||||
A021827B528F1EDC9101CA58 /* AppCoordinatorProtocol.swift in Sources */,
|
||||
4FF90E2242DBD596E1ED2E27 /* AppCoordinatorStateMachine.swift in Sources */,
|
||||
9D9690D2FD4CD26FF670620F /* AppDelegate.swift in Sources */,
|
||||
12CCA59536EDD99A3272CF77 /* AppSettings.swift in Sources */,
|
||||
9462C62798F47E39DCC182D2 /* Application.swift in Sources */,
|
||||
74604ACFDBE7F54260E7B617 /* ApplicationProtocol.swift in Sources */,
|
||||
90EB25D13AE6EEF034BDE9D2 /* Assets.swift in Sources */,
|
||||
@ -2830,7 +2828,6 @@
|
||||
172E6E9A612ADCF10A62CF13 /* BugReportServiceProtocol.swift in Sources */,
|
||||
86C2E93920FD15AD17E193A9 /* BugReportViewModel.swift in Sources */,
|
||||
187E18F21EF4DA244E436E58 /* BugReportViewModelProtocol.swift in Sources */,
|
||||
CA9558C0B40C1EE2AD00124A /* BuildSettings.swift in Sources */,
|
||||
E1DF24D085572A55C9758A2D /* Bundle.swift in Sources */,
|
||||
6A0E7551E0D1793245F34CDD /* ClientError.swift in Sources */,
|
||||
1950A80CD198BED283DFC2CE /* ClientProxy.swift in Sources */,
|
||||
@ -2841,7 +2838,6 @@
|
||||
1CF18DE71D5D23C61BD88852 /* DebugScreen.swift in Sources */,
|
||||
EE8491AD81F47DF3C192497B /* DecorationTimelineItemProtocol.swift in Sources */,
|
||||
FE4593FC2A02AAF92E089565 /* ElementAnimations.swift in Sources */,
|
||||
9738F894DB1BD383BE05767A /* ElementSettings.swift in Sources */,
|
||||
D8CFF02C2730EE5BC4F17ABF /* ElementToggleStyle.swift in Sources */,
|
||||
7C1A7B594B2F8143F0DD0005 /* ElementXAttributeScope.swift in Sources */,
|
||||
7361B011A79BF723D8C9782B /* EmojiCategory.swift in Sources */,
|
||||
@ -3081,10 +3077,10 @@
|
||||
files = (
|
||||
97CECF91D68235F1D13598D7 /* AnalyticsConfiguration.swift in Sources */,
|
||||
8024BE37156FF0A95A7A3465 /* AnalyticsPromptUITests.swift in Sources */,
|
||||
9377D6BE1511E1529EA1662B /* AppSettings.swift in Sources */,
|
||||
7405B4824D45BA7C3D943E76 /* Application.swift in Sources */,
|
||||
ACF094CF3BF02DBFA6DFDE60 /* AuthenticationCoordinatorUITests.swift in Sources */,
|
||||
7756C4E90CABE6F14F7920A0 /* BugReportUITests.swift in Sources */,
|
||||
29E20505F321071E8375F99B /* BuildSettings.swift in Sources */,
|
||||
94D0F36A87E596A93C0C178A /* Bundle.swift in Sources */,
|
||||
E3C328EF20C4B3326D263BCD /* FileManager.swift in Sources */,
|
||||
9DC5FB22B8F86C3B51E907C1 /* HomeScreenUITests.swift in Sources */,
|
||||
|
@ -52,23 +52,30 @@ class AppCoordinator: AppCoordinatorProtocol {
|
||||
|
||||
init() {
|
||||
navigationRootCoordinator = NavigationRootCoordinator()
|
||||
|
||||
Self.setupServiceLocator(navigationRootCoordinator: navigationRootCoordinator)
|
||||
Self.setupLogging()
|
||||
|
||||
stateMachine = AppCoordinatorStateMachine()
|
||||
|
||||
bugReportService = BugReportService(withBaseURL: BuildSettings.bugReportServiceBaseURL, sentryURL: BuildSettings.bugReportSentryURL)
|
||||
bugReportService = BugReportService(withBaseURL: ServiceLocator.shared.settings.bugReportServiceBaseURL, sentryURL: ServiceLocator.shared.settings.bugReportSentryURL)
|
||||
|
||||
navigationRootCoordinator.setRootCoordinator(SplashScreenCoordinator())
|
||||
|
||||
ServiceLocator.shared.register(userNotificationController: UserNotificationController(rootCoordinator: navigationRootCoordinator))
|
||||
|
||||
backgroundTaskService = UIKitBackgroundTaskService {
|
||||
UIApplication.shared
|
||||
}
|
||||
|
||||
userSessionStore = UserSessionStore(backgroundTaskService: backgroundTaskService)
|
||||
|
||||
setupStateMachine()
|
||||
// Reset everything if the app has been deleted since the previous run
|
||||
if !ServiceLocator.shared.settings.hasAppLaunchedOnce {
|
||||
AppSettings.reset()
|
||||
userSessionStore.reset()
|
||||
ServiceLocator.shared.settings.hasAppLaunchedOnce = true
|
||||
}
|
||||
|
||||
setupLogging()
|
||||
setupStateMachine()
|
||||
|
||||
Bundle.elementFallbackLanguage = "en"
|
||||
|
||||
@ -91,7 +98,12 @@ class AppCoordinator: AppCoordinatorProtocol {
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func setupLogging() {
|
||||
private static func setupServiceLocator(navigationRootCoordinator: NavigationRootCoordinator) {
|
||||
ServiceLocator.shared.register(userNotificationController: UserNotificationController(rootCoordinator: navigationRootCoordinator))
|
||||
ServiceLocator.shared.register(appSettings: AppSettings())
|
||||
}
|
||||
|
||||
private static func setupLogging() {
|
||||
let loggerConfiguration = MXLogConfiguration()
|
||||
loggerConfiguration.maxLogFilesCount = 10
|
||||
|
||||
@ -270,7 +282,7 @@ class AppCoordinator: AppCoordinatorProtocol {
|
||||
}
|
||||
|
||||
private func configureNotificationManager() {
|
||||
guard BuildSettings.enableNotifications else {
|
||||
guard ServiceLocator.shared.settings.enableNotifications else {
|
||||
return
|
||||
}
|
||||
guard notificationManager == nil else {
|
||||
|
138
ElementX/Sources/Application/AppSettings.swift
Normal file
138
ElementX/Sources/Application/AppSettings.swift
Normal file
@ -0,0 +1,138 @@
|
||||
//
|
||||
// Copyright 2022 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
/// Store Element specific app settings.
|
||||
final class AppSettings: ObservableObject {
|
||||
private enum UserDefaultsKeys: String {
|
||||
case hasAppLaunchedOnce
|
||||
case timelineStyle
|
||||
case enableAnalytics
|
||||
case isIdentifiedForAnalytics
|
||||
case slidingSyncProxyBaseURLString
|
||||
case enableInAppNotifications
|
||||
case pusherProfileTag
|
||||
}
|
||||
|
||||
private static var suiteName: String = InfoPlistReader.target.appGroupIdentifier
|
||||
|
||||
/// UserDefaults to be used on reads and writes.
|
||||
private static var store: UserDefaults! = UserDefaults(suiteName: suiteName)
|
||||
|
||||
static func reset() {
|
||||
store.removePersistentDomain(forName: suiteName)
|
||||
}
|
||||
|
||||
static func configureWithSuiteName(_ name: String) {
|
||||
suiteName = name
|
||||
|
||||
guard let userDefaults = UserDefaults(suiteName: name) else {
|
||||
fatalError("Fail to load shared UserDefaults")
|
||||
}
|
||||
|
||||
store = userDefaults
|
||||
}
|
||||
|
||||
// MARK: - Application
|
||||
|
||||
/// Simple flag to check if app has been deleted between runs.
|
||||
/// Used to clear data stored in the shared container and keychain
|
||||
@AppStorage(UserDefaultsKeys.hasAppLaunchedOnce.rawValue, store: store)
|
||||
var hasAppLaunchedOnce = false
|
||||
|
||||
let defaultHomeserverAddress = "matrix.org"
|
||||
|
||||
// MARK: - Notifications
|
||||
|
||||
var pusherAppId: String {
|
||||
#if DEBUG
|
||||
InfoPlistReader.target.baseBundleIdentifier + ".ios.dev"
|
||||
#else
|
||||
InfoPlistReader.target.baseBundleIdentifier + ".ios.prod"
|
||||
#endif
|
||||
}
|
||||
|
||||
let pushGatewayBaseURL = URL(staticString: "https://matrix.org/_matrix/push/v1/notify")
|
||||
|
||||
let enableNotifications = false
|
||||
|
||||
// MARK: - Bug report
|
||||
|
||||
let bugReportServiceBaseURL = URL(staticString: "https://riot.im/bugreports")
|
||||
let bugReportSentryURL = URL(staticString: "https://f39ac49e97714316965b777d9f3d6cd8@sentry.tools.element.io/44")
|
||||
// Use the name allocated by the bug report server
|
||||
let bugReportApplicationId = "riot-ios"
|
||||
let bugReportUISIId = "element-auto-uisi"
|
||||
let bugReportGHLabels = ["Element-X"]
|
||||
|
||||
// MARK: - Analytics
|
||||
|
||||
#if DEBUG
|
||||
/// The configuration to use for analytics during development. Set `isEnabled` to false to disable analytics in debug builds.
|
||||
/// **Note:** Analytics are disabled by default for forks. If you are maintaining a fork, set custom configurations.
|
||||
let analyticsConfiguration = AnalyticsConfiguration(isEnabled: InfoPlistReader.target.bundleIdentifier.starts(with: "io.element.elementx"),
|
||||
host: "https://posthog.element.dev",
|
||||
apiKey: "phc_VtA1L35nw3aeAtHIx1ayrGdzGkss7k1xINeXcoIQzXN",
|
||||
termsURL: URL(staticString: "https://element.io/cookie-policy"))
|
||||
#else
|
||||
/// The configuration to use for analytics. Set `isEnabled` to false to disable analytics.
|
||||
/// **Note:** Analytics are disabled by default for forks. If you are maintaining a fork, set custom configurations.
|
||||
let analyticsConfiguration = AnalyticsConfiguration(isEnabled: InfoPlistReader.target.bundleIdentifier.starts(with: "io.element.elementx"),
|
||||
host: "https://posthog.hss.element.io",
|
||||
apiKey: "phc_Jzsm6DTm6V2705zeU5dcNvQDlonOR68XvX2sh1sEOHO",
|
||||
termsURL: URL(staticString: "https://element.io/cookie-policy"))
|
||||
#endif
|
||||
|
||||
/// Whether the user has already been shown the PostHog analytics prompt.
|
||||
var hasSeenAnalyticsPrompt: Bool {
|
||||
Self.store.object(forKey: UserDefaultsKeys.enableAnalytics.rawValue) != nil
|
||||
}
|
||||
|
||||
/// `true` when the user has opted in to send analytics.
|
||||
@AppStorage(UserDefaultsKeys.enableAnalytics.rawValue, store: store)
|
||||
var enableAnalytics = false
|
||||
|
||||
/// Indicates if the device has already called identify for this session to PostHog.
|
||||
/// This is separate to `enableAnalytics` as logging out leaves analytics
|
||||
/// enabled, but requires the next account to be identified separately.
|
||||
@AppStorage(UserDefaultsKeys.isIdentifiedForAnalytics.rawValue, store: store)
|
||||
var isIdentifiedForAnalytics = false
|
||||
|
||||
// MARK: - Room Screen
|
||||
|
||||
@AppStorage(UserDefaultsKeys.timelineStyle.rawValue, store: store)
|
||||
var timelineStyle = TimelineStyle.bubbles
|
||||
|
||||
// MARK: - Client
|
||||
|
||||
@AppStorage(UserDefaultsKeys.slidingSyncProxyBaseURLString.rawValue, store: store)
|
||||
var slidingSyncProxyBaseURLString = "https://slidingsync.lab.element.dev"
|
||||
|
||||
// MARK: - Notifications
|
||||
|
||||
@AppStorage(UserDefaultsKeys.enableInAppNotifications.rawValue, store: store)
|
||||
var enableInAppNotifications = true
|
||||
|
||||
/// Tag describing which set of device specific rules a pusher executes.
|
||||
@AppStorage(UserDefaultsKeys.pusherProfileTag.rawValue, store: store)
|
||||
var pusherProfileTag: String?
|
||||
|
||||
// MARK: - Other
|
||||
|
||||
let permalinkBaseURL = URL(staticString: "https://matrix.to")
|
||||
}
|
@ -1,80 +0,0 @@
|
||||
//
|
||||
// Copyright 2022 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
final class BuildSettings {
|
||||
// MARK: - Bundle Settings
|
||||
|
||||
static var pusherAppId: String {
|
||||
#if DEBUG
|
||||
InfoPlistReader.target.baseBundleIdentifier + ".ios.dev"
|
||||
#else
|
||||
InfoPlistReader.target.baseBundleIdentifier + ".ios.prod"
|
||||
#endif
|
||||
}
|
||||
|
||||
// MARK: - Servers
|
||||
|
||||
static let defaultHomeserverAddress = "matrix.org"
|
||||
static let defaultSlidingSyncProxyBaseURLString = "https://slidingsync.lab.element.dev"
|
||||
static let pushGatewayBaseURL = URL(staticString: "https://matrix.org/_matrix/push/v1/notify")
|
||||
|
||||
// MARK: - Bug report
|
||||
|
||||
static let bugReportServiceBaseURL = URL(staticString: "https://riot.im/bugreports")
|
||||
static let bugReportSentryURL = URL(staticString: "https://f39ac49e97714316965b777d9f3d6cd8@sentry.tools.element.io/44")
|
||||
// Use the name allocated by the bug report server
|
||||
static let bugReportApplicationId = "riot-ios"
|
||||
static let bugReportUISIId = "element-auto-uisi"
|
||||
|
||||
static let bugReportGHLabels = ["Element-X"]
|
||||
|
||||
// MARK: - Analytics
|
||||
|
||||
#if DEBUG
|
||||
/// The configuration to use for analytics during development. Set `isEnabled` to false to disable analytics in debug builds.
|
||||
/// **Note:** Analytics are disabled by default for forks. If you are maintaining a fork, set custom configurations.
|
||||
static let analyticsConfiguration = AnalyticsConfiguration(isEnabled: InfoPlistReader.target.bundleIdentifier.starts(with: "io.element.elementx"),
|
||||
host: "https://posthog.element.dev",
|
||||
apiKey: "phc_VtA1L35nw3aeAtHIx1ayrGdzGkss7k1xINeXcoIQzXN",
|
||||
termsURL: URL(staticString: "https://element.io/cookie-policy"))
|
||||
#else
|
||||
/// The configuration to use for analytics. Set `isEnabled` to false to disable analytics.
|
||||
/// **Note:** Analytics are disabled by default for forks. If you are maintaining a fork, set custom configurations.
|
||||
static let analyticsConfiguration = AnalyticsConfiguration(isEnabled: InfoPlistReader.target.bundleIdentifier.starts(with: "io.element.elementx"),
|
||||
host: "https://posthog.hss.element.io",
|
||||
apiKey: "phc_Jzsm6DTm6V2705zeU5dcNvQDlonOR68XvX2sh1sEOHO",
|
||||
termsURL: URL(staticString: "https://element.io/cookie-policy"))
|
||||
#endif
|
||||
|
||||
// MARK: - Settings screen
|
||||
|
||||
static let settingsCrashButtonVisible = true
|
||||
static let settingsShowTimelineStyle = true
|
||||
|
||||
// MARK: - Room screen
|
||||
|
||||
static let defaultRoomTimelineStyle: TimelineStyle = .bubbles
|
||||
|
||||
// MARK: - Other
|
||||
|
||||
static var permalinkBaseURL = URL(staticString: "https://matrix.to")
|
||||
|
||||
// MARK: - Notifications
|
||||
|
||||
static let enableNotifications = false
|
||||
}
|
@ -26,4 +26,10 @@ class ServiceLocator {
|
||||
func register(userNotificationController: UserNotificationControllerProtocol) {
|
||||
self.userNotificationController = userNotificationController
|
||||
}
|
||||
|
||||
private(set) var settings: AppSettings!
|
||||
|
||||
func register(appSettings: AppSettings) {
|
||||
settings = appSettings
|
||||
}
|
||||
}
|
||||
|
@ -1,82 +0,0 @@
|
||||
//
|
||||
// Copyright 2022 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
/// Store Element specific app settings.
|
||||
final class ElementSettings: ObservableObject {
|
||||
// MARK: - Constants
|
||||
|
||||
public enum UserDefaultsKeys: String {
|
||||
case timelineStyle
|
||||
case enableAnalytics
|
||||
case isIdentifiedForAnalytics
|
||||
case slidingSyncProxyBaseURLString
|
||||
case enableInAppNotifications
|
||||
case pusherProfileTag
|
||||
}
|
||||
|
||||
static let shared = ElementSettings()
|
||||
|
||||
/// UserDefaults to be used on reads and writes.
|
||||
static var store: UserDefaults {
|
||||
guard let userDefaults = UserDefaults(suiteName: InfoPlistReader.target.appGroupIdentifier) else {
|
||||
fatalError("Fail to load shared UserDefaults")
|
||||
}
|
||||
return userDefaults
|
||||
}
|
||||
|
||||
private init() {
|
||||
// no-op
|
||||
}
|
||||
|
||||
// MARK: - Analytics
|
||||
|
||||
/// Whether the user has already been shown the PostHog analytics prompt.
|
||||
var hasSeenAnalyticsPrompt: Bool {
|
||||
Self.store.object(forKey: UserDefaultsKeys.enableAnalytics.rawValue) != nil
|
||||
}
|
||||
|
||||
/// `true` when the user has opted in to send analytics.
|
||||
@AppStorage(UserDefaultsKeys.enableAnalytics.rawValue, store: store)
|
||||
var enableAnalytics = false
|
||||
|
||||
/// Indicates if the device has already called identify for this session to PostHog.
|
||||
/// This is separate to `enableAnalytics` as logging out leaves analytics
|
||||
/// enabled, but requires the next account to be identified separately.
|
||||
@AppStorage(UserDefaultsKeys.isIdentifiedForAnalytics.rawValue, store: store)
|
||||
var isIdentifiedForAnalytics = false
|
||||
|
||||
// MARK: - Room Screen
|
||||
|
||||
@AppStorage(UserDefaultsKeys.timelineStyle.rawValue, store: store)
|
||||
var timelineStyle = BuildSettings.defaultRoomTimelineStyle
|
||||
|
||||
// MARK: - Client
|
||||
|
||||
@AppStorage(UserDefaultsKeys.slidingSyncProxyBaseURLString.rawValue, store: store)
|
||||
var slidingSyncProxyBaseURLString = BuildSettings.defaultSlidingSyncProxyBaseURLString
|
||||
|
||||
// MARK: - Notifications
|
||||
|
||||
@AppStorage(UserDefaultsKeys.enableInAppNotifications.rawValue, store: store)
|
||||
var enableInAppNotifications = true
|
||||
|
||||
@AppStorage(UserDefaultsKeys.pusherProfileTag.rawValue, store: store)
|
||||
/// Tag describing which set of device specific rules a pusher executes.
|
||||
var pusherProfileTag: String?
|
||||
}
|
@ -37,7 +37,7 @@ enum PermalinkBuilder {
|
||||
throw PermalinkBuilderError.invalidUserIdentifier
|
||||
}
|
||||
|
||||
let urlString = "\(BuildSettings.permalinkBaseURL)/#/\(userIdentifier)"
|
||||
let urlString = "\(ServiceLocator.shared.settings.permalinkBaseURL)/#/\(userIdentifier)"
|
||||
|
||||
guard let url = URL(string: urlString) else {
|
||||
throw PermalinkBuilderError.failedConstructingURL
|
||||
@ -75,7 +75,7 @@ enum PermalinkBuilder {
|
||||
throw PermalinkBuilderError.failedAddingPercentEncoding
|
||||
}
|
||||
|
||||
let urlString = "\(BuildSettings.permalinkBaseURL)/#/\(roomId)/\(eventId)"
|
||||
let urlString = "\(ServiceLocator.shared.settings.permalinkBaseURL)/#/\(roomId)/\(eventId)"
|
||||
|
||||
guard let url = URL(string: urlString) else {
|
||||
throw PermalinkBuilderError.failedConstructingURL
|
||||
@ -91,7 +91,7 @@ enum PermalinkBuilder {
|
||||
throw PermalinkBuilderError.failedAddingPercentEncoding
|
||||
}
|
||||
|
||||
let urlString = "\(BuildSettings.permalinkBaseURL)/#/\(identifier)"
|
||||
let urlString = "\(ServiceLocator.shared.settings.permalinkBaseURL)/#/\(identifier)"
|
||||
|
||||
guard let url = URL(string: urlString) else {
|
||||
throw PermalinkBuilderError.failedConstructingURL
|
||||
|
@ -30,7 +30,7 @@ final class AnalyticsPromptCoordinator: CoordinatorProtocol {
|
||||
init(parameters: AnalyticsPromptCoordinatorParameters) {
|
||||
self.parameters = parameters
|
||||
|
||||
viewModel = AnalyticsPromptViewModel(termsURL: BuildSettings.analyticsConfiguration.termsURL)
|
||||
viewModel = AnalyticsPromptViewModel(termsURL: ServiceLocator.shared.settings.analyticsConfiguration.termsURL)
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
|
@ -55,7 +55,7 @@ struct AnalyticsPromptStrings {
|
||||
|
||||
// Replace the placeholder with a link.
|
||||
var link = AttributedString(ElementL10n.analyticsOptInContentLink)
|
||||
link.link = BuildSettings.analyticsConfiguration.termsURL
|
||||
link.link = ServiceLocator.shared.settings.analyticsConfiguration.termsURL
|
||||
optInContent.replaceSubrange(range, with: link)
|
||||
|
||||
self.optInContent = optInContent
|
||||
|
@ -114,7 +114,7 @@ struct AnalyticsPrompt: View {
|
||||
// MARK: - Previews
|
||||
|
||||
struct AnalyticsPrompt_Previews: PreviewProvider {
|
||||
static let viewModel = AnalyticsPromptViewModel(termsURL: BuildSettings.analyticsConfiguration.termsURL)
|
||||
static let viewModel = AnalyticsPromptViewModel(termsURL: ServiceLocator.shared.settings.analyticsConfiguration.termsURL)
|
||||
static var previews: some View {
|
||||
AnalyticsPrompt(context: viewModel.context)
|
||||
.tint(.element.accent)
|
||||
|
@ -61,7 +61,7 @@ class AuthenticationCoordinator: CoordinatorProtocol {
|
||||
private func startAuthentication() async {
|
||||
startLoading()
|
||||
|
||||
switch await authenticationService.configure(for: BuildSettings.defaultHomeserverAddress) {
|
||||
switch await authenticationService.configure(for: ServiceLocator.shared.settings.defaultHomeserverAddress) {
|
||||
case .success:
|
||||
stopLoading()
|
||||
showLoginScreen()
|
||||
|
@ -23,7 +23,7 @@ class ServerSelectionViewModel: ServerSelectionViewModelType, ServerSelectionVie
|
||||
|
||||
init(homeserverAddress: String, isModallyPresented: Bool) {
|
||||
let bindings = ServerSelectionBindings(homeserverAddress: homeserverAddress,
|
||||
slidingSyncProxyAddress: ElementSettings.shared.slidingSyncProxyBaseURLString)
|
||||
slidingSyncProxyAddress: ServiceLocator.shared.settings.slidingSyncProxyBaseURLString)
|
||||
|
||||
super.init(initialViewState: ServerSelectionViewState(bindings: bindings,
|
||||
isModallyPresented: isModallyPresented))
|
||||
@ -33,8 +33,8 @@ class ServerSelectionViewModel: ServerSelectionViewModelType, ServerSelectionVie
|
||||
switch viewAction {
|
||||
case .confirm:
|
||||
if !state.bindings.slidingSyncProxyAddress.isEmpty,
|
||||
state.bindings.slidingSyncProxyAddress != ElementSettings.shared.slidingSyncProxyBaseURLString {
|
||||
ElementSettings.shared.slidingSyncProxyBaseURLString = state.bindings.slidingSyncProxyAddress
|
||||
state.bindings.slidingSyncProxyAddress != ServiceLocator.shared.settings.slidingSyncProxyBaseURLString {
|
||||
ServiceLocator.shared.settings.slidingSyncProxyBaseURLString = state.bindings.slidingSyncProxyAddress
|
||||
}
|
||||
|
||||
callback?(.confirm(homeserverAddress: state.bindings.homeserverAddress))
|
||||
|
@ -68,7 +68,7 @@ class BugReportViewModel: BugReportViewModelType, BugReportViewModelProtocol {
|
||||
let result = try await bugReportService.submitBugReport(text: context.reportText,
|
||||
includeLogs: context.sendingLogsEnabled,
|
||||
includeCrashLog: true,
|
||||
githubLabels: BuildSettings.bugReportGHLabels,
|
||||
githubLabels: ServiceLocator.shared.settings.bugReportGHLabels,
|
||||
files: files)
|
||||
MXLog.info("SubmitBugReport succeeded, result: \(result.reportUrl)")
|
||||
callback?(.submitFinished)
|
||||
|
@ -17,7 +17,7 @@
|
||||
import SwiftUI
|
||||
|
||||
struct RoomScreen: View {
|
||||
@ObservedObject private var settings = ElementSettings.shared
|
||||
@ObservedObject private var settings = ServiceLocator.shared.settings
|
||||
@ObservedObject var context: RoomScreenViewModel.Context
|
||||
@State private var showReactionsMenuForItemId = ""
|
||||
|
||||
|
@ -35,7 +35,7 @@ enum TimelineStyle: String, CaseIterable {
|
||||
// MARK: - Environment
|
||||
|
||||
private struct TimelineStyleKey: EnvironmentKey {
|
||||
static let defaultValue = BuildSettings.defaultRoomTimelineStyle
|
||||
static let defaultValue = TimelineStyle.bubbles
|
||||
}
|
||||
|
||||
extension EnvironmentValues {
|
||||
|
@ -50,8 +50,6 @@ final class SettingsCoordinator: CoordinatorProtocol {
|
||||
self.toggleAnalytics()
|
||||
case .reportBug:
|
||||
self.presentBugReportScreen()
|
||||
case .crash:
|
||||
self.parameters.bugReportService.crash()
|
||||
case .logout:
|
||||
self.callback?(.logout)
|
||||
}
|
||||
@ -67,7 +65,7 @@ final class SettingsCoordinator: CoordinatorProtocol {
|
||||
// MARK: - Private
|
||||
|
||||
private func toggleAnalytics() {
|
||||
if ElementSettings.shared.enableAnalytics {
|
||||
if ServiceLocator.shared.settings.enableAnalytics {
|
||||
Analytics.shared.optOut()
|
||||
} else {
|
||||
Analytics.shared.optIn(with: parameters.userSession)
|
||||
|
@ -21,7 +21,6 @@ enum SettingsViewModelAction {
|
||||
case close
|
||||
case toggleAnalytics
|
||||
case reportBug
|
||||
case crash
|
||||
case logout
|
||||
}
|
||||
|
||||
@ -33,13 +32,12 @@ struct SettingsViewState: BindableState {
|
||||
}
|
||||
|
||||
struct SettingsViewStateBindings {
|
||||
var enableAnalytics = ElementSettings.shared.enableAnalytics
|
||||
var enableAnalytics = ServiceLocator.shared.settings.enableAnalytics
|
||||
}
|
||||
|
||||
enum SettingsViewAction {
|
||||
case close
|
||||
case toggleAnalytics
|
||||
case reportBug
|
||||
case crash
|
||||
case logout
|
||||
}
|
||||
|
@ -51,8 +51,6 @@ class SettingsViewModel: SettingsViewModelType, SettingsViewModelProtocol {
|
||||
callback?(.toggleAnalytics)
|
||||
case .reportBug:
|
||||
callback?(.reportBug)
|
||||
case .crash:
|
||||
callback?(.crash)
|
||||
case .logout:
|
||||
callback?(.logout)
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ import SwiftUI
|
||||
struct SettingsScreen: View {
|
||||
@State private var showingLogoutConfirmation = false
|
||||
@Environment(\.colorScheme) private var colorScheme
|
||||
@ObservedObject private var settings = ElementSettings.shared
|
||||
@ObservedObject private var settings = ServiceLocator.shared.settings
|
||||
|
||||
@ScaledMetric private var avatarSize = AvatarSize.user(on: .settings).value
|
||||
@ScaledMetric private var menuIconSize = 30.0
|
||||
@ -110,30 +110,20 @@ struct SettingsScreen: View {
|
||||
.listRowSeparator(.hidden)
|
||||
.foregroundColor(.element.primaryContent)
|
||||
.accessibilityIdentifier("reportBugButton")
|
||||
|
||||
if BuildSettings.settingsCrashButtonVisible {
|
||||
Button("Crash app",
|
||||
role: .destructive) { context.send(viewAction: .crash)
|
||||
}
|
||||
.listRowInsets(listRowInsets)
|
||||
.accessibilityIdentifier("crashButton")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private var userInterfaceSection: some View {
|
||||
if BuildSettings.settingsShowTimelineStyle {
|
||||
Section {
|
||||
Picker(ElementL10n.settingsTimelineStyle, selection: $settings.timelineStyle) {
|
||||
ForEach(TimelineStyle.allCases, id: \.self) { style in
|
||||
Text(style.description)
|
||||
.tag(style)
|
||||
}
|
||||
Section {
|
||||
Picker(ElementL10n.settingsTimelineStyle, selection: $settings.timelineStyle) {
|
||||
ForEach(TimelineStyle.allCases, id: \.self) { style in
|
||||
Text(style.description)
|
||||
.tag(style)
|
||||
}
|
||||
.listRowInsets(listRowInsets)
|
||||
.accessibilityIdentifier("timelineStylePicker")
|
||||
}
|
||||
.listRowInsets(listRowInsets)
|
||||
.accessibilityIdentifier("timelineStylePicker")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -49,14 +49,14 @@ class Analytics {
|
||||
/// Whether to show the user the analytics opt in prompt.
|
||||
var shouldShowAnalyticsPrompt: Bool {
|
||||
// Only show the prompt once, and when analytics are enabled in BuildSettings.
|
||||
!ElementSettings.shared.hasSeenAnalyticsPrompt && BuildSettings.analyticsConfiguration.isEnabled
|
||||
!ServiceLocator.shared.settings.hasSeenAnalyticsPrompt && ServiceLocator.shared.settings.analyticsConfiguration.isEnabled
|
||||
}
|
||||
|
||||
/// Opts in to analytics tracking with the supplied user session.
|
||||
/// - Parameter userSession: The user session to use to when reading/generating the analytics ID.
|
||||
/// The session will be ignored if not running.
|
||||
func optIn(with userSession: UserSessionProtocol) {
|
||||
ElementSettings.shared.enableAnalytics = true
|
||||
ServiceLocator.shared.settings.enableAnalytics = true
|
||||
startIfEnabled()
|
||||
|
||||
Task { await useAnalyticsSettings(from: userSession) }
|
||||
@ -64,7 +64,7 @@ class Analytics {
|
||||
|
||||
/// Stops analytics tracking and calls `reset` to clear any IDs and event queues.
|
||||
func optOut() {
|
||||
ElementSettings.shared.enableAnalytics = false
|
||||
ServiceLocator.shared.settings.enableAnalytics = false
|
||||
|
||||
// The order is important here. PostHog ignores the reset if stopped.
|
||||
reset()
|
||||
@ -76,7 +76,7 @@ class Analytics {
|
||||
|
||||
/// Starts the analytics client if the user has opted in, otherwise does nothing.
|
||||
func startIfEnabled() {
|
||||
guard ElementSettings.shared.enableAnalytics, !isRunning else { return }
|
||||
guard ServiceLocator.shared.settings.enableAnalytics, !isRunning else { return }
|
||||
|
||||
client.start()
|
||||
// monitoringClient.start()
|
||||
@ -96,8 +96,8 @@ class Analytics {
|
||||
/// - Parameter userSession: The user session to read analytics settings from.
|
||||
func useAnalyticsSettings(from userSession: UserSessionProtocol) async {
|
||||
guard
|
||||
ElementSettings.shared.enableAnalytics,
|
||||
!ElementSettings.shared.isIdentifiedForAnalytics
|
||||
ServiceLocator.shared.settings.enableAnalytics,
|
||||
!ServiceLocator.shared.settings.isIdentifiedForAnalytics
|
||||
else { return }
|
||||
|
||||
let service = AnalyticsService(userSession: userSession)
|
||||
@ -122,7 +122,7 @@ class Analytics {
|
||||
// monitoringClient.reset()
|
||||
|
||||
MXLog.debug("Reset.")
|
||||
ElementSettings.shared.isIdentifiedForAnalytics = false
|
||||
ServiceLocator.shared.settings.isIdentifiedForAnalytics = false
|
||||
|
||||
// Stop collecting crash logs
|
||||
// MXLogger.logCrashes(false)
|
||||
@ -147,7 +147,7 @@ class Analytics {
|
||||
|
||||
client.identify(id: id)
|
||||
MXLog.debug("Identified.")
|
||||
ElementSettings.shared.isIdentifiedForAnalytics = true
|
||||
ServiceLocator.shared.settings.isIdentifiedForAnalytics = true
|
||||
}
|
||||
|
||||
/// Capture an event in the `client`.
|
||||
|
@ -18,7 +18,7 @@ import PostHog
|
||||
|
||||
extension PHGPostHogConfiguration {
|
||||
static var standard: PHGPostHogConfiguration? {
|
||||
let analyticsConfiguration = BuildSettings.analyticsConfiguration
|
||||
let analyticsConfiguration = ServiceLocator.shared.settings.analyticsConfiguration
|
||||
guard analyticsConfiguration.isEnabled else { return nil }
|
||||
|
||||
let postHogConfiguration = PHGPostHogConfiguration(apiKey: analyticsConfiguration.apiKey, host: analyticsConfiguration.host)
|
||||
|
@ -22,7 +22,7 @@ class AuthenticationServiceProxy: AuthenticationServiceProxyProtocol {
|
||||
private let authenticationService: AuthenticationService
|
||||
private let userSessionStore: UserSessionStoreProtocol
|
||||
|
||||
private(set) var homeserver = LoginHomeserver(address: BuildSettings.defaultHomeserverAddress, loginMode: .unknown)
|
||||
private(set) var homeserver = LoginHomeserver(address: ServiceLocator.shared.settings.defaultHomeserverAddress, loginMode: .unknown)
|
||||
|
||||
init(userSessionStore: UserSessionStoreProtocol) {
|
||||
self.userSessionStore = userSessionStore
|
||||
|
@ -28,7 +28,7 @@ class BugReportService: BugReportServiceProtocol {
|
||||
|
||||
init(withBaseURL baseURL: URL,
|
||||
sentryURL: URL,
|
||||
applicationId: String = BuildSettings.bugReportApplicationId,
|
||||
applicationId: String = ServiceLocator.shared.settings.bugReportApplicationId,
|
||||
session: URLSession = .shared) {
|
||||
self.baseURL = baseURL
|
||||
self.sentryURL = sentryURL
|
||||
|
@ -81,7 +81,7 @@ class ClientProxy: ClientProxyProtocol {
|
||||
|
||||
await Task.dispatch(on: clientQueue) {
|
||||
do {
|
||||
let slidingSyncBuilder = try client.slidingSync().homeserver(url: ElementSettings.shared.slidingSyncProxyBaseURLString)
|
||||
let slidingSyncBuilder = try client.slidingSync().homeserver(url: ServiceLocator.shared.settings.slidingSyncProxyBaseURLString)
|
||||
|
||||
let slidingSyncView = try SlidingSyncViewBuilder()
|
||||
.timelineLimit(limit: 10)
|
||||
|
@ -89,12 +89,12 @@ class NotificationManager: NSObject, NotificationManagerProtocol {
|
||||
do {
|
||||
try await clientProxy.setPusher(pushkey: deviceToken.base64EncodedString(),
|
||||
kind: .http,
|
||||
appId: BuildSettings.pusherAppId,
|
||||
appId: ServiceLocator.shared.settings.pusherAppId,
|
||||
appDisplayName: "\(InfoPlistReader.target.bundleDisplayName) (iOS)",
|
||||
deviceDisplayName: UIDevice.current.name,
|
||||
profileTag: pusherProfileTag(),
|
||||
lang: Bundle.preferredLanguages.first ?? "en",
|
||||
url: BuildSettings.pushGatewayBaseURL.absoluteString,
|
||||
url: ServiceLocator.shared.settings.pushGatewayBaseURL.absoluteString,
|
||||
format: .eventIdOnly,
|
||||
defaultPayload: [
|
||||
"aps": [
|
||||
@ -113,7 +113,7 @@ class NotificationManager: NSObject, NotificationManagerProtocol {
|
||||
}
|
||||
|
||||
private func pusherProfileTag() -> String {
|
||||
if let currentTag = ElementSettings.shared.pusherProfileTag {
|
||||
if let currentTag = ServiceLocator.shared.settings.pusherProfileTag {
|
||||
return currentTag
|
||||
}
|
||||
let chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
||||
@ -122,7 +122,7 @@ class NotificationManager: NSObject, NotificationManagerProtocol {
|
||||
return String(chars[chars.index(chars.startIndex, offsetBy: offset)])
|
||||
}.joined()
|
||||
|
||||
ElementSettings.shared.pusherProfileTag = newTag
|
||||
ServiceLocator.shared.settings.pusherProfileTag = newTag
|
||||
return newTag
|
||||
}
|
||||
}
|
||||
@ -132,7 +132,7 @@ class NotificationManager: NSObject, NotificationManagerProtocol {
|
||||
extension NotificationManager: UNUserNotificationCenterDelegate {
|
||||
func userNotificationCenter(_ center: UNUserNotificationCenter,
|
||||
willPresent notification: UNNotification) async -> UNNotificationPresentationOptions {
|
||||
guard ElementSettings.shared.enableInAppNotifications else {
|
||||
guard ServiceLocator.shared.settings.enableInAppNotifications else {
|
||||
return []
|
||||
}
|
||||
guard let delegate else {
|
||||
|
@ -36,6 +36,12 @@ class UserSessionStore: UserSessionStoreProtocol {
|
||||
MXLog.debug("Setup base directory at: \(baseDirectory)")
|
||||
}
|
||||
|
||||
/// Deletes all data stored in the shared container and keychain
|
||||
func reset() {
|
||||
try? FileManager.default.removeItem(at: baseDirectory)
|
||||
keychainController.removeAllRestorationTokens()
|
||||
}
|
||||
|
||||
func restoreUserSession() async -> Result<UserSession, UserSessionStoreError> {
|
||||
let availableCredentials = keychainController.restorationTokens()
|
||||
|
||||
|
@ -25,6 +25,9 @@ enum UserSessionStoreError: Error {
|
||||
}
|
||||
|
||||
protocol UserSessionStoreProtocol {
|
||||
/// Deletes all data stored in the shared container and keychain
|
||||
func reset()
|
||||
|
||||
/// Whether or not there are sessions in the store.
|
||||
var hasSessions: Bool { get }
|
||||
|
||||
|
@ -28,6 +28,10 @@ class UITestsAppCoordinator: AppCoordinatorProtocol {
|
||||
mockScreens = UITestScreenIdentifier.allCases.map { MockScreen(id: $0, navigationRootCoordinator: navigationRootCoordinator) }
|
||||
|
||||
ServiceLocator.shared.register(userNotificationController: MockUserNotificationController())
|
||||
|
||||
AppSettings.configureWithSuiteName("io.element.elementx.uitests")
|
||||
AppSettings.reset()
|
||||
ServiceLocator.shared.register(appSettings: AppSettings())
|
||||
}
|
||||
|
||||
func start() {
|
||||
|
@ -26,12 +26,9 @@ class SettingsUITests: XCTestCase {
|
||||
let reportBugButton = app.buttons["reportBugButton"]
|
||||
XCTAssert(reportBugButton.exists)
|
||||
XCTAssertEqual(reportBugButton.label, ElementL10n.sendBugReport)
|
||||
XCTAssertEqual(app.buttons["crashButton"].exists, BuildSettings.settingsCrashButtonVisible)
|
||||
|
||||
XCTAssertEqual(app.buttons["timelineStylePicker"].exists, BuildSettings.settingsShowTimelineStyle)
|
||||
if BuildSettings.settingsShowTimelineStyle {
|
||||
XCTAssertTrue(app.staticTexts[ElementL10n.settingsTimelineStyle].exists)
|
||||
}
|
||||
XCTAssertTrue(app.buttons["timelineStylePicker"].exists)
|
||||
XCTAssertTrue(app.staticTexts[ElementL10n.settingsTimelineStyle].exists)
|
||||
|
||||
let logoutButton = app.buttons["logoutButton"]
|
||||
XCTAssert(logoutButton.exists)
|
||||
|
BIN
UITests/Sources/__Snapshots__/Application/de-DE-iPad-9th-generation.settings.png
(Stored with Git LFS)
BIN
UITests/Sources/__Snapshots__/Application/de-DE-iPad-9th-generation.settings.png
(Stored with Git LFS)
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/de-DE-iPhone-14.settings.png
(Stored with Git LFS)
BIN
UITests/Sources/__Snapshots__/Application/de-DE-iPhone-14.settings.png
(Stored with Git LFS)
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/en-GB-iPad-9th-generation.settings.png
(Stored with Git LFS)
BIN
UITests/Sources/__Snapshots__/Application/en-GB-iPad-9th-generation.settings.png
(Stored with Git LFS)
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/en-GB-iPhone-14.settings.png
(Stored with Git LFS)
BIN
UITests/Sources/__Snapshots__/Application/en-GB-iPhone-14.settings.png
(Stored with Git LFS)
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/fr-FR-iPad-9th-generation.settings.png
(Stored with Git LFS)
BIN
UITests/Sources/__Snapshots__/Application/fr-FR-iPad-9th-generation.settings.png
(Stored with Git LFS)
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/fr-FR-iPhone-14.settings.png
(Stored with Git LFS)
BIN
UITests/Sources/__Snapshots__/Application/fr-FR-iPhone-14.settings.png
(Stored with Git LFS)
Binary file not shown.
@ -57,7 +57,7 @@ targets:
|
||||
- "**/__Snapshots__/**"
|
||||
- path: ../SupportingFiles
|
||||
- path: ../../Tools/Scripts/Templates/SimpleScreenExample/Tests/UI
|
||||
- path: ../../ElementX/Sources/Application/BuildSettings.swift
|
||||
- path: ../../ElementX/Sources/Application/AppSettings.swift
|
||||
- path: ../../ElementX/Sources/Screens/RoomScreen/View/Style/TimelineStyle.swift
|
||||
- path: ../../ElementX/Sources/Services/Analytics/AnalyticsConfiguration.swift
|
||||
- path: ../../ElementX/Sources/UITests/UITestScreenIdentifier.swift
|
||||
|
@ -19,10 +19,16 @@ import AnalyticsEvents
|
||||
import XCTest
|
||||
|
||||
class AnalyticsTests: XCTestCase {
|
||||
private var applicationSettings: AppSettings!
|
||||
|
||||
override func setUp() {
|
||||
AppSettings.configureWithSuiteName("io.element.elementx.unitests")
|
||||
AppSettings.reset()
|
||||
applicationSettings = AppSettings()
|
||||
}
|
||||
|
||||
func testAnalyticsPromptNewUser() {
|
||||
// Given a fresh install of the app (without PostHog analytics having been set).
|
||||
ElementSettings.store.removeObject(forKey: ElementSettings.UserDefaultsKeys.enableAnalytics.rawValue)
|
||||
|
||||
// When the user is prompted for analytics.
|
||||
let showPrompt = Analytics.shared.shouldShowAnalyticsPrompt
|
||||
|
||||
@ -32,7 +38,7 @@ class AnalyticsTests: XCTestCase {
|
||||
|
||||
func testAnalyticsPromptUserDeclinedPostHog() {
|
||||
// Given an existing install of the app where the user previously declined PostHog
|
||||
ElementSettings.shared.enableAnalytics = false
|
||||
applicationSettings.enableAnalytics = false
|
||||
|
||||
// When the user is prompted for analytics
|
||||
let showPrompt = Analytics.shared.shouldShowAnalyticsPrompt
|
||||
@ -43,7 +49,7 @@ class AnalyticsTests: XCTestCase {
|
||||
|
||||
func testAnalyticsPromptUserAcceptedPostHog() {
|
||||
// Given an existing install of the app where the user previously accepted PostHog
|
||||
ElementSettings.shared.enableAnalytics = true
|
||||
applicationSettings.enableAnalytics = true
|
||||
|
||||
// When the user is prompted for analytics
|
||||
let showPrompt = Analytics.shared.shouldShowAnalyticsPrompt
|
||||
|
@ -18,12 +18,20 @@
|
||||
import XCTest
|
||||
|
||||
class PermalinkBuilderTests: XCTestCase {
|
||||
private var appSettings: AppSettings!
|
||||
|
||||
override func setUp() {
|
||||
AppSettings.configureWithSuiteName("io.element.elementx.unitests")
|
||||
AppSettings.reset()
|
||||
appSettings = AppSettings()
|
||||
}
|
||||
|
||||
func testUserIdentifierPermalink() {
|
||||
let userId = "@abcdefghijklmnopqrstuvwxyz1234567890._-=/:matrix.org"
|
||||
|
||||
do {
|
||||
let permalink = try PermalinkBuilder.permalinkTo(userIdentifier: userId)
|
||||
XCTAssertEqual(permalink, URL(string: "\(BuildSettings.permalinkBaseURL)/#/\(userId)"))
|
||||
XCTAssertEqual(permalink, URL(string: "\(appSettings.permalinkBaseURL)/#/\(userId)"))
|
||||
} catch {
|
||||
XCTFail("User identifier must be valid: \(error)")
|
||||
}
|
||||
@ -43,7 +51,7 @@ class PermalinkBuilderTests: XCTestCase {
|
||||
|
||||
do {
|
||||
let permalink = try PermalinkBuilder.permalinkTo(roomIdentifier: roomId)
|
||||
XCTAssertEqual(permalink, URL(string: "\(BuildSettings.permalinkBaseURL)/#/!abcdefghijklmnopqrstuvwxyz1234567890%3Amatrix.org"))
|
||||
XCTAssertEqual(permalink, URL(string: "\(appSettings.permalinkBaseURL)/#/!abcdefghijklmnopqrstuvwxyz1234567890%3Amatrix.org"))
|
||||
} catch {
|
||||
XCTFail("Room identifier must be valid: \(error)")
|
||||
}
|
||||
@ -63,7 +71,7 @@ class PermalinkBuilderTests: XCTestCase {
|
||||
|
||||
do {
|
||||
let permalink = try PermalinkBuilder.permalinkTo(roomAlias: roomAlias)
|
||||
XCTAssertEqual(permalink, URL(string: "\(BuildSettings.permalinkBaseURL)/#/%23abcdefghijklmnopqrstuvwxyz-_.1234567890%3Amatrix.org"))
|
||||
XCTAssertEqual(permalink, URL(string: "\(appSettings.permalinkBaseURL)/#/%23abcdefghijklmnopqrstuvwxyz-_.1234567890%3Amatrix.org"))
|
||||
} catch {
|
||||
XCTFail("Room alias must be valid: \(error)")
|
||||
}
|
||||
@ -84,7 +92,7 @@ class PermalinkBuilderTests: XCTestCase {
|
||||
|
||||
do {
|
||||
let permalink = try PermalinkBuilder.permalinkTo(eventIdentifier: eventId, roomIdentifier: roomId)
|
||||
XCTAssertEqual(permalink, URL(string: "\(BuildSettings.permalinkBaseURL)/#/!abcdefghijklmnopqrstuvwxyz1234567890%3Amatrix.org/%24abcdefghijklmnopqrstuvwxyz1234567890"))
|
||||
XCTAssertEqual(permalink, URL(string: "\(appSettings.permalinkBaseURL)/#/!abcdefghijklmnopqrstuvwxyz1234567890%3Amatrix.org/%24abcdefghijklmnopqrstuvwxyz1234567890"))
|
||||
} catch {
|
||||
XCTFail("Room and event identifiers must be valid: \(error)")
|
||||
}
|
||||
|
@ -56,15 +56,4 @@ class SettingsViewModelTests: XCTestCase {
|
||||
await Task.yield()
|
||||
XCTAssert(correctResult)
|
||||
}
|
||||
|
||||
func testCrash() async throws {
|
||||
var correctResult = false
|
||||
viewModel.callback = { result in
|
||||
correctResult = result == .crash
|
||||
}
|
||||
|
||||
context.send(viewAction: .crash)
|
||||
await Task.yield()
|
||||
XCTAssert(correctResult)
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user