import Foundation import RunnerCore import SwiftTUI // MARK: - Configuration let resultsURL = "/Users/cediackermann/Projects/m323/Sources/MiniProject/data/results.txt" let startListURL = "/Users/cediackermann/Projects/m323/Sources/MiniProject/data/startList.txt" // MARK: - Entry Point let results = parseResults(readFile(resultsURL), separator: "\t") let starters = parseStarters(readFile(startListURL), separator: "\t") let finished = assembleRunners(starters: starters, results: results) let absent = nonParticipants(starters: starters, results: results) Application(rootView: RunnerBrowser(finished: finished, absent: absent)).start() // MARK: - TUI struct RunnerBrowser: View { let finished: [Runner] let absent: [Runner] @State private var query: String = "" @State private var sortKey: SortKey = .number @State private var includedGroups: Set = Set(AgeGroup.allCases) @State private var showAbsent: Bool = false private var source: [Runner] { showAbsent ? absent : finished } private var visible: [Runner] { visibleRunners(source, query: query, includedGroups: includedGroups, sortKey: sortKey) } var body: some View { VStack(alignment: .leading) { Text("Stadt-Rundlauf - \(visible.count)/\(source.count) runners") .bold() HStack { Text("Show:") Button(menuLabel("Finished", on: !showAbsent)) { showAbsent = false } Button(menuLabel("Did not start", on: showAbsent)) { showAbsent = true } } HStack { Text("Sort:") ForEach(SortKey.allCases, id: \.rawValue) { key in Button(menuLabel(key.rawValue, on: key == sortKey)) { sortKey = key } } } HStack { Text("Groups:") ForEach(AgeGroup.allCases, id: \.rawValue) { group in Button(menuLabel("\(group)", on: includedGroups.contains(group))) { includedGroups = toggling(includedGroups, group) } } } TextField(placeholder: "Search by name…") { value in query = value } Divider() Text(formatRow("Nr", "Name", "Group", "Time")).bold() ScrollView { ForEach(visible, id: \.number) { runner in Text(formatRow("#\(runner.number)", runner.name, "\(runner.ageGroup)", runner.time)) } } } .padding() } }