Hi all, I am a complete newbie here. Probably an easy fix but I cannot get this to work:
I am trying to sort an array of Time objects so that in the UI the subject that happens first appears first. Here is the code:
import SwiftUI
import SwiftData
@available(iOS 18.0, *)
struct SubjectView: View {
@Environment(\.modelContext) private var context
@Query private var subjects: [Subject]
@State private var showSheet = false
private var daysOfWeek = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
@State private var selectedDay: String = ""
@AppStorage("showPreviousEvents") var showPreviousSubjects: Bool = true
@State private var skillsPresented = false
@State private var selectedTest: Test?
var body: some View {
ScrollViewReader { pos in
NavigationStack {
VStack(spacing: 0) {
ScrollView(.horizontal, showsIndicators: false) {
HStack {
ForEach(daysOfWeek, id: \.self) { day in
Button {
selectedDay = day
withAnimation {
pos.scrollTo(day, anchor: .center)
}
} label: {
Text(day)
.font(.largeTitle)
.fontWeight(.semibold)
.foregroundColor(selectedDay == day ? .black : .gray)
.padding(.horizontal, 3)
.id(day)
}
}
}
.padding()
}
Divider()
List(subjects) { subject in
ForEach(
subject.day
.filter { $0.dayName == selectedDay }
.filter { showPreviousSubjects ? combineDateAndTime(date: Date(), time: $0.endTime) > Date() : true }
) { time in
ZStack {
NavigationLink(destination: {
UpdatedEditView(subject: subject)
}, label: {
EmptyView()
})
ZStack {
RoundedRectangle(cornerRadius: 10)
.foregroundColor(Color(hex: subject.colour))
.frame(height: 80)
HStack {
VStack(alignment: .leading, spacing: 3) {
Text(subject.title)
.bold().font(.title)
HStack {
Image(systemName: "clock")
Text("\(shortTime(time.startTime)) - \(shortTime(time.endTime))")
}
Spacer()
}
Spacer()
VStack {
HStack (spacing: 3){
Image(systemName: "mappin.and.ellipse")
Text(subject.classroom)
}.padding(.trailing).padding(.top, 8)
Spacer()
}
}.foregroundColor(.white)
.padding(.top)
.padding(.leading, 10.0)
}
.swipeActions {
Button(role: .destructive) {
for time in subject.day {
EventHelper().deleteEvent(time.identifier ?? "")
}
context.delete(subject)
} label: {
Image(systemName: "trash")
}
}
}
}
.listRowSeparator(.hidden).listRowBackground(Color.clear)
}
.listStyle(.plain)
.sheet(isPresented: $showSheet) {
AddSubjectView()
}
.background { Color(.systemGray6) }
}.toolbar {
ToolbarItem(placement: .topBarTrailing) {
Button("Add Subject", systemImage: "plus") {
showSheet.toggle()
}
}
ToolbarItem(placement: .topBarLeading) {
NavigationLink {
List(subjects) { subject in
ForEach(subject.tests.sorted { $0.date > $1.date }) { test in
Button {
selectedTest = test
} label: {
ZStack {
RoundedRectangle(cornerRadius: 10).frame(height: 80).foregroundColor(Color(hex: subject.colour))
HStack {
VStack (alignment: .leading, spacing: 0){
Text(test.name).font(.title2).bold().padding([.leading, .top]).padding(.bottom, 10)
HStack (spacing: 3){
Image(systemName: "calendar.circle")
Text(formattedDate(test.date))
}.padding(.leading)
Spacer()
}
Spacer()
}
}.foregroundColor(.white)
}.padding(.horizontal, 5).listRowSeparator(.hidden).listRowBackground(Color.clear).swipeActions {
Button(role: .destructive) {
subject.tests.removeAll { $0 == test}
try? context.save()
} label: {
Image(systemName: "trash")
}
}
}
}
} label: {
Image(systemName: "graduationcap")
}
}
}
}
.onAppear {
let currentDayName = DateFormatter()
currentDayName.dateFormat = "EEEE"
selectedDay = currentDayName.string(from: Date())
withAnimation {
pos.scrollTo(selectedDay, anchor: .center)
}
}.ignoresSafeArea().sheet(item: $selectedTest) { test in
TestEditView(selectedTest: test)
}
}
}
}
Definitions of Time and Subject:
import Foundation
import SwiftData
import SwiftUI
import UIKit
@available(iOS 17, *)
@available(iOS 17, *)
@Model
class Item: Identifiable {
var name: String = ""
init(name: String) {
self.name = name
}
}
@available(iOS 17, *)
@Model
class Subject: Identifiable {
var id = UUID()
var title: String
var classroom: String
var teacherName: String
var items: [Item]?
var day: [Time]
var colour: String
var eOrS: Int = 1
var tests: [Test] = []
init(subjectName: String, classroom: String, teacherName: String, items: [Item]?, day: [Time], colour: String, eOrS: Int, tests: [Test]) {
self.title = subjectName
self.classroom = classroom
self.teacherName = teacherName
self.items = items
self.day = day
self.colour = colour
self.eOrS = eOrS
self.tests = tests
}
}
@available(iOS 17, *)
@Model
class Time: Identifiable {
var dayName: String
var startTime: Date
var endTime: Date
var identifier: String?
init(dayName: String, startTime: Date, endTime: Date) {
self.dayName = dayName
self.startTime = startTime
self.endTime = endTime
}
}
@available(iOS 17, *)
@Model
class Term: Identifiable {
var id = UUID()
var name: String
var startDate: Date
var endDate: Date
init(name: String, startDate: Date, endDate: Date) {
self.name = name
self.startDate = startDate
self.endDate = endDate
}
}
@available(iOS 17, *)
@Model
class Test: Identifiable {
var name: String
var date: Date
var skills: [String]
init(name: String, date: Date, skills: [String]) {
self.name = name
self.date = date
self.skills = skills
}
}
You will see a list with an embedded foreach loop, I need to sort that foreach loop by time.startTime. I cannot figure it out. Help is very much appreciated.
Thank you.