From e1053ae6d7e0135de92315f8a819223156241137 Mon Sep 17 00:00:00 2001 From: KP9lKk Date: Wed, 4 Dec 2024 11:11:13 +0300 Subject: [PATCH] add reactive navigation --- Presence.Desktop/App.axaml | 6 -- Presence.Desktop/App.axaml.cs | 6 +- .../DI/ServiceColletionExtensions.cs | 2 +- Presence.Desktop/ViewLocator.cs | 29 ++----- Presence.Desktop/ViewModels/GroupViewModel.cs | 73 +++++++++++++++++ .../ViewModels/MainWindowViewModel.cs | 79 +++---------------- .../ViewModels/PrecenceViewModel.cs | 11 +++ Presence.Desktop/Views/GroupView.axaml | 45 +++++++++++ Presence.Desktop/Views/GroupView.axaml.cs | 17 ++++ Presence.Desktop/Views/MainWindow.axaml | 50 +++--------- Presence.Desktop/Views/MainWindow.axaml.cs | 18 +++-- Presence.Desktop/Views/PrecenceView.axaml | 8 ++ Presence.Desktop/Views/PrecenceView.axaml.cs | 16 ++++ 13 files changed, 216 insertions(+), 144 deletions(-) create mode 100644 Presence.Desktop/ViewModels/GroupViewModel.cs create mode 100644 Presence.Desktop/ViewModels/PrecenceViewModel.cs create mode 100644 Presence.Desktop/Views/GroupView.axaml create mode 100644 Presence.Desktop/Views/GroupView.axaml.cs create mode 100644 Presence.Desktop/Views/PrecenceView.axaml create mode 100644 Presence.Desktop/Views/PrecenceView.axaml.cs diff --git a/Presence.Desktop/App.axaml b/Presence.Desktop/App.axaml index eea6afa..8b8af41 100644 --- a/Presence.Desktop/App.axaml +++ b/Presence.Desktop/App.axaml @@ -1,14 +1,8 @@ - - - - - diff --git a/Presence.Desktop/App.axaml.cs b/Presence.Desktop/App.axaml.cs index 2640ca7..023b7c1 100644 --- a/Presence.Desktop/App.axaml.cs +++ b/Presence.Desktop/App.axaml.cs @@ -20,13 +20,13 @@ namespace Presence.Desktop var serviceCollection = new ServiceCollection(); serviceCollection.AddCommonService(); var services = serviceCollection.BuildServiceProvider(); - var mainViewModel = services.GetRequiredService(); + var mainViewModel = services.GetRequiredService(); if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { - desktop.MainWindow = new MainWindow + desktop.MainWindow = new MainWindow() { - DataContext = mainViewModel, + DataContext = new MainWindowViewModel(services), }; } diff --git a/Presence.Desktop/DI/ServiceColletionExtensions.cs b/Presence.Desktop/DI/ServiceColletionExtensions.cs index 340bc24..7527f09 100644 --- a/Presence.Desktop/DI/ServiceColletionExtensions.cs +++ b/Presence.Desktop/DI/ServiceColletionExtensions.cs @@ -20,7 +20,7 @@ namespace Presence.Desktop.DI .AddDbContext() .AddSingleton() .AddTransient() - .AddTransient(); + .AddTransient(); } } } diff --git a/Presence.Desktop/ViewLocator.cs b/Presence.Desktop/ViewLocator.cs index 74b8a57..6e218c4 100644 --- a/Presence.Desktop/ViewLocator.cs +++ b/Presence.Desktop/ViewLocator.cs @@ -2,31 +2,18 @@ using Avalonia.Controls; using Avalonia.Controls.Templates; using Presence.Desktop.ViewModels; using System; +using Presence.Desktop.Views; +using ReactiveUI; namespace Presence.Desktop { - public class ViewLocator : IDataTemplate + public class ViewLocator : IViewLocator { - - public Control? Build(object? param) + public IViewFor? ResolveView(T? viewModel, string? contract = null) => viewModel switch { - if (param is null) - return null; - - var name = param.GetType().FullName!.Replace("ViewModel", "View", StringComparison.Ordinal); - var type = Type.GetType(name); - - if (type != null) - { - return (Control)Activator.CreateInstance(type)!; - } - - return new TextBlock { Text = "Not Found: " + name }; - } - - public bool Match(object? data) - { - return data is ViewModelBase; - } + GroupViewModel groupViewModel => new GroupView{DataContext = groupViewModel}, + PresenceViewModel presenceViewModel => new PresenceView{DataContext = presenceViewModel}, + _ => throw new ArgumentOutOfRangeException(nameof(viewModel)) + }; } } diff --git a/Presence.Desktop/ViewModels/GroupViewModel.cs b/Presence.Desktop/ViewModels/GroupViewModel.cs new file mode 100644 index 0000000..99131e5 --- /dev/null +++ b/Presence.Desktop/ViewModels/GroupViewModel.cs @@ -0,0 +1,73 @@ +using domain.UseCase; +using DynamicData; +using DynamicData.Binding; +using Presence.Desktop.Models; +using ReactiveUI; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Reactive.Linq; +using Tmds.DBus.Protocol; + +namespace Presence.Desktop.ViewModels +{ + public class GroupViewModel : ViewModelBase, IRoutableViewModel + { + private readonly List _groupPresentersDataSource = new List(); + private ObservableCollection _groups; + public ObservableCollection Groups => _groups; + + public GroupPresenter? SelectedGroupItem { + get => _selectedGroupItem; + set => this.RaiseAndSetIfChanged(ref _selectedGroupItem, value); } + + private GroupPresenter? _selectedGroupItem; + + + + public ObservableCollection Users { get => _users;} + public ObservableCollection _users; + public GroupViewModel(IGroupUseCase groupUseCase) + { + foreach (var item in groupUseCase.GetGroupsWithStudents()) + { + GroupPresenter groupPresenter = new GroupPresenter + { + Id = item.Id, + Name = item.Name, + users = item.Users?.Select(user => new UserPresenter + { + Name = user.Name, + Guid = user.Guid, + Group = new GroupPresenter { Id = item.Id, Name = item.Name } + } + ).ToList() + }; + _groupPresentersDataSource.Add(groupPresenter); + } + _groups = new ObservableCollection(_groupPresentersDataSource); + + _users = new ObservableCollection(); + + this.WhenAnyValue(vm => vm.SelectedGroupItem) + .Subscribe(_ => SetUsers()); + + } + + private void SetUsers() + { + if(SelectedGroupItem == null) return; + if (SelectedGroupItem.users == null) return; + Users.Clear(); + foreach (var item in SelectedGroupItem.users) + { + Users.Add(item); + } + } + + public string? UrlPathSegment { get; } + public IScreen HostScreen { get; } + } +} + diff --git a/Presence.Desktop/ViewModels/MainWindowViewModel.cs b/Presence.Desktop/ViewModels/MainWindowViewModel.cs index 8eb6331..a4640b4 100644 --- a/Presence.Desktop/ViewModels/MainWindowViewModel.cs +++ b/Presence.Desktop/ViewModels/MainWindowViewModel.cs @@ -1,73 +1,16 @@ -using domain.UseCase; -using DynamicData; -using DynamicData.Binding; -using Presence.Desktop.Models; -using ReactiveUI; using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using System.Reactive.Linq; -using Tmds.DBus.Protocol; +using Microsoft.Extensions.DependencyInjection; +using ReactiveUI; -namespace Presence.Desktop.ViewModels +namespace Presence.Desktop.ViewModels; + +public class MainWindowViewModel: ViewModelBase, IScreen { - public class MainWindowViewModel : ViewModelBase + public RoutingState Router { get; } = new RoutingState(); + + public MainWindowViewModel(IServiceProvider serviceProvider) { - private readonly IGroupUseCase _groupService; - private List groupPresentersDataSource = new List(); - private ObservableCollection _groups; - public ObservableCollection Groups => _groups; - - public GroupPresenter? SelectedGroupItem { - get => _selectedGroupItem; - set => this.RaiseAndSetIfChanged(ref _selectedGroupItem, value); } - - private GroupPresenter? _selectedGroupItem; - - - - public ObservableCollection Users { get => _users;} - public ObservableCollection _users; - public MainWindowViewModel(IGroupUseCase groupUseCase) - { - _groupService = groupUseCase; - - foreach (var item in _groupService.GetGroupsWithStudents()) - { - GroupPresenter groupPresenter = new GroupPresenter - { - Id = item.Id, - Name = item.Name, - users = item.Users?.Select(user => new UserPresenter - { - Name = user.Name, - Guid = user.Guid, - Group = new GroupPresenter { Id = item.Id, Name = item.Name } - } - ).ToList() - }; - groupPresentersDataSource.Add(groupPresenter); - } - _groups = new ObservableCollection(groupPresentersDataSource); - - _users = new ObservableCollection(); - - this.WhenAnyValue(vm => vm.SelectedGroupItem) - .Subscribe(_ => SetUsers()); - - } - - private void SetUsers() - { - if(SelectedGroupItem == null) return; - if (SelectedGroupItem.users == null) return; - Users.Clear(); - foreach (var item in SelectedGroupItem.users) - { - Users.Add(item); - } - } + var groupViewModel = serviceProvider.GetRequiredService(); + Router.Navigate.Execute(groupViewModel); } -} - +} \ No newline at end of file diff --git a/Presence.Desktop/ViewModels/PrecenceViewModel.cs b/Presence.Desktop/ViewModels/PrecenceViewModel.cs new file mode 100644 index 0000000..d492c79 --- /dev/null +++ b/Presence.Desktop/ViewModels/PrecenceViewModel.cs @@ -0,0 +1,11 @@ +using ReactiveUI; + +namespace Presence.Desktop.ViewModels; + +public class PresenceViewModel: ViewModelBase, IRoutableViewModel +{ + public string? UrlPathSegment { get; } + public IScreen HostScreen { get; } +} + + \ No newline at end of file diff --git a/Presence.Desktop/Views/GroupView.axaml b/Presence.Desktop/Views/GroupView.axaml new file mode 100644 index 0000000..e82f70e --- /dev/null +++ b/Presence.Desktop/Views/GroupView.axaml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Presence.Desktop/Views/GroupView.axaml.cs b/Presence.Desktop/Views/GroupView.axaml.cs new file mode 100644 index 0000000..7702263 --- /dev/null +++ b/Presence.Desktop/Views/GroupView.axaml.cs @@ -0,0 +1,17 @@ +using Avalonia.Controls; +using Avalonia.Markup.Xaml; +using Avalonia.ReactiveUI; +using Presence.Desktop.ViewModels; +using ReactiveUI; + +namespace Presence.Desktop.Views +{ + public partial class GroupView : ReactiveUserControl + { + public GroupView() + { + this.WhenActivated(disposables => { }); + AvaloniaXamlLoader.Load(this); + } + } +} \ No newline at end of file diff --git a/Presence.Desktop/Views/MainWindow.axaml b/Presence.Desktop/Views/MainWindow.axaml index e2c94fa..25f9e3a 100644 --- a/Presence.Desktop/Views/MainWindow.axaml +++ b/Presence.Desktop/Views/MainWindow.axaml @@ -1,47 +1,19 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + Title="MainWindow"> + + + + + + + diff --git a/Presence.Desktop/Views/MainWindow.axaml.cs b/Presence.Desktop/Views/MainWindow.axaml.cs index 2619e70..2385b19 100644 --- a/Presence.Desktop/Views/MainWindow.axaml.cs +++ b/Presence.Desktop/Views/MainWindow.axaml.cs @@ -1,12 +1,18 @@ +using Avalonia; using Avalonia.Controls; +using Avalonia.Markup.Xaml; +using Avalonia.ReactiveUI; +using Presence.Desktop.ViewModels; +using ReactiveUI; -namespace Presence.Desktop.Views +namespace Presence.Desktop.Views; + +public partial class MainWindow : ReactiveWindow { - public partial class MainWindow : Window + public MainWindow() { - public MainWindow() - { - InitializeComponent(); - } + this.WhenActivated(disposables => { }); + AvaloniaXamlLoader.Load(this); + } } \ No newline at end of file diff --git a/Presence.Desktop/Views/PrecenceView.axaml b/Presence.Desktop/Views/PrecenceView.axaml new file mode 100644 index 0000000..574763a --- /dev/null +++ b/Presence.Desktop/Views/PrecenceView.axaml @@ -0,0 +1,8 @@ + + Welcome to Avalonia! + diff --git a/Presence.Desktop/Views/PrecenceView.axaml.cs b/Presence.Desktop/Views/PrecenceView.axaml.cs new file mode 100644 index 0000000..ad4e1fe --- /dev/null +++ b/Presence.Desktop/Views/PrecenceView.axaml.cs @@ -0,0 +1,16 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; +using Avalonia.ReactiveUI; +using Presence.Desktop.ViewModels; +using ReactiveUI; + +namespace Presence.Desktop.Views; + +public partial class PresenceView : ReactiveUserControl +{ + public PresenceView() + { + this.WhenActivated(disposables => { }); + AvaloniaXamlLoader.Load(this); } +} \ No newline at end of file