Commit 91b67642 by Demid Merzlyakov

Fix moonrise / moonset.

parent fccd6f5e
......@@ -32,8 +32,8 @@ public struct CurrentWeather: Equatable, Hashable {
public var sunState: CelestialState? = .normal
public var moonrise: Date?
public var moonset: Date?
/// An approximate moonset value that can be used to draw animation when usual moonset is not available. Do not show this value to the user as actual time.
public var approximateMoonset: Date?
/// An approximate moonrise value that can be used to draw animation when usual moonrise is not available. Do not show this value to the user as actual time.
public var approximateMoonrise: Date?
public var moonState: CelestialState? = .normal
public var moonPhase: MoonPhase? = .unknown
}
......@@ -70,6 +70,7 @@ extension CurrentWeather: UpdatableModelObjectInTime {
result.moonset = incrementalChanges.moonset ?? result.moonset
result.moonState = incrementalChanges.moonState ?? result.moonState
result.moonPhase = incrementalChanges.moonPhase ?? result.moonPhase
result.approximateMoonrise = incrementalChanges.approximateMoonrise ?? result.approximateMoonrise
return result
}
......
......@@ -27,9 +27,9 @@ public struct DailyWeather: Equatable, Hashable {
public var sunset: Date?
public var sunState: CelestialState? = .normal
/// Note: this is when the moon rises in the evening. So, moonset < moonrise. It's different in CurrentWeather.
/// Note: moonrise can be before moonset or after it, or a day before or after. I love WDT...
public var moonrise: Date?
/// Note: this is when the moon sets in the morning. So, moonset < moonrise. It's different in CurrentWeather.
/// Note: moonset can be before moonrise or after it, or a day before or after. I love WDT...
public var moonset: Date?
public var moonState: CelestialState? = .normal
public var moonPhase: MoonPhase? = .unknown
......
......@@ -47,43 +47,66 @@ struct WdtLocation: Codable {
today.minTemp = todayInDaily.minTemp
today.maxTemp = todayInDaily.maxTemp
today.precipitationProbability = todayInDaily.precipitationProbability
today.sunState = todayInDaily.sunState ?? .normal
today.approximateMoonset = todayInDaily.moonset
today.sunState = todayInDaily.sunState
today.approximateMoonrise = todayInDaily.moonrise?.addingTimeInterval(-24 * 3600) // -24 hours
let currentDate = Date()
// In CurrentWeather (which is what `today` is) we're only interested in moonrise / moonset pair that hasn't passed yet.
// Moonrise / moonset are available in daily in the WDT API.
// And in DailyWeather moonset happens in the morning, before the moonrise in the evening.
// So, we need to find the first moonset in daily that hasn't passed (and that isn't too far from the current date). The day before it (if we have it) will contain the corresponding moonrise.
let dayWithNextMoonsetFilter: (DailyWeather) -> Bool = {
// not too efficient, but acceptable
guard let moonset = $0.moonset else {
return false
}
guard moonset > currentDate else {
return false
enum MoonType: CustomDebugStringConvertible {
case rise
case set
var debugDescription: String {
return self == .rise ? "rise" : "set"
}
let dateWithin24Hours = fabs($0.date.timeIntervalSince(currentDate)) < TimeInterval(24 * 3600)
guard dateWithin24Hours else {
return false
}
struct MoonEvent {
var type: MoonType
let date: Date
let phase: MoonPhase?
let state: CelestialState?
init?(type: MoonType, phase: MoonPhase?, state: CelestialState?, date: Date?) {
guard let date = date else { return nil }
self.type = type
self.date = date
self.phase = phase
self.state = state
}
return true
}
if let indexOfDayWithNextMoonset = daily.firstIndex(where: dayWithNextMoonsetFilter) {
let moonsetDayInDaily = daily[indexOfDayWithNextMoonset]
var moonriseDayInDaily: DailyWeather? = nil
if indexOfDayWithNextMoonset > 0 {
moonriseDayInDaily = daily[indexOfDayWithNextMoonset - 1]
let allMoonrises: [MoonEvent] = daily.compactMap { MoonEvent(type: .rise, phase: $0.moonPhase, state: $0.moonState, date: $0.moonrise) }
let allMoonsets: [MoonEvent] = daily.compactMap { MoonEvent(type: .set, phase: $0.moonPhase, state: $0.moonState, date: $0.moonset) }
let currentDate = Date()
let allMoonEvents: [MoonEvent] = (allMoonrises + allMoonsets)
.filter({ fabs($0.date.timeIntervalSince(currentDate)) < TimeInterval(24 * 3600) }) // +-24 hours from current date
.sorted(by: { $1.date > $0.date })
let nextMoonsetFilter: (MoonEvent) -> Bool = {
$0.type == .set && $0.date > currentDate
}
if let indexOfNextMoonset = allMoonEvents.firstIndex(where: nextMoonsetFilter) {
let nextMoonset = allMoonEvents[indexOfNextMoonset]
today.moonset = nextMoonset.date
today.moonPhase = nextMoonset.phase
today.moonState = nextMoonset.state
if indexOfNextMoonset > 0 && allMoonEvents[indexOfNextMoonset - 1].type == .rise {
today.moonrise = allMoonEvents[indexOfNextMoonset - 1].date
}
today.moonset = moonsetDayInDaily.moonset
today.moonPhase = moonsetDayInDaily.moonPhase
today.moonState = moonsetDayInDaily.moonState
today.moonrise = moonriseDayInDaily?.moonrise
}
//TODO: finish debugging, doesn't work properly.
return today
}
......
......@@ -131,23 +131,31 @@ class MoonPhaseCell: UITableViewCell {
//Public
public func configure(with location:Location) {
MoonPhaseCell.dateFormatter.timeZone = location.today?.timeZone
MoonPhaseCell.nowDateFormatter.timeZone = location.today?.timeZone
moonTypeLabel.text = location.today?.moonPhase?.localized
let today = location.today // for convenience
MoonPhaseCell.dateFormatter.timeZone = today?.timeZone
MoonPhaseCell.nowDateFormatter.timeZone = today?.timeZone
moonTypeLabel.text = today?.moonPhase?.localized
guard
let moonrise = location.today?.moonrise,
let moonset = location.today?.moonset
let moonrise = today?.moonrise ?? today?.approximateMoonrise,
let moonset = today?.moonset
else {
return
}
moonriseTimeLabel.text = MoonPhaseCell.dateFormatter.string(from: moonrise)
if today?.moonrise != nil {
// it's not approximate moonrise
moonriseTimeLabel.text = MoonPhaseCell.dateFormatter.string(from: moonrise)
}
else {
moonriseTimeLabel.text = ""
}
moonsetTimeLabel.text = MoonPhaseCell.dateFormatter.string(from: moonset)
let moonTimePeriod = moonset.timeIntervalSince1970 - moonrise.timeIntervalSince1970
let moonTimePeriod = moonset.timeIntervalSince(moonrise)
let nowString = MoonPhaseCell.nowDateFormatter.string(from: Date())
let nowDate = MoonPhaseCell.nowDateFormatter.date(from: nowString) ?? Date()
self.moonProgress = CGFloat((nowDate.timeIntervalSince1970 - moonrise.timeIntervalSince1970) / moonTimePeriod)
self.moonProgress = CGFloat(nowDate.timeIntervalSince(moonrise) / moonTimePeriod)
}
public func updateMoonPosition() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment