Inhalt
Aktueller Ordner:
duesseldorfer-schuelerinventar-swift-client/Duesk/ViewsMainView.swift
import SwiftUI
struct MainView: View {
@StateObject private var viewModel = ProfileListViewModel()
@State private var showingNewProfile = false
@State private var showingGroupManager = false
@State private var showingTimeSeries = false
@State private var selectedProfile: Profile?
@State private var selectedGroupForTimeSeries: String?
@State private var showGroupedView = false
@State private var editingProfile: Profile?
var body: some View {
NavigationSplitView {
// Sidebar mit Gruppen
List(selection: $selectedGroupForTimeSeries) {
Section("Alle Profile") {
Label("Alle Profile", systemImage: "person.3.fill")
.tag(nil as String?)
}
Section("Gruppen") {
ForEach(viewModel.groupNames, id: \.self) { groupName in
HStack {
Label(groupName, systemImage: "folder")
Spacer()
Text("\(viewModel.getProfilesForGroup(groupName).count)")
.font(.caption)
.foregroundColor(.secondary)
}
.tag(groupName as String?)
}
}
}
.listStyle(SidebarListStyle())
.frame(minWidth: 200)
.toolbar {
ToolbarItem(placement: .primaryAction) {
Menu {
Button("Neues Profil", action: { showingNewProfile = true })
Button("Gruppen verwalten", action: { showingGroupManager = true })
Button("Zeitreihe", action: { showingTimeSeries = true })
Divider()
Button("Abmelden", role: .destructive, action: logout)
} label: {
Label("Menü", systemImage: "ellipsis.circle")
}
}
}
} detail: {
// Detailansicht mit Profilliste
VStack(spacing: 0) {
// Search Bar
HStack {
Image(systemName: "magnifyingglass")
.foregroundColor(.gray)
TextField("Suchen...", text: $viewModel.searchText)
.textFieldStyle(PlainTextFieldStyle())
if !viewModel.searchText.isEmpty {
Button(action: { viewModel.searchText = "" }) {
Image(systemName: "xmark.circle.fill")
.foregroundColor(.gray)
}
.buttonStyle(PlainButtonStyle())
}
}
.padding(8)
.background(Color(.textBackgroundColor))
.cornerRadius(8)
.padding(.horizontal)
.padding(.top, 8)
// Profile List
if viewModel.isLoading {
Spacer()
ProgressView()
Spacer()
} else {
let profilesToShow = selectedGroupForTimeSeries == nil
? viewModel.filteredProfiles
: viewModel.getProfilesForGroup(selectedGroupForTimeSeries ?? "")
List {
ForEach(profilesToShow) { profile in
ProfileRow(profile: profile)
.onTapGesture {
selectedProfile = profile
}
.contextMenu {
Button("Anzeigen") { selectedProfile = profile }
Button("Bearbeiten") { editingProfile = profile }
Button("Löschen", role: .destructive) {
Task {
if let index = viewModel.filteredProfiles.firstIndex(where: { $0.id == profile.id }) {
await viewModel.deleteProfile(at: IndexSet(integer: index))
}
}
}
}
}
.onDelete { indexSet in
Task {
await viewModel.deleteProfile(at: indexSet)
}
}
}
.listStyle(InsetListStyle())
}
}
.navigationTitle(selectedGroupForTimeSeries ?? "DÜSK")
.refreshable {
await viewModel.loadProfiles()
}
.sheet(item: $selectedProfile) { profile in
ProfileDetailView(profile: profile)
}
.sheet(item: $editingProfile) { profile in
ProfileEditView(profile: profile, onSaved: {
Task { await viewModel.loadProfiles() }
})
}
.sheet(isPresented: $showingNewProfile) {
ProfileEditView(onSaved: {
Task { await viewModel.loadProfiles() }
})
}
.sheet(isPresented: $showingGroupManager) {
GroupManagerView(onChanged: {
Task { await viewModel.loadProfiles() }
})
}
.sheet(item: $selectedGroupForTimeSeries) { groupName in
TimeSeriesView(groupId: nil, groupName: groupName)
}
.task {
await viewModel.loadProfiles()
}
}
}
private func logout() {
SessionManager.shared.clear()
if let windowScene = NSApplication.shared.windows.first?.contentViewController?.view.window {
// macOS handling
}
}
}
struct ProfileRow: View {
let profile: Profile
var body: some View {
HStack {
VStack(alignment: .leading, spacing: 4) {
Text(profile.name)
.font(.headline)
Text(profile.gruppename ?? "Keine Gruppe")
.font(.caption)
.foregroundColor(.secondary)
}
Spacer()
Text(profile.profilID)
.font(.caption)
.foregroundColor(.secondary)
}
.padding(.vertical, 4)
}
}
// Für Sheets mit String
extension String: Identifiable {
public var id: String { self }
}