| struct RatingsView: View {
@Binding var entries: [SpotEntry]
var onOpenInAppMap: ((String, UUID) -> Void)? = nil
// Group entries by star rating (5 down to 1), then unrated (0)
private var groups: [(rating: Int, entries: [SpotEntry])] {
let order = [5, 4, 3, 2, 1, 0]
return order.compactMap { rating in
let group = entries
.filter { $0.starRating == rating }
.sorted { $0.dateTime > $1.dateTime } // most recent first within group
return group.isEmpty ? nil : (rating: rating, entries: group)
}
}
var body: some View {
List {
if entries.isEmpty {
ContentUnavailableView(
"Nothing Here Yet",
systemImage: "fork.knife",
description: Text("Add your first restaurant to get started")
)
} else {
ForEach(groups, id: \.rating) { group in
Section(header: sectionHeader(for: group.rating)) {
ForEach(group.entries) { entry in
if let index = entries.firstIndex(where: { $0.id == entry.id }) {
NavigationLink(destination: EntryDetailView(entry: $entries[index], onOpenInAppMap: onOpenInAppMap)) {
EntryRowView(entry: entries[index], linksEnabled: false, showBell: false, showRatingStars: true)
}
.listRowInsets(EdgeInsets(top: 6, leading: 16, bottom: 6, trailing: 16))
.opacity(group.rating > 0 ? 1.0 : 0.4)
}
}
}
}
}
}
.listStyle(.plain)
.environment(\.defaultMinListRowHeight, 0)
.navigationTitle("Ratings")
.navigationBarTitleDisplayMode(.inline)
}
private func sectionHeader(for rating: Int) -> some View {
HStack(spacing: 3) {
if rating == 0 {
Text("Unrated")
.font(.system(size: 16, weight: .semibold))
.foregroundColor(.primary)
} else {
ForEach(1...5, id: \.self) { star in
Image(systemName: star <= rating ? "star.fill" : "star")
.font(.system(size: 12))
.foregroundColor(star <= rating ? .yellow : .gray.opacity(0.3))
}
}
Spacer()
Text("\(group(rating).count) \(group(rating).count == 1 ? "Spot" : "Spots")")
.font(.system(size: 14))
.foregroundColor(.secondary)
}
.listRowInsets(EdgeInsets(top: 0, leading: 16, bottom: 0, trailing: 16))
}
private func group(_ starRating: Int) -> [SpotEntry] {
groups.first(where: { $0.rating == starRating })?.entries ?? []
}
} | `RatingsView` struct | Defines the `RatingsView` struct. Conforms to View. |