Skip to content

Commit caa51cc

Browse files
committed
Add teleprompter auto-loop toggle (#42)
1 parent 0546b80 commit caa51cc

13 files changed

Lines changed: 133 additions & 3 deletions

File tree

src/PrompterOne.Core/Workspace/Models/ReaderSettings.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,6 @@ public sealed record ReaderSettings(
1212
bool ShowFocusLine = ReaderSettingsDefaults.ShowFocusLine,
1313
bool ShowProgress = ReaderSettingsDefaults.ShowProgress,
1414
bool ShowCameraScene = ReaderSettingsDefaults.ShowCameraScene,
15+
bool AutoLoop = ReaderSettingsDefaults.AutoLoop,
1516
int FocalPointPercent = ReaderSettingsDefaults.FocalPointPercent,
1617
ReaderSpeedCueDisplayMode SpeedCueDisplayMode = ReaderSettingsDefaults.SpeedCueDisplayMode);

src/PrompterOne.Core/Workspace/Models/ReaderSettingsDefaults.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ public static class ReaderSettingsDefaults
1313
public const bool ShowFocusLine = true;
1414
public const bool ShowProgress = true;
1515
public const bool ShowCameraScene = false;
16+
public const bool AutoLoop = true;
1617
public const int FocalPointPercent = 30;
1718
public const ReaderSpeedCueDisplayMode SpeedCueDisplayMode = ReaderSpeedCueDisplayMode.WordsPerMinute;
1819
}

src/PrompterOne.Shared/Contracts/UiTestIds.Teleprompter.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ public static partial class UiTestIds
55
public static class Teleprompter
66
{
77
public const string ActiveWord = "teleprompter-active-word";
8+
public const string AutoLoopToggle = "teleprompter-auto-loop-toggle";
89
public const string Back = "teleprompter-back";
910
public const string AlignmentCenter = "teleprompter-alignment-center";
1011
public const string AlignmentControls = "teleprompter-alignment-controls";

src/PrompterOne.Shared/Teleprompter/Pages/TeleprompterPage.ReaderPlayback.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,14 @@ private async Task<int> AdvanceReaderPlaybackAsync(CancellationToken cancellatio
411411
return GetCurrentWordDelayMilliseconds();
412412
}
413413

414+
if (!_isReaderAutoLoopEnabled && _activeReaderCardIndex == _cards.Count - 1)
415+
{
416+
StopReaderPlaybackLoop();
417+
UpdateReaderDisplayState(requestAlignment: false);
418+
await InvokeAsync(StateHasChanged);
419+
return MinimumReaderLoopDelayMilliseconds;
420+
}
421+
414422
// Playback loop always advances upward — even when wrapping
415423
// from the last card back to index 0. Without an explicit
416424
// direction, the wrap would compare 0 < lastIndex and fire

src/PrompterOne.Shared/Teleprompter/Pages/TeleprompterPage.ReaderPreferences.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,15 @@ private Task PersistReaderCameraPreferenceAsync() =>
2626
ShowCameraScene = _isReaderCameraActive
2727
});
2828

29+
private async Task ToggleReaderAutoLoopAsync()
30+
{
31+
_isReaderAutoLoopEnabled = !_isReaderAutoLoopEnabled;
32+
await PersistReaderSettingsAsync(currentSettings => currentSettings with
33+
{
34+
AutoLoop = _isReaderAutoLoopEnabled
35+
});
36+
}
37+
2938
private async Task SetReaderSpeedCueDisplayModeAsync(ReaderSpeedCueDisplayMode displayMode)
3039
{
3140
var normalizedDisplayMode = NormalizeReaderSpeedCueDisplayMode(displayMode);

src/PrompterOne.Shared/Teleprompter/Pages/TeleprompterPage.Tooltips.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ public partial class TeleprompterPage
1010

1111
private string ReaderCameraTooltip => Text(UiTextKey.TooltipToggleCameraPreview);
1212

13+
private string ReaderAutoLoopTooltip => _isReaderAutoLoopEnabled
14+
? Text(UiTextKey.TooltipLoopPlaybackOn)
15+
: Text(UiTextKey.TooltipLoopPlaybackOff);
16+
1317
private string ReaderNextBlockTooltip => Text(UiTextKey.TooltipNextBlock);
1418

1519
private string ReaderNextWordTooltip => Text(UiTextKey.TooltipNextWord);

src/PrompterOne.Shared/Teleprompter/Pages/TeleprompterPage.razor

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -208,11 +208,12 @@
208208
CameraTooltip="@ReaderCameraTooltip" ControlsCssClass="@BuildReaderControlsCssClass()"
209209
EdgeInfoCssClass="@BuildReaderEdgeInfoCssClass()" EdgeProgressCssClass="@BuildReaderEdgeProgressCssClass()"
210210
EdgeSectionLabel="@_edgeSectionLabel" EdgeSegments="@BuildReaderEdgeSegments()" ElapsedLabel="@BuildElapsedLabel()"
211-
IsCameraActive="@_isReaderCameraActive" IsReaderPlaying="@_isReaderPlaying" NextBlockTooltip="@ReaderNextBlockTooltip"
211+
IsAutoLoopEnabled="@_isReaderAutoLoopEnabled" IsCameraActive="@_isReaderCameraActive" IsReaderPlaying="@_isReaderPlaying"
212+
NextBlockTooltip="@ReaderNextBlockTooltip"
212213
NextWordTooltip="@ReaderNextWordTooltip" OnCameraToggle="ToggleReaderCameraAsync" OnNextBlock="JumpToNextReaderCardAsync"
213-
OnNextWord="StepReaderForwardAsync" OnPlayToggle="ToggleReaderPlaybackAsync" OnPreviousBlock="JumpToPreviousReaderCardAsync"
214+
OnAutoLoopToggle="ToggleReaderAutoLoopAsync" OnNextWord="StepReaderForwardAsync" OnPlayToggle="ToggleReaderPlaybackAsync" OnPreviousBlock="JumpToPreviousReaderCardAsync"
214215
OnPreviousWord="StepReaderBackwardAsync" OnSpeedDown="DecreaseReaderPlaybackSpeedAsync" OnSpeedUp="IncreaseReaderPlaybackSpeedAsync"
215-
PlayToggleTooltip="@ReaderPlayToggleTooltip" PreviousBlockTooltip="@ReaderPreviousBlockTooltip"
216+
AutoLoopTooltip="@ReaderAutoLoopTooltip" PlayToggleTooltip="@ReaderPlayToggleTooltip" PreviousBlockTooltip="@ReaderPreviousBlockTooltip"
216217
PreviousWordTooltip="@ReaderPreviousWordTooltip" ProgressFillStyle="@BuildReaderProgressStyle()"
217218
ProgressLabel="@BuildReaderProgressLabel()" ProgressSegments="@BuildReaderProgressSegments()"
218219
ProgressShellCssClass="@BuildReaderProgressShellCssClass()" SpeedDownTooltip="@ReaderSpeedDownTooltip"

src/PrompterOne.Shared/Teleprompter/Pages/TeleprompterPage.razor.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ public partial class TeleprompterPage : IAsyncDisposable
7575
private bool _isFocalGuideActive;
7676
private bool _isReaderCameraActive;
7777
private bool _isReaderCountdownActive;
78+
private bool _isReaderAutoLoopEnabled = ReaderSettingsDefaults.AutoLoop;
7879
private bool _isReaderPlaying;
7980
private bool _loadState = true;
8081
private int _activeReaderCardIndex;
@@ -191,6 +192,7 @@ private async Task PopulateReaderStateAsync()
191192
_readerSpeedCueDisplayMode = NormalizeReaderSpeedCueDisplayMode(SessionService.State.ReaderSettings.SpeedCueDisplayMode);
192193
_readerTextAlignment = NormalizeReaderTextAlignment(SessionService.State.ReaderSettings.TextAlignment);
193194
_readerTextOrientation = SessionService.State.ReaderSettings.TextOrientation;
195+
_isReaderAutoLoopEnabled = SessionService.State.ReaderSettings.AutoLoop;
194196
_activeReaderCardIndex = 0;
195197
_activeReaderWordIndex = -1;
196198
_activeReaderPauseChunkIndex = null;

src/PrompterOne.Shared/Teleprompter/Pages/TeleprompterReaderTransport.razor

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,16 @@
107107

108108
<div class="rd-ctrl-group">
109109
<span class="rd-ctrl-label rd-block-indicator" id="@UiDomIds.Teleprompter.BlockIndicator" data-test="@UiTestIds.Teleprompter.BlockIndicator">@BlockIndicatorLabel</span>
110+
<TooltipAnchor OwnerTestId="@UiTestIds.Teleprompter.AutoLoopToggle" Text="@AutoLoopTooltip">
111+
<button class="rd-ctrl-btn"
112+
@onclick="OnAutoLoopToggle"
113+
aria-label="@AutoLoopTooltip"
114+
aria-pressed="@BuildBooleanDataAttribute(IsAutoLoopEnabled)"
115+
data-active="@BuildBooleanDataAttribute(IsAutoLoopEnabled)"
116+
data-test="@UiTestIds.Teleprompter.AutoLoopToggle">
117+
<UiIcon Kind="UiIconKind.Loop" Size="16" />
118+
</button>
119+
</TooltipAnchor>
110120
<TooltipAnchor OwnerTestId="@UiTestIds.Teleprompter.CameraToggle" Text="@CameraTooltip">
111121
<button class="@CameraButtonCssClass"
112122
id="@UiDomIds.Teleprompter.CameraButton"
@@ -121,8 +131,10 @@
121131
</div>
122132

123133
@code {
134+
[Parameter] public bool IsAutoLoopEnabled { get; set; }
124135
[Parameter] public bool IsCameraActive { get; set; }
125136
[Parameter] public bool IsReaderPlaying { get; set; }
137+
[Parameter, EditorRequired] public string AutoLoopTooltip { get; set; } = string.Empty;
126138
[Parameter, EditorRequired] public string BlockIndicatorLabel { get; set; } = string.Empty;
127139
[Parameter, EditorRequired] public string CameraButtonCssClass { get; set; } = string.Empty;
128140
[Parameter, EditorRequired] public string CameraTooltip { get; set; } = string.Empty;
@@ -133,6 +145,7 @@
133145
[Parameter, EditorRequired] public string EdgeSectionLabel { get; set; } = string.Empty;
134146
[Parameter, EditorRequired] public string ElapsedLabel { get; set; } = string.Empty;
135147
[Parameter] public EventCallback OnCameraToggle { get; set; }
148+
[Parameter] public EventCallback OnAutoLoopToggle { get; set; }
136149
[Parameter] public EventCallback OnNextBlock { get; set; }
137150
[Parameter] public EventCallback OnNextWord { get; set; }
138151
[Parameter] public EventCallback OnPlayToggle { get; set; }

tests/PrompterOne.Core.Tests/Workspace/ReaderSettingsSerializationTests.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ public void ReaderSettings_DeserializesLegacyPayload_WithDefaultFocalPointPercen
3030
Assert.Equal(ReaderSettingsDefaults.MirrorVertical, settings.MirrorVertical);
3131
Assert.Equal(ReaderSettingsDefaults.TextOrientation, settings.TextOrientation);
3232
Assert.Equal(ReaderSettingsDefaults.SpeedCueDisplayMode, settings.SpeedCueDisplayMode);
33+
Assert.Equal(ReaderSettingsDefaults.AutoLoop, settings.AutoLoop);
3334
Assert.Equal(1.11d, settings.FontScale);
3435
Assert.Equal(0.8182d, settings.TextWidth);
3536
}

0 commit comments

Comments
 (0)