Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ AdaptiveRemote is a remote control application for TV and AV equipment designed
- Support for both touch/mouse and specialized input devices

## Technology Stack
- **Platform:** Windows OS only (.NET 8 / net8.0-windows)
- **Platform:** Windows OS only (.NET 10 / net10.0-windows)
- **UI Framework:** WPF with Blazor WebView components (Microsoft.AspNetCore.Components.WebView.Wpf)
- **Language:** C# with nullable reference types enabled
- **Build System:** .NET SDK, MSBuild
Expand Down Expand Up @@ -60,7 +60,7 @@ The AdaptiveRemote.Headless host uses Playwright for cross-platform E2E testing
```
- **Install Playwright Browsers (one-time):**
```bash
pwsh src/AdaptiveRemote.Headless/bin/Debug/net8.0/playwright.ps1 install chromium
pwsh src/AdaptiveRemote.Headless/bin/Debug/net10.0/playwright.ps1 install chromium
```
- **Run Tests:** No special environment needed - fully headless
```bash
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v5
with:
dotnet-version: '8.0.x'
dotnet-version: '10.0.x'

- name: Restore dependencies
run: dotnet restore
Expand All @@ -35,7 +35,7 @@ jobs:

- name: Install Chromium browser for Playwright headless tests
shell: pwsh
run: pwsh ./src/AdaptiveRemote.Headless/bin/Debug/net8.0/playwright.ps1 install chromium
run: pwsh ./src/AdaptiveRemote.Headless/bin/Debug/net10.0/playwright.ps1 install chromium

- name: Test
run: dotnet test --no-build --verbosity normal --logger trx --results-directory "TestResults"
Expand Down
2 changes: 1 addition & 1 deletion src/AdaptiveRemote.App/AdaptiveRemote.App.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<RootNamespace>AdaptiveRemote</RootNamespace>
Expand Down
12 changes: 10 additions & 2 deletions src/AdaptiveRemote.App/Services/IFileSystemExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,19 @@ public static Stream OpenWrite(this IFileSystem fileSystem, string path, bool cr
{
if (createDirectory)
{
CreateDirectory(fileSystem, DirectoryFor(path), recursive: true);
string? directory = DirectoryFor(path);
if (!string.IsNullOrEmpty(directory))
{
CreateDirectory(fileSystem, directory, recursive: true);
}
}

return fileSystem.OpenWrite(path);
}

private static string DirectoryFor(string path) => Path.GetDirectoryName(path)!;
private static string? DirectoryFor(string path)
{
string? directory = Path.GetDirectoryName(path);
return string.IsNullOrEmpty(directory) ? null : directory;
}
}
2 changes: 1 addition & 1 deletion src/AdaptiveRemote.Console/AdaptiveRemote.Console.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0-windows7.0</TargetFramework>
<TargetFramework>net10.0-windows7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<EnableWindowsTargeting>true</EnableWindowsTargeting>
Expand Down
2 changes: 1 addition & 1 deletion src/AdaptiveRemote.Headless/AdaptiveRemote.Headless.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
Expand Down
20 changes: 20 additions & 0 deletions src/AdaptiveRemote.Headless/Components/App.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
@using AdaptiveRemote.Components

<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<base href="/" />
<link rel="stylesheet" href="css/app.min.css" />
<link rel="icon" type="image/png" href="favicon.png" />
<HeadOutlet />
</head>

<body>
<Routes />
<script src="_framework/blazor.web.js"></script>
</body>

</html>
3 changes: 3 additions & 0 deletions src/AdaptiveRemote.Headless/Components/Routes.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@using AdaptiveRemote.Components

<Root />
10 changes: 10 additions & 0 deletions src/AdaptiveRemote.Headless/Components/_Imports.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
@using System.Net.Http
@using System.Net.Http.Json
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using static Microsoft.AspNetCore.Components.Web.RenderMode
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.JSInterop
@using AdaptiveRemote.Headless
@using AdaptiveRemote.Headless.Components
13 changes: 4 additions & 9 deletions src/AdaptiveRemote.Headless/Pages/_Host.cshtml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
@* This page needs to be kept in sync with AdaptiveRemote.App\wwwroot\index.html *@
@page
@using Microsoft.AspNetCore.Components.Web
@using AdaptiveRemote.Components
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
<!DOCTYPE html>
Expand All @@ -11,17 +12,11 @@
<base href="~/" />
<link href="css/app.min.css" rel="stylesheet" />
<link href="WpfBlazor.styles.css" rel="stylesheet" />
<link rel="icon" type="image/png" href="favicon.png" />
<component type="typeof(HeadOutlet)" render-mode="ServerPrerendered" />
</head>
<body>
<div id="app">
<component type="typeof(Root)" render-mode="Server" />
</div>

<div id="blazor-error-ui" data-nosnippet>
An unhandled error has occurred.
<a href="" class="reload">Reload</a>
<a class="dismiss">🗙</a>
</div>
<component type="typeof(Root)" render-mode="ServerPrerendered" />
<script src="_framework/blazor.server.js"></script>
</body>
</html>
12 changes: 9 additions & 3 deletions src/AdaptiveRemote.Headless/PlaywrightBrowserLifetimeService.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using AdaptiveRemote.Services.Testing;
using AdaptiveRemote.Utilities;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Hosting.Server.Features;
using Microsoft.Extensions.Options;
using Microsoft.Playwright;

Expand All @@ -13,6 +15,7 @@ internal class PlaywrightBrowserLifetimeService : BackgroundService, IBrowserUIA
{
private readonly ILogger<PlaywrightBrowserLifetimeService> _logger;
private readonly IHostApplicationLifetime _lifetime;
private readonly IServer _server;
private readonly PlaywrightSettings _settings;
private IPlaywright? _playwright;
private IBrowser? _browser;
Expand All @@ -27,10 +30,12 @@ internal class PlaywrightBrowserLifetimeService : BackgroundService, IBrowserUIA
public PlaywrightBrowserLifetimeService(
ILogger<PlaywrightBrowserLifetimeService> logger,
IOptions<PlaywrightSettings> options,
IHostApplicationLifetime lifetime)
IHostApplicationLifetime lifetime,
IServer server)
{
_logger = logger;
_lifetime = lifetime;
_server = server;
_settings = options.Value;
}

Expand All @@ -43,8 +48,9 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)

try
{
// Get the port the app is listening on (from configuration or default)
string appUrl = "http://localhost:5000"; // Default
// Get the actual URL the server is listening on
var serverAddressesFeature = _server.Features.Get<IServerAddressesFeature>();
string appUrl = serverAddressesFeature?.Addresses.FirstOrDefault() ?? "http://localhost:5000";

_logger.LogInformation("Will navigate to: {AppUrl}", appUrl);

Expand Down
18 changes: 10 additions & 8 deletions src/AdaptiveRemote.Headless/Program.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using AdaptiveRemote.Headless;
using AdaptiveRemote.Headless.Components;
using AdaptiveRemote.Services.Conversation;
using AdaptiveRemote.Services.Lifecycle;
using AdaptiveRemote.Services.Testing;
Expand All @@ -22,9 +23,9 @@
.AddSingleton<IGrammarProvider, StubGrammarProvider>()
.AddSingleton<ISpeechRecognitionEngine, StubSpeechRecognition>();

// Add the minimal services for ASP.NET to serve the Blazor UI
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
// Add services to the container - using the .NET 10 template approach
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents();

// Register circuit handler for logging
builder.Services.AddSingleton<CircuitHandler, LoggingCircuitHandler>();
Expand All @@ -38,15 +39,16 @@

WebApplication app = builder.Build();

// Configure the HTTP request pipeline - following .NET 10 template pattern
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseExceptionHandler("/Error", createScopeForErrors: true);
}

app.UseStaticFiles();
app.UseRouting();
app.UseAntiforgery();

app.MapBlazorHub();
app.MapFallbackToPage("/_Host");
app.MapStaticAssets();
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode();

app.Run();
2 changes: 1 addition & 1 deletion src/AdaptiveRemote/AdaptiveRemote.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows</TargetFramework>
<TargetFramework>net10.0-windows</TargetFramework>
<RuntimeIdentifiers>win-x64</RuntimeIdentifiers>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

Expand Down
Loading