fix(v5): Kleinkram der Durchsicht — Rückfragen vor Beenden und Löschen, Enter speichert, Escape schließt, ein Toast je Disc, NFO mit Kennung, „(2)" statt Kennungsstumpf, Werkzeug-Suche gemerkt, CD-Lesen ohne Blockade
WAS (je Fund der Durchsicht vom 12.09.2026): - F15 Tray „Beenden" fragt nach, wenn ein Rip oder eine Kompression läuft (app.quit reißt makemkvcon/HandBrake über die Leine mit). - F17 „Roh-Dateien löschen" und „Ordner löschen" fragen im Fenster nach (Größe und Pfad stehen dabei) — ein Klick war vorher 30 GB. - F18 Eingabefelder speichern auch bei Enter und beim Verschwinden des Feldes (Bereichswechsel) — Tipparbeit ging vorher verloren. - F19 Dialoge: Escape schließt, role=dialog/aria-modal, Fokus im Dialog. - F20 Toast „Disc erkannt" einmal je Disc und Titel, nicht dreimal. - F21 Was mit dem Poster passiert, steht in den Hinweisen (R4). - F22 Werkzeug-Funde gelten 60 s; ein neuer Pfad und „werkzeuge-laden" suchen frisch — vorher bei fehlendem MakeMKV je Aufruf dreimal reg query /s (bis 45 s, synchron). - F23 movie.nfo/tvshow.nfo tragen <uniqueid type=tmdb|imdb>. - F24 Doppelter Zielordner heißt „Akira (1988) (2)" statt „[bluray-2]". - F25 Umlaute in drei Knopftexten. - F26 Phase „rettet" zählt im Haupt als laufender Vorgang (Update-Sperre, Taskleiste). - F27 „Neu komprimieren" nicht mehr für verschobene, unkomprimierte Vorgänge. - F28 Die Automatik sagt bei Audio-CD und unbekannter Disc, warum sie nichts tut. - F30 Audio-CD-Spuren werden asynchron gelesen (alle acht Blöcke Luft), „Abbrechen" wirkt mitten in der Spur. - A5 Der tote Schlüssel transcodePreset ist aus presetFuer raus. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
783b8e4897
commit
c1ee339446
@@ -375,6 +375,23 @@ export function Feld({
|
||||
}) {
|
||||
const [entwurf, setEntwurf] = useState(wert)
|
||||
useEffect(() => setEntwurf(wert), [wert])
|
||||
// 5.7.0 (Durchsicht F18): Gespeichert wird beim Verlassen, bei Enter UND
|
||||
// wenn das Feld verschwindet (Bereichswechsel, Dialog zu) — vorher ging
|
||||
// Tipparbeit verloren, wenn man statt zu klicken Enter drückte oder in
|
||||
// einen anderen Bereich wechselte. Die Refs tragen den jüngsten Stand in
|
||||
// die Aufräum-Funktion des Effekts.
|
||||
const juengster = useRef({ entwurf, wert, aufAendern })
|
||||
juengster.current = { entwurf, wert, aufAendern }
|
||||
useEffect(
|
||||
() => () => {
|
||||
const j = juengster.current
|
||||
if (j.entwurf !== j.wert) j.aufAendern(j.entwurf)
|
||||
},
|
||||
[],
|
||||
)
|
||||
const speichern = (): void => {
|
||||
if (entwurf !== wert) aufAendern(entwurf)
|
||||
}
|
||||
return (
|
||||
<label className="block">
|
||||
<span className="text-xs font-semibold text-dunst">{name}</span>
|
||||
@@ -384,8 +401,9 @@ export function Feld({
|
||||
value={entwurf}
|
||||
placeholder={platzhalter}
|
||||
onChange={(e) => setEntwurf(e.target.value)}
|
||||
onBlur={() => {
|
||||
if (entwurf !== wert) aufAendern(entwurf)
|
||||
onBlur={speichern}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') speichern()
|
||||
}}
|
||||
className={FELD_KLASSE}
|
||||
/>
|
||||
@@ -465,10 +483,28 @@ export function DialogRahmen({
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
const hintergrund = useHintergrundKlick(schliessen)
|
||||
// 5.7.0 (Durchsicht F19): Escape schließt, der Dialog ist als solcher
|
||||
// ausgezeichnet (role/aria-modal) und bekommt den Fokus — ohne das blieb
|
||||
// die Tastatur auf der Seite dahinter, und Escape tat nichts.
|
||||
const karte = useRef<HTMLDivElement>(null)
|
||||
useEffect(() => {
|
||||
const taste = (e: KeyboardEvent): void => {
|
||||
if (e.key === 'Escape') schliessen()
|
||||
}
|
||||
window.addEventListener('keydown', taste)
|
||||
// Fokus in den Dialog — aber nicht aus einem Eingabefeld heraus, das
|
||||
// ein Kind schon per autoFocus genommen hat.
|
||||
if (document.activeElement === null || document.activeElement === document.body) karte.current?.focus()
|
||||
return () => window.removeEventListener('keydown', taste)
|
||||
}, [schliessen])
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/70 p-6 backdrop-blur-sm" {...hintergrund}>
|
||||
<div
|
||||
className={`max-h-[85vh] w-full ${breite} overflow-y-auto rounded-2xl border border-tinte/12 bg-buehne p-5 shadow-2xl shadow-black/60`}
|
||||
ref={karte}
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
tabIndex={-1}
|
||||
className={`max-h-[85vh] w-full ${breite} overflow-y-auto rounded-2xl border border-tinte/12 bg-buehne p-5 shadow-2xl shadow-black/60 focus:outline-none`}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
{children}
|
||||
|
||||
@@ -198,6 +198,9 @@ export function RohDateienKarte({ verbindung, aktivFuer }: { verbindung: Verbind
|
||||
const v = verbindung.vorgaenge
|
||||
const [presetWahl, setPresetWahl] = useState<Record<string, string>>({})
|
||||
const [alleZeigen, setAlleZeigen] = useState(aktivFuer === true)
|
||||
// 5.7.0 (Durchsicht F17): Löschen fragt nach — ein Klick war vorher 30 GB.
|
||||
// Der erste Klick macht aus dem Knopf die Rückfrage, der zweite löscht.
|
||||
const [loeschfrage, setLoeschfrage] = useState<string | null>(null)
|
||||
const presets = verbindung.werkzeuge?.presets ?? []
|
||||
const regelWert = werte['rohAufbewahrung'] ?? '7'
|
||||
const phasenText: Record<VorgangEintrag['phase'], string> = {
|
||||
@@ -312,11 +315,28 @@ export function RohDateienKarte({ verbindung, aktivFuer }: { verbindung: Verbind
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
{!e.rohGeloescht && ruhig && (
|
||||
<button onClick={() => vorgangRohLoeschen(e.id)} className="rounded-lg border border-rot/40 bg-rot/10 px-3 py-1 text-[11px] text-rot hover:bg-rot/20" title="Den Roh-Ordner dieses Vorgangs jetzt löschen">
|
||||
Roh-Dateien löschen
|
||||
{!e.rohGeloescht && ruhig && loeschfrage !== e.id && (
|
||||
<button onClick={() => setLoeschfrage(e.id)} className="rounded-lg border border-rot/40 bg-rot/10 px-3 py-1 text-[11px] text-rot hover:bg-rot/20" title="Den Roh-Ordner dieses Vorgangs löschen — fragt erst nach">
|
||||
Roh-Dateien löschen …
|
||||
</button>
|
||||
)}
|
||||
{!e.rohGeloescht && ruhig && loeschfrage === e.id && (
|
||||
<span className="inline-flex flex-wrap items-center gap-2 rounded-lg border border-rot/50 bg-rot/10 px-2 py-1 text-[11px] text-rot">
|
||||
{gb(e.rohBytes)} unter {e.rohOrdner} unwiderruflich löschen?
|
||||
<button
|
||||
onClick={() => {
|
||||
setLoeschfrage(null)
|
||||
vorgangRohLoeschen(e.id)
|
||||
}}
|
||||
className="rounded-md bg-rot px-2 py-0.5 font-semibold text-buehne hover:brightness-110"
|
||||
>
|
||||
Ja, löschen
|
||||
</button>
|
||||
<button onClick={() => setLoeschfrage(null)} className="rounded-md border border-tinte/20 px-2 py-0.5 text-dunst hover:text-schnee">
|
||||
Nein
|
||||
</button>
|
||||
</span>
|
||||
)}
|
||||
{e.phase === 'fertig' && e.zielOrdner.length > 0 && (
|
||||
<button onClick={() => void window.rippy.ordnerOeffnen(e.zielOrdner)} className="rounded-lg border border-tinte/15 px-3 py-1 text-[11px] text-dunst hover:text-schnee">
|
||||
Ordner öffnen
|
||||
@@ -348,9 +368,27 @@ export function RohDateienKarte({ verbindung, aktivFuer }: { verbindung: Verbind
|
||||
<span className="min-w-0 break-all font-mono text-[11px] text-dunst">
|
||||
{f.ordner} · {gb(f.bytes)}
|
||||
</span>
|
||||
<button onClick={() => fremdenOrdnerLoeschen(f.ordner)} className="flex-none rounded-lg border border-rot/40 bg-rot/10 px-2.5 py-0.5 text-[10.5px] text-rot hover:bg-rot/20">
|
||||
Löschen
|
||||
</button>
|
||||
{loeschfrage !== f.ordner ? (
|
||||
<button onClick={() => setLoeschfrage(f.ordner)} className="flex-none rounded-lg border border-rot/40 bg-rot/10 px-2.5 py-0.5 text-[10.5px] text-rot hover:bg-rot/20">
|
||||
Löschen …
|
||||
</button>
|
||||
) : (
|
||||
<span className="flex flex-none items-center gap-1.5 text-[10.5px] text-rot">
|
||||
wirklich?
|
||||
<button
|
||||
onClick={() => {
|
||||
setLoeschfrage(null)
|
||||
fremdenOrdnerLoeschen(f.ordner)
|
||||
}}
|
||||
className="rounded-md bg-rot px-2 py-0.5 font-semibold text-buehne hover:brightness-110"
|
||||
>
|
||||
Ja
|
||||
</button>
|
||||
<button onClick={() => setLoeschfrage(null)} className="rounded-md border border-tinte/20 px-2 py-0.5 text-dunst hover:text-schnee">
|
||||
Nein
|
||||
</button>
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -159,7 +159,7 @@ export function LaufwerkKachel({
|
||||
onClick={aufRippen}
|
||||
disabled={!discDa}
|
||||
className="inline-flex items-center gap-2 rounded-xl bg-gradient-to-b from-gold-hell to-gold-tief px-5 py-1.5 text-xs font-bold text-buehne shadow-[inset_0_1px_0_oklch(1_0_0/0.4),0_8px_24px_oklch(0.75_0.13_60/0.3)] hover:from-gold-hell hover:to-gold disabled:cursor-not-allowed disabled:opacity-35 disabled:shadow-none"
|
||||
title="Titel der Disc lesen und auswaehlen — danach verlustfrei rippen"
|
||||
title="Titel der Disc lesen und auswählen — danach verlustfrei rippen"
|
||||
>
|
||||
<IconPlay />
|
||||
Rippen
|
||||
@@ -411,9 +411,9 @@ export function LaufwerkKachel({
|
||||
<button
|
||||
onClick={() => ripUeberspringen(geraet.id)}
|
||||
className="rounded-lg border border-warn/50 bg-warn/15 px-3 py-1 text-[11px] font-semibold text-warn hover:bg-warn/25"
|
||||
title="Diesen Titel aufgeben und mit dem naechsten weitermachen"
|
||||
title="Diesen Titel aufgeben und mit dem nächsten weitermachen"
|
||||
>
|
||||
Titel ueberspringen
|
||||
Titel überspringen
|
||||
</button>
|
||||
<span className="font-mono text-[10.5px] text-nebel">oder weiter versuchen — abbrechen geht oben.</span>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user