From ed5f941ba8c84d4798c4c50a12543cafc9a5dec8 Mon Sep 17 00:00:00 2001 From: Dennis Brentjes Date: Sun, 1 Feb 2026 20:07:06 +0100 Subject: [PATCH] Non working start to a NavigationStack. --- Gamenight.Ui/Directory.Packages.props | 4 +++ Gamenight.Ui/Gamenight.Ui/App.axaml.cs | 14 +++++++--- Gamenight.Ui/Gamenight.Ui/Gamenight.Ui.csproj | 4 +++ .../Gamenight.Ui/Models/GamenightState.cs | 13 ++++++++++ Gamenight.Ui/Gamenight.Ui/ViewLocator.cs | 10 ++++++- .../ViewModels/GamenightsViewModel.cs | 24 +++++++++++++++++ .../Gamenight.Ui/ViewModels/MainViewModel.cs | 15 ++++++----- .../ViewModels/SideBarViewModel.cs | 26 +++++++++++++++++-- .../Gamenight.Ui/Views/GamenightsView.axaml | 14 ++++++++++ .../Views/GamenightsView.axaml.cs | 18 +++++++++++++ .../Gamenight.Ui/Views/HeaderView.axaml | 3 +-- .../Gamenight.Ui/Views/MainView.axaml | 19 ++++++++++---- .../Gamenight.Ui/Views/SideBarView.axaml | 1 + 13 files changed, 145 insertions(+), 20 deletions(-) create mode 100644 Gamenight.Ui/Gamenight.Ui/Models/GamenightState.cs create mode 100644 Gamenight.Ui/Gamenight.Ui/ViewModels/GamenightsViewModel.cs create mode 100644 Gamenight.Ui/Gamenight.Ui/Views/GamenightsView.axaml create mode 100644 Gamenight.Ui/Gamenight.Ui/Views/GamenightsView.axaml.cs diff --git a/Gamenight.Ui/Directory.Packages.props b/Gamenight.Ui/Directory.Packages.props index 39d76c9..d2b9a2e 100644 --- a/Gamenight.Ui/Directory.Packages.props +++ b/Gamenight.Ui/Directory.Packages.props @@ -17,6 +17,10 @@ + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + diff --git a/Gamenight.Ui/Gamenight.Ui/App.axaml.cs b/Gamenight.Ui/Gamenight.Ui/App.axaml.cs index bdf036b..5adb465 100644 --- a/Gamenight.Ui/Gamenight.Ui/App.axaml.cs +++ b/Gamenight.Ui/Gamenight.Ui/App.axaml.cs @@ -3,13 +3,14 @@ using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Data.Core.Plugins; using System.Linq; using Avalonia.Markup.Xaml; -using Avalonia.ReactiveUI; using Gamenight.Ui.ViewModels; using Gamenight.Ui.Views; using Microsoft.Extensions.DependencyInjection; using Gamenight.Ui.Services; using System; using Refit; +using Gamenight.Ui.Models; +using ReactiveUI; namespace Gamenight.Ui; @@ -26,13 +27,21 @@ public partial class App : Application { // Register all the services needed for the application to run var collection = new ServiceCollection(); + var state = new GamenightState(); + collection.AddSingleton(state); + var gamenightApi = RestService.For("http://localhost:8080", - new RefitSettings {} + new RefitSettings + { + AuthorizationHeaderValueGetter = state.GetBearerToken + } ); collection.AddSingleton(gamenightApi); collection.AddSingleton(); + collection.AddSingleton(sp => sp.GetRequiredService()); collection.AddSingleton(); collection.AddSingleton(); + collection.AddSingleton(); if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime) { collection.AddSingleton(); @@ -45,7 +54,6 @@ public partial class App : Application ServiceProvider = collection.BuildServiceProvider(); var mainViewModel = ServiceProvider.GetRequiredService(); - if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { // Avoid duplicate validations from both Avalonia and the CommunityToolkit. diff --git a/Gamenight.Ui/Gamenight.Ui/Gamenight.Ui.csproj b/Gamenight.Ui/Gamenight.Ui/Gamenight.Ui.csproj index 6ca4010..5157276 100644 --- a/Gamenight.Ui/Gamenight.Ui/Gamenight.Ui.csproj +++ b/Gamenight.Ui/Gamenight.Ui/Gamenight.Ui.csproj @@ -22,6 +22,10 @@ + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + diff --git a/Gamenight.Ui/Gamenight.Ui/Models/GamenightState.cs b/Gamenight.Ui/Gamenight.Ui/Models/GamenightState.cs new file mode 100644 index 0000000..84e16a6 --- /dev/null +++ b/Gamenight.Ui/Gamenight.Ui/Models/GamenightState.cs @@ -0,0 +1,13 @@ + +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; + +namespace Gamenight.Ui.Models; + +public class GamenightState +{ + public string JwtToken { get; set; } = ""; + + public Task GetBearerToken(HttpRequestMessage req, CancellationToken ct) => Task.FromResult($"Bearer: {JwtToken}"); +} \ No newline at end of file diff --git a/Gamenight.Ui/Gamenight.Ui/ViewLocator.cs b/Gamenight.Ui/Gamenight.Ui/ViewLocator.cs index 2b79fb2..d50b3b3 100644 --- a/Gamenight.Ui/Gamenight.Ui/ViewLocator.cs +++ b/Gamenight.Ui/Gamenight.Ui/ViewLocator.cs @@ -3,6 +3,8 @@ using System.Diagnostics.CodeAnalysis; using Avalonia.Controls; using Avalonia.Controls.Templates; using Gamenight.Ui.ViewModels; +using Gamenight.Ui.Views; +using ReactiveUI; namespace Gamenight.Ui; @@ -12,7 +14,7 @@ namespace Gamenight.Ui; [RequiresUnreferencedCode( "Default implementation of ViewLocator involves reflection which may be trimmed away.", Url = "https://docs.avaloniaui.net/docs/concepts/view-locator")] -public class ViewLocator : IDataTemplate +public class ViewLocator : IDataTemplate, ReactiveUI.IViewLocator { public Control? Build(object? param) { @@ -34,4 +36,10 @@ public class ViewLocator : IDataTemplate { return data is ViewModelBase; } + + public IViewFor ResolveView(T? viewModel, string? contract = null) => viewModel switch + { + GamenightsViewModel context => new GamenightsView { DataContext = context }, + _ => throw new ArgumentOutOfRangeException(nameof(viewModel)) + }; } \ No newline at end of file diff --git a/Gamenight.Ui/Gamenight.Ui/ViewModels/GamenightsViewModel.cs b/Gamenight.Ui/Gamenight.Ui/ViewModels/GamenightsViewModel.cs new file mode 100644 index 0000000..a4a60ef --- /dev/null +++ b/Gamenight.Ui/Gamenight.Ui/ViewModels/GamenightsViewModel.cs @@ -0,0 +1,24 @@ + +using System; +using Gamenight.Ui.Services; +using ReactiveUI; + +namespace Gamenight.Ui.ViewModels; + +public class GamenightsViewModel : ReactiveObject, IRoutableViewModel +{ + private IGamenightApi GamenightApi { get; } + public IScreen HostScreen { get; } + public string? UrlPathSegment { get; } = Guid.NewGuid().ToString().Substring(0, 5); + + public GamenightsViewModel(IGamenightApi gamenightApi, IScreen hostScreen) + { + GamenightApi = gamenightApi; + HostScreen = hostScreen; + } + + public GamenightsViewModel() + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/Gamenight.Ui/Gamenight.Ui/ViewModels/MainViewModel.cs b/Gamenight.Ui/Gamenight.Ui/ViewModels/MainViewModel.cs index 2e24613..47c1e9e 100644 --- a/Gamenight.Ui/Gamenight.Ui/ViewModels/MainViewModel.cs +++ b/Gamenight.Ui/Gamenight.Ui/ViewModels/MainViewModel.cs @@ -1,33 +1,34 @@ using System.Threading.Tasks; -using System.Windows.Input; using CommunityToolkit.Mvvm.ComponentModel; using Gamenight.Ui.Services; using ReactiveUI; +using ReactiveUI.SourceGenerators; namespace Gamenight.Ui.ViewModels; -public partial class MainViewModel : ViewModelBase +public partial class MainViewModel : ReactiveObject, IScreen { - [ObservableProperty] + [ObservableAsProperty] private string _greeting = "Welcome to Avalonia!"; private IGamenightApi GamenightApi { get; } public HeaderViewModel HeaderViewModel { get; } public SideBarViewModel SideBarViewModel { get; } - [ObservableProperty] - private ICommand _loginCommand; + public RoutingState Router { get; } = new RoutingState(); + + [ObservableAsProperty] + private IReactiveCommand _loginCommand; public MainViewModel(IGamenightApi gamenightApi, HeaderViewModel headerViewModel, SideBarViewModel sideBarViewModel) { GamenightApi = gamenightApi; HeaderViewModel = headerViewModel; SideBarViewModel = sideBarViewModel; + SideBarViewModel.Screen = this; _loginCommand = ReactiveCommand.Create(Test); } - public MainViewModel() => throw new System.NotImplementedException(); - public async Task Test() { var token = await GamenightApi.Token(new Login() { Username = "admin", diff --git a/Gamenight.Ui/Gamenight.Ui/ViewModels/SideBarViewModel.cs b/Gamenight.Ui/Gamenight.Ui/ViewModels/SideBarViewModel.cs index d08cb70..d6eba10 100644 --- a/Gamenight.Ui/Gamenight.Ui/ViewModels/SideBarViewModel.cs +++ b/Gamenight.Ui/Gamenight.Ui/ViewModels/SideBarViewModel.cs @@ -1,7 +1,29 @@ +using System.Reactive; +using ReactiveUI; + namespace Gamenight.Ui.ViewModels; -public class SideBarViewModel : ViewModelBase +public partial class SideBarViewModel : ReactiveObject { - + public IReactiveCommand PushViewModel + { + get; + set => this.RaiseAndSetIfChanged(ref field, value); + } + + public GamenightsViewModel GamenightsViewModel + { + get; + set => this.RaiseAndSetIfChanged(ref field, value); + } + + public IScreen Screen { get; set; } + + + public SideBarViewModel(GamenightsViewModel gamenightsViewModel) + { + PushViewModel = ReactiveCommand.CreateFromObservable((IRoutableViewModel x) => Screen.Router.Navigate.Execute(x)); + GamenightsViewModel = gamenightsViewModel; + } } \ No newline at end of file diff --git a/Gamenight.Ui/Gamenight.Ui/Views/GamenightsView.axaml b/Gamenight.Ui/Gamenight.Ui/Views/GamenightsView.axaml new file mode 100644 index 0000000..b8e4125 --- /dev/null +++ b/Gamenight.Ui/Gamenight.Ui/Views/GamenightsView.axaml @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file diff --git a/Gamenight.Ui/Gamenight.Ui/Views/GamenightsView.axaml.cs b/Gamenight.Ui/Gamenight.Ui/Views/GamenightsView.axaml.cs new file mode 100644 index 0000000..7746dfe --- /dev/null +++ b/Gamenight.Ui/Gamenight.Ui/Views/GamenightsView.axaml.cs @@ -0,0 +1,18 @@ +using Avalonia.Markup.Xaml; +using Avalonia.ReactiveUI; +using Gamenight.Ui.ViewModels; + +namespace Gamenight.Ui.Views; + +public partial class GamenightsView : ReactiveUserControl +{ + public GamenightsView() + { + InitializeComponent(); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } +} \ No newline at end of file diff --git a/Gamenight.Ui/Gamenight.Ui/Views/HeaderView.axaml b/Gamenight.Ui/Gamenight.Ui/Views/HeaderView.axaml index 5e98caa..690132b 100644 --- a/Gamenight.Ui/Gamenight.Ui/Views/HeaderView.axaml +++ b/Gamenight.Ui/Gamenight.Ui/Views/HeaderView.axaml @@ -2,8 +2,7 @@ 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" - xmlns:vm="using:Gamenight.Ui.ViewModels" - xmlns:views="clr-namespace:Gamenight.Ui.Views" + xmlns:vm="using:Gamenight.Ui.ViewModels" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="Gamenight.Ui.Views.HeaderView" x:DataType="vm:HeaderViewModel"> diff --git a/Gamenight.Ui/Gamenight.Ui/Views/MainView.axaml b/Gamenight.Ui/Gamenight.Ui/Views/MainView.axaml index 3bbd93d..ec1c3fa 100644 --- a/Gamenight.Ui/Gamenight.Ui/Views/MainView.axaml +++ b/Gamenight.Ui/Gamenight.Ui/Views/MainView.axaml @@ -3,7 +3,9 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:vm="using:Gamenight.Ui.ViewModels" - xmlns:views="clr-namespace:Gamenight.Ui.Views" + xmlns:views="clr-namespace:Gamenight.Ui.Views" + xmlns:reactiveUi="http://reactiveui.net" + xmlns:ui="clr-namespace:Gamenight.Ui" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="Gamenight.Ui.Views.MainView" x:DataType="vm:MainViewModel"> @@ -24,10 +26,17 @@ - - -