UI: Add keybinds to useful things

This commit is contained in:
Evan Husted 2024-10-19 16:39:21 -05:00
parent 59b3ff7802
commit 741eba2798
13 changed files with 88 additions and 70 deletions

View file

@ -47,7 +47,7 @@ namespace Ryujinx.Ava.UI.Models
TitleId = info.ProgramId; TitleId = info.ProgramId;
UserId = info.UserId; UserId = info.UserId;
var appData = MainWindow.MainWindowViewModel.Applications.FirstOrDefault(x => x.IdString.Equals(TitleIdString, StringComparison.OrdinalIgnoreCase)); var appData = App.MainWindow.ViewModel.Applications.FirstOrDefault(x => x.IdString.Equals(TitleIdString, StringComparison.OrdinalIgnoreCase));
InGameList = appData != null; InGameList = appData != null;

View file

@ -33,7 +33,7 @@ namespace Ryujinx.Ava.UI.ViewModels
private readonly string _amiiboJsonPath; private readonly string _amiiboJsonPath;
private readonly byte[] _amiiboLogoBytes; private readonly byte[] _amiiboLogoBytes;
private readonly HttpClient _httpClient; private readonly HttpClient _httpClient;
private readonly StyleableAppWindow _owner; private readonly AmiiboWindow _owner;
private Bitmap _amiiboImage; private Bitmap _amiiboImage;
private List<AmiiboApi> _amiiboList; private List<AmiiboApi> _amiiboList;
@ -49,7 +49,7 @@ namespace Ryujinx.Ava.UI.ViewModels
private static readonly AmiiboJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions()); private static readonly AmiiboJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
public AmiiboWindowViewModel(StyleableAppWindow owner, string lastScannedAmiiboId, string titleId) public AmiiboWindowViewModel(AmiiboWindow owner, string lastScannedAmiiboId, string titleId)
{ {
_owner = owner; _owner = owner;
@ -186,6 +186,22 @@ namespace Ryujinx.Ava.UI.ViewModels
} }
} }
public void Scan()
{
if (AmiiboSelectedIndex > -1)
{
_owner.ScannedAmiibo = AmiiboList[AmiiboSelectedIndex];
_owner.IsScanned = true;
_owner.Close();
}
}
public void Cancel()
{
_owner.IsScanned = false;
_owner.Close();
}
public void Dispose() public void Dispose()
{ {
GC.SuppressFinalize(this); GC.SuppressFinalize(this);

View file

@ -110,6 +110,8 @@ namespace Ryujinx.Ava.UI.ViewModels
public ApplicationData ListSelectedApplication; public ApplicationData ListSelectedApplication;
public ApplicationData GridSelectedApplication; public ApplicationData GridSelectedApplication;
public MainWindow Window { get; init; }
internal AppHost AppHost { get; set; } internal AppHost AppHost { get; set; }
public MainWindowViewModel() public MainWindowViewModel()
@ -1424,7 +1426,7 @@ namespace Ryujinx.Ava.UI.ViewModels
public async Task ExitCurrentState() public async Task ExitCurrentState()
{ {
if (WindowState == WindowState.FullScreen) if (WindowState == MainWindow.FullScreenWindowState)
{ {
ToggleFullscreen(); ToggleFullscreen();
} }
@ -1710,6 +1712,28 @@ namespace Ryujinx.Ava.UI.ViewModels
}); });
} }
public async Task OpenAmiiboWindow()
{
if (!IsAmiiboRequested)
return;
if (AppHost.Device.System.SearchingForAmiibo(out int deviceId))
{
string titleId = AppHost.Device.Processes.ActiveApplication.ProgramIdText.ToUpper();
AmiiboWindow window = new(ShowAll, LastScannedAmiiboId, titleId);
await window.ShowDialog(Window);
if (window.IsScanned)
{
ShowAll = window.ViewModel.ShowAllAmiibo;
LastScannedAmiiboId = window.ScannedAmiibo.GetId();
AppHost.Device.System.ScanAmiibo(deviceId, LastScannedAmiiboId, window.ViewModel.UseRandomUuid);
}
}
}
public void ToggleFullscreen() public void ToggleFullscreen()
{ {
if (Environment.TickCount64 - LastFullscreenToggle < HotKeyPressDelayMs) if (Environment.TickCount64 - LastFullscreenToggle < HotKeyPressDelayMs)
@ -1719,7 +1743,7 @@ namespace Ryujinx.Ava.UI.ViewModels
LastFullscreenToggle = Environment.TickCount64; LastFullscreenToggle = Environment.TickCount64;
if (WindowState == WindowState.FullScreen) if (WindowState is not WindowState.Normal)
{ {
WindowState = WindowState.Normal; WindowState = WindowState.Normal;
@ -1730,7 +1754,7 @@ namespace Ryujinx.Ava.UI.ViewModels
} }
else else
{ {
WindowState = WindowState.FullScreen; WindowState = MainWindow.FullScreenWindowState;
if (IsGameRunning) if (IsGameRunning)
{ {
@ -1738,7 +1762,7 @@ namespace Ryujinx.Ava.UI.ViewModels
} }
} }
IsFullScreen = WindowState == WindowState.FullScreen; IsFullScreen = WindowState == MainWindow.FullScreenWindowState;
} }
public static void SaveConfig() public static void SaveConfig()

View file

@ -240,6 +240,7 @@
Click="OpenAmiiboWindow" Click="OpenAmiiboWindow"
Header="{locale:Locale MenuBarActionsScanAmiibo}" Header="{locale:Locale MenuBarActionsScanAmiibo}"
Icon="{icon:Icon mdi-cube-scan}" Icon="{icon:Icon mdi-cube-scan}"
InputGesture="Ctrl + A"
IsEnabled="{Binding IsAmiiboRequested}" /> IsEnabled="{Binding IsAmiiboRequested}" />
<MenuItem <MenuItem
Command="{Binding TakeScreenshot}" Command="{Binding TakeScreenshot}"

View file

@ -144,26 +144,7 @@ namespace Ryujinx.Ava.UI.Views.Main
} }
public async void OpenAmiiboWindow(object sender, RoutedEventArgs e) public async void OpenAmiiboWindow(object sender, RoutedEventArgs e)
{ => await ViewModel.OpenAmiiboWindow();
if (!ViewModel.IsAmiiboRequested)
return;
if (ViewModel.AppHost.Device.System.SearchingForAmiibo(out int deviceId))
{
string titleId = ViewModel.AppHost.Device.Processes.ActiveApplication.ProgramIdText.ToUpper();
AmiiboWindow window = new(ViewModel.ShowAll, ViewModel.LastScannedAmiiboId, titleId);
await window.ShowDialog(Window);
if (window.IsScanned)
{
ViewModel.ShowAll = window.ViewModel.ShowAllAmiibo;
ViewModel.LastScannedAmiiboId = window.ScannedAmiibo.GetId();
ViewModel.AppHost.Device.System.ScanAmiibo(deviceId, ViewModel.LastScannedAmiiboId, window.ViewModel.UseRandomUuid);
}
}
}
public async void OpenCheatManagerForCurrentApp(object sender, RoutedEventArgs e) public async void OpenCheatManagerForCurrentApp(object sender, RoutedEventArgs e)
{ {

View file

@ -45,16 +45,23 @@
<CheckBox Margin="10" Grid.Column="0" VerticalContentAlignment="Center" <CheckBox Margin="10" Grid.Column="0" VerticalContentAlignment="Center"
IsChecked="{Binding ShowAllAmiibo}" IsChecked="{Binding ShowAllAmiibo}"
Content="{locale:Locale AmiiboOptionsShowAllLabel}" /> Content="{locale:Locale AmiiboOptionsShowAllLabel}" />
<CheckBox Margin="10" VerticalContentAlignment="Center" Grid.Column="1" IsChecked="{Binding UseRandomUuid}" <CheckBox HotKey="H"
Margin="10" VerticalContentAlignment="Center" Grid.Column="1"
IsChecked="{Binding UseRandomUuid}"
Content="{locale:Locale AmiiboOptionsUsRandomTagLabel}" /> Content="{locale:Locale AmiiboOptionsUsRandomTagLabel}" />
<Button Grid.Column="3"
<Button Grid.Column="3" IsEnabled="{Binding EnableScanning}" Width="80" IsEnabled="{Binding EnableScanning}"
Content="{locale:Locale AmiiboScanButtonLabel}" Name="ScanButton" Width="80"
Name="ScanButton"
HotKey="Return"
Content="{locale:Locale AmiiboScanButtonLabel}"
Click="ScanButton_Click" /> Click="ScanButton_Click" />
<Button Grid.Column="4" <Button Grid.Column="4"
Margin="10,0" Margin="10,0"
Width="80" Width="80"
Name="CancelButton" Name="CancelButton"
HotKey="Escape"
Content="{locale:Locale InputDialogCancel}"
Click="CancelButton_Click" /> Click="CancelButton_Click" />
</Grid> </Grid>
</Grid> </Grid>

View file

@ -9,13 +9,11 @@ namespace Ryujinx.Ava.UI.Windows
{ {
public AmiiboWindow(bool showAll, string lastScannedAmiiboId, string titleId) public AmiiboWindow(bool showAll, string lastScannedAmiiboId, string titleId)
{ {
ViewModel = new AmiiboWindowViewModel(this, lastScannedAmiiboId, titleId) DataContext = ViewModel = new AmiiboWindowViewModel(this, lastScannedAmiiboId, titleId)
{ {
ShowAllAmiibo = showAll, ShowAllAmiibo = showAll,
}; };
DataContext = ViewModel;
InitializeComponent(); InitializeComponent();
Title = App.FormatTitle(LocaleKeys.Amiibo); Title = App.FormatTitle(LocaleKeys.Amiibo);
@ -23,9 +21,7 @@ namespace Ryujinx.Ava.UI.Windows
public AmiiboWindow() public AmiiboWindow()
{ {
ViewModel = new AmiiboWindowViewModel(this, string.Empty, string.Empty); DataContext = ViewModel = new AmiiboWindowViewModel(this, string.Empty, string.Empty);
DataContext = ViewModel;
InitializeComponent(); InitializeComponent();
@ -37,23 +33,10 @@ namespace Ryujinx.Ava.UI.Windows
public bool IsScanned { get; set; } public bool IsScanned { get; set; }
public AmiiboApi ScannedAmiibo { get; set; } public AmiiboApi ScannedAmiibo { get; set; }
public AmiiboWindowViewModel ViewModel { get; set; } public AmiiboWindowViewModel ViewModel;
private void ScanButton_Click(object sender, RoutedEventArgs e) private void ScanButton_Click(object sender, RoutedEventArgs e) => ViewModel.Scan();
{
if (ViewModel.AmiiboSelectedIndex > -1)
{
ScannedAmiibo = ViewModel.AmiiboList[ViewModel.AmiiboSelectedIndex];
IsScanned = true;
Close();
}
}
private void CancelButton_Click(object sender, RoutedEventArgs e) private void CancelButton_Click(object sender, RoutedEventArgs e) => ViewModel.Cancel();
{
IsScanned = false;
Close();
}
} }
} }

View file

@ -1,4 +1,4 @@
<window:StyleableAppWindow <window:StyleableAppWindow
x:Class="Ryujinx.Ava.UI.Windows.CheatWindow" x:Class="Ryujinx.Ava.UI.Windows.CheatWindow"
xmlns="https://github.com/avaloniaui" xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
@ -98,6 +98,7 @@
Name="SaveButton" Name="SaveButton"
MinWidth="90" MinWidth="90"
Margin="5" Margin="5"
HotKey="Ctrl+S"
Command="{Binding Save}" Command="{Binding Save}"
IsVisible="{Binding !NoCheatsFound}"> IsVisible="{Binding !NoCheatsFound}">
<TextBlock Text="{locale:Locale SettingsButtonSave}" /> <TextBlock Text="{locale:Locale SettingsButtonSave}" />
@ -106,6 +107,7 @@
Name="CancelButton" Name="CancelButton"
MinWidth="90" MinWidth="90"
Margin="5" Margin="5"
HotKey="Escape"
Command="{Binding Close}"> Command="{Binding Close}">
<TextBlock Text="{locale:Locale InputDialogCancel}" /> <TextBlock Text="{locale:Locale InputDialogCancel}" />
</Button> </Button>

View file

@ -40,6 +40,7 @@
<KeyBinding Gesture="Ctrl+Cmd+F" Command="{Binding ToggleFullscreen}" /> <KeyBinding Gesture="Ctrl+Cmd+F" Command="{Binding ToggleFullscreen}" />
<KeyBinding Gesture="F9" Command="{Binding ToggleDockMode}" /> <KeyBinding Gesture="F9" Command="{Binding ToggleDockMode}" />
<KeyBinding Gesture="Escape" Command="{Binding ExitCurrentState}" /> <KeyBinding Gesture="Escape" Command="{Binding ExitCurrentState}" />
<KeyBinding Gesture="Ctrl+A" Command="{Binding OpenAmiiboWindow}" />
</Window.KeyBindings> </Window.KeyBindings>
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" RowDefinitions="*"> <Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" RowDefinitions="*">
<helpers:OffscreenTextBox IsEnabled="False" Opacity="0" Name="HiddenTextBox" IsHitTestVisible="False" IsTabStop="False" /> <helpers:OffscreenTextBox IsEnabled="False" Opacity="0" Name="HiddenTextBox" IsHitTestVisible="False" IsTabStop="False" />

View file

@ -37,8 +37,6 @@ namespace Ryujinx.Ava.UI.Windows
{ {
public partial class MainWindow : StyleableAppWindow public partial class MainWindow : StyleableAppWindow
{ {
internal static MainWindowViewModel MainWindowViewModel { get; private set; }
public MainWindowViewModel ViewModel { get; } public MainWindowViewModel ViewModel { get; }
internal readonly AvaHostUIHandler UiHandler; internal readonly AvaHostUIHandler UiHandler;
@ -69,9 +67,20 @@ namespace Ryujinx.Ava.UI.Windows
public readonly double StatusBarHeight; public readonly double StatusBarHeight;
public readonly double MenuBarHeight; public readonly double MenuBarHeight;
// The special window decoration from AppWindow in FluentAvalonia is only present on Windows;
// and as such optimizing for the fact that the menu bar and the title bar are the same is only needed on Windows.
// Maximized is considered superior to FullScreen on Windows in this case because you get the benefits of being in full screen,
// while still being able to use the standard 3 window controls in the top right to minimize, make the window smaller, or close the app.
public static readonly WindowState FullScreenWindowState =
OperatingSystem.IsWindows() ? WindowState.Maximized : WindowState.FullScreen;
public MainWindow() public MainWindow()
{ {
DataContext = ViewModel = MainWindowViewModel = new MainWindowViewModel(); DataContext = ViewModel = new MainWindowViewModel
{
Window = this
};
InitializeComponent(); InitializeComponent();
Load(); Load();
@ -184,7 +193,7 @@ namespace Ryujinx.Ava.UI.Windows
ViewModel.ShowContent = true; ViewModel.ShowContent = true;
ViewModel.IsLoadingIndeterminate = false; ViewModel.IsLoadingIndeterminate = false;
if (startFullscreen && ViewModel.WindowState != WindowState.FullScreen) if (startFullscreen && ViewModel.WindowState != MainWindow.FullScreenWindowState)
{ {
ViewModel.ToggleFullscreen(); ViewModel.ToggleFullscreen();
} }
@ -196,7 +205,7 @@ namespace Ryujinx.Ava.UI.Windows
ViewModel.ShowLoadProgress = true; ViewModel.ShowLoadProgress = true;
ViewModel.IsLoadingIndeterminate = true; ViewModel.IsLoadingIndeterminate = true;
if (startFullscreen && ViewModel.WindowState != WindowState.FullScreen) if (startFullscreen && ViewModel.WindowState != MainWindow.FullScreenWindowState)
{ {
ViewModel.ToggleFullscreen(); ViewModel.ToggleFullscreen();
} }

View file

@ -14,7 +14,7 @@ namespace Ryujinx.Ava.UI.Windows
{ {
public partial class ModManagerWindow : UserControl public partial class ModManagerWindow : UserControl
{ {
public ModManagerViewModel ViewModel; public readonly ModManagerViewModel ViewModel;
public ModManagerWindow() public ModManagerWindow()
{ {

View file

@ -10,14 +10,13 @@ namespace Ryujinx.Ava.UI.Windows
{ {
public partial class SettingsWindow : StyleableAppWindow public partial class SettingsWindow : StyleableAppWindow
{ {
internal SettingsViewModel ViewModel { get; set; } internal readonly SettingsViewModel ViewModel;
public SettingsWindow(VirtualFileSystem virtualFileSystem, ContentManager contentManager) public SettingsWindow(VirtualFileSystem virtualFileSystem, ContentManager contentManager)
{ {
Title = App.FormatTitle(LocaleKeys.Settings); Title = App.FormatTitle(LocaleKeys.Settings);
ViewModel = new SettingsViewModel(virtualFileSystem, contentManager); DataContext = ViewModel = new SettingsViewModel(virtualFileSystem, contentManager);
DataContext = ViewModel;
ViewModel.CloseWindow += Close; ViewModel.CloseWindow += Close;
ViewModel.SaveSettingsEvent += SaveSettings; ViewModel.SaveSettingsEvent += SaveSettings;
@ -28,8 +27,7 @@ namespace Ryujinx.Ava.UI.Windows
public SettingsWindow() public SettingsWindow()
{ {
ViewModel = new SettingsViewModel(); DataContext = ViewModel = new SettingsViewModel();
DataContext = ViewModel;
InitializeComponent(); InitializeComponent();
Load(); Load();

View file

@ -1,13 +1,9 @@
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Media.Imaging;
using Avalonia.Platform; using Avalonia.Platform;
using FluentAvalonia.UI.Windowing; using FluentAvalonia.UI.Windowing;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
using Ryujinx.UI.Common.Configuration;
using System.IO;
using System.Reflection;
namespace Ryujinx.Ava.UI.Windows namespace Ryujinx.Ava.UI.Windows
{ {