Herunterladen steht jetzt im Kontextmenü
Bisher führte der Weg über die Detailseite — zwei Schritte für etwas, das man beim Vorbeiscrollen entscheidet. Langes Drücken auf eine Kachel bietet es jetzt direkt an, samt derselben Qualitätsauswahl. Die Kachel kennt nur eine Zusammenfassung ohne Dateiangaben; geholt wird deshalb erst beim Tippen. Eine Reihe aus zwanzig Kacheln wären sonst zwanzig Anfragen für ein Menü, das selten aufgeht. **Nur bei Filmen und Folgen.** Bei einer Serie oder Staffel lädt man nicht *den* Titel, sondern seine Folgen — dafür gibt es auf der Seite „Alle Folgen laden". Und nicht bei dem, was schon in der Warteschlange steht. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
6b6bc6ad02
commit
25e6ada0ce
@@ -1,5 +1,6 @@
|
||||
import SwiftUI
|
||||
import FlixyDesign
|
||||
import FlixyDownloads
|
||||
import MediaKit
|
||||
|
||||
/// Eine Kachel, die zur Detailseite führt — mit einem Knopf, der sofort
|
||||
@@ -29,10 +30,19 @@ struct QuickPlayTile<Card: View>: View {
|
||||
@Environment(FlixySession.self) private var session
|
||||
@Environment(PlaybackCoordinator.self) private var playback
|
||||
@Environment(QuickPlay.self) private var quickPlay
|
||||
@Environment(DownloadCoordinator.self) private var downloads
|
||||
@Environment(LanguagePreferences.self) private var languages
|
||||
@Environment(\.flixyAccent) private var accent
|
||||
|
||||
@State private var isPointerInside = false
|
||||
@State private var errorMessage: String?
|
||||
/// Der nachgeladene Titel, sobald die Qualitätsauswahl offen sein soll.
|
||||
///
|
||||
/// **Zwei Dinge in einem Zustand**, und das mit Absicht: die Kachel kennt
|
||||
/// nur eine Zusammenfassung ohne Dateiangaben, also muss vor der Frage
|
||||
/// nachgeladen werden. Ein eigenes `Bool` daneben wäre ein zweiter
|
||||
/// Zustand, der mit diesem gleichziehen müsste.
|
||||
@State private var downloadChoice: MediaItem?
|
||||
|
||||
/// Was die umgebende Seite tun soll, wenn sich am Server etwas geändert
|
||||
/// hat. Siehe `ItemActionEntries`.
|
||||
@@ -93,6 +103,15 @@ struct QuickPlayTile<Card: View>: View {
|
||||
Divider()
|
||||
}
|
||||
Button("tile.play", systemImage: "play.fill") { trigger() }
|
||||
|
||||
// **Herunterladen gehört hierher.** Bisher führte der Weg
|
||||
// über die Detailseite — zwei Schritte für etwas, das man
|
||||
// beim Vorbeiscrollen entscheidet.
|
||||
if isDownloadable {
|
||||
Button("downloads.download", systemImage: "arrow.down.circle") {
|
||||
Task { await prepareDownload() }
|
||||
}
|
||||
}
|
||||
Divider()
|
||||
}
|
||||
ItemActionEntries(
|
||||
@@ -117,6 +136,24 @@ struct QuickPlayTile<Card: View>: View {
|
||||
// Aktion, die Millisekunden dauert, zu spät und ginge zu früh. Geht
|
||||
// sie dagegen schief, muss man es erfahren — sonst bliebe der Haken
|
||||
// einfach aus, und das sieht aus wie ein Fehler der App.
|
||||
.confirmationDialog(
|
||||
Text("downloads.quality.title"),
|
||||
isPresented: Binding(
|
||||
get: { downloadChoice != nil },
|
||||
set: { if !$0 { downloadChoice = nil } }
|
||||
),
|
||||
titleVisibility: .visible
|
||||
) {
|
||||
if let ziel = downloadChoice {
|
||||
let wahl = DownloadQualityChoice(item: ziel, backend: session.backend)
|
||||
ForEach(wahl.available) { quality in
|
||||
Button(wahl.label(for: quality)) { enqueue(ziel, quality: quality) }
|
||||
}
|
||||
}
|
||||
Button("action.cancel", role: .cancel) {}
|
||||
} message: {
|
||||
Text("downloads.quality.hint")
|
||||
}
|
||||
.alert(
|
||||
Text("error.title"),
|
||||
isPresented: Binding(get: { errorMessage != nil }, set: { if !$0 { errorMessage = nil } })
|
||||
@@ -177,6 +214,35 @@ struct QuickPlayTile<Card: View>: View {
|
||||
.accessibilityHidden(true)
|
||||
}
|
||||
|
||||
/// Ob es etwas herunterzuladen gibt — und ob es nicht schon da ist.
|
||||
///
|
||||
/// Sammlungen, Serien und Staffeln fallen heraus: dort lädt man nicht
|
||||
/// *den* Titel, sondern seine Folgen, und dafür gibt es auf der Seite
|
||||
/// „Alle Folgen laden".
|
||||
private var isDownloadable: Bool {
|
||||
guard item.kind == .movie || item.kind == .episode else { return false }
|
||||
return !downloads.items.contains { $0.ratingKey == item.id }
|
||||
}
|
||||
|
||||
/// Holt die Dateiangaben nach und öffnet dann die Auswahl.
|
||||
///
|
||||
/// Erst beim Tippen, nicht beim Zeichnen: eine Reihe aus zwanzig Kacheln
|
||||
/// wären sonst zwanzig Anfragen für ein Menü, das selten aufgeht.
|
||||
private func prepareDownload() async {
|
||||
downloadChoice = (try? await session.backend?.item(id: item.id)) ?? item
|
||||
}
|
||||
|
||||
private func enqueue(_ ziel: MediaItem, quality: DownloadQuality) {
|
||||
let service = DownloadService(
|
||||
backend: session.backend, coordinator: downloads, languages: languages
|
||||
)
|
||||
do {
|
||||
_ = try service.download(ziel, quality: quality)
|
||||
} catch {
|
||||
errorMessage = error.explanation
|
||||
}
|
||||
}
|
||||
|
||||
private func trigger() {
|
||||
quickPlay.start(item, backend: session.backend, coordinator: playback)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user