Files
psu-schedule/ios/PSUSchedule/Views/SettingsView.swift
Zakhar Timoshenko 170a44c377 Add date and time handling, models, schedule management, storage, and widget support
- Introduced `Dates.swift` for handling date and time in the university's timezone.
- Created `Models.swift` to define data structures for timetable, lessons, and directory search results.
- Implemented `Schedule.swift` for managing lesson slots and timetable functionalities.
- Developed `Storage.swift` for user settings and data persistence.
- Added `Widgets.swift` to create widgets displaying lessons and upcoming classes.
2026-10-18 20:26:12 +03:00

88 lines
5.4 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import SwiftUI
struct SettingsView: View {
@Environment(AppModel.self) private var model
@Environment(\.dismiss) private var dismiss
var body: some View {
let s = model.settings
let d = s.display
NavigationStack {
Form {
Section("Тема") {
Picker("Тема", selection: Binding(get: { s.theme }, set: { model.setTheme($0) })) {
Text("Авто").tag(ThemeMode.system)
Text("Светлая").tag(ThemeMode.light)
Text("Тёмная").tag(ThemeMode.dark)
}
.pickerStyle(.segmented)
}
Section {
toggle("Цвета предметов", "Каждый предмет своим цветом в карточках, сетке и обзоре", d.colors) { var x = d; x.colors = $0; model.setDisplay(x) }
toggle("Преподаватели", "Фамилии в карточках занятий", d.teachers) { var x = d; x.teachers = $0; model.setDisplay(x) }
toggle("Аудитории", "Номера аудиторий в карточках и в сетке", d.rooms) { var x = d; x.rooms = $0; model.setDisplay(x) }
toggle("Номера пар", "«2 пара» рядом со временем", d.pairs) { var x = d; x.pairs = $0; model.setDisplay(x) }
toggle("Метки занятий", "Лекция или практика, белые и зелёные недели, общее занятие", d.tags) { var x = d; x.tags = $0; model.setDisplay(x) }
toggle("Пометки из Word", "Например, «3-13н.» — даты по ним уже рассчитаны", d.notes) { var x = d; x.notes = $0; model.setDisplay(x) }
} header: {
Text("Расписание")
} footer: {
Text("Полные сведения о занятии всегда открываются по нажатию на карточку.")
}
if !s.hidden.isEmpty {
Section("Скрытые занятия") {
ForEach(s.hidden.sorted(), id: \.self) { key in
let parts = key.split(separator: "|", maxSplits: 1).map(String.init)
HStack {
Text((parts.first ?? key).prefix(1).uppercased() + (parts.first ?? key).dropFirst() + (parts.count > 1 && !parts[1].isEmpty ? " · " + parts[1] : ""))
Spacer()
Button("Показать") { model.setHidden(key, false) }
}
}
}
}
Section {
Toggle(isOn: Binding(get: { s.reminders }, set: { on in
if on { Task { model.setReminders(await Reminders.authorize()) } } else { model.setReminders(false) }
})) {
VStack(alignment: .leading, spacing: 2) {
Text("Перед парой")
Text("Уведомление с предметом и аудиторией. Работает без интернета, по сохранённому расписанию.")
.font(.footnote).foregroundStyle(.secondary)
}
}
if s.reminders {
Picker("За сколько минут", selection: Binding(get: { s.reminderMinutes }, set: { model.setReminderMinutes($0) })) {
ForEach([5, 10, 15, 30], id: \.self) { Text("\($0)").tag($0) }
}
.pickerStyle(.segmented)
}
} header: {
Text("Напоминания")
}
Section {
LabeledContent("Документ", value: model.timetable?.document.name ?? "Группа не выбрана")
if let sem = model.timetable?.semester { LabeledContent("Семестр", value: sem.label) }
LabeledContent("Сервер", value: model.api.base.absoluteString)
} header: {
Text("О расписании")
} footer: {
Text("Расписание берётся из публичного каталога ПГУ и пересчитывается по таблице белых и зелёных недель. Приложение неофициальное: при сомнениях сверяйтесь с документом Word.")
}
}
.navigationTitle("Настройки")
.navigationBarTitleDisplayMode(.inline)
.toolbar { ToolbarItem(placement: .confirmationAction) { Button("Готово", systemImage: "checkmark") { dismiss() } } }
}
}
private func toggle(_ title: String, _ text: String, _ on: Bool, _ set: @escaping (Bool) -> Void) -> some View {
Toggle(isOn: Binding(get: { on }, set: set)) {
VStack(alignment: .leading, spacing: 2) {
Text(title)
Text(text).font(.footnote).foregroundStyle(.secondary)
}
}
}
}