mirror of
https://github.com/NinjaCheetah/RIT-Dining.git
synced 2026-01-17 12:05:57 -05:00
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).
This commit is contained in:
parent
71c37749e3
commit
b51335768f
@ -8,48 +8,50 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
/// Gets the current open status of a location based on the open time and close time.
|
/// Gets the current open status of a location based on the open time and close time.
|
||||||
func parseOpenStatus(openTime: Date, closeTime: Date) -> OpenStatus {
|
func parseOpenStatus(openTime: Date, closeTime: Date, referenceTime: 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
|
// If the location is open but the close time is within the next 30 minutes, label it as closing soon, and do the opposite
|
||||||
// 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.
|
// if it's closed but the open time is within the next 30 minutes.
|
||||||
let calendar = Calendar.current
|
let calendar = Calendar.current
|
||||||
let now = Date()
|
if referenceTime >= openTime && referenceTime <= closeTime {
|
||||||
var openStatus: OpenStatus = .closed
|
|
||||||
if now >= openTime && now <= closeTime {
|
|
||||||
// This is basically just for Bytes, it checks the case where the open and close times are exactly 24 hours apart, which is
|
// 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.
|
// only true for 24-hour locations.
|
||||||
if closeTime == calendar.date(byAdding: .day, value: 1, to: openTime)! {
|
if closeTime == calendar.date(byAdding: .day, value: 1, to: openTime)! {
|
||||||
openStatus = .open
|
return .open
|
||||||
} else if closeTime < calendar.date(byAdding: .minute, value: 30, to: now)! {
|
} else if closeTime < calendar.date(byAdding: .minute, value: 30, to: referenceTime)! {
|
||||||
openStatus = .closingSoon
|
return .closingSoon
|
||||||
} else {
|
|
||||||
openStatus = .open
|
|
||||||
}
|
}
|
||||||
} else if openTime <= calendar.date(byAdding: .minute, value: 30, to: now)! && closeTime > now {
|
return .open
|
||||||
openStatus = .openingSoon
|
} else if referenceTime < openTime && openTime <= calendar.date(byAdding: .minute, value: 30, to: referenceTime)! {
|
||||||
} else {
|
return .openingSoon
|
||||||
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
|
|
||||||
} else {
|
} else {
|
||||||
return .closed
|
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.
|
/// Parses the JSON responses from the TigerCenter API into the format used throughout TigerDine.
|
||||||
func parseLocationInfo(location: DiningLocationParser, forDate: Date?) -> DiningLocation {
|
func parseLocationInfo(location: DiningLocationParser, forDate: Date?) -> DiningLocation {
|
||||||
print("beginning parse for \(location.name)")
|
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.
|
// 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
|
var openStatus: OpenStatus = .closed
|
||||||
for i in diningTimes.indices {
|
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
|
// 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.
|
// accurately catch Gracie's multiple open periods each day.
|
||||||
if openStatus != .closed {
|
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.
|
// 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:
|
case .open:
|
||||||
.hereNow
|
.hereNow
|
||||||
case .closed:
|
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
|
// 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.
|
// time progresses and locations open/close/etc.
|
||||||
mutating func updateOpenStatus() {
|
mutating func updateOpenStatus() {
|
||||||
// Gets the open status with the multi opening period compatible function.
|
|
||||||
self.open = parseMultiOpenStatus(diningTimes: diningTimes)
|
|
||||||
if let visitingChefs = visitingChefs, !visitingChefs.isEmpty {
|
|
||||||
let now = Date()
|
let now = Date()
|
||||||
|
// Gets the open status with the multi opening period compatible function.
|
||||||
|
self.open = parseMultiOpenStatus(diningTimes: diningTimes, referenceTime: now)
|
||||||
|
if let visitingChefs = visitingChefs, !visitingChefs.isEmpty {
|
||||||
for i in visitingChefs.indices {
|
for i in visitingChefs.indices {
|
||||||
self.visitingChefs![i].status = switch parseOpenStatus(
|
self.visitingChefs![i].status = switch parseOpenStatus(
|
||||||
openTime: visitingChefs[i].openTime,
|
openTime: visitingChefs[i].openTime,
|
||||||
closeTime: visitingChefs[i].closeTime) {
|
closeTime: visitingChefs[i].closeTime,
|
||||||
|
referenceTime: now) {
|
||||||
case .open:
|
case .open:
|
||||||
.hereNow
|
.hereNow
|
||||||
case .closed:
|
case .closed:
|
||||||
|
|||||||
@ -292,7 +292,7 @@
|
|||||||
CODE_SIGN_ENTITLEMENTS = TigerDineWidgets/TigerDineWidgets.entitlements;
|
CODE_SIGN_ENTITLEMENTS = TigerDineWidgets/TigerDineWidgets.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 28;
|
CURRENT_PROJECT_VERSION = 29;
|
||||||
DEVELOPMENT_TEAM = 5GF7GKNTK4;
|
DEVELOPMENT_TEAM = 5GF7GKNTK4;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
INFOPLIST_FILE = TigerDineWidgets/Info.plist;
|
INFOPLIST_FILE = TigerDineWidgets/Info.plist;
|
||||||
@ -325,7 +325,7 @@
|
|||||||
CODE_SIGN_ENTITLEMENTS = TigerDineWidgets/TigerDineWidgets.entitlements;
|
CODE_SIGN_ENTITLEMENTS = TigerDineWidgets/TigerDineWidgets.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 28;
|
CURRENT_PROJECT_VERSION = 29;
|
||||||
DEVELOPMENT_TEAM = 5GF7GKNTK4;
|
DEVELOPMENT_TEAM = 5GF7GKNTK4;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
INFOPLIST_FILE = TigerDineWidgets/Info.plist;
|
INFOPLIST_FILE = TigerDineWidgets/Info.plist;
|
||||||
@ -481,7 +481,7 @@
|
|||||||
CODE_SIGN_ENTITLEMENTS = TigerDine/TigerDine.entitlements;
|
CODE_SIGN_ENTITLEMENTS = TigerDine/TigerDine.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 28;
|
CURRENT_PROJECT_VERSION = 29;
|
||||||
DEVELOPMENT_TEAM = 5GF7GKNTK4;
|
DEVELOPMENT_TEAM = 5GF7GKNTK4;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
@ -518,7 +518,7 @@
|
|||||||
CODE_SIGN_ENTITLEMENTS = TigerDine/TigerDine.entitlements;
|
CODE_SIGN_ENTITLEMENTS = TigerDine/TigerDine.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 28;
|
CURRENT_PROJECT_VERSION = 29;
|
||||||
DEVELOPMENT_TEAM = 5GF7GKNTK4;
|
DEVELOPMENT_TEAM = 5GF7GKNTK4;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
|||||||
@ -9,13 +9,13 @@ import SwiftUI
|
|||||||
|
|
||||||
struct OpeningHoursGauge: View {
|
struct OpeningHoursGauge: View {
|
||||||
let diningTimes: [DiningTimes]?
|
let diningTimes: [DiningTimes]?
|
||||||
let now: Date
|
let referenceTime: Date
|
||||||
|
|
||||||
private let dayDuration: TimeInterval = 86_400
|
private let dayDuration: TimeInterval = 86_400
|
||||||
|
|
||||||
private var barFillColor: Color {
|
private var barFillColor: Color {
|
||||||
if let diningTimes = diningTimes {
|
if let diningTimes = diningTimes {
|
||||||
let openStatus = parseMultiOpenStatus(diningTimes: diningTimes)
|
let openStatus = parseMultiOpenStatus(diningTimes: diningTimes, referenceTime: referenceTime)
|
||||||
switch openStatus {
|
switch openStatus {
|
||||||
case .open:
|
case .open:
|
||||||
return Color.green
|
return Color.green
|
||||||
@ -34,10 +34,10 @@ struct OpeningHoursGauge: View {
|
|||||||
let width = geometry.size.width
|
let width = geometry.size.width
|
||||||
let barHeight: CGFloat = 16
|
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 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) {
|
ZStack(alignment: .leading) {
|
||||||
Capsule()
|
Capsule()
|
||||||
|
|||||||
@ -89,9 +89,7 @@ struct Provider: AppIntentTimelineProvider {
|
|||||||
close: Date?
|
close: Date?
|
||||||
) -> [Date] {
|
) -> [Date] {
|
||||||
|
|
||||||
var dates: Set<Date> = []
|
var dates: Set<Date> = [now]
|
||||||
|
|
||||||
dates.insert(now)
|
|
||||||
|
|
||||||
if let open = open, let close = close {
|
if let open = open, let close = close {
|
||||||
dates.insert(open)
|
dates.insert(open)
|
||||||
@ -127,39 +125,35 @@ struct OpenWidgetEntryView : View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
Text(entry.name)
|
Text(entry.name)
|
||||||
.font(.title2)
|
.font(.title3)
|
||||||
.fontWeight(.bold)
|
.fontWeight(.bold)
|
||||||
|
|
||||||
// Should maybe try to unify this with the almost-identical UI code in DetailView.
|
|
||||||
if let diningTimes = entry.diningTimes {
|
if let diningTimes = entry.diningTimes {
|
||||||
let openStatus = parseMultiOpenStatus(diningTimes: diningTimes)
|
let openStatus = parseMultiOpenStatus(diningTimes: diningTimes, referenceTime: entry.date)
|
||||||
switch openStatus {
|
switch openStatus {
|
||||||
case .open:
|
case .open:
|
||||||
Text("Open")
|
Text("Open")
|
||||||
.font(.title3)
|
|
||||||
.foregroundStyle(.green)
|
.foregroundStyle(.green)
|
||||||
case .closed:
|
case .closed:
|
||||||
Text("Closed")
|
Text("Closed")
|
||||||
.font(.title3)
|
|
||||||
.foregroundStyle(.red)
|
.foregroundStyle(.red)
|
||||||
case .openingSoon:
|
case .openingSoon:
|
||||||
Text("Opening Soon")
|
Text("Opening Soon")
|
||||||
.font(.title3)
|
|
||||||
.foregroundStyle(.orange)
|
.foregroundStyle(.orange)
|
||||||
case .closingSoon:
|
case .closingSoon:
|
||||||
Text("Closing Soon")
|
Text("Closing Soon")
|
||||||
.font(.title3)
|
|
||||||
.foregroundStyle(.orange)
|
.foregroundStyle(.orange)
|
||||||
}
|
}
|
||||||
|
|
||||||
Text("\(dateDisplay.string(from: diningTimes[0].openTime)) - \(dateDisplay.string(from: diningTimes[0].closeTime))")
|
Text("\(dateDisplay.string(from: diningTimes[0].openTime)) - \(dateDisplay.string(from: diningTimes[0].closeTime))")
|
||||||
|
.font(.system(size: 15))
|
||||||
.foregroundStyle(.secondary)
|
.foregroundStyle(.secondary)
|
||||||
} else {
|
} else {
|
||||||
Text("Closed")
|
Text("Closed")
|
||||||
.font(.title3)
|
|
||||||
.foregroundStyle(.red)
|
.foregroundStyle(.red)
|
||||||
|
|
||||||
Text("Not Open Today")
|
Text("Not Open Today")
|
||||||
|
.font(.system(size: 15))
|
||||||
.foregroundStyle(.secondary)
|
.foregroundStyle(.secondary)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,7 +161,7 @@ struct OpenWidgetEntryView : View {
|
|||||||
|
|
||||||
OpeningHoursGauge(
|
OpeningHoursGauge(
|
||||||
diningTimes: entry.diningTimes,
|
diningTimes: entry.diningTimes,
|
||||||
now: entry.date
|
referenceTime: entry.date
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user