feat: add iOS support and harden receipt scanning

This commit is contained in:
Timo
2026-08-20 23:48:26 +02:00
parent f5e06c32b0
commit cf1b799e1b
107 changed files with 11755 additions and 122 deletions

View File

@@ -0,0 +1,49 @@
import Foundation
import UIKit
/// Drives the "Beleg scannen" flow: takes a captured/picked `UIImage`,
/// uploads it to `POST /api/scan` for AI extraction, and hands the resulting
/// `Receipt` back to the view. Does NOT persist anything itself saving
/// happens later in `ReceiptReviewView` via `ReceiptsAPI.sync(...)`.
@MainActor
final class ScanViewModel: ObservableObject {
@Published var isUploading = false
@Published var errorMessage: String?
/// Converts the image to JPEG and uploads it for extraction.
/// Returns the extracted `Receipt` on success, or `nil` on failure
/// (in which case `errorMessage` is set to German user-facing text).
func uploadAndExtract(image: UIImage) async -> Receipt? {
guard let data = image.jpegData(compressionQuality: 0.85) else {
errorMessage = "Bild konnte nicht verarbeitet werden."
return nil
}
return await uploadAndExtract(imageData: data)
}
/// Same as above, but takes already-encoded JPEG data directly.
func uploadAndExtract(imageData: Data) async -> Receipt? {
isUploading = true
errorMessage = nil
defer { isUploading = false }
do {
let response = try await ReceiptsAPI.scan(
fileData: imageData,
fileName: "receipt.jpg",
mimeType: "image/jpeg"
)
guard let receipt = response.receipt else {
errorMessage = "Es konnten keine Belegdaten erkannt werden."
return nil
}
return receipt
} catch let error as APIError {
errorMessage = error.localizedDescription
return nil
} catch {
errorMessage = error.localizedDescription
return nil
}
}
}