using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Threading.Tasks; using CommunityToolkit.Mvvm.ComponentModel; using Nebula.Launcher.Services; using Nebula.Launcher.ViewModels.Popup; using Nebula.Launcher.Views; using Nebula.Launcher.Views.Pages; using Nebula.Shared.Models; using Nebula.Shared.Services; using Nebula.Shared.Utils; namespace Nebula.Launcher.ViewModels.Pages; [ViewModelRegister(typeof(ServerListView))] [ConstructGenerator] public partial class ServerListViewModel : ViewModelBase, IViewModelPage { [ObservableProperty] private string _searchText = string.Empty; [ObservableProperty] private bool _isFavoriteMode; [ObservableProperty] private bool _isFilterVisible; public ObservableCollection Servers { get; }= new(); public ObservableCollection HubErrors { get; } = new(); public Action? OnSearchChange; [GenerateProperty] private HubService HubService { get; } [GenerateProperty] private PopupMessageService PopupMessageService { get; } [GenerateProperty] private CancellationService CancellationService { get; } [GenerateProperty] private DebugService DebugService { get; } [GenerateProperty, DesignConstruct] private ViewHelperService ViewHelperService { get; } private ServerViewContainer ServerViewContainer { get; set; } private List UnsortedServers { get; } = new(); private List _filters = new(); //Design think protected override void InitialiseInDesignMode() { ServerViewContainer = new ServerViewContainer(this, ViewHelperService); HubErrors.Add(new Exception("UVI")); } //real think protected override void Initialise() { ServerViewContainer = new ServerViewContainer(this, ViewHelperService); foreach (var info in HubService.ServerList) UnsortedServers.Add(info); HubService.HubServerChangedEventArgs += HubServerChangedEventArgs; HubService.HubServerLoaded += UpdateServerEntries; HubService.HubServerLoadingError += HubServerLoadingError; OnSearchChange += OnChangeSearch; if (!HubService.IsUpdating) UpdateServerEntries(); UpdateFavoriteEntries(); } public void OnFilterChanged(string name, bool active) { DebugService.Debug($"OnFilterChanged: {name} {active}"); if(active) _filters.Add(name); else _filters.Remove(name); if(IsFavoriteMode) { UpdateFavoriteEntries(); } else { UpdateServerEntries(); } } private void HubServerLoadingError(Exception obj) { HubErrors.Add(obj); } private void UpdateServerEntries() { foreach(var fav in Servers.ToList()){ Servers.Remove(fav); } Task.Run(() => { UnsortedServers.Sort(new ServerComparer()); foreach (var info in UnsortedServers.Where(CheckServerThink)) { var view = ServerViewContainer.Get(info.Address.ToRobustUrl(), info.StatusData); Servers.Add(view); } }); } private void OnChangeSearch() { if(string.IsNullOrEmpty(SearchText)) return; if(IsFavoriteMode) { UpdateFavoriteEntries(); } else { UpdateServerEntries(); } } private void HubServerChangedEventArgs(HubServerChangedEventArgs obj) { if (obj.Action == HubServerChangeAction.Add) foreach (var info in obj.Items) UnsortedServers.Add(info); if (obj.Action == HubServerChangeAction.Remove) foreach (var info in obj.Items) UnsortedServers.Remove(info); if (obj.Action == HubServerChangeAction.Clear) { UnsortedServers.Clear(); ServerViewContainer.Clear(); UpdateFavoriteEntries(); } } private bool CheckServerThink(ServerHubInfo hubInfo) { var isNameEqual = string.IsNullOrEmpty(SearchText) || hubInfo.StatusData.Name.ToLower().Contains(SearchText.ToLower()); if (_filters.Count == 0) return isNameEqual; if(_filters.Select(t=>t.Replace('_',':').Replace("ERPYes","18+")).Any(t=>hubInfo.StatusData.Tags.Contains(t) || hubInfo.InferredTags.Contains(t))) return isNameEqual; return false; } public void FilterRequired() { IsFilterVisible = !IsFilterVisible; } public void AddFavoriteRequired() { var p = ViewHelperService.GetViewModel(); PopupMessageService.Popup(p); } public void UpdateRequired() { HubErrors.Clear(); Task.Run(HubService.UpdateHub); } public void OnPageOpen(object? args) { if (args is bool fav) { IsFavoriteMode = fav; } } } public class ServerViewContainer( ServerListViewModel serverListViewModel, ViewHelperService viewHelperService ) { private readonly Dictionary _entries = new(); public void Clear() { _entries.Clear(); } public ServerEntryModelView Get(RobustUrl url, ServerStatus? serverStatus = null) { ServerEntryModelView? entry; lock (_entries) { if (_entries.TryGetValue(url.ToString(), out entry)) { return entry; } entry = viewHelperService.GetViewModel().WithData(url, serverStatus); _entries.Add(url.ToString(), entry); } entry.OnFavoriteToggle += () => { if (entry.IsFavorite) serverListViewModel.RemoveFavorite(entry); else serverListViewModel.AddFavorite(entry); }; return entry; } } public class ServerComparer : IComparer, IComparer, IComparer<(RobustUrl,ServerStatus)> { 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; 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); } }