From 30c025e113627c7fe7cda763c5622fc25fce4b23 Mon Sep 17 00:00:00 2001 From: NinjaCheetah <58050615+NinjaCheetah@users.noreply.github.com> Date: Tue, 2 Sep 2025 15:03:43 -0400 Subject: [PATCH] Lots of code cleanup Separated types out into their own file to make them easier to keep track of, and described what they're all for better. Also removed unnecessary "Location" type used in ContentView to display data, because it was almost an exact duplicate of the type that it was being created from. Removing that removed a lot of pointless extra logic, and should make the processs of how it pulls and parses the data easier to understand. Multiple open periods for one location are also now sorted, so that the earliest open time will be shown first. Some locations have them flipped in the response data, so they were backwards before. --- RIT Dining/ContentView.swift | 73 +++++++++------------------ RIT Dining/DetailView.swift | 28 ++++++++--- RIT Dining/FetchData.swift | 98 +++++++++--------------------------- RIT Dining/Types.swift | 66 ++++++++++++++++++++++++ 4 files changed, 136 insertions(+), 129 deletions(-) create mode 100644 RIT Dining/Types.swift 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..