Files
Calendarr/ios/Calendarr iOS/Views/Calendar/CalendarDrawer.swift
T
ScarriffleandClaude Opus 5 6e981e7aea chore(repo): iOS-App als ios/ ins Hauptrepo uebernehmen
Calendarr-IOS wird mit vollstaendiger Historie als Unterverzeichnis
ios/ eingebunden. Damit liegen Server, Web, Android und iOS in einem
gemeinsamen Repo.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-14 09:20:12 +02:00

126 lines
4.9 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
/// The left side drawer: calendar visibility + group/view switching, plus a
/// single entry into the full menu (Settings/Accounts/Profile/…/Sync/Logout).
struct CalendarDrawer: View {
let api: CalendarrAPI
let store: CalendarStore
let groups: [CalGroup]
let onSwitchGroup: (CalGroup?) -> Void
let onSelectView: (CalViewType) -> Void
let onOpenMenu: () -> Void
let onSync: () -> Void
let onClose: () -> Void
@Environment(AppState.self) private var appState
@AppStorage("appLanguage") private var appLang = "system"
var body: some View {
VStack(spacing: 0) {
header
Divider()
viewSwitcher
if !groups.isEmpty {
Divider()
groupSwitcher
}
Divider()
CalendarFilterContent(api: api, store: store)
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
.background(Color(.systemBackground))
}
// MARK: – Header
private var header: some View {
HStack(spacing: 14) {
Circle()
.fill(Color.accentColor)
.frame(width: 48, height: 48)
.overlay {
Text(appState.username.prefix(1).uppercased())
.font(.title3.bold()).foregroundStyle(.white)
}
VStack(alignment: .leading, spacing: 2) {
Text(appState.username).font(.title3.weight(.semibold)).lineLimit(1)
Text(appState.serverURL
.replacingOccurrences(of: "https://", with: "")
.replacingOccurrences(of: "http://", with: ""))
.font(.footnote).foregroundStyle(.secondary).lineLimit(1)
}
Spacer()
HStack(spacing: 20) {
Button { onSync() } label: {
Image(systemName: "arrow.triangle.2.circlepath").font(.system(size: 19, weight: .medium))
}
.buttonStyle(.plain).foregroundStyle(Color.accentColor)
.accessibilityLabel(L10n.t("menu.sync", appLang))
Button { onOpenMenu() } label: {
Image(systemName: "gearshape").font(.system(size: 19, weight: .medium))
}
.buttonStyle(.plain).foregroundStyle(Color.accentColor)
.accessibilityLabel(L10n.t("menu.section.settings", appLang))
Button { onClose() } label: {
Image(systemName: "xmark").font(.system(size: 17, weight: .semibold))
}
.buttonStyle(.plain).foregroundStyle(.secondary)
}
}
.padding(.horizontal, 18).padding(.top, 20).padding(.bottom, 16)
}
// MARK: – View switcher
private var viewSwitcher: some View {
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 8) {
ForEach(CalViewType.allCases, id: \.self) { vt in
let selected = store.viewType == vt
Button { onSelectView(vt) } label: {
Label(vt.label(appLang), systemImage: vt.systemImage)
.font(.caption.weight(.medium))
.padding(.horizontal, 12).padding(.vertical, 7)
.background(selected ? Color.accentColor : Color(.secondarySystemBackground))
.foregroundStyle(selected ? .white : .primary)
.clipShape(Capsule())
}
.buttonStyle(.plain)
}
}
.padding(.horizontal, 16).padding(.vertical, 13)
}
}
// MARK: – Group switcher
private var groupSwitcher: some View {
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 8) {
chip(label: L10n.t("groups.personal", appLang),
systemImage: "person",
selected: store.activeGroup == nil) { onSwitchGroup(nil) }
ForEach(groups) { g in
chip(label: g.name,
systemImage: GroupIcons.symbol(g.icon),
selected: store.activeGroup?.id == g.id) { onSwitchGroup(g) }
}
}
.padding(.horizontal, 16).padding(.vertical, 13)
}
}
private func chip(label: String, systemImage: String, selected: Bool, action: @escaping () -> Void) -> some View {
Button(action: action) {
Label(label, systemImage: systemImage)
.font(.caption.weight(.medium))
.padding(.horizontal, 12).padding(.vertical, 7)
.background(selected ? Color.accentColor : Color(.secondarySystemBackground))
.foregroundStyle(selected ? .white : .primary)
.clipShape(Capsule())
}
.buttonStyle(.plain)
}
}