Compare commits

..

4 Commits

Author SHA1 Message Date
Evan Husted
4ae9f1c0d2 UI: Use Hosted Games & Player Count localization keys in list view too 2025-02-04 23:31:31 -06:00
Evan Husted
717851985e UI: Reorganize Game Info dialog popup + localization 2025-02-04 23:28:37 -06:00
Evan Husted
bd08a111a8 UI: Show what each value is in the Game Info dialog, add game icon 2025-02-04 22:47:12 -06:00
Evan Husted
1972a47f39 UI: Game stats button on right click for Grid view users 2025-02-04 19:32:17 -06:00
10 changed files with 525 additions and 131 deletions

View File

@@ -1525,151 +1525,151 @@
{ {
"ID": "GameListHeaderDeveloper", "ID": "GameListHeaderDeveloper",
"Translations": { "Translations": {
"ar_SA": "المطور", "ar_SA": "",
"de_DE": "Entwickler", "de_DE": "",
"el_GR": "Προγραμματιστής", "el_GR": "",
"en_US": "Developer", "en_US": "Developed by {0}",
"es_ES": "Desarrollador", "es_ES": "",
"fr_FR": "Développeur", "fr_FR": "",
"he_IL": "מפתח", "he_IL": "",
"it_IT": "Sviluppatore", "it_IT": "",
"ja_JP": "開発元", "ja_JP": "",
"ko_KR": "개발자", "ko_KR": "",
"no_NO": "Utvikler", "no_NO": "",
"pl_PL": "Twórca", "pl_PL": "",
"pt_BR": "Desenvolvedor", "pt_BR": "",
"ru_RU": "Разработчик", "ru_RU": "",
"sv_SE": "Utvecklare", "sv_SE": "",
"th_TH": "ผู้พัฒนา", "th_TH": "",
"tr_TR": "Geliştirici", "tr_TR": "",
"uk_UA": "Розробник", "uk_UA": "",
"zh_CN": "制作商", "zh_CN": "",
"zh_TW": "開發者" "zh_TW": ""
} }
}, },
{ {
"ID": "GameListHeaderVersion", "ID": "GameListHeaderVersion",
"Translations": { "Translations": {
"ar_SA": "الإصدار", "ar_SA": "",
"de_DE": "", "de_DE": "",
"el_GR": "Έκδοση", "el_GR": "Έκδοση: {0}",
"en_US": "Version", "en_US": "Version: {0}",
"es_ES": "Versión", "es_ES": "Versión: {0}",
"fr_FR": "", "fr_FR": "",
"he_IL": "גרסה", "he_IL": "",
"it_IT": "Versione", "it_IT": "Versione: {0}",
"ja_JP": "バージョン", "ja_JP": "バージョン: {0}",
"ko_KR": "버전", "ko_KR": "버전: {0}",
"no_NO": "Versjon", "no_NO": "Versjon: {0}",
"pl_PL": "Wersja", "pl_PL": "Wersja: {0}",
"pt_BR": "Versão", "pt_BR": "Versão: {0}",
"ru_RU": "Версия", "ru_RU": "Версия: {0}",
"sv_SE": "", "sv_SE": "",
"th_TH": "เวอร์ชั่น", "th_TH": "เวอร์ชั่น: {0}",
"tr_TR": "Sürüm", "tr_TR": "Sürüm: {0}",
"uk_UA": "Версія", "uk_UA": "Версія: {0}",
"zh_CN": "版本", "zh_CN": "版本: {0}",
"zh_TW": "版本" "zh_TW": "版本: {0}"
} }
}, },
{ {
"ID": "GameListHeaderTimePlayed", "ID": "GameListHeaderTimePlayed",
"Translations": { "Translations": {
"ar_SA": "وقت اللعب", "ar_SA": "",
"de_DE": "Spielzeit", "de_DE": "Spielzeit: {0}",
"el_GR": "Χρόνος", "el_GR": "Χρόνος: {0}",
"en_US": "Play Time", "en_US": "Play Time: {0}",
"es_ES": "Tiempo jugado", "es_ES": "Tiempo jugado: {0}",
"fr_FR": "Temps de jeu", "fr_FR": "Temps de jeu: {0}",
"he_IL": "זמן משחק", "he_IL": "",
"it_IT": "Tempo di gioco", "it_IT": "Tempo di gioco: {0}",
"ja_JP": "プレイ時間", "ja_JP": "プレイ時間: {0}",
"ko_KR": "플레이 타임", "ko_KR": "플레이 타임: {0}",
"no_NO": "Spilletid", "no_NO": "Spilletid: {0}",
"pl_PL": "Czas w grze:", "pl_PL": "Czas w grze: {0}",
"pt_BR": "Tempo de jogo", "pt_BR": "Tempo de jogo: {0}",
"ru_RU": "Время в игре", "ru_RU": "Время в игре: {0}",
"sv_SE": "Speltid", "sv_SE": "Speltid: {0}",
"th_TH": "เล่นไปแล้ว", "th_TH": "เล่นไปแล้ว: {0}",
"tr_TR": "Oynama Süresi", "tr_TR": "Oynama Süresi: {0}",
"uk_UA": "Зіграно часу", "uk_UA": "Зіграно часу: {0}",
"zh_CN": "游玩时长", "zh_CN": "游玩时长: {0}",
"zh_TW": "遊玩時數" "zh_TW": "遊玩時數: {0}"
} }
}, },
{ {
"ID": "GameListHeaderLastPlayed", "ID": "GameListHeaderLastPlayed",
"Translations": { "Translations": {
"ar_SA": "آخر مرة لُعبت", "ar_SA": "",
"de_DE": "Zuletzt gespielt", "de_DE": "Zuletzt gespielt: {0}",
"el_GR": "Παίχτηκε", "el_GR": "Παίχτηκε: {0}",
"en_US": "Last Played", "en_US": "Last Played: {0}",
"es_ES": "Jugado por última vez", "es_ES": "Jugado por última vez: {0}",
"fr_FR": "Dernière partie jouée", "fr_FR": "Dernière partie jouée: {0}",
"he_IL": "שוחק לאחרונה", "he_IL": "",
"it_IT": "Ultima partita", "it_IT": "Ultima partita: {0}",
"ja_JP": "最終プレイ日時", "ja_JP": "最終プレイ日時: {0}",
"ko_KR": "마지막 플레이", "ko_KR": "마지막 플레이: {0}",
"no_NO": "Sist Spilt", "no_NO": "Sist Spilt: {0}",
"pl_PL": "Ostatnio grane", "pl_PL": "Ostatnio grane: {0}",
"pt_BR": "Último jogo", "pt_BR": "Último jogo: {0}",
"ru_RU": "Последний запуск", "ru_RU": "Последний запуск: {0}",
"sv_SE": "Senast spelad", "sv_SE": "Senast spelad: {0}",
"th_TH": "เล่นล่าสุด", "th_TH": "เล่นล่าสุด: {0}",
"tr_TR": "Son Oynama Tarihi", "tr_TR": "Son Oynama Tarihi: {0}",
"uk_UA": "Востаннє зіграно", "uk_UA": "Востаннє зіграно: {0}",
"zh_CN": "最近游玩", "zh_CN": "最近游玩: {0}",
"zh_TW": "最近遊玩" "zh_TW": "最近遊玩: {0}"
} }
}, },
{ {
"ID": "GameListHeaderFileExtension", "ID": "GameListHeaderFileExtension",
"Translations": { "Translations": {
"ar_SA": "صيغة الملف", "ar_SA": "",
"de_DE": "Dateiformat", "de_DE": "Dateiformat: {0}",
"el_GR": "Κατάληξη", "el_GR": "Κατάληξη: {0}",
"en_US": "File Ext", "en_US": "Extension: {0}",
"es_ES": "Extensión", "es_ES": "Extensión: {0}",
"fr_FR": "Extension du Fichier", "fr_FR": "Extension du Fichier: {0}",
"he_IL": "סיומת קובץ", "he_IL": "",
"it_IT": "Estensione", "it_IT": "Estensione: {0}",
"ja_JP": "ファイル拡張子", "ja_JP": "ファイル拡張子: {0}",
"ko_KR": "파일 확장자", "ko_KR": "파일 확장자: {0}",
"no_NO": "Fil Eks.", "no_NO": "Fil Eks.: {0}",
"pl_PL": "Rozszerzenie pliku", "pl_PL": "Rozszerzenie pliku: {0}",
"pt_BR": "Extensão", "pt_BR": "Extensão: {0}",
"ru_RU": "Расширение файла", "ru_RU": "Расширение файла: {0}",
"sv_SE": "Filänd", "sv_SE": "Filänd: {0}",
"th_TH": "นามสกุลไฟล์", "th_TH": "นามสกุลไฟล์: {0}",
"tr_TR": "Dosya Uzantısı", "tr_TR": "Dosya Uzantısı: {0}",
"uk_UA": "Розширення файлу", "uk_UA": "Розширення файлу: {0}",
"zh_CN": "扩展名", "zh_CN": "扩展名: {0}",
"zh_TW": "副檔名" "zh_TW": "副檔名: {0}"
} }
}, },
{ {
"ID": "GameListHeaderFileSize", "ID": "GameListHeaderFileSize",
"Translations": { "Translations": {
"ar_SA": "حجم الملف", "ar_SA": "",
"de_DE": "Dateigröße", "de_DE": "Dateigröße: {0}",
"el_GR": "Μέγεθος Αρχείου", "el_GR": "Μέγεθος Αρχείου: {0}",
"en_US": "File Size", "en_US": "File Size: {0}",
"es_ES": "Tamaño del archivo", "es_ES": "Tamaño del archivo: {0}",
"fr_FR": "Taille du Fichier", "fr_FR": "Taille du Fichier: {0}",
"he_IL": "גודל הקובץ", "he_IL": "",
"it_IT": "Dimensione file", "it_IT": "Dimensione file: {0}",
"ja_JP": "ファイルサイズ", "ja_JP": "ファイルサイズ: {0}",
"ko_KR": "파일 크기", "ko_KR": "파일 크기: {0}",
"no_NO": "Fil Størrelse", "no_NO": "Fil Størrelse: {0}",
"pl_PL": "Rozmiar pliku", "pl_PL": "Rozmiar pliku: {0}",
"pt_BR": "Tamanho", "pt_BR": "Tamanho: {0}",
"ru_RU": "Размер файла", "ru_RU": "Размер файла: {0}",
"sv_SE": "Filstorlek", "sv_SE": "Filstorlek: {0}",
"th_TH": "ขนาดไฟล์", "th_TH": "ขนาดไฟล์: {0}",
"tr_TR": "Dosya Boyutu", "tr_TR": "Dosya Boyutu: {0}",
"uk_UA": "Розмір файлу", "uk_UA": "Розмір файлу: {0}",
"zh_CN": "大小", "zh_CN": "大小: {0}",
"zh_TW": "檔案大小" "zh_TW": "檔案大小: {0}"
} }
}, },
{ {
@@ -1697,6 +1697,106 @@
"zh_TW": "路徑" "zh_TW": "路徑"
} }
}, },
{
"ID": "GameListHeaderCompatibilityStatus",
"Translations": {
"ar_SA": "",
"de_DE": "",
"el_GR": "",
"en_US": "Compatibility:",
"es_ES": "",
"fr_FR": "",
"he_IL": "",
"it_IT": "",
"ja_JP": "",
"ko_KR": "",
"no_NO": "",
"pl_PL": "",
"pt_BR": "",
"ru_RU": "",
"sv_SE": "",
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_TW": ""
}
},
{
"ID": "GameListHeaderTitleId",
"Translations": {
"ar_SA": "",
"de_DE": "",
"el_GR": "",
"en_US": "Title ID:",
"es_ES": "",
"fr_FR": "",
"he_IL": "",
"it_IT": "",
"ja_JP": "",
"ko_KR": "",
"no_NO": "",
"pl_PL": "",
"pt_BR": "",
"ru_RU": "",
"sv_SE": "",
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_TW": ""
}
},
{
"ID": "GameListHeaderHostedGames",
"Translations": {
"ar_SA": "",
"de_DE": "",
"el_GR": "",
"en_US": "Hosted Games: {0}",
"es_ES": "",
"fr_FR": "",
"he_IL": "",
"it_IT": "",
"ja_JP": "",
"ko_KR": "",
"no_NO": "",
"pl_PL": "",
"pt_BR": "",
"ru_RU": "",
"sv_SE": "",
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_TW": ""
}
},
{
"ID": "GameListHeaderPlayerCount",
"Translations": {
"ar_SA": "",
"de_DE": "",
"el_GR": "",
"en_US": "Online Players: {0}",
"es_ES": "",
"fr_FR": "",
"he_IL": "",
"it_IT": "",
"ja_JP": "",
"ko_KR": "",
"no_NO": "",
"pl_PL": "",
"pt_BR": "",
"ru_RU": "",
"sv_SE": "",
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_TW": ""
}
},
{ {
"ID": "GameListContextMenuOpenUserSaveDirectory", "ID": "GameListContextMenuOpenUserSaveDirectory",
"Translations": { "Translations": {
@@ -2572,6 +2672,56 @@
"zh_TW": "" "zh_TW": ""
} }
}, },
{
"ID": "GameListContextMenuShowGameData",
"Translations": {
"ar_SA": "",
"de_DE": "",
"el_GR": "",
"en_US": "Show Game Info",
"es_ES": "",
"fr_FR": "",
"he_IL": "",
"it_IT": "",
"ja_JP": "",
"ko_KR": "",
"no_NO": "",
"pl_PL": "",
"pt_BR": "",
"ru_RU": "",
"sv_SE": "",
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_TW": ""
}
},
{
"ID": "GameListContextMenuShowGameDataToolTip",
"Translations": {
"ar_SA": "",
"de_DE": "",
"el_GR": "",
"en_US": "Show stats & details about the currently selected game.",
"es_ES": "",
"fr_FR": "",
"he_IL": "",
"it_IT": "",
"ja_JP": "",
"ko_KR": "",
"no_NO": "",
"pl_PL": "",
"pt_BR": "",
"ru_RU": "",
"sv_SE": "",
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_TW": ""
}
},
{ {
"ID": "GameListContextMenuOpenModsDirectory", "ID": "GameListContextMenuOpenModsDirectory",
"Translations": { "Translations": {

View File

@@ -32,6 +32,9 @@ namespace Ryujinx.Ava
public static MainWindow MainWindow => Current! public static MainWindow MainWindow => Current!
.ApplicationLifetime.Cast<IClassicDesktopStyleApplicationLifetime>() .ApplicationLifetime.Cast<IClassicDesktopStyleApplicationLifetime>()
.MainWindow.Cast<MainWindow>(); .MainWindow.Cast<MainWindow>();
public static IClassicDesktopStyleApplicationLifetime AppLifetime => Current!
.ApplicationLifetime.Cast<IClassicDesktopStyleApplicationLifetime>();
public static bool IsClipboardAvailable(out IClipboard clipboard) public static bool IsClipboardAvailable(out IClipboard clipboard)
{ {

View File

@@ -25,6 +25,11 @@
Header="{ext:Locale GameListContextMenuShowCompatEntry}" Header="{ext:Locale GameListContextMenuShowCompatEntry}"
Icon="{ext:Icon mdi-gamepad}" Icon="{ext:Icon mdi-gamepad}"
ToolTip.Tip="{ext:Locale GameListContextMenuShowCompatEntryToolTip}"/> ToolTip.Tip="{ext:Locale GameListContextMenuShowCompatEntryToolTip}"/>
<MenuItem
Click="OpenApplicationData_Click"
Header="{ext:Locale GameListContextMenuShowGameData}"
Icon="{ext:Icon mdi-chart-line}"
ToolTip.Tip="{ext:Locale GameListContextMenuShowGameDataToolTip}"/>
<Separator /> <Separator />
<MenuItem <MenuItem
Click="OpenUserSaveDirectory_Click" Click="OpenUserSaveDirectory_Click"

View File

@@ -392,6 +392,12 @@ namespace Ryujinx.Ava.UI.Controls
if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel }) if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
await CompatibilityList.Show(viewModel.SelectedApplication.IdString); await CompatibilityList.Show(viewModel.SelectedApplication.IdString);
} }
public async void OpenApplicationData_Click(object sender, RoutedEventArgs args)
{
if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
await ApplicationDataView.Show(viewModel.SelectedApplication);
}
public async void RunApplication_Click(object sender, RoutedEventArgs args) public async void RunApplication_Click(object sender, RoutedEventArgs args)
{ {
@@ -401,12 +407,8 @@ namespace Ryujinx.Ava.UI.Controls
public async void TrimXCI_Click(object sender, RoutedEventArgs args) public async void TrimXCI_Click(object sender, RoutedEventArgs args)
{ {
MainWindowViewModel viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel; if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
if (viewModel?.SelectedApplication != null)
{
await viewModel.TrimXCIFile(viewModel.SelectedApplication.Path); await viewModel.TrimXCIFile(viewModel.SelectedApplication.Path);
}
} }
} }
} }

View File

@@ -0,0 +1,114 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
xmlns:ext="using:Ryujinx.Ava.Common.Markup"
xmlns:viewModels="using:Ryujinx.Ava.UI.ViewModels"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Ryujinx.Ava.UI.Controls.ApplicationDataView"
x:DataType="viewModels:ApplicationDataViewModel">
<StackPanel Orientation="Horizontal">
<Image Margin="0"
MaxWidth="256"
MinWidth="256"
Source="{Binding AppData.Icon, Converter={x:Static helpers:BitmapArrayValueConverter.Instance}}" />
<Border Margin="5, 0" Width="1" Height="256" BorderBrush="Gray" Background="Gray" />
<StackPanel Orientation="Vertical">
<Grid
RowDefinitions="Auto,Auto,Auto"
ColumnDefinitions="*">
<StackPanel Grid.Row="0">
<TextBlock HorizontalAlignment="Left"
Text="{Binding FormattedVersion}"
TextAlignment="Start"
TextWrapping="Wrap" />
<TextBlock HorizontalAlignment="Left"
Text="{Binding FormattedDeveloper}"
TextAlignment="Start"
TextWrapping="Wrap" />
<TextBlock HorizontalAlignment="Stretch"
Text="{Binding FormattedFileExtension}"
TextAlignment="Start"
TextWrapping="Wrap" />
<TextBlock HorizontalAlignment="Stretch"
Text="{Binding FormattedFileSize}"
TextAlignment="Start"
TextWrapping="Wrap" />
</StackPanel>
<Separator Grid.Row="1" Margin="0, 10, 0, 10" Height="1" BorderBrush="Gray" Background="Gray" />
<StackPanel Grid.Row="2"
HorizontalAlignment="Left"
Orientation="Vertical"
Spacing="5">
<StackPanel Orientation="Horizontal">
<TextBlock Padding="0, 0, 5, 0" Text="{ext:Locale GameListHeaderCompatibilityStatus}" />
<Button
Click="PlayabilityStatus_OnClick"
HorizontalContentAlignment="Left"
VerticalAlignment="Center"
IsVisible="{Binding AppData.HasPlayabilityInfo}"
Background="{DynamicResource AppListBackgroundColor}"
Padding="0">
<TextBlock
Margin="1.5"
Tag="{Binding AppData.IdString}"
Text="{Binding AppData.LocalizedStatus}"
Foreground="{Binding AppData.PlayabilityStatus, Converter={x:Static helpers:PlayabilityStatusConverter.Shared}}"
TextAlignment="Start"
TextWrapping="Wrap" />
<Button.Styles>
<Style Selector="Button">
<Setter Property="MinWidth"
Value="0" />
<!-- avoids very wide buttons from the overall project avalonia style -->
</Style>
</Button.Styles>
</Button>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Padding="0, 0, 5, 0" Text="{ext:Locale GameListHeaderTitleId}" />
<Button
Click="IdString_OnClick"
HorizontalContentAlignment="Left"
VerticalAlignment="Center"
Background="{DynamicResource AppListBackgroundColor}"
Padding="0">
<TextBlock
Margin="1.5"
HorizontalAlignment="Stretch"
Text="{Binding AppData.IdString}"
TextAlignment="Start"
TextWrapping="Wrap" />
</Button>
</StackPanel>
</StackPanel>
</Grid>
<Separator Margin="0, 10, 0, 10" Height="1" BorderBrush="Gray" Background="Gray" />
<TextBlock
HorizontalAlignment="Stretch"
IsVisible="{Binding AppData.HasLdnGames}"
Text="{Binding FormattedLdnInfo}"
TextAlignment="Start"
TextWrapping="Wrap" />
<Separator IsVisible="{Binding AppData.HasLdnGames}" Margin="0, 10, 0, 10" Height="1" BorderBrush="Gray" Background="Gray" />
<StackPanel
HorizontalAlignment="Left"
VerticalAlignment="Top"
Orientation="Vertical"
Spacing="5">
<TextBlock
HorizontalAlignment="Stretch"
Text="{Binding FormattedLastPlayed}"
TextAlignment="Start"
TextWrapping="Wrap" />
<TextBlock
HorizontalAlignment="Stretch"
Text="{Binding FormattedPlayTime}"
IsVisible="{Binding AppData.HasPlayedPreviously}"
TextAlignment="Start"
TextWrapping="Wrap" />
</StackPanel>
</StackPanel>
</StackPanel>
</UserControl>

View File

@@ -0,0 +1,86 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input.Platform;
using Avalonia.Interactivity;
using Avalonia.Styling;
using FluentAvalonia.UI.Controls;
using Ryujinx.Ava;
using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Controls;
using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.Ava.UI.Windows;
using Ryujinx.Ava.Utilities.AppLibrary;
using Ryujinx.Ava.Utilities.Compat;
using System.Linq;
using System.Threading.Tasks;
namespace Ryujinx.Ava.UI.Controls
{
public partial class ApplicationDataView : UserControl
{
public static async Task Show(ApplicationData appData)
{
ContentDialog contentDialog = new()
{
Title = appData.Name,
PrimaryButtonText = string.Empty,
SecondaryButtonText = string.Empty,
CloseButtonText = LocaleManager.Instance[LocaleKeys.SettingsButtonClose],
MinWidth = 256,
Content = new ApplicationDataView { DataContext = new ApplicationDataViewModel(appData) }
};
Style closeButton = new(x => x.Name("CloseButton"));
closeButton.Setters.Add(new Setter(WidthProperty, 160d));
Style closeButtonParent = new(x => x.Name("CommandSpace"));
closeButtonParent.Setters.Add(new Setter(HorizontalAlignmentProperty,
Avalonia.Layout.HorizontalAlignment.Center));
contentDialog.Styles.Add(closeButton);
contentDialog.Styles.Add(closeButtonParent);
await ContentDialogHelper.ShowAsync(contentDialog);
}
public ApplicationDataView()
{
InitializeComponent();
}
private async void PlayabilityStatus_OnClick(object sender, RoutedEventArgs e)
{
if (sender is not Button { Content: TextBlock playabilityLabel })
return;
if (RyujinxApp.AppLifetime.Windows.TryGetFirst(x => x is ContentDialogOverlayWindow, out Window window))
window.Close(ContentDialogResult.None);
await CompatibilityList.Show((string)playabilityLabel.Tag);
}
private async void IdString_OnClick(object sender, RoutedEventArgs e)
{
if (DataContext is not MainWindowViewModel mwvm)
return;
if (sender is not Button { Content: TextBlock idText })
return;
if (!RyujinxApp.IsClipboardAvailable(out IClipboard clipboard))
return;
ApplicationData appData = mwvm.Applications.FirstOrDefault(it => it.IdString == idText.Text);
if (appData is null)
return;
await clipboard.SetTextAsync(appData.IdString);
NotificationHelper.ShowInformation(
"Copied Title ID",
$"{appData.Name} ({appData.IdString})");
}
}
}

View File

@@ -140,6 +140,7 @@
TextWrapping="Wrap" /> TextWrapping="Wrap" />
<TextBlock <TextBlock
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
IsVisible="{Binding HasLdnGames}"
Text="{Binding Converter={helpers:MultiplayerInfoConverter}}" Text="{Binding Converter={helpers:MultiplayerInfoConverter}}"
TextAlignment="Start" TextAlignment="Start"
TextWrapping="Wrap"/> TextWrapping="Wrap"/>

View File

@@ -1,8 +1,11 @@
using Avalonia.Data.Converters; using Avalonia.Data.Converters;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Gommon;
using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.Utilities.AppLibrary; using Ryujinx.Ava.Utilities.AppLibrary;
using System; using System;
using System.Globalization; using System.Globalization;
using System.Text;
namespace Ryujinx.Ava.UI.Helpers namespace Ryujinx.Ava.UI.Helpers
{ {
@@ -12,16 +15,17 @@ namespace Ryujinx.Ava.UI.Helpers
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{ {
if (value is ApplicationData applicationData) if (value is not ApplicationData { HasLdnGames: true } applicationData)
{ return "";
if (applicationData.PlayerCount != 0 && applicationData.GameCount != 0)
{
return $"Hosted Games: {applicationData.GameCount}\nOnline Players: {applicationData.PlayerCount}";
}
}
return "";
return new StringBuilder()
.AppendLine(
LocaleManager.Instance[LocaleKeys.GameListHeaderHostedGames]
.Format(applicationData.GameCount))
.Append(
LocaleManager.Instance[LocaleKeys.GameListHeaderPlayerCount]
.Format(applicationData.PlayerCount))
.ToString();
} }
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)

View File

@@ -0,0 +1,26 @@
using Gommon;
using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.Utilities.AppLibrary;
namespace Ryujinx.Ava.UI.ViewModels
{
public class ApplicationDataViewModel : BaseModel
{
public ApplicationData AppData { get; }
public ApplicationDataViewModel(ApplicationData appData) => AppData = appData;
public string FormattedVersion => LocaleManager.Instance[LocaleKeys.GameListHeaderVersion].Format(AppData.Version);
public string FormattedDeveloper => LocaleManager.Instance[LocaleKeys.GameListHeaderDeveloper].Format(AppData.Developer);
public string FormattedFileExtension => LocaleManager.Instance[LocaleKeys.GameListHeaderFileExtension].Format(AppData.FileExtension);
public string FormattedLastPlayed => LocaleManager.Instance[LocaleKeys.GameListHeaderLastPlayed].Format(AppData.LastPlayedString);
public string FormattedPlayTime => LocaleManager.Instance[LocaleKeys.GameListHeaderTimePlayed].Format(AppData.TimePlayedString);
public string FormattedFileSize => LocaleManager.Instance[LocaleKeys.GameListHeaderFileSize].Format(AppData.FileSizeString);
public string FormattedLdnInfo =>
$"{LocaleManager.Instance[LocaleKeys.GameListHeaderHostedGames].Format(AppData.GameCount)}" +
$"\n" +
$"{LocaleManager.Instance[LocaleKeys.GameListHeaderPlayerCount].Format(AppData.PlayerCount)}";
}
}

View File

@@ -49,6 +49,9 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
public int PlayerCount { get; set; } public int PlayerCount { get; set; }
public int GameCount { get; set; } public int GameCount { get; set; }
public bool HasLdnGames => PlayerCount != 0 && GameCount != 0;
public TimeSpan TimePlayed { get; set; } public TimeSpan TimePlayed { get; set; }
public DateTime? LastPlayed { get; set; } public DateTime? LastPlayed { get; set; }
public string FileExtension { get; set; } public string FileExtension { get; set; }