Das Kreuz faerbt sich beim Darueberfahren rot -- aber nur, solange der Upload laeuft. Dasselbe Zeichen tut zwei Dinge: eine Meldung wegraeumen ist folgenlos, einen laufenden Vorgang fallen zu lassen nicht. Unter dem Balken steht jetzt "4.2 MB / 18.0 MB · 1.8 MB/s · 8 s left". Die Zahlen kamen schon immer vom XMLHttpRequest, sie wurden nur weggeworfen. Neu gerechnet wird nur das Tempo -- der Browser meldet Bytes, nicht deren Ableitung. Zwei Daempfungen, aus zwei Gruenden: * Das Tempo aus einem einzelnen Abstand springt zwischen dem Doppelten und der Haelfte. Gleitender Mittelwert (0,7/0,3) ueber Messpunkte von mindestens 0,2 s. * Die Anzeige wird hoechstens alle 150 ms nachgezogen. Der Browser meldet im 50-ms-Takt; bei drei Dateien waeren das sechzig Neuaufbauten der Liste je Sekunde fuer eine Zahl, die niemand so schnell liest. Jeder Teil erscheint erst, wenn er stimmt: Groesse sofort, Tempo nach dem zweiten Messpunkt, Restzeit erst mit beidem. Eine Schaetzung aus dem Nichts waere schlimmer als keine -- man richtet sich danach. formatDuration in src/format.ts, 5 Tests (37 gesamt). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
46 lines
1.8 KiB
TypeScript
46 lines
1.8 KiB
TypeScript
/**
|
||
* Zahlen, wie ein Mensch sie liest.
|
||
*
|
||
* Stand bis hierher in `pages/FileBrowser.tsx` – und **fünf** Module holten
|
||
* sie von dort: Papierkorb, Etiketten, „Geteilt mit mir", Fassungen,
|
||
* Eigenschaften. Eine Seite als Fundort für eine Rechenfunktion heißt, dass
|
||
* jedes dieser Module am Dateibrowser hängt, samt allem, was der mitbringt.
|
||
* Zum Umbenennen einer Zahl musste man eine Seite anfassen.
|
||
*/
|
||
|
||
/**
|
||
* Byte-Zahl in Kilo, Mega, Giga.
|
||
*
|
||
* Tausend-vierundzwanzig, nicht tausend: Das ist die Einheit, in der
|
||
* Dateisysteme und Betriebssysteme rechnen – eine Datei, die dort „1,4 MB"
|
||
* heißt, soll hier nicht 1,5 heißen.
|
||
*/
|
||
export function formatBytes(n: number): string {
|
||
if (n < 1024) return `${n} B`
|
||
if (n < 1024 ** 2) return `${(n / 1024).toFixed(1)} KB`
|
||
if (n < 1024 ** 3) return `${(n / 1024 ** 2).toFixed(1)} MB`
|
||
return `${(n / 1024 ** 3).toFixed(1)} GB`
|
||
}
|
||
|
||
/**
|
||
* Eine Dauer, wie man sie beim Warten liest.
|
||
*
|
||
* Grob genug, dass die Zahl nicht zappelt, genau genug, dass sie etwas sagt:
|
||
* unter einer Minute in Sekunden, darüber als `3:07 min`. Sekunden bis in die
|
||
* zehnte Minute auszuschreiben hieße eine Zahl, die sich jede Sekunde ändert
|
||
* und trotzdem niemandem hilft.
|
||
*
|
||
* Leer bei allem, was keine Dauer ist – unendlich, negativ, keine Zahl. Der
|
||
* Aufrufer zeigt dann gar nichts an, statt „NaN s" zu schreiben.
|
||
*/
|
||
export function formatDuration(seconds: number): string {
|
||
if (!Number.isFinite(seconds) || seconds < 0) return ''
|
||
// Unter einer Sekunde bleibt "1 s" stehen: "0 s" sähe aus wie fertig,
|
||
// während der Balken noch läuft.
|
||
if (seconds < 60) return `${Math.max(1, Math.round(seconds))} s`
|
||
const total = Math.round(seconds)
|
||
const m = Math.floor(total / 60)
|
||
if (m < 60) return `${m}:${String(total % 60).padStart(2, '0')} min`
|
||
return `${Math.floor(m / 60)}:${String(m % 60).padStart(2, '0')} h`
|
||
}
|