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.
This commit is contained in:
GreemDev 2025-05-20 04:19:54 -05:00
parent df3b5b4bd8
commit 92440afcd7
5 changed files with 95 additions and 2 deletions

View File

@ -1947,6 +1947,31 @@
"zh_TW": "LDN 上在線的玩家數量: {0}" "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", "ID": "GameListContextMenuOpenUserSaveDirectory",
"Translations": { "Translations": {
@ -24748,4 +24773,4 @@
} }
} }
] ]
} }

View File

@ -51,6 +51,26 @@ namespace Ryujinx.Ava.Systems.AppLibrary
public readonly IObservableCache<(TitleUpdateModel TitleUpdate, bool IsSelected), TitleUpdateModel> TitleUpdates; public readonly IObservableCache<(TitleUpdateModel TitleUpdate, bool IsSelected), TitleUpdateModel> TitleUpdates;
public readonly IObservableCache<(DownloadableContentModel Dlc, bool IsEnabled), DownloadableContentModel> DownloadableContents; public readonly IObservableCache<(DownloadableContentModel Dlc, bool IsEnabled), DownloadableContentModel> DownloadableContents;
private Gommon.Optional<TimeSpan> _totalTimePlayed;
public Gommon.Optional<TimeSpan> TotalTimePlayed
{
get => _totalTimePlayed;
private set
{
_totalTimePlayed = value;
_totalTimePlayedChanged.Call(value);
}
}
public event Action<Gommon.Optional<TimeSpan>> TotalTimePlayedRecalculated
{
add => _totalTimePlayedChanged.Add(value);
remove => _totalTimePlayedChanged.Remove(value);
}
private readonly Event<Gommon.Optional<TimeSpan>> _totalTimePlayedChanged = new();
private readonly byte[] _nspIcon; private readonly byte[] _nspIcon;
private readonly byte[] _xciIcon; private readonly byte[] _xciIcon;
private readonly byte[] _ncaIcon; private readonly byte[] _ncaIcon;
@ -825,6 +845,22 @@ namespace Ryujinx.Ava.Systems.AppLibrary
} }
} }
public Task RefreshTotalTimePlayedAsync()
{
TotalTimePlayed = Gommon.Optional<TimeSpan>.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() public async Task RefreshLdn()
{ {
if (ConfigurationState.Instance.Multiplayer.Mode == MultiplayerMode.LdnRyu) if (ConfigurationState.Instance.Multiplayer.Mode == MultiplayerMode.LdnRyu)

View File

@ -25,6 +25,7 @@ using Ryujinx.Ava.UI.Renderer;
using Ryujinx.Ava.UI.Windows; using Ryujinx.Ava.UI.Windows;
using Ryujinx.Ava.Systems.AppLibrary; using Ryujinx.Ava.Systems.AppLibrary;
using Ryujinx.Ava.Systems.Configuration; using Ryujinx.Ava.Systems.Configuration;
using Ryujinx.Ava.Utilities;
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Helper; using Ryujinx.Common.Helper;
@ -112,6 +113,7 @@ namespace Ryujinx.Ava.UI.ViewModels
await Updater.BeginUpdateAsync(true); await Updater.BeginUpdateAsync(true);
}); });
private bool _showTotalTimePlayed;
private bool _showLoadProgress; private bool _showLoadProgress;
private bool _isGameRunning; private bool _isGameRunning;
private bool _isAmiiboRequested; private bool _isAmiiboRequested;
@ -197,6 +199,8 @@ namespace Ryujinx.Ava.UI.ViewModels
#if DEBUG #if DEBUG
topLevel.AttachDevTools(new KeyGesture(Avalonia.Input.Key.F12, KeyModifiers.Control)); topLevel.AttachDevTools(new KeyGesture(Avalonia.Input.Key.F12, KeyModifiers.Control));
#endif #endif
Window.ApplicationLibrary.TotalTimePlayedRecalculated += TotalTimePlayed_Recalculated;
} }
#region Properties #region Properties
@ -299,6 +303,24 @@ namespace Ryujinx.Ava.UI.ViewModels
OnPropertyChanged(nameof(ShowFirmwareStatus)); OnPropertyChanged(nameof(ShowFirmwareStatus));
} }
} }
private void TotalTimePlayed_Recalculated(Optional<TimeSpan> 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 public ApplicationData ListSelectedApplication
{ {

View File

@ -29,7 +29,7 @@
Margin="5" Margin="5"
VerticalAlignment="Center" VerticalAlignment="Center"
IsVisible="{Binding EnableNonGameRunningControls}"> IsVisible="{Binding EnableNonGameRunningControls}">
<Grid Margin="0" ColumnDefinitions="Auto,Auto,Auto,*"> <Grid Margin="0" ColumnDefinitions="Auto,Auto,Auto,*,Auto,Auto,*">
<Button <Button
Width="25" Width="25"
Height="25" Height="25"
@ -68,6 +68,14 @@
IsVisible="{Binding StatusBarVisible}" IsVisible="{Binding StatusBarVisible}"
Maximum="{Binding StatusBarProgressMaximum}" Maximum="{Binding StatusBarProgressMaximum}"
Value="{Binding StatusBarProgressValue}" /> Value="{Binding StatusBarProgressValue}" />
<controls:MiniVerticalSeparator Grid.Column="4" IsVisible="{Binding ShowTotalTimePlayed}" />
<TextBlock
Grid.Column="5"
Margin="5,0,5,0"
VerticalAlignment="Center"
IsVisible="{Binding ShowTotalTimePlayed}"
Text="{ext:Locale GameListLabelTotalTimePlayed}">
</TextBlock>
</Grid> </Grid>
</StackPanel> </StackPanel>
<StackPanel <StackPanel

View File

@ -717,6 +717,8 @@ namespace Ryujinx.Ava.UI.Windows
ShowNewContentAddedDialog(dlcLoaded, dlcRemoved, updatesLoaded, updatesRemoved); ShowNewContentAddedDialog(dlcLoaded, dlcRemoved, updatesLoaded, updatesRemoved);
} }
Executor.ExecuteBackgroundAsync(ApplicationLibrary.RefreshTotalTimePlayedAsync);
_isLoading = false; _isLoading = false;
}) })