From b51335768fdfaf285e2bb9946c9c18a8ac3d82db Mon Sep 17 00:00:00 2001 From: NinjaCheetah <58050615+NinjaCheetah@users.noreply.github.com> Date: Wed, 14 Jan 2026 21:43:33 -0500 Subject: [PATCH] Mostly fixed multi opening period widgets! - The opening status label on widgets should update properly on time now. - Improved some of the logic related to determining opening statuses. Guards exist! - Reduced the text sizes so that more of the location names fits in the widgets. Also ensures that the full opening times will be displayed (this always worked for 24-hour time but wasn't guaranteed to fit for 12-hour time). --- Shared/Components/TigerCenterParsers.swift | 77 ++++++++++---------- TigerDine.xcodeproj/project.pbxproj | 8 +- TigerDineWidgets/Components/HoursGague.swift | 8 +- TigerDineWidgets/Widgets/HoursWidget.swift | 18 ++--- 4 files changed, 54 insertions(+), 57 deletions(-) diff --git a/Shared/Components/TigerCenterParsers.swift b/Shared/Components/TigerCenterParsers.swift index 9afd43e..b4f48d4 100644 --- a/Shared/Components/TigerCenterParsers.swift +++ b/Shared/Components/TigerCenterParsers.swift @@ -8,48 +8,50 @@ import Foundation /// Gets the current open status of a location based on the open time and close time. -func parseOpenStatus(openTime: Date, closeTime: Date) -> OpenStatus { - // This can probably be done a little cleaner but it's okay for now. If the location is open but the close date is within the next - // 30 minutes, label it as closing soon, and do the opposite if it's closed but the open date is within the next 30 minutes. +func parseOpenStatus(openTime: Date, closeTime: Date, referenceTime: Date) -> OpenStatus { + // If the location is open but the close time is within the next 30 minutes, label it as closing soon, and do the opposite + // if it's closed but the open time is within the next 30 minutes. let calendar = Calendar.current - let now = Date() - var openStatus: OpenStatus = .closed - if now >= openTime && now <= closeTime { + if referenceTime >= openTime && referenceTime <= closeTime { // This is basically just for Bytes, it checks the case where the open and close times are exactly 24 hours apart, which is // only true for 24-hour locations. if closeTime == calendar.date(byAdding: .day, value: 1, to: openTime)! { - openStatus = .open - } else if closeTime < calendar.date(byAdding: .minute, value: 30, to: now)! { - openStatus = .closingSoon - } else { - openStatus = .open + return .open + } else if closeTime < calendar.date(byAdding: .minute, value: 30, to: referenceTime)! { + return .closingSoon } - } else if openTime <= calendar.date(byAdding: .minute, value: 30, to: now)! && closeTime > now { - openStatus = .openingSoon - } else { - openStatus = .closed - } - return openStatus -} - -/// Gets the current open status of a location with multiple opening periods based on all of its open and close times. -func parseMultiOpenStatus(diningTimes: [DiningTimes]?) -> OpenStatus { - var openStatus: OpenStatus = .closed - if let diningTimes = diningTimes, !diningTimes.isEmpty { - for i in diningTimes.indices { - openStatus = parseOpenStatus(openTime: diningTimes[i].openTime, closeTime: diningTimes[i].closeTime) - // If the first event pass came back closed, loop again in case a later event has a different status. This is mostly to - // accurately catch Gracie's/Brick City Cafe's multiple open periods each day. - if openStatus != .closed { - break - } - } - return openStatus + return .open + } else if referenceTime < openTime && openTime <= calendar.date(byAdding: .minute, value: 30, to: referenceTime)! { + return .openingSoon } else { return .closed } } +/// Gets the current open status of a location with multiple opening periods based on all of its open and close times. +func parseMultiOpenStatus(diningTimes: [DiningTimes]?, referenceTime: Date) -> OpenStatus { + var openStatus: OpenStatus = .closed + + guard let diningTimes, !diningTimes.isEmpty else { + return .closed + } + + for i in diningTimes.indices { + openStatus = parseOpenStatus( + openTime: diningTimes[i].openTime, + closeTime: diningTimes[i].closeTime, + referenceTime: referenceTime + ) + // If the first event pass came back closed, loop again in case a later event has a different status. This is mostly to + // accurately catch Gracie's/Brick City Cafe's multiple open periods each day. + if openStatus != .closed { + return openStatus + } + } + + return .closed +} + /// Parses the JSON responses from the TigerCenter API into the format used throughout TigerDine. func parseLocationInfo(location: DiningLocationParser, forDate: Date?) -> DiningLocation { print("beginning parse for \(location.name)") @@ -181,7 +183,7 @@ func parseLocationInfo(location: DiningLocationParser, forDate: Date?) -> Dining // 30 minutes, label it as closing soon, and do the opposite if it's closed but the open date is within the next 30 minutes. var openStatus: OpenStatus = .closed for i in diningTimes.indices { - openStatus = parseOpenStatus(openTime: diningTimes[i].openTime, closeTime: diningTimes[i].closeTime) + openStatus = parseOpenStatus(openTime: diningTimes[i].openTime, closeTime: diningTimes[i].closeTime, referenceTime: now) // If the first event pass came back closed, loop again in case a later event has a different status. This is mostly to // accurately catch Gracie's multiple open periods each day. if openStatus != .closed { @@ -242,7 +244,7 @@ func parseLocationInfo(location: DiningLocationParser, forDate: Date?) -> Dining } // Parse the chef's status, mapping the OpenStatus to a VisitingChefStatus. - let visitngChefStatus: VisitingChefStatus = switch parseOpenStatus(openTime: openTime, closeTime: closeTime) { + let visitngChefStatus: VisitingChefStatus = switch parseOpenStatus(openTime: openTime, closeTime: closeTime, referenceTime: now) { case .open: .hereNow case .closed: @@ -297,14 +299,15 @@ extension DiningLocation { // Updates the open status of a location and of its visiting chefs, so that the labels in the UI update automatically as // time progresses and locations open/close/etc. mutating func updateOpenStatus() { + let now = Date() // Gets the open status with the multi opening period compatible function. - self.open = parseMultiOpenStatus(diningTimes: diningTimes) + self.open = parseMultiOpenStatus(diningTimes: diningTimes, referenceTime: now) if let visitingChefs = visitingChefs, !visitingChefs.isEmpty { - let now = Date() for i in visitingChefs.indices { self.visitingChefs![i].status = switch parseOpenStatus( openTime: visitingChefs[i].openTime, - closeTime: visitingChefs[i].closeTime) { + closeTime: visitingChefs[i].closeTime, + referenceTime: now) { case .open: .hereNow case .closed: diff --git a/TigerDine.xcodeproj/project.pbxproj b/TigerDine.xcodeproj/project.pbxproj index 6f44a6c..4be2207 100644 --- a/TigerDine.xcodeproj/project.pbxproj +++ b/TigerDine.xcodeproj/project.pbxproj @@ -292,7 +292,7 @@ CODE_SIGN_ENTITLEMENTS = TigerDineWidgets/TigerDineWidgets.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 28; + CURRENT_PROJECT_VERSION = 29; DEVELOPMENT_TEAM = 5GF7GKNTK4; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = TigerDineWidgets/Info.plist; @@ -325,7 +325,7 @@ CODE_SIGN_ENTITLEMENTS = TigerDineWidgets/TigerDineWidgets.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 28; + CURRENT_PROJECT_VERSION = 29; DEVELOPMENT_TEAM = 5GF7GKNTK4; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = TigerDineWidgets/Info.plist; @@ -481,7 +481,7 @@ CODE_SIGN_ENTITLEMENTS = TigerDine/TigerDine.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 28; + CURRENT_PROJECT_VERSION = 29; DEVELOPMENT_TEAM = 5GF7GKNTK4; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; @@ -518,7 +518,7 @@ CODE_SIGN_ENTITLEMENTS = TigerDine/TigerDine.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 28; + CURRENT_PROJECT_VERSION = 29; DEVELOPMENT_TEAM = 5GF7GKNTK4; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; diff --git a/TigerDineWidgets/Components/HoursGague.swift b/TigerDineWidgets/Components/HoursGague.swift index daf522e..bff2f7f 100644 --- a/TigerDineWidgets/Components/HoursGague.swift +++ b/TigerDineWidgets/Components/HoursGague.swift @@ -9,13 +9,13 @@ import SwiftUI struct OpeningHoursGauge: View { let diningTimes: [DiningTimes]? - let now: Date + let referenceTime: Date private let dayDuration: TimeInterval = 86_400 private var barFillColor: Color { if let diningTimes = diningTimes { - let openStatus = parseMultiOpenStatus(diningTimes: diningTimes) + let openStatus = parseMultiOpenStatus(diningTimes: diningTimes, referenceTime: referenceTime) switch openStatus { case .open: return Color.green @@ -34,10 +34,10 @@ struct OpeningHoursGauge: View { let width = geometry.size.width let barHeight: CGFloat = 16 - let startOfToday = Calendar.current.startOfDay(for: now) + let startOfToday = Calendar.current.startOfDay(for: referenceTime) let startOfTomorrow = Calendar.current.date(byAdding: .day, value: 1, to: startOfToday)! - let nowX = position(for: now, start: startOfToday, width: width) + let nowX = position(for: referenceTime, start: startOfToday, width: width) ZStack(alignment: .leading) { Capsule() diff --git a/TigerDineWidgets/Widgets/HoursWidget.swift b/TigerDineWidgets/Widgets/HoursWidget.swift index 2749bf1..423f2e6 100644 --- a/TigerDineWidgets/Widgets/HoursWidget.swift +++ b/TigerDineWidgets/Widgets/HoursWidget.swift @@ -89,9 +89,7 @@ struct Provider: AppIntentTimelineProvider { close: Date? ) -> [Date] { - var dates: Set = [] - - dates.insert(now) + var dates: Set = [now] if let open = open, let close = close { dates.insert(open) @@ -127,39 +125,35 @@ struct OpenWidgetEntryView : View { var body: some View { VStack(alignment: .leading) { Text(entry.name) - .font(.title2) + .font(.title3) .fontWeight(.bold) - // Should maybe try to unify this with the almost-identical UI code in DetailView. if let diningTimes = entry.diningTimes { - let openStatus = parseMultiOpenStatus(diningTimes: diningTimes) + let openStatus = parseMultiOpenStatus(diningTimes: diningTimes, referenceTime: entry.date) switch openStatus { case .open: Text("Open") - .font(.title3) .foregroundStyle(.green) case .closed: Text("Closed") - .font(.title3) .foregroundStyle(.red) case .openingSoon: Text("Opening Soon") - .font(.title3) .foregroundStyle(.orange) case .closingSoon: Text("Closing Soon") - .font(.title3) .foregroundStyle(.orange) } Text("\(dateDisplay.string(from: diningTimes[0].openTime)) - \(dateDisplay.string(from: diningTimes[0].closeTime))") + .font(.system(size: 15)) .foregroundStyle(.secondary) } else { Text("Closed") - .font(.title3) .foregroundStyle(.red) Text("Not Open Today") + .font(.system(size: 15)) .foregroundStyle(.secondary) } @@ -167,7 +161,7 @@ struct OpenWidgetEntryView : View { OpeningHoursGauge( diningTimes: entry.diningTimes, - now: entry.date + referenceTime: entry.date ) } }