fix(schedule): use start of day for date range queries

- Fix startDate to use Calendar.startOfDay instead of Date() to include
  games earlier in the current day
- Add SyncLogger for file-based sync logging viewable in Settings
- Add "View Sync Logs" button in Settings debug section
- Add diagnostics and NBA game logging to ScheduleViewModel
- Add dropped game logging to DataProvider.filterRichGames
- Use SyncLogger in SportsTimeApp and CloudKitService for sync operations

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Trey t
2026-01-20 22:25:44 -06:00
parent 8ea3e6112a
commit 87079b434d
6 changed files with 355 additions and 19 deletions

View File

@@ -14,6 +14,7 @@ struct SettingsView: View {
@State private var showOnboardingPaywall = false
#if DEBUG
@State private var selectedSyncStatus: EntitySyncStatus?
@State private var showSyncLogs = false
#endif
var body: some View {
@@ -433,6 +434,13 @@ struct SettingsView: View {
} label: {
Label("Trigger Sync Now", systemImage: "arrow.triangle.2.circlepath")
}
// View sync logs
Button {
showSyncLogs = true
} label: {
Label("View Sync Logs", systemImage: "doc.text.magnifyingglass")
}
} header: {
Text("Sync Status")
} footer: {
@@ -442,6 +450,9 @@ struct SettingsView: View {
.sheet(item: $selectedSyncStatus) { status in
SyncStatusDetailSheet(status: status)
}
.sheet(isPresented: $showSyncLogs) {
SyncLogViewerSheet()
}
}
#endif
@@ -666,4 +677,67 @@ private struct DetailRow: View {
}
}
/// Sheet to view sync logs
struct SyncLogViewerSheet: View {
@Environment(\.dismiss) private var dismiss
@State private var logContent = ""
@State private var autoScroll = true
var body: some View {
NavigationStack {
ScrollViewReader { proxy in
ScrollView {
Text(logContent)
.font(.system(.caption, design: .monospaced))
.frame(maxWidth: .infinity, alignment: .leading)
.padding()
.id("logBottom")
}
.onChange(of: logContent) {
if autoScroll {
withAnimation {
proxy.scrollTo("logBottom", anchor: .bottom)
}
}
}
}
.navigationTitle("Sync Logs")
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .topBarLeading) {
Button("Clear") {
SyncLogger.shared.clearLog()
logContent = "Log cleared."
}
}
ToolbarItem(placement: .topBarTrailing) {
Button("Done") {
dismiss()
}
}
ToolbarItem(placement: .bottomBar) {
HStack {
Button {
logContent = SyncLogger.shared.readLog()
} label: {
Label("Refresh", systemImage: "arrow.clockwise")
}
Spacer()
Toggle("Auto-scroll", isOn: $autoScroll)
.toggleStyle(.switch)
.labelsHidden()
Text("Auto-scroll")
.font(.caption)
}
}
}
.onAppear {
logContent = SyncLogger.shared.readLog()
}
}
}
}
#endif