krz/moonrise

Night-sky companion for iPhone, Apple Watch and Vision Pro: what's up tonight, the Moon, planets, launches and missions, and a Library of the solar system. SwiftUI app with a Cloudflare Workers backend. astronomy cloudflare-workers ios night-sky space swiftui visionos watchos

Packages/MoonriseKit/Sources/Library/Tours.swift

6c4b28384d65e09486e0ad62f2ac9d10401cc80c
moonrise/Packages/MoonriseKit/Sources/Library/Tours.swift history · blame · raw

55 lines · 1979 bytes

 1import Foundation
 2
 3/// A guided walk around one season's evening sky.
 4public struct Tour: Sendable, Decodable, Identifiable {
 5    public struct Target: Sendable, Decodable, Hashable {
 6        /// IAU abbreviation, e.g. "Ori".
 7        public var constellation: String?
 8        public var hr: Int?
 9        /// Body raw value, e.g. "jupiter".
10        public var body: String?
11
12        public init(constellation: String? = nil, hr: Int? = nil, body: String? = nil) {
13            self.constellation = constellation
14            self.hr = hr
15            self.body = body
16        }
17    }
18
19    public struct Step: Sendable, Decodable, Hashable {
20        public var title: String
21        public var target: Target
22        public var text: String
23        /// Library page to open, when it is not the target's own page.
24        public var page: String?
25    }
26
27    public var id: String
28    public var title: String
29    /// Months (1–12) when the tour's stars are up in the evening (the same in both hemispheres).
30    public var months: [Int]
31    public var intro: String
32    public var steps: [Step]
33
34    public static let all: [Tour] = {
35        let url = Bundle.module.url(forResource: "tours", withExtension: "json", subdirectory: "tours")!
36        return try! JSONDecoder().decode([Tour].self, from: Data(contentsOf: url))
37    }()
38
39    /// Tours in order from the one for `month` onwards.
40    public static func ordered(month: Int) -> [Tour] {
41        let start = all.firstIndex { $0.months.contains(month) } ?? 0
42        return Array(all[start...] + all[..<start])
43    }
44}
45
46extension Tour.Step {
47    /// The step's own Library page, else the target's.
48    public var libraryPage: LibraryPage? {
49        if let page { return Library.page(id: page) }
50        if let hr = target.hr { return Library.page(hr: hr) }
51        if let c = target.constellation { return Library.page(constellation: c) }
52        if let b = target.body { return Library.page(body: b) }
53        return nil
54    }
55}