Removing Dead Code part 1 (#2234)

This commit is contained in:
Mauro 2023-12-13 09:51:57 +01:00 committed by GitHub
parent 09b276d94b
commit d99d26fcdc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
88 changed files with 115 additions and 477 deletions

View File

@ -12,7 +12,7 @@ targets:
- UITests - UITests
- UnitTests - UnitTests
report_exclude: report_exclude:
# includes subscript which is not detectable: https://github.com/apple/swift/issues/56541 - ElementX/Sources/Mocks/Generated/GeneratedMocks.swift
- ElementX/Sources/Screens/Settings/AvancedOptionsScreen/AdvancedSettingsScreenModels.swift - ElementX/Sources/Mocks/Generated/SDKGeneratedMocks.swift
verbose: true verbose: true
retain_swift_ui_previews: true retain_swift_ui_previews: true

View File

@ -315,7 +315,6 @@
50539366B408780B232C1910 /* EstimatedWaveformView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD0FF64B0E6470F66F42E182 /* EstimatedWaveformView.swift */; }; 50539366B408780B232C1910 /* EstimatedWaveformView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD0FF64B0E6470F66F42E182 /* EstimatedWaveformView.swift */; };
50C90117FE25390BFBD40173 /* RustTracing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 542D4F49FABA056DEEEB3400 /* RustTracing.swift */; }; 50C90117FE25390BFBD40173 /* RustTracing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 542D4F49FABA056DEEEB3400 /* RustTracing.swift */; };
5100F53E6884A15F9BA07CC3 /* AttributedStringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37CA26F55123E36B50DB0B3A /* AttributedStringTests.swift */; }; 5100F53E6884A15F9BA07CC3 /* AttributedStringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37CA26F55123E36B50DB0B3A /* AttributedStringTests.swift */; };
516534FC5C893D57F169D5A8 /* MapTilerGeocoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33720F7AD25E85E4A84669E8 /* MapTilerGeocoding.swift */; };
518C93DC6516D3D018DE065F /* UNNotificationRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49E751D7EDB6043238111D90 /* UNNotificationRequest.swift */; }; 518C93DC6516D3D018DE065F /* UNNotificationRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49E751D7EDB6043238111D90 /* UNNotificationRequest.swift */; };
51C240F4660F7269203A9B3A /* MigrationScreenUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75910F5A36EA8FF9BAD08D18 /* MigrationScreenUITests.swift */; }; 51C240F4660F7269203A9B3A /* MigrationScreenUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75910F5A36EA8FF9BAD08D18 /* MigrationScreenUITests.swift */; };
520EEDAFBC778AB0B41F2F53 /* ClientMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADE6170EFE6A161B0A68AB61 /* ClientMock.swift */; }; 520EEDAFBC778AB0B41F2F53 /* ClientMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADE6170EFE6A161B0A68AB61 /* ClientMock.swift */; };
@ -852,7 +851,6 @@
D8385A51A3D0FA9283556281 /* RoundedLabelItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 745323FCF9AF21A117252C53 /* RoundedLabelItem.swift */; }; D8385A51A3D0FA9283556281 /* RoundedLabelItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 745323FCF9AF21A117252C53 /* RoundedLabelItem.swift */; };
D871C8CF46950F959C9A62C3 /* WelcomeScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = C54464351F170D570110AFCA /* WelcomeScreen.swift */; }; D871C8CF46950F959C9A62C3 /* WelcomeScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = C54464351F170D570110AFCA /* WelcomeScreen.swift */; };
D876EC0FED3B6D46C806912A /* AvatarSize.swift in Sources */ = {isa = PBXBuildFile; fileRef = E24B88AD3D1599E8CB1376E0 /* AvatarSize.swift */; }; D876EC0FED3B6D46C806912A /* AvatarSize.swift in Sources */ = {isa = PBXBuildFile; fileRef = E24B88AD3D1599E8CB1376E0 /* AvatarSize.swift */; };
D8CFF02C2730EE5BC4F17ABF /* ElementToggleStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0960A7F5C1B0B6679BDF26F9 /* ElementToggleStyle.swift */; };
D9473FC9B077A6EDB7A12001 /* LocationRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 772334731A8BF8E6D90B194D /* LocationRoomTimelineView.swift */; }; D9473FC9B077A6EDB7A12001 /* LocationRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 772334731A8BF8E6D90B194D /* LocationRoomTimelineView.swift */; };
D98B5EE8C4F5A2CE84687AE8 /* UTType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 897DF5E9A70CE05A632FC8AF /* UTType.swift */; }; D98B5EE8C4F5A2CE84687AE8 /* UTType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 897DF5E9A70CE05A632FC8AF /* UTType.swift */; };
D9F80CE61BF8FF627FDB0543 /* LoadableImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C352359663A0E52BA20761EE /* LoadableImage.swift */; }; D9F80CE61BF8FF627FDB0543 /* LoadableImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C352359663A0E52BA20761EE /* LoadableImage.swift */; };
@ -1088,7 +1086,6 @@
086B997409328F091EBA43CE /* RoomScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomScreenUITests.swift; sourceTree = "<group>"; }; 086B997409328F091EBA43CE /* RoomScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomScreenUITests.swift; sourceTree = "<group>"; };
086C19086DD16E9B38E25954 /* ReportContentViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportContentViewModelTests.swift; sourceTree = "<group>"; }; 086C19086DD16E9B38E25954 /* ReportContentViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportContentViewModelTests.swift; sourceTree = "<group>"; };
095AED4CF56DFF3EB7BB84C8 /* RoomTimelineProviderProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineProviderProtocol.swift; sourceTree = "<group>"; }; 095AED4CF56DFF3EB7BB84C8 /* RoomTimelineProviderProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineProviderProtocol.swift; sourceTree = "<group>"; };
0960A7F5C1B0B6679BDF26F9 /* ElementToggleStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElementToggleStyle.swift; sourceTree = "<group>"; };
099F2D36C141D845A445B1E6 /* EmojiProviderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiProviderTests.swift; sourceTree = "<group>"; }; 099F2D36C141D845A445B1E6 /* EmojiProviderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiProviderTests.swift; sourceTree = "<group>"; };
09CE2B7AD979BDEE09FEDB08 /* WaitlistScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaitlistScreenModels.swift; sourceTree = "<group>"; }; 09CE2B7AD979BDEE09FEDB08 /* WaitlistScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaitlistScreenModels.swift; sourceTree = "<group>"; };
0A3E77399BD262D301451BF2 /* RoomDetailsEditScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDetailsEditScreenCoordinator.swift; sourceTree = "<group>"; }; 0A3E77399BD262D301451BF2 /* RoomDetailsEditScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDetailsEditScreenCoordinator.swift; sourceTree = "<group>"; };
@ -1243,7 +1240,6 @@
32C5DAA1773F57653BF1C4F9 /* SoftLogoutViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SoftLogoutViewModelTests.swift; sourceTree = "<group>"; }; 32C5DAA1773F57653BF1C4F9 /* SoftLogoutViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SoftLogoutViewModelTests.swift; sourceTree = "<group>"; };
33649299575BADC34924ABC6 /* InvitesScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InvitesScreenCoordinator.swift; sourceTree = "<group>"; }; 33649299575BADC34924ABC6 /* InvitesScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InvitesScreenCoordinator.swift; sourceTree = "<group>"; };
3368395F06AA180138E185B6 /* PollFormScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollFormScreenUITests.swift; sourceTree = "<group>"; }; 3368395F06AA180138E185B6 /* PollFormScreenUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollFormScreenUITests.swift; sourceTree = "<group>"; };
33720F7AD25E85E4A84669E8 /* MapTilerGeocoding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapTilerGeocoding.swift; sourceTree = "<group>"; };
33E49C5C6F802B4D94CA78D1 /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = ro.lproj/Localizable.strings; sourceTree = "<group>"; }; 33E49C5C6F802B4D94CA78D1 /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = ro.lproj/Localizable.strings; sourceTree = "<group>"; };
340179A0FC1AD4AEDA7FC134 /* CreateRoomViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateRoomViewModelProtocol.swift; sourceTree = "<group>"; }; 340179A0FC1AD4AEDA7FC134 /* CreateRoomViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateRoomViewModelProtocol.swift; sourceTree = "<group>"; };
342BEBC3C5FC3F9943C41C4C /* TemplateScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateScreenViewModelProtocol.swift; sourceTree = "<group>"; }; 342BEBC3C5FC3F9943C41C4C /* TemplateScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateScreenViewModelProtocol.swift; sourceTree = "<group>"; };
@ -2511,7 +2507,6 @@
CC743C7A85E3171BCBF0A653 /* AvatarHeaderView.swift */, CC743C7A85E3171BCBF0A653 /* AvatarHeaderView.swift */,
C1FA515B3B0D61EF1E907D2D /* BadgeView.swift */, C1FA515B3B0D61EF1E907D2D /* BadgeView.swift */,
8CC23C63849452BC86EA2852 /* ButtonStyle.swift */, 8CC23C63849452BC86EA2852 /* ButtonStyle.swift */,
0960A7F5C1B0B6679BDF26F9 /* ElementToggleStyle.swift */,
7EC2F1622C5BBABED6012E12 /* HeroImage.swift */, 7EC2F1622C5BBABED6012E12 /* HeroImage.swift */,
B590BD4507D4F0A377FDE01A /* LoadableAvatarImage.swift */, B590BD4507D4F0A377FDE01A /* LoadableAvatarImage.swift */,
C352359663A0E52BA20761EE /* LoadableImage.swift */, C352359663A0E52BA20761EE /* LoadableImage.swift */,
@ -4267,7 +4262,6 @@
B81B6170DB690013CEB646F4 /* MapLibreModels.swift */, B81B6170DB690013CEB646F4 /* MapLibreModels.swift */,
592A35163B0749C66BFD6186 /* MapLibreStaticMapView.swift */, 592A35163B0749C66BFD6186 /* MapLibreStaticMapView.swift */,
E062C1750EFC8627DE4CAB8E /* MapTilerAuthorization.swift */, E062C1750EFC8627DE4CAB8E /* MapTilerAuthorization.swift */,
33720F7AD25E85E4A84669E8 /* MapTilerGeocoding.swift */,
C23B3FAD8B23C421BC0D1B1E /* MapTilerGeoCodingServiceProtocol.swift */, C23B3FAD8B23C421BC0D1B1E /* MapTilerGeoCodingServiceProtocol.swift */,
1A4D29F2683F5772AC72406F /* MapTilerStaticMap.swift */, 1A4D29F2683F5772AC72406F /* MapTilerStaticMap.swift */,
20872C3887F835958CE2F1D0 /* MapTilerStaticMapProtocol.swift */, 20872C3887F835958CE2F1D0 /* MapTilerStaticMapProtocol.swift */,
@ -5490,7 +5484,6 @@
FE4593FC2A02AAF92E089565 /* ElementAnimations.swift in Sources */, FE4593FC2A02AAF92E089565 /* ElementAnimations.swift in Sources */,
07CC13C5729C24255348CBBD /* ElementCallWidgetDriver.swift in Sources */, 07CC13C5729C24255348CBBD /* ElementCallWidgetDriver.swift in Sources */,
370AF5BFCD4384DD455479B6 /* ElementCallWidgetDriverProtocol.swift in Sources */, 370AF5BFCD4384DD455479B6 /* ElementCallWidgetDriverProtocol.swift in Sources */,
D8CFF02C2730EE5BC4F17ABF /* ElementToggleStyle.swift in Sources */,
7C1A7B594B2F8143F0DD0005 /* ElementXAttributeScope.swift in Sources */, 7C1A7B594B2F8143F0DD0005 /* ElementXAttributeScope.swift in Sources */,
7361B011A79BF723D8C9782B /* EmojiCategory.swift in Sources */, 7361B011A79BF723D8C9782B /* EmojiCategory.swift in Sources */,
E45C9FA22BC13B477FD3B4AC /* EmojiDetection.swift in Sources */, E45C9FA22BC13B477FD3B4AC /* EmojiDetection.swift in Sources */,
@ -5598,7 +5591,6 @@
D181AC8FF236B7F91C0A8C28 /* MapTiler.swift in Sources */, D181AC8FF236B7F91C0A8C28 /* MapTiler.swift in Sources */,
FCDA202B246F75BA28E10C5F /* MapTilerAuthorization.swift in Sources */, FCDA202B246F75BA28E10C5F /* MapTilerAuthorization.swift in Sources */,
7ABAB3A1D52B86FACF2F74CF /* MapTilerGeoCodingServiceProtocol.swift in Sources */, 7ABAB3A1D52B86FACF2F74CF /* MapTilerGeoCodingServiceProtocol.swift in Sources */,
516534FC5C893D57F169D5A8 /* MapTilerGeocoding.swift in Sources */,
D6661A94DBD97658B2ADBD6A /* MapTilerStaticMap.swift in Sources */, D6661A94DBD97658B2ADBD6A /* MapTilerStaticMap.swift in Sources */,
7B5DAB915357BE596529BF25 /* MapTilerStaticMapProtocol.swift in Sources */, 7B5DAB915357BE596529BF25 /* MapTilerStaticMapProtocol.swift in Sources */,
83A4DAB181C56987C3E804FF /* MapTilerStyle.swift in Sources */, 83A4DAB181C56987C3E804FF /* MapTilerStyle.swift in Sources */,

View File

@ -1,16 +0,0 @@
{
"images" : [
{
"filename" : "text-formatting.svg",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"preserves-vector-representation" : true,
"template-rendering-intent" : "template"
}
}

View File

@ -1,3 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6 19C5.71667 19 5.47917 18.9042 5.2875 18.7125C5.09583 18.5208 5 18.2833 5 18C5 17.7167 5.09583 17.4792 5.2875 17.2875C5.47917 17.0958 5.71667 17 6 17H18C18.2833 17 18.5208 17.0958 18.7125 17.2875C18.9042 17.4792 19 17.7167 19 18C19 18.2833 18.9042 18.5208 18.7125 18.7125C18.5208 18.9042 18.2833 19 18 19H6ZM7.35 13.8L10.775 4.6C10.8417 4.41667 10.9542 4.27083 11.1125 4.1625C11.2708 4.05417 11.45 4 11.65 4H12.35C12.55 4 12.7292 4.05417 12.8875 4.1625C13.0458 4.27083 13.1583 4.41667 13.225 4.6L16.65 13.825C16.75 14.1083 16.7167 14.375 16.55 14.625C16.3833 14.875 16.15 15 15.85 15C15.6667 15 15.4958 14.9458 15.3375 14.8375C15.1792 14.7292 15.0667 14.5833 15 14.4L14.25 12.2H9.8L9 14.425C8.93333 14.6083 8.825 14.75 8.675 14.85C8.525 14.95 8.35833 15 8.175 15C7.85833 15 7.6125 14.8708 7.4375 14.6125C7.2625 14.3542 7.23333 14.0833 7.35 13.8ZM10.35 10.6H13.65L12.05 6.05H11.95L10.35 10.6Z" fill="black"/>
</svg>

Before

Width:  |  Height:  |  Size: 1022 B

View File

@ -45,6 +45,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate,
private var authenticationCoordinator: AuthenticationCoordinator? private var authenticationCoordinator: AuthenticationCoordinator?
private let appLockFlowCoordinator: AppLockFlowCoordinator private let appLockFlowCoordinator: AppLockFlowCoordinator
// periphery:ignore - used to avoid deallocation
private var appLockSetupFlowCoordinator: AppLockSetupFlowCoordinator? private var appLockSetupFlowCoordinator: AppLockSetupFlowCoordinator?
private var userSessionFlowCoordinator: UserSessionFlowCoordinator? private var userSessionFlowCoordinator: UserSessionFlowCoordinator?
private var softLogoutCoordinator: SoftLogoutScreenCoordinator? private var softLogoutCoordinator: SoftLogoutScreenCoordinator?
@ -90,7 +91,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate,
navigationRootCoordinator = NavigationRootCoordinator() navigationRootCoordinator = NavigationRootCoordinator()
Self.setupServiceLocator(navigationRootCoordinator: navigationRootCoordinator, appSettings: appSettings) Self.setupServiceLocator(appSettings: appSettings)
ServiceLocator.shared.analytics.startIfEnabled() ServiceLocator.shared.analytics.startIfEnabled()
@ -209,9 +210,9 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate,
// MARK: - AuthenticationCoordinatorDelegate // MARK: - AuthenticationCoordinatorDelegate
func authenticationCoordinator(_ authenticationCoordinator: AuthenticationCoordinator, didLoginWithSession userSession: UserSessionProtocol) { func authenticationCoordinator(didLoginWithSession userSession: UserSessionProtocol) {
self.userSession = userSession self.userSession = userSession
self.authenticationCoordinator = nil authenticationCoordinator = nil
stateMachine.processEvent(.createdUserSession) stateMachine.processEvent(.createdUserSession)
} }
@ -232,7 +233,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate,
UIApplication.shared.unregisterForRemoteNotifications() UIApplication.shared.unregisterForRemoteNotifications()
} }
func shouldDisplayInAppNotification(_ service: NotificationManagerProtocol, content: UNNotificationContent) -> Bool { func shouldDisplayInAppNotification(content: UNNotificationContent) -> Bool {
guard let roomID = content.roomID else { guard let roomID = content.roomID else {
return true return true
} }
@ -243,7 +244,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate,
return !userSessionFlowCoordinator.isDisplayingRoomScreen(withRoomID: roomID) return !userSessionFlowCoordinator.isDisplayingRoomScreen(withRoomID: roomID)
} }
func notificationTapped(_ service: NotificationManagerProtocol, content: UNNotificationContent) async { func notificationTapped(content: UNNotificationContent) async {
MXLog.info("[AppCoordinator] tappedNotification") MXLog.info("[AppCoordinator] tappedNotification")
guard let roomID = content.roomID, guard let roomID = content.roomID,
@ -284,7 +285,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate,
setenv("RUST_BACKTRACE", "1", 1) setenv("RUST_BACKTRACE", "1", 1)
} }
private static func setupServiceLocator(navigationRootCoordinator: NavigationRootCoordinator, appSettings: AppSettings) { private static func setupServiceLocator(appSettings: AppSettings) {
ServiceLocator.shared.register(userIndicatorController: UserIndicatorController()) ServiceLocator.shared.register(userIndicatorController: UserIndicatorController())
ServiceLocator.shared.register(appSettings: appSettings) ServiceLocator.shared.register(appSettings: appSettings)
ServiceLocator.shared.register(networkMonitor: NetworkMonitor()) ServiceLocator.shared.register(networkMonitor: NetworkMonitor())

View File

@ -17,7 +17,6 @@
import Foundation import Foundation
protocol AppCoordinatorProtocol: CoordinatorProtocol { protocol AppCoordinatorProtocol: CoordinatorProtocol {
var notificationManager: NotificationManagerProtocol { get }
var windowManager: WindowManager { get } var windowManager: WindowManager { get }
@discardableResult func handleDeepLink(_ url: URL) -> Bool @discardableResult func handleDeepLink(_ url: URL) -> Bool
} }

View File

@ -87,8 +87,6 @@ final class AppSettings {
@UserPreference(key: UserDefaultsKeys.lastVersionLaunched, storageType: .userDefaults(store)) @UserPreference(key: UserDefaultsKeys.lastVersionLaunched, storageType: .userDefaults(store))
var lastVersionLaunched: String? var lastVersionLaunched: String?
let lastLaunchDate = Date()
/// The Set of room identifiers of invites that the user already saw in the invites list. /// 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. /// This Set is being used to implement badges for unread invites.
@UserPreference(key: UserDefaultsKeys.seenInvites, defaultValue: [], storageType: .userDefaults(store)) @UserPreference(key: UserDefaultsKeys.seenInvites, defaultValue: [], storageType: .userDefaults(store))
@ -180,7 +178,6 @@ final class AppSettings {
let bugReportSentryURL: URL = "https://f39ac49e97714316965b777d9f3d6cd8@sentry.tools.element.io/44" let bugReportSentryURL: URL = "https://f39ac49e97714316965b777d9f3d6cd8@sentry.tools.element.io/44"
// Use the name allocated by the bug report server // Use the name allocated by the bug report server
let bugReportApplicationId = "element-x-ios" let bugReportApplicationId = "element-x-ios"
let bugReportUISIId = "element-auto-uisi"
/// The maximum size of the upload request. Default value is just below CloudFlare's max request size. /// The maximum size of the upload request. Default value is just below CloudFlare's max request size.
let bugReportMaxUploadSize = 50 * 1024 * 1024 let bugReportMaxUploadSize = 50 * 1024 * 1024
@ -257,9 +254,6 @@ final class AppSettings {
// maptiler api key // maptiler api key
let mapTilerApiKey = InfoPlistReader.main.mapLibreAPIKey let mapTilerApiKey = InfoPlistReader.main.mapLibreAPIKey
// maptiler geocoding url
let geocodingURLFormatString = "https://api.maptiler.com/geocoding/%f,%f.json"
// MARK: - Feature Flags // MARK: - Feature Flags
@UserPreference(key: UserDefaultsKeys.userSuggestionsEnabled, defaultValue: false, storageType: .volatile) @UserPreference(key: UserDefaultsKeys.userSuggestionsEnabled, defaultValue: false, storageType: .volatile)

View File

@ -16,6 +16,7 @@
import Foundation import Foundation
// periphery:ignore - markdown protocol
@MainActor @MainActor
protocol FlowCoordinatorProtocol { protocol FlowCoordinatorProtocol {
func handleAppRoute(_ appRoute: AppRoute, animated: Bool) func handleAppRoute(_ appRoute: AppRoute, animated: Bool)

View File

@ -83,8 +83,6 @@ class AppLockFlowCoordinator: CoordinatorProtocol {
private let stateMachine: StateMachine<State, Event> private let stateMachine: StateMachine<State, Event>
/// A task used to await biometric unlock before showing the PIN screen.
@CancellableTask private var unlockTask: Task<Void, Never>?
private var cancellables: Set<AnyCancellable> = [] private var cancellables: Set<AnyCancellable> = []
/// Whether or not biometric unlock should be attempted instead of asking for a PIN. /// Whether or not biometric unlock should be attempted instead of asking for a PIN.

View File

@ -39,7 +39,6 @@ internal enum Asset {
internal static let addLocation = ImageAsset(name: "images/add-location") internal static let addLocation = ImageAsset(name: "images/add-location")
internal static let attachment = ImageAsset(name: "images/attachment") internal static let attachment = ImageAsset(name: "images/attachment")
internal static let takePhoto = ImageAsset(name: "images/take-photo") internal static let takePhoto = ImageAsset(name: "images/take-photo")
internal static let textFormatting = ImageAsset(name: "images/text-formatting")
internal static let bold = ImageAsset(name: "images/bold") internal static let bold = ImageAsset(name: "images/bold")
internal static let bulletList = ImageAsset(name: "images/bullet-list") internal static let bulletList = ImageAsset(name: "images/bullet-list")
internal static let closeRte = ImageAsset(name: "images/close-rte") internal static let closeRte = ImageAsset(name: "images/close-rte")

View File

@ -45,18 +45,6 @@ extension ApplicationMock {
underlyingApplicationState = applicationState underlyingApplicationState = applicationState
underlyingBackgroundTimeRemaining = backgroundTimeRemaining underlyingBackgroundTimeRemaining = backgroundTimeRemaining
beginBackgroundTaskExpirationHandlerClosure = { [weak self] handler in
guard let self else {
return .invalid
}
guard allowTasks else {
return .invalid
}
return beginBackgroundTask(withName: nil, expirationHandler: handler)
}
beginBackgroundTaskWithNameExpirationHandlerClosure = { _, handler in beginBackgroundTaskWithNameExpirationHandlerClosure = { _, handler in
guard allowTasks else { guard allowTasks else {
return .invalid return .invalid

View File

@ -56,18 +56,6 @@ class AnalyticsClientMock: AnalyticsClientProtocol {
stopCallsCount += 1 stopCallsCount += 1
stopClosure?() stopClosure?()
} }
//MARK: - flush
var flushCallsCount = 0
var flushCalled: Bool {
return flushCallsCount > 0
}
var flushClosure: (() -> Void)?
func flush() {
flushCallsCount += 1
flushClosure?()
}
//MARK: - capture //MARK: - capture
var captureCallsCount = 0 var captureCallsCount = 0
@ -100,22 +88,6 @@ class AnalyticsClientMock: AnalyticsClientProtocol {
screenReceivedInvocations.append(event) screenReceivedInvocations.append(event)
screenClosure?(event) screenClosure?(event)
} }
//MARK: - updateUserProperties
var updateUserPropertiesCallsCount = 0
var updateUserPropertiesCalled: Bool {
return updateUserPropertiesCallsCount > 0
}
var updateUserPropertiesReceivedUserProperties: AnalyticsEvent.UserProperties?
var updateUserPropertiesReceivedInvocations: [AnalyticsEvent.UserProperties] = []
var updateUserPropertiesClosure: ((AnalyticsEvent.UserProperties) -> Void)?
func updateUserProperties(_ userProperties: AnalyticsEvent.UserProperties) {
updateUserPropertiesCallsCount += 1
updateUserPropertiesReceivedUserProperties = userProperties
updateUserPropertiesReceivedInvocations.append(userProperties)
updateUserPropertiesClosure?(userProperties)
}
} }
class AppLockServiceMock: AppLockServiceProtocol { class AppLockServiceMock: AppLockServiceProtocol {
var isMandatory: Bool { var isMandatory: Bool {
@ -323,23 +295,6 @@ class ApplicationMock: ApplicationProtocol {
//MARK: - beginBackgroundTask //MARK: - beginBackgroundTask
var beginBackgroundTaskExpirationHandlerCallsCount = 0
var beginBackgroundTaskExpirationHandlerCalled: Bool {
return beginBackgroundTaskExpirationHandlerCallsCount > 0
}
var beginBackgroundTaskExpirationHandlerReturnValue: UIBackgroundTaskIdentifier!
var beginBackgroundTaskExpirationHandlerClosure: (((() -> Void)?) -> UIBackgroundTaskIdentifier)?
func beginBackgroundTask(expirationHandler handler: (() -> Void)?) -> UIBackgroundTaskIdentifier {
beginBackgroundTaskExpirationHandlerCallsCount += 1
if let beginBackgroundTaskExpirationHandlerClosure = beginBackgroundTaskExpirationHandlerClosure {
return beginBackgroundTaskExpirationHandlerClosure(handler)
} else {
return beginBackgroundTaskExpirationHandlerReturnValue
}
}
//MARK: - beginBackgroundTask
var beginBackgroundTaskWithNameExpirationHandlerCallsCount = 0 var beginBackgroundTaskWithNameExpirationHandlerCallsCount = 0
var beginBackgroundTaskWithNameExpirationHandlerCalled: Bool { var beginBackgroundTaskWithNameExpirationHandlerCalled: Bool {
return beginBackgroundTaskWithNameExpirationHandlerCallsCount > 0 return beginBackgroundTaskWithNameExpirationHandlerCallsCount > 0
@ -739,18 +694,6 @@ class BugReportServiceMock: BugReportServiceProtocol {
resetCallsCount += 1 resetCallsCount += 1
resetClosure?() resetClosure?()
} }
//MARK: - crash
var crashCallsCount = 0
var crashCalled: Bool {
return crashCallsCount > 0
}
var crashClosure: (() -> Void)?
func crash() {
crashCallsCount += 1
crashClosure?()
}
//MARK: - submitBugReport //MARK: - submitBugReport
var submitBugReportProgressListenerCallsCount = 0 var submitBugReportProgressListenerCallsCount = 0

View File

@ -106,10 +106,6 @@ enum RoomAvatarSizeOnScreen {
} }
extension AvatarSize { extension AvatarSize {
var size: CGSize {
CGSize(width: value, height: value)
}
var scaledSize: CGSize { var scaledSize: CGSize {
CGSize(width: scaledValue, height: scaledValue) CGSize(width: scaledValue, height: scaledValue)
} }

View File

@ -130,12 +130,6 @@ private extension String {
self[index(startIndex, offsetBy: offset)] self[index(startIndex, offsetBy: offset)]
} }
subscript(bounds: CountableClosedRange<Int>) -> Substring {
let start = index(startIndex, offsetBy: bounds.lowerBound)
let end = index(startIndex, offsetBy: bounds.upperBound)
return self[start...end]
}
subscript(bounds: CountableRange<Int>) -> Substring { subscript(bounds: CountableRange<Int>) -> Substring {
let start = index(startIndex, offsetBy: bounds.lowerBound) let start = index(startIndex, offsetBy: bounds.lowerBound)
let end = index(startIndex, offsetBy: bounds.upperBound) let end = index(startIndex, offsetBy: bounds.upperBound)

View File

@ -16,6 +16,7 @@
import Foundation import Foundation
// periphery:ignore - property wrappers generate false positives
@propertyWrapper @propertyWrapper
struct CancellableTask<S: Sendable, F: Error> { struct CancellableTask<S: Sendable, F: Error> {
private var storedValue: Task<S, F>? private var storedValue: Task<S, F>?

View File

@ -47,18 +47,18 @@ struct CollapsibleReactionLayout: Layout {
rows: collapsedRows, rows: collapsedRows,
collapseButton: subviewsByType.collapseButton, collapseButton: subviewsByType.collapseButton,
addMoreButton: subviewsByType.addMoreButton) addMoreButton: subviewsByType.addMoreButton)
let size = sizeThatFits(proposal: proposal, rows: collapsedRowsWithButtons) let size = sizeThatFits(rows: collapsedRowsWithButtons)
return size return size
} else { } else {
// Show all subviews with the button at the end // Show all subviews with the button at the end
var rowsWithButtons = calculateRows(proposal: proposal, subviews: Array(subviews)) var rowsWithButtons = calculateRows(proposal: proposal, subviews: Array(subviews))
ensureCollapseAndAddMoreButtonsAreOnTheSameRow(&rowsWithButtons) ensureCollapseAndAddMoreButtonsAreOnTheSameRow(&rowsWithButtons)
let size = sizeThatFits(proposal: proposal, rows: rowsWithButtons) let size = sizeThatFits(rows: rowsWithButtons)
return size return size
} }
} else { } else {
// Otherwise we are just calculating the size of all items without the button // Otherwise we are just calculating the size of all items without the button
return sizeThatFits(proposal: proposal, rows: reactionsAndAddMore) return sizeThatFits(rows: reactionsAndAddMore)
} }
} }
@ -140,7 +140,7 @@ struct CollapsibleReactionLayout: Layout {
/// - proposal: The proposed size /// - proposal: The proposed size
/// - rows: The list of rows /// - rows: The list of rows
/// - Returns: The size render the rows /// - Returns: The size render the rows
private func sizeThatFits(proposal: ProposedViewSize, rows: [[FlowLayoutSubview]]) -> CGSize { private func sizeThatFits(rows: [[FlowLayoutSubview]]) -> CGSize {
let sizes = rows.map { row in let sizes = rows.map { row in
row.map { subview in row.map { subview in
subview.sizeThatFits(.unspecified) subview.sizeThatFits(.unspecified)

View File

@ -31,6 +31,18 @@ extension View {
}) })
return alert(item.wrappedValue?.title ?? "", isPresented: binding, presenting: item.wrappedValue, actions: actions, message: message) return alert(item.wrappedValue?.title ?? "", isPresented: binding, presenting: item.wrappedValue, actions: actions, message: message)
} }
// periphery: ignore - not used yet but might be useful
func alert<Item, Actions>(item: Binding<Item?>, @ViewBuilder actions: (Item) -> Actions) -> some View where Item: AlertProtocol, Actions: View {
let binding = Binding<Bool>(get: {
item.wrappedValue != nil
}, set: { newValue in
if !newValue {
item.wrappedValue = nil
}
})
return alert(item.wrappedValue?.title ?? "", isPresented: binding, presenting: item.wrappedValue, actions: actions)
}
} }
/// A type that describes an alert to be shown to the user. /// A type that describes an alert to be shown to the user.

View File

@ -73,13 +73,3 @@ extension Array where Element == RoomTimelineItemProtocol {
first { $0.id.timelineID == id.timelineID } first { $0.id.timelineID == id.timelineID }
} }
} }
extension Array {
func appending(_ element: Element) -> [Element] {
self + [element]
}
func appending(_ elements: [Element]) -> [Element] {
self + elements
}
}

View File

@ -34,6 +34,7 @@ extension View {
return confirmationDialog(item.wrappedValue?.title ?? "", isPresented: binding, titleVisibility: titleVisibility, presenting: item.wrappedValue, actions: actions) return confirmationDialog(item.wrappedValue?.title ?? "", isPresented: binding, titleVisibility: titleVisibility, presenting: item.wrappedValue, actions: actions)
} }
// periphery: ignore - not used yet but might be useful
func confirmationDialog<Item, Actions, Message>(item: Binding<Item?>, func confirmationDialog<Item, Actions, Message>(item: Binding<Item?>,
titleVisibility: Visibility = .automatic, titleVisibility: Visibility = .automatic,
@ViewBuilder actions: (Item) -> Actions, @ViewBuilder actions: (Item) -> Actions,

View File

@ -21,9 +21,3 @@ extension MapTilerStyleBuilder {
self.init(baseURL: appSettings.mapTilerBaseURL, key: appSettings.mapTilerApiKey) self.init(baseURL: appSettings.mapTilerBaseURL, key: appSettings.mapTilerApiKey)
} }
} }
extension MapTilerGeoCodingService {
init(session: URLSession = .shared, appSettings: AppSettings) {
self.init(session: session, key: appSettings.mapTilerApiKey, geocodingURL: appSettings.geocodingURLFormatString)
}
}

View File

@ -22,7 +22,6 @@ struct AttributedStringBuilder: AttributedStringBuilderProtocol {
private let cacheKey: String private let cacheKey: String
private let temporaryBlockquoteMarkingColor = UIColor.magenta private let temporaryBlockquoteMarkingColor = UIColor.magenta
private let temporaryCodeBlockMarkingColor = UIColor.cyan private let temporaryCodeBlockMarkingColor = UIColor.cyan
private let linkColor = UIColor.blue
private let permalinkBaseURL: URL private let permalinkBaseURL: URL
private let mentionBuilder: MentionBuilderProtocol private let mentionBuilder: MentionBuilderProtocol
@ -33,10 +32,6 @@ struct AttributedStringBuilder: AttributedStringBuilderProtocol {
caches.removeAll() caches.removeAll()
} }
static func invalidateCache(for key: String = defaultKey) {
caches[key]?.removeAllValues()
}
init(cacheKey: String = defaultKey, permalinkBaseURL: URL, mentionBuilder: MentionBuilderProtocol) { init(cacheKey: String = defaultKey, permalinkBaseURL: URL, mentionBuilder: MentionBuilderProtocol) {
self.cacheKey = cacheKey self.cacheKey = cacheKey
if Self.caches[cacheKey] == nil { if Self.caches[cacheKey] == nil {
@ -73,7 +68,7 @@ struct AttributedStringBuilder: AttributedStringBuilderProtocol {
// that could happen with the default HTML renderer of NSAttributedString which is a // that could happen with the default HTML renderer of NSAttributedString which is a
// webview. // webview.
func fromHTML(_ htmlString: String?) -> AttributedString? { func fromHTML(_ htmlString: String?) -> AttributedString? {
guard var originalHTMLString = htmlString else { guard let originalHTMLString = htmlString else {
return nil return nil
} }

View File

@ -18,27 +18,27 @@ import Foundation
enum BlockquoteAttribute: AttributedStringKey { enum BlockquoteAttribute: AttributedStringKey {
typealias Value = Bool typealias Value = Bool
public static var name = "MXBlockquoteAttribute" static var name = "MXBlockquoteAttribute"
} }
enum UserIDAttribute: AttributedStringKey { enum UserIDAttribute: AttributedStringKey {
typealias Value = String typealias Value = String
public static var name = "MXUserIDAttribute" static var name = "MXUserIDAttribute"
} }
enum RoomIDAttribute: AttributedStringKey { enum RoomIDAttribute: AttributedStringKey {
typealias Value = String typealias Value = String
public static var name = "MXRoomIDAttribute" static var name = "MXRoomIDAttribute"
} }
enum RoomAliasAttribute: AttributedStringKey { enum RoomAliasAttribute: AttributedStringKey {
typealias Value = String typealias Value = String
public static var name = "MXRoomAliasAttribute" static var name = "MXRoomAliasAttribute"
} }
enum AllUsersMentionAttribute: AttributedStringKey { enum AllUsersMentionAttribute: AttributedStringKey {
typealias Value = Bool typealias Value = Bool
public static var name = "MXAllUsersMentionAttribute" static var name = "MXAllUsersMentionAttribute"
} }
struct EventIDAttributeValue: Hashable { struct EventIDAttributeValue: Hashable {
@ -48,9 +48,10 @@ struct EventIDAttributeValue: Hashable {
enum EventIDAttribute: AttributedStringKey { enum EventIDAttribute: AttributedStringKey {
typealias Value = EventIDAttributeValue typealias Value = EventIDAttributeValue
public static var name = "MXEventIDAttribute" static var name = "MXEventIDAttribute"
} }
// periphery: ignore - required to make NSAttributedString to AttributedString conversion even if not used directly
extension AttributeScopes { extension AttributeScopes {
struct ElementXAttributes: AttributeScope { struct ElementXAttributes: AttributeScope {
let blockquote: BlockquoteAttribute let blockquote: BlockquoteAttribute
@ -69,6 +70,7 @@ extension AttributeScopes {
var elementX: ElementXAttributes.Type { ElementXAttributes.self } var elementX: ElementXAttributes.Type { ElementXAttributes.self }
} }
// periphery: ignore - required to make NSAttributedString to AttributedString conversion even if not used directly
extension AttributeDynamicLookup { extension AttributeDynamicLookup {
subscript<T: AttributedStringKey>(dynamicMember keyPath: KeyPath<AttributeScopes.ElementXAttributes, T>) -> T { subscript<T: AttributedStringKey>(dynamicMember keyPath: KeyPath<AttributeScopes.ElementXAttributes, T>) -> T {
self[T.self] self[T.self]

View File

@ -1,72 +0,0 @@
//
// Copyright 2023 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 CoreLocation
import Foundation
struct MapTilerGeoCodingService: MapTilerGeoCodingServiceProtocol {
private let key: String
private let session: URLSession
private let geocodingURL: String
init(session: URLSession = .shared, key: String, geocodingURL: String) {
self.session = session
self.key = key
self.geocodingURL = geocodingURL
}
private struct GeocodedPlace: Decodable {
struct FeatureCollection: Decodable {
let placeName: String
}
let features: [FeatureCollection]
}
func reverseGeoCoding(for coordinate: CLLocationCoordinate2D) async -> Result<String, MapTilerGeocodingError> {
let latitude = coordinate.latitude
let longitude = coordinate.longitude
let path = String(format: geocodingURL, longitude, latitude)
guard var url = URL(string: path) else { return .failure(.wrongGeocodingURL) }
let authorization = MapTilerAuthorization(key: key)
url = authorization.authorizeURL(url)
url.append(queryItems: [.init(name: "limit", value: "1")])
var request = URLRequest(url: url)
request.httpMethod = "GET"
do {
let (data, response) = try await session.dataWithRetry(for: request)
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
let errorDescription = String(data: data, encoding: .utf8)?.trimmingCharacters(in: .whitespacesAndNewlines) ?? "Unknown"
MXLog.error("Failed to get reverse geocoding: \(errorDescription)")
MXLog.error("Response: \(response)")
return .failure(.geocodingFailed)
}
// Parse the JSON data
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let decodedResponse = try decoder.decode(GeocodedPlace.self, from: data)
guard let placeName = decodedResponse.features.first?.placeName else { return .failure(.geocodingFailed) }
return .success(placeName)
} catch {
return .failure(.geocodingFailed)
}
}
}

View File

@ -45,6 +45,6 @@ public extension Animation {
/// - Parameters: /// - Parameters:
/// - animation: Animation /// - animation: Animation
/// - body: operations to be animated /// - body: operations to be animated
public func withElementAnimation<Result>(_ animation: Animation? = .default, _ body: () throws -> Result) rethrows -> Result { func withElementAnimation<Result>(_ animation: Animation? = .default, _ body: () throws -> Result) rethrows -> Result {
try withAnimation(animation?.disabledDuringTests(), body) try withAnimation(animation?.disabledDuringTests(), body)
} }

View File

@ -79,11 +79,8 @@ struct ShimmerOverlay_Previews: PreviewProvider, TestablePreview {
static let viewModel = HomeScreenViewModel(userSession: MockUserSession(clientProxy: MockClientProxy(userID: ""), static let viewModel = HomeScreenViewModel(userSession: MockUserSession(clientProxy: MockClientProxy(userID: ""),
mediaProvider: MockMediaProvider(), mediaProvider: MockMediaProvider(),
voiceMessageMediaManager: VoiceMessageMediaManagerMock()), voiceMessageMediaManager: VoiceMessageMediaManagerMock()),
attributedStringBuilder: AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL,
mentionBuilder: MentionBuilder()),
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(), selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(),
appSettings: ServiceLocator.shared.settings, appSettings: ServiceLocator.shared.settings,
analytics: ServiceLocator.shared.analytics,
userIndicatorController: ServiceLocator.shared.userIndicatorController) userIndicatorController: ServiceLocator.shared.userIndicatorController)
static var previews: some View { static var previews: some View {

View File

@ -27,7 +27,11 @@ struct CustomLayoutLabelStyle: LabelStyle {
let spacing: CGFloat let spacing: CGFloat
var alignment: VerticalAlignment var alignment: VerticalAlignment
enum IconLayout { case leading, trailing } enum IconLayout {
case leading
case trailing
}
var iconLayout: IconLayout var iconLayout: IconLayout
fileprivate init(spacing: CGFloat, alignment: VerticalAlignment, iconLayout: IconLayout) { fileprivate init(spacing: CGFloat, alignment: VerticalAlignment, iconLayout: IconLayout) {
@ -38,10 +42,11 @@ struct CustomLayoutLabelStyle: LabelStyle {
func makeBody(configuration: Configuration) -> some View { func makeBody(configuration: Configuration) -> some View {
HStack(alignment: alignment, spacing: spacing) { HStack(alignment: alignment, spacing: spacing) {
if iconLayout == .leading { switch iconLayout {
case .leading:
configuration.icon configuration.icon
configuration.title configuration.title
} else { case .trailing:
configuration.title configuration.title
configuration.icon configuration.icon
} }

View File

@ -26,7 +26,7 @@ struct AppActivityView: UIViewControllerRepresentable {
private var onCancel: (() -> Void)? private var onCancel: (() -> Void)?
private var onComplete: CompletionType? private var onComplete: CompletionType?
public init(activityItems: [Any], init(activityItems: [Any],
applicationActivities: [UIActivity]? = nil, applicationActivities: [UIActivity]? = nil,
excludedActivityTypes: [UIActivity.ActivityType] = [], excludedActivityTypes: [UIActivity.ActivityType] = [],
onCancel: (() -> Void)? = nil, onCancel: (() -> Void)? = nil,
@ -38,7 +38,7 @@ struct AppActivityView: UIViewControllerRepresentable {
self.onComplete = onComplete self.onComplete = onComplete
} }
public func makeUIViewController(context: Context) -> UIViewControllerType { func makeUIViewController(context: Context) -> UIViewControllerType {
let viewController = UIViewControllerType(activityItems: activityItems, applicationActivities: applicationActivities) let viewController = UIViewControllerType(activityItems: activityItems, applicationActivities: applicationActivities)
viewController.excludedActivityTypes = excludedActivityTypes viewController.excludedActivityTypes = excludedActivityTypes
@ -57,9 +57,9 @@ struct AppActivityView: UIViewControllerRepresentable {
return viewController return viewController
} }
public func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) { } func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) { }
public static func dismantleUIViewController(_ uiViewController: UIViewControllerType, coordinator: Coordinator) { static func dismantleUIViewController(_ uiViewController: UIViewControllerType, coordinator: Coordinator) {
uiViewController.completionWithItemsHandler = nil uiViewController.completionWithItemsHandler = nil
} }
} }

View File

@ -1,30 +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 SwiftUI
/// A toggle style that uses a button, with a checked/unchecked image like a checkbox.
struct ElementToggleStyle: ToggleStyle {
func makeBody(configuration: Configuration) -> some View {
Button { configuration.isOn.toggle() } label: {
Image(systemName: configuration.isOn ? "checkmark.square.fill" : "square")
.font(.title3.weight(.regular))
.imageScale(.large)
.foregroundColor(.compound.textActionPrimary)
}
.buttonStyle(.plain)
}
}

View File

@ -57,7 +57,6 @@ struct EstimatedWaveformView: View {
var lineWidth: CGFloat = 2 var lineWidth: CGFloat = 2
var linePadding: CGFloat = 2 var linePadding: CGFloat = 2
var waveform: EstimatedWaveform var waveform: EstimatedWaveform
private let minimumGraphAmplitude: CGFloat = 1
var progress: CGFloat = 0.0 var progress: CGFloat = 0.0
@State private var normalizedWaveformData: [Float] = [] @State private var normalizedWaveformData: [Float] = []

View File

@ -30,7 +30,6 @@ enum AppLockScreenCoordinatorAction {
} }
final class AppLockScreenCoordinator: CoordinatorProtocol { final class AppLockScreenCoordinator: CoordinatorProtocol {
private let parameters: AppLockScreenCoordinatorParameters
private var viewModel: AppLockScreenViewModelProtocol private var viewModel: AppLockScreenViewModelProtocol
private let actionsSubject: PassthroughSubject<AppLockScreenCoordinatorAction, Never> = .init() private let actionsSubject: PassthroughSubject<AppLockScreenCoordinatorAction, Never> = .init()
private var cancellables = Set<AnyCancellable>() private var cancellables = Set<AnyCancellable>()
@ -40,8 +39,6 @@ final class AppLockScreenCoordinator: CoordinatorProtocol {
} }
init(parameters: AppLockScreenCoordinatorParameters) { init(parameters: AppLockScreenCoordinatorParameters) {
self.parameters = parameters
viewModel = AppLockScreenViewModel(appLockService: parameters.appLockService) viewModel = AppLockScreenViewModel(appLockService: parameters.appLockService)
} }

View File

@ -26,7 +26,6 @@ enum AppLockSetupBiometricsScreenCoordinatorAction {
} }
final class AppLockSetupBiometricsScreenCoordinator: CoordinatorProtocol { final class AppLockSetupBiometricsScreenCoordinator: CoordinatorProtocol {
private let parameters: AppLockSetupBiometricsScreenCoordinatorParameters
private var viewModel: AppLockSetupBiometricsScreenViewModelProtocol private var viewModel: AppLockSetupBiometricsScreenViewModelProtocol
private let actionsSubject: PassthroughSubject<AppLockSetupBiometricsScreenCoordinatorAction, Never> = .init() private let actionsSubject: PassthroughSubject<AppLockSetupBiometricsScreenCoordinatorAction, Never> = .init()
private var cancellables = Set<AnyCancellable>() private var cancellables = Set<AnyCancellable>()
@ -36,8 +35,6 @@ final class AppLockSetupBiometricsScreenCoordinator: CoordinatorProtocol {
} }
init(parameters: AppLockSetupBiometricsScreenCoordinatorParameters) { init(parameters: AppLockSetupBiometricsScreenCoordinatorParameters) {
self.parameters = parameters
viewModel = AppLockSetupBiometricsScreenViewModel(appLockService: parameters.appLockService) viewModel = AppLockSetupBiometricsScreenViewModel(appLockService: parameters.appLockService)
} }

View File

@ -36,7 +36,6 @@ enum AppLockSetupPINScreenCoordinatorAction {
} }
final class AppLockSetupPINScreenCoordinator: CoordinatorProtocol { final class AppLockSetupPINScreenCoordinator: CoordinatorProtocol {
private let parameters: AppLockSetupPINScreenCoordinatorParameters
private var viewModel: AppLockSetupPINScreenViewModelProtocol private var viewModel: AppLockSetupPINScreenViewModelProtocol
private let actionsSubject: PassthroughSubject<AppLockSetupPINScreenCoordinatorAction, Never> = .init() private let actionsSubject: PassthroughSubject<AppLockSetupPINScreenCoordinatorAction, Never> = .init()
private var cancellables = Set<AnyCancellable>() private var cancellables = Set<AnyCancellable>()
@ -48,7 +47,6 @@ final class AppLockSetupPINScreenCoordinator: CoordinatorProtocol {
init(parameters: AppLockSetupPINScreenCoordinatorParameters) { init(parameters: AppLockSetupPINScreenCoordinatorParameters) {
guard parameters.initialMode != .confirm else { fatalError(".confirm is an invalid initial mode") } guard parameters.initialMode != .confirm else { fatalError(".confirm is an invalid initial mode") }
self.parameters = parameters
viewModel = AppLockSetupPINScreenViewModel(initialMode: parameters.initialMode, viewModel = AppLockSetupPINScreenViewModel(initialMode: parameters.initialMode,
isMandatory: parameters.isMandatory, isMandatory: parameters.isMandatory,
appLockService: parameters.appLockService) appLockService: parameters.appLockService)

View File

@ -45,7 +45,7 @@ class AppLockSetupPINScreenViewModel: AppLockSetupPINScreenViewModelType, AppLoc
.debounce(for: 0.1, scheduler: DispatchQueue.main) // Show the last digit for long enough to be read. .debounce(for: 0.1, scheduler: DispatchQueue.main) // Show the last digit for long enough to be read.
.sink { [weak self] pinCode in .sink { [weak self] pinCode in
guard pinCode.count == 4 else { return } guard pinCode.count == 4 else { return }
self?.submit(pinCode) self?.submit()
} }
.store(in: &cancellables) .store(in: &cancellables)
} }
@ -64,7 +64,7 @@ class AppLockSetupPINScreenViewModel: AppLockSetupPINScreenViewModelType, AppLoc
// MARK: - Private // MARK: - Private
/// Handle the entered PIN code. /// Handle the entered PIN code.
private func submit(_ pinCode: String) { private func submit() {
switch state.mode { switch state.mode {
case .create: case .create:
createPIN() createPIN()

View File

@ -29,7 +29,6 @@ enum AppLockSetupSettingsScreenCoordinatorAction {
} }
final class AppLockSetupSettingsScreenCoordinator: CoordinatorProtocol { final class AppLockSetupSettingsScreenCoordinator: CoordinatorProtocol {
private let parameters: AppLockSetupSettingsScreenCoordinatorParameters
private var viewModel: AppLockSetupSettingsScreenViewModelProtocol private var viewModel: AppLockSetupSettingsScreenViewModelProtocol
private let actionsSubject: PassthroughSubject<AppLockSetupSettingsScreenCoordinatorAction, Never> = .init() private let actionsSubject: PassthroughSubject<AppLockSetupSettingsScreenCoordinatorAction, Never> = .init()
private var cancellables = Set<AnyCancellable>() private var cancellables = Set<AnyCancellable>()
@ -39,8 +38,6 @@ final class AppLockSetupSettingsScreenCoordinator: CoordinatorProtocol {
} }
init(parameters: AppLockSetupSettingsScreenCoordinatorParameters) { init(parameters: AppLockSetupSettingsScreenCoordinatorParameters) {
self.parameters = parameters
viewModel = AppLockSetupSettingsScreenViewModel(appLockService: parameters.appLockService) viewModel = AppLockSetupSettingsScreenViewModel(appLockService: parameters.appLockService)
} }

View File

@ -19,8 +19,7 @@ import SwiftUI
@MainActor @MainActor
protocol AuthenticationCoordinatorDelegate: AnyObject { protocol AuthenticationCoordinatorDelegate: AnyObject {
func authenticationCoordinator(_ authenticationCoordinator: AuthenticationCoordinator, func authenticationCoordinator(didLoginWithSession userSession: UserSessionProtocol)
didLoginWithSession userSession: UserSessionProtocol)
} }
class AuthenticationCoordinator: CoordinatorProtocol { class AuthenticationCoordinator: CoordinatorProtocol {
@ -34,6 +33,7 @@ class AuthenticationCoordinator: CoordinatorProtocol {
private var cancellables = Set<AnyCancellable>() private var cancellables = Set<AnyCancellable>()
private var oidcPresenter: OIDCAuthenticationPresenter? private var oidcPresenter: OIDCAuthenticationPresenter?
// periphery: ignore - used to store the coordinator to avoid deallocation
private var appLockFlowCoordinator: AppLockSetupFlowCoordinator? private var appLockFlowCoordinator: AppLockSetupFlowCoordinator?
weak var delegate: AuthenticationCoordinatorDelegate? weak var delegate: AuthenticationCoordinatorDelegate?
@ -245,7 +245,7 @@ class AuthenticationCoordinator: CoordinatorProtocol {
} else if analytics.shouldShowAnalyticsPrompt { } else if analytics.shouldShowAnalyticsPrompt {
showAnalyticsPrompt(userSession: userSession) showAnalyticsPrompt(userSession: userSession)
} else { } else {
delegate?.authenticationCoordinator(self, didLoginWithSession: userSession) delegate?.authenticationCoordinator(didLoginWithSession: userSession)
} }
} }
@ -261,7 +261,7 @@ class AuthenticationCoordinator: CoordinatorProtocol {
if analytics.shouldShowAnalyticsPrompt { if analytics.shouldShowAnalyticsPrompt {
showAnalyticsPrompt(userSession: userSession) showAnalyticsPrompt(userSession: userSession)
} else { } else {
delegate?.authenticationCoordinator(self, didLoginWithSession: userSession) delegate?.authenticationCoordinator(didLoginWithSession: userSession)
} }
case .forceLogout: case .forceLogout:
fatalError("The PIN creation flow should not fail.") fatalError("The PIN creation flow should not fail.")
@ -281,7 +281,7 @@ class AuthenticationCoordinator: CoordinatorProtocol {
guard let self else { return } guard let self else { return }
switch action { switch action {
case .done: case .done:
delegate?.authenticationCoordinator(self, didLoginWithSession: userSession) delegate?.authenticationCoordinator(didLoginWithSession: userSession)
} }
} }
.store(in: &cancellables) .store(in: &cancellables)

View File

@ -44,7 +44,6 @@ public extension TextFieldStyle where Self == AuthenticationTextFieldStyle {
/// The text field style used in authentication screens. /// The text field style used in authentication screens.
public struct AuthenticationTextFieldStyle: TextFieldStyle { public struct AuthenticationTextFieldStyle: TextFieldStyle {
@Environment(\.isEnabled) private var isEnabled @Environment(\.isEnabled) private var isEnabled
@Environment(\.colorScheme) private var colorScheme
@FocusState private var isFocused: Bool @FocusState private var isFocused: Bool
public let labelText: Text? public let labelText: Text?

View File

@ -24,6 +24,7 @@ class BugReportScreenViewModel: BugReportScreenViewModelType, BugReportScreenVie
private let userID: String private let userID: String
private let deviceID: String? private let deviceID: String?
private let actionsSubject: PassthroughSubject<BugReportScreenViewModelAction, Never> = .init() private let actionsSubject: PassthroughSubject<BugReportScreenViewModelAction, Never> = .init()
// periphery:ignore - when set to nil this is automatically cancelled
@CancellableTask private var uploadTask: Task<Void, Never>? @CancellableTask private var uploadTask: Task<Void, Never>?
var actions: AnyPublisher<BugReportScreenViewModelAction, Never> { var actions: AnyPublisher<BugReportScreenViewModelAction, Never> {

View File

@ -140,12 +140,6 @@ struct BugReportScreen: View {
// MARK: - Previews // MARK: - Previews
struct BugReport_Previews: PreviewProvider, TestablePreview { struct BugReport_Previews: PreviewProvider, TestablePreview {
static let viewModel = BugReportScreenViewModel(bugReportService: BugReportServiceMock(),
userID: "@mock.client.com",
deviceID: nil,
screenshot: nil,
isModallyPresented: false)
static var previews: some View { static var previews: some View {
NavigationStack { NavigationStack {
BugReportScreen(context: BugReportScreenViewModel(bugReportService: BugReportServiceMock(), BugReportScreen(context: BugReportScreenViewModel(bugReportService: BugReportServiceMock(),

View File

@ -32,7 +32,6 @@ enum CallScreenCoordinatorAction {
} }
final class CallScreenCoordinator: CoordinatorProtocol { final class CallScreenCoordinator: CoordinatorProtocol {
private let parameters: CallScreenCoordinatorParameters
private var viewModel: CallScreenViewModelProtocol private var viewModel: CallScreenViewModelProtocol
private let actionsSubject: PassthroughSubject<CallScreenCoordinatorAction, Never> = .init() private let actionsSubject: PassthroughSubject<CallScreenCoordinatorAction, Never> = .init()
@ -42,8 +41,6 @@ final class CallScreenCoordinator: CoordinatorProtocol {
} }
init(parameters: CallScreenCoordinatorParameters) { init(parameters: CallScreenCoordinatorParameters) {
self.parameters = parameters
viewModel = CallScreenViewModel(roomProxy: parameters.roomProxy, viewModel = CallScreenViewModel(roomProxy: parameters.roomProxy,
callBaseURL: parameters.callBaseURL, callBaseURL: parameters.callBaseURL,
clientID: parameters.clientID, clientID: parameters.clientID,

View File

@ -23,13 +23,13 @@ typealias CallScreenViewModelType = StateStoreViewModel<CallScreenViewState, Cal
class CallScreenViewModel: CallScreenViewModelType, CallScreenViewModelProtocol { class CallScreenViewModel: CallScreenViewModelType, CallScreenViewModelProtocol {
private let roomProxy: RoomProxyProtocol private let roomProxy: RoomProxyProtocol
private let callBaseURL: URL
private let clientID: String
private let widgetDriver: ElementCallWidgetDriverProtocol private let widgetDriver: ElementCallWidgetDriverProtocol
private let callController = CXCallController() private let callController = CXCallController()
// periphery: ignore - call kit magic do not remove
private let callProvider = CXProvider(configuration: .init()) private let callProvider = CXProvider(configuration: .init())
private let callID = UUID() private let callID = UUID()
private let actionsSubject: PassthroughSubject<CallScreenViewModelAction, Never> = .init() private let actionsSubject: PassthroughSubject<CallScreenViewModelAction, Never> = .init()
@ -51,8 +51,6 @@ class CallScreenViewModel: CallScreenViewModelType, CallScreenViewModelProtocol
clientID: String, clientID: String,
useEncryption: Bool) { useEncryption: Bool) {
self.roomProxy = roomProxy self.roomProxy = roomProxy
self.callBaseURL = callBaseURL
self.clientID = clientID
widgetDriver = roomProxy.elementCallWidgetDriver() widgetDriver = roomProxy.elementCallWidgetDriver()
@ -132,12 +130,14 @@ class CallScreenViewModel: CallScreenViewModelType, CallScreenViewModelProtocol
// MARK: - CXCallObserverDelegate // MARK: - CXCallObserverDelegate
// periphery: ignore - call kit magic do not remove
func callObserver(_ callObserver: CXCallObserver, callChanged call: CXCall) { func callObserver(_ callObserver: CXCallObserver, callChanged call: CXCall) {
MXLog.info("Call changed: \(call)") MXLog.info("Call changed: \(call)")
} }
// MARK: - CXProviderDelegate // MARK: - CXProviderDelegate
// periphery: ignore - call kit magic do not remove
func providerDidReset(_ provider: CXProvider) { func providerDidReset(_ provider: CXProvider) {
MXLog.info("Call provider did reset: \(provider)") MXLog.info("Call provider did reset: \(provider)")
} }

View File

@ -53,7 +53,6 @@ private struct WebView: UIViewRepresentable {
@MainActor @MainActor
class Coordinator: NSObject, WKScriptMessageHandler, WKUIDelegate, WKNavigationDelegate { class Coordinator: NSObject, WKScriptMessageHandler, WKUIDelegate, WKNavigationDelegate {
private let viewModelContext: CallScreenViewModel.Context private let viewModelContext: CallScreenViewModel.Context
private var webViewURLObservation: NSKeyValueObservation?
private(set) var webView: WKWebView! private(set) var webView: WKWebView!

View File

@ -30,15 +30,6 @@ enum SuggestionItem: Identifiable, Equatable {
return PillConstants.atRoom return PillConstants.atRoom
} }
} }
var name: String? {
switch self {
case .user(let user):
return user.displayName
case .allUsers:
return PillConstants.everyone
}
}
} }
struct MentionSuggestionItem: Identifiable, Equatable { struct MentionSuggestionItem: Identifiable, Equatable {

View File

@ -25,6 +25,7 @@ struct SuggestionPattern: Equatable {
let text: String let text: String
} }
// periphery: ignore - markdown protocol
protocol ComposerToolbarViewModelProtocol { protocol ComposerToolbarViewModelProtocol {
var actions: AnyPublisher<ComposerToolbarViewModelAction, Never> { get } var actions: AnyPublisher<ComposerToolbarViewModelAction, Never> { get }
var context: ComposerToolbarViewModelType.Context { get } var context: ComposerToolbarViewModelType.Context { get }

View File

@ -313,8 +313,8 @@ struct ComposerToolbar_Previews: PreviewProvider, TestablePreview {
VStack(spacing: 8) { VStack(spacing: 8) {
ComposerToolbar.textWithVoiceMessage(focused: false) ComposerToolbar.textWithVoiceMessage(focused: false)
ComposerToolbar.textWithVoiceMessage(focused: true) ComposerToolbar.textWithVoiceMessage(focused: true)
ComposerToolbar.voiceMessageRecordingMock(recording: true) ComposerToolbar.voiceMessageRecordingMock()
ComposerToolbar.voiceMessagePreviewMock(recording: false, uploading: false) ComposerToolbar.voiceMessagePreviewMock(uploading: false)
} }
.previewDisplayName("Voice Message") .previewDisplayName("Voice Message")
} }
@ -355,7 +355,7 @@ extension ComposerToolbar {
keyCommandHandler: { _ in false }) keyCommandHandler: { _ in false })
} }
static func voiceMessageRecordingMock(recording: Bool) -> ComposerToolbar { static func voiceMessageRecordingMock() -> ComposerToolbar {
let wysiwygViewModel = WysiwygComposerViewModel() let wysiwygViewModel = WysiwygComposerViewModel()
var composerViewModel: ComposerToolbarViewModel { var composerViewModel: ComposerToolbarViewModel {
let model = ComposerToolbarViewModel(wysiwygViewModel: wysiwygViewModel, let model = ComposerToolbarViewModel(wysiwygViewModel: wysiwygViewModel,
@ -371,7 +371,7 @@ extension ComposerToolbar {
keyCommandHandler: { _ in false }) keyCommandHandler: { _ in false })
} }
static func voiceMessagePreviewMock(recording: Bool, uploading: Bool) -> ComposerToolbar { static func voiceMessagePreviewMock(uploading: Bool) -> ComposerToolbar {
let wysiwygViewModel = WysiwygComposerViewModel() let wysiwygViewModel = WysiwygComposerViewModel()
let waveformData: [Float] = Array(repeating: 1.0, count: 1000) let waveformData: [Float] = Array(repeating: 1.0, count: 1000)
var composerViewModel: ComposerToolbarViewModel { var composerViewModel: ComposerToolbarViewModel {

View File

@ -33,7 +33,6 @@ enum CreateRoomCoordinatorAction {
} }
final class CreateRoomCoordinator: CoordinatorProtocol { final class CreateRoomCoordinator: CoordinatorProtocol {
private let parameters: CreateRoomCoordinatorParameters
private var viewModel: CreateRoomViewModelProtocol private var viewModel: CreateRoomViewModelProtocol
private let actionsSubject: PassthroughSubject<CreateRoomCoordinatorAction, Never> = .init() private let actionsSubject: PassthroughSubject<CreateRoomCoordinatorAction, Never> = .init()
private var cancellables = Set<AnyCancellable>() private var cancellables = Set<AnyCancellable>()
@ -43,7 +42,6 @@ final class CreateRoomCoordinator: CoordinatorProtocol {
} }
init(parameters: CreateRoomCoordinatorParameters) { init(parameters: CreateRoomCoordinatorParameters) {
self.parameters = parameters
viewModel = CreateRoomViewModel(userSession: parameters.userSession, viewModel = CreateRoomViewModel(userSession: parameters.userSession,
createRoomParameters: parameters.createRoomParameters, createRoomParameters: parameters.createRoomParameters,
selectedUsers: parameters.selectedUsers, selectedUsers: parameters.selectedUsers,

View File

@ -39,7 +39,6 @@ enum HomeScreenCoordinatorAction {
} }
final class HomeScreenCoordinator: CoordinatorProtocol { final class HomeScreenCoordinator: CoordinatorProtocol {
private let parameters: HomeScreenCoordinatorParameters
private var viewModel: HomeScreenViewModelProtocol private var viewModel: HomeScreenViewModelProtocol
private let actionsSubject: PassthroughSubject<HomeScreenCoordinatorAction, Never> = .init() private let actionsSubject: PassthroughSubject<HomeScreenCoordinatorAction, Never> = .init()
@ -50,13 +49,9 @@ final class HomeScreenCoordinator: CoordinatorProtocol {
} }
init(parameters: HomeScreenCoordinatorParameters) { init(parameters: HomeScreenCoordinatorParameters) {
self.parameters = parameters
viewModel = HomeScreenViewModel(userSession: parameters.userSession, viewModel = HomeScreenViewModel(userSession: parameters.userSession,
attributedStringBuilder: parameters.attributedStringBuilder,
selectedRoomPublisher: parameters.selectedRoomPublisher, selectedRoomPublisher: parameters.selectedRoomPublisher,
appSettings: ServiceLocator.shared.settings, appSettings: ServiceLocator.shared.settings,
analytics: ServiceLocator.shared.analytics,
userIndicatorController: ServiceLocator.shared.userIndicatorController) userIndicatorController: ServiceLocator.shared.userIndicatorController)
viewModel.actions viewModel.actions

View File

@ -21,9 +21,7 @@ typealias HomeScreenViewModelType = StateStoreViewModel<HomeScreenViewState, Hom
class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol { class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol {
private let userSession: UserSessionProtocol private let userSession: UserSessionProtocol
private let attributedStringBuilder: AttributedStringBuilderProtocol
private let appSettings: AppSettings private let appSettings: AppSettings
private let analytics: AnalyticsService
private let userIndicatorController: UserIndicatorControllerProtocol private let userIndicatorController: UserIndicatorControllerProtocol
private let roomSummaryProvider: RoomSummaryProviderProtocol? private let roomSummaryProvider: RoomSummaryProviderProtocol?
@ -39,15 +37,11 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
} }
init(userSession: UserSessionProtocol, init(userSession: UserSessionProtocol,
attributedStringBuilder: AttributedStringBuilderProtocol,
selectedRoomPublisher: CurrentValuePublisher<String?, Never>, selectedRoomPublisher: CurrentValuePublisher<String?, Never>,
appSettings: AppSettings, appSettings: AppSettings,
analytics: AnalyticsService,
userIndicatorController: UserIndicatorControllerProtocol) { userIndicatorController: UserIndicatorControllerProtocol) {
self.userSession = userSession self.userSession = userSession
self.attributedStringBuilder = attributedStringBuilder
self.appSettings = appSettings self.appSettings = appSettings
self.analytics = analytics
self.userIndicatorController = userIndicatorController self.userIndicatorController = userIndicatorController
roomSummaryProvider = userSession.clientProxy.roomSummaryProvider roomSummaryProvider = userSession.clientProxy.roomSummaryProvider

View File

@ -306,14 +306,9 @@ struct HomeScreen_Previews: PreviewProvider, TestablePreview {
mediaProvider: MockMediaProvider(), mediaProvider: MockMediaProvider(),
voiceMessageMediaManager: VoiceMessageMediaManagerMock()) voiceMessageMediaManager: VoiceMessageMediaManagerMock())
let attributedStringBuilder = AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL,
mentionBuilder: MentionBuilder())
return HomeScreenViewModel(userSession: userSession, return HomeScreenViewModel(userSession: userSession,
attributedStringBuilder: attributedStringBuilder,
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(), selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(),
appSettings: ServiceLocator.shared.settings, appSettings: ServiceLocator.shared.settings,
analytics: ServiceLocator.shared.analytics,
userIndicatorController: ServiceLocator.shared.userIndicatorController) userIndicatorController: ServiceLocator.shared.userIndicatorController)
} }
} }

View File

@ -155,10 +155,8 @@ struct HomeScreenEmptyStateView_Previews: PreviewProvider, TestablePreview {
voiceMessageMediaManager: VoiceMessageMediaManagerMock()) voiceMessageMediaManager: VoiceMessageMediaManagerMock())
return HomeScreenViewModel(userSession: userSession, return HomeScreenViewModel(userSession: userSession,
attributedStringBuilder: AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL, mentionBuilder: MentionBuilder()),
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(), selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(),
appSettings: ServiceLocator.shared.settings, appSettings: ServiceLocator.shared.settings,
analytics: ServiceLocator.shared.analytics,
userIndicatorController: ServiceLocator.shared.userIndicatorController) userIndicatorController: ServiceLocator.shared.userIndicatorController)
}() }()
} }

View File

@ -72,14 +72,9 @@ struct HomeScreenRecoveryKeyConfirmationBanner_Previews: PreviewProvider, Testab
mediaProvider: MockMediaProvider(), mediaProvider: MockMediaProvider(),
voiceMessageMediaManager: VoiceMessageMediaManagerMock()) voiceMessageMediaManager: VoiceMessageMediaManagerMock())
let attributedStringBuilder = AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL,
mentionBuilder: MentionBuilder())
return HomeScreenViewModel(userSession: userSession, return HomeScreenViewModel(userSession: userSession,
attributedStringBuilder: attributedStringBuilder,
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(), selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(),
appSettings: ServiceLocator.shared.settings, appSettings: ServiceLocator.shared.settings,
analytics: ServiceLocator.shared.analytics,
userIndicatorController: ServiceLocator.shared.userIndicatorController) userIndicatorController: ServiceLocator.shared.userIndicatorController)
} }
} }

View File

@ -186,11 +186,8 @@ struct HomeScreenRoomCell_Previews: PreviewProvider, TestablePreview {
voiceMessageMediaManager: VoiceMessageMediaManagerMock()) voiceMessageMediaManager: VoiceMessageMediaManagerMock())
let viewModel = HomeScreenViewModel(userSession: userSession, let viewModel = HomeScreenViewModel(userSession: userSession,
attributedStringBuilder: AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL,
mentionBuilder: MentionBuilder()),
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(), selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(),
appSettings: ServiceLocator.shared.settings, appSettings: ServiceLocator.shared.settings,
analytics: ServiceLocator.shared.analytics,
userIndicatorController: ServiceLocator.shared.userIndicatorController) userIndicatorController: ServiceLocator.shared.userIndicatorController)
let rooms: [HomeScreenRoom] = summaryProvider.roomListPublisher.value.compactMap { summary -> HomeScreenRoom? in let rooms: [HomeScreenRoom] = summaryProvider.roomListPublisher.value.compactMap { summary -> HomeScreenRoom? in

View File

@ -72,14 +72,9 @@ struct HomeScreenSessionVerificationBanner_Previews: PreviewProvider, TestablePr
mediaProvider: MockMediaProvider(), mediaProvider: MockMediaProvider(),
voiceMessageMediaManager: VoiceMessageMediaManagerMock()) voiceMessageMediaManager: VoiceMessageMediaManagerMock())
let attributedStringBuilder = AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL,
mentionBuilder: MentionBuilder())
return HomeScreenViewModel(userSession: userSession, return HomeScreenViewModel(userSession: userSession,
attributedStringBuilder: attributedStringBuilder,
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(), selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(),
appSettings: ServiceLocator.shared.settings, appSettings: ServiceLocator.shared.settings,
analytics: ServiceLocator.shared.analytics,
userIndicatorController: ServiceLocator.shared.userIndicatorController) userIndicatorController: ServiceLocator.shared.userIndicatorController)
} }
} }

View File

@ -18,8 +18,6 @@ import Compound
import SwiftUI import SwiftUI
struct HomeScreenUserMenuButton: View { struct HomeScreenUserMenuButton: View {
@Environment(\.colorScheme) private var colorScheme
@ObservedObject var context: HomeScreenViewModel.Context @ObservedObject var context: HomeScreenViewModel.Context
var body: some View { var body: some View {

View File

@ -518,7 +518,7 @@ class RoomScreenInteractionHandler {
} }
} catch { } catch {
MXLog.error("Failed to load voice message: \(error)") MXLog.error("Failed to load voice message: \(error)")
audioPlayerState.reportError(error) audioPlayerState.reportError()
} }
return return

View File

@ -14,6 +14,7 @@
// limitations under the License. // limitations under the License.
// //
// periphery: ignore - markdown protocol
protocol TextBasedRoomTimelineViewProtocol { protocol TextBasedRoomTimelineViewProtocol {
associatedtype TimelineItemType: TextBasedRoomTimelineItem associatedtype TimelineItemType: TextBasedRoomTimelineItem

View File

@ -20,11 +20,9 @@ import SwiftUI
typealias AnalyticsSettingsScreenViewModelType = StateStoreViewModel<AnalyticsSettingsScreenViewState, AnalyticsSettingsScreenViewAction> typealias AnalyticsSettingsScreenViewModelType = StateStoreViewModel<AnalyticsSettingsScreenViewState, AnalyticsSettingsScreenViewAction>
class AnalyticsSettingsScreenViewModel: AnalyticsSettingsScreenViewModelType, AnalyticsSettingsScreenViewModelProtocol { class AnalyticsSettingsScreenViewModel: AnalyticsSettingsScreenViewModelType, AnalyticsSettingsScreenViewModelProtocol {
private let appSettings: AppSettings
private let analytics: AnalyticsService private let analytics: AnalyticsService
init(appSettings: AppSettings, analytics: AnalyticsService) { init(appSettings: AppSettings, analytics: AnalyticsService) {
self.appSettings = appSettings
self.analytics = analytics self.analytics = analytics
let strings = AnalyticsSettingsScreenStrings(termsURL: appSettings.analyticsConfiguration.termsURL) let strings = AnalyticsSettingsScreenStrings(termsURL: appSettings.analyticsConfiguration.termsURL)

View File

@ -14,6 +14,7 @@
// limitations under the License. // limitations under the License.
// //
// periphery:ignore:all - subscripts lead to false positives
import Foundation import Foundation
struct AdvancedSettingsScreenViewState: BindableState { struct AdvancedSettingsScreenViewState: BindableState {

View File

@ -24,6 +24,7 @@ struct DeveloperOptionsScreenViewState: BindableState {
var bindings: DeveloperOptionsScreenViewStateBindings var bindings: DeveloperOptionsScreenViewStateBindings
} }
// periphery: ignore - subscripts are seen as false positive
@dynamicMemberLookup @dynamicMemberLookup
struct DeveloperOptionsScreenViewStateBindings { struct DeveloperOptionsScreenViewStateBindings {
private let developerOptions: DeveloperOptionsProtocol private let developerOptions: DeveloperOptionsProtocol

View File

@ -31,9 +31,6 @@ protocol AnalyticsClientProtocol {
/// Stop the analytics client reporting data. /// Stop the analytics client reporting data.
func stop() func stop()
/// Send any queued events immediately.
func flush()
/// Capture the supplied analytics event. /// Capture the supplied analytics event.
/// - Parameter event: The event to capture. /// - Parameter event: The event to capture.
func capture(_ event: AnalyticsEventProtocol) func capture(_ event: AnalyticsEventProtocol)
@ -41,14 +38,6 @@ protocol AnalyticsClientProtocol {
/// Capture the supplied analytics screen event. /// Capture the supplied analytics screen event.
/// - Parameter event: The screen event to capture. /// - Parameter event: The screen event to capture.
func screen(_ event: AnalyticsScreenProtocol) func screen(_ event: AnalyticsScreenProtocol)
/// Updates any user properties to help with creating cohorts.
/// - Parameter userProperties: The user properties to be updated.
///
/// Only non-nil properties will be updated when calling this method. There might
/// be a delay when updating user properties as these are cached to be included
/// as part of the next event that gets captured.
func updateUserProperties(_ userProperties: AnalyticsEvent.UserProperties)
} }
// sourcery: AutoMockable // sourcery: AutoMockable

View File

@ -105,13 +105,6 @@ class AnalyticsService {
appSettings.analyticsConsentState = .unknown appSettings.analyticsConsentState = .unknown
} }
/// Flushes the event queue in the analytics client, uploading all pending events.
/// Normally events are sent in batches. Call this method when you need an event
/// to be sent immediately.
func forceUpload() {
client.flush()
}
// MARK: - Private // MARK: - Private
/// Capture an event in the `client`. /// Capture an event in the `client`.

View File

@ -24,10 +24,6 @@ protocol AudioSessionProtocol: AnyObject {
} }
extension AudioSessionProtocol { extension AudioSessionProtocol {
func setCategory(_ category: AVAudioSession.Category, mode: AVAudioSession.Mode) throws {
try setCategory(category, mode: mode, options: [])
}
func setActive(_ active: Bool) throws { func setActive(_ active: Bool) throws {
try setActive(active, options: []) try setActive(active, options: [])
} }

View File

@ -46,12 +46,13 @@ class AudioPlayer: NSObject, AudioPlayerProtocol {
private var statusObserver: NSKeyValueObservation? private var statusObserver: NSKeyValueObservation?
private var rateObserver: NSKeyValueObservation? private var rateObserver: NSKeyValueObservation?
private var playToEndObserver: NSObjectProtocol?
private var appBackgroundObserver: NSObjectProtocol?
private var autoplay = false private var autoplay = false
private let audioSession = AVAudioSession.sharedInstance() private let audioSession = AVAudioSession.sharedInstance()
// periphery:ignore - when set to nil is automatically cancelled
@CancellableTask private var releaseAudioSessionTask: Task<Void, Never>? @CancellableTask private var releaseAudioSessionTask: Task<Void, Never>?
private let releaseAudioSessionTimeoutInterval = 5.0 private let releaseAudioSessionTimeoutInterval = 5.0
private(set) var url: URL? private(set) var url: URL?

View File

@ -19,7 +19,6 @@ import Foundation
enum AudioPlayerError: Error { enum AudioPlayerError: Error {
case genericError case genericError
case loadFileError
} }
enum AudioPlayerAction { enum AudioPlayerAction {

View File

@ -110,7 +110,7 @@ class AudioPlayerState: ObservableObject, Identifiable {
playbackState = .stopped playbackState = .stopped
} }
func reportError(_ error: Error) { func reportError() {
playbackState = .error playbackState = .error
} }
@ -167,6 +167,7 @@ class AudioPlayerState: ObservableObject, Identifiable {
displayLink?.add(to: .current, forMode: .common) displayLink?.add(to: .current, forMode: .common)
} }
// periphery:ignore:parameters displayLink - required for objc selector
@objc private func updateProgress(displayLink: CADisplayLink) { @objc private func updateProgress(displayLink: CADisplayLink) {
if let currentTime = audioPlayer?.currentTime, duration > 0 { if let currentTime = audioPlayer?.currentTime, duration > 0 {
progress = currentTime / duration progress = currentTime / duration

View File

@ -343,9 +343,9 @@ class AudioRecorder: AudioRecorderProtocol {
.store(in: &cancellables) .store(in: &cancellables)
NotificationCenter.default.publisher(for: Notification.Name.AVAudioEngineConfigurationChange) NotificationCenter.default.publisher(for: Notification.Name.AVAudioEngineConfigurationChange)
.sink { [weak self] notification in .sink { [weak self] _ in
guard let self else { return } guard let self else { return }
self.handleConfigurationChange(notification: notification) self.handleConfigurationChange()
} }
.store(in: &cancellables) .store(in: &cancellables)
@ -396,7 +396,7 @@ class AudioRecorder: AudioRecorderProtocol {
} }
} }
func handleConfigurationChange(notification: Notification) { func handleConfigurationChange() {
guard let audioEngine else { return } guard let audioEngine else { return }
MXLog.warning("Configuration changed: \(audioEngine.inputNode.inputFormat(forBus: 0))") MXLog.warning("Configuration changed: \(audioEngine.inputNode.inputFormat(forBus: 0))")
if internalState != .suspended { if internalState != .suspended {

View File

@ -24,7 +24,6 @@ enum AudioRecorderError: Error, Equatable {
case audioFileCreationFailure case audioFileCreationFailure
case interrupted case interrupted
case recordingCancelled case recordingCancelled
case recordingFailed
case recordPermissionNotGranted case recordPermissionNotGranted
} }

View File

@ -57,7 +57,7 @@ class AudioRecorderState: ObservableObject, Identifiable {
recordingState = .stopped recordingState = .stopped
} }
func reportError(_ error: Error) { func reportError() {
recordingState = .error recordingState = .error
} }
@ -98,6 +98,7 @@ class AudioRecorderState: ObservableObject, Identifiable {
displayLink?.add(to: .current, forMode: .common) displayLink?.add(to: .current, forMode: .common)
} }
// periphery:ignore:parameters displayLink - required for objc selector
@objc private func publishUpdate(displayLink: CADisplayLink) { @objc private func publishUpdate(displayLink: CADisplayLink) {
if let currentTime = audioRecorder?.currentTime { if let currentTime = audioRecorder?.currentTime {
duration = currentTime duration = currentTime

View File

@ -19,8 +19,6 @@ import UIKit
// sourcery: AutoMockable // sourcery: AutoMockable
protocol ApplicationProtocol { protocol ApplicationProtocol {
func beginBackgroundTask(expirationHandler handler: (() -> Void)?) -> UIBackgroundTaskIdentifier
func beginBackgroundTask(withName taskName: String?, expirationHandler handler: (() -> Void)?) -> UIBackgroundTaskIdentifier func beginBackgroundTask(withName taskName: String?, expirationHandler handler: (() -> Void)?) -> UIBackgroundTaskIdentifier
func endBackgroundTask(_ identifier: UIBackgroundTaskIdentifier) func endBackgroundTask(_ identifier: UIBackgroundTaskIdentifier)

View File

@ -29,12 +29,6 @@ protocol BackgroundTaskProtocol: AnyObject {
/// Flag indicating the background task is reusable. If reusable, `name` is the key to distinguish background tasks. /// Flag indicating the background task is reusable. If reusable, `name` is the key to distinguish background tasks.
var isReusable: Bool { get } var isReusable: Bool { get }
/// Elapsed time after the task started. In milliseconds.
var elapsedTime: TimeInterval { get }
/// Expiration handler for the background task
var expirationHandler: BackgroundTaskExpirationHandler? { get }
/// Method to be called when a task reused one more time. Should only be valid for reusable tasks. /// Method to be called when a task reused one more time. Should only be valid for reusable tasks.
func reuse() func reuse()

View File

@ -116,10 +116,6 @@ class BugReportService: NSObject, BugReportServiceProtocol {
MXLog.info("Reset.") MXLog.info("Reset.")
} }
func crash() {
SentrySDK.crash()
}
func submitBugReport(_ bugReport: BugReport, func submitBugReport(_ bugReport: BugReport,
progressListener: CurrentValueSubject<Double, Never>) async -> Result<SubmitBugReportResponse, BugReportServiceError> { progressListener: CurrentValueSubject<Double, Never>) async -> Result<SubmitBugReportResponse, BugReportServiceError> {
var params = [ var params = [

View File

@ -52,6 +52,7 @@ enum BugReportServiceError: LocalizedError {
// sourcery: AutoMockable // sourcery: AutoMockable
protocol BugReportServiceProtocol { protocol BugReportServiceProtocol {
// periphery: ignore
var isRunning: Bool { get } var isRunning: Bool { get }
var crashedLastRun: Bool { get } var crashedLastRun: Bool { get }
@ -62,8 +63,6 @@ protocol BugReportServiceProtocol {
func reset() func reset()
func crash()
func submitBugReport(_ bugReport: BugReport, func submitBugReport(_ bugReport: BugReport,
progressListener: CurrentValueSubject<Double, Never>) async -> Result<SubmitBugReportResponse, BugReportServiceError> progressListener: CurrentValueSubject<Double, Never>) async -> Result<SubmitBugReportResponse, BugReportServiceError>
} }

View File

@ -25,15 +25,17 @@ class ClientProxy: ClientProxyProtocol {
private let appSettings: AppSettings private let appSettings: AppSettings
private let networkMonitor: NetworkMonitorProtocol private let networkMonitor: NetworkMonitorProtocol
private var sessionVerificationControllerProxy: SessionVerificationControllerProxy?
private let mediaLoader: MediaLoaderProtocol private let mediaLoader: MediaLoaderProtocol
private let clientQueue: DispatchQueue private let clientQueue: DispatchQueue
private var roomListService: RoomListService? private var roomListService: RoomListService?
// periphery: ignore - only for retain
private var roomListStateUpdateTaskHandle: TaskHandle? private var roomListStateUpdateTaskHandle: TaskHandle?
// periphery: ignore - only for retain
private var roomListStateLoadingStateUpdateTaskHandle: TaskHandle? private var roomListStateLoadingStateUpdateTaskHandle: TaskHandle?
private var syncService: SyncService? private var syncService: SyncService?
// periphery: ignore - only for retain
private var syncServiceStateUpdateTaskHandle: TaskHandle? private var syncServiceStateUpdateTaskHandle: TaskHandle?
private var delegateHandle: TaskHandle? private var delegateHandle: TaskHandle?
@ -49,8 +51,6 @@ class ClientProxy: ClientProxyProtocol {
let secureBackupController: SecureBackupControllerProtocol let secureBackupController: SecureBackupControllerProtocol
private let roomListRecencyOrderingAllowedEventTypes = ["m.room.message", "m.room.encrypted", "m.sticker"]
private static var roomCreationPowerLevelOverrides: PowerLevels { private static var roomCreationPowerLevelOverrides: PowerLevels {
.init(usersDefault: nil, .init(usersDefault: nil,
eventsDefault: nil, eventsDefault: nil,
@ -79,7 +79,6 @@ class ClientProxy: ClientProxyProtocol {
} }
private var cancellables = Set<AnyCancellable>() private var cancellables = Set<AnyCancellable>()
private var visibleRoomsListProxyStateObservationToken: AnyCancellable?
/// Will be `true` whilst the app cleans up and forces a logout. Prevents the sync service from restarting /// Will be `true` whilst the app cleans up and forces a logout. Prevents the sync service from restarting
/// before the client is released which ends up running in a loop. This is a workaround until the sync service /// before the client is released which ends up running in a loop. This is a workaround until the sync service
@ -413,18 +412,6 @@ class ClientProxy: ClientProxyProtocol {
} }
} }
func accountDataEvent<Content>(type: String) async -> Result<Content?, ClientProxyError> where Content: Decodable {
await Task.dispatch(on: clientQueue) {
.failure(.failedRetrievingAccountData)
}
}
func setAccountData<Content: Encodable>(content: Content, type: String) async -> Result<Void, ClientProxyError> {
await Task.dispatch(on: clientQueue) {
.failure(.failedSettingAccountData)
}
}
func sessionVerificationControllerProxy() async -> Result<SessionVerificationControllerProxyProtocol, ClientProxyError> { func sessionVerificationControllerProxy() async -> Result<SessionVerificationControllerProxyProtocol, ClientProxyError> {
await Task.dispatch(on: clientQueue) { await Task.dispatch(on: clientQueue) {
do { do {

View File

@ -42,8 +42,6 @@ enum ClientProxyError: Error {
case failedRetrievingUserDisplayName case failedRetrievingUserDisplayName
case failedRetrievingUserAvatarURL case failedRetrievingUserAvatarURL
case failedSettingUserDisplayName case failedSettingUserDisplayName
case failedRetrievingAccountData
case failedSettingAccountData
case failedRetrievingSessionVerificationController case failedRetrievingSessionVerificationController
case failedLoadingMedia case failedLoadingMedia
case mediaFileError case mediaFileError
@ -123,10 +121,6 @@ protocol ClientProxyProtocol: AnyObject, MediaLoaderProtocol {
func removeUserAvatar() async -> Result<Void, ClientProxyError> func removeUserAvatar() async -> Result<Void, ClientProxyError>
func accountDataEvent<Content: Decodable>(type: String) async -> Result<Content?, ClientProxyError>
func setAccountData<Content: Encodable>(content: Content, type: String) async -> Result<Void, ClientProxyError>
func sessionVerificationControllerProxy() async -> Result<SessionVerificationControllerProxyProtocol, ClientProxyError> func sessionVerificationControllerProxy() async -> Result<SessionVerificationControllerProxyProtocol, ClientProxyError>
func logout() async -> URL? func logout() async -> URL?

View File

@ -117,14 +117,6 @@ class MockClientProxy: ClientProxyProtocol {
.failure(.failedSettingUserAvatar) .failure(.failedSettingUserAvatar)
} }
func accountDataEvent<Content>(type: String) async -> Result<Content?, ClientProxyError> where Content: Decodable {
.failure(.failedRetrievingAccountData)
}
func setAccountData<Content>(content: Content, type: String) async -> Result<Void, ClientProxyError> where Content: Encodable {
.failure(.failedSettingAccountData)
}
func loadMediaContentForSource(_ source: MediaSourceProxy) async throws -> Data { func loadMediaContentForSource(_ source: MediaSourceProxy) async throws -> Data {
throw ClientProxyError.failedLoadingMedia throw ClientProxyError.failedLoadingMedia
} }

View File

@ -28,7 +28,6 @@ enum ElementCallWidgetDriverError: Error {
enum ElementCallWidgetDriverAction { enum ElementCallWidgetDriverAction {
case callEnded case callEnded
case errorReceived(ElementCallWidgetDriverError)
} }
// sourcery: AutoMockable // sourcery: AutoMockable

View File

@ -25,5 +25,4 @@ struct EmojiItem: Equatable, Identifiable {
let unicode: String let unicode: String
let keywords: [String] let keywords: [String]
let shortcodes: [String] let shortcodes: [String]
let skins: [String]
} }

View File

@ -97,6 +97,5 @@ extension EmojiItem {
label = emojibase.label label = emojibase.label
shortcodes = emojibase.shortcodes shortcodes = emojibase.shortcodes
keywords = emojibase.tags ?? [] keywords = emojibase.tags ?? []
skins = emojibase.skins?.map(\.unicode) ?? []
} }
} }

View File

@ -226,7 +226,7 @@ extension NotificationManager: UNUserNotificationCenterDelegate {
return [.badge, .sound, .list, .banner] return [.badge, .sound, .list, .banner]
} }
guard delegate.shouldDisplayInAppNotification(self, content: notification.request.content) else { guard delegate.shouldDisplayInAppNotification(content: notification.request.content) else {
return [] return []
} }
@ -245,8 +245,7 @@ extension NotificationManager: UNUserNotificationCenterDelegate {
content: response.notification.request.content, content: response.notification.request.content,
replyText: response.userText) replyText: response.userText)
case UNNotificationDefaultActionIdentifier: case UNNotificationDefaultActionIdentifier:
await delegate?.notificationTapped(self, await delegate?.notificationTapped(content: response.notification.request.content)
content: response.notification.request.content)
default: default:
break break
} }

View File

@ -18,10 +18,8 @@ import Foundation
import UserNotifications import UserNotifications
protocol NotificationManagerDelegate: AnyObject { protocol NotificationManagerDelegate: AnyObject {
func shouldDisplayInAppNotification(_ service: NotificationManagerProtocol, func shouldDisplayInAppNotification(content: UNNotificationContent) -> Bool
content: UNNotificationContent) -> Bool func notificationTapped(content: UNNotificationContent) async
func notificationTapped(_ service: NotificationManagerProtocol,
content: UNNotificationContent) async
func handleInlineReply(_ service: NotificationManagerProtocol, func handleInlineReply(_ service: NotificationManagerProtocol,
content: UNNotificationContent, content: UNNotificationContent,
replyText: String) async replyText: String) async

View File

@ -16,4 +16,5 @@
import Foundation import Foundation
// periphery: ignore - markdown protocol
protocol DecorationTimelineItemProtocol: RoomTimelineItemProtocol { } protocol DecorationTimelineItemProtocol: RoomTimelineItemProtocol { }

View File

@ -38,13 +38,4 @@ class CreateRoomScreenUITests: XCTestCase {
app.textFields[A11yIdentifiers.createRoomScreen.roomName].typeText("\n") app.textFields[A11yIdentifiers.createRoomScreen.roomName].typeText("\n")
try await app.assertScreenshot(.createRoom, step: 1) try await app.assertScreenshot(.createRoom, step: 1)
} }
// Disabled because tapping on the textView doesn't work
func disabled_testLongInputTopicText() async throws {
let app = Application.launch(.createRoom)
let textView = app.textViews[A11yIdentifiers.createRoomScreen.roomTopic]
textView.tap()
textView.typeText(.init(repeating: "Topic\n", count: 3))
try await app.assertScreenshot(.createRoom, step: 2)
}
} }

View File

@ -624,7 +624,7 @@ class AttributedStringBuilderTests: XCTestCase {
XCTFail("Couldn't find expected value.") XCTFail("Couldn't find expected value.")
} }
private func checkAttachment(attributedString: AttributedString?, expectedRuns: Int, expectedAttachments: Int = 1) { private func checkAttachment(attributedString: AttributedString?, expectedRuns: Int) {
guard let attributedString else { guard let attributedString else {
XCTFail("Could not build the attributed string") XCTFail("Could not build the attributed string")
return return

View File

@ -31,9 +31,6 @@ class AudioPlayerStateTests: XCTestCase {
} }
private var audioPlayerSeekCallsSubject: PassthroughSubject<Double, Never>! private var audioPlayerSeekCallsSubject: PassthroughSubject<Double, Never>!
private var audioPlayerSeekCalls: AnyPublisher<Double, Never> {
audioPlayerSeekCallsSubject.eraseToAnyPublisher()
}
private func buildAudioPlayerMock() -> AudioPlayerMock { private func buildAudioPlayerMock() -> AudioPlayerMock {
let audioPlayerMock = AudioPlayerMock() let audioPlayerMock = AudioPlayerMock()
@ -115,7 +112,7 @@ class AudioPlayerStateTests: XCTestCase {
func testReportError() async throws { func testReportError() async throws {
XCTAssertEqual(audioPlayerState.playbackState, .stopped) XCTAssertEqual(audioPlayerState.playbackState, .stopped)
audioPlayerState.reportError(AudioPlayerError.genericError) audioPlayerState.reportError()
XCTAssertEqual(audioPlayerState.playbackState, .error) XCTAssertEqual(audioPlayerState.playbackState, .error)
} }

View File

@ -59,7 +59,7 @@ class AudioRecorderStateTests: XCTestCase {
func testReportError() async throws { func testReportError() async throws {
XCTAssertEqual(audioRecorderState.recordingState, .stopped) XCTAssertEqual(audioRecorderState.recordingState, .stopped)
audioRecorderState.reportError(AudioRecorderError.audioEngineFailure) audioRecorderState.reportError()
XCTAssertEqual(audioRecorderState.recordingState, .error) XCTAssertEqual(audioRecorderState.recordingState, .error)
} }

View File

@ -21,12 +21,13 @@ import Foundation
import XCTest import XCTest
class BugReportServiceTests: XCTestCase { class BugReportServiceTests: XCTestCase {
var bugReportService: BugReportServiceMock! var bugReportService: BugReportServiceProtocol!
override func setUpWithError() throws { override func setUpWithError() throws {
bugReportService = BugReportServiceMock() let bugReportServiceMock = BugReportServiceMock()
bugReportService.underlyingCrashedLastRun = false bugReportServiceMock.underlyingCrashedLastRun = false
bugReportService.submitBugReportProgressListenerReturnValue = .success(SubmitBugReportResponse(reportUrl: "https://www.example.com/123")) bugReportServiceMock.submitBugReportProgressListenerReturnValue = .success(SubmitBugReportResponse(reportUrl: "https://www.example.com/123"))
bugReportService = bugReportServiceMock
} }
func testInitialStateWithMockService() { func testInitialStateWithMockService() {

View File

@ -21,7 +21,7 @@ import XCTest
@MainActor @MainActor
final class EmojiProviderTests: XCTestCase { final class EmojiProviderTests: XCTestCase {
func testWhenEmojisLoadedCategoriesAreLoadedFromLoader() async throws { func testWhenEmojisLoadedCategoriesAreLoadedFromLoader() async throws {
let item = EmojiItem(label: "test", unicode: "test", keywords: ["1", "2"], shortcodes: ["1", "2"], skins: ["🙂"]) let item = EmojiItem(label: "test", unicode: "test", keywords: ["1", "2"], shortcodes: ["1", "2"])
let category = EmojiCategory(id: "test", emojis: [item]) let category = EmojiCategory(id: "test", emojis: [item])
let emojiLoaderMock = EmojiLoaderMock() let emojiLoaderMock = EmojiLoaderMock()
@ -34,7 +34,7 @@ final class EmojiProviderTests: XCTestCase {
} }
func testWhenEmojisLoadedAndSearchStringEmptyAllCategoriesReturned() async throws { func testWhenEmojisLoadedAndSearchStringEmptyAllCategoriesReturned() async throws {
let item = EmojiItem(label: "test", unicode: "test", keywords: ["1", "2"], shortcodes: ["1", "2"], skins: ["🙂"]) let item = EmojiItem(label: "test", unicode: "test", keywords: ["1", "2"], shortcodes: ["1", "2"])
let category = EmojiCategory(id: "test", emojis: [item]) let category = EmojiCategory(id: "test", emojis: [item])
let emojiLoaderMock = EmojiLoaderMock() let emojiLoaderMock = EmojiLoaderMock()
@ -47,8 +47,8 @@ final class EmojiProviderTests: XCTestCase {
} }
func testWhenEmojisLoadedSecondTimeCachedValuesAreUsed() async throws { func testWhenEmojisLoadedSecondTimeCachedValuesAreUsed() async throws {
let item = EmojiItem(label: "test", unicode: "test", keywords: ["1", "2"], shortcodes: ["1", "2"], skins: ["🙂"]) let item = EmojiItem(label: "test", unicode: "test", keywords: ["1", "2"], shortcodes: ["1", "2"])
let item2 = EmojiItem(label: "test2", unicode: "test2", keywords: ["3", "4"], shortcodes: ["3", "4"], skins: ["🙂"]) let item2 = EmojiItem(label: "test2", unicode: "test2", keywords: ["3", "4"], shortcodes: ["3", "4"])
let categoriesForFirstLoad = [EmojiCategory(id: "test", let categoriesForFirstLoad = [EmojiCategory(id: "test",
emojis: [item])] emojis: [item])]
let categoriesForSecondLoad = [EmojiCategory(id: "test2", let categoriesForSecondLoad = [EmojiCategory(id: "test2",
@ -69,12 +69,12 @@ final class EmojiProviderTests: XCTestCase {
func testWhenEmojisSearchedCorrectNumberOfCategoriesReturned() async throws { func testWhenEmojisSearchedCorrectNumberOfCategoriesReturned() async throws {
let searchString = "smile" let searchString = "smile"
var categories = [EmojiCategory]() var categories = [EmojiCategory]()
let item0WithSearchString = EmojiItem(label: "emoji0", unicode: "\(searchString)_123", keywords: ["key1", "key1"], shortcodes: ["key1", "key1"], skins: ["🙂"]) let item0WithSearchString = EmojiItem(label: "emoji0", unicode: "\(searchString)_123", keywords: ["key1", "key1"], shortcodes: ["key1", "key1"])
let item1WithSearchString = EmojiItem(label: searchString, unicode: "emoji1", keywords: ["key1", "key1"], shortcodes: ["key1", "key1"], skins: ["🙂"]) let item1WithSearchString = EmojiItem(label: searchString, unicode: "emoji1", keywords: ["key1", "key1"], shortcodes: ["key1", "key1"])
let item2WithSearchString = EmojiItem(label: "emoji_2", unicode: "emoji_2", keywords: ["key1", "\(searchString)_123"], shortcodes: ["key1", "key2"], skins: ["🙂"]) let item2WithSearchString = EmojiItem(label: "emoji_2", unicode: "emoji_2", keywords: ["key1", "\(searchString)_123"], shortcodes: ["key1", "key2"])
let item3WithSearchString = EmojiItem(label: "emoji_2", unicode: "emoji_2", keywords: ["key1", "key1"], shortcodes: ["key1", "\(searchString)_123"], skins: ["🙂"]) let item3WithSearchString = EmojiItem(label: "emoji_2", unicode: "emoji_2", keywords: ["key1", "key1"], shortcodes: ["key1", "\(searchString)_123"])
let item4WithoutSearchString = EmojiItem(label: "emoji_3", unicode: "emoji_3", keywords: ["key1", "key1"], shortcodes: ["key1", "key1"], skins: ["🙂"]) let item4WithoutSearchString = EmojiItem(label: "emoji_3", unicode: "emoji_3", keywords: ["key1", "key1"], shortcodes: ["key1", "key1"])
let item5WithSearchString = EmojiItem(label: "emoji0", unicode: "\(searchString)_123", keywords: ["key1", "key1"], shortcodes: ["key1", "key1"], skins: ["🙂"]) let item5WithSearchString = EmojiItem(label: "emoji0", unicode: "\(searchString)_123", keywords: ["key1", "key1"], shortcodes: ["key1", "key1"])
categories.append(EmojiCategory(id: "test", categories.append(EmojiCategory(id: "test",
emojis: [item0WithSearchString, emojis: [item0WithSearchString,
item1WithSearchString, item1WithSearchString,

View File

@ -32,10 +32,8 @@ class HomeScreenViewModelTests: XCTestCase {
viewModel = HomeScreenViewModel(userSession: MockUserSession(clientProxy: clientProxy, viewModel = HomeScreenViewModel(userSession: MockUserSession(clientProxy: clientProxy,
mediaProvider: MockMediaProvider(), mediaProvider: MockMediaProvider(),
voiceMessageMediaManager: VoiceMessageMediaManagerMock()), voiceMessageMediaManager: VoiceMessageMediaManagerMock()),
attributedStringBuilder: AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL, mentionBuilder: MentionBuilder()),
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(), selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(),
appSettings: ServiceLocator.shared.settings, appSettings: ServiceLocator.shared.settings,
analytics: ServiceLocator.shared.analytics,
userIndicatorController: ServiceLocator.shared.userIndicatorController) userIndicatorController: ServiceLocator.shared.userIndicatorController)
} }

View File

@ -246,11 +246,11 @@ extension NotificationManagerTests: NotificationManagerDelegate {
authorizationStatusWasGranted = false authorizationStatusWasGranted = false
} }
func shouldDisplayInAppNotification(_ service: ElementX.NotificationManagerProtocol, content: UNNotificationContent) -> Bool { func shouldDisplayInAppNotification(content: UNNotificationContent) -> Bool {
shouldDisplayInAppNotificationReturnValue shouldDisplayInAppNotificationReturnValue
} }
func notificationTapped(_ service: ElementX.NotificationManagerProtocol, content: UNNotificationContent) async { func notificationTapped(content: UNNotificationContent) async {
notificationTappedDelegateCalled = true notificationTappedDelegateCalled = true
} }