diff --git a/.idea/.idea.Nebula/.idea/avalonia.xml b/.idea/.idea.Nebula/.idea/avalonia.xml
index 50bc6a6..5a43723 100644
--- a/.idea/.idea.Nebula/.idea/avalonia.xml
+++ b/.idea/.idea.Nebula/.idea/avalonia.xml
@@ -28,6 +28,8 @@
+
+
diff --git a/Nebula.Launcher/Assets/svg/pencil.svg b/Nebula.Launcher/Assets/svg/pencil.svg
new file mode 100644
index 0000000..b59ab45
--- /dev/null
+++ b/Nebula.Launcher/Assets/svg/pencil.svg
@@ -0,0 +1,7 @@
+
+
diff --git a/Nebula.Launcher/LauncherConVar.cs b/Nebula.Launcher/LauncherConVar.cs
index d4b1ae7..a14ac80 100644
--- a/Nebula.Launcher/LauncherConVar.cs
+++ b/Nebula.Launcher/LauncherConVar.cs
@@ -18,7 +18,11 @@ public static class LauncherConVar
public static readonly ConVar Favorites =
ConVarBuilder.Build("server.favorites", []);
- public static readonly ConVar AuthServers = ConVarBuilder.Build("launcher.authServers", [
+ public static readonly ConVar> ServerCustomNames =
+ ConVarBuilder.Build>("server.names", []);
+
+ public static readonly ConVar AuthServers =
+ ConVarBuilder.Build("launcher.authServers", [
new AuthServerCredentials(
"WizDen",
[
diff --git a/Nebula.Launcher/ViewModels/Pages/ServerOverviewModel.cs b/Nebula.Launcher/ViewModels/Pages/ServerOverviewModel.cs
index e006757..75de996 100644
--- a/Nebula.Launcher/ViewModels/Pages/ServerOverviewModel.cs
+++ b/Nebula.Launcher/ViewModels/Pages/ServerOverviewModel.cs
@@ -4,6 +4,7 @@ using System.Collections.ObjectModel;
using System.Linq;
using System.Threading;
using CommunityToolkit.Mvvm.ComponentModel;
+using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection;
using Nebula.Launcher.Controls;
using Nebula.Launcher.Models;
@@ -24,24 +25,18 @@ public partial class ServerOverviewModel : ViewModelBase
[ObservableProperty] private bool _isFilterVisible;
- [ObservableProperty] private ServerListView _currentServerList = new ServerListView();
+ [ObservableProperty] private ServerListView _currentServerList = new();
- public readonly ServerFilter CurrentFilter = new ServerFilter();
+ public readonly ServerFilter CurrentFilter = new();
public Action? OnSearchChange;
-
- [GenerateProperty] private PopupMessageService PopupMessageService { get; }
- [GenerateProperty] private CancellationService CancellationService { get; }
- [GenerateProperty] private DebugService DebugService { get; }
[GenerateProperty] private IServiceProvider ServiceProvider { get; }
[GenerateProperty] private ConfigurationService ConfigurationService { get; }
[GenerateProperty] private FavoriteServerListProvider FavoriteServerListProvider { get; }
- [GenerateProperty, DesignConstruct] private ViewHelperService ViewHelperService { get; }
-
public ObservableCollection Items { get; private set; }
[ObservableProperty] private ServerListTabTemplate _selectedItem;
- [GenerateProperty, DesignConstruct] private ServerViewContainer ServerViewContainer { get; set; }
+ [GenerateProperty, DesignConstruct] private ServerViewContainer ServerViewContainer { get; }
private Dictionary _viewCache = [];
@@ -126,6 +121,7 @@ public partial class ServerOverviewModel : ViewModelBase
}
CurrentServerList = view;
+ ApplyFilter();
}
}
@@ -134,25 +130,77 @@ public partial class ServerOverviewModel : ViewModelBase
public class ServerViewContainer
{
private readonly ViewHelperService _viewHelperService;
- private List favorites = [];
+ private readonly List _favorites = [];
+ private readonly Dictionary _customNames = [];
public ServerViewContainer()
{
_viewHelperService = new ViewHelperService();
}
+ [UsedImplicitly]
public ServerViewContainer(ViewHelperService viewHelperService, ConfigurationService configurationService)
{
_viewHelperService = viewHelperService;
configurationService.SubscribeVarChanged(LauncherConVar.Favorites, OnFavoritesChange, true);
+ 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 = new List(value ?? []);
+ _favorites.Clear();
+ if(value == null) return;
- foreach (var favorite in favorites)
+ foreach (var favorite in value)
{
+ _favorites.Add(favorite);
if (_entries.TryGetValue(favorite, out var entry) && entry is IFavoriteEntryModelView favoriteView)
{
favoriteView.IsFavorite = true;
@@ -175,17 +223,20 @@ public class ServerViewContainer
lock (_entries)
{
+ _customNames.TryGetValue(url.ToString(), out var customName);
+
if (_entries.TryGetValue(url.ToString(), out entry))
{
return entry;
}
if (serverStatus is not null)
- entry = _viewHelperService.GetViewModel().WithData(url, serverStatus);
+ entry = _viewHelperService.GetViewModel().WithData(url, customName, serverStatus);
else
- entry = _viewHelperService.GetViewModel().LoadServerEntry(url, CancellationToken.None);
+ entry = _viewHelperService.GetViewModel().LoadServerEntry(url, customName, CancellationToken.None);
- if(favorites.Contains(url.ToString()) && entry is IFavoriteEntryModelView favoriteEntryModelView)
+ if(_favorites.Contains(url.ToString()) &&
+ entry is IFavoriteEntryModelView favoriteEntryModelView)
favoriteEntryModelView.IsFavorite = true;
_entries.Add(url.ToString(), entry);
@@ -205,6 +256,11 @@ public interface IFavoriteEntryModelView
public bool IsFavorite { get; set; }
}
+public interface IEntryNameHolder
+{
+ public string? Name { get; set; }
+}
+
public class ServerComparer : IComparer, IComparer, IComparer<(RobustUrl,ServerStatus)>
{
public int Compare(ServerHubInfo? x, ServerHubInfo? y)
@@ -262,4 +318,6 @@ public sealed class ServerFilter
{
return IsMatchByName(name) && IsMatchByTags(itemTags);
}
-}
\ No newline at end of file
+}
+
+public sealed record ServerCustomNameEntry(string Url, string Name);
\ No newline at end of file
diff --git a/Nebula.Launcher/ViewModels/Popup/EditServerNameViewModel.cs b/Nebula.Launcher/ViewModels/Popup/EditServerNameViewModel.cs
new file mode 100644
index 0000000..6a54204
--- /dev/null
+++ b/Nebula.Launcher/ViewModels/Popup/EditServerNameViewModel.cs
@@ -0,0 +1,56 @@
+using CommunityToolkit.Mvvm.ComponentModel;
+using Nebula.Launcher.Views.Popup;
+using Nebula.Shared.Services;
+
+namespace Nebula.Launcher.ViewModels.Popup;
+
+[ViewModelRegister(typeof(EditServerNameView), false)]
+[ConstructGenerator]
+public sealed partial class EditServerNameViewModel : PopupViewModelBase
+{
+ [GenerateProperty] public override PopupMessageService PopupMessageService { get; }
+ [GenerateProperty] public ConfigurationService ConfigurationService { get; }
+ public override string Title => "Edit server name";
+ public override bool IsClosable => true;
+
+ [ObservableProperty] private string _ipInput;
+ [ObservableProperty] private string _nameInput;
+
+ public void OnEnter()
+ {
+ if(string.IsNullOrWhiteSpace(IpInput))
+ return;
+
+ if (string.IsNullOrWhiteSpace(NameInput))
+ {
+ RemoveServerName();
+ Dispose();
+ return;
+ }
+
+ AddServerName();
+ Dispose();
+ }
+
+ private void AddServerName()
+ {
+ var currentNames = ConfigurationService.GetConfigValue(LauncherConVar.ServerCustomNames)!;
+ currentNames.Add(IpInput, NameInput);
+ ConfigurationService.SetConfigValue(LauncherConVar.ServerCustomNames, currentNames);
+ }
+
+ private void RemoveServerName()
+ {
+ var currentNames = ConfigurationService.GetConfigValue(LauncherConVar.ServerCustomNames)!;
+ currentNames.Remove(IpInput);
+ ConfigurationService.SetConfigValue(LauncherConVar.ServerCustomNames, currentNames);
+ }
+
+ protected override void InitialiseInDesignMode()
+ {
+ }
+
+ protected override void Initialise()
+ {
+ }
+}
\ No newline at end of file
diff --git a/Nebula.Launcher/ViewModels/ServerCompoundEntryModelView.cs b/Nebula.Launcher/ViewModels/ServerCompoundEntryModelView.cs
index eb47a6f..c15c938 100644
--- a/Nebula.Launcher/ViewModels/ServerCompoundEntryModelView.cs
+++ b/Nebula.Launcher/ViewModels/ServerCompoundEntryModelView.cs
@@ -18,51 +18,59 @@ namespace Nebula.Launcher.ViewModels;
[ViewModelRegister(typeof(ServerCompoundEntryView), false)]
[ConstructGenerator]
public sealed partial class ServerCompoundEntryViewModel :
- ViewModelBase, IFavoriteEntryModelView, IFilterConsumer, IListEntryModelView
+ ViewModelBase, IFavoriteEntryModelView, IFilterConsumer, IListEntryModelView, IEntryNameHolder
{
- [ObservableProperty] private ServerEntryModelView _currentEntry;
+ [ObservableProperty] private ServerEntryModelView? _currentEntry;
[ObservableProperty] private Control? _entryControl;
- [ObservableProperty] private string _name = "Loading...";
+ [ObservableProperty] private string _message = "Loading server entry...";
[ObservableProperty] private bool _isFavorite;
[ObservableProperty] private bool _loading = true;
+ private string? _name;
+
+ public string? Name
+ {
+ get => _name;
+ set
+ {
+ _name = value;
+ OnPropertyChanged();
+
+ if (CurrentEntry != null)
+ CurrentEntry.Name = value;
+ }
+ }
+
[GenerateProperty] private RestService RestService { get; }
[GenerateProperty] private IServiceProvider ServiceProvider{ get; }
[GenerateProperty] private FavoriteServerListProvider FavoriteServerListProvider { get; }
- private RobustUrl? _url;
-
-
protected override void InitialiseInDesignMode()
{
+ Name = "TEST.TEST";
}
protected override void Initialise()
{
}
- public ServerCompoundEntryViewModel LoadServerEntry(RobustUrl url, CancellationToken cancellationToken)
+ public ServerCompoundEntryViewModel LoadServerEntry(RobustUrl url,string? name, CancellationToken cancellationToken)
{
Task.Run(async () =>
{
try
{
- _url = url;
- Name = $"Loading {url}...";
+ Message = "Loading server entry...";
var status = await RestService.GetAsync(url.StatusUri, cancellationToken);
- await Dispatcher.UIThread.InvokeAsync(() =>
- {
- CurrentEntry = ServiceProvider.GetService()!.WithData(url, status);
- CurrentEntry.IsFavorite = IsFavorite;
- CurrentEntry.Loading = false;
- Loading = false;
- });
+ CurrentEntry = ServiceProvider.GetService()!.WithData(url,name, status);
+ CurrentEntry.IsFavorite = IsFavorite;
+ CurrentEntry.Loading = false;
+ Loading = false;
}
catch (Exception e)
{
- var error = new Exception("Unable to load server entry", e);
- Name = e.Message;
+ Message = e.Message;
}
}, cancellationToken);
@@ -71,13 +79,7 @@ public sealed partial class ServerCompoundEntryViewModel :
public void ToggleFavorites()
{
- if (_url == null)
- return;
- IsFavorite = !IsFavorite;
- if(IsFavorite)
- FavoriteServerListProvider.AddFavorite(_url);
- else
- FavoriteServerListProvider.RemoveFavorite(_url);
+ CurrentEntry?.ToggleFavorites();
}
diff --git a/Nebula.Launcher/ViewModels/ServerEntryModelView.cs b/Nebula.Launcher/ViewModels/ServerEntryModelView.cs
index 31327d9..2d59854 100644
--- a/Nebula.Launcher/ViewModels/ServerEntryModelView.cs
+++ b/Nebula.Launcher/ViewModels/ServerEntryModelView.cs
@@ -21,7 +21,7 @@ namespace Nebula.Launcher.ViewModels;
[ViewModelRegister(typeof(ServerEntryView), false)]
[ConstructGenerator]
-public partial class ServerEntryModelView : ViewModelBase, IFilterConsumer, IListEntryModelView, IFavoriteEntryModelView
+public partial class ServerEntryModelView : ViewModelBase, IFilterConsumer, IListEntryModelView, IFavoriteEntryModelView, IEntryNameHolder
{
[ObservableProperty] private string _description = "Fetching info...";
[ObservableProperty] private bool _expandInfo;
@@ -30,6 +30,13 @@ public partial class ServerEntryModelView : ViewModelBase, IFilterConsumer, ILis
[ObservableProperty] private bool _runVisible = true;
[ObservableProperty] private bool _tagDataVisible;
[ObservableProperty] private bool _loading;
+ [ObservableProperty] private string _realName;
+
+ public string? Name
+ {
+ get => RealName;
+ set => RealName = value ?? Status.Name;
+ }
private ILogger _logger;
private ServerInfo? _serverInfo;
@@ -83,6 +90,8 @@ public partial class ServerEntryModelView : ViewModelBase, IFilterConsumer, ILis
protected override void InitialiseInDesignMode()
{
+ IsVisible = true;
+ RealName = "TEST.TEST";
Description = "Server of meow girls! Nya~ \nNyaMeow\nOOOINK!!";
Links.Add(new ServerLink("Discord", "discord", "https://cinka.ru"));
Status = new ServerStatus("Ameba",
@@ -119,14 +128,22 @@ public partial class ServerEntryModelView : ViewModelBase, IFilterConsumer, ILis
OnPropertyChanged(nameof(Status));
}
-
- public ServerEntryModelView WithData(RobustUrl url, ServerStatus serverStatus)
+ public ServerEntryModelView WithData(RobustUrl url, string? name,ServerStatus serverStatus)
{
Address = url;
SetStatus(serverStatus);
+ Name = name;
return this;
}
+ public void EditName()
+ {
+ var popup = ViewHelperService.GetViewModel();
+ popup.IpInput = Address.ToString();
+ popup.NameInput = Name ?? string.Empty;
+ PopupMessageService.Popup(popup);
+ }
+
public void OpenContentViewer()
{
MainViewModel.RequirePage().Go(Address, ContentPath.Empty);
diff --git a/Nebula.Launcher/Views/Popup/EditServerNameView.axaml b/Nebula.Launcher/Views/Popup/EditServerNameView.axaml
new file mode 100644
index 0000000..36d5cda
--- /dev/null
+++ b/Nebula.Launcher/Views/Popup/EditServerNameView.axaml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Nebula.Launcher/Views/Popup/EditServerNameView.axaml.cs b/Nebula.Launcher/Views/Popup/EditServerNameView.axaml.cs
new file mode 100644
index 0000000..a95b06a
--- /dev/null
+++ b/Nebula.Launcher/Views/Popup/EditServerNameView.axaml.cs
@@ -0,0 +1,20 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+using Nebula.Launcher.ViewModels.Popup;
+
+namespace Nebula.Launcher.Views.Popup;
+
+public partial class EditServerNameView : UserControl
+{
+ public EditServerNameView()
+ {
+ InitializeComponent();
+ }
+
+ public EditServerNameView(EditServerNameViewModel viewModel)
+ : this()
+ {
+ DataContext = viewModel;
+ }
+}
\ No newline at end of file
diff --git a/Nebula.Launcher/Views/ServerCompoundEntryView.axaml b/Nebula.Launcher/Views/ServerCompoundEntryView.axaml
index 95f9220..a9b1122 100644
--- a/Nebula.Launcher/Views/ServerCompoundEntryView.axaml
+++ b/Nebula.Launcher/Views/ServerCompoundEntryView.axaml
@@ -36,9 +36,14 @@
Margin="10,0,0,0"
VerticalScrollBarVisibility="Disabled"
x:Name="AutoScrollViewer">
-
+
+
+
+
-
+
@@ -67,9 +67,19 @@
-
+
+
+
+