Skip to content

Commit 4440f97

Browse files
committed
workin on ui
1 parent 3649f3c commit 4440f97

File tree

60 files changed

+2292
-685
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+2292
-685
lines changed

AGENTS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ Browser test execution rules:
108108
- Inside that single process, the browser suite may run up to `4` parallel xUnit workers.
109109
- Do not run `PrompterLive.App.UITests` in parallel with another `dotnet build` or `dotnet test` command.
110110
- If a prior build already ran, prefer `dotnet test ... --no-build` for the browser suite.
111+
- Do not add Python or ad-hoc runner scripts to bootstrap browser verification. The repo test commands must self-host the app and execute the flows end to end on their own.
111112
- Browser UI scenarios are the primary acceptance gate for this repo. Component and core tests are supporting layers, not the release bar.
112113
- Major user flows MUST be covered by long Playwright scenarios that execute real browser interactions end to end.
113114
- Major browser scenarios MUST capture screenshot artifacts under `output/playwright/`.

docs/Features/SettingsMediaFeedback.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ sequenceDiagram
2424
participant Devices as "IMediaDeviceService"
2525
participant CameraInterop as "CameraPreviewInterop"
2626
participant MicInterop as "MicrophoneLevelInterop"
27-
participant Browser as "navigator.mediaDevices + AudioContext"
27+
participant Browser as "vendored LiveKit SDK + browser media APIs"
2828
2929
User->>Settings: Open Cameras or Microphones
3030
Settings->>Permissions: Query or request browser access
@@ -33,8 +33,8 @@ sequenceDiagram
3333
Settings->>MicCard: Pass selected microphone + active section state
3434
CameraCard->>CameraInterop: Attach or detach preview stream
3535
MicCard->>MicInterop: Start or stop live level monitor
36-
CameraInterop->>Browser: getUserMedia(video)
37-
MicInterop->>Browser: getUserMedia(audio) + analyser
36+
CameraInterop->>Browser: createLocalVideoTrack(device)
37+
MicInterop->>Browser: createLocalAudioTrack(device) + createAudioAnalyser(track)
3838
Browser-->>CameraCard: Live video stream
3939
Browser-->>MicCard: Live signal level
4040
User->>Settings: Adjust camera mirror, gain, or default devices
@@ -53,7 +53,7 @@ flowchart LR
5353
MicInterop["MicrophoneLevelInterop"]
5454
Scene["IMediaSceneService"]
5555
Studio["StudioSettingsStore"]
56-
Browser["browser-media.js thin bridge"]
56+
Browser["browser-media.js thin LiveKit-backed bridge"]
5757
5858
Page --> CameraCard
5959
Page --> MicCard
@@ -73,4 +73,5 @@ flowchart LR
7373
- the microphone meter UI must stay Blazor-owned; JS may sample browser audio and report numeric levels only
7474
- UI contracts for the feedback cards must use stable shared `UiTestIds` and `UiDomIds`
7575
- browser acceptance must verify real synthetic media attachment and live activity through the deterministic media harness
76+
- settings camera and microphone feedback must use the vendored LiveKit browser SDK that is already shipped with the app, not a second CDN or ad-hoc runtime
7677
- this document is about setup feedback only; routing remains documented in [GoLiveRuntime.md](./GoLiveRuntime.md)

src/PrompterLive.App/wwwroot/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
1010
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&family=JetBrains+Mono:wght@400;500;600&family=Playfair+Display:ital,wght@0,700;0,800;0,900;1,700;1,800&display=swap" rel="stylesheet" />
1111
<link rel="icon" type="image/png" href="_content/PrompterLive.Shared/favicon.png" />
12+
<script src="_content/PrompterLive.Shared/theme/browser-theme.js"></script>
1213
<link rel="stylesheet" href="_content/PrompterLive.Shared/design/tokens.css" />
1314
<link rel="stylesheet" href="_content/PrompterLive.Shared/design/components.css" />
1415
<link rel="stylesheet" href="_content/PrompterLive.Shared/design/styles.css" />

src/PrompterLive.Shared/AppShell/Layout/MainLayout.razor

Lines changed: 37 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,18 @@
6868
@oninput="HandleLibrarySearchInputAsync"
6969
data-testid="@UiTestIds.Header.LibrarySearch" />
7070
</div>
71+
<button type="button"
72+
class="btn-golive-header"
73+
@onclick="HandleOpenGoLiveClickAsync"
74+
data-live-state="@GoLiveIndicatorState"
75+
data-testid="@UiTestIds.Header.GoLive">
76+
<span class="btn-golive-dot" aria-hidden="true"></span>
77+
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
78+
<polygon points="23,7 16,12 23,17" />
79+
<rect x="1" y="5" width="15" height="14" rx="2" ry="2" />
80+
</svg>
81+
@Text(UiTextKey.HeaderGoLive)
82+
</button>
7183
<button type="button"
7284
class="btn-create"
7385
@onclick="HandleCreateScriptClickAsync"
@@ -79,6 +91,31 @@
7991
@Text(UiTextKey.HeaderNewScript)
8092
</button>
8193
}
94+
else
95+
{
96+
<button type="button"
97+
class="btn-live-shell"
98+
@onclick="HandleOpenGoLiveClickAsync"
99+
data-live-state="@GoLiveIndicatorState"
100+
data-testid="@UiTestIds.Header.GoLive">
101+
<span class="btn-live-shell-icon" aria-hidden="true">
102+
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
103+
<path d="M4 12a8 8 0 0 1 8-8" />
104+
<path d="M20 12a8 8 0 0 0-8-8" />
105+
<path d="M4 12a8 8 0 0 0 8 8" />
106+
<path d="M20 12a8 8 0 0 1-8 8" />
107+
<circle cx="12" cy="12" r="2.5" />
108+
</svg>
109+
</span>
110+
<span class="btn-live-shell-copy">
111+
<span class="btn-live-shell-label">@Text(UiTextKey.HeaderGoLive)</span>
112+
@if (GoLiveSessionState.HasActiveSession)
113+
{
114+
<span class="btn-live-shell-status">@GoLiveIndicatorCopy</span>
115+
}
116+
</span>
117+
</button>
118+
}
82119

83120
@if (ShowLearnAction)
84121
{
@@ -94,29 +131,6 @@
94131
</button>
95132
}
96133

97-
<button type="button"
98-
class="btn-live-shell"
99-
@onclick="HandleOpenGoLiveClickAsync"
100-
data-live-state="@GoLiveIndicatorState"
101-
data-testid="@UiTestIds.Header.GoLive">
102-
<span class="btn-live-shell-icon" aria-hidden="true">
103-
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
104-
<path d="M4 12a8 8 0 0 1 8-8" />
105-
<path d="M20 12a8 8 0 0 0-8-8" />
106-
<path d="M4 12a8 8 0 0 0 8 8" />
107-
<path d="M20 12a8 8 0 0 1-8 8" />
108-
<circle cx="12" cy="12" r="2.5" />
109-
</svg>
110-
</span>
111-
<span class="btn-live-shell-copy">
112-
<span class="btn-live-shell-label">@Text(UiTextKey.HeaderGoLive)</span>
113-
@if (GoLiveSessionState.HasActiveSession)
114-
{
115-
<span class="btn-live-shell-status">@GoLiveIndicatorCopy</span>
116-
}
117-
</span>
118-
</button>
119-
120134
@if (ShowLearnWpmBadge)
121135
{
122136
<span id="@UiDomIds.Learn.HeaderWpmBadge"

src/PrompterLive.Shared/AppShell/Layout/MainLayout.razor.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ public partial class MainLayout : LayoutComponentBase, IDisposable
2121
[Inject] private AppBootstrapper Bootstrapper { get; set; } = null!;
2222
[Inject] private AppShellService Shell { get; set; } = null!;
2323
[Inject] private BrowserConnectivityService Connectivity { get; set; } = null!;
24+
[Inject] private BrowserThemeService ThemeService { get; set; } = null!;
2425
[Inject] private GoLiveSessionService GoLiveSession { get; set; } = null!;
2526
[Inject] private IScriptSessionService SessionService { get; set; } = null!;
2627
[Inject] private ILogger<MainLayout> Logger { get; set; } = null!;
@@ -138,6 +139,7 @@ protected override async Task OnAfterRenderAsync(bool firstRender)
138139
return;
139140
}
140141

142+
await ThemeService.InitializeAsync();
141143
await Connectivity.StartAsync();
142144
await Bootstrapper.EnsureReadyAsync();
143145
}

src/PrompterLive.Shared/AppShell/Services/AppBootstrapper.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ namespace PrompterLive.Shared.Services;
88

99
public sealed class AppBootstrapper(
1010
IScriptSessionService sessionService,
11+
IScriptRepository scriptRepository,
1112
ILibraryFolderRepository libraryFolderRepository,
1213
IMediaSceneService mediaSceneService,
1314
BrowserSettingsStore settingsStore,
@@ -18,6 +19,7 @@ public sealed class AppBootstrapper(
1819
private const string SceneSettingsKey = "prompterlive.scene";
1920

2021
private readonly IScriptSessionService _sessionService = sessionService;
22+
private readonly IScriptRepository _scriptRepository = scriptRepository;
2123
private readonly ILibraryFolderRepository _libraryFolderRepository = libraryFolderRepository;
2224
private readonly IMediaSceneService _mediaSceneService = mediaSceneService;
2325
private readonly BrowserSettingsStore _settingsStore = settingsStore;
@@ -44,7 +46,8 @@ public async Task EnsureReadyAsync(CancellationToken cancellationToken = default
4446
}
4547

4648
_logger.LogInformation("Initializing PrompterLive browser state.");
47-
await _libraryFolderRepository.InitializeAsync([], cancellationToken);
49+
await _libraryFolderRepository.InitializeAsync(RuntimeLibrarySeedCatalog.CreateFolders(), cancellationToken);
50+
await _scriptRepository.InitializeAsync(RuntimeLibrarySeedCatalog.CreateDocuments(), cancellationToken);
4851
await _sessionService.InitializeAsync(cancellationToken);
4952

5053
var readerSettings = await _settingsStore.LoadAsync<ReaderSettings>(ReaderSettingsKey, cancellationToken);

src/PrompterLive.Shared/AppShell/Services/PrompterLiveServiceCollectionExtensions.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ public static IServiceCollection AddPrompterLiveShared(this IServiceCollection s
3838
services.AddScoped<IMediaDeviceService, BrowserMediaDeviceService>();
3939
services.AddScoped<IMediaSceneService, MediaSceneService>();
4040
services.AddScoped<BrowserSettingsStore>();
41+
services.AddScoped<BrowserThemeService>();
4142
services.AddScoped<StudioSettingsStore>();
4243
services.AddScoped<CameraPreviewInterop>();
4344
services.AddScoped<MicrophoneLevelInterop>();

src/PrompterLive.Shared/Contracts/UiTestIds.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ public static class Settings
205205
public const string CameraPreviewEmpty = "settings-camera-preview-empty";
206206
public const string CameraPreviewLabel = "settings-camera-preview-label";
207207
public const string CameraPreviewVideo = "settings-camera-preview-video";
208-
public const string CameraRoutingCta = "settings-camera-routing-cta";
208+
public const string CameraRoutingCta = Header.GoLive;
209209
public const string CameraMirrorToggle = "settings-camera-mirror-toggle";
210210
public const string CameraResolution = "settings-camera-resolution";
211211
public const string CamerasPanel = "settings-cameras-panel";
@@ -279,10 +279,14 @@ public static class Settings
279279

280280
public static string CameraDeviceAction(string deviceId) => $"settings-camera-device-action-{deviceId}";
281281

282+
public static string CameraPrimaryAction(string deviceId) => $"settings-camera-primary-{deviceId}";
283+
282284
public static string MicDelay(string deviceId) => $"settings-mic-delay-{deviceId}";
283285

284286
public static string MicDevice(string deviceId) => $"settings-mic-device-{deviceId}";
285287

288+
public static string ThemeOption(string value) => $"settings-theme-option-{value}";
289+
286290
public static string SceneCamera(string sourceId) => $"settings-scene-camera-{sourceId}";
287291

288292
public static string SceneFlip(string sourceId) => $"settings-scene-flip-{sourceId}";

src/PrompterLive.Shared/Library/Pages/LibraryPage.ViewState.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ private async Task SetSortMode(LibrarySortMode sortMode)
1616
private void RebuildLibraryView()
1717
{
1818
_folderNodes = LibraryFolderTreeBuilder.BuildTree(_folders, _allCards, _selectedFolderId, _expandedFolderIds);
19-
_folderChips = LibraryFolderTreeBuilder.BuildChips(_folders, _allCards, _selectedFolderId);
2019
_folderOptions = LibraryFolderTreeBuilder.BuildOptions(_folders);
2120
_cards = SortCards(FilterCards()).ToList();
2221
Shell.ShowLibrary(ResolveSelectedFolderLabel());

src/PrompterLive.Shared/Library/Pages/LibraryPage.razor

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,6 @@
2929
data-testid="@UiTestIds.Library.SortWpm">@Text(UiTextKey.LibrarySortWpm)</button>
3030
</div>
3131

32-
<LibraryFolderChips Chips="_folderChips"
33-
OnSelectFolder="SelectFolder" />
34-
3532
<LibraryCardsGrid Cards="_cards"
3633
FolderOptions="_folderOptions"
3734
OnOpenScript="OpenScriptAsync"

0 commit comments

Comments
 (0)