From 6eb17a18e901e2d7faa219d7e5a79083a5891dc9 Mon Sep 17 00:00:00 2001 From: ivar Date: Thu, 7 May 2026 01:24:28 +0200 Subject: Refactors --- Solverv/ContentView.swift | 171 +++++++++++++++++++++++++++---- Solverv/SolvervApp.swift | 1 - Solverv/Views/InfoScreenView.swift | 200 ------------------------------------- 3 files changed, 154 insertions(+), 218 deletions(-) delete mode 100644 Solverv/Views/InfoScreenView.swift (limited to 'Solverv') diff --git a/Solverv/ContentView.swift b/Solverv/ContentView.swift index 38c6153..dff6e23 100644 --- a/Solverv/ContentView.swift +++ b/Solverv/ContentView.swift @@ -1,32 +1,169 @@ // -// ContentView.swift +// InfoScreenView.swift // Solverv // -// Created by Ivar Løvlie on 15/12/2025. +// Created by Ivar Løvlie on 23/03/2026. // import SwiftUI +import Combine struct ContentView: View { + @State private var upcomingEvents: [SolsticeEvent] = [] + @State private var nextEvent: SolsticeEvent? + @State private var currentEvent: SolsticeEvent? + @State private var progressData: (elapsed: Int, total: Int)? = nil + @State private var sunriseTime: Date? + @State private var sunsetTime: Date? + var body: some View { - NavigationStack { - VStack { - Text("Solstice Countdown") - .font(.title) - - NavigationLink(destination: InfoScreenView()) { - Label("View Details", systemImage: "info.circle") - .padding() - .background(Color.blue) - .foregroundColor(.white) - .cornerRadius(8) + ScrollView { + VStack(spacing: 24) { + VStack(spacing: 16) { + if let next = nextEvent, let current = currentEvent { + Image(current.season.assetName) + .resizable() + .scaledToFit() + .frame(height: 200) + .clipped() + + VStack(spacing: 8) { + Text(current.name) + .font(.title3) + + Text("\(next.daysUntil())") + .font(.system(.title, design: .default).weight(.bold)) + .foregroundColor(next.season.colorLight) + + Text("dager til \(next.shortName.lowercased())") + .font(.caption) + .foregroundColor(.secondary) + } + + if let progress = progressData { + ProgressView(value: Double(progress.elapsed) / Double(progress.total)) + .tint(next.season.colorLight) + } + } + } + .padding() + .background(Color(.systemGray6)) + .cornerRadius(12) + + VStack(spacing: 16) { + VStack(alignment: .leading, spacing: 12) { + Text("Solgang idag") + .font(.headline) + + HStack { + Label("Oppgang", systemImage: "sunrise.fill") + Spacer() + if let sunrise = sunriseTime { + Text(sunrise, style: .time) + } else { + Text("—").foregroundColor(.secondary) + } + } + + HStack { + Label("Nedgang", systemImage: "sunset.fill") + Spacer() + if let sunset = sunsetTime { + Text(sunset, style: .time) + } else { + Text("—").foregroundColor(.secondary) + } + } + } } + .padding() + .background(Color(.systemGray6)) + .cornerRadius(12) + + eventsListSection } - .navigationTitle("Home") + .padding() + } + .navigationTitle("Solverv og jevndøgn") + .onAppear(perform: loadData) + .onReceive(Timer.publish(every: 60, on: .main, in: .common).autoconnect()) { _ in + loadData() } } -} -#Preview { - ContentView() + private var eventsListSection: some View { + VStack(alignment: .leading, spacing: 12) { + Text("Fremtiden") + .font(.headline) + + if upcomingEvents.isEmpty { + Text("Er her") + .foregroundColor(.secondary) + .font(.caption) + } else { + VStack(spacing: 0) { + ForEach(Array(upcomingEvents.enumerated()), id: \.element.id) { index, event in + VStack(spacing: 0) { + HStack { + VStack(alignment: .leading, spacing: 2) { + Text(event.name) + .font(.subheadline) + .lineLimit(1) + + Text(formatEventDate(event.localDateTime())) + .font(.caption) + .foregroundColor(.secondary) + } + + Spacer() + + VStack(alignment: .trailing, spacing: 2) { + Text("\(event.daysUntil())d") + .font(.subheadline) + + Circle() + .fill(event.season.colorLight) + .frame(width: 12, height: 12) + } + } + .padding(.vertical, 8) + + if index < upcomingEvents.count - 1 { + Divider() + } + } + } + } + } + } + .padding() + .background(Color(.systemGray6)) + .cornerRadius(12) + } + + private func loadData() { + nextEvent = SolsticeData.shared.nextEvent() + currentEvent = SolsticeData.shared.currentEvent() + upcomingEvents = SolsticeData.shared.upcomingEvents(count: 12) + progressData = SolsticeData.shared.progressToNextEvent() + + // Load sunrise/sunset from location if available + if let location = AppGroupManager.shared.getLocation() { + let sunTimes = SunTimes( + latitude: location.latitude, + longitude: location.longitude, + date: Date() + ) + sunriseTime = sunTimes.sunrise() + sunsetTime = sunTimes.sunset() + } + } + + private func formatEventDate(_ date: Date) -> String { + let formatter = DateFormatter() + formatter.dateStyle = .short + formatter.timeStyle = .short + formatter.timeZone = .current + return formatter.string(from: date) + } } diff --git a/Solverv/SolvervApp.swift b/Solverv/SolvervApp.swift index 955a946..9999f2d 100644 --- a/Solverv/SolvervApp.swift +++ b/Solverv/SolvervApp.swift @@ -19,7 +19,6 @@ struct SolvervApp: App { Item.self, ]) let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false) - do { return try ModelContainer(for: schema, configurations: [modelConfiguration]) } catch { diff --git a/Solverv/Views/InfoScreenView.swift b/Solverv/Views/InfoScreenView.swift deleted file mode 100644 index d876a45..0000000 --- a/Solverv/Views/InfoScreenView.swift +++ /dev/null @@ -1,200 +0,0 @@ -// -// InfoScreenView.swift -// Solverv -// -// Created by Ivar Løvlie on 23/03/2026. -// - -import SwiftUI -import Combine - -struct InfoScreenView: View { - @State private var upcomingEvents: [SolsticeEvent] = [] - @State private var nextEvent: SolsticeEvent? - @State private var progressData: (elapsed: Int, total: Int)? = nil - @State private var sunriseTime: Date? - @State private var sunsetTime: Date? - - var body: some View { - ScrollView { - VStack(spacing: 24) { - // Top section: Image + countdown - VStack(spacing: 16) { - if let next = nextEvent { - Image(next.season.assetName) - .resizable() - .scaledToFit() - .frame(height: 200) - .clipped() - - VStack(spacing: 8) { - Text(next.name) - .font(.title3) - - Text("\(next.daysUntil())") - .font(.system(.title, design: .default).weight(.bold)) - .foregroundColor(next.season.colorLight) - - Text("days remaining") - .font(.caption) - .foregroundColor(.secondary) - } - - if let progress = progressData { - ProgressView(value: Double(progress.elapsed) / Double(progress.total)) - .tint(next.season.colorLight) - } - } - } - .padding() - .background(Color(.systemGray6)) - .cornerRadius(12) - - // Middle section: Sun times + season info - VStack(spacing: 16) { - VStack(alignment: .leading, spacing: 12) { - Text("Today's Sun Times") - .font(.headline) - - HStack { - Label("Sunrise", systemImage: "sunrise.fill") - Spacer() - if let sunrise = sunriseTime { - Text(sunrise, style: .time) - } else { - Text("—").foregroundColor(.secondary) - } - } - - HStack { - Label("Sunset", systemImage: "sunset.fill") - Spacer() - if let sunset = sunsetTime { - Text(sunset, style: .time) - } else { - Text("—").foregroundColor(.secondary) - } - } - } - - Divider() - - if let next = nextEvent { - VStack(alignment: .leading, spacing: 8) { - Text("Current Season") - .font(.headline) - - HStack(spacing: 8) { - Circle() - .fill(next.season.colorLight) - .frame(width: 12, height: 12) - - VStack(alignment: .leading, spacing: 4) { - Text(next.season.displayName) - .font(.subheadline) - - Text(next.season.description) - .font(.caption) - .foregroundColor(.secondary) - } - } - } - } - } - .padding() - .background(Color(.systemGray6)) - .cornerRadius(12) - - // Bottom section: Upcoming events list - eventsListSection - } - .padding() - } - .navigationTitle("Solstices & Equinoxes") - .onAppear(perform: loadData) - .onReceive(Timer.publish(every: 60, on: .main, in: .common).autoconnect()) { _ in - loadData() - } - } - - private var eventsListSection: some View { - VStack(alignment: .leading, spacing: 12) { - Text("Upcoming Events") - .font(.headline) - - if upcomingEvents.isEmpty { - Text("No upcoming events") - .foregroundColor(.secondary) - .font(.caption) - } else { - VStack(spacing: 0) { - ForEach(Array(upcomingEvents.enumerated()), id: \.element.id) { index, event in - VStack(spacing: 0) { - HStack { - VStack(alignment: .leading, spacing: 2) { - Text(event.name) - .font(.subheadline) - .lineLimit(1) - - Text(formatEventDate(event.localDateTime())) - .font(.caption) - .foregroundColor(.secondary) - } - - Spacer() - - VStack(alignment: .trailing, spacing: 2) { - Text("\(event.daysUntil())d") - .font(.subheadline) - - Circle() - .fill(event.season.colorLight) - .frame(width: 12, height: 12) - } - } - .padding(.vertical, 8) - - if index < upcomingEvents.count - 1 { - Divider() - } - } - } - } - } - } - .padding() - .background(Color(.systemGray6)) - .cornerRadius(12) - } - - private func loadData() { - nextEvent = SolsticeData.shared.nextEvent() - upcomingEvents = SolsticeData.shared.upcomingEvents(count: 12) - progressData = SolsticeData.shared.progressToNextEvent() - - // Load sunrise/sunset from location if available - if let location = AppGroupManager.shared.getLocation() { - let sunTimes = SunTimes( - latitude: location.latitude, - longitude: location.longitude, - date: Date() - ) - sunriseTime = sunTimes.sunrise() - sunsetTime = sunTimes.sunset() - } - } - - private func formatEventDate(_ date: Date) -> String { - let formatter = DateFormatter() - formatter.dateStyle = .short - formatter.timeStyle = .short - formatter.timeZone = .current - return formatter.string(from: date) - } -} - -#Preview { - NavigationStack { - InfoScreenView() - } -} -- cgit v1.3