iOS-App angefangen; Import-Modi; MHD-Formatierung; Gebinde in Ablauf-Ansichten
iOS (neu, ios/):
- SwiftUI-App: Login (Server + Keychain-Token), Kamera-Scanner (EAN/UPC/Code128),
Einlagern mit mehreren Chargen und eigenem MHD, Auslagern mit Chargenauswahl
oder FEFO, Artikelsuche, Anlegen mit Open-Food-Facts-Vorbefuellung.
- Home-Screen-Shortcuts: Schnellaktionen (langer Druck) und URL-Schema
projectgood://checkin | ://checkout fuer eigene Symbole via Kurzbefehle.
- project.yml (XcodeGen) + README mit Build-Anleitung. NICHT kompiliert - auf
diesem Rechner ist kein Xcode vorhanden.
Import-Modi (wie besprochen sinnvoll):
- add (Standard, nichts loeschen), replace_listed (Bestaende der in der Datei
genannten Produkte ersetzen - fuer Inventur), replace_all (alles ersetzen).
Geleerte Bestaende werden als Korrektur-Bewegung protokolliert; die Oberflaeche
fragt bei den zerstoerenden Modi nach.
Anzeige:
- "Bald ablaufend"/"Abgelaufen" zeigen jetzt das Gebinde ("1 Glas") mit der
Basiseinheit klein darunter (ExpiringItem liefert die Einheiten mit).
- MHD als Zeitspanne mit korrektem Numerus: "in 3 Tagen", "in 1 Woche",
"vor 2 Wochen", dazu heute/morgen/gestern.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
93
ios/Sources/RootView.swift
Normal file
93
ios/Sources/RootView.swift
Normal file
@@ -0,0 +1,93 @@
|
||||
import SwiftUI
|
||||
|
||||
struct RootView: View {
|
||||
@EnvironmentObject private var session: Session
|
||||
@EnvironmentObject private var router: Router
|
||||
|
||||
var body: some View {
|
||||
Group {
|
||||
if session.isLoggedIn {
|
||||
HomeView()
|
||||
} else {
|
||||
LoginView()
|
||||
}
|
||||
}
|
||||
// Shortcut/URL öffnet den passenden Scan-Bildschirm direkt.
|
||||
.fullScreenCover(item: $router.route) { route in
|
||||
NavigationStack {
|
||||
switch route {
|
||||
case .checkin: CheckInView()
|
||||
case .checkout: CheckOutView()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension Route: Identifiable {
|
||||
var id: String { rawValue }
|
||||
}
|
||||
|
||||
struct HomeView: View {
|
||||
@EnvironmentObject private var session: Session
|
||||
@EnvironmentObject private var router: Router
|
||||
|
||||
var body: some View {
|
||||
NavigationStack {
|
||||
VStack(spacing: 16) {
|
||||
Button {
|
||||
router.route = .checkin
|
||||
} label: {
|
||||
ActionTile(title: "Einlagern", subtitle: "Barcode scannen und Bestand erfassen",
|
||||
systemImage: "arrow.down.to.line")
|
||||
}
|
||||
Button {
|
||||
router.route = .checkout
|
||||
} label: {
|
||||
ActionTile(title: "Auslagern", subtitle: "Barcode scannen und Menge entnehmen",
|
||||
systemImage: "arrow.up.from.line")
|
||||
}
|
||||
Spacer()
|
||||
}
|
||||
.padding()
|
||||
.navigationTitle("Project-Good")
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .topBarTrailing) {
|
||||
Menu {
|
||||
Text("Angemeldet als \(session.username)")
|
||||
Button("Abmelden", role: .destructive) { session.logout() }
|
||||
} label: {
|
||||
Image(systemName: "person.circle")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ActionTile: View {
|
||||
let title: String
|
||||
let subtitle: String
|
||||
let systemImage: String
|
||||
|
||||
var body: some View {
|
||||
HStack(spacing: 14) {
|
||||
Image(systemName: systemImage)
|
||||
.font(.title2)
|
||||
.frame(width: 44, height: 44)
|
||||
.background(Color.accentColor.opacity(0.15))
|
||||
.clipShape(RoundedRectangle(cornerRadius: 10))
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
Text(title).font(.headline)
|
||||
Text(subtitle).font(.caption).foregroundStyle(.secondary)
|
||||
.multilineTextAlignment(.leading)
|
||||
}
|
||||
Spacer()
|
||||
Image(systemName: "chevron.right").foregroundStyle(.tertiary)
|
||||
}
|
||||
.padding()
|
||||
.background(Color(.secondarySystemBackground))
|
||||
.clipShape(RoundedRectangle(cornerRadius: 12))
|
||||
.foregroundStyle(.primary)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user