You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
70 lines
2.5 KiB
70 lines
2.5 KiB
import DropTwoCore
|
|
import Foundation
|
|
|
|
/// Ein Element in der Dateiliste der Oberfläche, mit seinem aktuellen
|
|
/// Verarbeitungsstatus. Rein UI-seitig — die eigentliche Logik steckt in
|
|
/// `ConversionPipeline`/`JobQueue` in DropTwoCore.
|
|
struct DropItem: Identifiable {
|
|
let id: UUID
|
|
let sourceURL: URL
|
|
var status: Status
|
|
/// Ausschnitt für diese Datei, in der Review-Ansicht eingestellt.
|
|
var cropPlan = CropPlan()
|
|
/// Nutzer hat bei fehlendem Format im Namen "4x5 anhängen" gewählt.
|
|
var appendFormatWhenMissing = false
|
|
|
|
enum Status {
|
|
case waiting
|
|
case running(progress: Double)
|
|
case skipped(SkipReason)
|
|
case rejected(RejectionReason)
|
|
case succeeded(croppedDestination: URL)
|
|
case failed(message: String)
|
|
/// Nutzer hat sich bei einer Overwrite-Rückfrage bewusst fürs
|
|
/// Überspringen entschieden — kein Fehler, aber sichtbar im Verlauf.
|
|
case skippedByUser(reason: String)
|
|
|
|
/// Fehlerliste statt stiller Abbrüche: alles außer "läuft"/"fertig"/
|
|
/// "bewusst vom Nutzer übersprungen" braucht sichtbare Aufmerksamkeit.
|
|
var needsAttention: Bool {
|
|
switch self {
|
|
case .skipped, .rejected, .failed:
|
|
return true
|
|
case .waiting, .running, .succeeded, .skippedByUser:
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
|
|
init(sourceURL: URL) {
|
|
self.id = UUID()
|
|
self.sourceURL = sourceURL
|
|
self.status = .waiting
|
|
}
|
|
|
|
var fileName: String { sourceURL.lastPathComponent }
|
|
|
|
/// Was der Dateiname vor dem Lauf schon verrät — so sieht man Probleme
|
|
/// beim Reinziehen, nicht erst nach dem Start.
|
|
var nameOutcome: FileNameParseResult.Outcome {
|
|
FileNameParser.parse(fileName).outcome
|
|
}
|
|
|
|
/// true = im Namen steht kein Format, und der Nutzer hat noch nicht
|
|
/// entschieden, "4x5" anzuhängen.
|
|
var isMissingFormat: Bool {
|
|
guard !appendFormatWhenMissing, case .rejected(.formatSegmentMissing) = nameOutcome else { return false }
|
|
return true
|
|
}
|
|
|
|
/// Name der 4:5-Fassung, wie er entstehen wird. nil = wird so nicht verarbeitet.
|
|
var plannedTargetName: String? {
|
|
let root = URL(fileURLWithPath: "/", isDirectory: true)
|
|
return ConversionPipeline.previewDestination(
|
|
sourceURL: sourceURL,
|
|
outputRootDirectory: root,
|
|
appendFormatWhenMissing: appendFormatWhenMissing
|
|
)?.lastPathComponent
|
|
}
|
|
}
|