Commander-Wünsche vom 02.09.2026 vor der Freigabe von 5.4.0 (die deshalb nie veröffentlicht wurde): Kern: kern/index.ts ist nur noch Bootstrap und Router; Dienste in kern/dienste/ (Einstellungen, Werkzeuge, Laufwerke, Erkennung, Vorgänge, Speicher, Benachrichtigung, Automatik), Kontext in kern/kontext.ts, Protokoll-Datei in gemeinsam/protokoll.ts, Platz-Rechnung in gemeinsam/platz.ts. Oberfläche: fenster/App.tsx ist nur noch der Rahmen; bausteine.tsx, dialoge/, uebersicht/ (LaufwerkKachel, KompressionsKarte, SpeicherKarte, VerlaufKarte), einstellungen/ (Karten je Funktion, SprachAuswahl), einrichtung/ (ErstEinrichtung, PosterHintergrund). Neu: Bibliothek weg, dafür Verlauf; Speicher-und-Bilanz-Karte (statfs); LED-Fußleiste; MakeMKV-Kopf in die Einstellungen; Sprach-Chips mit Dropdown statt Allgemeinem Preset; Karten Automatik/Benachrichtigung/Allgemein/Update; Durchsuchen bei Werkzeugen; Arbeitsordner lokal (Encode dort, dann in die Ablage); Platz-Prüfung vor dem Rip (Dialog und Kern); Automatik mit Countdown; Serien-Merker über Discs; Rettungs-Abbild mit Nullen nur nach gesehenen Lesefehlern (kern/rip/rettung.ts, Phase rettet, iso:-Quelle); Warteschlange pausieren; Discord/Telegram-Benachrichtigung; Protokoll-Datei je Tag; Fensterlage 80 % mittig, gemerkt; Erst-Einrichtung in acht Schritten vor dem Poster-Grid. Beweise: 413 Tests (neu: speicher, benachrichtigung, automatik, rettung, fensterlage, protokoll, kleinkram-550), drei Typprüfungen, Klick-Beweis mit 29 Schritten inklusive Erst-Einrichtung (zweiter Start mit RIPPY_START_BEREICH=einrichtung), Bilder beweise/klick/01…09. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
87 lines
3.9 KiB
TypeScript
87 lines
3.9 KiB
TypeScript
// Die Brücke (Preload) — läuft im Fenster-Prozess mit contextIsolation.
|
|
// Sie reicht GENAU DREI Dinge in die Seite, mehr nicht:
|
|
// 1. den MessagePort zum Kern (Muster aus der Electron-Doku
|
|
// »MessagePorts in Electron«: window.postMessage mit Transfer über die
|
|
// Kontextgrenze — contextBridge kann keine Ports übertragen)
|
|
// 2. den Haupt-Status (Kanal 'haupt-status')
|
|
// 3. rippy.melden(art) für kurze Rückmeldungen ans Haupt
|
|
// … plus die Windows-Dialoge und Shell-Wege, die nur das Haupt öffnen kann
|
|
// (Ordner/Datei wählen, Ordner im Explorer zeigen, Protokoll öffnen).
|
|
//
|
|
// Beides wird GEPUFFERT: Das Haupt schickt Port und Status direkt nach
|
|
// did-finish-load — ob die React-Seite ihre Horcher da schon registriert
|
|
// hat, ist Timing. Ein Port, der vor dem Horcher eintrifft, wäre sonst
|
|
// stumm verloren (R2: nichts verlieren, nur weil eine Nachricht früh kam).
|
|
import { contextBridge, ipcRenderer, type IpcRendererEvent } from 'electron'
|
|
|
|
let seiteBereit = false
|
|
const wartendePorts: IpcRendererEvent[] = []
|
|
|
|
ipcRenderer.on('kern-port', (ereignis) => {
|
|
if (seiteBereit) {
|
|
window.postMessage({ art: 'kern-port' }, '*', ereignis.ports)
|
|
} else {
|
|
wartendePorts.push(ereignis)
|
|
}
|
|
})
|
|
|
|
let letzterStatus: unknown = null
|
|
const statusHorcher = new Set<(status: unknown) => void>()
|
|
|
|
ipcRenderer.on('haupt-status', (_ereignis, status: unknown) => {
|
|
letzterStatus = status
|
|
for (const horcher of statusHorcher) horcher(status)
|
|
})
|
|
|
|
contextBridge.exposeInMainWorld('rippy', {
|
|
/** Die Seite meldet: Mein 'message'-Horcher steht — gepufferte Ports jetzt. */
|
|
bereit(): void {
|
|
seiteBereit = true
|
|
for (const ereignis of wartendePorts.splice(0)) {
|
|
window.postMessage({ art: 'kern-port' }, '*', ereignis.ports)
|
|
}
|
|
},
|
|
/** Haupt-Status abonnieren; der letzte bekannte Stand kommt sofort. */
|
|
aufStatus(horcher: (status: unknown) => void): void {
|
|
statusHorcher.add(horcher)
|
|
if (letzterStatus !== null) horcher(letzterStatus)
|
|
},
|
|
/** Kurze Rückmeldung ans Haupt (z. B. 'kern-pong' im Smoke-Beweis). */
|
|
melden(art: string): void {
|
|
ipcRenderer.send('fenster-meldung', String(art))
|
|
},
|
|
/** Echter Windows-Ordnerdialog (§ 7). null = abgebrochen. */
|
|
ordnerWaehlen(titel: string): Promise<string | null> {
|
|
return ipcRenderer.invoke('ordner-waehlen', String(titel)) as Promise<string | null>
|
|
},
|
|
/** Echter Windows-Dateidialog für Programme (5.5.0: Werkzeuge → Durchsuchen). */
|
|
dateiWaehlen(titel: string): Promise<string | null> {
|
|
return ipcRenderer.invoke('datei-waehlen', String(titel)) as Promise<string | null>
|
|
},
|
|
/** Einen Ordner im Explorer zeigen (5.5.0). Liefert '' oder den Fehler. */
|
|
ordnerOeffnen(pfad: string): Promise<string> {
|
|
return ipcRenderer.invoke('ordner-oeffnen', String(pfad)) as Promise<string>
|
|
},
|
|
/** Den Protokoll-Ordner im Explorer zeigen (5.5.0). */
|
|
protokollOeffnen(): Promise<string> {
|
|
return ipcRenderer.invoke('protokoll-oeffnen') as Promise<string>
|
|
},
|
|
/** Autostart an/aus (§ 8) — liefert den tatsächlichen Zustand zurück. */
|
|
autostartSetzen(an: boolean): Promise<boolean> {
|
|
return ipcRenderer.invoke('autostart-setzen', an === true) as Promise<boolean>
|
|
},
|
|
/** Eigene Titelleiste (§ 4.2): minimieren | maximieren | schliessen.
|
|
* „schliessen" versteckt nur — Rippy lebt im Tray weiter. */
|
|
fensterSteuern(was: 'minimieren' | 'maximieren' | 'schliessen'): Promise<boolean> {
|
|
return ipcRenderer.invoke('fenster-steuern', String(was)) as Promise<boolean>
|
|
},
|
|
/** „Jetzt prüfen" (§ 6.8) — das Ergebnis kommt über den Haupt-Status. */
|
|
updatePruefen(): Promise<unknown> {
|
|
return ipcRenderer.invoke('update-pruefen') as Promise<unknown>
|
|
},
|
|
/** „Jetzt neu starten und installieren" — antwortet mit Grund, wenn nicht. */
|
|
updateInstallieren(): Promise<{ ok: boolean; grund: string }> {
|
|
return ipcRenderer.invoke('update-installieren') as Promise<{ ok: boolean; grund: string }>
|
|
},
|
|
})
|