diff --git a/Nebula.Launcher/Assets/AppResources.axaml b/Nebula.Launcher/Assets/AppResources.axaml index efab005..6d454d1 100644 --- a/Nebula.Launcher/Assets/AppResources.axaml +++ b/Nebula.Launcher/Assets/AppResources.axaml @@ -2,4 +2,5 @@ #222222 #121212 #D95F59 + 0 0 10 -1 #121212 diff --git a/Nebula.Launcher/ViewModels/Pages/ServerListViewModel.Favorite.cs b/Nebula.Launcher/ViewModels/Pages/ServerListViewModel.Favorite.cs new file mode 100644 index 0000000..e1f5394 --- /dev/null +++ b/Nebula.Launcher/ViewModels/Pages/ServerListViewModel.Favorite.cs @@ -0,0 +1,79 @@ +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Threading; +using CommunityToolkit.Mvvm.ComponentModel; +using Nebula.Shared; +using Nebula.Shared.Models; +using Nebula.Shared.Services; +using Nebula.Shared.Utils; + +namespace Nebula.Launcher.ViewModels.Pages; + +public partial class ServerListViewModel +{ + [GenerateProperty] private ConfigurationService ConfigurationService { get; } + [GenerateProperty] private RestService RestService { get; } + + [ObservableProperty] private bool _favoriteVisible = false; + + public List<(RobustUrl,ServerStatus)> FavoriteServers = new(); + public ObservableCollection SortedFavoriteServers { get; } = new(); + + private void SortFavorite() + { + SortedFavoriteServers.Clear(); + FavoriteServers.Sort(new ServerComparer()); + foreach (var server in FavoriteServers.Where(a => CheckServerThink(a.Item2))) + SortedFavoriteServers.Add(GetServerEntryModelView(server)); + } + + private ServerEntryModelView GetServerEntryModelView((RobustUrl, ServerStatus) server) + { + var model = ViewHelperService.GetViewModel().WithData(server.Item1, server.Item2); + model.OnFavoriteToggle += ()=> RemoveFavorite(model); + return model; + } + + private async void FetchFavorite() + { + FavoriteServers.Clear(); + + var servers = ConfigurationService.GetConfigValue(CurrentConVar.Favorites); + if (servers is null || servers.Length == 0) + { + FavoriteVisible = false; + return; + } + + FavoriteVisible = true; + + foreach (var server in servers) + { + var uri = server.ToRobustUrl(); + var serverInfo = await RestService.GetAsync(uri.StatusUri, CancellationToken.None); + if (serverInfo.Value is null) + { + continue; + } + + FavoriteServers.Add((uri, serverInfo.Value)); + } + + SortFavorite(); + } + + public void AddFavorite(ServerEntryModelView entryModelView) + { + var servers = (ConfigurationService.GetConfigValue(CurrentConVar.Favorites) ?? []).ToList(); + servers.Add(entryModelView.Address.ToString()); + ConfigurationService.SetConfigValue(CurrentConVar.Favorites, servers.ToArray()); + } + + public void RemoveFavorite(ServerEntryModelView entryModelView) + { + var servers = (ConfigurationService.GetConfigValue(CurrentConVar.Favorites) ?? []).ToList(); + servers.Remove(entryModelView.Address.ToString()); + ConfigurationService.SetConfigValue(CurrentConVar.Favorites, servers.ToArray()); + } +} \ No newline at end of file diff --git a/Nebula.Launcher/ViewModels/Pages/ServerListViewModel.cs b/Nebula.Launcher/ViewModels/Pages/ServerListViewModel.cs index 1b635e8..831b6a6 100644 --- a/Nebula.Launcher/ViewModels/Pages/ServerListViewModel.cs +++ b/Nebula.Launcher/ViewModels/Pages/ServerListViewModel.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; @@ -8,6 +9,7 @@ using Nebula.Launcher.Services; using Nebula.Launcher.Views.Pages; using Nebula.Shared.Models; using Nebula.Shared.Services; +using Nebula.Shared.Utils; namespace Nebula.Launcher.ViewModels.Pages; @@ -26,6 +28,9 @@ public partial class ServerListViewModel : ViewModelBase //Design think protected override void InitialiseInDesignMode() { + FavoriteVisible = true; + SortedFavoriteServers.Add(GetServerEntryModelView(("ss14://localhost".ToRobustUrl(), + new ServerStatus("Nebula", "TestCraft", ["16+", "RU"], "super", 12, 55, 1, false, DateTime.Now, 20)))); ServerInfos.Add(CreateServerView(new ServerHubInfo("ss14://localhost", new ServerStatus("Nebula", "TestCraft", ["16+", "RU"], "super", 12, 55, 1, false, DateTime.Now, 20), []))); ServerInfos.Add(CreateServerView(new ServerHubInfo("ss14://localhost", @@ -44,12 +49,14 @@ public partial class ServerListViewModel : ViewModelBase OnSearchChange += OnChangeSearch; if (!HubService.IsUpdating) SortServers(); + FetchFavorite(); } private void OnChangeSearch() { if(string.IsNullOrEmpty(SearchText)) return; SortServers(); + SortFavorite(); } private void HubServerChangedEventArgs(HubServerChangedEventArgs obj) @@ -69,20 +76,20 @@ public partial class ServerListViewModel : ViewModelBase { ServerInfos.Clear(); UnsortedServers.Sort(new ServerComparer()); - foreach (var server in UnsortedServers.Where(CheckServerThink)) ServerInfos.Add(CreateServerView(server)); + foreach (var server in UnsortedServers.Where(a => CheckServerThink(a.StatusData))) ServerInfos.Add(CreateServerView(server)); }); } - private bool CheckServerThink(ServerHubInfo hubInfo) + private bool CheckServerThink(ServerStatus hubInfo) { if (string.IsNullOrEmpty(SearchText)) return true; - return hubInfo.StatusData.Name.ToLower().Contains(SearchText.ToLower()); + return hubInfo.Name.ToLower().Contains(SearchText.ToLower()); } private ServerEntryModelView CreateServerView(ServerHubInfo serverHubInfo) { - var svn = ViewHelperService.GetViewModel(); - svn.ServerHubInfo = serverHubInfo; + var svn = ViewHelperService.GetViewModel().WithData(serverHubInfo); + svn.OnFavoriteToggle += () => AddFavorite(svn); return svn; } @@ -96,7 +103,7 @@ public partial class ServerListViewModel : ViewModelBase } } -public class ServerComparer : IComparer +public class ServerComparer : IComparer, IComparer, IComparer<(RobustUrl,ServerStatus)> { public int Compare(ServerHubInfo? x, ServerHubInfo? y) { @@ -107,6 +114,30 @@ public class ServerComparer : IComparer if (ReferenceEquals(null, x)) return -1; - return y.StatusData.Players.CompareTo(x.StatusData.Players); + return Compare(x.StatusData, y.StatusData); + } + + public int Compare(ServerStatus? x, ServerStatus? y) + { + if (ReferenceEquals(x, y)) + return 0; + if (ReferenceEquals(null, y)) + return 1; + if (ReferenceEquals(null, x)) + return -1; + + return y.Players.CompareTo(x.Players); + } + + public int Compare((RobustUrl, ServerStatus) x, (RobustUrl, ServerStatus) y) + { + if (ReferenceEquals(x, y)) + return 0; + if (ReferenceEquals(null, y)) + return 1; + if (ReferenceEquals(null, x)) + return -1; + + return Compare(x.Item2, y.Item2); } } \ No newline at end of file diff --git a/Nebula.Launcher/ViewModels/ServerEntryModelView.cs b/Nebula.Launcher/ViewModels/ServerEntryModelView.cs index 9f4eb93..100977e 100644 --- a/Nebula.Launcher/ViewModels/ServerEntryModelView.cs +++ b/Nebula.Launcher/ViewModels/ServerEntryModelView.cs @@ -1,18 +1,13 @@ using System; -using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.IO; -using System.Linq; using System.Text; using System.Text.RegularExpressions; -using System.Threading; using System.Threading.Tasks; using System.Windows.Input; -using Avalonia; using Avalonia.Media; using CommunityToolkit.Mvvm.ComponentModel; -using CommunityToolkit.Mvvm.Input; using Nebula.Launcher.Services; using Nebula.Launcher.ViewModels.Popup; using Nebula.Launcher.Views; @@ -27,8 +22,9 @@ namespace Nebula.Launcher.ViewModels; public partial class ServerEntryModelView : ViewModelBase { private Process? _p; - - + public RobustUrl Address { get; private set; } + public Action? OnFavoriteToggle; + public LogPopupModelView CurrLog; [GenerateProperty] private AuthService AuthService { get; } = default!; [GenerateProperty] private ContentService ContentService { get; } = default!; @@ -40,8 +36,13 @@ public partial class ServerEntryModelView : ViewModelBase [GenerateProperty] private RestService RestService { get; } = default!; [ObservableProperty] private string _description = "Fetching info..."; - public ObservableCollection Links { get; } = new(); [ObservableProperty] private bool _expandInfo = false; + [ObservableProperty] private bool _tagDataVisible = false; + + public ServerStatus Status { get; set; } = + new("", "", [], "", -1, -1, -1, false, DateTime.Now, -1); + + public ObservableCollection Links { get; } = new(); public bool RunVisible => Process == null; private ServerInfo? _serverInfo = null; @@ -51,7 +52,7 @@ public partial class ServerEntryModelView : ViewModelBase if (_serverInfo == null) { var result = - await RestService.GetAsync(ServerHubInfo.Address.ToRobustUrl().InfoUri, CancellationService.Token); + await RestService.GetAsync(Address.InfoUri, CancellationService.Token); if (result.Value == null) return null; _serverInfo = result.Value; } @@ -59,27 +60,6 @@ public partial class ServerEntryModelView : ViewModelBase return _serverInfo; } - private ServerHubInfo _serverHubInfo = default!; - public ServerHubInfo ServerHubInfo - { - get => _serverHubInfo; - set - { - Tags.Clear(); - foreach (var tag in value.StatusData.Tags) - { - Tags.Add(tag); - } - foreach (var tag in value.InferredTags) - { - Tags.Add(tag); - } - - _serverHubInfo = value; - OnPropertyChanged(nameof(ServerHubInfo)); - } - } - public ObservableCollection Tags { get; } = []; public ICommand OnLinkGo { get; }= new LinkGoCommand(); @@ -98,13 +78,12 @@ public partial class ServerEntryModelView : ViewModelBase { Description = "Server of meow girls! Nya~ \nNyaMeow\nOOOINK!!"; Links.Add(new ServerLink("Discord","discord","https://cinka.ru")); - ServerHubInfo = new ServerHubInfo("ss14://localhost", - new ServerStatus("Ameba", - "Locala meow meow meow meow meow meow meow meow meow meow meow meow meow meow meow meow meow meow meow meow meow meow meow meow meow meow meow meow meow meow meow meow meow meow meow meow ", - ["rp:hrp", "18+"], - "Antag", 15, 5, 1, false - , DateTime.Now, 100), - ["meow:rp"]); + Status = new ServerStatus("Ameba", + "Locala meow meow meow meow meow meow meow meow meow meow meow meow meow meow meow meow meow meow meow meow meow meow meow meow meow meow meow meow meow meow meow meow meow meow meow meow ", + ["rp:hrp", "18+"], + "Antag", 15, 5, 1, false + , DateTime.Now, 100); + Address = "ss14://localhost".ToRobustUrl(); } protected override void Initialise() @@ -112,6 +91,41 @@ public partial class ServerEntryModelView : ViewModelBase CurrLog = ViewHelperService.GetViewModel(); } + public ServerEntryModelView WithData(ServerHubInfo value) + { + Status = value.StatusData; + Address = value.Address.ToRobustUrl(); + Tags.Clear(); + foreach (var tag in Status.Tags) + { + Tags.Add(tag); + } + foreach (var tag in value.InferredTags) + { + Tags.Add(tag); + } + + return this; + } + + public ServerEntryModelView WithData(RobustUrl url, ServerStatus serverStatus) + { + Status = serverStatus; + Address = url; + Tags.Clear(); + foreach (var tag in Status.Tags) + { + Tags.Add(tag); + } + + return this; + } + + public void ToggleFavorites() + { + OnFavoriteToggle?.Invoke(); + } + public void RunInstance() { Task.Run(RunAsync); @@ -124,7 +138,7 @@ public partial class ServerEntryModelView : ViewModelBase var authProv = AuthService.SelectedAuth; var buildInfo = - await ContentService.GetBuildInfo(new RobustUrl(ServerHubInfo.Address), CancellationService.Token); + await ContentService.GetBuildInfo(Address, CancellationService.Token); using (var loadingContext = ViewHelperService.GetViewModel()) { @@ -145,7 +159,7 @@ public partial class ServerEntryModelView : ViewModelBase { "ROBUST_AUTH_TOKEN", authProv?.Token.Token }, { "ROBUST_AUTH_SERVER", authProv?.AuthLoginPassword.AuthServer }, { "ROBUST_AUTH_PUBKEY", buildInfo.BuildInfo.Auth.PublicKey }, - { "GAME_URL", ServerHubInfo.Address }, + { "GAME_URL", Address.ToString() }, { "AUTH_LOGIN", authProv?.AuthLoginPassword.Login } }, CreateNoWindow = true, diff --git a/Nebula.Launcher/Views/MainView.axaml b/Nebula.Launcher/Views/MainView.axaml index 2e9143d..f5dea88 100644 --- a/Nebula.Launcher/Views/MainView.axaml +++ b/Nebula.Launcher/Views/MainView.axaml @@ -1,5 +1,5 @@ - prototype-product-v0.01 + v0.02-a @@ -118,7 +118,7 @@ @@ -141,7 +141,7 @@ diff --git a/Nebula.Launcher/Views/Pages/AccountInfoView.axaml b/Nebula.Launcher/Views/Pages/AccountInfoView.axaml index fa56b9d..dd3933b 100644 --- a/Nebula.Launcher/Views/Pages/AccountInfoView.axaml +++ b/Nebula.Launcher/Views/Pages/AccountInfoView.axaml @@ -13,12 +13,13 @@ @@ -32,7 +33,8 @@ @@ -74,7 +76,8 @@ Grid.ColumnSpan="{Binding AuthViewSpan}" Grid.Row="0"> @@ -109,7 +112,7 @@ @@ -129,7 +132,7 @@ - + - + diff --git a/Nebula.Launcher/Views/Pages/FavoriteServerListView.axaml b/Nebula.Launcher/Views/Pages/FavoriteServerListView.axaml deleted file mode 100644 index 8150a62..0000000 --- a/Nebula.Launcher/Views/Pages/FavoriteServerListView.axaml +++ /dev/null @@ -1,11 +0,0 @@ - - Welcome to Avalonia! - \ No newline at end of file diff --git a/Nebula.Launcher/Views/Pages/FavoriteServerListView.axaml.cs b/Nebula.Launcher/Views/Pages/FavoriteServerListView.axaml.cs deleted file mode 100644 index b878607..0000000 --- a/Nebula.Launcher/Views/Pages/FavoriteServerListView.axaml.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Avalonia.Controls; - -namespace Nebula.Launcher.Views.Pages; - -public partial class FavoriteServerListView : UserControl -{ - public FavoriteServerListView() - { - InitializeComponent(); - } -} \ No newline at end of file diff --git a/Nebula.Launcher/Views/Pages/ServerListView.axaml b/Nebula.Launcher/Views/Pages/ServerListView.axaml index 729e163..e0c9b74 100644 --- a/Nebula.Launcher/Views/Pages/ServerListView.axaml +++ b/Nebula.Launcher/Views/Pages/ServerListView.axaml @@ -22,7 +22,24 @@ Grid.RowSpan="2" Margin="0,0,0,10" Padding="0,0,10,0"> - + + + + + + + + + @@ -46,7 +46,7 @@ VerticalScrollBarVisibility="Disabled" x:Name="AutoScrollViewer"> @@ -58,15 +58,14 @@ Orientation="Horizontal" VerticalAlignment="Center"> - @@ -167,7 +166,7 @@ Margin="5" VerticalAlignment="Center"> diff --git a/Nebula.Shared/CurrentConVar.cs b/Nebula.Shared/CurrentConVar.cs index d3d30cb..5f06b2c 100644 --- a/Nebula.Shared/CurrentConVar.cs +++ b/Nebula.Shared/CurrentConVar.cs @@ -29,4 +29,7 @@ public static class CurrentConVar public static readonly ConVar AuthCurrent = ConVarBuilder.Build("auth.current"); + + public static readonly ConVar Favorites = + ConVarBuilder.Build("server.favorites", []); } \ No newline at end of file