diff --git a/.swiftformat b/.swiftformat index c1b2534..66400fb 100644 --- a/.swiftformat +++ b/.swiftformat @@ -6,5 +6,16 @@ --wrapcollections before-first --commas inline --semicolons never ---self remove +# Default `--self remove` strippt `self.` auch in Closure-Captures +# und @autoclosure-Calls (z.B. OS_log Logger.info) weg, was Swift-6- +# strict-concurrency dann als „implicit use of self in closure" +# rejected. Komplette Regel ausschalten — Author entscheidet pro +# Stelle, wo `self.` nötig ist. +--disable redundantSelf +# Sendable bleibt explizit auf DTOs. Die `redundantSendable`-Regel +# würde `Sendable` von Codable-DTOs entfernen, die SwiftFormat als +# implicitly-Sendable inferiert; in Swift 6 strict-concurrency müssen +# DTOs aber über actor-Grenzen wandern und das Compiler-Setup +# verlässt sich auf den expliziten Marker. +--disable redundantSendable --importgrouping testable-bottom diff --git a/Sources/Core/API/ZitareAPI.swift b/Sources/Core/API/ZitareAPI.swift index 44ad828..1c4dbd6 100644 --- a/Sources/Core/API/ZitareAPI.swift +++ b/Sources/Core/API/ZitareAPI.swift @@ -75,7 +75,9 @@ struct QuoteDraft: Codable, Sendable, Equatable { enum SourceKind: String, Codable, Sendable, CaseIterable, Identifiable { case book, article, talk, film, other - var id: String { rawValue } + var id: String { + rawValue + } } } diff --git a/Sources/Core/Submit/PendingSubmissionModel.swift b/Sources/Core/Submit/PendingSubmissionModel.swift index 03e49c5..316a0be 100644 --- a/Sources/Core/Submit/PendingSubmissionModel.swift +++ b/Sources/Core/Submit/PendingSubmissionModel.swift @@ -74,7 +74,7 @@ enum PendingSubmissionContainer { static func make(inMemory: Bool = false) throws -> ModelContainer { let schema = Schema([PendingSubmission.self]) - let config: ModelConfiguration = if inMemory { + let config = if inMemory { ModelConfiguration(schema: schema, isStoredInMemoryOnly: true) } else { ModelConfiguration("submissions", schema: schema, url: defaultStoreURL()) diff --git a/Sources/Core/Submit/ReachabilityWatcher.swift b/Sources/Core/Submit/ReachabilityWatcher.swift index 7a9f39e..12c4dce 100644 --- a/Sources/Core/Submit/ReachabilityWatcher.swift +++ b/Sources/Core/Submit/ReachabilityWatcher.swift @@ -11,30 +11,30 @@ import OSLog /// reale App startet Watcher einmal beim Launch und lässt ihn bis /// zum Prozess-Ende laufen. final class ReachabilityWatcher: @unchecked Sendable { - private let monitor = NWPathMonitor() - private let queue = DispatchQueue(label: "ev.mana.zitare.reachability") - private let log = Logger(subsystem: "ev.mana.zitare", category: "reachability") - private var wasReachable: Bool? = nil - private var onReconnect: @Sendable () -> Void = {} + private let monitor = NWPathMonitor() + private let queue = DispatchQueue(label: "ev.mana.zitare.reachability") + private let log = Logger(subsystem: "ev.mana.zitare", category: "reachability") + private var wasReachable: Bool? + private var onReconnect: @Sendable () -> Void = {} - func start(onReconnect: @escaping @Sendable () -> Void) { - self.onReconnect = onReconnect - monitor.pathUpdateHandler = { [weak self] path in - guard let self else { return } - let reachable = path.status == .satisfied - let prev = self.wasReachable - self.wasReachable = reachable - if prev == false, reachable { - self.log.info("Reachable again — triggering reconnect-hook") - self.onReconnect() - } else if prev == nil { - self.log.info("Initial reachability: \(reachable ? "yes" : "no", privacy: .public)") - } - } - monitor.start(queue: queue) - } + func start(onReconnect: @escaping @Sendable () -> Void) { + self.onReconnect = onReconnect + monitor.pathUpdateHandler = { [weak self] path in + guard let self else { return } + let reachable = path.status == .satisfied + let prev = self.wasReachable + self.wasReachable = reachable + if prev == false, reachable { + self.log.info("Reachable again — triggering reconnect-hook") + self.onReconnect() + } else if prev == nil { + self.log.info("Initial reachability: \(reachable ? "yes" : "no", privacy: .public)") + } + } + monitor.start(queue: queue) + } - func stop() { - monitor.cancel() - } + func stop() { + monitor.cancel() + } } diff --git a/Sources/Features/Submit/SubmitQuoteView.swift b/Sources/Features/Submit/SubmitQuoteView.swift index fac2289..c7a8392 100644 --- a/Sources/Features/Submit/SubmitQuoteView.swift +++ b/Sources/Features/Submit/SubmitQuoteView.swift @@ -77,14 +77,14 @@ struct SubmitQuoteView: View { #if os(iOS) .navigationBarTitleDisplayMode(.inline) #endif - .task { - refreshPendingCount() - } - .onChange(of: scenePhase) { _, phase in - if phase == .active { - Task { await flushPending() } + .task { + refreshPendingCount() + } + .onChange(of: scenePhase) { _, phase in + if phase == .active { + Task { await flushPending() } + } } - } } } @@ -123,7 +123,6 @@ struct SubmitQuoteView: View { } } - @ViewBuilder private var sourceSection: some View { Section { Toggle("Quelle angeben (optional)", isOn: $includesSource) @@ -141,9 +140,9 @@ struct SubmitQuoteView: View { } } TextField("Jahr (z.B. 1885)", value: $draft.sourceYear, format: .number.grouping(.never)) - #if os(iOS) + #if os(iOS) .keyboardType(.numberPad) - #endif + #endif } } } @@ -154,9 +153,11 @@ struct SubmitQuoteView: View { VStack(alignment: .leading, spacing: 4) { Text("CC-BY-SA-4.0 zustimmen") .fontWeight(.medium) - Text("Mit Einreichen veröffentlichst du das Zitat unter CC-BY-SA-4.0. Andere dürfen es teilen und remixen, solange sie dich nennen und das Ergebnis ebenfalls frei teilen.") - .font(.caption) - .foregroundStyle(ZitareTheme.mutedForeground) + Text( + "Mit Einreichen veröffentlichst du das Zitat unter CC-BY-SA-4.0. Andere dürfen es teilen und remixen, solange sie dich nennen und das Ergebnis ebenfalls frei teilen." + ) + .font(.caption) + .foregroundStyle(ZitareTheme.mutedForeground) } } } header: { diff --git a/Widgets/ZitareWidget/ZitareWidgetBundle.swift b/Widgets/ZitareWidget/ZitareWidgetBundle.swift index af4eb21..b52ef48 100644 --- a/Widgets/ZitareWidget/ZitareWidgetBundle.swift +++ b/Widgets/ZitareWidget/ZitareWidgetBundle.swift @@ -32,7 +32,7 @@ struct DailyQuoteWidget: Widget { .systemMedium, .systemLarge, .accessoryInline, - .accessoryRectangular, + .accessoryRectangular ]) } }