mirror of
https://github.com/NinjaCheetah/RIT-Dining.git
synced 2026-03-04 21:25:27 -05:00
- Widgets will now open the appropriate DetailView in the app when you tap on them. - ...except when they don't. This is still a little buggy. It works correctly when the app is already alive in the background but only works about 75% of the time when the app isn't running yet. - Unified the loading view into a shared view used in all places requiring loading
116 lines
4.8 KiB
Swift
116 lines
4.8 KiB
Swift
//
|
|
// LocationList.swift
|
|
// TigerDine
|
|
//
|
|
// Created by Campbell on 10/1/25.
|
|
//
|
|
|
|
import SwiftUI
|
|
|
|
// This view handles the actual location list, because having it inside ContentView was too complex (both visually and for the
|
|
// type checker too, apparently).
|
|
struct LocationList: View {
|
|
@Binding var openLocationsFirst: Bool
|
|
@Binding var openLocationsOnly: Bool
|
|
@Binding var searchText: String
|
|
|
|
@Environment(DiningModel.self) var model
|
|
|
|
// The dining locations need to be sorted before being displayed. Favorites should always be shown first, followed by non-favorites.
|
|
// Afterwards, filters the sorted list based on any current search text and the "open locations only" filtering option.
|
|
private var filteredLocations: [DiningLocation] {
|
|
var newLocations = model.locationsByDay[0]
|
|
// Because "The Commons" should be C for "Commons" and not T for "The".
|
|
func removeThe(_ name: String) -> String {
|
|
let lowercased = name.lowercased()
|
|
if lowercased.hasPrefix("the ") {
|
|
return String(name.dropFirst(4))
|
|
}
|
|
return name
|
|
}
|
|
newLocations.sort { firstLoc, secondLoc in
|
|
let firstLocIsFavorite = model.favorites.contains(firstLoc)
|
|
let secondLocIsFavorite = model.favorites.contains(secondLoc)
|
|
// Favorites get priority!
|
|
if firstLocIsFavorite != secondLocIsFavorite {
|
|
return firstLocIsFavorite && !secondLocIsFavorite
|
|
}
|
|
// Additional sorting rule that sorts open locations ahead of closed locations, if enabled.
|
|
if openLocationsFirst {
|
|
let firstIsOpen = (firstLoc.open == .open || firstLoc.open == .closingSoon)
|
|
let secondIsOpen = (secondLoc.open == .open || secondLoc.open == .closingSoon)
|
|
if firstIsOpen != secondIsOpen {
|
|
return firstIsOpen && !secondIsOpen
|
|
}
|
|
}
|
|
return removeThe(firstLoc.name)
|
|
.localizedCaseInsensitiveCompare(removeThe(secondLoc.name)) == .orderedAscending
|
|
}
|
|
// Search/open only filtering step.
|
|
newLocations = newLocations.filter { location in
|
|
let searchedLocations = searchText.isEmpty || location.name.localizedCaseInsensitiveContains(searchText)
|
|
let openLocations = !openLocationsOnly || location.open == .open || location.open == .closingSoon
|
|
return searchedLocations && openLocations
|
|
}
|
|
return newLocations
|
|
}
|
|
|
|
var body: some View {
|
|
ForEach(filteredLocations, id: \.self) { location in
|
|
NavigationLink(value: location) {
|
|
VStack(alignment: .leading) {
|
|
HStack {
|
|
Text(location.name)
|
|
if model.favorites.contains(location) {
|
|
Image(systemName: "star.fill")
|
|
.foregroundStyle(.yellow)
|
|
}
|
|
}
|
|
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)
|
|
}
|
|
if let times = location.diningTimes, !times.isEmpty {
|
|
ForEach(times, id: \.self) { time in
|
|
Text("\(dateDisplay.string(from: time.openTime)) - \(dateDisplay.string(from: time.closeTime))")
|
|
.foregroundStyle(.secondary)
|
|
}
|
|
} else {
|
|
Text("Not Open Today")
|
|
.foregroundStyle(.secondary)
|
|
}
|
|
}
|
|
}
|
|
.swipeActions {
|
|
Button(action: {
|
|
withAnimation {
|
|
if model.favorites.contains(location) {
|
|
model.favorites.remove(location)
|
|
} else {
|
|
model.favorites.add(location)
|
|
}
|
|
}
|
|
|
|
}) {
|
|
if model.favorites.contains(location) {
|
|
Label("Unfavorite", systemImage: "star")
|
|
} else {
|
|
Label("Favorite", systemImage: "star")
|
|
}
|
|
}
|
|
.tint(model.favorites.contains(location) ? .yellow : nil)
|
|
}
|
|
}
|
|
}
|
|
}
|