diff --git a/Directory.Packages.props b/Directory.Packages.props index 36d49a39..2ec3752b 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -20,6 +20,7 @@ + diff --git a/SS14.Launcher/App.xaml b/SS14.Launcher/App.xaml index 07ee32fd..5fa52b9a 100644 --- a/SS14.Launcher/App.xaml +++ b/SS14.Launcher/App.xaml @@ -9,8 +9,8 @@ - + @@ -23,10 +23,10 @@ - - + + diff --git a/SS14.Launcher/Assets/Locale/el/text.ftl b/SS14.Launcher/Assets/Locale/el/text.ftl index a294afb0..f47d0850 100644 --- a/SS14.Launcher/Assets/Locale/el/text.ftl +++ b/SS14.Launcher/Assets/Locale/el/text.ftl @@ -542,8 +542,4 @@ connecting-privacy-policy-decline = Δεν αποδέχομαι (αποσύνδ tab-servers-table-round-time = Χρόνος server-entry-status-lobby = Λόμπι connecting-status-update-error-unknown = Άγνωστο -server-entry-round-time = - { $hours -> - [0] { $mins }M - *[1] { $hours }H { $mins }M - } +server-entry-round-time = { $hours }h { $mins }m diff --git a/SS14.Launcher/Assets/Locale/en-US/text.ftl b/SS14.Launcher/Assets/Locale/en-US/text.ftl index 3d9d62ba..d846a062 100644 --- a/SS14.Launcher/Assets/Locale/en-US/text.ftl +++ b/SS14.Launcher/Assets/Locale/en-US/text.ftl @@ -301,10 +301,7 @@ server-entry-player-count = [0] ∞ *[1] { $max } } -server-entry-round-time = { $hours -> - [0] { $mins }M -*[1] { $hours }H { $mins }M -} +server-entry-round-time = { $hours }h { $mins }m server-entry-fetching = Fetching… server-entry-description-offline = Unable to contact server server-entry-description-fetching = Fetching server status… diff --git a/SS14.Launcher/Assets/Locale/nl/text.ftl b/SS14.Launcher/Assets/Locale/nl/text.ftl index 8eefdb61..1684a1d6 100644 --- a/SS14.Launcher/Assets/Locale/nl/text.ftl +++ b/SS14.Launcher/Assets/Locale/nl/text.ftl @@ -540,10 +540,6 @@ connecting-privacy-policy-view = Bekijk privacybeleid connecting-privacy-policy-accept = Accepteer (doorgaan) connecting-privacy-policy-decline = Weigeren (verbreken) tab-servers-table-round-time = Tijd -server-entry-round-time = - { $hours -> - [0] { $mins }M - *[1] { $hours }U { $mins }M - } +server-entry-round-time = { $hours }u { $mins }m server-entry-status-lobby = Lobby connecting-status-update-error-unknown = Onbekend diff --git a/SS14.Launcher/Assets/Locale/pl/text.ftl b/SS14.Launcher/Assets/Locale/pl/text.ftl index 37a25f33..d03b3e3d 100644 --- a/SS14.Launcher/Assets/Locale/pl/text.ftl +++ b/SS14.Launcher/Assets/Locale/pl/text.ftl @@ -539,11 +539,7 @@ connecting-status-update-error-unknown = Nieznany server-entry-status-lobby = Menu connecting-privacy-policy-text = Ten serwer wymaga zaakceptowania swojej polityki prywatności przed połączeniem. tab-servers-table-round-time = Czas -server-entry-round-time = - { $hours -> - [0] { $mins }M - *[1] { $hours }G { $mins }M - } +server-entry-round-time = { $hours }g { $mins }m connecting-privacy-policy-text-version-changed = Ten serwer zaktualizował swoją politykę prywatności od twojej ostatniej rozgrywki. Musisz zaakceptować nową wersję przed połączeniem. connecting-privacy-policy-view = Pokaż politykę prywatności connecting-privacy-policy-accept = Zaakceptuj (kontynuuj) diff --git a/SS14.Launcher/Assets/Locale/ru/text.ftl b/SS14.Launcher/Assets/Locale/ru/text.ftl index abe124b1..1ac6bc63 100644 --- a/SS14.Launcher/Assets/Locale/ru/text.ftl +++ b/SS14.Launcher/Assets/Locale/ru/text.ftl @@ -540,11 +540,7 @@ connecting-privacy-policy-text = Перед подключением к этом connecting-privacy-policy-view = Посмотреть политику конфиденциальности connecting-privacy-policy-accept = Принять (продолжить) connecting-privacy-policy-decline = Отклонить (отключиться) -server-entry-round-time = - { $hours -> - [0] { $mins }м - *[1] { $hours }ч { $mins }м - } +server-entry-round-time = { $hours }ч { $mins }м tab-servers-table-round-time = Время connecting-status-update-error-unknown = Неизвестно server-entry-status-lobby = Лобби diff --git a/SS14.Launcher/Assets/Locale/tr/text.ftl b/SS14.Launcher/Assets/Locale/tr/text.ftl index f0eda6bf..f19d2314 100644 --- a/SS14.Launcher/Assets/Locale/tr/text.ftl +++ b/SS14.Launcher/Assets/Locale/tr/text.ftl @@ -541,11 +541,7 @@ connecting-privacy-policy-text-version-changed = Bu sunucu son oynadığınızda connecting-privacy-policy-accept = Kabul et (devam et) connecting-privacy-policy-decline = Reddet (bağlantıyı kes) tab-servers-table-round-time = Zaman -server-entry-round-time = - { $hours -> - [0] { $mins }M - *[1] { $hours }H { $mins }M - } +server-entry-round-time = { $hours }h { $mins }m server-entry-status-lobby = Lobi connecting-status-update-error-unknown = Bilinmeyen connecting-status-update-error-no-engine-for-platform = Bu oyun platformunuzu desteklemeyen eski bir versiyon kullanmaktadır. Lütfen farklı bir sunucu deneyiniz ya da yeniden deneyiniz. diff --git a/SS14.Launcher/Assets/Locale/uk/text.ftl b/SS14.Launcher/Assets/Locale/uk/text.ftl index 712e6893..523a03ce 100644 --- a/SS14.Launcher/Assets/Locale/uk/text.ftl +++ b/SS14.Launcher/Assets/Locale/uk/text.ftl @@ -540,11 +540,7 @@ connecting-privacy-policy-text-version-changed = Цей сервер онови connecting-privacy-policy-view = Переглянути політику конфіденційності connecting-privacy-policy-accept = Прийняти (продовжити) connecting-privacy-policy-decline = Відхилити (відключитися) -server-entry-round-time = - { $hours -> - [0] { $mins }хв - *[1] { $hours }г { $mins }хв - } +server-entry-round-time = { $hours }г { $mins }хв tab-servers-table-round-time = Час server-entry-status-lobby = Лоббі connecting-status-update-error-unknown = Невідомо diff --git a/SS14.Launcher/Assets/Locale/zh_Hans/text.ftl b/SS14.Launcher/Assets/Locale/zh_Hans/text.ftl index a09e4707..066b8a5f 100644 --- a/SS14.Launcher/Assets/Locale/zh_Hans/text.ftl +++ b/SS14.Launcher/Assets/Locale/zh_Hans/text.ftl @@ -539,11 +539,7 @@ connecting-privacy-policy-view = 查看隐私条款 connecting-privacy-policy-accept = 同意(继续) connecting-privacy-policy-decline = 拒绝(断开连接) login-login-show-password = 显示密码 -server-entry-round-time = - { $hours -> - [0] { $mins }分 - *[1] { $hours }时 { $mins }分 - } +server-entry-round-time = { $hours }时 { $mins }分 connecting-status-update-error-unknown = 未知 tab-servers-table-round-time = 时间 server-entry-status-lobby = 大厅 diff --git a/SS14.Launcher/Controls/TimerTextCell.xaml.cs b/SS14.Launcher/Controls/TimerTextCell.xaml.cs deleted file mode 100644 index 56b27461..00000000 --- a/SS14.Launcher/Controls/TimerTextCell.xaml.cs +++ /dev/null @@ -1,94 +0,0 @@ -using System; -using Avalonia; -using Avalonia.Controls.Primitives; -using Avalonia.Threading; -using SS14.Launcher.Localization; - -namespace SS14.Launcher.Controls; - -public class TimerTextCell : TemplatedControl -{ - private readonly LocalizationManager _loc = LocalizationManager.Instance; - - public static readonly DirectProperty ValueProperty = - AvaloniaProperty.RegisterDirect( - nameof(Value), - o => o.Value, - (o, v) => o.Value = v - ); - - public static readonly DirectProperty TextProperty = - AvaloniaProperty.RegisterDirect( - nameof(Text), - o => o.Text, - (o, v) => o.Text = v - ); - - private DateTime? _value; - private bool _attached; - - public DateTime? Value - { - get => _value; - set => SetAndRaise(ValueProperty, ref _value, value); - } - - private string _text = ""; - - public string Text - { - get => _text; - set => SetAndRaise(TextProperty, ref _text, value); - } - - private IDisposable? _timer; - - protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) - { - base.OnPropertyChanged(change); - - if (change.Property == ValueProperty) - { - UpdateText(); - } - } - - protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) - { - _attached = true; - StartTimer(); - } - - protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e) - { - _attached = false; - _timer?.Dispose(); - } - - // Trigger an update when the visible timer will roll over to the next minute - private void StartTimer() - { - _timer?.Dispose(); - - // Only start a new timer if we have a DateTime - // and we’re on the visual tree. - if (_attached && Value is { } dt) - { - var ts = DateTime.UtcNow.Subtract(dt); - _timer = DispatcherTimer.RunOnce(UpdateText, TimeSpan.FromSeconds((ts.Seconds >= 0 ? ts.Seconds : 60))); - } - } - - private void UpdateText() - { - this.Text = Value is { } dt ? GetTimeStringSince(dt) : ""; - StartTimer(); - } - - private string GetTimeStringSince(DateTime dateTime) - { - var ts = DateTime.UtcNow.Subtract(dateTime); - return _loc.GetString("server-entry-round-time", ("hours", Math.Floor(ts.TotalHours)), - ("mins", ts.Minutes.ToString().PadLeft(2, '0'))); - } -} diff --git a/SS14.Launcher/Models/ServerStatus/IServerStatusData.cs b/SS14.Launcher/Models/ServerStatus/IServerStatusData.cs index 5c68ae7d..cf6482b8 100644 --- a/SS14.Launcher/Models/ServerStatus/IServerStatusData.cs +++ b/SS14.Launcher/Models/ServerStatus/IServerStatusData.cs @@ -27,7 +27,5 @@ public interface IServerStatusData : INotifyPropertyChanged int SoftMaxPlayerCount { get; set; } - DateTime? RoundStartTime { get; set; } - GameRoundStatus RoundStatus { get; set; } } diff --git a/SS14.Launcher/Models/ServerStatus/ServerStatusCache.Data.cs b/SS14.Launcher/Models/ServerStatus/ServerStatusCache.Data.cs index d229f305..b4b491d3 100644 --- a/SS14.Launcher/Models/ServerStatus/ServerStatusCache.Data.cs +++ b/SS14.Launcher/Models/ServerStatus/ServerStatusCache.Data.cs @@ -79,12 +79,6 @@ public int SoftMaxPlayerCount set => SetProperty(ref _softMaxPlayerCount, value); } - public DateTime? RoundStartTime - { - get => _roundStartTime; - set => SetProperty(ref _roundStartTime, value); - } - public GameRoundStatus RoundStatus { get => _roundStatus; diff --git a/SS14.Launcher/Models/ServerStatus/ServerStatusCache.cs b/SS14.Launcher/Models/ServerStatus/ServerStatusCache.cs index 89e2d4a3..678d409f 100644 --- a/SS14.Launcher/Models/ServerStatus/ServerStatusCache.cs +++ b/SS14.Launcher/Models/ServerStatus/ServerStatusCache.cs @@ -128,23 +128,19 @@ public static void ApplyStatus(ServerStatusData data, ServerApi.ServerStatus sta switch (status.RunLevel) { - case ServerApi.GameRunLevel.InRound: - data.RoundStatus = GameRoundStatus.InRound; + case ServerApi.GameRunLevel.InRound when status.RoundStartTime is { } start: + var roundStartTime = DateTime.Parse(start, null, System.Globalization.DateTimeStyles.RoundtripKind); + data.RoundStatus = new InRound(roundStartTime); break; case ServerApi.GameRunLevel.PostRound: case ServerApi.GameRunLevel.PreRoundLobby: - data.RoundStatus = GameRoundStatus.InLobby; + data.RoundStatus = new InLobby(); break; default: - data.RoundStatus = GameRoundStatus.Unknown; + data.RoundStatus = new Unknown(); break; } - if (status.RoundStartTime != null) - { - data.RoundStartTime = DateTime.Parse(status.RoundStartTime, null, System.Globalization.DateTimeStyles.RoundtripKind); - } - var baseTags = status.Tags ?? Array.Empty(); var inferredTags = ServerTagInfer.InferTags(status); diff --git a/SS14.Launcher/Models/ServerStatus/ServerStatusCode.cs b/SS14.Launcher/Models/ServerStatus/ServerStatusCode.cs index 02ace184..2df78027 100644 --- a/SS14.Launcher/Models/ServerStatus/ServerStatusCode.cs +++ b/SS14.Launcher/Models/ServerStatus/ServerStatusCode.cs @@ -1,3 +1,5 @@ +using System; + namespace SS14.Launcher.Models.ServerStatus; public enum ServerStatusCode @@ -15,9 +17,30 @@ public enum ServerStatusInfoCode Fetched } -public enum GameRoundStatus +public abstract record GameRoundStatus : IComparable +{ + public int CompareTo(GameRoundStatus? other) + => (this, other) switch + { + (InRound a, InRound b) => a.TimeElapsed.CompareTo(b.TimeElapsed), + ({ } a, { } b) => Ordering(a).CompareTo(Ordering(b)), + _ => 1, + }; + + private static int Ordering(GameRoundStatus status) + => status switch + { + Unknown => 0, + InLobby => 1, + InRound => 2, + _ => throw new ArgumentOutOfRangeException(nameof(status), status, "You should add an ordering value"), + }; +} + +public record Unknown : GameRoundStatus; +public record InLobby : GameRoundStatus; + +public record InRound(DateTime RoundStartTime) : GameRoundStatus { - Unknown, - InLobby, - InRound, + public TimeSpan TimeElapsed => DateTime.UtcNow.Subtract(RoundStartTime); } diff --git a/SS14.Launcher/SS14.Launcher.csproj b/SS14.Launcher/SS14.Launcher.csproj index 9800cf9d..0b437f76 100644 --- a/SS14.Launcher/SS14.Launcher.csproj +++ b/SS14.Launcher/SS14.Launcher.csproj @@ -40,6 +40,7 @@ + diff --git a/SS14.Launcher/Theme/Theme.xaml b/SS14.Launcher/Theme/Theme.xaml index 485a8657..b5836244 100644 --- a/SS14.Launcher/Theme/Theme.xaml +++ b/SS14.Launcher/Theme/Theme.xaml @@ -39,7 +39,7 @@ diff --git a/SS14.Launcher/Theme/ThemeResources.xaml b/SS14.Launcher/Theme/ThemeResources.xaml index d3a85b84..12aca0a9 100644 --- a/SS14.Launcher/Theme/ThemeResources.xaml +++ b/SS14.Launcher/Theme/ThemeResources.xaml @@ -6,8 +6,12 @@ #202025 #EEEEEE + #1E1E22 + #262626 + #666 + #2E2E35 #464966 #3E6C45 @@ -22,11 +26,14 @@ #AA575B7F #00575B7F + #2E2E35 + + @@ -42,9 +49,9 @@ - - - + + + diff --git a/SS14.Launcher/Theme/ThemeServerList.axaml b/SS14.Launcher/Theme/ThemeServerList.axaml index 96f21570..0f1443c9 100644 --- a/SS14.Launcher/Theme/ThemeServerList.axaml +++ b/SS14.Launcher/Theme/ThemeServerList.axaml @@ -1,103 +1,57 @@ - + xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"> - - - - - - + + - - - - - - - - - - - - - + - + - - - - - - - - - + + - - - - - - - - - - - - - - - + + + + + diff --git a/SS14.Launcher/Theme/ThemeTimerTextCell.xaml b/SS14.Launcher/Theme/ThemeTimerTextCell.xaml deleted file mode 100644 index a1462e4b..00000000 --- a/SS14.Launcher/Theme/ThemeTimerTextCell.xaml +++ /dev/null @@ -1,13 +0,0 @@ - - - diff --git a/SS14.Launcher/ViewModels/MainWindowTabs/ServerEntryViewModel.cs b/SS14.Launcher/ViewModels/MainWindowTabs/ServerEntryViewModel.cs index 343b46f8..156ad31a 100644 --- a/SS14.Launcher/ViewModels/MainWindowTabs/ServerEntryViewModel.cs +++ b/SS14.Launcher/ViewModels/MainWindowTabs/ServerEntryViewModel.cs @@ -1,5 +1,8 @@ using System; +using System.Collections; +using System.Collections.Generic; using System.ComponentModel; +using Avalonia.Threading; using Microsoft.Toolkit.Mvvm.ComponentModel; using Microsoft.Toolkit.Mvvm.Messaging; using SS14.Launcher.Localization; @@ -20,6 +23,22 @@ public sealed class ServerEntryViewModel : ObservableRecipient, IRecipient + /// Maps a sorting key to a comparer to use for column sorting. + /// + public static readonly Dictionary ComparerMapping = new() + { + { NameSortKey, StringComparer.InvariantCultureIgnoreCase }, + { TimeSortKey, Comparer.Default }, + { PlayersSortKey, Comparer.Default }, + }; + public ServerEntryViewModel(MainWindowViewModel windowVm, ServerStatusData cacheData, IServerSource serverSource, DataManager cfg) { @@ -27,6 +46,11 @@ public ServerEntryViewModel(MainWindowViewModel windowVm, ServerStatusData cache _windowVm = windowVm; _cacheData = cacheData; _serverSource = serverSource; + + _cacheData.PropertyChanged += OnCacheDataOnPropertyChanged; + + _refreshRoundStartTimer.Start(); + _refreshRoundStartTimer.Tick += (_, _) => OnPropertyChanged(nameof(RoundStatusString)); } public ServerEntryViewModel( @@ -38,6 +62,8 @@ public ServerEntryViewModel( : this(windowVm, cacheData, serverSource, cfg) { Favorite = favorite; + + _cacheData.PropertyChanged += OnCacheDataOnPropertyChanged; } public ServerEntryViewModel( @@ -50,11 +76,6 @@ public ServerEntryViewModel( FallbackName = ssdfb.FallbackName ?? ""; } - public void Tick() - { - OnPropertyChanged(nameof(RoundStartTime)); - } - public void ConnectPressed() { ConnectingViewModel.StartConnect(_windowVm, Address); @@ -101,18 +122,25 @@ public string ServerStatusString } } + public int PlayerCount => _cacheData.PlayerCount; + // Give a ratio for servers with a defined player count, or just a current number for those without. public string PlayerCountString => _loc.GetString("server-entry-player-count", - ("players", _cacheData.PlayerCount), ("max", _cacheData.SoftMaxPlayerCount)); + ("players", PlayerCount.ToString().PadLeft(3)), + ("max", _cacheData.SoftMaxPlayerCount.ToString().PadRight(3))); - public DateTime? RoundStartTime => _cacheData.RoundStartTime; + public GameRoundStatus RoundStatus => _cacheData.RoundStatus; - public string RoundStatusString => - _cacheData.RoundStatus == GameRoundStatus.InLobby - ? _loc.GetString("server-entry-status-lobby") - : ""; + public string RoundStatusString + => _cacheData.RoundStatus switch + { + InLobby => _loc.GetString("server-entry-status-lobby"), + InRound r => _loc.GetString("server-entry-round-time", ("hours", Math.Floor(r.TimeElapsed.TotalHours)), + ("mins", r.TimeElapsed.Minutes.ToString().PadLeft(2, '0'))), + _ => "", + }; public string Description { @@ -237,10 +265,6 @@ private void OnCacheDataOnPropertyChanged(object? _, PropertyChangedEventArgs ar OnPropertyChanged(nameof(PlayerCountString)); break; - case nameof(IServerStatusData.RoundStartTime): - OnPropertyChanged(nameof(RoundStartTime)); - break; - case nameof(IServerStatusData.RoundStatus): OnPropertyChanged(nameof(RoundStatusString)); break; diff --git a/SS14.Launcher/ViewModels/MainWindowTabs/ServerListTabViewModel.cs b/SS14.Launcher/ViewModels/MainWindowTabs/ServerListTabViewModel.cs index bd50c08a..96ce3671 100644 --- a/SS14.Launcher/ViewModels/MainWindowTabs/ServerListTabViewModel.cs +++ b/SS14.Launcher/ViewModels/MainWindowTabs/ServerListTabViewModel.cs @@ -27,11 +27,13 @@ public class ServerListTabViewModel : MainWindowTabViewModel public string? SearchString { get => _searchString; - set => this.RaiseAndSetIfChanged(ref _searchString, value); + set + { + this.RaiseAndSetIfChanged(ref _searchString, value); + UpdateSearchedList(); + } } - private const int throttleMs = 200; - public bool SpinnerVisible => _serverListCache.Status < RefreshListStatus.Updated; public string ListText @@ -88,11 +90,6 @@ public ServerListTabViewModel(MainWindowViewModel windowVm) }; _loc.LanguageSwitched += () => Filters.UpdatePresentFilters(_serverListCache.AllServers); - - this.WhenAnyValue(x => x.SearchString) - .Throttle(TimeSpan.FromMilliseconds(throttleMs), RxApp.MainThreadScheduler) - .ObserveOn(RxApp.MainThreadScheduler) - .Subscribe(_ => UpdateSearchedList()); } private void FiltersOnFiltersUpdated() diff --git a/SS14.Launcher/Views/MainWindowContent.xaml b/SS14.Launcher/Views/MainWindowContent.xaml index 670c8e0e..31fe04de 100644 --- a/SS14.Launcher/Views/MainWindowContent.xaml +++ b/SS14.Launcher/Views/MainWindowContent.xaml @@ -53,7 +53,7 @@ + SelectedIndex="{Binding SelectedIndex,Mode=TwoWay}"> diff --git a/SS14.Launcher/Views/MainWindowTabs/HomePageView.xaml b/SS14.Launcher/Views/MainWindowTabs/HomePageView.xaml index 73e7e291..370bac62 100644 --- a/SS14.Launcher/Views/MainWindowTabs/HomePageView.xaml +++ b/SS14.Launcher/Views/MainWindowTabs/HomePageView.xaml @@ -14,7 +14,7 @@ - + - -