diff --git a/.gitignore b/.gitignore index 8d72798..ea8246b 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ obj/ riderModule.iml /_ReSharper.Caches/ release/ -publish/ \ No newline at end of file +publish/ +/.vs \ No newline at end of file diff --git a/Nebula.Launcher/Nebula.Launcher.csproj b/Nebula.Launcher/Nebula.Launcher.csproj index 5f6b17a..82891c5 100644 --- a/Nebula.Launcher/Nebula.Launcher.csproj +++ b/Nebula.Launcher/Nebula.Launcher.csproj @@ -32,6 +32,7 @@ + @@ -63,8 +64,4 @@ - - - - diff --git a/Nebula.Launcher/ServerListProviders/TestServerList.cs b/Nebula.Launcher/ServerListProviders/TestServerList.cs index 5a8e863..a899b66 100644 --- a/Nebula.Launcher/ServerListProviders/TestServerList.cs +++ b/Nebula.Launcher/ServerListProviders/TestServerList.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using Nebula.Launcher.Controls; using Nebula.Launcher.ViewModels; using Nebula.Launcher.ViewModels.Pages; diff --git a/Nebula.Launcher/ViewModels/Pages/ServerOverviewModel.cs b/Nebula.Launcher/ViewModels/Pages/ServerOverviewModel.cs index 4ba302d..c1422bd 100644 --- a/Nebula.Launcher/ViewModels/Pages/ServerOverviewModel.cs +++ b/Nebula.Launcher/ViewModels/Pages/ServerOverviewModel.cs @@ -118,6 +118,14 @@ public sealed class ServerViewContainer private readonly List _favorites = []; private readonly Dictionary _customNames = []; + private readonly Dictionary> _entries = new(); + + public ICollection Items => + _entries.Values + .Select(wr => wr.TryGetTarget(out var target) ? target : null) + .Where(t => t != null) + .ToList()!; + public ServerViewContainer() { _viewHelperService = new ViewHelperService(); @@ -131,108 +139,124 @@ public sealed class ServerViewContainer configurationService.SubscribeVarChanged(LauncherConVar.ServerCustomNames, OnCustomNamesChanged, true); } - private void OnCustomNamesChanged(Dictionary? value) - { - var oldNames = - _customNames.ToDictionary(k => k.Key, v => v.Value); //Clone think - - _customNames.Clear(); - - if(value == null) - { - foreach (var (ip,_) in oldNames) - { - if(!_entries.TryGetValue(ip, out var listEntry) || listEntry is not IEntryNameHolder entryNameHolder) - continue; - - entryNameHolder.Name = null; - } - - return; - } - - foreach (var (oldIp, oldName) in oldNames) - { - if(value.TryGetValue(oldIp, out var newName)) - { - if (oldName == newName) - value.Remove(newName); - - continue; - } - - if(!_entries.TryGetValue(oldIp, out var listEntry) || - listEntry is not IEntryNameHolder entryNameHolder) - continue; - - entryNameHolder.Name = null; - } - - foreach (var (ip, name) in value) - { - _customNames.Add(ip, name); - if(!_entries.TryGetValue(ip, out var listEntry) || listEntry is not IEntryNameHolder entryNameHolder) - continue; - - entryNameHolder.Name = name; - } - } - - private void OnFavoritesChange(string[]? value) - { - _favorites.Clear(); - if(value == null) return; - - foreach (var favorite in value) - { - _favorites.Add(favorite); - if (_entries.TryGetValue(favorite, out var entry) && entry is IFavoriteEntryModelView favoriteView) - { - favoriteView.IsFavorite = true; - } - } - } - - private readonly Dictionary _entries = new(); - - public ICollection Items => _entries.Values; - public void Clear() { - foreach (var (_, value) in _entries) + foreach (var (_, weakRef) in _entries) { - value.Dispose(); + if (weakRef.TryGetTarget(out var value)) + value.Dispose(); } + _entries.Clear(); } public IListEntryModelView Get(RobustUrl url, ServerStatus? serverStatus = null) { + var key = url.ToString(); IListEntryModelView? entry; - + lock (_entries) { - _customNames.TryGetValue(url.ToString(), out var customName); - - if (_entries.TryGetValue(url.ToString(), out entry)) + _customNames.TryGetValue(key, out var customName); + + if (_entries.TryGetValue(key, out var weakEntry) + && weakEntry.TryGetTarget(out entry)) { return entry; } if (serverStatus is not null) - entry = _viewHelperService.GetViewModel().WithData(url, customName, serverStatus); + { + entry = _viewHelperService + .GetViewModel() + .WithData(url, customName, serverStatus); + } else - entry = _viewHelperService.GetViewModel().LoadServerEntry(url, customName, CancellationToken.None); - - if(_favorites.Contains(url.ToString()) && - entry is IFavoriteEntryModelView favoriteEntryModelView) - favoriteEntryModelView.IsFavorite = true; - - _entries.Add(url.ToString(), entry); + { + entry = _viewHelperService + .GetViewModel() + .LoadServerEntry(url, customName, CancellationToken.None); + } + + if (_favorites.Contains(key) + && entry is IFavoriteEntryModelView fav) + { + fav.IsFavorite = true; + } + + _entries[key] = new WeakReference(entry); } - + return entry; } + + private void OnFavoritesChange(string[]? value) + { + _favorites.Clear(); + if (value == null) return; + + foreach (var favorite in value) + { + _favorites.Add(favorite); + if (_entries.TryGetValue(favorite, out var weak) + && weak.TryGetTarget(out var entry) + && entry is IFavoriteEntryModelView fav) + { + fav.IsFavorite = true; + } + } + } + + private void OnCustomNamesChanged(Dictionary? value) + { + var oldNames = _customNames.ToDictionary(x => x.Key, x => x.Value); + _customNames.Clear(); + + if (value == null) + { + foreach (var (ip, _) in oldNames) + { + ResetName(ip); + } + + return; + } + + foreach (var (oldIp, oldName) in oldNames) + { + if (value.TryGetValue(oldIp, out var newName)) + { + if (oldName == newName) + value.Remove(newName); + + continue; + } + + ResetName(oldIp); + } + + foreach (var (ip, name) in value) + { + _customNames.Add(ip, name); + + if (_entries.TryGetValue(ip, out var weak) + && weak.TryGetTarget(out var entry) + && entry is IEntryNameHolder holder) + { + holder.Name = name; + } + } + } + + private void ResetName(string ip) + { + if (_entries.TryGetValue(ip, out var weak) + && weak.TryGetTarget(out var entry) + && entry is IEntryNameHolder holder) + { + holder.Name = null; + } + } } public interface IListEntryModelView : IDisposable diff --git a/Nebula.Launcher/ViewModels/ServerCompoundEntryModelView.cs b/Nebula.Launcher/ViewModels/ServerCompoundEntryModelView.cs index 40b8ca5..459c226 100644 --- a/Nebula.Launcher/ViewModels/ServerCompoundEntryModelView.cs +++ b/Nebula.Launcher/ViewModels/ServerCompoundEntryModelView.cs @@ -1,7 +1,6 @@ using System; using System.Threading; using System.Threading.Tasks; -using Avalonia.Controls; using CommunityToolkit.Mvvm.ComponentModel; using Microsoft.Extensions.DependencyInjection; using Nebula.Launcher.Models; @@ -19,7 +18,7 @@ namespace Nebula.Launcher.ViewModels; public sealed partial class ServerCompoundEntryViewModel : ViewModelBase, IFavoriteEntryModelView, IFilterConsumer, IListEntryModelView, IEntryNameHolder { - [ObservableProperty] private ServerEntryModelView? _currentEntry; + private ServerEntryModelView? _currentEntry; [ObservableProperty] private string _message = "Loading server entry..."; [ObservableProperty] private bool _isFavorite; [ObservableProperty] private bool _loading = true; @@ -28,6 +27,28 @@ public sealed partial class ServerCompoundEntryViewModel : private RobustUrl? _url; private ServerFilter? _currentFilter; + public ServerEntryModelView? CurrentEntry + { + get => _currentEntry; + set + { + if (value == _currentEntry) return; + + _currentEntry = value; + + if (_currentEntry != null) + { + _currentEntry.IsFavorite = IsFavorite; + _currentEntry.Name = Name; + _currentEntry.ProcessFilter(_currentFilter); + } + + Loading = _currentEntry == null; + + OnPropertyChanged(); + } + } + public string? Name { get => _name; @@ -54,31 +75,43 @@ public sealed partial class ServerCompoundEntryViewModel : { } - public ServerCompoundEntryViewModel LoadServerEntry(RobustUrl url,string? name, CancellationToken cancellationToken) + public ServerCompoundEntryViewModel LoadWithEntry(ServerEntryModelView? entry) { - Task.Run(async () => - { - _url = url; - try - { - Message = "Loading server entry..."; - var status = await RestService.GetAsync(_url.StatusUri, cancellationToken); - - CurrentEntry = ServiceProvider.GetService()!.WithData(_url, name, status); - CurrentEntry.IsFavorite = IsFavorite; - CurrentEntry.Loading = false; - CurrentEntry.ProcessFilter(_currentFilter); - Loading = false; - } - catch (Exception e) - { - Message = e.Message; - } - }, cancellationToken); - + CurrentEntry = entry; return this; } + public ServerCompoundEntryViewModel LoadServerEntry(RobustUrl url, string? name, CancellationToken cancellationToken) + { + _url = url; + _name = name; + Task.Run(LoadServer, cancellationToken); + return this; + } + + private async Task LoadServer() + { + if (_url is null) + { + Message = "Url is not set"; + return; + } + + try + { + Message = "Loading server entry..."; + var status = await RestService.GetAsync(_url.StatusUri, CancellationToken.None); + + CurrentEntry = ServiceProvider.GetService()!.WithData(_url, null, status); + + Loading = false; + } + catch (Exception e) + { + Message = "Error while fetching data from " + _url + " : " + e.Message; + } + } + public void ToggleFavorites() { if (CurrentEntry is null && _url is not null) diff --git a/Nebula.Launcher/ViewModels/ServerEntryModelView.cs b/Nebula.Launcher/ViewModels/ServerEntryModelView.cs index c801993..6b822a3 100644 --- a/Nebula.Launcher/ViewModels/ServerEntryModelView.cs +++ b/Nebula.Launcher/ViewModels/ServerEntryModelView.cs @@ -28,8 +28,6 @@ public sealed partial class ServerEntryModelView : ViewModelBase, IFilterConsume [ObservableProperty] private bool _isFavorite; [ObservableProperty] private bool _isVisible; [ObservableProperty] private bool _runVisible = true; - [ObservableProperty] private bool _tagDataVisible; - [ObservableProperty] private bool _loading; [ObservableProperty] private string _realName; public string? Name @@ -131,7 +129,7 @@ public sealed partial class ServerEntryModelView : ViewModelBase, IFilterConsume OnPropertyChanged(nameof(Status)); } - public ServerEntryModelView WithData(RobustUrl url, string? name,ServerStatus serverStatus) + public ServerEntryModelView WithData(RobustUrl url, string? name, ServerStatus serverStatus) { Address = url; SetStatus(serverStatus); diff --git a/Nebula.Launcher/Views/ServerCompoundEntryView.axaml b/Nebula.Launcher/Views/ServerCompoundEntryView.axaml index a9b1122..caacfcb 100644 --- a/Nebula.Launcher/Views/ServerCompoundEntryView.axaml +++ b/Nebula.Launcher/Views/ServerCompoundEntryView.axaml @@ -70,9 +70,9 @@ - - - + diff --git a/Nebula.Launcher/Views/ServerListView.axaml b/Nebula.Launcher/Views/ServerListView.axaml index 6c73c6a..88f5690 100644 --- a/Nebula.Launcher/Views/ServerListView.axaml +++ b/Nebula.Launcher/Views/ServerListView.axaml @@ -2,7 +2,6 @@ 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:viewModels="clr-namespace:Nebula.Launcher.Controls" xmlns:services="clr-namespace:Nebula.Launcher.Services" xmlns:viewModels1="clr-namespace:Nebula.Launcher.ViewModels" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" diff --git a/Nebula.SourceGenerators/ViewConstructGenerator.cs b/Nebula.SourceGenerators/ViewConstructGenerator.cs index 9fb160e..9bc2681 100644 --- a/Nebula.SourceGenerators/ViewConstructGenerator.cs +++ b/Nebula.SourceGenerators/ViewConstructGenerator.cs @@ -64,18 +64,18 @@ namespace {viewNamespace} }}"; // Add the source code to the compilation. - context.AddSource($"{viewName}_viewConstructAuto.g.cs", SourceText.From(code, Encoding.UTF8)); + context.AddSource($"{viewModelName}_{viewName}_viewConstructAuto.g.cs", SourceText.From(code, Encoding.UTF8)); } catch (Exception e) { var coder1 = $@" // -// Error! +// Error! {e.Message} namespace {viewModelNamespace} {{ public partial class {viewModelName} {{ - // {e.Message} + // ERROR: {e.Message} }} }}"; @@ -84,6 +84,4 @@ namespace {viewModelNamespace} } } } - - } \ No newline at end of file diff --git a/Nebula.sln.DotSettings.user b/Nebula.sln.DotSettings.user index 45a2645..4ededbf 100644 --- a/Nebula.sln.DotSettings.user +++ b/Nebula.sln.DotSettings.user @@ -2,6 +2,7 @@ ForceIncluded ForceIncluded ForceIncluded + ForceIncluded ForceIncluded ForceIncluded ForceIncluded