summaryrefslogtreecommitdiffstats
path: root/Solverv
diff options
context:
space:
mode:
Diffstat (limited to 'Solverv')
-rw-r--r--Solverv/ContentView.swift53
-rw-r--r--Solverv/Views/InfoScreenView.swift200
2 files changed, 212 insertions, 41 deletions
diff --git a/Solverv/ContentView.swift b/Solverv/ContentView.swift
index b82e2c7..38c6153 100644
--- a/Solverv/ContentView.swift
+++ b/Solverv/ContentView.swift
@@ -6,56 +6,27 @@
//
import SwiftUI
-import SwiftData
struct ContentView: View {
- @Environment(\.modelContext) private var modelContext
- @Query private var items: [Item]
-
var body: some View {
- NavigationSplitView {
- List {
- ForEach(items) { item in
- NavigationLink {
- Text("Item at \(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))")
- } label: {
- Text(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))
- }
- }
- .onDelete(perform: deleteItems)
- }
- .toolbar {
- ToolbarItem(placement: .navigationBarTrailing) {
- EditButton()
- }
- ToolbarItem {
- Button(action: addItem) {
- Label("Add Item", systemImage: "plus")
- }
- }
- }
- } detail: {
- Text("Select an item")
- }
- }
-
- private func addItem() {
- withAnimation {
- let newItem = Item(timestamp: Date())
- modelContext.insert(newItem)
- }
- }
+ NavigationStack {
+ VStack {
+ Text("Solstice Countdown")
+ .font(.title)
- private func deleteItems(offsets: IndexSet) {
- withAnimation {
- for index in offsets {
- modelContext.delete(items[index])
+ NavigationLink(destination: InfoScreenView()) {
+ Label("View Details", systemImage: "info.circle")
+ .padding()
+ .background(Color.blue)
+ .foregroundColor(.white)
+ .cornerRadius(8)
+ }
}
+ .navigationTitle("Home")
}
}
}
#Preview {
ContentView()
- .modelContainer(for: Item.self, inMemory: true)
}
diff --git a/Solverv/Views/InfoScreenView.swift b/Solverv/Views/InfoScreenView.swift
new file mode 100644
index 0000000..d876a45
--- /dev/null
+++ b/Solverv/Views/InfoScreenView.swift
@@ -0,0 +1,200 @@
+//
+// 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()
+ }
+}