Files
firka/firka/ios/FirkaWatch Watch App/Views/GradeSubjectView.swift
Horváth Gergely 35e1e2c6ab Add Apple Watch app and watch sync support
Add a new Firka Watch app target with UI components, views and services: DataStore, BackgroundRefreshManager, WatchConnectivity/WatchSession integration, localization (WatchL10n), entitlements and assets. Move widget/shared models into ios/Shared and update Xcode project/schemes; add native Kreta API client and TokenManager for watch use. Implement watch-side caching, proactive token refresh, background scheduling, and pairing/pairing UI. Update Flutter side (watch_sync_helper, main, API/token helper changes) and tweak iOS .gitignore and project metadata to enable the watch integration and data sync between phone and watch.
2026-02-27 23:23:56 +01:00

99 lines
3.1 KiB
Swift

import SwiftUI
struct GradeSubjectView: View {
let subjectName: String
let grades: [WidgetGrade]
let average: Double
var body: some View {
ScrollView {
VStack(alignment: .leading, spacing: 12) {
FirkaCard {
HStack {
Text("average".localized)
.font(.caption)
.foregroundColor(.secondary)
Text(String(format: "%.2f", average))
.font(.headline)
.fontWeight(.bold)
.foregroundColor(averageColor(average))
}
}
ForEach(groupedGrades, id: \.date) { group in
VStack(alignment: .leading, spacing: 6) {
Text(formatDate(group.date))
.font(.caption)
.foregroundColor(.secondary)
ForEach(group.grades) { grade in
gradeRow(grade)
}
}
}
}
.padding()
}
.navigationTitle(subjectName)
}
private var groupedGrades: [(date: Date, grades: [WidgetGrade])] {
let calendar = Calendar.current
let grouped = Dictionary(grouping: grades) { grade in
calendar.startOfDay(for: grade.recordDate)
}
return grouped
.map { (date: $0.key, grades: $0.value) }
.sorted { $0.date > $1.date }
}
@ViewBuilder
private func gradeRow(_ grade: WidgetGrade) -> some View {
FirkaCard {
HStack(alignment: .top, spacing: 10) {
if let numeric = grade.numericValue {
GradeBadge(grade: numeric)
} else {
Text(grade.displayValue)
.font(.caption)
.fontWeight(.bold)
.padding(6)
.background(Color.gray)
.cornerRadius(12)
}
VStack(alignment: .leading, spacing: 2) {
Text(grade.displayType)
.font(.subheadline)
.fontWeight(.medium)
if let topic = grade.topic, !topic.isEmpty {
Text(topic)
.font(.caption)
.foregroundColor(.secondary)
.lineLimit(2)
}
}
Spacer()
}
}
}
private func formatDate(_ date: Date) -> String {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy. MM. dd."
return formatter.string(from: date)
}
private func averageColor(_ avg: Double) -> Color {
switch avg {
case 4.5...: return .green
case 3.5..<4.5: return .blue
case 2.5..<3.5: return .yellow
case 1.5..<2.5: return .orange
default: return .red
}
}
}