From 7c2e468288365dcf7bfb089a680d27f61aa68bc9 Mon Sep 17 00:00:00 2001 From: Rory& Date: Mon, 5 Aug 2024 06:50:57 +0200 Subject: List rooms --- LibMatrix | 2 +- .../Services/MatrixAuthenticationService.cs | 2 +- ModerationClient/ViewModels/ClientViewModel.cs | 138 ++++++++++++++++----- ModerationClient/Views/ClientView.axaml | 50 +++++--- ModerationClient/Views/ClientView.axaml.cs | 6 - ModerationClient/Views/LoginView.axaml.cs | 19 +-- ModerationClient/Views/MainWindow.axaml.cs | 37 +++--- 7 files changed, 159 insertions(+), 95 deletions(-) diff --git a/LibMatrix b/LibMatrix index d04269e..3b48824 160000 --- a/LibMatrix +++ b/LibMatrix @@ -1 +1 @@ -Subproject commit d04269ea2bc944099d95a32aada7bcd4639969b2 +Subproject commit 3b488242050bbc0521d846bd31cb6ea59b8d4e38 diff --git a/ModerationClient/Services/MatrixAuthenticationService.cs b/ModerationClient/Services/MatrixAuthenticationService.cs index 69f8810..7e9ce70 100644 --- a/ModerationClient/Services/MatrixAuthenticationService.cs +++ b/ModerationClient/Services/MatrixAuthenticationService.cs @@ -44,8 +44,8 @@ public class MatrixAuthenticationService(ILogger lo var mxidParts = username.Split(':', 2); var res = await hsProvider.Login(mxidParts[1], username, password); await File.WriteAllTextAsync(Path.Combine(cfg.ProfileDirectory, "login.json"), res.ToJson()); - IsLoggedIn = true; + await LoadProfileAsync(); // Console.WriteLine("Login result: " + res.ToJson()); } diff --git a/ModerationClient/ViewModels/ClientViewModel.cs b/ModerationClient/ViewModels/ClientViewModel.cs index 340eb56..1e287ec 100644 --- a/ModerationClient/ViewModels/ClientViewModel.cs +++ b/ModerationClient/ViewModels/ClientViewModel.cs @@ -1,63 +1,135 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.Diagnostics; +using System.IO; using System.Linq; using System.Threading.Tasks; using ArcaneLibs.Collections; +using LibMatrix.EventTypes.Spec.State; using LibMatrix.Helpers; using LibMatrix.Responses; +using MatrixUtils.Abstractions; using Microsoft.Extensions.Logging; using ModerationClient.Services; namespace ModerationClient.ViewModels; -public partial class ClientViewModel : ViewModelBase -{ - public ClientViewModel(ILogger logger, MatrixAuthenticationService authService) { - this.logger = logger; - this.authService = authService; +public partial class ClientViewModel : ViewModelBase { + public ClientViewModel(ILogger logger, MatrixAuthenticationService authService, CommandLineConfiguration cfg) { + _logger = logger; + _authService = authService; + _cfg = cfg; + DisplayedSpaces.Add(_allRoomsNode = new AllRoomsSpaceNode(this)); _ = Task.Run(Run); } - - private readonly ILogger logger; - private readonly MatrixAuthenticationService authService; - - private Exception? _exception; - - public Exception? Exception { - get => _exception; - private set => SetProperty(ref _exception, value); - } - public ObservableCollection DisplayedSpaces { get; } = [ - new SpaceNode { Name = "Root", Children = [ - new SpaceNode { Name = "Child 1" }, - new SpaceNode { Name = "Child 2" }, - new SpaceNode { Name = "Child 3" } - ] }, - new SpaceNode { Name = "Root 2", Children = [ - new SpaceNode { Name = "Child 4" }, - new SpaceNode { Name = "Child 5" }, - new SpaceNode { Name = "Child 6" } - ] } - ]; + private readonly ILogger _logger; + private readonly MatrixAuthenticationService _authService; + private readonly CommandLineConfiguration _cfg; + private SpaceNode? _currentSpace; + private readonly SpaceNode _allRoomsNode; + public ObservableCollection DisplayedSpaces { get; } = []; + public ObservableDictionary AllRooms { get; } = new(); + + public SpaceNode CurrentSpace { + get => _currentSpace ?? _allRoomsNode; + set => SetProperty(ref _currentSpace, value); + } public async Task Run() { - var sh = new SyncStateResolver(authService.Homeserver, logger); + var sh = new SyncStateResolver(_authService.Homeserver, _logger, storageProvider: new FileStorageProvider(Path.Combine(_cfg.ProfileDirectory, "syncCache"))); // var res = await sh.SyncAsync(); + //await sh.OptimiseStore(); while (true) { var res = await sh.ContinueAsync(); - Console.WriteLine("mow"); + await ApplySpaceChanges(res.next); + //OnPropertyChanged(nameof(CurrentSpace)); + //OnPropertyChanged(nameof(CurrentSpace.ChildRooms)); + // Console.WriteLine($"mow A={AllRooms.Count}|D={DisplayedSpaces.Count}"); + // for (int i = 0; i < GC.MaxGeneration; i++) { + // GC.Collect(i, GCCollectionMode.Forced, blocking: true); + // GC.WaitForPendingFinalizers(); + // } } } - private void ApplySpaceChanges(SyncResponse newSync) { + private async Task ApplySpaceChanges(SyncResponse newSync) { + List tasks = []; + foreach (var room in newSync.Rooms?.Join ?? []) { + if (!AllRooms.ContainsKey(room.Key)) { + AllRooms.Add(room.Key, new RoomNode { Name = "Loading..." }); + } + + if (room.Value.State?.Events is not null) { + var nameEvent = room.Value.State!.Events!.FirstOrDefault(x => x.Type == "m.room.name" && x.StateKey == ""); + AllRooms[room.Key].Name = (nameEvent?.TypedContent as RoomNameEventContent)?.Name ?? ""; + if (string.IsNullOrWhiteSpace(AllRooms[room.Key].Name)) { + AllRooms[room.Key].Name = "Loading..."; + tasks.Add(_authService.Homeserver!.GetRoom(room.Key).GetNameOrFallbackAsync().ContinueWith(r => AllRooms[room.Key].Name = r.Result)); + } + } + } + + // await Task.WhenAll(tasks); + + return; + List handledRoomIds = []; - + var spaces = newSync.Rooms?.Join? + .Where(x => x.Value.State?.Events is not null) + .Where(x => x.Value.State!.Events!.Any(y => y.Type == "m.room.create" && (y.TypedContent as RoomCreateEventContent)!.Type == "m.space")) + .ToList(); + Console.WriteLine("spaces: " + spaces.Count); + var nonRootSpaces = spaces + .Where(x => spaces.Any(x => x.Value.State!.Events!.Any(y => y.Type == "m.space.child" && y.StateKey == x.Key))) + .ToDictionary(); + + var rootSpaces = spaces + .Where(x => !nonRootSpaces.ContainsKey(x.Key)) + .ToDictionary(); + // var rootSpaces = spaces + // .Where(x=>!spaces.Any(x=>x.Value.State!.Events!.Any(y=>y.Type == "m.space.child" && y.StateKey == x.Key))) + // .ToList(); + + foreach (var (roomId, room) in rootSpaces) { + var space = new SpaceNode { Name = (room.State!.Events!.First(x => x.Type == "m.room.name")!.TypedContent as RoomNameEventContent).Name }; + DisplayedSpaces.Add(space); + handledRoomIds.Add(roomId); + } } } -public class SpaceNode { +public class SpaceNode : RoomNode { + public ObservableCollection ChildSpaces { get; set; } = []; + public ObservableCollection ChildRooms { get; set; } = []; +} + +public class RoomNode { public string Name { get; set; } - public ObservableCollection Children { get; set; } = []; +} + +// implementation details +public class AllRoomsSpaceNode : SpaceNode { + public AllRoomsSpaceNode(ClientViewModel vm) { + Name = "All rooms"; + vm.AllRooms.CollectionChanged += (_, args) => { + switch (args.Action) { + case NotifyCollectionChangedAction.Add: + case NotifyCollectionChangedAction.Remove: + case NotifyCollectionChangedAction.Replace: { + foreach (var room in args.NewItems?.Cast>() ?? []) ChildRooms.Add(room.Value); + foreach (var room in args.OldItems?.Cast>() ?? []) ChildRooms.Remove(room.Value); + break; + } + + case NotifyCollectionChangedAction.Reset: { + ChildSpaces.Clear(); + ChildRooms.Clear(); + break; + } + } + }; + } } \ No newline at end of file diff --git a/ModerationClient/Views/ClientView.axaml b/ModerationClient/Views/ClientView.axaml index 21ce5d9..0ed8021 100644 --- a/ModerationClient/Views/ClientView.axaml +++ b/ModerationClient/Views/ClientView.axaml @@ -7,24 +7,36 @@ mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="ModerationClient.Views.ClientView" x:DataType="viewModels:ClientViewModel"> - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ModerationClient/Views/ClientView.axaml.cs b/ModerationClient/Views/ClientView.axaml.cs index 1ca5a89..894e807 100644 --- a/ModerationClient/Views/ClientView.axaml.cs +++ b/ModerationClient/Views/ClientView.axaml.cs @@ -1,5 +1,3 @@ -using System; -using System.Linq; using Avalonia.Controls; using Avalonia.Markup.Xaml; @@ -26,8 +24,4 @@ public partial class ClientView : UserControl { // } // }; } - - private void InitializeComponent() { - AvaloniaXamlLoader.Load(this); - } } diff --git a/ModerationClient/Views/LoginView.axaml.cs b/ModerationClient/Views/LoginView.axaml.cs index 2e95e80..5e84ace 100644 --- a/ModerationClient/Views/LoginView.axaml.cs +++ b/ModerationClient/Views/LoginView.axaml.cs @@ -1,33 +1,18 @@ using System; -using Avalonia; using Avalonia.Controls; using Avalonia.Interactivity; using Avalonia.Markup.Xaml; -using Avalonia.VisualTree; -using Microsoft.Extensions.DependencyInjection; -using ModerationClient.Services; using ModerationClient.ViewModels; namespace ModerationClient.Views; public partial class LoginView : UserControl { - private MatrixAuthenticationService AuthService { get; set; } - public LoginView() { InitializeComponent(); } - - private void InitializeComponent() { - Console.WriteLine("LoginWindow loaded"); - - AvaloniaXamlLoader.Load(this); - Console.WriteLine("LoginWindow loaded 2"); - } // ReSharper disable once AsyncVoidMethod - private async void Login(object? sender, RoutedEventArgs e) { - Console.WriteLine("Login????"); - // await AuthService.LoginAsync(Username, Password); - await ((LoginViewModel)DataContext).LoginAsync(); + private async void Login(object? _, RoutedEventArgs __) { + await (DataContext as LoginViewModel ?? throw new InvalidCastException("LoginView did not receive LoginViewModel?")).LoginAsync(); } } diff --git a/ModerationClient/Views/MainWindow.axaml.cs b/ModerationClient/Views/MainWindow.axaml.cs index ccabd71..884e90c 100644 --- a/ModerationClient/Views/MainWindow.axaml.cs +++ b/ModerationClient/Views/MainWindow.axaml.cs @@ -1,10 +1,8 @@ using System; -using System.Threading; using Avalonia; using Avalonia.Controls; using Avalonia.Diagnostics; using Avalonia.Input; -using CommunityToolkit.Mvvm.Input; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using ModerationClient.Services; @@ -13,11 +11,10 @@ using ModerationClient.ViewModels; namespace ModerationClient.Views; public partial class MainWindow : Window { - //viewmodel - private MainWindowViewModel? _viewModel { get; set; } - public MainWindow(CommandLineConfiguration cfg, MainWindowViewModel dataContext, IHostApplicationLifetime appLifetime) { InitializeComponent(); + DataContext = dataContext; + _ = dataContext.AuthService.LoadProfileAsync(); Console.WriteLine("mainwnd"); #if DEBUG this.AttachDevTools(new DevToolsOptions() { @@ -30,19 +27,17 @@ public partial class MainWindow : Window { switch (args.Property.Name) { case nameof(Height): case nameof(Width): { - if (_viewModel is null) { + if (DataContext is not MainWindowViewModel viewModel) { Console.WriteLine("WARN: MainWindowViewModel is null, ignoring height/width change!"); return; } // Console.WriteLine("height/width changed"); - _viewModel.Scale = _viewModel.Scale; + viewModel.Scale = viewModel.Scale; break; } } }; - DataContext = _viewModel = dataContext; - _ = dataContext.AuthService.LoadProfileAsync(); dataContext.AuthService.PropertyChanged += (sender, args) => { if (args.PropertyName == nameof(MatrixAuthenticationService.IsLoggedIn)) { if (dataContext.AuthService.IsLoggedIn) { @@ -68,26 +63,32 @@ public partial class MainWindow : Window { protected override void OnKeyDown(KeyEventArgs e) => OnKeyDown(this, e); private void OnKeyDown(object? _, KeyEventArgs e) { - if (_viewModel is null) { - Console.WriteLine("WARN: MainWindowViewModel is null, ignoring key press!"); + if (DataContext is not MainWindowViewModel viewModel) { + Console.WriteLine($"WARN: DataContext is {DataContext?.GetType().Name ?? "null"}, ignoring key press!"); return; } // Console.WriteLine("MainWindow KeyDown: " + e.Key); if (e.Key == Key.Escape) { - _viewModel.Scale = 1.0f; + viewModel.Scale = 1.0f; } else if (e.Key == Key.F1) { - _viewModel.Scale -= 0.1f; - if (_viewModel.Scale < 0.1f) { - _viewModel.Scale = 0.1f; + viewModel.Scale -= 0.1f; + if (viewModel.Scale < 0.1f) { + viewModel.Scale = 0.1f; } } else if (e.Key == Key.F2) { - _viewModel.Scale += 0.1f; - if (_viewModel.Scale > 5.0f) { - _viewModel.Scale = 5.0f; + viewModel.Scale += 0.1f; + if (viewModel.Scale > 5.0f) { + viewModel.Scale = 5.0f; + } + } + else if (e.Key == Key.K && e.KeyModifiers == KeyModifiers.Control) { + if(viewModel.CurrentViewModel is ClientViewModel clientViewModel) { + Console.WriteLine("QuickSwitcher invoked"); } + else Console.WriteLine("WARN: CurrentViewModel is not ClientViewModel, ignoring Quick Switcher"); } } } \ No newline at end of file -- cgit 1.4.1