Add SwiftFormat to the project. (#129)

* Run swiftformat for whitespace.
* Run swiftformat with some rules.
This commit is contained in:
Doug
2022-07-06 14:49:05 +01:00
committed by GitHub
parent 26d8affaa8
commit 02eb4b35e2
188 changed files with 759 additions and 717 deletions
+17
View File
@@ -0,0 +1,17 @@
--swiftversion 5.6
--exclude ElementX/Sources/Generated
--disable wrapMultiLineStatementBraces
--disable blankLinesAtStartOfScope
--disable blankLinesAtEndOfScope
--disable hoistPatternLet
--commas inline
--ifdef no-indent
--nospaceoperators ...,..<
--stripunusedargs closure-only
--trimwhitespace nonblank-lines
--wrapparameters after-first
--redundanttype inferred
--emptybraces spaced
+4 -4
View File
@@ -1,5 +1,5 @@
import Foundation
import Danger
import Foundation
SwiftLint.lint(inline: true)
@@ -19,7 +19,7 @@ if danger.github.pullRequest.body?.isEmpty ?? true {
let editedFiles = danger.git.modifiedFiles + danger.git.createdFiles
let changelogFiles = editedFiles.filter { $0.hasPrefix("changelog.d/") }
if editedFiles.count > 0 && changelogFiles.isEmpty {
if editedFiles.count > 0, changelogFiles.isEmpty {
warn("Please add a changelog.")
}
@@ -27,7 +27,7 @@ if editedFiles.count > 0 && changelogFiles.isEmpty {
if let ticketNumberRegex = try? NSRegularExpression(pattern: "#\\d+") {
let missingTicketNumber = !danger.git.commits.filter {
!$0.message.contains("vector-im/element-x-ios/issues/") &&
ticketNumberRegex.firstMatch(in: $0.message, options: [], range: .init(location: 0, length: $0.message.utf16.count)) == nil
ticketNumberRegex.firstMatch(in: $0.message, options: [], range: .init(location: 0, length: $0.message.utf16.count)) == nil
}.isEmpty
if missingTicketNumber {
@@ -63,7 +63,7 @@ if requiresSignOff {
!$0.message.contains(signOff)
}.isEmpty
if !hasPRBodySignOff && isMissingCommitsSignOff {
if !hasPRBodySignOff, isMissingCommitsSignOff {
fail("Please add a sign-off to either the PR description or to the commits themselves.")
}
}
@@ -1,4 +1,4 @@
//
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,8 +14,8 @@
// limitations under the License.
//
import SwiftUI
import DesignTokens
import SwiftUI
public extension ButtonStyle where Self == ElementActionButtonStyle {
/// The CTA button style as defined in Compound.
@@ -70,17 +70,17 @@ public struct ElementActionButtonStyle_Previews: PreviewProvider {
Button("Enabled") { /* preview */ }
.buttonStyle(ElementActionButtonStyle())
Button("Disabled") { /* preview */ }
Button("Disabled") { /* preview */ }
.buttonStyle(ElementActionButtonStyle())
.disabled(true)
Button { /* preview */ } label: {
Button { /* preview */ } label: {
Text("Clear BG")
.foregroundColor(.element.alert)
}
.buttonStyle(ElementActionButtonStyle(color: .clear))
Button("Red BG") { /* preview */ }
Button("Red BG") { /* preview */ }
.buttonStyle(ElementActionButtonStyle(color: .element.alert))
}
.padding()
@@ -14,8 +14,8 @@
// limitations under the License.
//
import SwiftUI
import DesignTokens
import SwiftUI
public extension ButtonStyle where Self == ElementGhostButtonStyle {
/// The Ghost button style as defined in Compound.
@@ -35,110 +35,111 @@ public class ElementSharedFonts {
/// Returns an instance of the font associated with the text style and scaled appropriately for the content size category defined in the trait collection.
/// Keep this method private method at the moment and create a DesignKit.Fonts.TextStyle if needed.
fileprivate func font(forTextStyle textStyle: UIFont.TextStyle, compatibleWith traitCollection: UITraitCollection? = nil) -> UIFont {
return UIFont.preferredFont(forTextStyle: textStyle, compatibleWith: traitCollection)
private func font(forTextStyle textStyle: UIFont.TextStyle, compatibleWith traitCollection: UITraitCollection? = nil) -> UIFont {
UIFont.preferredFont(forTextStyle: textStyle, compatibleWith: traitCollection)
}
}
// MARK: - Fonts protocol
extension ElementSharedFonts {
public extension ElementSharedFonts {
public var largeTitle: SharedFont {
var largeTitle: SharedFont {
let uiFont = font(forTextStyle: .largeTitle)
return SharedFont(uiFont: uiFont, font: .largeTitle)
}
public var largeTitleB: SharedFont {
var largeTitleB: SharedFont {
let uiFont = largeTitle.uiFont.bold
return SharedFont(uiFont: uiFont, font: .largeTitle.bold())
}
public var title1: SharedFont {
var title1: SharedFont {
let uiFont = font(forTextStyle: .title1)
return SharedFont(uiFont: uiFont, font: .title)
}
public var title1B: SharedFont {
var title1B: SharedFont {
let uiFont = title1.uiFont.bold
return SharedFont(uiFont: uiFont, font: .title.bold())
}
public var title2: SharedFont {
var title2: SharedFont {
let uiFont = font(forTextStyle: .title2)
return SharedFont(uiFont: uiFont, font: .title2)
}
public var title2B: SharedFont {
var title2B: SharedFont {
let uiFont = title2.uiFont.bold
return SharedFont(uiFont: uiFont, font: .title2.bold())
}
public var title3: SharedFont {
var title3: SharedFont {
let uiFont = font(forTextStyle: .title3)
return SharedFont(uiFont: uiFont, font: .title3)
}
public var title3SB: SharedFont {
var title3SB: SharedFont {
let uiFont = title3.uiFont.semiBold
return SharedFont(uiFont: uiFont, font: .title3.weight(.semibold))
}
public var headline: SharedFont {
var headline: SharedFont {
let uiFont = font(forTextStyle: .headline)
return SharedFont(uiFont: uiFont, font: .headline)
}
public var subheadline: SharedFont {
var subheadline: SharedFont {
let uiFont = font(forTextStyle: .subheadline)
return SharedFont(uiFont: uiFont, font: .subheadline)
}
public var body: SharedFont {
var body: SharedFont {
let uiFont = font(forTextStyle: .body)
return SharedFont(uiFont: uiFont, font: .body)
}
public var bodySB: SharedFont {
var bodySB: SharedFont {
let uiFont = body.uiFont.semiBold
return SharedFont(uiFont: uiFont, font: .body.weight(.semibold))
}
public var callout: SharedFont {
var callout: SharedFont {
let uiFont = font(forTextStyle: .callout)
return SharedFont(uiFont: uiFont, font: .callout)
}
public var calloutSB: SharedFont {
var calloutSB: SharedFont {
let uiFont = callout.uiFont.semiBold
return SharedFont(uiFont: uiFont, font: .callout.weight(.semibold))
}
public var footnote: SharedFont {
var footnote: SharedFont {
let uiFont = font(forTextStyle: .footnote)
return SharedFont(uiFont: uiFont, font: .footnote)
}
public var footnoteSB: SharedFont {
var footnoteSB: SharedFont {
let uiFont = footnote.uiFont.semiBold
return SharedFont(uiFont: uiFont, font: .footnote.weight(.semibold))
}
public var caption1: SharedFont {
var caption1: SharedFont {
let uiFont = font(forTextStyle: .caption1)
return SharedFont(uiFont: uiFont, font: .caption)
}
public var caption1SB: SharedFont {
var caption1SB: SharedFont {
let uiFont = caption1.uiFont.semiBold
return SharedFont(uiFont: uiFont, font: .caption.weight(.semibold))
}
public var caption2: SharedFont {
var caption2: SharedFont {
let uiFont = font(forTextStyle: .caption2)
return SharedFont(uiFont: uiFont, font: .caption2)
}
public var caption2SB: SharedFont {
var caption2SB: SharedFont {
let uiFont = caption2.uiFont.semiBold
return SharedFont(uiFont: uiFont, font: .caption2.weight(.semibold))
}
+4 -4
View File
@@ -1,4 +1,4 @@
//
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -44,14 +44,14 @@ public extension UIFont {
// MARK: - Shortcuts
var bold: UIFont {
return withTraits(.traitBold)
withTraits(.traitBold)
}
var semiBold: UIFont {
return withWeight(weight: .semibold)
withWeight(weight: .semibold)
}
var italic: UIFont {
return withTraits(.traitItalic)
withTraits(.traitItalic)
}
}
@@ -1,4 +1,4 @@
//
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -1,4 +1,4 @@
//
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +14,9 @@
// limitations under the License.
//
import SwiftUI
import DesignTokens
import Introspect
import SwiftUI
/// A bordered style of text input
///
@@ -48,7 +48,7 @@ public struct BorderedInputFieldStyle: TextFieldStyle {
}
private var backgroundColor: Color {
if !isEnabled && colorScheme == .dark {
if !isEnabled, colorScheme == .dark {
return .element.quinaryContent
}
return .element.background
@@ -14,8 +14,8 @@
// limitations under the License.
//
import SwiftUI
import DesignTokens
import SwiftUI
@available(iOS 15.0, *)
public extension TextFieldStyle where Self == ElementTextFieldStyle {
+1 -1
View File
@@ -1,5 +1,5 @@
import XCTest
@testable import DesignKit
import XCTest
final class DesignKitTests: XCTestCase {
func testExample() throws {
+23 -4
View File
@@ -130,6 +130,7 @@
62BBF5BE7B905222F0477FF2 /* MediaSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8210612D17A39369480FC183 /* MediaSource.swift */; };
63C9AF0FB8278AF1C0388A0C /* TemplateModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAB10E673916D2B8D21FD197 /* TemplateModels.swift */; };
6647430A45B4A8E692909A8F /* EmoteRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = F77C060C2ACC4CB7336A29E7 /* EmoteRoomTimelineItem.swift */; };
67C05C50AD734283374605E3 /* MatrixEntityRegex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AD1A853D605C2146B0DC028 /* MatrixEntityRegex.swift */; };
67E391A2E00709FB41903B36 /* MockMediaProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6920A4869821BF72FFC58842 /* MockMediaProvider.swift */; };
6832733838C57A7D3FE8FEB5 /* Introspect in Frameworks */ = {isa = PBXBuildFile; productRef = 04C28663564E008DB32B5972 /* Introspect */; };
684BDE198AE5AA1392288A73 /* SplashScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32CE6D4FF64C9A3C18619224 /* SplashScreen.swift */; };
@@ -279,7 +280,6 @@
EE8491AD81F47DF3C192497B /* DecorationTimelineItemProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 184CF8C196BE143AE226628D /* DecorationTimelineItemProtocol.swift */; };
EEC40663922856C65D1E0DF5 /* KeychainControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDB9C37196A4C79F24CE80C6 /* KeychainControllerTests.swift */; };
EF99A92701E401C4CD5ADC50 /* SplashScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCE978A6118C131D7F2A04B3 /* SplashScreenModels.swift */; };
F03E16ED043C62FED5A07AE0 /* MatrixEntityRegex.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B81C8227BBEA95CCE86037 /* MatrixEntityRegex.swift */; };
F040ABFEB0A2B142D948BA12 /* Untranslated.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = F75DF9500D69A3AAF8339E69 /* Untranslated.stringsdict */; };
F2DD8661B5C0BA2BB526FA6C /* KeychainControllerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CD51F9FDC91C231906D76C8 /* KeychainControllerProtocol.swift */; };
F4C3FEDB1B3A05376A1723A3 /* KeychainController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A4427F9E0571B4E6E048A2B /* KeychainController.swift */; };
@@ -479,6 +479,7 @@
6920A4869821BF72FFC58842 /* MockMediaProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockMediaProvider.swift; sourceTree = "<group>"; };
6A152791A2F56BD193BFE986 /* MemberDetailsProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemberDetailsProvider.swift; sourceTree = "<group>"; };
6A901D95158B02CA96C79C7F /* InfoPlist.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfoPlist.swift; sourceTree = "<group>"; };
6AD1A853D605C2146B0DC028 /* MatrixEntityRegex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MatrixEntityRegex.swift; sourceTree = "<group>"; };
6B73A8C3118EAC7BF3F3EE7A /* SplashScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplashScreenViewModelProtocol.swift; sourceTree = "<group>"; };
6D4777F0142E330A75C46FE4 /* SessionVerificationUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationUITests.swift; sourceTree = "<group>"; };
6DB53055CB130F0651C70763 /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/Localizable.strings; sourceTree = "<group>"; };
@@ -691,7 +692,6 @@
F6A8C632CEF4600107792899 /* TextRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextRoomTimelineItem.swift; sourceTree = "<group>"; };
F73FF1A33198F5FAE9D34B1F /* FormattedBodyText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormattedBodyText.swift; sourceTree = "<group>"; };
F77C060C2ACC4CB7336A29E7 /* EmoteRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmoteRoomTimelineItem.swift; sourceTree = "<group>"; };
F7B81C8227BBEA95CCE86037 /* MatrixEntityRegex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MatrixEntityRegex.swift; sourceTree = "<group>"; };
F9E785D5137510481733A3E8 /* TextRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextRoomTimelineView.swift; sourceTree = "<group>"; };
FA154570F693D93513E584C1 /* RoomMessageFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMessageFactory.swift; sourceTree = "<group>"; };
FAB10E673916D2B8D21FD197 /* TemplateModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateModels.swift; sourceTree = "<group>"; };
@@ -1443,7 +1443,7 @@
CF4B39D52CAE7D21D276ABEE /* ElementNavigationController.swift */,
1027BB9A852F445B7623897F /* ElementSettings.swift */,
12A626D74BBE9F4A60763B45 /* ImageAnonymizer.swift */,
F7B81C8227BBEA95CCE86037 /* MatrixEntityRegex.swift */,
6AD1A853D605C2146B0DC028 /* MatrixEntityRegex.swift */,
44BBB96FAA2F0D53C507396B /* Extensions */,
8F9A844EB44B6AD7CA18FD96 /* HTMLParsing */,
06501F0E978B2D5C92771DC7 /* Logging */,
@@ -1659,6 +1659,7 @@
isa = PBXNativeTarget;
buildConfigurationList = B15427F8699AD5A5FC75C17E /* Build configuration list for PBXNativeTarget "ElementX" */;
buildPhases = (
B35AB66424BB30087EEE408C /* 🧹 SwiftFormat */,
A7130911BCB2DF3D249A1836 /* 🛠 SwiftGen */,
9797D588420FCBBC228A63C9 /* Sources */,
215E1D91B98672C856F559D0 /* Resources */,
@@ -1886,6 +1887,24 @@
shellPath = /bin/sh;
shellScript = "export PATH=\"$PATH:/opt/homebrew/bin\"\nif which swiftgen >/dev/null; then\n swiftgen config run --config Tools/SwiftGen/swiftgen-config.yml\nelse\n echo \"warning: SwiftGen not installed, download from https://github.com/SwiftGen/SwiftGen\"\nfi\n";
};
B35AB66424BB30087EEE408C /* 🧹 SwiftFormat */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
name = "🧹 SwiftFormat";
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "export PATH=\"$PATH:/opt/homebrew/bin\"\nif which swiftformat >/dev/null; then\n swiftformat $PROJECT_DIR\nelse\n echo \"warning: SwiftFormat not installed, download from https://github.com/nicklockwood/SwiftFormat\"\nfi\n";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
@@ -1997,7 +2016,7 @@
2F30EFEB7BD39242D1AD96F3 /* LoginViewModelProtocol.swift in Sources */,
B94368839BDB69172E28E245 /* MXLog.swift in Sources */,
BCC3EDB7AD0902797CB4BBC2 /* MXLogger.m in Sources */,
F03E16ED043C62FED5A07AE0 /* MatrixEntityRegex.swift in Sources */,
67C05C50AD734283374605E3 /* MatrixEntityRegex.swift in Sources */,
EA1E7949533E19C6D862680A /* MediaProvider.swift in Sources */,
7002C55A4C917F3715765127 /* MediaProviderProtocol.swift in Sources */,
62BBF5BE7B905222F0477FF2 /* MediaSource.swift in Sources */,
+2 -1
View File
@@ -6,8 +6,8 @@
// Copyright © 2022 Element. All rights reserved.
//
import UIKit
import Combine
import UIKit
class AppCoordinator: AuthenticationCoordinatorDelegate, Coordinator {
private let window: UIWindow
@@ -149,6 +149,7 @@ class AppCoordinator: AuthenticationCoordinatorDelegate, Coordinator {
fatalError("Failed transition with context: \(context)")
}
}
// swiftlint:enable cyclomatic_complexity function_body_length
private func restoreUserSession() {
@@ -77,23 +77,23 @@ class AppCoordinatorStateMachine {
init() {
stateMachine = StateMachine(state: .initial) { machine in
machine.addRoutes(event: .startWithAuthentication, transitions: [ .initial => .signedOut ])
machine.addRoutes(event: .succeededSigningIn, transitions: [ .signedOut => .homeScreen ])
machine.addRoutes(event: .startWithAuthentication, transitions: [.initial => .signedOut])
machine.addRoutes(event: .succeededSigningIn, transitions: [.signedOut => .homeScreen])
machine.addRoutes(event: .startWithExistingSession, transitions: [ .initial => .restoringSession ])
machine.addRoutes(event: .succeededRestoringSession, transitions: [ .restoringSession => .homeScreen ])
machine.addRoutes(event: .failedRestoringSession, transitions: [ .restoringSession => .signedOut ])
machine.addRoutes(event: .startWithExistingSession, transitions: [.initial => .restoringSession])
machine.addRoutes(event: .succeededRestoringSession, transitions: [.restoringSession => .homeScreen])
machine.addRoutes(event: .failedRestoringSession, transitions: [.restoringSession => .signedOut])
machine.addRoutes(event: .attemptSignOut, transitions: [ .settingsScreen => .signingOut ])
machine.addRoutes(event: .attemptSignOut, transitions: [.settingsScreen => .signingOut])
machine.addRoutes(event: .succeededSigningOut, transitions: [ .signingOut => .signedOut ])
machine.addRoutes(event: .failedSigningOut, transitions: [ .signingOut => .settingsScreen ])
machine.addRoutes(event: .succeededSigningOut, transitions: [.signingOut => .signedOut])
machine.addRoutes(event: .failedSigningOut, transitions: [.signingOut => .settingsScreen])
machine.addRoutes(event: .showSettingsScreen, transitions: [ .homeScreen => .settingsScreen ])
machine.addRoutes(event: .dismissedSettingsScreen, transitions: [ .settingsScreen => .homeScreen ])
machine.addRoutes(event: .showSettingsScreen, transitions: [.homeScreen => .settingsScreen])
machine.addRoutes(event: .dismissedSettingsScreen, transitions: [.settingsScreen => .homeScreen])
machine.addRoutes(event: .showSessionVerificationScreen, transitions: [ .homeScreen => .sessionVerificationScreen ])
machine.addRoutes(event: .dismissedSessionVerificationScreen, transitions: [ .sessionVerificationScreen => .homeScreen ])
machine.addRoutes(event: .showSessionVerificationScreen, transitions: [.homeScreen => .sessionVerificationScreen])
machine.addRoutes(event: .dismissedSessionVerificationScreen, transitions: [.sessionVerificationScreen => .homeScreen])
// Transitions with associated values need to be handled through `addRouteMapping`
machine.addRouteMapping { event, fromState, _ in
+4 -6
View File
@@ -14,8 +14,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
private lazy var appCoordinator: Coordinator = isRunningUITests ? UITestsAppCoordinator() : AppCoordinator()
func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
// fixme: Use `Bundle.elementLanguage = ".."` when we have the functionality
// use `en` as fallback language
Bundle.elementFallbackLanguage = "en"
@@ -34,17 +32,17 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
private var isRunningUnitTests: Bool {
#if DEBUG
ProcessInfo.processInfo.environment["IS_RUNNING_UNIT_TESTS"] == "1"
ProcessInfo.processInfo.environment["IS_RUNNING_UNIT_TESTS"] == "1"
#else
false
false
#endif
}
private var isRunningUITests: Bool {
#if DEBUG
ProcessInfo.processInfo.environment["IS_RUNNING_UI_TESTS"] == "1"
ProcessInfo.processInfo.environment["IS_RUNNING_UI_TESTS"] == "1"
#else
false
false
#endif
}
}
+7 -3
View File
@@ -11,22 +11,26 @@ import Foundation
final class BuildSettings {
// MARK: - Servers
static let defaultHomeserverURLString = "https://matrix.org"
// MARK: - Bug report
static let bugReportServiceBaseUrlString = "https://riot.im/bugreports"
static let bugReportSentryEndpoint = "https://f39ac49e97714316965b777d9f3d6cd8@sentry.tools.element.io/44"
// Use the name allocated by the bug report server
static let bugReportApplicationId = "riot-ios"
static let bugReportUISIId = "element-auto-uisi"
static let bugReportGHLabels: [String] = ["Element-X"]
static let bugReportGHLabels = ["Element-X"]
// MARK: - Settings screen
static let settingsCrashButtonVisible: Bool = true
static let settingsShowTimelineStyle: Bool = true
static let settingsCrashButtonVisible = true
static let settingsShowTimelineStyle = true
// MARK: - Room screen
static let defaultRoomTimelineStyle: TimelineStyle = .bubbles
}
+2 -2
View File
@@ -9,9 +9,9 @@
import Foundation
struct Benchmark {
static private var trackingIdentifiers = [String: CFAbsoluteTime]()
private static var trackingIdentifiers = [String: CFAbsoluteTime]()
static public var trackingEnabled = false
public static var trackingEnabled = false
static func startTrackingForIdentifier(_ identifier: String, message: String? = nil) {
guard trackingEnabled else {
+52 -54
View File
@@ -2,25 +2,25 @@ import UIKit
// swiftlint:disable all
extension UIImage {
public convenience init?(blurHash: String, size: CGSize, punch: Float = 1) {
public extension UIImage {
convenience init?(blurHash: String, size: CGSize, punch: Float = 1) {
guard blurHash.count >= 6 else { return nil }
let sizeFlag = String(blurHash[0]).decode83()
let numY = (sizeFlag / 9) + 1
let numX = (sizeFlag % 9) + 1
let sizeFlag = String(blurHash[0]).decode83()
let numY = (sizeFlag / 9) + 1
let numX = (sizeFlag % 9) + 1
let quantisedMaximumValue = String(blurHash[1]).decode83()
let quantisedMaximumValue = String(blurHash[1]).decode83()
let maximumValue = Float(quantisedMaximumValue + 1) / 166
guard blurHash.count == 4 + 2 * numX * numY else { return nil }
let colours: [(Float, Float, Float)] = (0 ..< numX * numY).map { i in
let colours: [(Float, Float, Float)] = (0..<numX * numY).map { i in
if i == 0 {
let value = String(blurHash[2 ..< 6]).decode83()
let value = String(blurHash[2..<6]).decode83()
return decodeDC(value)
} else {
let value = String(blurHash[4 + i * 2 ..< 4 + i * 2 + 2]).decode83()
let value = String(blurHash[4 + i * 2..<4 + i * 2 + 2]).decode83()
return decodeAC(value, maximumValue: maximumValue * punch)
}
}
@@ -32,14 +32,14 @@ extension UIImage {
CFDataSetLength(data, bytesPerRow * height)
guard let pixels = CFDataGetMutableBytePtr(data) else { return nil }
for y in 0 ..< height {
for x in 0 ..< width {
for y in 0..<height {
for x in 0..<width {
var r: Float = 0
var g: Float = 0
var b: Float = 0
for j in 0 ..< numY {
for i in 0 ..< numX {
for j in 0..<numY {
for i in 0..<numX {
let basis = cos(Float.pi * Float(x) * Float(i) / Float(width)) * cos(Float.pi * Float(y) * Float(j) / Float(height))
let colour = colours[i + j * numX]
r += colour.0 * basis
@@ -62,7 +62,7 @@ extension UIImage {
guard let provider = CGDataProvider(data: data) else { return nil }
guard let cgImage = CGImage(width: width, height: height, bitsPerComponent: 8, bitsPerPixel: 24, bytesPerRow: bytesPerRow,
space: CGColorSpaceCreateDeviceRGB(), bitmapInfo: bitmapInfo, provider: provider, decode: nil, shouldInterpolate: true, intent: .defaultIntent) else { return nil }
space: CGColorSpaceCreateDeviceRGB(), bitmapInfo: bitmapInfo, provider: provider, decode: nil, shouldInterpolate: true, intent: .defaultIntent) else { return nil }
self.init(cgImage: cgImage)
}
@@ -76,21 +76,21 @@ private func decodeDC(_ value: Int) -> (Float, Float, Float) {
}
private func decodeAC(_ value: Int, maximumValue: Float) -> (Float, Float, Float) {
let quantR = value / (19 * 19)
let quantG = (value / 19) % 19
let quantB = value % 19
let quantR = value / (19 * 19)
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
)
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 rgb
}
private func signPow(_ value: Float, _ exp: Float) -> Float {
return copysign(pow(abs(value), exp), value)
copysign(pow(abs(value), exp), value)
}
private func linearTosRGB(_ value: Float) -> Int {
@@ -105,46 +105,44 @@ private func sRGBToLinear<Type: BinaryInteger>(_ value: Type) -> Float {
else { return pow((v + 0.055) / 1.055, 2.4) }
}
private let encodeCharacters: [String] = {
return "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz#$%*+,-.:;=?@[]^_{|}~".map { String($0) }
}()
private let encodeCharacters: [String] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz#$%*+,-.:;=?@[]^_{|}~".map { String($0) }
private let decodeCharacters: [String: Int] = {
var dict: [String: Int] = [:]
for (index, character) in encodeCharacters.enumerated() {
dict[character] = index
}
return dict
var dict: [String: Int] = [:]
for (index, character) in encodeCharacters.enumerated() {
dict[character] = index
}
return dict
}()
extension String {
func decode83() -> Int {
var value: Int = 0
for character in self {
if let digit = decodeCharacters[String(character)] {
value = value * 83 + digit
}
}
return value
}
func decode83() -> Int {
var value = 0
for character in self {
if let digit = decodeCharacters[String(character)] {
value = value * 83 + digit
}
}
return value
}
}
private extension String {
subscript (offset: Int) -> Character {
return self[index(startIndex, offsetBy: offset)]
}
subscript(offset: Int) -> Character {
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: 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 {
let start = index(startIndex, offsetBy: bounds.lowerBound)
let end = index(startIndex, offsetBy: bounds.upperBound)
return self[start..<end]
}
subscript(bounds: CountableRange<Int>) -> Substring {
let start = index(startIndex, offsetBy: bounds.lowerBound)
let end = index(startIndex, offsetBy: bounds.upperBound)
return self[start..<end]
}
}
// swiftlint:enable all
+1 -1
View File
@@ -47,6 +47,6 @@ extension Coordinator {
}
func remove(childCoordinator: Coordinator) {
self.childCoordinators = self.childCoordinators.filter { $0 !== childCoordinator }
childCoordinators = childCoordinators.filter { $0 !== childCoordinator }
}
}
@@ -36,15 +36,15 @@ public extension Bundle {
}
/// Preferred languages in the priority order.
static private(set) var preferredLanguages: [String] = calculatePreferredLanguages()
private(set) static var preferredLanguages: [String] = calculatePreferredLanguages()
private static func calculatePreferredLanguages() -> [String] {
var set = Set<String>()
return ([Bundle.elementLanguage] +
Locale.preferredLanguages +
[Bundle.elementFallbackLanguage])
.compactMap { $0 }
.filter { set.insert($0).inserted }
Locale.preferredLanguages +
[Bundle.elementFallbackLanguage])
.compactMap { $0 }
.filter { set.insert($0).inserted }
}
}
@@ -1,4 +1,4 @@
//
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -6,8 +6,8 @@
// Copyright © 2022 Element. All rights reserved.
//
import Foundation
import DTCoreText
import Foundation
struct AttributedStringBuilder: AttributedStringBuilderProtocol {
@@ -55,8 +55,8 @@ struct AttributedStringBuilder: AttributedStringBuilderProtocol {
func fromHTML(_ htmlString: String?) -> AttributedString? {
guard let htmlString = htmlString,
let data = htmlString.data(using: .utf8) else {
return nil
}
return nil
}
let defaultFont = UIFont.preferredFont(forTextStyle: .body)
@@ -65,7 +65,7 @@ struct AttributedStringBuilder: AttributedStringBuilderProtocol {
DTDefaultFontFamily: defaultFont.familyName,
DTDefaultFontName: defaultFont.fontName,
DTDefaultFontSize: defaultFont.pointSize,
DTDefaultStyleSheet: DTCSSStylesheet(styleBlock: self.defaultCSS) as Any
DTDefaultStyleSheet: DTCSSStylesheet(styleBlock: defaultCSS) as Any
]
guard let builder = DTHTMLAttributedStringBuilder(html: data, options: parsingOptions, documentAttributes: nil) else {
@@ -96,7 +96,7 @@ struct AttributedStringBuilder: AttributedStringBuilderProtocol {
return nil
}
return attributedString.runs[\.blockquote].map { (value, range) in
return attributedString.runs[\.blockquote].map { value, range in
var attributedString = AttributedString(attributedString[range])
// Remove trailing new lines if any
@@ -119,8 +119,8 @@ struct AttributedStringBuilder: AttributedStringBuilderProtocol {
guard let value = value as? NSArray,
let dtTextBlock = value.firstObject as? DTTextBlock,
dtTextBlock.backgroundColor == temporaryBlockquoteMarkingColor else {
return
}
return
}
attributedString.addAttribute(.MXBlockquote, value: true, range: range)
}
@@ -128,8 +128,8 @@ struct AttributedStringBuilder: AttributedStringBuilderProtocol {
attributedString.enumerateAttribute(.backgroundColor, in: .init(location: 0, length: attributedString.length), options: []) { value, range, _ in
guard let value = value as? UIColor,
value == temporaryBlockquoteMarkingColor else {
return
}
return
}
attributedString.removeAttribute(.backgroundColor, range: range)
attributedString.addAttribute(.MXBlockquote, value: true, range: range)
@@ -212,22 +212,22 @@ struct AttributedStringBuilder: AttributedStringBuilderProtocol {
}
private var defaultCSS: String {
"""
blockquote {
background: \(temporaryBlockquoteMarkingColor.toHexString());
display: block;
}
pre,code {
background-color: \(temporaryCodeBlockMarkingColor.toHexString());
display: inline;
font-family: monospace;
white-space: pre;
-coretext-fontname: Menlo-Regular;
}
h1,h2,h3 {
font-size: 1.2em;
}
"""
"""
blockquote {
background: \(temporaryBlockquoteMarkingColor.toHexString());
display: block;
}
pre,code {
background-color: \(temporaryCodeBlockMarkingColor.toHexString());
display: inline;
font-family: monospace;
white-space: pre;
-coretext-fontname: Menlo-Regular;
}
h1,h2,h3 {
font-size: 1.2em;
}
"""
}
}
@@ -240,7 +240,7 @@ extension UIColor {
getRed(&red, green: &green, blue: &blue, alpha: &alpha)
let rgb: Int = (Int)(red*255)<<16 | (Int)(green*255)<<8 | (Int)(blue*255)<<0
let rgb = Int(red * 255) << 16 | Int(green * 255) << 8 | Int(blue * 255) << 0
return NSString(format: "#%06x", rgb) as String
}
@@ -6,8 +6,8 @@
// Copyright © 2022 Element. All rights reserved.
//
import Foundation
import DTCoreText
import Foundation
public extension DTHTMLElement {
/// Sanitize the element using the given parameters.
@@ -26,6 +26,6 @@ extension AttributeScopes {
extension AttributeDynamicLookup {
subscript<T: AttributedStringKey>(dynamicMember keyPath: KeyPath<AttributeScopes.ElementXAttributes, T>) -> T {
return self[T.self]
self[T.self]
}
}
+3 -3
View File
@@ -7,14 +7,14 @@
//
import Foundation
import Vision
import UIKit
import Vision
enum ImageAnonymizerError: Error {
case noCgImageBased
}
struct ImageAnonymizer {
enum ImageAnonymizer {
private static var allowedTextItems: [String] = [
"#",
@@ -96,7 +96,7 @@ struct ImageAnonymizer {
continue
}
if let textObservation = observation as? VNRecognizedTextObservation,
let text = textObservation.topCandidates(1).first?.string {
let text = textObservation.topCandidates(1).first?.string {
if Double(text) != nil || Self.allowedTextItems.contains(text) {
continue
}
+7 -7
View File
@@ -21,10 +21,10 @@ import SwiftyBeaver
@objc public class MXLogConfiguration: NSObject {
/// the desired log level. `.verbose` by default.
@objc public var logLevel: MXLogLevel = MXLogLevel.verbose
@objc public var logLevel = MXLogLevel.verbose
/// whether logs should be written directly to files. `false` by default.
@objc public var redirectLogsToFiles: Bool = false
@objc public var redirectLogsToFiles = false
/// the maximum total space to use for log files in bytes. `100MB` by default.
@objc public var logFilesSizeLimit: UInt = 100 * 1024 * 1024 // 100MB
@@ -64,7 +64,7 @@ private var logger: SwiftyBeaver.Type = {
/// Please see `MXLogConfiguration` for all available options.
/// - Parameters:
/// - configuration: the `MXLogConfiguration` instance to use
@objc static public func configure(_ configuration: MXLogConfiguration) {
@objc public static func configure(_ configuration: MXLogConfiguration) {
configureLogger(logger, withConfiguration: configuration)
}
@@ -107,8 +107,8 @@ private var logger: SwiftyBeaver.Type = {
logger.info(message, file, function, line: line)
}
public static func warning(_ message: @autoclosure () -> Any, _
file: String = #file,
public static func warning(_ message: @autoclosure () -> Any,
_ file: String = #file,
_ function: String = #function,
line: Int = #line,
context: Any? = nil) {
@@ -133,8 +133,8 @@ private var logger: SwiftyBeaver.Type = {
logger.error(message, file, function, line: line)
}
public static func failure(_ message: @autoclosure () -> Any, _
file: String = #file,
public static func failure(_ message: @autoclosure () -> Any,
_ file: String = #file,
_ function: String = #function,
line: Int = #line,
context: Any? = nil) {
@@ -1,4 +1,4 @@
//
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -30,7 +30,7 @@ struct NavigationModule {
extension NavigationModule: CustomStringConvertible {
var description: String {
return "NavigationModule: \(presentable), pop completion: \(String(describing: popCompletion))"
"NavigationModule: \(presentable), pop completion: \(String(describing: popCompletion))"
}
}
@@ -23,7 +23,7 @@ final class NavigationRouter: NSObject, NavigationRouterType {
// MARK: Private
private var completions: [UIViewController : () -> Void]
private var completions: [UIViewController: () -> Void]
private let navigationController: UINavigationController
/// Stores the association between the added Presentable and his view controller.
@@ -34,34 +34,34 @@ final class NavigationRouter: NSObject, NavigationRouterType {
/// Returns the presentables associated to each view controller
var modules: [Presentable] {
return self.viewControllers.map { (viewController) -> Presentable in
return self.module(for: viewController)
viewControllers.map { viewController -> Presentable in
self.module(for: viewController)
}
}
/// Return the view controllers stack
var viewControllers: [UIViewController] {
return navigationController.viewControllers
navigationController.viewControllers
}
// MARK: - Setup
init(navigationController: UINavigationController) {
self.navigationController = navigationController
self.completions = [:]
completions = [:]
super.init()
self.navigationController.delegate = self
// Post local notification on NavigationRouter creation
let userInfo: [String: Any] = [NavigationRouter.NotificationUserInfoKey.navigationRouter: self,
NavigationRouter.NotificationUserInfoKey.navigationController: navigationController]
NavigationRouter.NotificationUserInfoKey.navigationController: navigationController]
NotificationCenter.default.post(name: NavigationRouter.didCreate, object: self, userInfo: userInfo)
}
deinit {
// Post local notification on NavigationRouter deinit
let userInfo: [String: Any] = [NavigationRouter.NotificationUserInfoKey.navigationRouter: self,
NavigationRouter.NotificationUserInfoKey.navigationController: navigationController]
NavigationRouter.NotificationUserInfoKey.navigationController: navigationController]
NotificationCenter.default.post(name: NavigationRouter.willDestroy, object: self, userInfo: userInfo)
}
@@ -88,9 +88,9 @@ final class NavigationRouter: NSObject, NavigationRouterType {
return
}
self.addModule(module, for: controller)
addModule(module, for: controller)
let controllersToPop = self.navigationController.viewControllers.reversed()
let controllersToPop = navigationController.viewControllers.reversed()
controllersToPop.forEach {
self.willPopViewController($0)
@@ -100,7 +100,7 @@ final class NavigationRouter: NSObject, NavigationRouterType {
completions[controller] = popCompletion
}
self.willPushViewController(controller)
willPushViewController(controller)
navigationController.setViewControllers([controller], animated: animated)
navigationController.isNavigationBarHidden = hideNavigationBar
@@ -111,22 +111,22 @@ final class NavigationRouter: NSObject, NavigationRouterType {
}
// Add again controller to module association, in case same module instance is added back
self.addModule(module, for: controller)
addModule(module, for: controller)
self.didPushViewController(controller)
didPushViewController(controller)
}
func setModules(_ modules: [NavigationModule], hideNavigationBar: Bool, animated: Bool) {
MXLog.debug("[NavigationRouter] Set modules \(modules)")
let controllers = modules.map { (module) -> UIViewController in
let controllers = modules.map { module -> UIViewController in
let controller = module.presentable.toPresentable()
self.addModule(module.presentable, for: controller)
return controller
}
let controllersToPop = self.navigationController.viewControllers.reversed()
let controllersToPop = navigationController.viewControllers.reversed()
controllersToPop.forEach {
self.willPopViewController($0)
@@ -146,7 +146,7 @@ final class NavigationRouter: NSObject, NavigationRouterType {
}
// Add again controller to module association, in case same modules instance are added back
modules.forEach { (module) in
modules.forEach { module in
self.addModule(module.presentable, for: module.presentable.toPresentable())
}
@@ -158,7 +158,7 @@ final class NavigationRouter: NSObject, NavigationRouterType {
func popToRootModule(animated: Bool) {
MXLog.debug("[NavigationRouter] Pop to root module")
let controllers = self.navigationController.viewControllers
let controllers = navigationController.viewControllers
if controllers.count > 1 {
let controllersToPop = controllers[1..<controllers.count]
@@ -179,7 +179,7 @@ final class NavigationRouter: NSObject, NavigationRouterType {
MXLog.debug("[NavigationRouter] Pop to module \(module)")
let controller = module.toPresentable()
let controllersBeforePop = self.navigationController.viewControllers
let controllersBeforePop = navigationController.viewControllers
if let controllerIndex = controllersBeforePop.firstIndex(of: controller) {
let controllersToPop = controllersBeforePop[controllerIndex..<controllersBeforePop.count]
@@ -207,17 +207,17 @@ final class NavigationRouter: NSObject, NavigationRouterType {
return
}
self.addModule(module, for: controller)
addModule(module, for: controller)
if let completion = popCompletion {
completions[controller] = completion
}
self.willPushViewController(controller)
willPushViewController(controller)
navigationController.pushViewController(controller, animated: animated)
self.didPushViewController(controller)
didPushViewController(controller)
}
func push(_ modules: [NavigationModule], animated: Bool) {
@@ -231,22 +231,22 @@ final class NavigationRouter: NSObject, NavigationRouterType {
for module in modules {
let controller = module.presentable.toPresentable()
self.addModule(module.presentable, for: controller)
addModule(module.presentable, for: controller)
if let completion = module.popCompletion {
completions[controller] = completion
}
self.willPushViewController(controller)
willPushViewController(controller)
}
var viewControllers = navigationController.viewControllers
viewControllers.append(contentsOf: modules.map({ $0.presentable.toPresentable() }))
viewControllers.append(contentsOf: modules.map { $0.presentable.toPresentable() })
navigationController.setViewControllers(viewControllers, animated: animated)
for module in modules {
let controller = module.presentable.toPresentable()
self.didPushViewController(controller)
didPushViewController(controller)
}
}
@@ -254,22 +254,22 @@ final class NavigationRouter: NSObject, NavigationRouterType {
MXLog.debug("[NavigationRouter] Pop module")
if let lastController = navigationController.viewControllers.last {
self.willPopViewController(lastController)
willPopViewController(lastController)
}
if let controller = navigationController.popViewController(animated: animated) {
self.didPopViewController(controller)
didPopViewController(controller)
}
}
func popAllModules(animated: Bool) {
MXLog.debug("[NavigationRouter] Pop all modules")
let controllersToPop = self.navigationController.viewControllers.reversed()
let controllersToPop = navigationController.viewControllers.reversed()
controllersToPop.forEach {
self.willPopViewController($0)
}
}
navigationController.setViewControllers([], animated: animated)
@@ -281,31 +281,31 @@ final class NavigationRouter: NSObject, NavigationRouterType {
func contains(_ module: Presentable) -> Bool {
let controller = module.toPresentable()
return self.navigationController.viewControllers.contains(controller)
return navigationController.viewControllers.contains(controller)
}
// MARK: Presentable
func toPresentable() -> UIViewController {
return navigationController
navigationController
}
// MARK: - Private
private func module(for viewController: UIViewController) -> Presentable {
guard let module = self.storedModules[viewController] as? Presentable else {
guard let module = storedModules[viewController] as? Presentable else {
return viewController
}
return module
}
private func addModule(_ module: Presentable, for viewController: UIViewController) {
self.storedModules[viewController] = module as AnyObject
storedModules[viewController] = module as AnyObject
}
private func removeModule(for viewController: UIViewController) {
self.storedModules[viewController] = nil
storedModules[viewController] = nil
}
private func runCompletion(for controller: UIViewController) {
@@ -317,30 +317,30 @@ final class NavigationRouter: NSObject, NavigationRouterType {
}
private func willPushViewController(_ viewController: UIViewController) {
self.postNotification(withName: NavigationRouter.willPushModule, for: viewController)
postNotification(withName: NavigationRouter.willPushModule, for: viewController)
}
private func didPushViewController(_ viewController: UIViewController) {
self.postNotification(withName: NavigationRouter.didPushModule, for: viewController)
postNotification(withName: NavigationRouter.didPushModule, for: viewController)
}
private func willPopViewController(_ viewController: UIViewController) {
self.postNotification(withName: NavigationRouter.willPopModule, for: viewController)
postNotification(withName: NavigationRouter.willPopModule, for: viewController)
}
private func didPopViewController(_ viewController: UIViewController) {
self.postNotification(withName: NavigationRouter.didPopModule, for: viewController)
private func didPopViewController(_ viewController: UIViewController) {
postNotification(withName: NavigationRouter.didPopModule, for: viewController)
// Call completion closure associated to the view controller
// So associated coordinator can be deallocated
runCompletion(for: viewController)
self.removeModule(for: viewController)
removeModule(for: viewController)
}
private func postNotification(withName name: Notification.Name, for viewController: UIViewController) {
let module = self.module(for: viewController)
let module = module(for: viewController)
let userInfo: [String: Any] = [
NotificationUserInfoKey.navigationRouter: self,
@@ -352,6 +352,7 @@ final class NavigationRouter: NSObject, NavigationRouterType {
}
// MARK: - UINavigationControllerDelegate
extension NavigationRouter: UINavigationControllerDelegate {
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
@@ -363,17 +364,18 @@ extension NavigationRouter: UINavigationControllerDelegate {
// Ensure the view controller is popping
guard let poppedViewController = navigationController.transitionCoordinator?.viewController(forKey: .from),
!navigationController.viewControllers.contains(poppedViewController) else {
return
!navigationController.viewControllers.contains(poppedViewController) else {
return
}
MXLog.debug("[NavigationRouter] Popped module: \(poppedViewController)")
self.didPopViewController(poppedViewController)
didPopViewController(poppedViewController)
}
}
// MARK: - NavigationRouter notification constants
extension NavigationRouter {
// MARK: Notification names
@@ -388,7 +390,7 @@ extension NavigationRouter {
// MARK: Notification keys
public struct NotificationUserInfoKey {
public enum NotificationUserInfoKey {
/// The associated view controller (UIViewController).
static let viewController = "viewController"
@@ -1,4 +1,4 @@
//
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -25,7 +25,7 @@ class NavigationRouterStore: NavigationRouterStoreProtocol {
// MARK: - Properties
// WeakDictionary does not work with protocol
// WeakDictionary does not work with protocol
// Find a way to use NavigationRouterType as value
private var navigationRouters = WeakDictionary<UINavigationController, NavigationRouter>()
@@ -33,14 +33,14 @@ class NavigationRouterStore: NavigationRouterStoreProtocol {
/// As we are ensuring that there is only one navigation controller per NavigationRouter, the class here should be used as a singleton.
private init() {
self.registerNavigationRouterNotifications()
registerNavigationRouterNotifications()
}
// MARK: - Public
func navigationRouter(for navigationController: UINavigationController) -> NavigationRouterType {
if let existingNavigationRouter = self.findNavigationRouter(for: navigationController) {
if let existingNavigationRouter = findNavigationRouter(for: navigationController) {
return existingNavigationRouter
}
@@ -51,11 +51,11 @@ class NavigationRouterStore: NavigationRouterStoreProtocol {
// MARK: - Private
private func findNavigationRouter(for navigationController: UINavigationController) -> NavigationRouterType? {
return self.navigationRouters[navigationController]
navigationRouters[navigationController]
}
private func removeNavigationRouter(for navigationController: UINavigationController) {
self.navigationRouters[navigationController] = nil
navigationRouters[navigationController] = nil
}
private func registerNavigationRouterNotifications() {
@@ -71,12 +71,12 @@ class NavigationRouterStore: NavigationRouterStoreProtocol {
return
}
if let existingNavigationRouter = self.findNavigationRouter(for: navigationController) {
if let existingNavigationRouter = findNavigationRouter(for: navigationController) {
fatalError("\(existingNavigationRouter) is already tied to the same navigation controller as \(navigationRouter). We should have only one NavigationRouter per navigation controller")
} else {
// WeakDictionary does not work with protocol
// Find a way to avoid this cast
self.navigationRouters[navigationController] = navigationRouter as? NavigationRouter
navigationRouters[navigationController] = navigationRouter as? NavigationRouter
}
}
@@ -87,10 +87,10 @@ class NavigationRouterStore: NavigationRouterStoreProtocol {
return
}
if let existingNavigationRouter = self.findNavigationRouter(for: navigationController), existingNavigationRouter !== navigationRouter {
if let existingNavigationRouter = findNavigationRouter(for: navigationController), existingNavigationRouter !== navigationRouter {
fatalError("\(existingNavigationRouter) is already tied to the same navigation controller as \(navigationRouter). We should have only one NavigationRouter per navigation controller")
}
self.removeNavigationRouter(for: navigationController)
removeNavigationRouter(for: navigationController)
}
}
@@ -1,4 +1,4 @@
//
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -24,7 +24,7 @@ protocol Presentable {
extension UIViewController: Presentable {
public func toPresentable() -> UIViewController {
return self
self
}
}
@@ -33,7 +33,7 @@ extension Presentable {
/// Returns a new module from the presentable without a pop completion block
/// - Returns: Module
func toModule() -> NavigationModule {
return NavigationModule(presentable: self, popCompletion: nil)
NavigationModule(presentable: self, popCompletion: nil)
}
}
+10 -10
View File
@@ -33,9 +33,9 @@ final class RootRouter: RootRouterType {
let window: UIWindow
/// The root view controller currently presented
/// The root view controller currently presented
var rootViewController: UIViewController? {
return self.window.rootViewController
window.rootViewController
}
// MARK: - Setup
@@ -47,23 +47,23 @@ final class RootRouter: RootRouterType {
// MARK: - Public methods
func setRootModule(_ module: Presentable) {
self.updateRootViewController(rootViewController: module.toPresentable(), animated: false, completion: nil)
self.window.makeKeyAndVisible()
updateRootViewController(rootViewController: module.toPresentable(), animated: false, completion: nil)
window.makeKeyAndVisible()
}
func dismissRootModule(animated: Bool, completion: (() -> Void)?) {
self.updateRootViewController(rootViewController: nil, animated: animated, completion: completion)
updateRootViewController(rootViewController: nil, animated: animated, completion: completion)
}
func presentModule(_ module: Presentable, animated: Bool, completion: (() -> Void)?) {
let viewControllerPresenter = self.rootViewController?.presentedViewController ?? self.rootViewController
let viewControllerPresenter = rootViewController?.presentedViewController ?? rootViewController
viewControllerPresenter?.present(module.toPresentable(), animated: animated, completion: completion)
self.presentedModule = module
presentedModule = module
}
func dismissModule(animated: Bool, completion: (() -> Void)?) {
self.presentedModule?.toPresentable().dismiss(animated: animated, completion: completion)
presentedModule?.toPresentable().dismiss(animated: animated, completion: completion)
}
// MARK: - Private methods
@@ -76,11 +76,11 @@ final class RootRouter: RootRouterType {
UIView.setAnimationsEnabled(false)
self.window.rootViewController = rootViewController
UIView.setAnimationsEnabled(oldState)
}, completion: { (_: Bool) -> Void in
}, completion: { _ in
completion?()
})
} else {
self.window.rootViewController = rootViewController
window.rootViewController = rootViewController
completion?()
}
}
@@ -19,12 +19,12 @@ import UIKit
/// Protocol describing a router that wraps the root navigation of the application.
/// Routers are used to be passed between coordinators. They handles only `physical` navigation.
@MainActor
protocol RootRouterType: AnyObject {
protocol RootRouterType: AnyObject {
/// Update the root view controller
///
/// - Parameter module: The new root view controller to set
func setRootModule(_ module: Presentable)
func setRootModule(_ module: Presentable)
/// Dismiss the root view controller
///
@@ -1,4 +1,4 @@
//
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -1,4 +1,4 @@
//
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -1,4 +1,4 @@
//
//
// Copyright 2022 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,9 @@
import SwiftUI
// swiftlint:disable private_over_fileprivate
/// Positions this view within an invisible frame that fills the width of its parent view,
/// whilst limiting the width of the content to a readable size (which is customizable).
fileprivate struct ReadableFrameModifier: ViewModifier {
private struct ReadableFrameModifier: ViewModifier {
var maxWidth: CGFloat
func body(content: Content) -> some View {
@@ -1,4 +1,4 @@
//
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -1,4 +1,4 @@
//
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -27,9 +27,7 @@ extension BindableState where BindStateType == Void {
/// We provide a default implementation for the Void type so that we can have `ViewState` that
/// just doesn't include/take advantage of the bindings.
var bindings: Void {
get {
}
get { }
set {
fatalError("Can't bind to the default Void binding.")
}
@@ -14,8 +14,8 @@
// limitations under the License.
//
import Foundation
import Combine
import Foundation
/// A constrained and concise interface for interacting with the ViewModel.
///
@@ -96,8 +96,8 @@ class StateStoreViewModel<State: BindableState, ViewAction> {
// MARK: Setup
init(initialViewState: State) {
self.context = Context(initialViewState: initialViewState)
self.context.viewActions.sink { [weak self] action in
context = Context(initialViewState: initialViewState)
context.viewActions.sink { [weak self] action in
guard let self = self else { return }
Task { await self.process(viewAction: action) }
@@ -52,7 +52,7 @@ final class ActivityIndicatorPresenter: ActivityIndicatorPresenterType {
view.isUserInteractionEnabled = false
let backgroundOverlayView = self.createBackgroundOverlayView(with: view.frame)
let backgroundOverlayView = createBackgroundOverlayView(with: view.frame)
let activityIndicatorView = ActivityIndicatorView()
@@ -89,9 +89,9 @@ final class ActivityIndicatorPresenter: ActivityIndicatorPresenterType {
}
func removeCurrentActivityIndicator(animated: Bool, completion: (() -> Void)? = nil) {
guard let presentingView = self.presentingView,
let backgroundOverlayView = self.backgroundOverlayView,
let activityIndicatorView = self.activityIndicatorView else {
guard let presentingView = presentingView,
let backgroundOverlayView = backgroundOverlayView,
let activityIndicatorView = activityIndicatorView else {
return
}
@@ -29,23 +29,23 @@ final class ActivityIndicatorView: UIView {
// MARK: Outlets
@IBOutlet private weak var activityIndicatorView: UIActivityIndicatorView!
@IBOutlet private weak var activityIndicatorBackgroundView: UIView!
@IBOutlet private var activityIndicatorView: UIActivityIndicatorView!
@IBOutlet private var activityIndicatorBackgroundView: UIView!
// MARK: Public
var color: UIColor? {
get {
return activityIndicatorView.color
activityIndicatorView.color
}
set {
set {
activityIndicatorView.color = newValue
}
}
// MARK: - Setup
private func commonInit() {
private func commonInit() {
activityIndicatorBackgroundView.layer.masksToBounds = true
}
@@ -68,8 +68,8 @@ final class ActivityIndicatorView: UIView {
// MARK: - Overrides
override var intrinsicContentSize: CGSize {
return CGSize(width: activityIndicatorView.intrinsicContentSize.width + Constants.activityIndicatorMargin.width,
height: activityIndicatorView.intrinsicContentSize.height + Constants.activityIndicatorMargin.height)
CGSize(width: activityIndicatorView.intrinsicContentSize.width + Constants.activityIndicatorMargin.width,
height: activityIndicatorView.intrinsicContentSize.height + Constants.activityIndicatorMargin.height)
}
override func layoutSubviews() {
@@ -91,22 +91,22 @@ final class ActivityIndicatorView: UIView {
private extension UIView {
static var nib: UINib {
return UINib(nibName: String(describing: self), bundle: Bundle(for: self))
UINib(nibName: String(describing: self), bundle: Bundle(for: self))
}
func loadNibContent() {
let layoutAttributes: [NSLayoutConstraint.Attribute] = [.top, .leading, .bottom, .trailing]
for case let view as UIView in type(of: self).nib.instantiate(withOwner: self, options: nil) {
view.translatesAutoresizingMaskIntoConstraints = false
addSubview(view)
NSLayoutConstraint.activate(layoutAttributes.map { attribute in
NSLayoutConstraint(
item: view, attribute: attribute,
relatedBy: .equal,
toItem: self, attribute: attribute,
multiplier: 1, constant: 0.0
)
})
}
let layoutAttributes: [NSLayoutConstraint.Attribute] = [.top, .leading, .bottom, .trailing]
for case let view as UIView in type(of: self).nib.instantiate(withOwner: self, options: nil) {
view.translatesAutoresizingMaskIntoConstraints = false
addSubview(view)
NSLayoutConstraint.activate(layoutAttributes.map { attribute in
NSLayoutConstraint(
item: view, attribute: attribute,
relatedBy: .equal,
toItem: self, attribute: attribute,
multiplier: 1, constant: 0.0
)
})
}
}
}
@@ -1,4 +1,4 @@
//
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -1,4 +1,4 @@
//
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -49,15 +49,14 @@ final class LabelledActivityIndicatorView: UIView {
return view
}()
private let label: UILabel = {
UILabel()
}()
private let label = UILabel()
init(text: String) {
super.init(frame: .zero)
setup(text: text)
}
@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@@ -1,4 +1,4 @@
//
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,7 +20,7 @@ import UIKit
class RectangleToastView: UIView {
private enum Constants {
static let padding: UIEdgeInsets = UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16)
static let padding = UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16)
static let cornerRadius: CGFloat = 8.0
}
@@ -81,6 +81,7 @@ class RectangleToastView: UIView {
layer.masksToBounds = true
}
@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@@ -1,4 +1,4 @@
//
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,7 +23,7 @@ class RoundedToastView: UIView {
let opacity: Float
}
private struct Constants {
private enum Constants {
static let padding = UIEdgeInsets(top: 10, left: 12, bottom: 10, right: 12)
static let activityIndicatorScale = CGFloat(0.75)
static let imageViewSize = CGFloat(15)
@@ -57,15 +57,14 @@ class RoundedToastView: UIView {
return stack
}()
private let label: UILabel = {
UILabel()
}()
private let label = UILabel()
init(viewState: ToastViewState) {
super.init(frame: .zero)
setup(viewState: viewState)
}
@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@@ -1,4 +1,4 @@
//
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,7 +19,7 @@ import UIKit
/// A presenter responsible for showing / hiding a toast view for loading spinners or success messages.
/// It is managed by an `UserIndicator`, meaning the `present` and `dismiss` methods will be called when the parent `UserIndicator` starts or completes.
class ToastViewPresenter: UserIndicatorViewPresentable {
struct Constants {
enum Constants {
static let navigationBarPatting = CGFloat(10)
}
@@ -1,4 +1,4 @@
//
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -1,4 +1,4 @@
//
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -1,4 +1,4 @@
//
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -1,4 +1,4 @@
//
//
// Copyright 2022 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -1,4 +1,4 @@
//
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -1,4 +1,4 @@
//
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -1,4 +1,4 @@
//
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -1,4 +1,4 @@
//
//
// Copyright 2022 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -1,4 +1,4 @@
//
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,7 +18,7 @@ public struct WeakDictionary<Key: Hashable, Value: AnyObject> {
public init(dictionary: [Key: Value]) {
var newStorage = [Key: WeakDictionaryReference<Value>]()
dictionary.forEach({ key, value in newStorage[key] = WeakDictionaryReference<Value>(value: value) })
dictionary.forEach { key, value in newStorage[key] = WeakDictionaryReference<Value>(value: value) }
self.init(storage: newStorage)
}
@@ -31,7 +31,7 @@ public struct WeakDictionary<Key: Hashable, Value: AnyObject> {
}
public func weakDictionary() -> WeakDictionary<Key, Value> {
return self[startIndex ..< endIndex]
self[startIndex..<endIndex]
}
public func dictionary() -> [Key: Value] {
@@ -52,15 +52,15 @@ extension WeakDictionary: Collection {
public typealias Index = DictionaryIndex<Key, WeakDictionaryReference<Value>>
public var startIndex: Index {
return storage.startIndex
storage.startIndex
}
public var endIndex: Index {
return storage.endIndex
storage.endIndex
}
public func index(after index: Index) -> Index {
return storage.index(after: index)
storage.index(after: index)
}
public subscript(position: Index) -> (Key, WeakDictionaryReference<Value>) {
@@ -87,18 +87,18 @@ extension WeakDictionary: Collection {
}
public subscript(bounds: Range<Index>) -> WeakDictionary<Key, Value> {
let subStorage = storage[bounds.lowerBound ..< bounds.upperBound]
let subStorage = storage[bounds.lowerBound..<bounds.upperBound]
var newStorage = [Key: WeakDictionaryReference<Value>]()
subStorage.filter { _, value in return value.value != nil }
subStorage.filter { _, value in value.value != nil }
.forEach { key, value in newStorage[key] = value }
return WeakDictionary<Key, Value>(storage: newStorage)
}
}
extension Dictionary where Value: AnyObject {
public func weakDictionary() -> WeakDictionary<Key, Value> {
return WeakDictionary<Key, Value>(dictionary: self)
public extension Dictionary where Value: AnyObject {
func weakDictionary() -> WeakDictionary<Key, Value> {
WeakDictionary<Key, Value>(dictionary: self)
}
}
@@ -8,7 +8,7 @@
import Foundation
public struct WeakDictionaryKey<Key: AnyObject & Hashable, Value: AnyObject> : Hashable {
public struct WeakDictionaryKey<Key: AnyObject & Hashable, Value: AnyObject>: Hashable {
private weak var baseKey: Key?
private let hash: Int
@@ -22,7 +22,7 @@ public struct WeakDictionaryKey<Key: AnyObject & Hashable, Value: AnyObject> : H
}
public static func == (lhs: WeakDictionaryKey, rhs: WeakDictionaryKey) -> Bool {
return (lhs.baseKey != nil && rhs.baseKey != nil && lhs.baseKey == rhs.baseKey)
(lhs.baseKey != nil && rhs.baseKey != nil && lhs.baseKey == rhs.baseKey)
|| lhs.hashValue == rhs.hashValue
}
@@ -35,6 +35,6 @@ public struct WeakDictionaryKey<Key: AnyObject & Hashable, Value: AnyObject> : H
}
public var key: Key? {
return baseKey
baseKey
}
}
@@ -16,6 +16,6 @@ public struct WeakDictionaryReference<Value: AnyObject> {
}
public var value: Value? {
return referencedValue
referencedValue
}
}
@@ -48,11 +48,11 @@ public struct WeakKeyDictionary<Key: AnyObject & Hashable, Value: AnyObject> {
}
public func weakDictionary() -> WeakDictionary<Key, Value> {
return dictionary().weakDictionary()
dictionary().weakDictionary()
}
public func weakKeyDictionary() -> WeakKeyDictionary<Key, Value> {
return self[startIndex ..< endIndex]
self[startIndex..<endIndex]
}
public func dictionary() -> [Key: Value] {
@@ -73,15 +73,15 @@ extension WeakKeyDictionary: Collection {
public typealias Index = DictionaryIndex<WeakDictionaryKey<Key, Value>, WeakDictionaryReference<Value>>
public var startIndex: Index {
return storage.startIndex
storage.startIndex
}
public var endIndex: Index {
return storage.endIndex
storage.endIndex
}
public func index(after index: Index) -> Index {
return storage.index(after: index)
storage.index(after: index)
}
public subscript(position: Index) -> (WeakDictionaryKey<Key, Value>, WeakDictionaryReference<Value>) {
@@ -90,7 +90,7 @@ extension WeakKeyDictionary: Collection {
public subscript(key: Key) -> Value? {
get {
return storage[WeakDictionaryKey<Key, Value>(key: key)]
storage[WeakDictionaryKey<Key, Value>(key: key)]
}
set {
@@ -101,24 +101,24 @@ extension WeakKeyDictionary: Collection {
}
public subscript(bounds: Range<Index>) -> WeakKeyDictionary<Key, Value> {
let subStorage = storage[bounds.lowerBound ..< bounds.upperBound]
let subStorage = storage[bounds.lowerBound..<bounds.upperBound]
var newStorage = WeakDictionary<WeakDictionaryKey<Key, Value>, Value>()
subStorage.filter { key, value in return key.key != nil && value.value != nil }
subStorage.filter { key, value in key.key != nil && value.value != nil }
.forEach { key, value in newStorage[key] = value.value }
return WeakKeyDictionary<Key, Value>(storage: newStorage)
}
}
extension WeakDictionary where Key: AnyObject {
public func weakKeyDictionary(valuesRetainedByKey: Bool = false) -> WeakKeyDictionary<Key, Value> {
return WeakKeyDictionary<Key, Value>(dictionary: dictionary(), valuesRetainedByKey: valuesRetainedByKey)
public extension WeakDictionary where Key: AnyObject {
func weakKeyDictionary(valuesRetainedByKey: Bool = false) -> WeakKeyDictionary<Key, Value> {
WeakKeyDictionary<Key, Value>(dictionary: dictionary(), valuesRetainedByKey: valuesRetainedByKey)
}
}
extension Dictionary where Key: AnyObject, Value: AnyObject {
public func weakKeyDictionary(valuesRetainedByKey: Bool = false) -> WeakKeyDictionary<Key, Value> {
return WeakKeyDictionary<Key, Value>(dictionary: self, valuesRetainedByKey: valuesRetainedByKey)
public extension Dictionary where Key: AnyObject, Value: AnyObject {
func weakKeyDictionary(valuesRetainedByKey: Bool = false) -> WeakKeyDictionary<Key, Value> {
WeakKeyDictionary<Key, Value>(dictionary: self, valuesRetainedByKey: valuesRetainedByKey)
}
}
@@ -6,8 +6,8 @@
// Copyright © 2022 Element. All rights reserved.
//
import UIKit
import MatrixRustSDK
import UIKit
@MainActor
protocol AuthenticationCoordinatorDelegate: AnyObject {
@@ -1,4 +1,4 @@
//
//
// Copyright 2022 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,8 +14,8 @@
// limitations under the License.
//
import SwiftUI
import MatrixRustSDK
import SwiftUI
struct LoginCoordinatorParameters {
/// The service used to authenticate the user.
@@ -56,7 +56,7 @@ final class LoginCoordinator: Coordinator, Presentable {
// Must be used only internally
var childCoordinators: [Coordinator] = []
var callback: (@MainActor (LoginCoordinatorAction) -> Void)?
var callback: (@MainActor(LoginCoordinatorAction) -> Void)?
// MARK: - Setup
@@ -73,6 +73,7 @@ final class LoginCoordinator: Coordinator, Presentable {
}
// MARK: - Public
func start() {
MXLog.debug("[LoginCoordinator] did start.")
@@ -1,4 +1,4 @@
//
//
// Copyright 2022 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -1,4 +1,4 @@
//
//
// Copyright 2022 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -53,7 +53,7 @@ struct LoginViewState: BindableState {
/// Data about the selected homeserver.
var homeserver: LoginHomeserver
/// Whether a new homeserver is currently being loaded.
var isLoading: Bool = false
var isLoading = false
/// View state that can be bound to from SwiftUI.
var bindings: LoginBindings
@@ -24,7 +24,7 @@ class LoginViewModel: LoginViewModelType, LoginViewModelProtocol {
// MARK: Public
var callback: (@MainActor (LoginViewModelAction) -> Void)?
var callback: (@MainActor(LoginViewModelAction) -> Void)?
// MARK: - Setup
@@ -1,4 +1,4 @@
//
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,7 +19,7 @@ import Foundation
@MainActor
protocol LoginViewModelProtocol {
var callback: (@MainActor (LoginViewModelAction) -> Void)? { get set }
var callback: (@MainActor(LoginViewModelAction) -> Void)? { get set }
var context: LoginViewModelType.Context { get }
/// Update the view to reflect that a new homeserver is being loaded.
@@ -1,4 +1,4 @@
//
//
// Copyright 2022 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -46,7 +46,7 @@ final class ServerSelectionCoordinator: Coordinator, Presentable {
// Must be used only internally
var childCoordinators: [Coordinator] = []
var callback: (@MainActor (ServerSelectionCoordinatorAction) -> Void)?
var callback: (@MainActor(ServerSelectionCoordinatorAction) -> Void)?
// MARK: - Setup
@@ -1,4 +1,4 @@
//
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -26,7 +26,7 @@ class ServerSelectionViewModel: ServerSelectionViewModelType, ServerSelectionVie
// MARK: Public
var callback: (@MainActor (ServerSelectionViewModelAction) -> Void)?
var callback: (@MainActor(ServerSelectionViewModelAction) -> Void)?
// MARK: - Setup
@@ -1,4 +1,4 @@
//
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,7 +19,7 @@ import Foundation
@MainActor
protocol ServerSelectionViewModelProtocol {
var callback: (@MainActor (ServerSelectionViewModelAction) -> Void)? { get set }
var callback: (@MainActor(ServerSelectionViewModelAction) -> Void)? { get set }
var context: ServerSelectionViewModelType.Context { get }
/// Displays an error to the user.
@@ -1,4 +1,4 @@
//
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -1,4 +1,4 @@
//
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -1,4 +1,4 @@
//
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,7 +18,7 @@ import SwiftUI
@available(iOS 14, *)
typealias BugReportViewModelType = StateStoreViewModel<BugReportViewState,
BugReportViewAction>
BugReportViewAction>
@available(iOS 14, *)
class BugReportViewModel: BugReportViewModelType, BugReportViewModelProtocol {
@@ -50,7 +50,7 @@ class BugReportViewModel: BugReportViewModelType, BugReportViewModelProtocol {
files: files)
MXLog.info("[BugReportViewModel] submitBugReport succeeded, result: \(result.reportUrl)")
callback?(.submitFinished)
} catch let error {
} catch {
MXLog.error("[BugReportViewModel] submitBugReport failed: \(error)")
callback?(.submitFailed(error: error))
}
@@ -1,4 +1,4 @@
//
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -1,4 +1,4 @@
//
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,8 +14,8 @@
// limitations under the License.
//
import SwiftUI
import Combine
import SwiftUI
struct HomeScreenCoordinatorParameters {
let userSession: UserSessionProtocol
@@ -108,12 +108,11 @@ final class HomeScreenCoordinator: Coordinator, Presentable {
}
// MARK: - Public
func start() {
}
func start() { }
func toPresentable() -> UIViewController {
return self.hostingController
hostingController
}
// MARK: - Private
@@ -1,4 +1,4 @@
//
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -34,14 +34,14 @@ struct HomeScreenViewState: BindableState {
var userDisplayName: String?
var userAvatar: UIImage?
var showSessionVerificationBanner: Bool = false
var showSessionVerificationBanner = false
var rooms: [HomeScreenRoom] = []
var isLoadingRooms: Bool = false
var isLoadingRooms = false
var visibleDMs: [HomeScreenRoom] {
searchFilteredRooms.filter { $0.isDirect }
searchFilteredRooms.filter(\.isDirect)
}
var visibleRooms: [HomeScreenRoom] {
@@ -62,7 +62,7 @@ struct HomeScreenViewState: BindableState {
}
struct HomeScreenViewStateBindings {
var searchQuery: String = ""
var searchQuery = ""
}
struct HomeScreenRoom: Identifiable, Equatable {
@@ -14,8 +14,8 @@
// limitations under the License.
//
import SwiftUI
import Combine
import SwiftUI
typealias HomeScreenViewModelType = StateStoreViewModel<HomeScreenViewState, HomeScreenViewAction>
@@ -65,7 +65,7 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
roomUpdateListeners.removeAll()
roomSummaries.forEach({ roomSummary in
roomSummaries.forEach { roomSummary in
roomSummary.callbacks
.receive(on: DispatchQueue.main)
.sink { [weak self] callback in
@@ -81,7 +81,7 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
}
}
.store(in: &roomUpdateListeners)
})
}
}
@@ -1,4 +1,4 @@
//
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -1,4 +1,4 @@
//
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -167,7 +167,7 @@ struct RoomCell: View {
}
private func roomName(_ room: HomeScreenRoom) -> String {
room.displayName ?? room.id + (room.isEncrypted ? "🛡": "")
room.displayName ?? room.id + (room.isEncrypted ? "🛡" : "")
}
}
@@ -55,11 +55,10 @@ final class RoomScreenCoordinator: Coordinator, Presentable {
}
// MARK: - Public
func start() {
}
func start() { }
func toPresentable() -> UIViewController {
return self.roomScreenHostingController
roomScreenHostingController
}
}
@@ -1,4 +1,4 @@
//
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,9 +17,7 @@
import Foundation
import UIKit
enum RoomScreenViewModelAction {
}
enum RoomScreenViewModelAction { }
enum TimelineItemContextMenuAction: Hashable {
case copy
@@ -35,14 +33,14 @@ enum RoomScreenViewAction {
}
struct RoomScreenViewState: BindableState {
var roomTitle: String = ""
var roomTitle = ""
var roomAvatar: UIImage?
var roomEncryptionBadge: UIImage?
var items: [RoomTimelineViewProvider] = []
var isBackPaginating = false
var bindings: RoomScreenViewStateBindings
var contextMenuBuilder: (@MainActor (_ itemId: String) -> TimelineItemContextMenu)?
var contextMenuBuilder: (@MainActor(_ itemId: String) -> TimelineItemContextMenu)?
var sendButtonDisabled: Bool {
bindings.composerText.count == 0
@@ -20,7 +20,7 @@ typealias RoomScreenViewModelType = StateStoreViewModel<RoomScreenViewState, Roo
class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol {
private struct Constants {
private enum Constants {
static let backPaginationPageSize: UInt = 30
}
@@ -96,7 +96,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
// MARK: - Private
private func buildTimelineViews() {
let stateItems = timelineController.timelineItems.map { item in
let stateItems = timelineController.timelineItems.map { item in
timelineViewFactory.buildTimelineViewFor(timelineItem: item)
}
@@ -106,13 +106,13 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
// MARK: ContextMenus
private func buildContexMenuForItemId(_ itemId: String) -> TimelineItemContextMenu {
TimelineItemContextMenu(contextMenuActions: self.contextMenuActionsForItemId(itemId)) { [weak self] action in
TimelineItemContextMenu(contextMenuActions: contextMenuActionsForItemId(itemId)) { [weak self] action in
self?.processContentMenuAction(action, itemId: itemId)
}
}
private func contextMenuActionsForItemId(_ itemId: String) -> [TimelineItemContextMenuAction] {
guard let timelineItem = self.timelineController.timelineItems.first(where: { $0.id == itemId }),
guard let timelineItem = timelineController.timelineItems.first(where: { $0.id == itemId }),
timelineItem is EventBasedTimelineItemProtocol else {
return []
}
@@ -121,7 +121,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
}
private func processContentMenuAction(_ action: TimelineItemContextMenuAction, itemId: String) {
guard let timelineItem = self.timelineController.timelineItems.first(where: { $0.id == itemId }),
guard let timelineItem = timelineController.timelineItems.first(where: { $0.id == itemId }),
let item = timelineItem as? EventBasedTimelineItemProtocol else {
return
}
@@ -1,4 +1,4 @@
//
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -6,8 +6,8 @@
// Copyright © 2022 Element. All rights reserved.
//
import UIKit
import Combine
import UIKit
class ListTableViewAdapter: NSObject, UITableViewDelegate {
@@ -79,8 +79,8 @@ class ListTableViewAdapter: NSObject, UITableViewDelegate {
}
guard let tableView = tableView,
tableView.numberOfSections > 0 else {
return
tableView.numberOfSections > 0 else {
return
}
let currentItemCount = tableView.numberOfRows(inSection: 0)
@@ -89,7 +89,7 @@ class ListTableViewAdapter: NSObject, UITableViewDelegate {
case .bottomOffset:
tableView.scrollToRow(at: .init(row: max(0, currentItemCount - 1), section: 0), at: .bottom, animated: false)
case .topOffset(let indexPath, let previousItemCount):
let row = indexPath.row + max(0, (currentItemCount - previousItemCount))
let row = indexPath.row + max(0, currentItemCount - previousItemCount)
if row < currentItemCount {
tableView.scrollToRow(at: .init(row: row, section: 0), at: .top, animated: false)
}
@@ -108,8 +108,8 @@ class ListTableViewAdapter: NSObject, UITableViewDelegate {
func scrollToBottom(animated: Bool = false) {
guard let tableView = tableView,
tableView.numberOfSections > 0 else {
return
tableView.numberOfSections > 0 else {
return
}
let currentItemCount = tableView.numberOfRows(inSection: 0)
@@ -180,9 +180,9 @@ class ListTableViewAdapter: NSObject, UITableViewDelegate {
scrollViewBottomVisiblePublisher.send(isBottomVisible)
}
if !draggingInitiated && tableView.isDragging {
if !draggingInitiated, tableView.isDragging {
draggingInitiated = true
} else if draggingInitiated && !tableView.isDragging {
} else if draggingInitiated, !tableView.isDragging {
draggingInitiated = false
scrollViewDidRestPublisher.send(())
}
@@ -193,7 +193,7 @@ class ListTableViewAdapter: NSObject, UITableViewDelegate {
sender.state == .ended,
draggingInitiated == true,
!tableView.isDecelerating else {
return
return
}
draggingInitiated = false
@@ -23,7 +23,7 @@ struct MessageComposerTextField: View {
init(placeholder: String, text: Binding<String>, maxHeight: CGFloat) {
self.placeholder = placeholder
self._text = text
_text = text
self.maxHeight = maxHeight
}
@@ -36,7 +36,7 @@ struct MessageComposerTextField: View {
}
private var borderWidth: CGFloat {
return isEditing ? 2.0 : 1.0
isEditing ? 2.0 : 1.0
}
var body: some View {
@@ -89,18 +89,18 @@ private struct UITextViewWrapper: UIViewRepresentable {
}
func updateUIView(_ view: UITextView, context: UIViewRepresentableContext<UITextViewWrapper>) {
if view.text != self.text {
view.text = self.text
if view.text != text {
view.text = text
}
UITextViewWrapper.recalculateHeight(view: view, result: $calculatedHeight, maxHeight: maxHeight)
}
func makeCoordinator() -> Coordinator {
return Coordinator(text: $text,
height: $calculatedHeight,
isEditing: $isEditing,
maxHeight: maxHeight)
Coordinator(text: $text,
height: $calculatedHeight,
isEditing: $isEditing,
maxHeight: maxHeight)
}
fileprivate static func recalculateHeight(view: UIView, result: Binding<CGFloat>, maxHeight: CGFloat) {
@@ -124,7 +124,7 @@ private struct UITextViewWrapper: UIViewRepresentable {
init(text: Binding<String>, height: Binding<CGFloat>, isEditing: Binding<Bool>, maxHeight: CGFloat) {
self.text = text
self.calculatedHeight = height
calculatedHeight = height
self.isEditing = isEditing
self.maxHeight = maxHeight
}
@@ -137,7 +137,7 @@ private struct UITextViewWrapper: UIViewRepresentable {
}
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
return true
true
}
func textViewDidBeginEditing(_ textView: UITextView) {
@@ -6,9 +6,9 @@
// Copyright © 2022 Element. All rights reserved.
//
import Combine
import Foundation
import SwiftUI
import Combine
import Introspect
@@ -65,8 +65,7 @@ struct RoomHeaderView_Previews: PreviewProvider {
let viewModel = RoomScreenViewModel(timelineController: MockRoomTimelineController(),
timelineViewFactory: RoomTimelineViewFactory(),
roomName: "Some Room name",
roomAvatar: Asset.Images.appLogo.image
)
roomAvatar: Asset.Images.appLogo.image)
RoomHeaderView(context: viewModel.context)
.previewLayout(.sizeThatFits)
@@ -79,8 +78,7 @@ struct RoomHeaderView_Previews: PreviewProvider {
timelineViewFactory: RoomTimelineViewFactory(),
roomName: "Some Room name",
roomAvatar: nil,
roomEncryptionBadge: Asset.Images.encryptionTrusted.image
)
roomEncryptionBadge: Asset.Images.encryptionTrusted.image)
RoomHeaderView(context: viewModel.context)
.previewLayout(.sizeThatFits)
@@ -1,4 +1,4 @@
//
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -89,7 +89,7 @@ struct TimelineItemBubbledStylerView<Content: View>: View {
}
private var shouldAvoidBubbling: Bool {
return timelineItem is ImageRoomTimelineItem
timelineItem is ImageRoomTimelineItem
}
private var bubbleColor: Color {
@@ -108,7 +108,7 @@ struct TimelineItemBubbledStylerView_Previews: PreviewProvider {
@ViewBuilder
static var body: some View {
VStack(alignment: .leading) {
ForEach((1..<MockRoomTimelineController().timelineItems.count), id: \.self) { index in
ForEach(1..<MockRoomTimelineController().timelineItems.count, id: \.self) { index in
let item = MockRoomTimelineController().timelineItems[index]
RoomTimelineViewFactory().buildTimelineViewFor(timelineItem: item)
}
@@ -48,7 +48,7 @@ struct TimelineItemPlainStylerView_Previews: PreviewProvider {
@ViewBuilder
static var body: some View {
VStack(alignment: .leading) {
ForEach((1..<MockRoomTimelineController().timelineItems.count), id: \.self) { index in
ForEach(1..<MockRoomTimelineController().timelineItems.count, id: \.self) { index in
let item = MockRoomTimelineController().timelineItems[index]
RoomTimelineViewFactory().buildTimelineViewFor(timelineItem: item)
}
@@ -48,11 +48,11 @@ struct EmoteRoomTimelineView_Previews: PreviewProvider {
}
private static func itemWith(text: String, timestamp: String, senderId: String) -> EmoteRoomTimelineItem {
return EmoteRoomTimelineItem(id: UUID().uuidString,
text: text,
timestamp: timestamp,
shouldShowSenderDetails: true,
isOutgoing: false,
senderId: senderId)
EmoteRoomTimelineItem(id: UUID().uuidString,
text: text,
timestamp: timestamp,
shouldShowSenderDetails: true,
isOutgoing: false,
senderId: senderId)
}
}
@@ -45,25 +45,26 @@ struct FormattedBodyText_Previews: PreviewProvider {
@ViewBuilder
static var body: some View {
let htmlStrings = [
"""
Text before blockquote
<blockquote>
<b>bold</b> <i>italic</i>
</blockquote>
Text after blockquote
""",
"""
<blockquote>First blockquote with a <a href=\"https://www.matrix.org/\">link</a> in it</blockquote>
<blockquote>Second blockquote with a <a href=\"https://www.matrix.org/\">link</a> in it</blockquote>
<blockquote>Third blockquote with a <a href=\"https://www.matrix.org/\">link</a> in it</blockquote>
""",
"""
<code>Hello world</code>
<p>Text</p>
<code><b>Hello</b> <i>world</i></code>
<p>Text</p>
<code>Hello world</code>
"""]
"""
Text before blockquote
<blockquote>
<b>bold</b> <i>italic</i>
</blockquote>
Text after blockquote
""",
"""
<blockquote>First blockquote with a <a href=\"https://www.matrix.org/\">link</a> in it</blockquote>
<blockquote>Second blockquote with a <a href=\"https://www.matrix.org/\">link</a> in it</blockquote>
<blockquote>Third blockquote with a <a href=\"https://www.matrix.org/\">link</a> in it</blockquote>
""",
"""
<code>Hello world</code>
<p>Text</p>
<code><b>Hello</b> <i>world</i></code>
<p>Text</p>
<code>Hello world</code>
"""
]
let attributedStringBuilder = AttributedStringBuilder()
VStack(alignment: .leading, spacing: 24.0) {
@@ -49,11 +49,11 @@ struct NoticeRoomTimelineView_Previews: PreviewProvider {
}
private static func itemWith(text: String, timestamp: String, senderId: String) -> NoticeRoomTimelineItem {
return NoticeRoomTimelineItem(id: UUID().uuidString,
text: text,
timestamp: timestamp,
shouldShowSenderDetails: true,
isOutgoing: false,
senderId: senderId)
NoticeRoomTimelineItem(id: UUID().uuidString,
text: text,
timestamp: timestamp,
shouldShowSenderDetails: true,
isOutgoing: false,
senderId: senderId)
}
}
@@ -1,4 +1,4 @@
//
//
// Copyright 2022 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -52,24 +52,24 @@ struct TextRoomTimelineView_Previews: PreviewProvider {
shouldShowSenderDetails: true,
isOutgoing: false,
senderId: "Bob"))
.timelineStyle(.plain)
.timelineStyle(.plain)
TextRoomTimelineView(timelineItem: itemWith(text: "Some other text",
timestamp: "Later",
shouldShowSenderDetails: true,
isOutgoing: true,
senderId: "Anne"))
.timelineStyle(.plain)
.timelineStyle(.plain)
}
.padding(.horizontal, 8)
}
private static func itemWith(text: String, timestamp: String, shouldShowSenderDetails: Bool, isOutgoing: Bool, senderId: String) -> TextRoomTimelineItem {
return TextRoomTimelineItem(id: UUID().uuidString,
text: text,
timestamp: timestamp,
shouldShowSenderDetails: shouldShowSenderDetails,
isOutgoing: isOutgoing,
senderId: senderId)
TextRoomTimelineItem(id: UUID().uuidString,
text: text,
timestamp: timestamp,
shouldShowSenderDetails: shouldShowSenderDetails,
isOutgoing: isOutgoing,
senderId: senderId)
}
}
@@ -6,13 +6,13 @@
// Copyright © 2022 Element. All rights reserved.
//
import SwiftUI
import Combine
import Introspect
import SwiftUI
struct TimelineItemList: View {
@State private var tableViewObserver: ListTableViewAdapter = ListTableViewAdapter()
@State private var tableViewObserver = ListTableViewAdapter()
@State private var timelineItems: [RoomTimelineViewProvider] = []
@State private var hasPendingChanges = false
@ObservedObject private var settings = ElementSettings.shared
@@ -65,7 +65,7 @@ struct TimelineItemList: View {
}
tableViewObserver = ListTableViewAdapter(tableView: tableView,
topDetectionOffset: (tableView.bounds.size.height / 3.0),
topDetectionOffset: tableView.bounds.size.height / 3.0,
bottomDetectionOffset: 10.0)
tableViewObserver.scrollToBottom()
@@ -136,11 +136,11 @@ struct TimelineItemList: View {
}
private var isPreview: Bool {
#if DEBUG
#if DEBUG
return ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1"
#else
#else
return false
#endif
#endif
}
}
@@ -6,9 +6,9 @@
// Copyright © 2022 Element. All rights reserved.
//
import Combine
import Foundation
import SwiftUI
import Combine
import Introspect
@@ -1,4 +1,4 @@
//
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");

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