Add lead workflows, PDF signing, AR projects and photo gallery integration

This commit is contained in:
Dennis Nemec
2026-11-08 17:49:39 +01:00
parent a343bde741
commit 8d18873412
82 changed files with 6401 additions and 34 deletions

View File

@ -60,8 +60,8 @@ struct GalleryView: View {
PhotoViewer(
photo: photo,
photos: project.photos.sorted { $0.creationDate > $1.creationDate }
) {
delete(photo)
) { selected in
delete(selected)
}
}
}
@ -158,9 +158,10 @@ private struct DrawingStroke {
var isEraser: Bool
}
private struct PhotoViewer: View {
struct PhotoViewer: View {
let photos: [ProjectPhoto]
let onDelete: () -> Void
let onDelete: (ProjectPhoto) throws -> Void
let usesNavigationStack: Bool
@Environment(\.dismiss) private var dismiss
@Environment(\.modelContext) private var modelContext
@ -172,19 +173,36 @@ private struct PhotoViewer: View {
@State private var drawingColor = Color.red
@State private var drawingWidth: Double = 0.012
@State private var imageRevision = 0
@State private var deletionError: String?
private var currentPhoto: ProjectPhoto {
photos[currentIndex]
}
init(photo: ProjectPhoto, photos: [ProjectPhoto], onDelete: @escaping () -> Void) {
init(photo: ProjectPhoto, photos: [ProjectPhoto], usesNavigationStack: Bool = true,
onDelete: @escaping (ProjectPhoto) throws -> Void) {
self.photos = photos
self.onDelete = onDelete
self.usesNavigationStack = usesNavigationStack
_currentIndex = State(initialValue: photos.firstIndex(of: photo) ?? 0)
}
var body: some View {
NavigationStack {
Group {
if usesNavigationStack {
NavigationStack { content }
} else {
content
}
}
.alert("Foto konnte nicht gelöscht werden", isPresented: Binding(
get: { deletionError != nil }, set: { if !$0 { deletionError = nil } }
)) {
Button("OK", role: .cancel) { deletionError = nil }
} message: { Text(deletionError ?? "") }
}
private var content: some View {
TabView(selection: $currentIndex) {
ForEach(photos.indices, id: \.self) { index in
photoLayout(for: photos[index])
@ -197,7 +215,7 @@ private struct PhotoViewer: View {
ToolbarItem(placement: .topBarLeading) {
if isDrawing {
EmptyView()
} else {
} else if usesNavigationStack {
Button("Fertig") { dismiss() }
}
}
@ -213,8 +231,10 @@ private struct PhotoViewer: View {
.accessibilityLabel("Zeichnung speichern")
} else {
Button("Löschen", systemImage: "trash", role: .destructive) {
onDelete()
dismiss()
do {
try onDelete(currentPhoto)
dismiss()
} catch { deletionError = error.localizedDescription }
}
}
}
@ -250,7 +270,6 @@ private struct PhotoViewer: View {
}
}
.navigationBarTitleDisplayMode(.inline)
}
}
private func photoLayout(for photo: ProjectPhoto) -> some View {
@ -619,6 +638,6 @@ private struct PhotoLocationCard: View {
#Preview("Foto-Detail") {
let photo = PreviewSupport.samplePhoto()
PhotoViewer(photo: photo, photos: [photo]) {}
PhotoViewer(photo: photo, photos: [photo]) { _ in }
}
#endif