diff --git a/RIT Dining/ContentView.swift b/RIT Dining/ContentView.swift index f9c9675..ad66957 100644 --- a/RIT Dining/ContentView.swift +++ b/RIT Dining/ContentView.swift @@ -7,24 +7,24 @@ import SwiftUI -struct Location: Hashable { - let name: String - let summary: String - let desc: String - let mapsUrl: String - let todaysHours: [String] - let isOpen: openStatus -} - struct LocationList: View { - let diningLocations: [Location] + let diningLocations: [DiningLocation] + + // I forgot this before and was really confused why all of the times were in UTC. + private let display: DateFormatter = { + let display = DateFormatter() + display.timeZone = TimeZone(identifier: "America/New_York") + display.dateStyle = .none + display.timeStyle = .short + return display + }() var body: some View { ForEach(diningLocations, id: \.self) { location in NavigationLink(destination: DetailView(location: location)) { VStack(alignment: .leading) { Text(location.name) - switch location.isOpen { + switch location.open { case .open: Text("Open") .foregroundStyle(.green) @@ -38,8 +38,13 @@ struct LocationList: View { Text("Closing Soon") .foregroundStyle(.orange) } - ForEach(location.todaysHours, id: \.self) { hours in - Text(hours) + if let times = location.diningTimes, !times.isEmpty { + ForEach(times, id: \.self) { time in + Text("\(display.string(from: time.openTime)) - \(display.string(from: time.closeTime))") + .foregroundStyle(.secondary) + } + } else { + Text("Not Open Today") .foregroundStyle(.secondary) } } @@ -51,7 +56,7 @@ struct LocationList: View { struct ContentView: View { @State private var isLoading = true @State private var rotationDegrees: Double = 0 - @State private var diningLocations: [Location] = [] + @State private var diningLocations: [DiningLocation] = [] @State private var lastRefreshed: Date? @State private var searchText: String = "" @State private var openLocationsOnly: Bool = false @@ -64,49 +69,21 @@ struct ContentView: View { // Asynchronously fetch the data for all of the locations and parse their data to display it. private func getDiningData() { - var newDiningLocations: [Location] = [] - getDiningLocation { result in + var newDiningLocations: [DiningLocation] = [] + getAllDiningInfo { result in DispatchQueue.global().async { switch result { case .success(let locations): for i in 0..) -> Void) { +func getAllDiningInfo(completionHandler: @escaping (Result) -> Void) { // The endpoint requires that you specify a date, so get today's. let date_string = Date().formatted(.iso8601 .year().month().day() @@ -70,34 +39,12 @@ func getDiningLocation(completionHandler: @escaping (Result = Result(catching: { try JSONDecoder().decode(DiningLocations.self, from: data) }) + let decoded: Result = Result(catching: { try JSONDecoder().decode(DiningLocationsParser.self, from: data) }) completionHandler(decoded) }.resume() } -enum openStatus { - case open - case closed - case openingSoon - case closingSoon -} - -struct DiningTimes: Equatable { - let openTime: Date - let closeTime: Date -} - -struct DiningInfo { - let id: Int - let name: String - let summary: String - let desc: String - let mapsUrl: String - let diningTimes: [DiningTimes]? - let open: openStatus -} - -func getLocationInfo(location: DiningLocation) -> DiningInfo { +func getLocationInfo(location: DiningLocationParser) -> DiningLocation { print("beginning parse for \(location.name)") // The descriptions sometimes have HTML
tags despite also having \n. Those need to be removed. @@ -105,13 +52,13 @@ func getLocationInfo(location: DiningLocation) -> DiningInfo { // Early return if there are no events, good for things like the food trucks which can very easily have no openings in a week. if location.events.isEmpty { - return DiningInfo( + return DiningLocation( id: location.id, name: location.name, summary: location.summary, desc: desc, mapsUrl: location.mapsUrl, - diningTimes: .none, + diningTimes: nil, open: .closed) } @@ -124,13 +71,13 @@ func getLocationInfo(location: DiningLocation) -> DiningInfo { if let exceptions = event.exceptions, !exceptions.isEmpty { // Early return if the exception for the day specifies that the location is closed. Used for things like holidays. if !exceptions[0].open { - return DiningInfo( + return DiningLocation( id: location.id, name: location.name, summary: location.summary, desc: desc, mapsUrl: location.mapsUrl, - diningTimes: .none, + diningTimes: nil, open: .closed) } openStrings.append(exceptions[0].startTime) @@ -167,26 +114,34 @@ func getLocationInfo(location: DiningLocation) -> DiningInfo { second: closeTimeComponents.second!, of: now)!) } + var diningTimes: [DiningTimes] = [] + for i in 0..= openDates[i] && now <= closeDates[i] { - if closeDates[i] < calendar.date(byAdding: .minute, value: 30, to: now)! { + var openStatus: OpenStatus = .closed + for i in diningTimes.indices { + if now >= diningTimes[i].openTime && now <= diningTimes[i].closeTime { + if diningTimes[i].closeTime < calendar.date(byAdding: .minute, value: 30, to: now)! { openStatus = .closingSoon } else { openStatus = .open } - } else if openDates[i] <= calendar.date(byAdding: .minute, value: 30, to: now)! && closeDates[i] > now { + } else if diningTimes[i].openTime <= calendar.date(byAdding: .minute, value: 30, to: now)! && diningTimes[i].closeTime > now { openStatus = .openingSoon } else { openStatus = .closed @@ -198,12 +153,7 @@ func getLocationInfo(location: DiningLocation) -> DiningInfo { } } - var diningTimes: [DiningTimes] = [] - for i in 0..