Files
NebulaLauncher/Nebula.Launcher/ViewModels/Pages/ServerOverviewModel.cs

323 lines
9.4 KiB
C#
Raw Normal View History

2024-12-21 15:15:04 +03:00
using System;
2024-12-26 09:49:01 +03:00
using System.Collections.Generic;
2024-12-22 16:38:47 +03:00
using System.Collections.ObjectModel;
2024-12-27 08:22:17 +03:00
using System.Linq;
2025-06-22 10:40:42 +03:00
using System.Threading;
2024-12-22 16:38:47 +03:00
using CommunityToolkit.Mvvm.ComponentModel;
2025-06-22 22:11:27 +03:00
using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection;
using Nebula.Launcher.Controls;
using Nebula.Launcher.Models;
using Nebula.Launcher.ServerListProviders;
2025-01-14 22:10:16 +03:00
using Nebula.Launcher.Services;
2024-12-21 15:15:04 +03:00
using Nebula.Launcher.Views.Pages;
using Nebula.Shared;
2025-01-05 17:05:23 +03:00
using Nebula.Shared.Models;
using Nebula.Shared.Services;
2024-12-21 15:15:04 +03:00
2025-01-14 22:10:16 +03:00
namespace Nebula.Launcher.ViewModels.Pages;
2024-12-21 15:15:04 +03:00
[ViewModelRegister(typeof(ServerOverviewView))]
2025-01-14 22:10:16 +03:00
[ConstructGenerator]
public partial class ServerOverviewModel : ViewModelBase
2024-12-21 15:15:04 +03:00
{
2025-01-14 22:10:16 +03:00
[ObservableProperty] private string _searchText = string.Empty;
2025-01-30 10:11:54 +03:00
2025-03-14 19:42:55 +03:00
[ObservableProperty] private bool _isFilterVisible;
2025-06-22 22:11:27 +03:00
[ObservableProperty] private ServerListView _currentServerList = new();
2025-03-14 19:42:55 +03:00
2025-06-22 22:11:27 +03:00
public readonly ServerFilter CurrentFilter = new();
2025-01-30 20:18:40 +03:00
2024-12-27 08:22:17 +03:00
public Action? OnSearchChange;
[GenerateProperty] private IServiceProvider ServiceProvider { get; }
[GenerateProperty] private ConfigurationService ConfigurationService { get; }
[GenerateProperty] private FavoriteServerListProvider FavoriteServerListProvider { get; }
public ObservableCollection<ServerListTabTemplate> Items { get; private set; }
[ObservableProperty] private ServerListTabTemplate _selectedItem;
2025-06-22 22:11:27 +03:00
[GenerateProperty, DesignConstruct] private ServerViewContainer ServerViewContainer { get; }
private Dictionary<string, ServerListView> _viewCache = [];
2025-01-30 10:11:54 +03:00
2025-01-14 22:10:16 +03:00
2024-12-22 21:38:19 +03:00
//Design think
2025-01-14 22:10:16 +03:00
protected override void InitialiseInDesignMode()
2024-12-22 16:38:47 +03:00
{
Items = new ObservableCollection<ServerListTabTemplate>([
new ServerListTabTemplate(new TestServerList(), "Test think"),
new ServerListTabTemplate(new TestServerList(), "Test think2")
]);
SelectedItem = Items[0];
2024-12-22 16:38:47 +03:00
}
2025-01-14 22:10:16 +03:00
2024-12-22 21:38:19 +03:00
//real think
2025-01-14 22:10:16 +03:00
protected override void Initialise()
2025-06-19 21:12:42 +03:00
{
ConfigurationService.SubscribeVarChanged(LauncherConVar.Hub, OnHubListChanged, true);
}
private void OnHubListChanged(ServerHubRecord[]? value)
2024-12-22 16:38:47 +03:00
{
var tempItems = new List<ServerListTabTemplate>();
2025-06-19 21:12:42 +03:00
foreach (var record in value ?? [])
{
tempItems.Add(new ServerListTabTemplate(ServiceProvider.GetService<HubServerListProvider>()!.With(record.MainUrl), record.Name));
}
2025-01-30 10:11:54 +03:00
tempItems.Add(new ServerListTabTemplate(FavoriteServerListProvider, "Favorite"));
Items = new ObservableCollection<ServerListTabTemplate>(tempItems);
SelectedItem = Items[0];
2025-06-15 14:04:29 +03:00
OnSearchChange += SearchChangeEvent;
2024-12-27 08:22:17 +03:00
}
2025-06-15 14:04:29 +03:00
private void SearchChangeEvent()
{
CurrentFilter.SearchText = SearchText;
ApplyFilter();
}
public void ApplyFilter()
2025-03-14 19:42:55 +03:00
{
foreach (var entry in ServerViewContainer.Items)
2025-03-14 19:42:55 +03:00
{
2025-06-22 10:40:42 +03:00
if(entry is IFilterConsumer filterConsumer)
filterConsumer.ProcessFilter(CurrentFilter);
2025-03-14 19:42:55 +03:00
}
}
public void OnFilterChanged(FilterBoxChangedEventArgs args)
{
if (args.Checked)
CurrentFilter.Tags.Add(args.Tag);
2025-03-14 19:42:55 +03:00
else
CurrentFilter.Tags.Remove(args.Tag);
ApplyFilter();
2025-03-14 19:42:55 +03:00
}
public void FilterRequired()
2025-01-30 10:11:54 +03:00
{
IsFilterVisible = !IsFilterVisible;
2025-01-30 10:11:54 +03:00
}
public void UpdateRequired()
2024-12-27 08:22:17 +03:00
{
2025-06-22 10:40:42 +03:00
ServerViewContainer.Clear();
CurrentServerList.RefreshFromProvider();
2025-06-17 21:07:32 +03:00
CurrentServerList.RequireStatusUpdate();
CurrentServerList.ApplyFilter(CurrentFilter);
2024-12-22 16:38:47 +03:00
}
partial void OnSelectedItemChanged(ServerListTabTemplate value)
2024-12-21 15:15:04 +03:00
{
if (!_viewCache.TryGetValue(value.TabName, out var view))
2025-01-30 20:18:40 +03:00
{
view = ServerListView.TakeFrom(value.ServerListProvider);
_viewCache[value.TabName] = view;
2025-01-30 20:18:40 +03:00
}
CurrentServerList = view;
2025-06-22 22:11:27 +03:00
ApplyFilter();
2024-12-27 08:22:17 +03:00
}
}
2024-12-27 08:22:17 +03:00
[ServiceRegister]
public class ServerViewContainer
{
private readonly ViewHelperService _viewHelperService;
2025-06-22 22:11:27 +03:00
private readonly List<string> _favorites = [];
private readonly Dictionary<string, string> _customNames = [];
2025-01-29 12:32:42 +03:00
public ServerViewContainer()
2024-12-27 19:15:33 +03:00
{
_viewHelperService = new ViewHelperService();
2024-12-27 19:15:33 +03:00
}
2025-01-29 12:32:42 +03:00
2025-06-22 22:11:27 +03:00
[UsedImplicitly]
2025-06-19 21:12:42 +03:00
public ServerViewContainer(ViewHelperService viewHelperService, ConfigurationService configurationService)
2025-01-29 12:32:42 +03:00
{
_viewHelperService = viewHelperService;
2025-06-19 21:12:42 +03:00
configurationService.SubscribeVarChanged(LauncherConVar.Favorites, OnFavoritesChange, true);
2025-06-22 22:11:27 +03:00
configurationService.SubscribeVarChanged(LauncherConVar.ServerCustomNames, OnCustomNamesChanged, true);
}
private void OnCustomNamesChanged(Dictionary<string,string>? 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;
}
2025-01-29 12:32:42 +03:00
}
2025-06-19 21:12:42 +03:00
private void OnFavoritesChange(string[]? value)
{
2025-06-22 22:11:27 +03:00
_favorites.Clear();
if(value == null) return;
2025-06-19 21:12:42 +03:00
2025-06-22 22:11:27 +03:00
foreach (var favorite in value)
2025-06-19 21:12:42 +03:00
{
2025-06-22 22:11:27 +03:00
_favorites.Add(favorite);
2025-06-22 10:40:42 +03:00
if (_entries.TryGetValue(favorite, out var entry) && entry is IFavoriteEntryModelView favoriteView)
2025-06-19 21:12:42 +03:00
{
2025-06-22 10:40:42 +03:00
favoriteView.IsFavorite = true;
2025-06-19 21:12:42 +03:00
}
}
}
2025-06-22 10:40:42 +03:00
private readonly Dictionary<string, IListEntryModelView> _entries = new();
2025-06-22 10:40:42 +03:00
public ICollection<IListEntryModelView> Items => _entries.Values;
2025-01-30 10:11:54 +03:00
2025-01-30 20:18:40 +03:00
public void Clear()
{
_entries.Clear();
}
2025-06-22 10:40:42 +03:00
public IListEntryModelView Get(RobustUrl url, ServerStatus? serverStatus = null)
2025-01-30 10:11:54 +03:00
{
2025-06-22 10:40:42 +03:00
IListEntryModelView? entry;
2025-02-01 13:13:49 +03:00
lock (_entries)
2025-01-30 10:11:54 +03:00
{
2025-06-22 22:11:27 +03:00
_customNames.TryGetValue(url.ToString(), out var customName);
2025-02-01 13:13:49 +03:00
if (_entries.TryGetValue(url.ToString(), out entry))
{
2025-02-01 13:13:49 +03:00
return entry;
}
2025-01-30 10:11:54 +03:00
2025-06-22 10:40:42 +03:00
if (serverStatus is not null)
2025-06-22 22:11:27 +03:00
entry = _viewHelperService.GetViewModel<ServerEntryModelView>().WithData(url, customName, serverStatus);
2025-06-22 10:40:42 +03:00
else
2025-06-22 22:11:27 +03:00
entry = _viewHelperService.GetViewModel<ServerCompoundEntryViewModel>().LoadServerEntry(url, customName, CancellationToken.None);
2025-02-01 13:13:49 +03:00
2025-06-22 22:11:27 +03:00
if(_favorites.Contains(url.ToString()) &&
entry is IFavoriteEntryModelView favoriteEntryModelView)
2025-06-22 10:40:42 +03:00
favoriteEntryModelView.IsFavorite = true;
2025-06-19 21:12:42 +03:00
2025-02-01 13:13:49 +03:00
_entries.Add(url.ToString(), entry);
2025-01-30 20:18:40 +03:00
}
2025-02-01 13:13:49 +03:00
2025-01-30 10:11:54 +03:00
return entry;
}
}
2025-06-22 10:40:42 +03:00
public interface IListEntryModelView
{
}
public interface IFavoriteEntryModelView
{
public bool IsFavorite { get; set; }
}
2025-06-22 22:11:27 +03:00
public interface IEntryNameHolder
{
public string? Name { get; set; }
}
2025-01-28 19:59:35 +03:00
public class ServerComparer : IComparer<ServerHubInfo>, IComparer<ServerStatus>, IComparer<(RobustUrl,ServerStatus)>
2024-12-26 09:49:01 +03:00
{
public int Compare(ServerHubInfo? x, ServerHubInfo? y)
{
if (ReferenceEquals(x, y))
return 0;
if (ReferenceEquals(null, y))
return 1;
if (ReferenceEquals(null, x))
return -1;
2025-01-28 19:59:35 +03:00
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)
{
return Compare(x.Item2, y.Item2);
2024-12-21 15:15:04 +03:00
}
}
public sealed class ServerFilter
{
public string SearchText { get; set; } = "";
public HashSet<string> Tags { get; } = new();
public bool IsMatchByName(string name)
{
if (string.IsNullOrWhiteSpace(SearchText))
return true;
return name.Contains(SearchText, StringComparison.OrdinalIgnoreCase);
}
public bool IsMatchByTags(IEnumerable<string> itemTags)
{
if (Tags.Count == 0)
return true;
var itemTagSet = new HashSet<string>(itemTags);
return Tags.All(tag => itemTagSet.Contains(tag));
}
public bool IsMatch(string name, IEnumerable<string> itemTags)
{
return IsMatchByName(name) && IsMatchByTags(itemTags);
}
2025-06-22 22:11:27 +03:00
}
public sealed record ServerCustomNameEntry(string Url, string Name);