What the scene's loading spinner shows and tells the viewer as a wait goes on. Pure apart from nowMs(): JRScene passes what is waiting and the time, so the rule is the same on any screen and in a test.
Three things can be waiting: the scene's own spinner (startLoadingSpinner(), a cast), the app waits the whole app is in (appWaits, a playback start), and the named waits the active screen has open (screenWaits). showing() decides between them.
Nothing is said before STILL_LOADING_MS: a wait that short is normal, and even a 512 MB Stick shows a large library's first page in about 3.4 s from a server that keeps up (measured 2026-09-24, 8,643-movie library). Past it the viewer is told the app is still working, which is the usual ~10 s point where a wait needs feedback; past SERVER_SLOW_MS, that the wait is the server's. That is true of every kind that gets text, because each waits on a server answer. Kinds whose wait is not a server answer get no text at all.
Members
(static, constant) MAX_AGE_MS
Past every stage; ageMs() stops counting here.
- Default Value
- 86400000
(static, constant) SERVER_SLOW_MS
- Default Value
- 30000
(static, constant) STILL_LOADING_MS
- Default Value
- 8000
Methods
(static) ageMs(startedMs, now) → {integer}
Milliseconds from startedMs to now, both from nowMs(), as an Integer the stage rules take. Clamped: a wall clock can step backwards (a time sync), and a wait a day old is past every stage anyway.
| Name | Type | Description |
|---|---|---|
startedMs | dynamic | |
now | dynamic |
- Type:
- integer
(static) hasStages(kind) → {boolean}
Whether kind tells the viewer anything as its wait goes on.
| Name | Type | Description |
|---|---|---|
kind | string |
- Type:
- boolean
(static) longestWait(entries) → {dynamic}
The wait whose text shows among entries ({ kind, startedMs }): the oldest one with stages, or the oldest one when none has any. invalid when entries is empty.
| Name | Type | Description |
|---|---|---|
entries | object |
- Type:
- dynamic
(static) msUntilNextChange(kind, elapsedMs) → {integer}
Milliseconds from elapsedMs until the text for kind next changes, or -1 when it never will: the kind has no stages, or the last one is already showing.
| Name | Type | Description |
|---|---|---|
kind | string | |
elapsedMs | integer |
- Type:
- integer
(static) nowMs() → {dynamic}
Wall-clock milliseconds as a LongInteger: the one clock a screen's waits and the scene both read, so a wait's age means the same on either side. Not an roTimespan, which belongs to one component and whose Integer milliseconds overflow after ~24.8 days of the app running; not UpTime(), a 32-bit Float, too coarse on a device that has been up for months. A wall clock can step (a time sync); the only effect is stage text shown early or late once.
- Type:
- dynamic
(static) showing(sceneWait, appWaits, waits, now) → {object}
What the spinner shows now: { visible, kind, elapsedMs, label }.
Waits the whole app is in (the scene's own spinner and its app waits) win while any is open, and the screen's waits show again, still counting from when they started, once the last of those ends. Among the waits that show, the text counts from the OLDEST one with stages, since that is how long the viewer has been waiting. label is the newest app wait's label (a channel's name), "" when none has one; the scene's own spinner carries its text in loadingText instead, so the scene chooses between the two.
| Name | Type | Description |
|---|---|---|
sceneWait | object | { isLoading, kind, startedMs } of the scene's own spinner |
appWaits | dynamic | the scene's open app waits (key -> { kind, label, startedMs }), or invalid |
waits | dynamic | the active screen's |
now | dynamic |
- Type:
- object
(static) textKeyAt(kind, elapsedMs) → {string}
The translation key for the text under the spinner after elapsedMs, or "" for none.
| Name | Type | Description |
|---|---|---|
kind | string | |
elapsedMs | integer |
- Type:
- string