Update files following swiftformat upgrade

This commit is contained in:
Stefan Ceriu
2026-01-27 08:47:03 +02:00
committed by Stefan Ceriu
parent 2bb26efbe1
commit 04053ae69b
343 changed files with 1502 additions and 1048 deletions

View File

@@ -11,7 +11,7 @@ SwiftLint.lint(.modifiedAndCreatedFiles(directory: nil),
let danger = Danger()
// All of the new and modified files together.
/// All of the new and modified files together.
let editedFiles = danger.git.modifiedFiles + danger.git.createdFiles
// Warn when there is a big PR
@@ -24,7 +24,7 @@ if danger.github.pullRequest.body?.isEmpty ?? true {
warn("Please provide a description for this PR.")
}
// Check for screenshots on view changes
/// Check for screenshots on view changes
let hasChangedViews = !editedFiles.filter { $0.lowercased().contains("/view") }.isEmpty
if hasChangedViews {
if (danger.github.pullRequest.body?.contains("user-attachments") ?? false) == false {
@@ -32,7 +32,7 @@ if hasChangedViews {
}
}
// Check for pngs on resources
/// Check for pngs on resources
let hasPngs = !editedFiles.filter { $0.lowercased().contains(".xcassets") && $0.lowercased().hasSuffix(".png") }.isEmpty
if hasPngs {
warn("You seem to have made changes to some resource images. Please consider using an SVG or PDF.")

View File

@@ -118,7 +118,9 @@ struct PreviewsWrapperView: View {
private let name: String
private let previews: [_Preview]
private(set) var currentIndex = -1
var currentPreview: _Preview { previews[currentIndex] }
var currentPreview: _Preview {
previews[currentIndex]
}
private(set) var isDone = false

View File

@@ -13,5 +13,7 @@ protocol AppSettingsHookProtocol {
}
struct DefaultAppSettingsHook: AppSettingsHookProtocol {
func configure(_ appSettings: AppSettings) -> AppSettings { appSettings }
func configure(_ appSettings: AppSettings) -> AppSettings {
appSettings
}
}

View File

@@ -13,5 +13,7 @@ protocol BugReportHookProtocol {
}
struct DefaultBugReportHook: BugReportHookProtocol {
func update(_ bugReport: BugReport) -> BugReport { bugReport }
func update(_ bugReport: BugReport) -> BugReport {
bugReport
}
}

View File

@@ -13,5 +13,7 @@ protocol ClientBuilderHookProtocol {
}
struct DefaultClientBuilderHook: ClientBuilderHookProtocol {
func configure(_ builder: ClientBuilder) -> ClientBuilder { builder }
func configure(_ builder: ClientBuilder) -> ClientBuilder {
builder
}
}

View File

@@ -12,5 +12,7 @@ protocol DeveloperOptionsScreenHookProtocol {
}
struct DefaultDeveloperOptionsScreenHook: DeveloperOptionsScreenHookProtocol {
func generalSectionRows() -> AnyView? { nil }
func generalSectionRows() -> AnyView? {
nil
}
}

View File

@@ -15,5 +15,7 @@ protocol RoomScreenHookProtocol {
struct DefaultRoomScreenHook: RoomScreenHookProtocol {
func configure(with userSession: UserSessionProtocol?) async { }
func update(_ viewState: RoomScreenViewState) -> RoomScreenViewState { viewState }
func update(_ viewState: RoomScreenViewState) -> RoomScreenViewState {
viewState
}
}

View File

@@ -198,18 +198,16 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
}
func toPresentable() -> AnyView {
AnyView(
navigationRootCoordinator.toPresentable()
.environment(\.analyticsService, ServiceLocator.shared.analytics)
.onReceive(appSettings.$appAppearance) { [weak self] appAppearance in
guard let self else { return }
AnyView(navigationRootCoordinator.toPresentable()
.environment(\.analyticsService, ServiceLocator.shared.analytics)
.onReceive(appSettings.$appAppearance) { [weak self] appAppearance in
guard let self else { return }
windowManager.windows.forEach { window in
// Unfortunately .preferredColorScheme doesn't propagate properly throughout the app when changed
window.overrideUserInterfaceStyle = appAppearance.interfaceStyle
}
windowManager.windows.forEach { window in
// Unfortunately .preferredColorScheme doesn't propagate properly throughout the app when changed
window.overrideUserInterfaceStyle = appAppearance.interfaceStyle
}
)
})
}
func handlePotentialPhishingAttempt(url: URL, openURLAction: @escaping (URL) -> Void) -> Bool {
@@ -450,7 +448,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
userSessionMigrationsOldVersion = nil
}
// This could be removed once the adoption of 25.06.x is widespread.
/// This could be removed once the adoption of 25.06.x is widespread.
private func performSettingsToAccountDataMigration(userSession: UserSessionProtocol) {
guard let userDefaults = UserDefaults(suiteName: InfoPlistReader.main.appGroupIdentifier) else {
return
@@ -1200,12 +1198,12 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
// This is important for the app to keep refreshing in the background
scheduleBackgroundAppRefresh()
/// We have a lot of crashes stemming here which we previously believed are caused by stopSync not being async
/// on the client proxy side (see the comment on that method). We have now realised that will likely not fix anything but
/// we also noticed this does not crash on the main thread, even though the whole AppCoordinator is on the Main actor.
/// As such, we introduced a MainActor conformance on the expirationHandler but we are also assuming main actor
/// isolated in the `stopSync` method above.
/// https://sentry.tools.element.io/organizations/element/issues/4477794/
// We have a lot of crashes stemming here which we previously believed are caused by stopSync not being async
// on the client proxy side (see the comment on that method). We have now realised that will likely not fix anything but
// we also noticed this does not crash on the main thread, even though the whole AppCoordinator is on the Main actor.
// As such, we introduced a MainActor conformance on the expirationHandler but we are also assuming main actor
// isolated in the `stopSync` method above.
// https://sentry.tools.element.io/organizations/element/issues/4477794/
task.expirationHandler = { @Sendable [weak self] in
MXLog.info("Background app refresh task is about to expire.")

View File

@@ -18,7 +18,7 @@ class AppMediator: AppMediatorProtocol {
self.networkMonitor = networkMonitor
}
// UIApplication.State won't update if we store this e.g. in the constructor
/// UIApplication.State won't update if we store this e.g. in the constructor
private var application: UIApplication {
UIApplication.shared
}

View File

@@ -41,6 +41,11 @@ struct CommonFlowParameters {
let notificationManager: NotificationManagerProtocol
let stateMachineFactory: StateMachineFactoryProtocol
var windowManager: WindowManagerProtocol { appMediator.windowManager }
var ongoingCallRoomIDPublisher: CurrentValuePublisher<String?, Never> { elementCallService.ongoingCallRoomIDPublisher }
var windowManager: WindowManagerProtocol {
appMediator.windowManager
}
var ongoingCallRoomIDPublisher: CurrentValuePublisher<String?, Never> {
elementCallService.ongoingCallRoomIDPublisher
}
}

View File

@@ -57,8 +57,13 @@ import SwiftUI
let module: NavigationModule
let details: TabDetails
var id: ObjectIdentifier { module.id }
@MainActor var coordinator: CoordinatorProtocol? { module.coordinator }
var id: ObjectIdentifier {
module.id
}
@MainActor var coordinator: CoordinatorProtocol? {
module.coordinator
}
}
fileprivate var tabModules = [TabModule]() {

View File

@@ -13,7 +13,7 @@ import EmbeddedElementCall
import Foundation
import SwiftUI
// Common settings between app and NSE
/// Common settings between app and NSE
protocol CommonSettingsProtocol {
var logLevel: LogLevel { get }
var traceLogPacks: Set<TraceLogPack> { get }
@@ -265,7 +265,9 @@ final class AppSettings {
}
private(set) var pushGatewayBaseURL: URL = "https://matrix.org"
var pushGatewayNotifyEndpoint: URL { pushGatewayBaseURL.appending(path: "_matrix/push/v1/notify") }
var pushGatewayNotifyEndpoint: URL {
pushGatewayBaseURL.appending(path: "_matrix/push/v1/notify")
}
@UserPreference(key: UserDefaultsKeys.enableNotifications, defaultValue: true, storageType: .userDefaults(store))
var enableNotifications
@@ -305,7 +307,9 @@ final class AppSettings {
/// The URL to open with more information about analytics terms. When this is `nil` the "Learn more" link will be hidden.
private(set) var analyticsTermsURL: URL? = "https://element.io/cookie-policy"
/// Whether or not there the app is able ask for user consent to enable analytics or sentry reporting.
var canPromptForAnalytics: Bool { analyticsConfiguration != nil || bugReportSentryURL != nil }
var canPromptForAnalytics: Bool {
analyticsConfiguration != nil || bugReportSentryURL != nil
}
private static func makeAnalyticsConfiguration() -> AnalyticsConfiguration? {
guard let host = Secrets.postHogHost, let apiKey = Secrets.postHogAPIKey else { return nil }
@@ -364,7 +368,7 @@ final class AppSettings {
// MARK: - Maps
// maptiler base url
/// maptiler base url
private(set) var mapTilerConfiguration = MapTilerConfiguration(baseURL: "https://api.maptiler.com/maps",
apiKey: Secrets.mapLibreAPIKey,
lightStyleID: "9bc819c8-e627-474a-a348-ec144fe3d810",
@@ -377,14 +381,14 @@ final class AppSettings {
// MARK: - Feature Flags
// Spaces
/// Spaces
@UserPreference(key: UserDefaultsKeys.spaceSettingsEnabled, defaultValue: false, storageType: .userDefaults(store))
var spaceSettingsEnabled
@UserPreference(key: UserDefaultsKeys.createSpaceEnabled, defaultValue: false, storageType: .userDefaults(store))
var createSpaceEnabled
// Others
/// Others
@UserPreference(key: UserDefaultsKeys.publicSearchEnabled, defaultValue: false, storageType: .userDefaults(store))
var publicSearchEnabled

View File

@@ -22,5 +22,7 @@ struct MapTilerConfiguration {
/// A MapLibre style ID for a dark-mode map.
let darkStyleID: String
var isEnabled: Bool { apiKey != nil }
var isEnabled: Bool {
apiKey != nil
}
}

View File

@@ -16,8 +16,13 @@ import Combine
class RemotePreference<T: Equatable> {
private let defaultValue: T
private let subject: CurrentValueSubject<T, Never>
var publisher: CurrentValuePublisher<T, Never> { subject.asCurrentValuePublisher() }
var isRemotelyConfigured: Bool { subject.value != defaultValue }
var publisher: CurrentValuePublisher<T, Never> {
subject.asCurrentValuePublisher()
}
var isRemotelyConfigured: Bool {
subject.value != defaultValue
}
init(_ defaultValue: T) {
self.defaultValue = defaultValue

View File

@@ -24,14 +24,17 @@ final class UserPreference<T: Codable> {
}
private let key: String
private var remoteKey: String { "\(Self.remotePrefix)\(key)" }
private var remoteKey: String {
"\(Self.remotePrefix)\(key)"
}
private var keyedStorage: any KeyedStorage<T>
private let defaultValue: T
private let subject: PassthroughSubject<T, Never> = .init()
private let mode: Mode
// This can be used to check if is still possible for the user to change the value or not
// Can only be accessed by using `_preferenceName.isLockedToRemote`
/// This can be used to check if is still possible for the user to change the value or not
/// Can only be accessed by using `_preferenceName.isLockedToRemote`
var isLockedToRemote: Bool {
mode == .remoteOverLocal && remoteValue != nil
}
@@ -53,7 +56,7 @@ final class UserPreference<T: Codable> {
self.mode = mode
}
// The wrapped value is supposed to be the one updated by the user so it can only control the local value
/// The wrapped value is supposed to be the one updated by the user so it can only control the local value
var wrappedValue: T {
get {
switch mode {
@@ -69,8 +72,8 @@ final class UserPreference<T: Codable> {
}
}
// This is supposed to be the value that is set by the remote settings
// So it can only be accessed by doing `AppSettings._preferenceName.remoteValue`
/// This is supposed to be the value that is set by the remote settings
/// So it can only be accessed by doing `AppSettings._preferenceName.remoteValue`
var remoteValue: T? {
get {
keyedStorage[remoteKey]

View File

@@ -25,7 +25,9 @@ class ChatsTabFlowCoordinator: FlowCoordinatorProtocol {
private let navigationSplitCoordinator: NavigationSplitCoordinator
private let flowParameters: CommonFlowParameters
private var userSession: UserSessionProtocol { flowParameters.userSession }
private var userSession: UserSessionProtocol {
flowParameters.userSession
}
private let stateMachine: ChatsTabFlowCoordinatorStateMachine

View File

@@ -20,7 +20,9 @@ class MediaEventsTimelineFlowCoordinator: FlowCoordinatorProtocol {
private let navigationStackCoordinator: NavigationStackCoordinator
private let flowParameters: CommonFlowParameters
private var userSession: UserSessionProtocol { flowParameters.userSession }
private var userSession: UserSessionProtocol {
flowParameters.userSession
}
private let actionsSubject: PassthroughSubject<MediaEventsTimelineFlowCoordinatorAction, Never> = .init()
var actionsPublisher: AnyPublisher<MediaEventsTimelineFlowCoordinatorAction, Never> {

View File

@@ -21,7 +21,9 @@ class PinnedEventsTimelineFlowCoordinator: FlowCoordinatorProtocol {
private let navigationStackCoordinator: NavigationStackCoordinator
private let flowParameters: CommonFlowParameters
private var userSession: UserSessionProtocol { flowParameters.userSession }
private var userSession: UserSessionProtocol {
flowParameters.userSession
}
private let actionsSubject: PassthroughSubject<PinnedEventsTimelineFlowCoordinatorAction, Never> = .init()
var actionsPublisher: AnyPublisher<PinnedEventsTimelineFlowCoordinatorAction, Never> {

View File

@@ -67,7 +67,9 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
private let navigationStackCoordinator: NavigationStackCoordinator
private let flowParameters: CommonFlowParameters
private var userSession: UserSessionProtocol { flowParameters.userSession }
private var userSession: UserSessionProtocol {
flowParameters.userSession
}
private var roomProxy: JoinedRoomProxyProtocol!

View File

@@ -28,7 +28,7 @@ final class SpaceSettingsFlowCoordinator: FlowCoordinatorProtocol {
/// The edit address screen
case editAddress
// Other flows
/// Other flows
/// The roles and permissions screen
case rolesAndPermissionsFlow
/// The members flow screen

View File

@@ -27,7 +27,9 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
private let appLockService: AppLockServiceProtocol
private let flowParameters: CommonFlowParameters
private var userSession: UserSessionProtocol { flowParameters.userSession }
private var userSession: UserSessionProtocol {
flowParameters.userSession
}
private let onboardingFlowCoordinator: OnboardingFlowCoordinator
private let onboardingStackCoordinator: NavigationStackCoordinator
@@ -145,12 +147,12 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
chatsTabFlowCoordinator.clearRoute(animated: animated)
}
// Clearing routes is more complicated than it first seems. When passing routes
// to the chats flow we can't clear all routes as e.g. childRoom/childEvent etc
// expect to push into the existing stack. But we do need to hide any sheets that
// might cover up the presented route. BUT! We probably shouldn't dismiss onboarding
// or verification flows until they're complete This needs more thought before we
// codify it all into the state machine.
/// Clearing routes is more complicated than it first seems. When passing routes
/// to the chats flow we can't clear all routes as e.g. childRoom/childEvent etc
/// expect to push into the existing stack. But we do need to hide any sheets that
/// might cover up the presented route. BUT! We probably shouldn't dismiss onboarding
/// or verification flows until they're complete This needs more thought before we
/// codify it all into the state machine.
private func clearPresentedSheets(animated: Bool) {
switch stateMachine.state {
case .initial, .tabBar:

View File

@@ -38,7 +38,7 @@ extension RoomMemberProxyMock {
powerLevel = configuration.powerLevel
}
// Mocks
/// Mocks
static var mockMe: RoomMemberProxyMock {
RoomMemberProxyMock(with: .init(userID: "@me:matrix.org",
displayName: "Me",

View File

@@ -9,7 +9,7 @@
import Foundation
extension UserProfileProxy {
// Mocks
/// Mocks
static var mockAlice: UserProfileProxy {
.init(userID: "@alice:matrix.org", displayName: "Alice", avatarURL: "mxc://matrix.org/UcCimidcvpFvWkPzvjXMQPHA")
}

View File

@@ -56,7 +56,9 @@ enum A11yIdentifiers {
}
struct AppLockScreen {
func numpad(_ digit: Int) -> String { "app_lock-numpad_\(digit)" }
func numpad(_ digit: Int) -> String {
"app_lock-numpad_\(digit)"
}
}
struct AppLockSetupBiometricsScreen {

View File

@@ -15,7 +15,6 @@ struct ScreenTrackerViewModifier: ViewModifier {
let screen: AnalyticsEvent.MobileScreen.ScreenName
@ViewBuilder
func body(content: Content) -> some View {
content
.onAppear {

View File

@@ -13,7 +13,7 @@ enum Avatars {
enum Size {
case user(on: UserAvatarSizeOnScreen)
case room(on: RoomAvatarSizeOnScreen)
// custom
/// custom
case custom(CGFloat)
/// Value in UIKit points

View File

@@ -102,11 +102,9 @@ private func decodeAC(_ value: Int, maximumValue: Float) -> (Float, Float, Float
let quantG = (value / 19) % 19
let quantB = value % 19
let rgb = (signPow((Float(quantR) - 9) / 9, 2) * maximumValue,
signPow((Float(quantG) - 9) / 9, 2) * maximumValue,
signPow((Float(quantB) - 9) / 9, 2) * maximumValue)
return rgb
return (signPow((Float(quantR) - 9) / 9, 2) * maximumValue,
signPow((Float(quantG) - 9) / 9, 2) * maximumValue,
signPow((Float(quantB) - 9) / 9, 2) * maximumValue)
}
private func signPow(_ value: Float, _ exp: Float) -> Float {

View File

@@ -39,14 +39,12 @@ struct CollapsibleReactionLayout: Layout {
rows: collapsedRows,
collapseButton: subviewsByType.collapseButton,
addMoreButton: subviewsByType.addMoreButton)
let size = sizeThatFits(rows: collapsedRowsWithButtons)
return size
return sizeThatFits(rows: collapsedRowsWithButtons)
} else {
// Show all subviews with the button at the end
var rowsWithButtons = calculateRows(proposal: proposal, subviews: Array(subviews))
ensureCollapseAndAddMoreButtonsAreOnTheSameRow(&rowsWithButtons)
let size = sizeThatFits(rows: rowsWithButtons)
return size
return sizeThatFits(rows: rowsWithButtons)
}
} else {
// Otherwise we are just calculating the size of all items without the button

View File

@@ -21,7 +21,7 @@ struct CurrentValuePublisher<Output, Failure: Error>: Publisher {
self.init(CurrentValueSubject(value))
}
func receive<S>(subscriber: S) where S: Subscriber, Failure == S.Failure, Output == S.Input {
func receive<S: Subscriber>(subscriber: S) where Failure == S.Failure, Output == S.Input {
subject.receive(subscriber: subscriber)
}

View File

@@ -13,7 +13,7 @@ protocol AlertProtocol {
}
extension View {
func alert<Item, Actions, Message>(item: Binding<Item?>, @ViewBuilder actions: (Item) -> Actions, @ViewBuilder message: (Item) -> Message) -> some View where Item: AlertProtocol, Actions: View, Message: View {
func alert<Item: AlertProtocol, Actions: View, Message: View>(item: Binding<Item?>, @ViewBuilder actions: (Item) -> Actions, @ViewBuilder message: (Item) -> Message) -> some View {
let binding = Binding<Bool>(get: {
item.wrappedValue != nil
}, set: { newValue in
@@ -25,7 +25,7 @@ extension View {
}
// 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 {
func alert<Item: AlertProtocol, Actions: View>(item: Binding<Item?>, @ViewBuilder actions: (Item) -> Actions) -> some View {
let binding = Binding<Bool>(get: {
item.wrappedValue != nil
}, set: { newValue in

View File

@@ -9,7 +9,7 @@
import Foundation
extension AttributedString {
// faster than doing `String(characters)`: https://forums.swift.org/t/attributedstring-to-string/61667
/// faster than doing `String(characters)`: https://forums.swift.org/t/attributedstring-to-string/61667
var string: String {
String(characters[...])
}

View File

@@ -13,9 +13,9 @@ protocol ConfirmationDialogProtocol {
}
extension View {
func confirmationDialog<Item, Actions>(item: Binding<Item?>,
titleVisibility: Visibility = .automatic,
@ViewBuilder actions: (Item) -> Actions) -> some View where Item: ConfirmationDialogProtocol, Actions: View {
func confirmationDialog<Item: ConfirmationDialogProtocol, Actions: View>(item: Binding<Item?>,
titleVisibility: Visibility = .automatic,
@ViewBuilder actions: (Item) -> Actions) -> some View {
let binding = Binding<Bool>(get: {
item.wrappedValue != nil
}, set: { newValue in
@@ -27,10 +27,10 @@ extension View {
}
// periphery: ignore - not used yet but might be useful
func confirmationDialog<Item, Actions, Message>(item: Binding<Item?>,
titleVisibility: Visibility = .automatic,
@ViewBuilder actions: (Item) -> Actions,
@ViewBuilder message: (Item) -> Message) -> some View where Item: ConfirmationDialogProtocol, Actions: View, Message: View {
func confirmationDialog<Item: ConfirmationDialogProtocol, Actions: View, Message: View>(item: Binding<Item?>,
titleVisibility: Visibility = .automatic,
@ViewBuilder actions: (Item) -> Actions,
@ViewBuilder message: (Item) -> Message) -> some View {
let binding = Binding<Bool>(get: {
item.wrappedValue != nil
}, set: { newValue in

View File

@@ -67,8 +67,8 @@ extension Date {
}
private extension DateFormatter {
// There doesn't appear to be a way to get "Today" out of
// `Date.RelativeFormatStyle` so use the old way instead 😐
/// There doesn't appear to be a way to get "Today" out of
/// `Date.RelativeFormatStyle` so use the old way instead 😐
static let relative: DateFormatter = {
let formatter = DateFormatter()
formatter.doesRelativeDateFormatting = true

View File

@@ -197,5 +197,7 @@ extension NSItemProvider {
}
private extension NSString {
var hasPathExtension: Bool { !pathExtension.isEmpty }
var hasPathExtension: Bool {
!pathExtension.isEmpty
}
}

View File

@@ -7,7 +7,6 @@
//
import Foundation
import OrderedCollections
extension OrderedSet {

View File

@@ -9,7 +9,7 @@
import SwiftUI
extension Section where Parent == Color, Content == EmptyView, Footer == EmptyView {
// An empty section whose purpose is to keep Form's background color when there is no content into it.
/// An empty section whose purpose is to keep Form's background color when there is no content into it.
static var empty: some View {
Section {
EmptyView()

View File

@@ -135,12 +135,29 @@ extension URL {
// MARK: Mocks
static var mockMXCAudio: URL { "mxc://matrix.org/1234567890AuDiO" }
static var mockMXCFile: URL { "mxc://matrix.org/1234567890FiLe" }
static var mockMXCImage: URL { "mxc://matrix.org/1234567890ImAgE" }
static var mockMXCVideo: URL { "mxc://matrix.org/1234567890ViDeO" }
static var mockMXCAvatar: URL { "mxc://matrix.org/1234567890AvAtAr" }
static var mockMXCUserAvatar: URL { "mxc://matrix.org/1234567890AvAtArUsEr" }
static var mockMXCAudio: URL {
"mxc://matrix.org/1234567890AuDiO"
}
static var mockMXCFile: URL {
"mxc://matrix.org/1234567890FiLe"
}
static var mockMXCImage: URL {
"mxc://matrix.org/1234567890ImAgE"
}
static var mockMXCVideo: URL {
"mxc://matrix.org/1234567890ViDeO"
}
static var mockMXCAvatar: URL {
"mxc://matrix.org/1234567890AvAtAr"
}
static var mockMXCUserAvatar: URL {
"mxc://matrix.org/1234567890AvAtArUsEr"
}
}
// MARK: - Helpers

View File

@@ -96,7 +96,7 @@ extension XCTestCase {
timeout: TimeInterval = 10,
message: String? = nil) -> DeferredFulfillment<P.Output> {
var expectedOrder = transitionValues
let deferred = deferFulfillment(publisher, timeout: timeout, message: message) { value in
return deferFulfillment(publisher, timeout: timeout, message: message) { value in
let receivedValue = value[keyPath: keyPath]
if let index = expectedOrder.firstIndex(where: { $0 == receivedValue }), index == 0 {
expectedOrder.remove(at: index)
@@ -104,8 +104,6 @@ extension XCTestCase {
return expectedOrder.isEmpty
}
return deferred
}
/// XCTest utility that assists in subscribing to an async sequence and deferring the fulfilment and results until some other actions have been performed.
@@ -120,15 +118,13 @@ extension XCTestCase {
timeout: TimeInterval = 10,
message: String? = nil) -> DeferredFulfillment<Value> {
var expectedOrder = transitionValues
let deferred = deferFulfillment(asyncSequence, timeout: timeout, message: message) { value in
return deferFulfillment(asyncSequence, timeout: timeout, message: message) { value in
if let index = expectedOrder.firstIndex(where: { $0 == value }), index == 0 {
expectedOrder.remove(at: index)
}
return expectedOrder.isEmpty
}
return deferred
}
/// XCTest utility that assists in subscribing to a publisher and deferring the failure for a particular value until some other actions have been performed.

View File

@@ -72,13 +72,13 @@ struct AttributedStringBuilder: AttributedStringBuilderProtocol {
return result
}
// Do not use the default HTML renderer of NSAttributedString because this method
// runs on the UI thread which we want to avoid because renderHTMLString is called
// most of the time from a background thread.
// Use DTCoreText HTML renderer instead.
// Using DTCoreText, which renders static string, helps to avoid code injection attacks
// that could happen with the default HTML renderer of NSAttributedString which is a
// webview.
/// Do not use the default HTML renderer of NSAttributedString because this method
/// runs on the UI thread which we want to avoid because renderHTMLString is called
/// most of the time from a background thread.
/// Use DTCoreText HTML renderer instead.
/// Using DTCoreText, which renders static string, helps to avoid code injection attacks
/// that could happen with the default HTML renderer of NSAttributedString which is a
/// webview.
func fromHTML(_ htmlString: String?) -> AttributedString? {
guard let originalHTMLString = htmlString else {
return nil

View File

@@ -89,7 +89,9 @@ extension AttributeScopes {
let uiKit: UIKitAttributes
}
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

View File

@@ -26,7 +26,9 @@ enum Tracing {
/// This basically only affects ``logFiles``, and doesn't inform the SDK to write
/// the logs to a different directory, which should be done before setting this.
static var logsDirectoryOverride: URL?
static var legacyLogsDirectory: URL { .appGroupContainerDirectory }
static var legacyLogsDirectory: URL {
.appGroupContainerDirectory
}
static let fileExtension = "log"
@@ -60,7 +62,9 @@ enum Tracing {
}
/// A list of all log file URLs, sorted chronologically.
static var logFiles: [URL] { logFiles(in: logsDirectory) }
static var logFiles: [URL] {
logFiles(in: logsDirectory)
}
/// Collect all of the logs in the given directory, sorting them chronologically.
private static func logFiles(in directory: URL) -> [URL] {

View File

@@ -8,7 +8,7 @@
import Foundation
/*
/**
Behavior mode of the current user's location, can be hidden, only shown and shown following the user
*/
enum ShowUserLocationMode {

View File

@@ -114,7 +114,9 @@ struct MapLibreStaticMapView_Previews: PreviewProvider, TestablePreview {
}
private struct MapTilerURLBuilderMock: MapTilerURLBuilderProtocol {
func interactiveMapURL(for style: MapTilerStyle) -> URL? { nil }
func interactiveMapURL(for style: MapTilerStyle) -> URL? {
nil
}
func staticMapTileImageURL(for style: MapTilerStyle,
coordinates: CLLocationCoordinate2D,

View File

@@ -8,7 +8,7 @@
import Foundation
// https://spec.matrix.org/latest/appendices/#identifier-grammar
/// https://spec.matrix.org/latest/appendices/#identifier-grammar
enum MatrixEntityRegex: String {
case homeserver
case userID

View File

@@ -22,7 +22,7 @@ final class MessageTextView: UITextView, PillAttachmentViewProviderDelegate, UIG
super.addGestureRecognizer(gestureRecognizer)
}
// This prevents the magnifying glass from showing up
/// This prevents the magnifying glass from showing up
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
if otherGestureRecognizer is UILongPressGestureRecognizer {
return false

View File

@@ -9,7 +9,6 @@
import SwiftUI
import SwiftUIIntrospect
import UIKit
import WysiwygComposer
protocol PillAttachmentViewProviderDelegate: AnyObject {

View File

@@ -29,7 +29,6 @@ struct PillView: View {
}
}
@ViewBuilder
private var mainContent: some View {
Text(context.viewState.displayText)
.font(.compound.bodyLGSemibold)

View File

@@ -8,7 +8,7 @@
import Foundation
// In the future we might use this to do some customisation in what is plain text used to represent mentions.
/// In the future we might use this to do some customisation in what is plain text used to represent mentions.
struct PlainMentionBuilder: MentionBuilderProtocol {
func handleEventOnRoomAliasMention(for attributedString: NSMutableAttributedString, in range: NSRange, url: URL, eventID: String, roomAlias: String) { }

View File

@@ -26,123 +26,177 @@ final class SDKListener<T> {
// MARK: QRCodeLoginService
extension SDKListener: QrLoginProgressListener where T == QrLoginProgress {
func onUpdate(state: QrLoginProgress) { onUpdateClosure(state) }
func onUpdate(state: QrLoginProgress) {
onUpdateClosure(state)
}
}
extension SDKListener: GrantQrLoginProgressListener where T == GrantQrLoginProgress {
func onUpdate(state: GrantQrLoginProgress) { onUpdateClosure(state) }
func onUpdate(state: GrantQrLoginProgress) {
onUpdateClosure(state)
}
}
extension SDKListener: GrantGeneratedQrLoginProgressListener where T == GrantGeneratedQrLoginProgress {
func onUpdate(state: GrantGeneratedQrLoginProgress) { onUpdateClosure(state) }
func onUpdate(state: GrantGeneratedQrLoginProgress) {
onUpdateClosure(state)
}
}
// MARK: ClientProxy
extension SDKListener: MediaPreviewConfigListener where T == MediaPreviewConfig? {
func onChange(mediaPreviewConfig: MediaPreviewConfig?) { onUpdateClosure(mediaPreviewConfig) }
func onChange(mediaPreviewConfig: MediaPreviewConfig?) {
onUpdateClosure(mediaPreviewConfig)
}
}
extension SDKListener: SyncServiceStateObserver where T == SyncServiceState {
func onUpdate(state: SyncServiceState) { onUpdateClosure(state) }
func onUpdate(state: SyncServiceState) {
onUpdateClosure(state)
}
}
extension SDKListener: RoomListServiceStateListener where T == RoomListServiceState {
func onUpdate(state: RoomListServiceState) { onUpdateClosure(state) }
func onUpdate(state: RoomListServiceState) {
onUpdateClosure(state)
}
}
extension SDKListener: RoomListServiceSyncIndicatorListener where T == RoomListServiceSyncIndicator {
func onUpdate(syncIndicator: RoomListServiceSyncIndicator) { onUpdateClosure(syncIndicator) }
func onUpdate(syncIndicator: RoomListServiceSyncIndicator) {
onUpdateClosure(syncIndicator)
}
}
extension SDKListener: VerificationStateListener where T == VerificationState {
func onUpdate(status: VerificationState) { onUpdateClosure(status) }
func onUpdate(status: VerificationState) {
onUpdateClosure(status)
}
}
extension SDKListener: IgnoredUsersListener where T == [String] {
func call(ignoredUserIds: [String]) { onUpdateClosure(ignoredUserIds) }
func call(ignoredUserIds: [String]) {
onUpdateClosure(ignoredUserIds)
}
}
extension SDKListener: SendQueueRoomErrorListener where T == (String, ClientError) {
func onError(roomId: String, error: ClientError) { onUpdateClosure((roomId, error)) }
func onError(roomId: String, error: ClientError) {
onUpdateClosure((roomId, error))
}
}
// MARK: SecureBackupController
extension SDKListener: BackupStateListener where T == BackupState {
func onUpdate(status: BackupState) { onUpdateClosure(status) }
func onUpdate(status: BackupState) {
onUpdateClosure(status)
}
}
extension SDKListener: RecoveryStateListener where T == RecoveryState {
func onUpdate(status: RecoveryState) { onUpdateClosure(status) }
func onUpdate(status: RecoveryState) {
onUpdateClosure(status)
}
}
extension SDKListener: EnableRecoveryProgressListener where T == EnableRecoveryProgress {
func onUpdate(status: EnableRecoveryProgress) { onUpdateClosure(status) }
func onUpdate(status: EnableRecoveryProgress) {
onUpdateClosure(status)
}
}
extension SDKListener: BackupSteadyStateListener where T == BackupUploadState {
func onUpdate(status: BackupUploadState) { onUpdateClosure(status) }
func onUpdate(status: BackupUploadState) {
onUpdateClosure(status)
}
}
// MARK: RoomSummaryProvider
extension SDKListener: RoomListEntriesListener where T == [RoomListEntriesUpdate] {
func onUpdate(roomEntriesUpdate: [RoomListEntriesUpdate]) { onUpdateClosure(roomEntriesUpdate) }
func onUpdate(roomEntriesUpdate: [RoomListEntriesUpdate]) {
onUpdateClosure(roomEntriesUpdate)
}
}
extension SDKListener: RoomListLoadingStateListener where T == RoomListLoadingState {
func onUpdate(state: RoomListLoadingState) { onUpdateClosure(state) }
func onUpdate(state: RoomListLoadingState) {
onUpdateClosure(state)
}
}
// MARK: Spaces
extension SDKListener: SpaceServiceJoinedSpacesListener where T == [SpaceListUpdate] {
func onUpdate(rooms: [SpaceListUpdate]) { onUpdateClosure(rooms) }
func onUpdate(rooms: [SpaceListUpdate]) {
onUpdateClosure(rooms)
}
}
extension SDKListener: SpaceRoomListEntriesListener where T == [SpaceListUpdate] {
func onUpdate(roomUpdates: [SpaceListUpdate]) { onUpdateClosure(roomUpdates) }
func onUpdate(roomUpdates: [SpaceListUpdate]) {
onUpdateClosure(roomUpdates)
}
}
extension SDKListener: SpaceRoomListPaginationStateListener where T == SpaceRoomListPaginationState {
func onUpdate(paginationState: SpaceRoomListPaginationState) { onUpdateClosure(paginationState) }
func onUpdate(paginationState: SpaceRoomListPaginationState) {
onUpdateClosure(paginationState)
}
}
extension SDKListener: SpaceRoomListSpaceListener where T == SpaceRoom? {
func onUpdate(space: SpaceRoom?) { onUpdateClosure(space) }
func onUpdate(space: SpaceRoom?) {
onUpdateClosure(space)
}
}
extension SDKListener: SpaceServiceSpaceFiltersListener where T == [SpaceFilterUpdate] {
func onUpdate(filterUpdates: [SpaceFilterUpdate]) { onUpdateClosure(filterUpdates) }
func onUpdate(filterUpdates: [SpaceFilterUpdate]) {
onUpdateClosure(filterUpdates)
}
}
// MARK: Room
extension SDKListener: RoomInfoListener where T == RoomInfo {
func call(roomInfo: RoomInfo) { onUpdateClosure(roomInfo) }
func call(roomInfo: RoomInfo) {
onUpdateClosure(roomInfo)
}
}
extension SDKListener: CallDeclineListener where T == String {
func call(declinerUserId: String) { onUpdateClosure(declinerUserId) }
func call(declinerUserId: String) {
onUpdateClosure(declinerUserId)
}
}
extension SDKListener: TypingNotificationsListener where T == [String] {
func call(typingUserIds: [String]) { onUpdateClosure(typingUserIds) }
func call(typingUserIds: [String]) {
onUpdateClosure(typingUserIds)
}
}
extension SDKListener: IdentityStatusChangeListener where T == [IdentityStatusChange] {
func call(identityStatusChange: [IdentityStatusChange]) { onUpdateClosure(identityStatusChange) }
func call(identityStatusChange: [IdentityStatusChange]) {
onUpdateClosure(identityStatusChange)
}
}
extension SDKListener: KnockRequestsListener where T == [KnockRequest] {
func call(joinRequests: [KnockRequest]) { onUpdateClosure(joinRequests) }
func call(joinRequests: [KnockRequest]) {
onUpdateClosure(joinRequests)
}
}
// MARK: TimelineProxy
extension SDKListener: PaginationStatusListener where T == RoomPaginationStatus {
func onUpdate(status: RoomPaginationStatus) { onUpdateClosure(status) }
func onUpdate(status: RoomPaginationStatus) {
onUpdateClosure(status)
}
}
extension SDKListener: ProgressWatcher where T == Double {
@@ -156,11 +210,15 @@ extension SDKListener: ProgressWatcher where T == Double {
// MARK: TimelineItemProvider
extension SDKListener: TimelineListener where T == [TimelineDiff] {
func onUpdate(diff: [TimelineDiff]) { onUpdateClosure(diff) }
func onUpdate(diff: [TimelineDiff]) {
onUpdateClosure(diff)
}
}
// MARK: RoomDirectorySearchProxy
extension SDKListener: RoomDirectorySearchEntriesListener where T == [RoomDirectorySearchEntryUpdate] {
func onUpdate(roomEntriesUpdate: [RoomDirectorySearchEntryUpdate]) { onUpdateClosure(roomEntriesUpdate) }
func onUpdate(roomEntriesUpdate: [RoomDirectorySearchEntryUpdate]) {
onUpdateClosure(roomEntriesUpdate)
}
}

View File

@@ -19,7 +19,7 @@ public extension Animation {
return animation.disabledIfReduceMotionEnabled()
}
// `noAnimation` if running tests, otherwise `self` if `UIAccessibility.isReduceMotionEnabled` is false
/// `noAnimation` if running tests, otherwise `self` if `UIAccessibility.isReduceMotionEnabled` is false
func disabledDuringTests() -> Self {
let animation: Animation = ProcessInfo.isRunningTests ? .noAnimation : self
return animation.disabledIfReduceMotionEnabled()

View File

@@ -10,7 +10,9 @@ import SwiftUI
extension ButtonStyle where Self == MenuSheetButtonStyle {
/// A button style for buttons that are within a menu that is being presented as a sheet.
static var menuSheet: Self { MenuSheetButtonStyle() }
static var menuSheet: Self {
MenuSheetButtonStyle()
}
}
/// The style used for buttons that are part of a menu that's presented as

View File

@@ -31,7 +31,6 @@ extension View {
}
}
@ViewBuilder
func mediaGalleryTimelineAspectRatio(imageInfo: ImageInfoProxy?) -> some View {
aspectRatio(imageInfo?.aspectRatio, contentMode: .fill)
}

View File

@@ -53,7 +53,6 @@ private struct SearchControllerModifier: ViewModifier {
/// is `false`, checking if this value is `false` is pretty much meaningless.
@State private var isSearching = false
@ViewBuilder
func body(content: Content) -> some View {
let text: Text? = if let placeholder {
Text(placeholder)
@@ -191,7 +190,9 @@ private struct SearchController: UIViewControllerRepresentable {
}
@available(*, unavailable)
required init?(coder: NSCoder) { fatalError() }
required init?(coder: NSCoder) {
fatalError()
}
override func willMove(toParent parent: UIViewController?) {
parent?.navigationItem.searchController = searchController

View File

@@ -135,9 +135,7 @@ private struct LoadableImageContent<TransformerView: View, PlaceholderView: View
ZStack {
switch (contentLoader.content, shouldRender) {
case (.image(let image), true):
transformer(
AnyView(Image(uiImage: image).resizable())
)
transformer(AnyView(Image(uiImage: image).resizable()))
case (.gifData, true):
transformer(AnyView(KFAnimatedImage(source: .provider(self))))
case (.none, _), (_, false):
@@ -170,7 +168,7 @@ private struct LoadableImageContent<TransformerView: View, PlaceholderView: View
}
}
// Note: Returns `AnyView` as this is what `transformer` expects.
/// Note: Returns `AnyView` as this is what `transformer` expects.
var blurHashView: AnyView? {
if let blurhash,
// Build a small blurhash image so that it's fast
@@ -387,7 +385,10 @@ struct LoadableImage_Previews: PreviewProvider, TestablePreview {
}
}
static func placeholder() -> some View { Color.compound._bgBubbleIncoming }
static func placeholder() -> some View {
Color.compound._bgBubbleIncoming
}
static func transformer(_ view: AnyView) -> some View {
view.overlay {
Image(systemSymbol: .playCircleFill)

View File

@@ -17,7 +17,9 @@ struct UserProfileListRow: View {
let kind: ListRow<LoadableAvatarImage, EmptyView, EmptyView, Bool>.Kind<EmptyView, Bool>
var isUnknownProfile: Bool { !user.isVerified && membership == nil }
var isUnknownProfile: Bool {
!user.isVerified && membership == nil
}
private var subtitle: String? {
guard !isUnknownProfile else { return L10n.commonInviteUnknownProfile }

View File

@@ -58,12 +58,10 @@ private struct VisualListItemLabelStyle: LabelStyle {
struct VisualListItem_Previews: PreviewProvider, TestablePreview {
static let strings = AnalyticsPromptScreenStrings(termsURL: ServiceLocator.shared.settings.analyticsTermsURL)
@ViewBuilder
static var testImage1: some View {
Image(systemName: "circle")
}
@ViewBuilder
static var testImage2: some View {
Image(systemName: "square")
}

View File

@@ -13,8 +13,13 @@ enum UserIndicatorType: Equatable {
case toast(progress: UserIndicator.Progress?)
case modal(progress: UserIndicator.Progress?, interactiveDismissDisabled: Bool, allowsInteraction: Bool)
static var toast: Self { .toast(progress: .none) }
static var modal: Self { .modal(progress: .indeterminate, interactiveDismissDisabled: false, allowsInteraction: false) }
static var toast: Self {
.toast(progress: .none)
}
static var modal: Self {
.modal(progress: .indeterminate, interactiveDismissDisabled: false, allowsInteraction: false)
}
}
struct UserIndicator: Equatable, Identifiable {

View File

@@ -76,28 +76,24 @@ struct UserIndicatorModalView_Previews: PreviewProvider, TestablePreview {
VStack(spacing: 0) {
UserIndicatorModalView(indicator: UserIndicator(type: .modal,
title: "Successfully logged in",
iconName: "checkmark")
)
iconName: "checkmark"))
UserIndicatorModalView(indicator: UserIndicator(type: .modal(progress: .published(CurrentValueSubject<Double, Never>(0.5).asCurrentValuePublisher()),
interactiveDismissDisabled: false,
allowsInteraction: false),
title: "Successfully logged in",
iconName: "checkmark")
)
iconName: "checkmark"))
UserIndicatorModalView(indicator: UserIndicator(type: .modal(progress: .none,
interactiveDismissDisabled: false,
allowsInteraction: false),
title: "Successfully logged in",
iconName: "checkmark")
)
iconName: "checkmark"))
UserIndicatorModalView(indicator: UserIndicator(type: .modal,
title: "Successfully logged in",
message: "You can now be happy.",
iconName: "checkmark")
)
iconName: "checkmark"))
}
}
}

View File

@@ -17,7 +17,6 @@ struct UserIndicatorPresenter: View {
.animation(.elementDefault, value: userIndicatorController.activeIndicator)
}
@ViewBuilder
private func indicatorViewFor(indicator: UserIndicator?) -> some View {
ZStack { // Need a container to properly animate transitions
if let indicator {

View File

@@ -83,10 +83,8 @@ private struct VoiceMessageButtonStyle: ButtonStyle {
func makeBody(configuration: Configuration) -> some View {
configuration.label
.foregroundColor(isEnabled ? .compound.textSecondary.opacity(configuration.isPressed ? 0.6 : 1) : .compound.iconDisabled)
.background(
Circle()
.foregroundColor(configuration.isPressed ? .compound.bgSubtlePrimary : .compound.bgCanvasDefault)
)
.background(Circle()
.foregroundColor(configuration.isPressed ? .compound.bgSubtlePrimary : .compound.bgCanvasDefault))
}
}

View File

@@ -39,8 +39,7 @@ private struct WaveformInteractionModifier: ViewModifier {
isDragging = true
let progress = dragGesture.location.x / geometry.size.width
onSeek(max(0, min(progress, 1.0)))
}
)
})
.offset(x: -cursorInteractiveSize / 2, y: 0)
}
.gesture(SpatialTapGesture()

View File

@@ -27,9 +27,15 @@ struct AppLockScreenViewState: BindableState {
var bindings: AppLockScreenViewStateBindings
/// The number of digits the user has entered so far.
var numberOfDigitsEntered: Int { bindings.pinCode.count }
var numberOfDigitsEntered: Int {
bindings.pinCode.count
}
/// Whether the subtitle is in a warning state or not.
var isSubtitleWarning: Bool { numberOfPINAttempts > 0 }
var isSubtitleWarning: Bool {
numberOfPINAttempts > 0
}
/// The string shown in the screen's subtitle.
var subtitle: String {
if !isSubtitleWarning {

View File

@@ -78,7 +78,7 @@ struct AppLockScreen: View {
/// The row of dots showing how many digits have been entered.
var pinInputField: some View {
HStack(spacing: 24) {
/// The size of each dot within the PIN input field.
// The size of each dot within the PIN input field.
let pinDotSize: CGFloat = 14
Circle()
.fill(context.viewState.numberOfDigitsEntered > 0 ? .compound.iconPrimary : .compound.bgSubtlePrimary)

View File

@@ -117,7 +117,9 @@ struct AppLockScreenPINKeypad_Previews: PreviewProvider {
@StateObject var model = PreviewModel()
class PreviewModel: ObservableObject {
@Published var pinCode = ""
var output: String { pinCode.isEmpty ? "Enter code" : pinCode }
var output: String {
pinCode.isEmpty ? "Enter code" : pinCode
}
}
var body: some View {

View File

@@ -17,9 +17,17 @@ struct AppLockSetupBiometricsScreenViewState: BindableState {
/// The supported biometry type on this device.
let biometryType: LABiometryType
var icon: SFSymbol { biometryType.systemSymbol }
var title: String { L10n.screenAppLockSetupBiometricUnlockAllowTitle(biometryType.localizedString) }
var subtitle: String { L10n.screenAppLockSetupBiometricUnlockSubtitle(biometryType.localizedString) }
var icon: SFSymbol {
biometryType.systemSymbol
}
var title: String {
L10n.screenAppLockSetupBiometricUnlockAllowTitle(biometryType.localizedString)
}
var subtitle: String {
L10n.screenAppLockSetupBiometricUnlockSubtitle(biometryType.localizedString)
}
}
enum AppLockSetupBiometricsScreenViewAction {

View File

@@ -50,7 +50,10 @@ struct AppLockSetupPINScreenViewState: BindableState {
}
/// Whether the subtitle is in a warning state or not.
var isSubtitleWarning: Bool { mode == .unlock && numberOfUnlockAttempts > 0 }
var isSubtitleWarning: Bool {
mode == .unlock && numberOfUnlockAttempts > 0
}
var subtitle: String {
guard mode == .unlock else { return L10n.screenAppLockSetupPinContext(InfoPlistReader.main.bundleDisplayName) }
if !isSubtitleWarning {

View File

@@ -22,8 +22,13 @@ struct AppLockSetupSettingsScreenViewState: BindableState {
let biometryType: LABiometryType
var bindings: AppLockSetupSettingsScreenViewStateBindings
var supportsBiometrics: Bool { biometryType != .none }
var enableBiometricsTitle: String { L10n.screenAppLockSetupBiometricUnlockAllowTitle(biometryType.localizedString) }
var supportsBiometrics: Bool {
biometryType != .none
}
var enableBiometricsTitle: String {
L10n.screenAppLockSetupBiometricUnlockAllowTitle(biometryType.localizedString)
}
}
struct AppLockSetupSettingsScreenViewStateBindings {

View File

@@ -26,12 +26,14 @@ enum LoginScreenCoordinatorAction {
case signedIn(UserSessionProtocol)
}
// Note: This code was brought over from Riot, we should move the authentication service logic into the view model.
/// Note: This code was brought over from Riot, we should move the authentication service logic into the view model.
final class LoginScreenCoordinator: CoordinatorProtocol {
private let parameters: LoginScreenCoordinatorParameters
private var viewModel: LoginScreenViewModelProtocol
private var authenticationService: AuthenticationServiceProtocol { parameters.authenticationService }
private var authenticationService: AuthenticationServiceProtocol {
parameters.authenticationService
}
private let actionsSubject: PassthroughSubject<LoginScreenCoordinatorAction, Never> = .init()
private var cancellables = Set<AnyCancellable>()

View File

@@ -31,7 +31,9 @@ struct LoginScreenViewState: BindableState {
var bindings = LoginScreenBindings()
/// The types of login supported by the homeserver.
var loginMode: LoginMode { homeserver.loginMode }
var loginMode: LoginMode {
homeserver.loginMode
}
/// `true` if the username and password are ready to be submitted.
var hasValidCredentials: Bool {

View File

@@ -103,7 +103,9 @@ class OIDCAuthenticationPresenter: NSObject {
// MARK: ASWebAuthenticationPresentationContextProviding
extension OIDCAuthenticationPresenter: ASWebAuthenticationPresentationContextProviding {
func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor { presentationAnchor }
func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor {
presentationAnchor
}
}
extension ASWebAuthenticationSession.Callback {

View File

@@ -103,9 +103,9 @@ struct ServerConfirmationScreen: View {
}
}
// This is such a hack. I hate it!
// But We're not in a List/Form, the compound picker doesn't
// support icons and this screen's design might change so 🤷.
/// This is such a hack. I hate it!
/// But We're not in a List/Form, the compound picker doesn't
/// support icons and this screen's design might change so 🤷.
private struct FakeInlinePicker: View {
let items: [String]
let icon: KeyPath<CompoundIcons, Image>

View File

@@ -22,12 +22,14 @@ enum ServerSelectionScreenCoordinatorAction {
case dismiss
}
// Note: This code was brought over from Riot, we should move the authentication service logic into the view model.
/// Note: This code was brought over from Riot, we should move the authentication service logic into the view model.
final class ServerSelectionScreenCoordinator: CoordinatorProtocol {
private let parameters: ServerSelectionScreenCoordinatorParameters
private let userIndicatorController: UserIndicatorControllerProtocol
private var viewModel: ServerSelectionScreenViewModelProtocol
private var authenticationService: AuthenticationServiceProtocol { parameters.authenticationService }
private var authenticationService: AuthenticationServiceProtocol {
parameters.authenticationService
}
private let actionsSubject: PassthroughSubject<ServerSelectionScreenCoordinatorAction, Never> = .init()
private var cancellables = Set<AnyCancellable>()

View File

@@ -34,14 +34,17 @@ enum SoftLogoutScreenCoordinatorResult: CustomStringConvertible {
}
}
// Note: This code was brought over from Riot, we should move the authentication service logic into the view model.
/// Note: This code was brought over from Riot, we should move the authentication service logic into the view model.
final class SoftLogoutScreenCoordinator: CoordinatorProtocol {
private let parameters: SoftLogoutScreenCoordinatorParameters
private var viewModel: SoftLogoutScreenViewModelProtocol
private let actionsSubject: PassthroughSubject<SoftLogoutScreenCoordinatorResult, Never> = .init()
private var cancellables = Set<AnyCancellable>()
private var authenticationService: AuthenticationServiceProtocol { parameters.authenticationService }
private var authenticationService: AuthenticationServiceProtocol {
parameters.authenticationService
}
private var oidcPresenter: OIDCAuthenticationPresenter?
var actions: AnyPublisher<SoftLogoutScreenCoordinatorResult, Never> {

View File

@@ -54,7 +54,9 @@ struct SoftLogoutScreenViewState: BindableState {
var bindings: SoftLogoutScreenBindings
/// The types of login supported by the homeserver.
var loginMode: LoginMode { homeserver.loginMode }
var loginMode: LoginMode {
homeserver.loginMode
}
/// The presentation anchor used for OIDC authentication.
var window: UIWindow?

View File

@@ -20,7 +20,9 @@ struct AuthenticationStartLogo: View {
/// The shape that the logo is composed on top of.
private let outerShape = RoundedRectangle(cornerRadius: 44)
private let outerShapeShadowColor = Color(red: 0.11, green: 0.11, blue: 0.13)
private var isLight: Bool { colorScheme == .light }
private var isLight: Bool {
colorScheme == .light
}
var body: some View {
if hideBrandChrome {

View File

@@ -83,12 +83,10 @@ final class BugReportScreenCoordinator: CoordinatorProtocol {
private static let loadingIndicatorIdentifier = "\(BugReportScreenCoordinator.self)-Loading"
private func startLoading(label: String = L10n.commonLoading, progressPublisher: CurrentValuePublisher<Double, Never>) {
parameters.userIndicatorController?.submitIndicator(
UserIndicator(id: Self.loadingIndicatorIdentifier,
type: .modal(progress: .published(progressPublisher), interactiveDismissDisabled: false, allowsInteraction: true),
title: label,
persistent: true)
)
parameters.userIndicatorController?.submitIndicator(UserIndicator(id: Self.loadingIndicatorIdentifier,
type: .modal(progress: .published(progressPublisher), interactiveDismissDisabled: false, allowsInteraction: true),
title: label,
persistent: true))
}
private func stopLoading() {

View File

@@ -15,8 +15,13 @@ struct BugReportScreen: View {
@Bindable var context: BugReportScreenViewModel.Context
var canSendLogFiles: Bool { context.viewState.canSendLogFiles }
var photosPickerTitle: String { context.viewState.screenshot == nil ? L10n.screenBugReportAttachScreenshot : L10n.screenBugReportEditScreenshot }
var canSendLogFiles: Bool {
context.viewState.canSendLogFiles
}
var photosPickerTitle: String {
context.viewState.screenshot == nil ? L10n.screenBugReportAttachScreenshot : L10n.screenBugReportEditScreenshot
}
var body: some View {
Form {
@@ -89,7 +94,6 @@ struct BugReportScreen: View {
}
}
@ViewBuilder
private var attachScreenshotSection: some View {
Section {
ListRow(kind: .custom {

View File

@@ -225,7 +225,7 @@ class CallScreenViewModel: CallScreenViewModelType, CallScreenViewModelProtocol
}
}
// This should always match the web app value
/// This should always match the web app value
private static let earpieceID = "earpiece-id"
private func handleOutputDeviceSelected(deviceID: String) {

View File

@@ -197,8 +197,8 @@ private struct CallView: UIViewRepresentable {
}
}
// This function is called by the webview output routing button
// it allows to open the OS output selector using the hidden button.
/// This function is called by the webview output routing button
/// it allows to open the OS output selector using the hidden button.
private func tapRoutePickerView() {
guard let button = routePickerView.subviews.first(where: { $0 is UIButton }) as? UIButton else {
return

View File

@@ -45,7 +45,6 @@ struct EncryptionResetPasswordScreen: View {
.onAppear { textFieldFocus = true }
}
@ViewBuilder
private var passwordSection: some View {
VStack(alignment: .leading, spacing: 8) {
Text(L10n.commonPassword)

View File

@@ -70,7 +70,6 @@ struct EncryptionResetScreen: View {
.environment(\.backgroundStyle, AnyShapeStyle(.compound.bgSubtleSecondary))
}
@ViewBuilder
private func checkMarkItem(title: String, position: ListPosition, positive: Bool) -> some View {
VisualListItem(title: title, position: position) {
CompoundIcon(positive ? \.check : \.info)

View File

@@ -106,10 +106,10 @@ private struct MediaPreviewViewController: UIViewControllerRepresentable {
])
}
// Don't use viewWillAppear due to the following warning:
// Presenting view controller <QLPreviewController> from detached view controller <HostingController> is not supported,
// and may result in incorrect safe area insets and a corrupt root presentation. Make sure <HostingController> is in
// the view controller hierarchy before presenting from it. Will become a hard exception in a future release.
/// Don't use viewWillAppear due to the following warning:
/// Presenting view controller <QLPreviewController> from detached view controller <HostingController> is not supported,
/// and may result in incorrect safe area insets and a corrupt root presentation. Make sure <HostingController> is in
/// the view controller hierarchy before presenting from it. Will become a hard exception in a future release.
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
@@ -153,7 +153,10 @@ private struct MediaPreviewViewController: UIViewControllerRepresentable {
class MediaPreviewItem: NSObject, QLPreviewItem {
let file: MediaFileHandleProxy
var previewItemURL: URL? { file.url }
var previewItemURL: URL? {
file.url
}
let previewItemTitle: String?
init(file: MediaFileHandleProxy, title: String?) {

View File

@@ -114,8 +114,13 @@ class TimelineMediaPreviewDataSource: NSObject, QLPreviewControllerDataSource {
// MARK: - QLPreviewControllerDataSource
var firstPreviewItemIndex: Int { backwardPadding }
var lastPreviewItemIndex: Int { backwardPadding + previewItems.count - 1 }
var firstPreviewItemIndex: Int {
backwardPadding
}
var lastPreviewItemIndex: Int {
backwardPadding + previewItems.count - 1
}
func numberOfPreviewItems(in controller: QLPreviewController) -> Int {
previewItems.count + backwardPadding + forwardPadding

View File

@@ -56,7 +56,10 @@ struct TimelineMediaPreviewViewState: BindableState {
var dataSource: TimelineMediaPreviewDataSource
/// The media item that is currently being previewed.
var currentItem: TimelineMediaPreviewItem { dataSource.currentItem }
var currentItem: TimelineMediaPreviewItem {
dataSource.currentItem
}
/// All of the available actions for the current item.
var currentItemActions: TimelineItemMenuActions?

View File

@@ -101,10 +101,10 @@ private struct MediaPreviewViewController: UIViewControllerRepresentable {
])
}
// Don't use viewWillAppear due to the following warning:
// Presenting view controller <QLPreviewController> from detached view controller <HostingController> is not supported,
// and may result in incorrect safe area insets and a corrupt root presentation. Make sure <HostingController> is in
// the view controller hierarchy before presenting from it. Will become a hard exception in a future release.
/// Don't use viewWillAppear due to the following warning:
/// Presenting view controller <QLPreviewController> from detached view controller <HostingController> is not supported,
/// and may result in incorrect safe area insets and a corrupt root presentation. Make sure <HostingController> is in
/// the view controller hierarchy before presenting from it. Will become a hard exception in a future release.
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)

View File

@@ -236,5 +236,7 @@ class TimelineMediaPreviewViewModel: TimelineMediaPreviewViewModelType {
title: L10n.screenMediaDetailsNoMoreMediaToShow))
}
private var statusIndicatorID: String { "\(Self.self)-Status" }
private var statusIndicatorID: String {
"\(Self.self)-Status"
}
}

View File

@@ -24,7 +24,10 @@ class TimelineMediaPreviewController: QLPreviewController {
private var cancellables: Set<AnyCancellable> = []
private var navigationBar: UINavigationBar? { view.subviews.first?.subviews.first { $0 is UINavigationBar } as? UINavigationBar }
private var navigationBar: UINavigationBar? {
view.subviews.first?.subviews.first { $0 is UINavigationBar } as? UINavigationBar
}
private var bottomBarItemsContainer: UIView? {
if #available(iOS 26, *) {
view.subviews.first?.subviews.last?.subviews.first
@@ -33,8 +36,13 @@ class TimelineMediaPreviewController: QLPreviewController {
}
}
private var pageScrollView: UIScrollView? { view.firstScrollView() }
private var captionView: UIView { captionHostingController.view }
private var pageScrollView: UIScrollView? {
view.firstScrollView()
}
private var captionView: UIView {
captionHostingController.view
}
override var overrideUserInterfaceStyle: UIUserInterfaceStyle {
get { .dark }
@@ -255,7 +263,9 @@ class TimelineMediaPreviewController: QLPreviewController {
private struct HeaderView: View {
@ObservedObject var context: TimelineMediaPreviewViewModel.Context
private var currentItem: TimelineMediaPreviewItem { context.viewState.currentItem }
private var currentItem: TimelineMediaPreviewItem {
context.viewState.currentItem
}
var body: some View {
switch currentItem {
@@ -281,7 +291,9 @@ private struct HeaderView: View {
private struct DetailsButton: View {
@ObservedObject var context: TimelineMediaPreviewViewModel.Context
private var currentItem: TimelineMediaPreviewItem { context.viewState.currentItem }
private var currentItem: TimelineMediaPreviewItem {
context.viewState.currentItem
}
var isHidden: Bool {
switch currentItem {
@@ -301,7 +313,9 @@ private struct DetailsButton: View {
private struct CaptionView: View {
@ObservedObject var context: TimelineMediaPreviewViewModel.Context
private var currentItem: TimelineMediaPreviewItem { context.viewState.currentItem }
private var currentItem: TimelineMediaPreviewItem {
context.viewState.currentItem
}
var body: some View {
if case let .media(mediaItem) = currentItem, let caption = mediaItem.caption {
@@ -323,7 +337,9 @@ private struct CaptionView: View {
private struct DownloadIndicatorView: View {
@ObservedObject var context: TimelineMediaPreviewViewModel.Context
private var currentItem: TimelineMediaPreviewItem { context.viewState.currentItem }
private var currentItem: TimelineMediaPreviewItem {
context.viewState.currentItem
}
private var shouldShowDownloadIndicator: Bool {
switch currentItem {

View File

@@ -11,7 +11,9 @@ import SwiftUI
struct TimelineMediaPreviewFileExportPicker: UIViewControllerRepresentable {
struct File: Identifiable {
let url: URL
var id: String { url.absoluteString }
var id: String {
url.absoluteString
}
}
let file: File

View File

@@ -57,7 +57,6 @@ struct TimelineMediaPreviewRedactConfirmationView: View {
.padding(.horizontal, 24)
}
@ViewBuilder
private var preview: some View {
HStack(spacing: 12) {
if let mediaSource = item.thumbnailMediaSource {

View File

@@ -130,7 +130,7 @@ struct HomeScreenViewState: BindableState {
}
}
// Used to hide all the rooms when the search field is focused and the query is empty
/// Used to hide all the rooms when the search field is focused and the query is empty
var shouldHideRoomList: Bool {
bindings.isSearchFieldFocused && bindings.searchQuery.isEmpty
}

View File

@@ -29,7 +29,9 @@ private struct BloomModifier: ViewModifier {
@State private var height = CGFloat.zero
private var endPointY: CGFloat { hasSearchBar ? 0.35 : 0.55 }
private var endPointY: CGFloat {
hasSearchBar ? 0.35 : 0.55
}
func body(content: Content) -> some View {
content
@@ -102,7 +104,9 @@ private struct OldBloomModifier: ViewModifier {
return bloom
}
private var endPointY: CGFloat { hasSearchBar ? 0.5 : 0.7 }
private var endPointY: CGFloat {
hasSearchBar ? 0.5 : 0.7
}
private var bloomGradient: some View {
LinearGradient(gradient: .compound.subtle,
@@ -117,9 +121,9 @@ private struct OldBloomModifier: ViewModifier {
bloom.colorScheme == colorScheme && bloom.baseColor == .compound.gradientSubtleStop1
}
// This is a class to avoid a "Modifying state during view update" warning when storing
// the result on the same run-loop - we want to avoid dispatching that to the next loop as
// that can result in further (unnecessary) renders being made.
/// This is a class to avoid a "Modifying state during view update" warning when storing
/// the result on the same run-loop - we want to avoid dispatching that to the next loop as
/// that can result in further (unnecessary) renders being made.
class Bloom {
var image: UIImage?
var colorScheme: ColorScheme?

View File

@@ -8,7 +8,6 @@
import Combine
import Foundation
import MatrixRustSDK
import OrderedCollections

View File

@@ -15,7 +15,9 @@ struct RoomListFiltersView: View {
/// When you connect a mouse on macOS the scrollbars aren't hidden. This is some extra padding
/// applied to the scroll view content to make sure the bars don't overlap the filters.
private var macScrollBarPadding: CGFloat { ProcessInfo.processInfo.isiOSAppOnMac ? 16 : 0 }
private var macScrollBarPadding: CGFloat {
ProcessInfo.processInfo.isiOSAppOnMac ? 16 : 0
}
var body: some View {
ScrollViewReader { proxy in

View File

@@ -92,7 +92,6 @@ struct HomeScreenInviteCell: View {
}
}
@ViewBuilder
private var textualContent: some View {
VStack(alignment: .leading, spacing: 0) {
Text(title)

View File

@@ -65,7 +65,6 @@ struct HomeScreenKnockedCell: View {
}
}
@ViewBuilder
private var textualContent: some View {
VStack(alignment: .leading, spacing: 0) {
Text(title)

View File

@@ -76,7 +76,6 @@ struct HomeScreenRoomCell: View {
}
}
@ViewBuilder
private var header: some View {
HStack(alignment: .top, spacing: 16) {
Text(room.name)
@@ -93,7 +92,6 @@ struct HomeScreenRoomCell: View {
}
}
@ViewBuilder
private var footer: some View {
HStack(alignment: .firstTextBaseline, spacing: 0) {
ZStack(alignment: .topLeading) {

View File

@@ -20,7 +20,6 @@ struct HomeScreenRoomList: View {
}
}
@ViewBuilder
private var content: some View {
ForEach(context.viewState.visibleRooms) { room in
switch room.type {

View File

@@ -56,7 +56,6 @@ struct JoinRoomScreen: View {
}
}
@ViewBuilder
private var defaultView: some View {
VStack(spacing: 16) {
RoomAvatarImage(avatar: context.viewState.avatar ?? .room(id: "", name: nil, avatarURL: nil),
@@ -140,7 +139,6 @@ struct JoinRoomScreen: View {
}
}
@ViewBuilder
private var knockedView: some View {
VStack(spacing: 16) {
BigIcon(icon: \.checkCircleSolid, style: .successSolid)
@@ -157,7 +155,6 @@ struct JoinRoomScreen: View {
}
}
@ViewBuilder
private var knockMessage: some View {
VStack(alignment: .leading, spacing: 12) {
HStack(spacing: 0) {

View File

@@ -36,8 +36,8 @@ struct KnockRequestsListScreenViewState: BindableState {
var isKnockableRoom = true
var handledEventIDs: Set<String> = []
// If all the permissions are denied or the join rule changes while we are in the view
// we want to stop displaying any request
/// If all the permissions are denied or the join rule changes while we are in the view
/// we want to stop displaying any request
var shouldDisplayRequests: Bool {
!displayedRequests.isEmpty && isKnockableRoom && (canAccept || canDecline || canBan)
}

View File

@@ -80,7 +80,6 @@ struct KnockRequestCell: View {
}
}
@ViewBuilder
private var actions: some View {
VStack(spacing: 16) {
if onDecline != nil || onAccept != nil {
@@ -174,7 +173,9 @@ private struct DisclosableText: View {
}
extension KnockRequestCellInfo: Identifiable {
var id: String { eventID }
var id: String {
eventID
}
}
struct KnockRequestCell_Previews: PreviewProvider, TestablePreview {

Some files were not shown because too many files have changed in this diff Show More