misc: Canary-specific naming & other small changes I had that I need to push.

This commit is contained in:
Evan Husted 2024-11-06 18:23:21 -06:00
parent 36c374cc7a
commit 730ba44043
11 changed files with 200 additions and 229 deletions

View file

@ -23,8 +23,10 @@ namespace Ryujinx.Ava
{
internal static string FormatTitle(LocaleKeys? windowTitleKey = null)
=> windowTitleKey is null
? $"Ryujinx {Program.Version}"
: $"Ryujinx {Program.Version} - {LocaleManager.Instance[windowTitleKey.Value]}";
? $"{FullAppName} {Program.Version}"
: $"{FullAppName} {Program.Version} - {LocaleManager.Instance[windowTitleKey.Value]}";
public static readonly string FullAppName = ReleaseInformation.IsCanaryBuild ? "Ryujinx Canary" : "Ryujinx";
public static MainWindow MainWindow => Current!
.ApplicationLifetime.Cast<IClassicDesktopStyleApplicationLifetime>()

View file

@ -2,19 +2,38 @@
using Avalonia.Markup.Xaml;
using Avalonia.Markup.Xaml.MarkupExtensions;
using Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings;
using Gommon;
using System;
// ReSharper disable VirtualMemberNeverOverridden.Global
// ReSharper disable MemberCanBeProtected.Global
// ReSharper disable MemberCanBePrivate.Global
#nullable enable
namespace Ryujinx.Ava.Common.Markup
{
internal abstract class BasicMarkupExtension : MarkupExtension
internal abstract class BasicMarkupExtension<T> : MarkupExtension
{
protected abstract ClrPropertyInfo PropertyInfo { get; }
public override object ProvideValue(IServiceProvider serviceProvider) =>
new CompiledBindingExtension(
new CompiledBindingPathBuilder()
.Property(PropertyInfo, PropertyInfoAccessorFactory.CreateInpcPropertyAccessor)
.Build()
).ProvideValue(serviceProvider);
public virtual string Name => "Item";
public virtual Action<object, T?>? Setter => null;
protected abstract T? GetValue();
protected virtual void ConfigureBindingExtension(CompiledBindingExtension _) { }
private ClrPropertyInfo PropertyInfo =>
new(Name,
_ => GetValue(),
Setter as Action<object, object?>,
typeof(T));
public override object ProvideValue(IServiceProvider serviceProvider)
=> new CompiledBindingExtension(
new CompiledBindingPathBuilder()
.Property(PropertyInfo, PropertyInfoAccessorFactory.CreateInpcPropertyAccessor)
.Build()
)
.Apply(ConfigureBindingExtension)
.ProvideValue(serviceProvider);
}
}

View file

@ -1,51 +1,24 @@
using Avalonia.Data.Core;
using Avalonia.Markup.Xaml;
using Avalonia.Markup.Xaml.MarkupExtensions;
using Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings;
using Projektanker.Icons.Avalonia;
using Ryujinx.Ava.Common.Locale;
using System;
namespace Ryujinx.Ava.Common.Markup
{
internal class IconExtension(string iconString) : BasicMarkupExtension
internal class IconExtension(string iconString) : BasicMarkupExtension<Icon>
{
protected override ClrPropertyInfo PropertyInfo
=> new(
"Item",
_ => new Icon { Value = iconString },
null,
typeof(Icon)
);
protected override Icon GetValue() => new() { Value = iconString };
}
internal class SpinningIconExtension(string iconString) : BasicMarkupExtension
internal class SpinningIconExtension(string iconString) : BasicMarkupExtension<Icon>
{
protected override ClrPropertyInfo PropertyInfo
=> new(
"Item",
_ => new Icon { Value = iconString, Animation = IconAnimation.Spin },
null,
typeof(Icon)
);
protected override Icon GetValue() => new() { Value = iconString, Animation = IconAnimation.Spin };
}
internal class LocaleExtension(LocaleKeys key) : MarkupExtension
internal class LocaleExtension(LocaleKeys key) : BasicMarkupExtension<string>
{
private ClrPropertyInfo PropertyInfo
=> new(
"Item",
_ => LocaleManager.Instance[key],
null,
typeof(string)
);
public override object ProvideValue(IServiceProvider serviceProvider) =>
new CompiledBindingExtension(
new CompiledBindingPathBuilder()
.Property(PropertyInfo, PropertyInfoAccessorFactory.CreateInpcPropertyAccessor)
.Build()
) { Source = LocaleManager.Instance }
.ProvideValue(serviceProvider);
protected override string GetValue() => LocaleManager.Instance[key];
protected override void ConfigureBindingExtension(CompiledBindingExtension bindingExtension)
=> bindingExtension.Source = LocaleManager.Instance;
}
}

View file

@ -23,21 +23,15 @@ namespace Ryujinx.Ava.Input
public bool IsConnected => true;
public GamepadFeaturesFlag Features => GamepadFeaturesFlag.None;
private class ButtonMappingEntry
private class ButtonMappingEntry(GamepadButtonInputId to, Key from)
{
public readonly Key From;
public readonly GamepadButtonInputId To;
public ButtonMappingEntry(GamepadButtonInputId to, Key from)
{
To = to;
From = from;
}
public readonly GamepadButtonInputId To = to;
public readonly Key From = from;
}
public AvaloniaKeyboard(AvaloniaKeyboardDriver driver, string id, string name)
{
_buttonsUserMapping = new List<ButtonMappingEntry>();
_buttonsUserMapping = [];
_driver = driver;
Id = id;

View file

@ -127,11 +127,11 @@ namespace Ryujinx.Ava.UI.Applet
try
{
_parent.ViewModel.AppHost.NpadManager.BlockInputUpdates();
var response = await SwkbdAppletDialog.ShowInputDialog(LocaleManager.Instance[LocaleKeys.SoftwareKeyboard], args);
(UserResult result, string userInput) = await SwkbdAppletDialog.ShowInputDialog(LocaleManager.Instance[LocaleKeys.SoftwareKeyboard], args);
if (response.Result == UserResult.Ok)
if (result == UserResult.Ok)
{
inputText = response.Input;
inputText = userInput;
okPressed = true;
}
}

View file

@ -33,7 +33,7 @@ namespace Ryujinx.Ava.UI.Views.Input
{
base.OnPointerReleased(e);
if (_currentAssigner != null && _currentAssigner.ToggledButton != null && !_currentAssigner.ToggledButton.IsPointerOver)
if (_currentAssigner is { ToggledButton.IsPointerOver: false })
{
_currentAssigner.Cancel();
}
@ -41,143 +41,146 @@ namespace Ryujinx.Ava.UI.Views.Input
private void Button_IsCheckedChanged(object sender, RoutedEventArgs e)
{
if (sender is ToggleButton button)
if (sender is not ToggleButton button)
return;
if (button.IsChecked is true)
{
if ((bool)button.IsChecked)
if (_currentAssigner != null && button == _currentAssigner.ToggledButton)
{
if (_currentAssigner != null && button == _currentAssigner.ToggledButton)
{
return;
}
if (_currentAssigner == null)
{
_currentAssigner = new ButtonKeyAssigner(button);
Focus(NavigationMethod.Pointer);
PointerPressed += MouseClick;
if (DataContext is not KeyboardInputViewModel viewModel)
return;
}
if (_currentAssigner == null)
IKeyboard keyboard =
(IKeyboard)viewModel.ParentModel.AvaloniaKeyboardDriver.GetGamepad("0"); // Open Avalonia keyboard for cancel operations.
IButtonAssigner assigner =
new KeyboardKeyAssigner((IKeyboard)viewModel.ParentModel.SelectedGamepad);
_currentAssigner.ButtonAssigned += (_, e) =>
{
_currentAssigner = new ButtonKeyAssigner(button);
Focus(NavigationMethod.Pointer);
PointerPressed += MouseClick;
var viewModel = (DataContext as KeyboardInputViewModel);
IKeyboard keyboard = (IKeyboard)viewModel.ParentModel.AvaloniaKeyboardDriver.GetGamepad("0"); // Open Avalonia keyboard for cancel operations.
IButtonAssigner assigner = CreateButtonAssigner();
_currentAssigner.ButtonAssigned += (sender, e) =>
if (e.ButtonValue.HasValue)
{
if (e.ButtonValue.HasValue)
var buttonValue = e.ButtonValue.Value;
viewModel.ParentModel.IsModified = true;
switch (button.Name)
{
var buttonValue = e.ButtonValue.Value;
viewModel.ParentModel.IsModified = true;
switch (button.Name)
{
case "ButtonZl":
viewModel.Config.ButtonZl = buttonValue.AsHidType<Key>();
break;
case "ButtonL":
viewModel.Config.ButtonL = buttonValue.AsHidType<Key>();
break;
case "ButtonMinus":
viewModel.Config.ButtonMinus = buttonValue.AsHidType<Key>();
break;
case "LeftStickButton":
viewModel.Config.LeftStickButton = buttonValue.AsHidType<Key>();
break;
case "LeftStickUp":
viewModel.Config.LeftStickUp = buttonValue.AsHidType<Key>();
break;
case "LeftStickDown":
viewModel.Config.LeftStickDown = buttonValue.AsHidType<Key>();
break;
case "LeftStickRight":
viewModel.Config.LeftStickRight = buttonValue.AsHidType<Key>();
break;
case "LeftStickLeft":
viewModel.Config.LeftStickLeft = buttonValue.AsHidType<Key>();
break;
case "DpadUp":
viewModel.Config.DpadUp = buttonValue.AsHidType<Key>();
break;
case "DpadDown":
viewModel.Config.DpadDown = buttonValue.AsHidType<Key>();
break;
case "DpadLeft":
viewModel.Config.DpadLeft = buttonValue.AsHidType<Key>();
break;
case "DpadRight":
viewModel.Config.DpadRight = buttonValue.AsHidType<Key>();
break;
case "LeftButtonSr":
viewModel.Config.LeftButtonSr = buttonValue.AsHidType<Key>();
break;
case "LeftButtonSl":
viewModel.Config.LeftButtonSl = buttonValue.AsHidType<Key>();
break;
case "RightButtonSr":
viewModel.Config.RightButtonSr = buttonValue.AsHidType<Key>();
break;
case "RightButtonSl":
viewModel.Config.RightButtonSl = buttonValue.AsHidType<Key>();
break;
case "ButtonZr":
viewModel.Config.ButtonZr = buttonValue.AsHidType<Key>();
break;
case "ButtonR":
viewModel.Config.ButtonR = buttonValue.AsHidType<Key>();
break;
case "ButtonPlus":
viewModel.Config.ButtonPlus = buttonValue.AsHidType<Key>();
break;
case "ButtonA":
viewModel.Config.ButtonA = buttonValue.AsHidType<Key>();
break;
case "ButtonB":
viewModel.Config.ButtonB = buttonValue.AsHidType<Key>();
break;
case "ButtonX":
viewModel.Config.ButtonX = buttonValue.AsHidType<Key>();
break;
case "ButtonY":
viewModel.Config.ButtonY = buttonValue.AsHidType<Key>();
break;
case "RightStickButton":
viewModel.Config.RightStickButton = buttonValue.AsHidType<Key>();
break;
case "RightStickUp":
viewModel.Config.RightStickUp = buttonValue.AsHidType<Key>();
break;
case "RightStickDown":
viewModel.Config.RightStickDown = buttonValue.AsHidType<Key>();
break;
case "RightStickRight":
viewModel.Config.RightStickRight = buttonValue.AsHidType<Key>();
break;
case "RightStickLeft":
viewModel.Config.RightStickLeft = buttonValue.AsHidType<Key>();
break;
}
case "ButtonZl":
viewModel.Config.ButtonZl = buttonValue.AsHidType<Key>();
break;
case "ButtonL":
viewModel.Config.ButtonL = buttonValue.AsHidType<Key>();
break;
case "ButtonMinus":
viewModel.Config.ButtonMinus = buttonValue.AsHidType<Key>();
break;
case "LeftStickButton":
viewModel.Config.LeftStickButton = buttonValue.AsHidType<Key>();
break;
case "LeftStickUp":
viewModel.Config.LeftStickUp = buttonValue.AsHidType<Key>();
break;
case "LeftStickDown":
viewModel.Config.LeftStickDown = buttonValue.AsHidType<Key>();
break;
case "LeftStickRight":
viewModel.Config.LeftStickRight = buttonValue.AsHidType<Key>();
break;
case "LeftStickLeft":
viewModel.Config.LeftStickLeft = buttonValue.AsHidType<Key>();
break;
case "DpadUp":
viewModel.Config.DpadUp = buttonValue.AsHidType<Key>();
break;
case "DpadDown":
viewModel.Config.DpadDown = buttonValue.AsHidType<Key>();
break;
case "DpadLeft":
viewModel.Config.DpadLeft = buttonValue.AsHidType<Key>();
break;
case "DpadRight":
viewModel.Config.DpadRight = buttonValue.AsHidType<Key>();
break;
case "LeftButtonSr":
viewModel.Config.LeftButtonSr = buttonValue.AsHidType<Key>();
break;
case "LeftButtonSl":
viewModel.Config.LeftButtonSl = buttonValue.AsHidType<Key>();
break;
case "RightButtonSr":
viewModel.Config.RightButtonSr = buttonValue.AsHidType<Key>();
break;
case "RightButtonSl":
viewModel.Config.RightButtonSl = buttonValue.AsHidType<Key>();
break;
case "ButtonZr":
viewModel.Config.ButtonZr = buttonValue.AsHidType<Key>();
break;
case "ButtonR":
viewModel.Config.ButtonR = buttonValue.AsHidType<Key>();
break;
case "ButtonPlus":
viewModel.Config.ButtonPlus = buttonValue.AsHidType<Key>();
break;
case "ButtonA":
viewModel.Config.ButtonA = buttonValue.AsHidType<Key>();
break;
case "ButtonB":
viewModel.Config.ButtonB = buttonValue.AsHidType<Key>();
break;
case "ButtonX":
viewModel.Config.ButtonX = buttonValue.AsHidType<Key>();
break;
case "ButtonY":
viewModel.Config.ButtonY = buttonValue.AsHidType<Key>();
break;
case "RightStickButton":
viewModel.Config.RightStickButton = buttonValue.AsHidType<Key>();
break;
case "RightStickUp":
viewModel.Config.RightStickUp = buttonValue.AsHidType<Key>();
break;
case "RightStickDown":
viewModel.Config.RightStickDown = buttonValue.AsHidType<Key>();
break;
case "RightStickRight":
viewModel.Config.RightStickRight = buttonValue.AsHidType<Key>();
break;
case "RightStickLeft":
viewModel.Config.RightStickLeft = buttonValue.AsHidType<Key>();
break;
}
};
_currentAssigner.GetInputAndAssign(assigner, keyboard);
}
else
{
if (_currentAssigner != null)
{
_currentAssigner.Cancel();
_currentAssigner = null;
button.IsChecked = false;
}
}
};
_currentAssigner.GetInputAndAssign(assigner, keyboard);
}
else
{
_currentAssigner?.Cancel();
_currentAssigner = null;
if (_currentAssigner != null)
{
_currentAssigner.Cancel();
_currentAssigner = null;
button.IsChecked = false;
}
}
}
else
{
_currentAssigner?.Cancel();
_currentAssigner = null;
}
}
private void MouseClick(object sender, PointerPressedEventArgs e)
@ -189,15 +192,6 @@ namespace Ryujinx.Ava.UI.Views.Input
PointerPressed -= MouseClick;
}
private IButtonAssigner CreateButtonAssigner()
{
IButtonAssigner assigner;
assigner = new KeyboardKeyAssigner((IKeyboard)(DataContext as KeyboardInputViewModel).ParentModel.SelectedGamepad);
return assigner;
}
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnDetachedFromVisualTree(e);

View file

@ -273,8 +273,8 @@
</MenuItem>
<MenuItem VerticalAlignment="Center" Header="{ext:Locale MenuBarView}">
<MenuItem VerticalAlignment="Center" Header="{ext:Locale MenuBarViewWindow}">
<MenuItem Header="{ext:Locale MenuBarViewWindow720}" Tag="720 1280" Click="ChangeWindowSize_Click" />
<MenuItem Header="{ext:Locale MenuBarViewWindow1080}" Tag="1080 1920" Click="ChangeWindowSize_Click" />
<MenuItem Header="{ext:Locale MenuBarViewWindow720}" Tag="1280 720" Click="ChangeWindowSize_Click" />
<MenuItem Header="{ext:Locale MenuBarViewWindow1080}" Tag="1920 1080" Click="ChangeWindowSize_Click" />
</MenuItem>
</MenuItem>
<MenuItem VerticalAlignment="Center" Header="{ext:Locale MenuBarHelp}">

View file

@ -184,8 +184,10 @@ namespace Ryujinx.Ava.UI.Views.Main
if (sender is not MenuItem { Tag: string resolution })
return;
(int height, int width) = resolution.Split(' ')
.Into(parts => (int.Parse(parts[0]), int.Parse(parts[1])));
(int width, int height) = resolution.Split(' ', 2)
.Into(parts =>
(int.Parse(parts[0]), int.Parse(parts[1]))
);
await Dispatcher.UIThread.InvokeAsync(() =>
{
@ -200,7 +202,7 @@ namespace Ryujinx.Ava.UI.Views.Main
public async void CheckForUpdates(object sender, RoutedEventArgs e)
{
if (Updater.CanUpdate(true))
await Updater.BeginParse(Window, true);
await Window.BeginUpdateAsync(true);
}
public async void OpenXCITrimmerWindow(object sender, RoutedEventArgs e) => await XCITrimmerWindow.Show(ViewModel);

View file

@ -63,8 +63,7 @@ namespace Ryujinx.Ava.UI.Views.User
private async void Import_OnClick(object sender, RoutedEventArgs e)
{
var window = this.GetVisualRoot() as Window;
var result = await window.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
var result = await ((Window)this.GetVisualRoot()!).StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
{
AllowMultiple = false,
FileTypeFilter = new List<FilePickerFileType>

View file

@ -28,6 +28,7 @@ using Ryujinx.UI.Common.Configuration;
using Ryujinx.UI.Common.Helper;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using System.Runtime.Versioning;
using System.Threading;
@ -349,12 +350,12 @@ namespace Ryujinx.Ava.UI.Windows
await Dispatcher.UIThread.InvokeAsync(async () => await UserErrorDialog.ShowUserErrorDialog(UserError.NoKeys));
}
if (ConfigurationState.Instance.CheckUpdatesOnStart && Updater.CanUpdate(false))
if (ConfigurationState.Instance.CheckUpdatesOnStart && Updater.CanUpdate())
{
await Updater.BeginParse(this, false).ContinueWith(task =>
{
Logger.Error?.Print(LogClass.Application, $"Updater Error: {task.Exception}");
}, TaskContinuationOptions.OnlyOnFaulted);
await this.BeginUpdateAsync()
.ContinueWith(
task => Logger.Error?.Print(LogClass.Application, $"Updater Error: {task.Exception}"),
TaskContinuationOptions.OnlyOnFaulted);
}
}
@ -392,30 +393,17 @@ namespace Ryujinx.Ava.UI.Windows
ViewModel.WindowState = ConfigurationState.Instance.UI.WindowStartup.WindowMaximized.Value ? WindowState.Maximized : WindowState.Normal;
if (CheckScreenBounds(savedPoint))
if (Screens.All.Any(screen => screen.Bounds.Contains(savedPoint)))
{
Position = savedPoint;
}
else
{
Logger.Warning?.Print(LogClass.Application, "Failed to find valid start-up coordinates. Defaulting to primary monitor center.");
WindowStartupLocation = WindowStartupLocation.CenterScreen;
}
}
private bool CheckScreenBounds(PixelPoint configPoint)
{
for (int i = 0; i < Screens.ScreenCount; i++)
{
if (Screens.All[i].Bounds.Contains(configPoint))
{
return true;
}
}
Logger.Warning?.Print(LogClass.Application, "Failed to find valid start-up coordinates. Defaulting to primary monitor center.");
return false;
}
private void SaveWindowSizePosition()
{
ConfigurationState.Instance.UI.WindowStartup.WindowMaximized.Value = WindowState == WindowState.Maximized;
@ -507,8 +495,7 @@ namespace Ryujinx.Ava.UI.Windows
private void VolumeStatus_CheckedChanged(object sender, RoutedEventArgs e)
{
var volumeSplitButton = sender as ToggleSplitButton;
if (ViewModel.IsGameRunning)
if (ViewModel.IsGameRunning && sender is ToggleSplitButton volumeSplitButton)
{
if (!volumeSplitButton.IsChecked)
{

View file

@ -32,6 +32,8 @@ namespace Ryujinx.Ava
internal static class Updater
{
private const string GitHubApiUrl = "https://api.github.com";
private const string LatestReleaseUrl = $"{GitHubApiUrl}/repos/{ReleaseInformation.ReleaseChannelOwner}/{ReleaseInformation.ReleaseChannelRepo}/releases/latest";
private static readonly GithubReleasesJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
private static readonly string _homeDir = AppDomain.CurrentDomain.BaseDirectory;
@ -46,9 +48,9 @@ namespace Ryujinx.Ava
private static bool _updateSuccessful;
private static bool _running;
private static readonly string[] _windowsDependencyDirs = Array.Empty<string>();
private static readonly string[] _windowsDependencyDirs = [];
public static async Task BeginParse(Window mainWindow, bool showVersionUpToDate)
public static async Task BeginUpdateAsync(this Window mainWindow, bool showVersionUpToDate = false)
{
if (_running)
{
@ -96,9 +98,8 @@ namespace Ryujinx.Ava
try
{
using HttpClient jsonClient = ConstructHttpClient();
string buildInfoUrl = $"{GitHubApiUrl}/repos/{ReleaseInformation.ReleaseChannelOwner}/{ReleaseInformation.ReleaseChannelRepo}/releases/latest";
string fetchedJson = await jsonClient.GetStringAsync(buildInfoUrl);
string fetchedJson = await jsonClient.GetStringAsync(LatestReleaseUrl);
var fetched = JsonHelper.Deserialize(fetchedJson, _serializerContext.GithubReleasesJsonResponse);
_buildVer = fetched.Name;
@ -159,7 +160,7 @@ namespace Ryujinx.Ava
}
catch
{
Logger.Error?.Print(LogClass.Application, "Failed to convert the received Ryujinx version from Github!");
Logger.Error?.Print(LogClass.Application, $"Failed to convert the received {App.FullAppName} version from GitHub!");
await ContentDialogHelper.CreateWarningDialog(
LocaleManager.Instance[LocaleKeys.DialogUpdaterConvertFailedGithubMessage],
@ -636,7 +637,7 @@ namespace Ryujinx.Ava
taskDialog.Hide();
}
public static bool CanUpdate(bool showWarnings)
public static bool CanUpdate(bool showWarnings = false)
{
#if !DISABLE_UPDATER
if (!NetworkInterface.GetIsNetworkAvailable())