import SwiftUI import Combine // MARK: - Models struct LessonBlock: Codable, Identifiable { var id: String { "\(day)-\(period)" } let day: String let period: String let timeStart: String let timeEnd: String let room: String let subject: String let group: String let teacher: String let color: String // "pink", "yellow", "green" enum CodingKeys: String, CodingKey { case day, period case timeStart = "time_start" case timeEnd = "time_end" case room, subject, group, teacher, color } } struct TimetableResponse: Codable { let day: String let lessons: [LessonBlock] } // MARK: - ViewModel class TimetableViewModel: ObservableObject { @Published var dayName: String = "" @Published var lessons: [LessonBlock] = [] @Published var isLoading = true @Published var errorMessage: String? func fetchTimetable() { isLoading = true guard let url = Bundle.main.url(forResource: "mock", withExtension: "json"), let data = try? Data(contentsOf: url) else { errorMessage = "mock.json nicht gefunden" isLoading = false return } do { let decoded = try JSONDecoder().decode(TimetableResponse.self, from: data) self.dayName = decoded.day self.lessons = decoded.lessons } catch { errorMessage = "JSON Fehler: \(error.localizedDescription)" } isLoading = false } func loadMockData() { dayName = "Montag" lessons = [ LessonBlock(day: "Montag", period: "1.", timeStart: "08:00", timeEnd: "08:55", room: "255", subject: "D", group: "G2", teacher: "VanC", color: "pink"), LessonBlock(day: "Montag", period: "2. & 3.", timeStart: "08:55", timeEnd: "10:25", room: "255", subject: "M", group: "G2", teacher: "ScLa", color: "yellow"), LessonBlock(day: "Montag", period: "4.", timeStart: "10:55", timeEnd: "11:40", room: "254", subject: "E", group: "G4", teacher: "RadF", color: "green"), LessonBlock(day: "Montag", period: "5.", timeStart: "11:40", timeEnd: "12:25", room: "255", subject: "D", group: "G2", teacher: "VanC", color: "pink"), ] isLoading = false } } // MARK: - Lesson Block View struct LessonBlockView: View { let lesson: LessonBlock var blockColor: Color { switch lesson.color { case "pink": return Color(red: 1.0, green: 0.85, blue: 0.88) case "yellow": return Color(red: 1.0, green: 1.0, blue: 0.82) case "green": return Color(red: 0.78, green: 0.95, blue: 0.84) default: return Color.gray.opacity(0.3) } } var body: some View { VStack(spacing: 0) { // Top row: Room | Subject Group | Teacher HStack { Text(lesson.room) .font(.system(size: 14, weight: .bold, design: .monospaced)) Spacer() Text("\(lesson.subject) \(lesson.group)") .font(.system(size: 14, weight: .bold, design: .monospaced)) Spacer() Text(lesson.teacher) .font(.system(size: 14, weight: .bold, design: .monospaced)) } .padding(.horizontal, 8) .padding(.top, 6) // Bottom row: Period | Time HStack { Text(lesson.period) .font(.system(size: 13, weight: .semibold, design: .monospaced)) Spacer() Text("\(lesson.timeStart)-\(lesson.timeEnd)") .font(.system(size: 13, weight: .semibold, design: .monospaced)) } .padding(.horizontal, 8) .padding(.bottom, 6) } .background(blockColor) .cornerRadius(4) .overlay( RoundedRectangle(cornerRadius: 4) .stroke(Color.black.opacity(0.3), lineWidth: 1) ) } } // MARK: - Main Content View struct ContentView: View { @StateObject private var viewModel = TimetableViewModel() var body: some View { Group { if viewModel.isLoading { ProgressView("Laden...") } else if let error = viewModel.errorMessage { VStack { Text(error) .font(.caption) .foregroundColor(.red) Button("Erneut versuchen") { viewModel.fetchTimetable() } .font(.caption2) } } else { ScrollView { VStack(spacing: 4) { Text(viewModel.dayName) .font(.system(size: 16, weight: .bold)) .foregroundColor(.white) .padding(.bottom, 4) ForEach(viewModel.lessons) { lesson in LessonBlockView(lesson: lesson) } } .padding(.horizontal, 2) } } } .onAppear { viewModel.fetchTimetable() } } } // MARK: - App Entry Point @main struct StundenplanApp: App { var body: some Scene { WindowGroup { ContentView() } } } /* Expected JSON format from your backend: { "day": "Montag", "lessons": [ { "period": "1.", "time_start": "08:00", "time_end": "08:55", "room": "255", "subject": "D", "group": "G2", "teacher": "VanC", "color": "pink", "day": "Montag" } ] } */