mirror of
https://github.com/NinjaCheetah/RIT-Dining.git
synced 2025-10-19 06:36:18 -04:00
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.
105 lines
3.6 KiB
Swift
105 lines
3.6 KiB
Swift
//
|
|
// DetailView.swift
|
|
// RIT Dining
|
|
//
|
|
// Created by Campbell on 9/1/25.
|
|
//
|
|
|
|
import SwiftUI
|
|
import SafariServices
|
|
|
|
// Gross disgusting UIKit code :(
|
|
// There isn't a direct way to use integrated Safari from SwiftUI, except maybe in iOS 26? I'm not targeting that though so I must fall
|
|
// back on UIKit stuff.
|
|
struct SafariView: UIViewControllerRepresentable {
|
|
let url: URL
|
|
|
|
func makeUIViewController(context: Context) -> SFSafariViewController {
|
|
SFSafariViewController(url: url)
|
|
}
|
|
|
|
func updateUIViewController(_ uiViewController: SFSafariViewController, context: Context) {}
|
|
}
|
|
|
|
struct DetailView: View {
|
|
@State var location: DiningLocation
|
|
@State private var showingSafari: Bool = false
|
|
|
|
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 {
|
|
ScrollView {
|
|
VStack(alignment: .leading) {
|
|
Text(location.name)
|
|
.font(.title)
|
|
Text(location.summary)
|
|
.font(.title2)
|
|
.foregroundStyle(.secondary)
|
|
HStack(alignment: .top) {
|
|
switch location.open {
|
|
case .open:
|
|
Text("Open")
|
|
.foregroundStyle(.green)
|
|
case .closed:
|
|
Text("Closed")
|
|
.foregroundStyle(.red)
|
|
case .openingSoon:
|
|
Text("Opening Soon")
|
|
.foregroundStyle(.orange)
|
|
case .closingSoon:
|
|
Text("Closing Soon")
|
|
.foregroundStyle(.orange)
|
|
}
|
|
VStack {
|
|
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)
|
|
}
|
|
}
|
|
}
|
|
.padding(.bottom, 10)
|
|
Button(action: {
|
|
showingSafari = true
|
|
}) {
|
|
Text("View on Map")
|
|
}
|
|
.padding(.bottom, 10)
|
|
Text(location.desc)
|
|
.font(.body)
|
|
.padding(.bottom, 10)
|
|
Text("IMPORTANT: Some locations' descriptions may refer to them as being cashless during certain hours. This is outdated information, as all RIT Dining locations are now cashless 24/7.")
|
|
.font(.callout)
|
|
.foregroundStyle(.secondary)
|
|
}
|
|
.padding(.horizontal, 8)
|
|
}
|
|
.navigationTitle("Details")
|
|
.navigationBarTitleDisplayMode(.inline)
|
|
.sheet(isPresented: $showingSafari) {
|
|
SafariView(url: URL(string: location.mapsUrl)!)
|
|
}
|
|
}
|
|
}
|
|
|
|
#Preview {
|
|
DetailView(location: DiningLocation(
|
|
id: 0,
|
|
name: "Example",
|
|
summary: "A Place",
|
|
desc: "A long description of the place",
|
|
mapsUrl: "https://example.com",
|
|
diningTimes: [DiningTimes(openTime: Date(), closeTime: Date())],
|
|
open: .open))
|
|
}
|