Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,514 changes: 1,514 additions & 0 deletions Localizable.xcstrings

Large diffs are not rendered by default.

20 changes: 18 additions & 2 deletions Solstice.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,12 @@
713F7FF929BE843700BEA156 /* AnnualOverview.swift in Sources */ = {isa = PBXBuildFile; fileRef = 713F7FF829BE843700BEA156 /* AnnualOverview.swift */; };
713F7FFA29BE843700BEA156 /* AnnualOverview.swift in Sources */ = {isa = PBXBuildFile; fileRef = 713F7FF829BE843700BEA156 /* AnnualOverview.swift */; };
713F7FFC29BE867E00BEA156 /* DailyOverview.swift in Sources */ = {isa = PBXBuildFile; fileRef = 713F7FFB29BE867E00BEA156 /* DailyOverview.swift */; };
71EC11FE2F30000000000011 /* EclipseCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71EC11FE2F30000000000001 /* EclipseCalculator.swift */; };
71EC11FE2F30000000000012 /* EclipseCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71EC11FE2F30000000000001 /* EclipseCalculator.swift */; };
71EC11FE2F30000000000013 /* EclipseCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71EC11FE2F30000000000001 /* EclipseCalculator.swift */; };
71EC11FE2F30000000000014 /* EclipseCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71EC11FE2F30000000000001 /* EclipseCalculator.swift */; };
71EC11FE2F30000000000021 /* EclipseOverview.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71EC11FE2F30000000000002 /* EclipseOverview.swift */; };
71EC11FE2F30000000000022 /* EclipseOverview.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71EC11FE2F30000000000002 /* EclipseOverview.swift */; };
713F7FFD29BE867E00BEA156 /* DailyOverview.swift in Sources */ = {isa = PBXBuildFile; fileRef = 713F7FFB29BE867E00BEA156 /* DailyOverview.swift */; };
713F7FFF29BE88E800BEA156 /* DaylightSummaryTitle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 713F7FFE29BE88E800BEA156 /* DaylightSummaryTitle.swift */; };
713F800029BE88E800BEA156 /* DaylightSummaryTitle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 713F7FFE29BE88E800BEA156 /* DaylightSummaryTitle.swift */; };
Expand Down Expand Up @@ -515,6 +521,8 @@
71C635C72E9D9A8C003FA1AE /* Shared Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Shared Assets.xcassets"; sourceTree = "<group>"; };
71C718202E83361C006A6835 /* TimeTravelCompactView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeTravelCompactView.swift; sourceTree = "<group>"; };
71C8F4CD29A38752009A86B4 /* SolsticeCalculator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SolsticeCalculator.swift; sourceTree = "<group>"; };
71EC11FE2F30000000000001 /* EclipseCalculator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EclipseCalculator.swift; sourceTree = "<group>"; };
71EC11FE2F30000000000002 /* EclipseOverview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EclipseOverview.swift; sourceTree = "<group>"; };
71CA1E0029E0000000000001 /* Calendar++.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Calendar++.swift"; sourceTree = "<group>"; };
71CCE7993022311F00E2782D /* TimeTravelOrnamentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeTravelOrnamentView.swift; sourceTree = "<group>"; };
71DB52AB29AB8BED00D62BB7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
Expand Down Expand Up @@ -649,6 +657,7 @@
713F7FF829BE843700BEA156 /* AnnualOverview.swift */,
713F7FFB29BE867E00BEA156 /* DailyOverview.swift */,
713F7FFE29BE88E800BEA156 /* DaylightSummaryTitle.swift */,
71EC11FE2F30000000000002 /* EclipseOverview.swift */,
7198469D28E58CCD00E866CE /* DetailView.swift */,
71C4D8092EA9856800EEB023 /* SolarExtremetiesOverview.swift */,
);
Expand Down Expand Up @@ -823,6 +832,7 @@
48E63C6609375907FE3E8C3C /* Secrets.swift */,
BE27E44FFAA0D1493AA14281 /* Secrets.swift.template */,
71E9457F2F31FDA600B26D02 /* NTSolar.swift */,
71EC11FE2F30000000000001 /* EclipseCalculator.swift */,
71C8F4CD29A38752009A86B4 /* SolsticeCalculator.swift */,
71908ACC2AC95A5500C7B610 /* StringBuilder.swift */,
7123E75E30052CE20091C591 /* ScreenshotSupport.swift */,
Expand Down Expand Up @@ -1230,6 +1240,7 @@
710720913009257E006AA79C /* MarketingWidgetRenderer.swift in Sources */,
7187147729DDE6B700EADF03 /* CLLocationCoordinate2D++.swift in Sources */,
7150CC5C29AB7C3200E6B90C /* SolsticeCalculator.swift in Sources */,
71EC11FE2F30000000000011 /* EclipseCalculator.swift in Sources */,
7121DE0229C22E7D0031EEE7 /* View+Debugging.swift in Sources */,
7198C40E29DB06C1009A457E /* OverviewWidget.swift in Sources */,
718177692F2EA2EC007A2E9E /* LocationAppEntity.swift in Sources */,
Expand Down Expand Up @@ -1306,6 +1317,7 @@
719465232C2C1E09008408C0 /* AppStorage++.swift in Sources */,
719465242C2C1E09008408C0 /* CLLocationCoordinate2D++.swift in Sources */,
719465252C2C1E09008408C0 /* SolsticeCalculator.swift in Sources */,
71EC11FE2F30000000000012 /* EclipseCalculator.swift in Sources */,
719465262C2C1E09008408C0 /* View+Debugging.swift in Sources */,
719465272C2C1E09008408C0 /* OverviewWidget.swift in Sources */,
719465282C2C1E09008408C0 /* Color+Mix.swift in Sources */,
Expand Down Expand Up @@ -1375,6 +1387,7 @@
7198468728E5895E00E866CE /* ContentView.swift in Sources */,
71A029B22C3052BC00E19819 /* EquinoxAndSolsticeDescriptions.swift in Sources */,
713F7FF929BE843700BEA156 /* AnnualOverview.swift in Sources */,
71EC11FE2F30000000000021 /* EclipseOverview.swift in Sources */,
71F641B729994DD900FE5AB5 /* LocationListRow.swift in Sources */,
7194650E2C22B61E008408C0 /* AppChangeMigrator.swift in Sources */,
713F7FFF29BE88E800BEA156 /* DaylightSummaryTitle.swift in Sources */,
Expand Down Expand Up @@ -1407,6 +1420,7 @@
712433A92D78870600709C20 /* StackedButtonStyle.swift in Sources */,
71BC51CB2E91B56D0025892F /* CircularSolarChart.swift in Sources */,
71C8F4CE29A38752009A86B4 /* SolsticeCalculator.swift in Sources */,
71EC11FE2F30000000000013 /* EclipseCalculator.swift in Sources */,
711782EA2E4E7CE20006CE5B /* AsyncButton.swift in Sources */,
7116B1EE2DDD12BA0018A294 /* TimeMachinePanelView.swift in Sources */,
718177622F2E9BCF007A2E9E /* SolsticeConfigurationIntent.swift in Sources */,
Expand Down Expand Up @@ -1467,6 +1481,7 @@
711782DD2E4E0E030006CE5B /* LandingView.swift in Sources */,
719F928829ACD29100C06921 /* ContentView.swift in Sources */,
713F7FFA29BE843700BEA156 /* AnnualOverview.swift in Sources */,
71EC11FE2F30000000000022 /* EclipseOverview.swift in Sources */,
7132AC1A29E6962D00523215 /* ConditionalGlobals.swift in Sources */,
711782DA2E4DFDFE0006CE5B /* DeduplicateLocationRecordsModifier.swift in Sources */,
711782E72E4E77AF0006CE5B /* View+glassButtonStyle.swift in Sources */,
Expand Down Expand Up @@ -1504,6 +1519,7 @@
7188714429DC8C60001A4327 /* View+RectangularEdgeMask.swift in Sources */,
71E945C82F32506000B26D02 /* CircularSolarChart.swift in Sources */,
719F927C29ACD22100C06921 /* SolsticeCalculator.swift in Sources */,
71EC11FE2F30000000000014 /* EclipseCalculator.swift in Sources */,
719465162C294B42008408C0 /* Color+Mix.swift in Sources */,
71E3C41B2EA12B030005C884 /* View+backportGlassEffect.swift in Sources */,
7194650F2C22B61E008408C0 /* AppChangeMigrator.swift in Sources */,
Expand Down Expand Up @@ -1873,7 +1889,7 @@
GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "Solstice uses your location to calculate local sunrise and sunset times";
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MARKETING_VERSION = 3.2.0;
MARKETING_VERSION = 3.3.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
Expand Down Expand Up @@ -1935,7 +1951,7 @@
GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "Solstice uses your location to calculate local sunrise and sunset times";
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MARKETING_VERSION = 3.2.0;
MARKETING_VERSION = 3.3.0;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = iphoneos;
Expand Down
40 changes: 40 additions & 0 deletions Solstice/Detail View/DetailView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
//

import CoreData
import CoreLocation
import Suite
import SwiftUI
import TimeMachine
Expand All @@ -26,6 +27,7 @@ struct DetailView<Location: ObservableLocation>: View {
#endif
@State private var showRemainingDaylight = false
@State private var showShareSheet = false
@State private var eclipse: EclipseCalculator.LocalCircumstances?

@AppStorage(Preferences.detailViewChartAppearance) private var chartAppearance
@SceneStorage("selectedLocation") private var selectedLocation: String?
Expand Down Expand Up @@ -56,10 +58,17 @@ struct DetailView<Location: ObservableLocation>: View {
DailyOverview(solar: solar, location: location)
}

if let eclipse {
EclipseOverview(circumstances: eclipse, location: location)
}

AnnualOverview(location: location)
.id(Self.annualAnchor)
}
.formStyle(.grouped)
.task(id: eclipseSearchKey) {
await findEclipse()
}
#if os(macOS)
// The macOS toolbar has no Share button to carry the detail-screen identifier
// (that's iOS-only below), so tag the detail root for screenshot navigation.
Expand Down Expand Up @@ -123,6 +132,37 @@ struct DetailView<Location: ObservableLocation>: View {
"annual-overview"
}

/// Keyed on the place and the *day*, not the instant. Searching for eclipses is far
/// heavier than building an `NTSolar`, so it can't live in a computed property that
/// re-evaluates on every body pass — and keying on the day means dragging the
/// time-travel slider doesn't restart the search on every frame.
private var eclipseSearchKey: String {
"\(location.latitude),\(location.longitude),\(timeMachine.date.startOfDay.timeIntervalSince1970)"
}

private func findEclipse() async {
let latitude = location.latitude
let longitude = location.longitude
let date = timeMachine.date

let result = await Task.detached(priority: .utility) {
EclipseCalculator.nextEclipse(
at: CLLocationCoordinate2D(latitude: latitude, longitude: longitude),
after: date,
within: Constants.Eclipse.detailWindow,
minimumObscuration: Constants.Eclipse.detailThreshold
)
}.value

// Animating at the mutation site rather than with `.animation(_:value:)` on the
// form, which would also animate everything else in it. Covers all three
// transitions: the section arriving once the first search finishes, leaving when
// the eclipse is time-travelled past, and swapping one eclipse for another.
withAnimation {
eclipse = result
}
}

var toolbarItemPlacement: ToolbarItemPlacement {
#if os(macOS)
return .automatic
Expand Down
Loading