From 92440afcd7c0c5a9f4e463a023283324ec3eba7f Mon Sep 17 00:00:00 2001 From: GreemDev Date: Tue, 20 May 2025 04:19:54 -0500 Subject: [PATCH] UI: Show Total Time Played at the bottom of the UI in the status bar next to game total. Does not show up in-game, and is recalculated every time the game list is reloaded. --- assets/locales.json | 27 +++++++++++++- .../Systems/AppLibrary/ApplicationLibrary.cs | 36 +++++++++++++++++++ .../UI/ViewModels/MainWindowViewModel.cs | 22 ++++++++++++ .../UI/Views/Main/MainStatusBarView.axaml | 10 +++++- src/Ryujinx/UI/Windows/MainWindow.axaml.cs | 2 ++ 5 files changed, 95 insertions(+), 2 deletions(-) diff --git a/assets/locales.json b/assets/locales.json index d7d42dded..9762ea8fe 100644 --- a/assets/locales.json +++ b/assets/locales.json @@ -1947,6 +1947,31 @@ "zh_TW": "LDN 上在線的玩家數量: {0}" } }, + { + "ID": "GameListLabelTotalTimePlayed", + "Translations": { + "ar_SA": "", + "de_DE": "Gesamte Spielzeit: {0}", + "el_GR": "Συνολικός χρόνος παιχνιδιού: {0}", + "en_US": "Total Play Time: {0}", + "es_ES": "Tiempo total de juego: {0}", + "fr_FR": "Temps de jeu total: {0}", + "he_IL": "", + "it_IT": "Tempo totale di gioco: {0}", + "ja_JP": "", + "ko_KR": "", + "no_NO": "", + "pl_PL": "Całkowity czas gry: {0}", + "pt_BR": "Tempo total de jogo: {0}", + "ru_RU": "", + "sv_SE": "", + "th_TH": "", + "tr_TR": "Toplam Oyun Süresi: {0}", + "uk_UA": "", + "zh_CN": "", + "zh_TW": "" + } + }, { "ID": "GameListContextMenuOpenUserSaveDirectory", "Translations": { @@ -24748,4 +24773,4 @@ } } ] -} \ No newline at end of file +} diff --git a/src/Ryujinx/Systems/AppLibrary/ApplicationLibrary.cs b/src/Ryujinx/Systems/AppLibrary/ApplicationLibrary.cs index 618bc2b66..9ac484768 100644 --- a/src/Ryujinx/Systems/AppLibrary/ApplicationLibrary.cs +++ b/src/Ryujinx/Systems/AppLibrary/ApplicationLibrary.cs @@ -51,6 +51,26 @@ namespace Ryujinx.Ava.Systems.AppLibrary public readonly IObservableCache<(TitleUpdateModel TitleUpdate, bool IsSelected), TitleUpdateModel> TitleUpdates; public readonly IObservableCache<(DownloadableContentModel Dlc, bool IsEnabled), DownloadableContentModel> DownloadableContents; + private Gommon.Optional _totalTimePlayed; + + public Gommon.Optional TotalTimePlayed + { + get => _totalTimePlayed; + private set + { + _totalTimePlayed = value; + _totalTimePlayedChanged.Call(value); + } + } + + public event Action> TotalTimePlayedRecalculated + { + add => _totalTimePlayedChanged.Add(value); + remove => _totalTimePlayedChanged.Remove(value); + } + + private readonly Event> _totalTimePlayedChanged = new(); + private readonly byte[] _nspIcon; private readonly byte[] _xciIcon; private readonly byte[] _ncaIcon; @@ -825,6 +845,22 @@ namespace Ryujinx.Ava.Systems.AppLibrary } } + public Task RefreshTotalTimePlayedAsync() + { + TotalTimePlayed = Gommon.Optional.None; + + TimeSpan temporary = TimeSpan.Zero; + + foreach (var installedApplication in Applications.Items) + { + temporary += LoadAndSaveMetaData(installedApplication.IdString).TimePlayed; + } + + TotalTimePlayed = temporary; + + return Task.CompletedTask; + } + public async Task RefreshLdn() { if (ConfigurationState.Instance.Multiplayer.Mode == MultiplayerMode.LdnRyu) diff --git a/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs b/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs index b0cd6a556..f265f4c06 100644 --- a/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs @@ -25,6 +25,7 @@ using Ryujinx.Ava.UI.Renderer; using Ryujinx.Ava.UI.Windows; using Ryujinx.Ava.Systems.AppLibrary; using Ryujinx.Ava.Systems.Configuration; +using Ryujinx.Ava.Utilities; using Ryujinx.Common; using Ryujinx.Common.Configuration; using Ryujinx.Common.Helper; @@ -112,6 +113,7 @@ namespace Ryujinx.Ava.UI.ViewModels await Updater.BeginUpdateAsync(true); }); + private bool _showTotalTimePlayed; private bool _showLoadProgress; private bool _isGameRunning; private bool _isAmiiboRequested; @@ -197,6 +199,8 @@ namespace Ryujinx.Ava.UI.ViewModels #if DEBUG topLevel.AttachDevTools(new KeyGesture(Avalonia.Input.Key.F12, KeyModifiers.Control)); #endif + + Window.ApplicationLibrary.TotalTimePlayedRecalculated += TotalTimePlayed_Recalculated; } #region Properties @@ -299,6 +303,24 @@ namespace Ryujinx.Ava.UI.ViewModels OnPropertyChanged(nameof(ShowFirmwareStatus)); } } + + private void TotalTimePlayed_Recalculated(Optional ts) + { + ShowTotalTimePlayed = ts.HasValue; + + if (ts.HasValue) + LocaleManager.Instance.SetDynamicValues(LocaleKeys.GameListLabelTotalTimePlayed, ValueFormatUtils.FormatTimeSpan(ts.Value)); + } + + public bool ShowTotalTimePlayed + { + get => _showTotalTimePlayed && EnableNonGameRunningControls; + set + { + _showTotalTimePlayed = value; + OnPropertyChanged(); + } + } public ApplicationData ListSelectedApplication { diff --git a/src/Ryujinx/UI/Views/Main/MainStatusBarView.axaml b/src/Ryujinx/UI/Views/Main/MainStatusBarView.axaml index 02cc1fc7b..296936565 100644 --- a/src/Ryujinx/UI/Views/Main/MainStatusBarView.axaml +++ b/src/Ryujinx/UI/Views/Main/MainStatusBarView.axaml @@ -29,7 +29,7 @@ Margin="5" VerticalAlignment="Center" IsVisible="{Binding EnableNonGameRunningControls}"> - +