From 12dab4cc37f8db2bc1f4ea61817f39a9e7fe1e0a Mon Sep 17 00:00:00 2001 From: Dallas Groot Date: Sat, 11 Apr 2026 01:52:16 -0700 Subject: [PATCH] quick fix --- iOS/Views/Companion/CompanionAPIService.swift | 54 +++++++++++++++++++ .../Companion/LibraryConflictsView.swift | 53 ------------------ iOS/Views/Library/DownloadsSettingsView.swift | 18 ++++--- 3 files changed, 66 insertions(+), 59 deletions(-) diff --git a/iOS/Views/Companion/CompanionAPIService.swift b/iOS/Views/Companion/CompanionAPIService.swift index 5e9f4ad..c409fe7 100644 --- a/iOS/Views/Companion/CompanionAPIService.swift +++ b/iOS/Views/Companion/CompanionAPIService.swift @@ -644,6 +644,60 @@ struct ConflictsResponse: Codable { let issues: [LibraryConflict] } +// MARK: - Conflict Manager +// Defined here (in CompanionAPIService.swift) so it compiles before +// DownloadsSettingsView.swift and LibraryConflictsView.swift reference it. + +@MainActor +class ConflictManager: ObservableObject { + static let shared = ConflictManager() + + @Published var conflicts: ConflictsResponse? + @Published var isLoading = false + @Published var lastError: String? + @Published var isFixing: String? = nil + + private let api = CompanionAPIService() + + var badgeCount: Int { conflicts?.errors ?? 0 } + var totalCount: Int { conflicts?.total ?? 0 } + + init() { + NotificationCenter.default.addObserver( + forName: .companionConflictsUpdated, + object: nil, + queue: .main + ) { [weak self] _ in + Task { await self?.refresh() } + } + } + + func refresh() async { + guard CompanionSettings.shared.isEnabled else { return } + isLoading = true + lastError = nil + do { + conflicts = try await api.fetchConflicts() + } catch { + lastError = error.localizedDescription + } + isLoading = false + } + + func fix(_ conflict: LibraryConflict) async { + guard let action = conflict.fix_action else { return } + isFixing = conflict.id + do { + try await api.fixConflict(action: action, fixData: conflict.fix_data) + try? await Task.sleep(for: .seconds(2)) + await refresh() + } catch { + lastError = error.localizedDescription + } + isFixing = nil + } +} + // MARK: - Library Fetch (Phase 1) extension CompanionAPIService { diff --git a/iOS/Views/Companion/LibraryConflictsView.swift b/iOS/Views/Companion/LibraryConflictsView.swift index c80a121..aa84fd1 100644 --- a/iOS/Views/Companion/LibraryConflictsView.swift +++ b/iOS/Views/Companion/LibraryConflictsView.swift @@ -22,59 +22,6 @@ extension LibraryConflict { } } -// MARK: - Conflict Manager - -@MainActor -class ConflictManager: ObservableObject { - static let shared = ConflictManager() - - @Published var conflicts: ConflictsResponse? - @Published var isLoading = false - @Published var lastError: String? - @Published var isFixing: String? = nil - - private let api = CompanionAPIService() - - var badgeCount: Int { conflicts?.errors ?? 0 } - var totalCount: Int { conflicts?.total ?? 0 } - - init() { - // Listen for conflicts_updated WebSocket events broadcast via NotificationCenter - NotificationCenter.default.addObserver( - forName: .companionConflictsUpdated, - object: nil, - queue: .main - ) { [weak self] _ in - Task { await self?.refresh() } - } - } - - func refresh() async { - guard CompanionSettings.shared.isEnabled else { return } - isLoading = true - lastError = nil - do { - conflicts = try await api.fetchConflicts() - } catch { - lastError = error.localizedDescription - } - isLoading = false - } - - func fix(_ conflict: LibraryConflict) async { - guard let action = conflict.fix_action else { return } - isFixing = conflict.id - do { - try await api.fixConflict(action: action, fixData: conflict.fix_data) - try? await Task.sleep(for: .seconds(2)) - await refresh() - } catch { - lastError = error.localizedDescription - } - isFixing = nil - } -} - // MARK: - Issues & Conflicts View struct LibraryConflictsView: View { diff --git a/iOS/Views/Library/DownloadsSettingsView.swift b/iOS/Views/Library/DownloadsSettingsView.swift index aeb93c1..d6bedb9 100644 --- a/iOS/Views/Library/DownloadsSettingsView.swift +++ b/iOS/Views/Library/DownloadsSettingsView.swift @@ -502,10 +502,11 @@ struct SettingsView: View { @EnvironmentObject var serverManager: ServerManager @ObservedObject var quality = StreamingQuality.shared @ObservedObject var debugLogger = DebugLogger.shared - @ObservedObject private var conflictManager = ConflictManager.shared @State private var showVisualizerSettings = false @State private var cacheSizeText = "..." + @State private var conflictErrorCount = 0 + @State private var conflictTotalCount = 0 private let accentPink = Color(red: 1.0, green: 0.176, blue: 0.333) @@ -555,17 +556,16 @@ struct SettingsView: View { HStack { Text("Issues & Conflicts") Spacer() - let count = ConflictManager.shared.badgeCount - if count > 0 { - Text("\(count)") + if conflictErrorCount > 0 { + Text("\(conflictErrorCount)") .font(.system(size: 12, weight: .bold)) .foregroundColor(.white) .padding(.horizontal, 7) .padding(.vertical, 2) .background(Color(red: 1, green: 0.176, blue: 0.333)) .clipShape(Capsule()) - } else if ConflictManager.shared.totalCount > 0 { - Text("\(ConflictManager.shared.totalCount)") + } else if conflictTotalCount > 0 { + Text("\(conflictTotalCount)") .font(.system(size: 12)) .foregroundColor(.gray) } @@ -738,6 +738,12 @@ struct SettingsView: View { } .onAppear { cacheSizeText = computeCacheSize() + conflictErrorCount = ConflictManager.shared.badgeCount + conflictTotalCount = ConflictManager.shared.totalCount + } + .onReceive(NotificationCenter.default.publisher(for: .companionConflictsUpdated)) { _ in + conflictErrorCount = ConflictManager.shared.badgeCount + conflictTotalCount = ConflictManager.shared.totalCount } } }