chore: commit all pending changes

This commit is contained in:
Trey t
2026-02-10 18:15:36 -06:00
parent b993ed3613
commit 53cc532ca9
51 changed files with 2583 additions and 268 deletions

View File

@@ -12,9 +12,11 @@ struct SettingsView: View {
@State private var showResetConfirmation = false
@State private var showPaywall = false
@State private var showOnboardingPaywall = false
@State private var showSyncLogs = false
@State private var isSyncActionInProgress = false
@State private var syncActionMessage: String?
#if DEBUG
@State private var selectedSyncStatus: EntitySyncStatus?
@State private var showSyncLogs = false
@State private var exporter = DebugShareExporter()
@State private var showExportProgress = false
#endif
@@ -39,6 +41,9 @@ struct SettingsView: View {
// Travel Preferences
travelSection
// Data Sync
syncHealthSection
// Privacy
privacySection
@@ -72,6 +77,17 @@ struct SettingsView: View {
.sheet(isPresented: $showOnboardingPaywall) {
OnboardingPaywallView(isPresented: $showOnboardingPaywall)
}
.sheet(isPresented: $showSyncLogs) {
SyncLogViewerSheet()
}
.alert("Sync Status", isPresented: Binding(
get: { syncActionMessage != nil },
set: { if !$0 { syncActionMessage = nil } }
)) {
Button("OK", role: .cancel) { syncActionMessage = nil }
} message: {
Text(syncActionMessage ?? "")
}
}
// MARK: - Appearance Section
@@ -370,6 +386,97 @@ struct SettingsView: View {
.listRowBackground(Theme.cardBackground(colorScheme))
}
// MARK: - Sync Health Section
private var syncHealthSection: some View {
Section {
let syncState = SyncState.current(in: modelContext)
if syncState.syncInProgress || isSyncActionInProgress {
HStack {
ProgressView()
.scaleEffect(0.8)
Text("Sync in progress...")
.font(.subheadline)
.foregroundStyle(.secondary)
}
}
if let lastSync = syncState.lastSuccessfulSync {
HStack {
Label("Last Successful Sync", systemImage: "checkmark.circle.fill")
.foregroundStyle(.green)
Spacer()
Text(lastSync.formatted(date: .abbreviated, time: .shortened))
.font(.caption)
.foregroundStyle(.secondary)
}
} else {
HStack {
Label("Last Successful Sync", systemImage: "clock.arrow.circlepath")
.foregroundStyle(.secondary)
Spacer()
Text("Never")
.font(.caption)
.foregroundStyle(.secondary)
}
}
if let lastError = syncState.lastSyncError, !lastError.isEmpty {
VStack(alignment: .leading, spacing: 4) {
Label("Last Sync Warning", systemImage: "exclamationmark.triangle.fill")
.foregroundStyle(.orange)
.font(.subheadline)
Text(lastError)
.font(.caption)
.foregroundStyle(.secondary)
}
}
if !syncState.syncEnabled {
VStack(alignment: .leading, spacing: 4) {
Label("Sync Paused", systemImage: "pause.circle.fill")
.foregroundStyle(.orange)
.font(.subheadline)
if let reason = syncState.syncPausedReason {
Text(reason)
.font(.caption)
.foregroundStyle(.secondary)
}
}
Button {
Task {
let syncService = CanonicalSyncService()
await syncService.resumeSync(context: modelContext)
syncActionMessage = "Sync has been re-enabled."
}
} label: {
Label("Re-enable Sync", systemImage: "play.circle")
}
.disabled(isSyncActionInProgress)
}
Button {
triggerManualSync()
} label: {
Label("Sync Now", systemImage: "arrow.triangle.2.circlepath")
}
.disabled(isSyncActionInProgress)
Button {
showSyncLogs = true
} label: {
Label("View Sync Logs", systemImage: "doc.text.magnifyingglass")
}
} header: {
Text("Data Sync")
} footer: {
Text("SportsTime loads bundled data first, then refreshes from CloudKit.")
}
.listRowBackground(Theme.cardBackground(colorScheme))
}
// MARK: - Debug Section
#if DEBUG
@@ -548,9 +655,6 @@ struct SettingsView: View {
.sheet(item: $selectedSyncStatus) { status in
SyncStatusDetailSheet(status: status)
}
.sheet(isPresented: $showSyncLogs) {
SyncLogViewerSheet()
}
}
#endif
@@ -633,6 +737,23 @@ struct SettingsView: View {
// MARK: - Helpers
private func triggerManualSync() {
guard !isSyncActionInProgress else { return }
isSyncActionInProgress = true
Task {
defer { isSyncActionInProgress = false }
do {
let result = try await BackgroundSyncManager.shared.triggerManualSync()
syncActionMessage = "Sync complete. Updated \(result.totalUpdated) records."
} catch {
syncActionMessage = "Sync failed: \(error.localizedDescription)"
}
}
}
private func sportColor(for sport: Sport) -> Color {
sport.themeColor
}
@@ -775,6 +896,8 @@ private struct DetailRow: View {
}
}
#endif
/// Sheet to view sync logs
struct SyncLogViewerSheet: View {
@Environment(\.dismiss) private var dismiss
@@ -837,5 +960,3 @@ struct SyncLogViewerSheet: View {
}
}
}
#endif