mirror of
https://github.com/pepaskopec-blip/Graduately.git
synced 2026-10-28 23:54:34 +00:00
154 lines
5.8 KiB
Swift
154 lines
5.8 KiB
Swift
import SwiftUI
|
||
|
||
@main
|
||
struct MaturitaApp: App {
|
||
@StateObject private var vm = AppModel()
|
||
|
||
var body: some Scene {
|
||
WindowGroup {
|
||
MaturitaRoot(vm: vm)
|
||
}
|
||
}
|
||
}
|
||
|
||
struct MaturitaRoot: View {
|
||
@ObservedObject var vm: AppModel
|
||
|
||
var body: some View {
|
||
let p = vm.palette
|
||
ZStack {
|
||
p.base.ignoresSafeArea()
|
||
VStack(spacing: 0) {
|
||
HStack {
|
||
Text("maturita.c")
|
||
.font(.system(size: 15, weight: .medium))
|
||
.foregroundStyle(p.text)
|
||
Spacer()
|
||
IconHit(action: { vm.searchOpen = true }) { SearchIcon(color: p.text) }
|
||
IconHit(action: { vm.go(.stats) }) { StatsIcon(color: p.text) }
|
||
IconHit(action: { vm.settingsOpen = true }) { SettingsIcon(color: p.text) }
|
||
}
|
||
.padding(.horizontal, 12)
|
||
.padding(.vertical, 6)
|
||
if vm.update.canInstall || vm.update.status == "downloading" || vm.update.status == "staged" {
|
||
HStack {
|
||
Text(bannerText)
|
||
.font(.system(size: 13))
|
||
.foregroundStyle(p.text)
|
||
Spacer()
|
||
if vm.update.canInstall {
|
||
PillButton(label: vm.tr("update_install"), palette: p) { vm.installUpdate() }
|
||
}
|
||
}
|
||
.padding(.horizontal, 12)
|
||
.padding(.vertical, 10)
|
||
.background(p.surface1, in: RoundedRectangle(cornerRadius: 14, style: .continuous))
|
||
.padding(.horizontal, 12)
|
||
}
|
||
routeView
|
||
.id(vm.tick)
|
||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||
}
|
||
if vm.searchOpen {
|
||
SearchOverlay(vm: vm).ignoresSafeArea(edges: .bottom)
|
||
}
|
||
if vm.settingsOpen {
|
||
SettingsSheet(vm: vm).ignoresSafeArea(edges: .bottom)
|
||
}
|
||
}
|
||
.preferredColorScheme(vm.mode == .dark ? .dark : .light)
|
||
.onAppear { vm.checkUpdate(false) }
|
||
}
|
||
|
||
private var bannerText: String {
|
||
if let arg = vm.update.messageArg {
|
||
return vm.fmt(vm.update.messageKey, arg)
|
||
}
|
||
return vm.tr(vm.update.messageKey)
|
||
}
|
||
|
||
@ViewBuilder
|
||
private var routeView: some View {
|
||
switch vm.route {
|
||
case .welcome: WelcomeScreen(vm: vm)
|
||
case .subjects: SubjectsScreen(vm: vm)
|
||
case .stats: StatsScreen(vm: vm)
|
||
case .roadmap: RoadmapScreen(vm: vm)
|
||
case .unitMap(let id): UnitMapScreen(vm: vm, unitId: id)
|
||
case .germanEx(let unit, let ex): GermanExercise(vm: vm, unitId: unit, ex: ex)
|
||
case .vocab(let id): VocabExercise(vm: vm, unitId: id)
|
||
case .netYears: NetYearsScreen(vm: vm)
|
||
case .netMap:
|
||
LessonMapScreen(
|
||
vm: vm,
|
||
title: vm.tr("net_year1"),
|
||
sub: vm.tr("net_sub"),
|
||
nodes: vm.content.netLessons.map { l in
|
||
let id = l.int("id")
|
||
return MapNode(
|
||
id: "n\(id)",
|
||
label: vm.tr(l.str("titleKey")),
|
||
locked: false,
|
||
done: vm.progress.netDone(id),
|
||
current: !vm.progress.netDone(id),
|
||
onClick: { vm.go(.netLesson(id)) }
|
||
)
|
||
}
|
||
)
|
||
case .netLesson(let id):
|
||
if let l = vm.content.netLesson(id) {
|
||
SlidesScreen(vm: vm, title: vm.tr(l.str("titleKey")), sub: vm.tr(l.str("subKey")), slides: l.arr("slides")) {
|
||
vm.go(.netEx(id))
|
||
}
|
||
}
|
||
case .netEx(let id): NetQuizScreen(vm: vm, id: id)
|
||
case .hwMap:
|
||
LessonMapScreen(
|
||
vm: vm,
|
||
title: vm.tr("Technické vybavení"),
|
||
sub: vm.tr("hw_sub"),
|
||
nodes: vm.content.hw.map { l in
|
||
let id = l.int("id")
|
||
return MapNode(
|
||
id: "h\(id)",
|
||
label: vm.tr(l.str("titleKey")),
|
||
locked: false,
|
||
done: vm.progress.hwDone(id),
|
||
current: !vm.progress.hwDone(id),
|
||
onClick: { vm.go(.hwLesson(id)) }
|
||
)
|
||
}
|
||
)
|
||
case .hwLesson(let id):
|
||
if let l = vm.content.hwLesson(id) {
|
||
SlidesScreen(vm: vm, title: vm.tr(l.str("titleKey")), sub: vm.tr(l.str("subKey")), slides: l.arr("slides")) {
|
||
vm.go(.hwEx(id))
|
||
}
|
||
}
|
||
case .hwEx(let id): HwQuizScreen(vm: vm, id: id)
|
||
case .czechMap: CzechMapScreen(vm: vm)
|
||
case .mluvnice:
|
||
LessonMapScreen(
|
||
vm: vm,
|
||
title: vm.tr("Mluvnice"),
|
||
sub: "Cvičení z mluvnice – styl maturita / přijímačky z ČJL",
|
||
nodes: vm.content.mluvnice.map { m in
|
||
let n = m.int("id")
|
||
return MapNode(
|
||
id: "m\(n)",
|
||
label: m.str("name"),
|
||
locked: false,
|
||
done: vm.progress.mluvDone(n),
|
||
current: !vm.progress.mluvDone(n),
|
||
onClick: { vm.go(.mluvEx(n)) }
|
||
)
|
||
}
|
||
)
|
||
case .mluvEx(let n): MluvExercise(vm: vm, n: n)
|
||
case .readingList: BookListScreen(vm: vm)
|
||
case .book(let id): BookScreen(vm: vm, id: id)
|
||
case .bookQuiz(let id): LitQuizScreen(vm: vm, id: id)
|
||
case .bookPlot(let id): PlotScreen(vm: vm, id: id)
|
||
}
|
||
}
|
||
}
|