fix(media): a played-out clip can play again; play button beside the Video File label
Reported 2026-11-05: "when I click Loop, the video doesn't play in the preview pane". Two causes, both real: - `VideoClipPipe.StartAsync` bailed out once it had run once (`_run != null`), so a clip that reached EOF could never be started again — it held its last frame forever. - Loop is only consulted at end-of-file by a LIVE decoder, so flipping it on a finished clip did nothing at all. Now: the pipe reports running state and is restartable after a natural end; the manager marks a session finished (keeping its last frame) and exposes `IsRunning`/`RestartAsync`; the layer shows `IsMediaRunning`/`IsMediaFinished`; flipping Loop on a finished clip restarts it. UI: `▶ Play` sits to the right of the **Video File** label and is enabled only while Loop is off (creator ruling: with Loop on the clip already runs continuously, so there is nothing to start). The panel says "Clip finished — holding the last frame." so a frozen picture explains itself. Also: verify.sh no longer runs physical-input tests by default. That test moves the real cursor (SetCursorPos + mouse_event); running it mid-gate hijacks the machine someone is using, which is exactly how it felt. Opt in with PHYSICAL_TESTS=1 when the desktop is idle; the header documents the scoped-run command for working hours. Test: `MediaPlaybackRestartTests` (pipe restart, finished state, Play again, Loop-on-finished). 8 scoped tests green. FULL SUITE NOT RUN — the machine was in use; run scripts/verify.sh in a quiet window before the next milestone.
This commit is contained in:
+23
-1
@@ -256,7 +256,10 @@ public class Source : SceneElement
|
||||
public bool MediaIsLooping
|
||||
{
|
||||
get => _mediaIsLooping;
|
||||
set => Set(ref _mediaIsLooping, value);
|
||||
set
|
||||
{
|
||||
if (Set(ref _mediaIsLooping, value)) Raise(nameof(CanPlayMedia));
|
||||
}
|
||||
}
|
||||
|
||||
private double _mediaVolume = 1.0;
|
||||
@@ -275,6 +278,25 @@ public class Source : SceneElement
|
||||
set => Set(ref _mediaMuted, value);
|
||||
}
|
||||
|
||||
private bool _isMediaRunning;
|
||||
/// <summary>True while the clip is decoding. False means it has played out and is holding its
|
||||
/// last frame — the panel then offers "Play again" instead of leaving a frozen picture with no
|
||||
/// explanation (the 2026-11-05 "clicking Loop did nothing" report).</summary>
|
||||
public bool IsMediaRunning
|
||||
{
|
||||
get => _isMediaRunning;
|
||||
set
|
||||
{
|
||||
if (Set(ref _isMediaRunning, value)) Raise(nameof(IsMediaFinished));
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsMediaFinished => !IsMediaRunning;
|
||||
|
||||
/// <summary>Play is a manual, one-shot action: while Loop is on the clip restarts itself, so the
|
||||
/// button would be a no-op (creator ruling 2026-11-05 — the button is beside the Video File label).</summary>
|
||||
public bool CanPlayMedia => !MediaIsLooping;
|
||||
|
||||
private MediaPlaybackState _mediaPlaybackState = MediaPlaybackState.Stopped;
|
||||
public MediaPlaybackState MediaPlaybackState
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user