-
Notifications
You must be signed in to change notification settings - Fork 0
feat(demo): scaffold Avalonia demo shell #34
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
luckydizzier
merged 1 commit into
main
from
codex/2025-10-01_19-57-10_create-demo-folder-and-scaffold-solution
Oct 1, 2025
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| <?xml version="1.0" encoding="utf-8"?> | ||
| <Application xmlns="https://github.com/avaloniaui" | ||
| xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" | ||
| x:Class="XBase.Demo.App.App"> | ||
| </Application> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| using System; | ||
| using Avalonia; | ||
| using Avalonia.Controls.ApplicationLifetimes; | ||
| using Avalonia.Markup.Xaml; | ||
| using Microsoft.Extensions.DependencyInjection; | ||
| using XBase.Demo.App.Views; | ||
|
|
||
| namespace XBase.Demo.App; | ||
|
|
||
| public partial class App : Application | ||
| { | ||
| public static IServiceProvider? Services { get; set; } | ||
|
|
||
| public override void Initialize() | ||
| { | ||
| AvaloniaXamlLoader.Load(this); | ||
| } | ||
|
|
||
| public override void OnFrameworkInitializationCompleted() | ||
| { | ||
| if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) | ||
| { | ||
| var services = Services ?? throw new InvalidOperationException("Service provider is not initialized."); | ||
| desktop.MainWindow = services.GetRequiredService<MainWindow>(); | ||
| } | ||
|
|
||
| base.OnFrameworkInitializationCompleted(); | ||
| } | ||
| } |
24 changes: 24 additions & 0 deletions
24
src/demo/XBase.Demo.App/DependencyInjection/ServiceCollectionExtensions.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| using System; | ||
| using Microsoft.Extensions.DependencyInjection; | ||
| using XBase.Demo.App.ViewModels; | ||
| using XBase.Demo.App.Views; | ||
| using XBase.Demo.Diagnostics; | ||
| using XBase.Demo.Infrastructure; | ||
|
|
||
| namespace XBase.Demo.App.DependencyInjection; | ||
|
|
||
| public static class ServiceCollectionExtensions | ||
| { | ||
| public static IServiceCollection AddDemoApp(this IServiceCollection services) | ||
| { | ||
| ArgumentNullException.ThrowIfNull(services); | ||
|
|
||
| services.AddXBaseDemoInfrastructure(); | ||
| services.AddXBaseDemoDiagnostics(); | ||
|
|
||
| services.AddSingleton<ShellViewModel>(); | ||
| services.AddSingleton<MainWindow>(); | ||
|
|
||
| return services; | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| using System; | ||
| using Avalonia; | ||
| using Avalonia.ReactiveUI; | ||
| using Microsoft.Extensions.DependencyInjection; | ||
| using Microsoft.Extensions.Hosting; | ||
| using XBase.Demo.App.DependencyInjection; | ||
|
|
||
| namespace XBase.Demo.App; | ||
|
|
||
| public static class Program | ||
| { | ||
| [STAThread] | ||
| public static int Main(string[] args) | ||
| { | ||
| using var host = CreateHost(args); | ||
| host.Start(); | ||
|
|
||
| App.Services = host.Services; | ||
|
|
||
| try | ||
| { | ||
| return BuildAvaloniaApp() | ||
| .AfterSetup(_ => App.Services = host.Services) | ||
|
||
| .StartWithClassicDesktopLifetime(args); | ||
| } | ||
| finally | ||
| { | ||
| host.StopAsync().GetAwaiter().GetResult(); | ||
| } | ||
| } | ||
|
|
||
| private static IHost CreateHost(string[] args) | ||
| { | ||
| var builder = Host.CreateApplicationBuilder(args); | ||
| builder.Services.AddDemoApp(); | ||
| return builder.Build(); | ||
| } | ||
|
|
||
| private static AppBuilder BuildAvaloniaApp() | ||
| => AppBuilder.Configure<App>() | ||
| .UsePlatformDetect() | ||
| .LogToTrace() | ||
| .UseReactiveUI(); | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,107 @@ | ||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.Reactive; | ||
| using System.Reactive.Linq; | ||
| using System.Threading.Tasks; | ||
| using Microsoft.Extensions.Logging; | ||
| using ReactiveUI; | ||
| using XBase.Demo.Domain.Catalog; | ||
| using XBase.Demo.Domain.Diagnostics; | ||
| using XBase.Demo.Domain.Services; | ||
|
|
||
| namespace XBase.Demo.App.ViewModels; | ||
|
|
||
| public class ShellViewModel : ReactiveObject | ||
| { | ||
| private readonly ITableCatalogService _catalogService; | ||
| private readonly ITablePageService _pageService; | ||
| private readonly IDemoTelemetrySink _telemetrySink; | ||
| private readonly ILogger<ShellViewModel> _logger; | ||
|
|
||
| private string? _catalogRoot; | ||
| private string? _tableSummary; | ||
| private bool _isBusy; | ||
|
|
||
| public ShellViewModel( | ||
| ITableCatalogService catalogService, | ||
| ITablePageService pageService, | ||
| IDemoTelemetrySink telemetrySink, | ||
| ILogger<ShellViewModel> logger) | ||
| { | ||
| _catalogService = catalogService; | ||
| _pageService = pageService; | ||
| _telemetrySink = telemetrySink; | ||
| _logger = logger; | ||
|
|
||
| OpenCatalogCommand = ReactiveCommand.CreateFromTask<string>(ExecuteOpenCatalogAsync); | ||
| OpenCatalogCommand.ThrownExceptions.Subscribe(OnOpenCatalogFault); | ||
| } | ||
|
|
||
| public ReactiveCommand<string, Unit> OpenCatalogCommand { get; } | ||
|
|
||
| public string? CatalogRoot | ||
| { | ||
| get => _catalogRoot; | ||
| private set => this.RaiseAndSetIfChanged(ref _catalogRoot, value); | ||
| } | ||
|
|
||
| public string? TableSummary | ||
| { | ||
| get => _tableSummary; | ||
| private set => this.RaiseAndSetIfChanged(ref _tableSummary, value); | ||
| } | ||
|
|
||
| public bool IsBusy | ||
| { | ||
| get => _isBusy; | ||
| private set => this.RaiseAndSetIfChanged(ref _isBusy, value); | ||
| } | ||
|
|
||
| private async Task ExecuteOpenCatalogAsync(string rootPath) | ||
| { | ||
| if (string.IsNullOrWhiteSpace(rootPath)) | ||
| { | ||
| return; | ||
| } | ||
|
|
||
| try | ||
| { | ||
| IsBusy = true; | ||
| CatalogRoot = rootPath; | ||
|
|
||
| var catalog = await _catalogService.LoadCatalogAsync(rootPath); | ||
| var payload = new Dictionary<string, object?> | ||
| { | ||
| ["root"] = catalog.RootPath, | ||
| ["tableCount"] = catalog.Tables.Count | ||
| }; | ||
| _telemetrySink.Publish(new DemoTelemetryEvent("CatalogLoaded", DateTimeOffset.UtcNow, payload)); | ||
|
|
||
| if (catalog.Tables.Count > 0) | ||
| { | ||
| var firstTable = catalog.Tables[0]; | ||
| var page = await _pageService.LoadPageAsync(firstTable, new TablePageRequest(0, 25)); | ||
| TableSummary = $"{catalog.Tables.Count} tables discovered. Preview rows: {page.Rows.Count} from {firstTable.Name}."; | ||
| } | ||
| else | ||
| { | ||
| TableSummary = "Catalog scanned successfully with no tables detected."; | ||
| } | ||
| } | ||
| finally | ||
| { | ||
| IsBusy = false; | ||
| } | ||
| } | ||
|
|
||
| private void OnOpenCatalogFault(Exception exception) | ||
| { | ||
| _logger.LogError(exception, "Catalog load failed"); | ||
| var payload = new Dictionary<string, object?> | ||
| { | ||
| ["message"] = exception.Message | ||
| }; | ||
| _telemetrySink.Publish(new DemoTelemetryEvent("CatalogLoadFailed", DateTimeOffset.UtcNow, payload)); | ||
| TableSummary = "Catalog load failed. Review diagnostics for details."; | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| <?xml version="1.0" encoding="utf-8"?> | ||
| <Window xmlns="https://github.com/avaloniaui" | ||
| xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" | ||
| xmlns:d="http://schemas.microsoft.com/expression/blend/2008" | ||
| xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" | ||
| x:Class="XBase.Demo.App.Views.MainWindow" | ||
| Width="1024" | ||
| Height="640" | ||
| Title="xBase Demo Shell" | ||
| mc:Ignorable="d"> | ||
| <Grid RowDefinitions="Auto,*" ColumnDefinitions="*"> | ||
| <StackPanel Orientation="Horizontal" Margin="12" Spacing="12"> | ||
| <TextBlock Text="Catalog Root:" VerticalAlignment="Center" FontWeight="Medium" /> | ||
| <TextBlock Text="{Binding CatalogRoot, FallbackValue=Select a directory}" VerticalAlignment="Center" /> | ||
| <TextBlock Text="{Binding TableSummary}" VerticalAlignment="Center" Margin="12,0,0,0" /> | ||
| </StackPanel> | ||
|
|
||
| <Border Grid.Row="1" Margin="12" Padding="12" BorderBrush="#FF4D596A" BorderThickness="1" CornerRadius="6"> | ||
| <TextBlock Text="Demo grid placeholder – wiring ready for implementation." TextWrapping="Wrap" /> | ||
| </Border> | ||
| </Grid> | ||
| </Window> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| using System; | ||
| using Avalonia.Markup.Xaml; | ||
| using Avalonia.ReactiveUI; | ||
| using Microsoft.Extensions.DependencyInjection; | ||
| using XBase.Demo.App.ViewModels; | ||
|
|
||
| namespace XBase.Demo.App.Views; | ||
|
|
||
| public partial class MainWindow : ReactiveWindow<ShellViewModel> | ||
| { | ||
| public MainWindow() | ||
| : this(ResolveViewModel()) | ||
| { | ||
| } | ||
|
|
||
| public MainWindow(ShellViewModel viewModel) | ||
| { | ||
| InitializeComponent(); | ||
| DataContext = viewModel; | ||
| } | ||
|
|
||
| private static ShellViewModel ResolveViewModel() | ||
| { | ||
| var services = App.Services ?? throw new InvalidOperationException("Service provider is not available for MainWindow."); | ||
| return services.GetRequiredService<ShellViewModel>(); | ||
| } | ||
|
|
||
| private void InitializeComponent() | ||
| { | ||
| AvaloniaXamlLoader.Load(this); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| <Project Sdk="Microsoft.NET.Sdk"> | ||
| <PropertyGroup> | ||
| <OutputType>WinExe</OutputType> | ||
| <AssemblyName>XBase.Demo.App</AssemblyName> | ||
| <RootNamespace>XBase.Demo.App</RootNamespace> | ||
| <Nullable>enable</Nullable> | ||
| </PropertyGroup> | ||
| <ItemGroup> | ||
| <ProjectReference Include="../XBase.Demo.Domain/XBase.Demo.Domain.csproj" /> | ||
| <ProjectReference Include="../XBase.Demo.Infrastructure/XBase.Demo.Infrastructure.csproj" /> | ||
| <ProjectReference Include="../XBase.Demo.Diagnostics/XBase.Demo.Diagnostics.csproj" /> | ||
| </ItemGroup> | ||
| <ItemGroup> | ||
| <PackageReference Include="Avalonia" Version="11.1.3" /> | ||
| <PackageReference Include="Avalonia.Desktop" Version="11.1.3" /> | ||
| <PackageReference Include="Avalonia.ReactiveUI" Version="11.1.3" /> | ||
| <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" /> | ||
| <PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" /> | ||
| </ItemGroup> | ||
| </Project> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| using System; | ||
| using System.Collections.Concurrent; | ||
| using System.Collections.Generic; | ||
| using Microsoft.Extensions.Logging; | ||
| using XBase.Demo.Domain.Diagnostics; | ||
|
|
||
| namespace XBase.Demo.Diagnostics; | ||
|
|
||
| /// <summary> | ||
| /// Captures telemetry events in-memory for UI consumption. | ||
| /// </summary> | ||
| public sealed class InMemoryTelemetrySink : IDemoTelemetrySink | ||
| { | ||
| private readonly ConcurrentQueue<DemoTelemetryEvent> _events = new(); | ||
| private readonly ILogger<InMemoryTelemetrySink> _logger; | ||
|
|
||
| public InMemoryTelemetrySink(ILogger<InMemoryTelemetrySink> logger) | ||
| { | ||
| _logger = logger; | ||
| } | ||
|
|
||
| public void Publish(DemoTelemetryEvent telemetryEvent) | ||
| { | ||
| ArgumentNullException.ThrowIfNull(telemetryEvent); | ||
|
|
||
| _events.Enqueue(telemetryEvent); | ||
| while (_events.Count > 128 && _events.TryDequeue(out _)) | ||
| { | ||
| } | ||
|
|
||
| _logger.LogInformation("Telemetry event {Name} captured", telemetryEvent.Name); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Returns a snapshot of the buffered events for visualization. | ||
| /// </summary> | ||
| public IReadOnlyCollection<DemoTelemetryEvent> GetSnapshot() | ||
| => _events.ToArray(); | ||
| } |
21 changes: 21 additions & 0 deletions
21
src/demo/XBase.Demo.Diagnostics/ServiceCollectionExtensions.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| using System; | ||
| using Microsoft.Extensions.DependencyInjection; | ||
| using XBase.Demo.Domain.Diagnostics; | ||
|
|
||
| namespace XBase.Demo.Diagnostics; | ||
|
|
||
| /// <summary> | ||
| /// Registers diagnostics sinks for the demo experience. | ||
| /// </summary> | ||
| public static class ServiceCollectionExtensions | ||
| { | ||
| public static IServiceCollection AddXBaseDemoDiagnostics(this IServiceCollection services) | ||
| { | ||
| ArgumentNullException.ThrowIfNull(services); | ||
|
|
||
| services.AddSingleton<InMemoryTelemetrySink>(); | ||
| services.AddSingleton<IDemoTelemetrySink>(sp => sp.GetRequiredService<InMemoryTelemetrySink>()); | ||
|
|
||
| return services; | ||
| } | ||
| } |
11 changes: 11 additions & 0 deletions
11
src/demo/XBase.Demo.Diagnostics/XBase.Demo.Diagnostics.csproj
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| <Project Sdk="Microsoft.NET.Sdk"> | ||
| <PropertyGroup> | ||
| <AssemblyName>XBase.Demo.Diagnostics</AssemblyName> | ||
| <RootNamespace>XBase.Demo.Diagnostics</RootNamespace> | ||
| </PropertyGroup> | ||
| <ItemGroup> | ||
| <ProjectReference Include="../XBase.Demo.Domain/XBase.Demo.Domain.csproj" /> | ||
| <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.0" /> | ||
| <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" /> | ||
| </ItemGroup> | ||
| </Project> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| using System.Collections.Generic; | ||
|
|
||
| namespace XBase.Demo.Domain.Catalog; | ||
|
|
||
| /// <summary> | ||
| /// Represents a catalog of xBase tables discovered under a root directory. | ||
| /// </summary> | ||
| /// <param name="RootPath">The file system root the catalog was scanned from.</param> | ||
| /// <param name="Tables">The set of tables available for browsing.</param> | ||
| public sealed record CatalogModel(string RootPath, IReadOnlyList<TableModel> Tables); | ||
|
|
||
| /// <summary> | ||
| /// Represents a single table, including metadata necessary for browsing. | ||
| /// </summary> | ||
| /// <param name="Name">Logical table name.</param> | ||
| /// <param name="Path">Absolute path to the DBF file.</param> | ||
| /// <param name="Indexes">Associated indexes discovered for the table.</param> | ||
| public sealed record TableModel(string Name, string Path, IReadOnlyList<IndexModel> Indexes); | ||
|
|
||
| /// <summary> | ||
| /// Represents an index that can be applied while browsing. | ||
| /// </summary> | ||
| /// <param name="Name">Index identifier.</param> | ||
| /// <param name="Expression">The expression used to compute the index key.</param> | ||
| /// <param name="Order">Optional ordering hint for display.</param> | ||
| public sealed record IndexModel(string Name, string Expression, int Order = 0); |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
App.Services is being set twice - once at line 18 and again in the AfterSetup callback at line 23. The first assignment appears redundant since the AfterSetup callback will override it.