Verleih-Abschnitt im Einzelstueck: an wen, seit wann, bis wann, dazu Herausgeben bzw. Zuruecknehmen und der Verleih-Verlauf. Pflicht ist nur der Name; Grund und Rueckgabedatum sind abschaltbar, weil "kurz mal mitgenommen" nicht an einem Datum scheitern soll. Der Abschnitt sitzt bewusst oben in ItemEditView, und zwar nicht nur der Wichtigkeit wegen: QR ueber Nachschlagen, eingenaehtes NFC-Tag und ein angetipptes Tag (vorrania://i/<UID>) landen alle in genau dieser Ansicht. Damit ist "scannen und verleihen" ueberall moeglich, ohne einen eigenen Weg dafuer zu bauen. In der Einzelstueck-Liste steht der Verleih unter dem Stueck - ueberfaellig in Rot - und das Filter-Menue kann auf Verliehen, Ueberfaellig oder Im Haus eingrenzen. Wo etwas ist, war bisher immer der Lagerort; ist es verliehen, ist der Entleiher die Antwort, und der Lagerort steht daneben. days_overdue rechnet der Server (GET /loans, ItemOut.loan), damit App und Web nicht getrennt rechnen und nicht auseinanderlaufen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
140 lines
7.5 KiB
Markdown
140 lines
7.5 KiB
Markdown
# Vorrania – iOS-App
|
||
|
||
Native SwiftUI-App für Lebensmittel **und** Gegenstände. Sie spricht dieselbe
|
||
REST-API wie die Web-Oberfläche.
|
||
|
||
> **Stand:** Voll nutzbar. Login; Scannen von Barcode, MHD/Datum (per
|
||
> Texterkennung, auch nur Tag+Monat ohne Jahr), Lagerort-QR und Name/Marke;
|
||
> Ein-/Auslagern mit mehreren Chargen bzw. Menge je Lagerort; Einzelstücke mit
|
||
> UID/QR, Kaufdatum, Garantie und Beleg – auch **verleihen** und
|
||
> zurücknehmen; Verbrauchsgegenstände als Charge;
|
||
> Artikel anlegen (Open Food/Products Facts oder manuell, mit Foto); getrennte
|
||
> Listen für Lebensmittel/Gegenstände/Einzelstücke, Kategoriefilter, Sortierung;
|
||
> Einkaufsliste, Ablaufliste, Mindestbestände; Verlauf mit Sprung zum Produkt;
|
||
> lokale Dashboards und Push-Benachrichtigungen bei ablaufenden Produkten.
|
||
|
||
## Projekt in Xcode öffnen
|
||
|
||
### Variante A – mit XcodeGen (empfohlen)
|
||
```bash
|
||
brew install xcodegen
|
||
cd ios
|
||
xcodegen generate
|
||
open Vorrania.xcodeproj
|
||
```
|
||
`project.yml` beschreibt das Projekt vollständig (Bundle-ID, Info.plist,
|
||
Shortcuts, URL-Schema).
|
||
|
||
### Variante B – ohne XcodeGen
|
||
1. Xcode → *File ▸ New ▸ Project…* → **App**, Interface **SwiftUI**, Sprache **Swift**
|
||
2. Produktname `Vorrania`, Bundle-ID z. B. `com.scarriffle.vorrania`
|
||
3. Die von Xcode erzeugte `ContentView.swift` und `…App.swift` löschen
|
||
4. Den Ordner `Sources/` per Drag & Drop ins Projekt ziehen („Copy items if needed")
|
||
5. In den Target-Einstellungen die mitgelieferte `Sources/Info.plist` als Info.plist setzen
|
||
(*Build Settings ▸ Info.plist File*) und *Generate Info.plist File* auf **No** stellen
|
||
|
||
## Auf dem iPhone installieren
|
||
1. iPhone per Kabel verbinden, in Xcode als Ziel auswählen
|
||
2. *Signing & Capabilities* → dein Apple-Developer-Team wählen
|
||
3. ▶︎ Run. Beim ersten Start auf dem iPhone unter
|
||
*Einstellungen ▸ Allgemein ▸ VPN & Geräteverwaltung* dem Entwickler vertrauen
|
||
|
||
## Erste Schritte in der App
|
||
Beim Start nach der Server-Adresse fragen lassen, z. B. `http://192.168.1.50:8080`
|
||
(dieselbe Adresse wie im Browser), dann mit deinem Benutzer anmelden. Adresse und
|
||
Token bleiben gespeichert – das Token liegt im Keychain.
|
||
|
||
Hat der Server einen Anmeldedienst eingerichtet (Single Sign-on, siehe
|
||
[../README.md](../README.md#single-sign-on-optional)), erscheint darunter ein
|
||
Knopf „Mit … anmelden". Die Anmeldung läuft dann im System-Browser (AppAuth mit
|
||
PKCE, kein eingebettetes WebView); der Anmeldezustand samt Refresh-Token liegt
|
||
je Serverprofil getrennt im Keychain, und die App erneuert ein abgelaufenes
|
||
Token still im Hintergrund.
|
||
|
||
## Home-Screen-Shortcuts
|
||
Es gibt zwei Wege direkt in den Scan-Bildschirm:
|
||
|
||
**Schnellaktionen** – langer Druck auf das App-Symbol zeigt „Einlagern" und
|
||
„Auslagern" (funktioniert ohne weitere Einrichtung).
|
||
|
||
**Eigene Symbole auf dem Home-Bildschirm** – über die Apple-App *Kurzbefehle*:
|
||
1. Kurzbefehle ▸ **+** ▸ Aktion *URL öffnen*
|
||
2. URL `vorrania://checkin` (bzw. `vorrania://checkout`) eintragen
|
||
3. Kurzbefehl benennen, dann ▸ *Zum Home-Bildschirm hinzufügen*
|
||
|
||
Beide Wege öffnen die App **direkt in der Kamera**.
|
||
|
||
## Einzelstücke verleihen
|
||
|
||
In der Ansicht eines Einzelstücks steht **Verleih** ganz oben: verliehen an wen,
|
||
seit wann, bis wann – und der Knopf zum Herausgeben bzw. Zurücknehmen. Pflicht
|
||
ist nur der Name; Grund und Rückgabedatum sind optional, denn „kurz mal
|
||
mitgenommen" soll nicht an einem Datum scheitern.
|
||
|
||
Dass der Knopf genau dort sitzt, macht **scannen und verleihen** möglich, ohne
|
||
einen eigenen Weg dafür zu bauen: Alle Scan-Wege der App enden in dieser
|
||
Ansicht – der QR über *Nachschlagen*, ein eingenähtes NFC-Tag über *NFC-Tag
|
||
lesen* und ein angetipptes Tag über `vorrania://i/<UID>`.
|
||
|
||
Der Lagerort bleibt beim Verleihen stehen – dorthin gehört das Stück zurück. Als
|
||
verliehen zählt es aber nicht mehr zum Bestand, es ist ja nicht im Haus. In der
|
||
Einzelstück-Liste steht der Verleih unter dem Stück (überfällig in Rot) und lässt
|
||
sich über das Filter-Menü auf *Verliehen*, *Überfällig* oder *Im Haus* eingrenzen.
|
||
|
||
## NFC-Tags für Kleidung
|
||
Ein aufgeklebtes QR-Etikett übersteht keine Wäsche. Für Kleidungsstücke gibt es
|
||
deshalb eingenähte NFC-Tags: Einzelstück öffnen ▸ **NFC-Tag beschreiben** ▸ Tag
|
||
an die Oberseite des iPhones halten. Auf das Tag kommt derselbe Link, der auch im
|
||
QR steckt (`vorrania://i/<UID>`).
|
||
|
||
Gelesen wird es unter **Nachschlagen** oder **Ort zuordnen** über
|
||
*NFC-Tag lesen*. Das Antippen bei gesperrtem Handy startet die App bewusst
|
||
nicht: iOS macht das nur über Universal Links auf einer festen Domain, und die
|
||
gibt es bei einem selbst gehosteten Dienst nicht.
|
||
|
||
> Zum Bauen muss für die App-ID im Apple-Developer-Portal die Capability
|
||
> *Near Field Communication Tag Reading* aktiv sein, sonst schlägt das Signieren
|
||
> fehl. NFC gibt es nur auf dem iPhone – auf dem iPad sind die Knöpfe ausgeblendet.
|
||
|
||
## Aufbau der Quellen
|
||
| Datei | Inhalt |
|
||
|---|---|
|
||
| `VorraniaApp.swift` | App-Einstieg, Schnellaktionen, URL-Schema |
|
||
| `Session.swift` | Server-Adresse (UserDefaults) und Token (Keychain) |
|
||
| `APIClient.swift` | REST-Aufrufe gegen `/api/...` |
|
||
| `Models.swift` | Codable-Typen passend zu `backend/app/schemas.py` |
|
||
| `ScannerView.swift` | Kamera + Barcode-Erkennung (EAN-8/13, UPC-E, Code128, QR) |
|
||
| `RootView.swift` | Startbildschirm und Routing |
|
||
| `LoginView.swift` | Server + Anmeldung |
|
||
| `CheckInView.swift` / `CheckInFormView.swift` | Scan → Charge (MHD), Menge je Lagerort oder Einzelstück |
|
||
| `CheckOutView.swift` | Scan → Menge, Chargenauswahl oder FEFO |
|
||
| `ProductViews.swift` | Artikelsuche und Anlegen (mit OFF-Vorbefüllung, Foto, Text-Scan) |
|
||
| `ProductDetailView.swift` | Produkt bearbeiten, Verwaltungsart ändern, Chargen korrigieren |
|
||
| `ObjectStockView.swift` | Gegenstände: Menge je Lagerort (hinzufügen/umlagern/entfernen) |
|
||
| `ItemViews.swift` / `ItemListView.swift` | Einzelstücke anlegen, bearbeiten und auflisten |
|
||
| `AssignScanView.swift` | Einzelstück (Scan, NFC oder Liste) einem Lagerort-QR zuordnen |
|
||
| `NFCTag.swift` / `NFCViews.swift` | NFC-Tags lesen und beschreiben, Einzelstück-Code zerlegen |
|
||
| `ListViews.swift` | Produktlisten, Einkaufsliste, „bald ablaufend", Mindestbestände |
|
||
| `DashboardView.swift` / `DashboardCards.swift` / `ChartCards.swift` | Übersicht mit Karten und Diagrammen |
|
||
| `NotificationScheduler.swift` / `NotificationSettings*.swift` | Push-Benachrichtigungen bei Ablauf |
|
||
| `DateScanView.swift` / `BestBeforeText.swift` | MHD/Text per Texterkennung ablesen |
|
||
| `DisplaySettings.swift` | Datumsformat und Einheiten-Beschriftungen vom Server |
|
||
| `CategoryPicker.swift` | Kategorie-Auswahl und Gruppe anlegen |
|
||
|
||
## Gruppe und Kategorie – zwei verschiedene Dinge
|
||
**Gruppe** dient der *Bestandsrechnung*: Mehl von Rewe, Aldi und Migros zählen
|
||
zusammen, wichtig ist „ich habe 5 kg Mehl“. Eine Gruppe hat deshalb einen
|
||
gemeinsamen Mindestbestand mit Einheit und EAN-Codes. Ordnest du einen Artikel
|
||
einer Gruppe zu, erscheint sein EAN-Code automatisch dort; wechselt er die
|
||
Gruppe, wandert der Code mit.
|
||
|
||
**Kategorie** dient *allein dem Überblick* („Süßwaren“, „Molkereiprodukte“) und
|
||
ist verschachtelbar wie ein Lagerort (Süßwaren → Schokolade). Sie hat keinen
|
||
Bestand, keinen Mindestbestand und keine EAN-Codes. Filterst du auf eine
|
||
Oberkategorie, erscheinen die Artikel ihrer Unterkategorien mit. Beim Anlegen
|
||
schlägt der Server eine Kategorie aus der Open-Food-Facts-Einordnung vor.
|
||
|
||
## Weiteres
|
||
Push-Benachrichtigungen bei Ablauf und Lagerort je Charge beim Einlagern sind
|
||
umgesetzt. Weitere Ideen stehen in [../docs/ROADMAP.md](../docs/ROADMAP.md).
|