Browse Source

UI: Game stats button on right click for Grid view users

Evan Husted 1 year ago
parent
commit
1972a47f39

+ 50 - 0
src/Ryujinx/Assets/locales.json

@@ -2572,6 +2572,56 @@
         "zh_TW": ""
       }
     },
+    {
+      "ID": "GameListContextMenuShowGameData",
+      "Translations": {
+        "ar_SA": "",
+        "de_DE": "",
+        "el_GR": "",
+        "en_US": "Show Game Stats",
+        "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 the other various information about the currently selected game that is missing from the Grid view layout.",
+        "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",
       "Translations": {

+ 3 - 0
src/Ryujinx/RyujinxApp.axaml.cs

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

+ 6 - 0
src/Ryujinx/UI/Controls/ApplicationContextMenu.axaml

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

+ 7 - 5
src/Ryujinx/UI/Controls/ApplicationContextMenu.axaml.cs

@@ -392,6 +392,12 @@ namespace Ryujinx.Ava.UI.Controls
             if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
                 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)
         {
@@ -401,12 +407,8 @@ namespace Ryujinx.Ava.UI.Controls
 
         public async void TrimXCI_Click(object sender, RoutedEventArgs args)
         {
-            MainWindowViewModel viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
-
-            if (viewModel?.SelectedApplication != null)
-            {
+            if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
                 await viewModel.TrimXCIFile(viewModel.SelectedApplication.Path);
-            }
         }
     }
 }

+ 116 - 0
src/Ryujinx/UI/Controls/ApplicationDataView.axaml

@@ -0,0 +1,116 @@
+<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:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
+             xmlns:appLibrary="using:Ryujinx.Ava.Utilities.AppLibrary"
+             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="appLibrary:ApplicationData">
+    <StackPanel Orientation="Vertical">
+        <Grid
+            RowDefinitions="Auto, Auto, Auto, Auto"
+            ColumnDefinitions="*">
+            <TextBlock Grid.Row="0"
+                       HorizontalAlignment="Center"
+                       Padding="0, -2, 0, 5" 
+                       Classes="h1" 
+                       Text="{Binding Name}" />
+            <TextBlock Grid.Row="1"
+                       HorizontalAlignment="Center"
+                       Text="{Binding Version}"
+                       TextAlignment="Start"
+                       TextWrapping="Wrap" />
+            <TextBlock Grid.Row="2"
+                       HorizontalAlignment="Center"
+                       Text="{Binding Developer}"
+                       TextAlignment="Start"
+                       TextWrapping="Wrap" />
+            <StackPanel Grid.ColumnSpan="2" Grid.Row="3" 
+                        HorizontalAlignment="Center" 
+                        Orientation="Horizontal" Margin="0 10, 0, 0" 
+                        Spacing="5">
+                <Button
+                    Click="PlayabilityStatus_OnClick"
+                    HorizontalContentAlignment="Left"
+                    VerticalAlignment="Center"
+                    IsVisible="{Binding HasPlayabilityInfo}"
+                    Background="{DynamicResource AppListBackgroundColor}"
+                    Padding="0">
+                    <TextBlock
+                        Margin="1.5"
+                        Tag="{Binding IdString}"
+                        Text="{Binding LocalizedStatus}"
+                        Foreground="{Binding 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>
+                <Button
+                    Click="IdString_OnClick"
+                    HorizontalContentAlignment="Left"
+                    VerticalAlignment="Center"
+                    Background="{DynamicResource AppListBackgroundColor}"
+                    Padding="0">
+                    <TextBlock
+                        Margin="1.5"
+                        HorizontalAlignment="Stretch"
+                        Text="{Binding IdString}"
+                        TextAlignment="Start"
+                        TextWrapping="Wrap" />
+                </Button>
+            </StackPanel>
+        </Grid>
+        <Separator Margin="0, 10, 0, 10" />
+        <Grid ColumnDefinitions="Auto,*,Auto">
+            <StackPanel Grid.Column="0"
+                        Margin="10,0,0,0"
+                        HorizontalAlignment="Left"
+                        VerticalAlignment="Top"
+                        Orientation="Vertical"
+                        Spacing="5">
+                <TextBlock
+                    HorizontalAlignment="Stretch"
+                    Text="{Binding FileExtension}"
+                    TextAlignment="Start"
+                    TextWrapping="Wrap" />
+                <TextBlock
+                    HorizontalAlignment="Stretch"
+                    Text="{Binding Converter={helpers:MultiplayerInfoConverter}}"
+                    TextAlignment="Start"
+                    TextWrapping="Wrap" />
+            </StackPanel>
+            <StackPanel
+                Grid.Column="2"
+                Margin="0,0,10,0"
+                HorizontalAlignment="Right"
+                VerticalAlignment="Top"
+                Orientation="Vertical"
+                Spacing="5">
+                <TextBlock
+                    HorizontalAlignment="Stretch"
+                    Text="{Binding LastPlayedString}"
+                    TextAlignment="End"
+                    TextWrapping="Wrap" />
+                <TextBlock
+                    HorizontalAlignment="Stretch"
+                    Text="{Binding TimePlayedString}"
+                    IsVisible="{Binding HasPlayedPreviously}"
+                    TextAlignment="End"
+                    TextWrapping="Wrap" />
+                <TextBlock
+                    HorizontalAlignment="Stretch"
+                    Text="{Binding FileSizeString}"
+                    TextAlignment="End"
+                    TextWrapping="Wrap" />
+            </StackPanel>
+        </Grid>
+    </StackPanel>
+</UserControl>

+ 84 - 0
src/Ryujinx/UI/Controls/ApplicationDataView.axaml.cs

@@ -0,0 +1,84 @@
+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()
+            {
+                PrimaryButtonText = string.Empty,
+                SecondaryButtonText = string.Empty,
+                CloseButtonText = LocaleManager.Instance[LocaleKeys.SettingsButtonClose],
+                Content = new ApplicationDataView { DataContext = 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})");
+        }
+    }
+}
+