Merge branch 'GreemDev:master' into master

This commit is contained in:
Vladimir Sokolov 2024-10-26 09:48:11 +10:00 committed by GitHub
commit ca5935f468
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
26 changed files with 156 additions and 242 deletions

View File

@ -1,4 +1,4 @@
name: Perform checks name: Build PR
on: on:
pull_request: pull_request:
@ -20,55 +20,6 @@ concurrency:
cancel-in-progress: true cancel-in-progress: true
jobs: jobs:
format:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-dotnet@v4
with:
global-json-file: global.json
- name: Overwrite csc problem matcher
run: echo "::add-matcher::.github/csc.json"
- run: dotnet restore
- name: Print dotnet format version
run: dotnet format --version
- name: Run dotnet format whitespace
run: |
dotnet format whitespace --verify-no-changes --report ./whitespace-report.json -v d
# For some unknown reason this step sometimes fails with exit code 139 (segfault?),
# so in that case we'll try again (3 tries max).
- name: Run dotnet format style
uses: TSRBerry/unstable-commands@v1
with:
commands: dotnet format style --severity info --verify-no-changes --report ./style-report.json -v d
timeout-minutes: 5
retry-codes: 139
# For some unknown reason this step sometimes fails with exit code 139 (segfault?),
# so in that case we'll try again (3 tries max).
- name: Run dotnet format analyzers
uses: TSRBerry/unstable-commands@v1
with:
commands: dotnet format analyzers --severity info --verify-no-changes --report ./analyzers-report.json -v d
timeout-minutes: 5
retry-codes: 139
- name: Upload report
if: failure()
uses: actions/upload-artifact@v4
with:
name: dotnet-format
path: ./*-report.json
pr_build: pr_build:
uses: ./.github/workflows/build.yml uses: ./.github/workflows/build.yml
needs: format
secrets: inherit secrets: inherit

View File

@ -3,9 +3,13 @@
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=SuggestVarOrType_005FSimpleTypes/@EntryIndexedValue">WARNING</s:String> <s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=SuggestVarOrType_005FSimpleTypes/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeStyle/CSharpVarKeywordUsage/ForOtherTypes/@EntryValue">UseExplicitType</s:String> <s:String x:Key="/Default/CodeStyle/CSharpVarKeywordUsage/ForOtherTypes/@EntryValue">UseExplicitType</s:String>
<s:String x:Key="/Default/CodeStyle/CSharpVarKeywordUsage/ForSimpleTypes/@EntryValue">UseExplicitType</s:String> <s:String x:Key="/Default/CodeStyle/CSharpVarKeywordUsage/ForSimpleTypes/@EntryValue">UseExplicitType</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=GL/@EntryIndexedValue">GL</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=SDL/@EntryIndexedValue">SDL</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=SDL/@EntryIndexedValue">OS</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=TypesAndNamespaces/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"&gt;&lt;ExtraRule Prefix="I" Suffix="" Style="AaBb" /&gt;&lt;/Policy&gt;</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=TypesAndNamespaces/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"&gt;&lt;ExtraRule Prefix="I" Suffix="" Style="AaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=a0b4bc4d_002Dd13b_002D4a37_002Db37e_002Dc9c6864e4302/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Any" AccessRightKinds="Any" Description="Types and namespaces"&gt;&lt;ElementKinds&gt;&lt;Kind Name="NAMESPACE" /&gt;&lt;Kind Name="CLASS" /&gt;&lt;Kind Name="STRUCT" /&gt;&lt;Kind Name="ENUM" /&gt;&lt;Kind Name="DELEGATE" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"&gt;&lt;ExtraRule Prefix="I" Suffix="" Style="AaBb" /&gt;&lt;/Policy&gt;&lt;/Policy&gt;</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=a0b4bc4d_002Dd13b_002D4a37_002Db37e_002Dc9c6864e4302/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Any" AccessRightKinds="Any" Description="Types and namespaces"&gt;&lt;ElementKinds&gt;&lt;Kind Name="NAMESPACE" /&gt;&lt;Kind Name="CLASS" /&gt;&lt;Kind Name="STRUCT" /&gt;&lt;Kind Name="ENUM" /&gt;&lt;Kind Name="DELEGATE" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"&gt;&lt;ExtraRule Prefix="I" Suffix="" Style="AaBb" /&gt;&lt;/Policy&gt;&lt;/Policy&gt;</s:String>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EPredefinedNamingRulesToUserRulesUpgrade/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EPredefinedNamingRulesToUserRulesUpgrade/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=amiibo/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=ASET/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=ASET/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Astc/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Astc/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Luma/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Luma/@EntryIndexedValue">True</s:Boolean>

View File

@ -98,7 +98,7 @@ namespace Ryujinx.Common.Configuration
if (IsPathSymlink(BaseDirPath)) if (IsPathSymlink(BaseDirPath))
{ {
Logger.Warning?.Print(LogClass.Application, $"Application data directory is a symlink. This may be unintended."); Logger.Warning?.Print(LogClass.Application, "Application data directory is a symlink. This may be unintended.");
} }
SetupBasePaths(); SetupBasePaths();

View File

@ -212,10 +212,8 @@ namespace Ryujinx.Common.Logging
foreach (var log in logs) foreach (var log in logs)
{ {
if (log.HasValue) if (log.HasValue)
{
levels.Add(log.Value.Level); levels.Add(log.Value.Level);
} }
}
return levels; return levels;
} }
@ -233,6 +231,7 @@ namespace Ryujinx.Common.Logging
case LogLevel.AccessLog : AccessLog = enabled ? new Log(LogLevel.AccessLog) : new Log?(); break; case LogLevel.AccessLog : AccessLog = enabled ? new Log(LogLevel.AccessLog) : new Log?(); break;
case LogLevel.Stub : Stub = enabled ? new Log(LogLevel.Stub) : new Log?(); break; case LogLevel.Stub : Stub = enabled ? new Log(LogLevel.Stub) : new Log?(); break;
case LogLevel.Trace : Trace = enabled ? new Log(LogLevel.Trace) : new Log?(); break; case LogLevel.Trace : Trace = enabled ? new Log(LogLevel.Trace) : new Log?(); break;
case LogLevel.Notice : break;
default: throw new ArgumentException("Unknown Log Level", nameof(logLevel)); default: throw new ArgumentException("Unknown Log Level", nameof(logLevel));
#pragma warning restore IDE0055 #pragma warning restore IDE0055
} }

View File

@ -469,7 +469,7 @@ namespace Ryujinx.Cpu.Jit
{ {
if (size == 0) if (size == 0)
{ {
return Enumerable.Empty<MemoryRange>(); return [];
} }
return GetPhysicalRegionsImpl(va, size); return GetPhysicalRegionsImpl(va, size);

View File

@ -156,6 +156,8 @@ namespace Ryujinx.UI.Common
"0100b7c00933a000", // Pikmin 4 "0100b7c00933a000", // Pikmin 4
"01004ad014bf0000", // Sonic Frontiers "01004ad014bf0000", // Sonic Frontiers
"01005ea01c0fc000", // SONIC X SHADOW GENERATIONS
"01005ea01c0fc001", // ^
"01004d300c5ae000", // Kirby and the Forgotten Land "01004d300c5ae000", // Kirby and the Forgotten Land
"01006b601380e000", // Kirby's Return to Dreamland Deluxe "01006b601380e000", // Kirby's Return to Dreamland Deluxe

View File

@ -66,11 +66,6 @@ namespace Ryujinx.Ava
} }
} }
private void CustomThemeChanged_Event(object sender, ReactiveEventArgs<bool> e)
{
ApplyConfiguredTheme();
}
private void ShowRestartDialog() private void ShowRestartDialog()
{ {
_ = Dispatcher.UIThread.InvokeAsync(async () => _ = Dispatcher.UIThread.InvokeAsync(async () =>
@ -94,10 +89,9 @@ namespace Ryujinx.Ava
}); });
} }
private void ThemeChanged_Event(object sender, ReactiveEventArgs<string> e) private void CustomThemeChanged_Event(object _, ReactiveEventArgs<bool> __) => ApplyConfiguredTheme();
{
ApplyConfiguredTheme(); private void ThemeChanged_Event(object _, ReactiveEventArgs<string> __) => ApplyConfiguredTheme();
}
public void ApplyConfiguredTheme() public void ApplyConfiguredTheme()
{ {

View File

@ -57,7 +57,6 @@ using Key = Ryujinx.Input.Key;
using MouseButton = Ryujinx.Input.MouseButton; using MouseButton = Ryujinx.Input.MouseButton;
using ScalingFilter = Ryujinx.Common.Configuration.ScalingFilter; using ScalingFilter = Ryujinx.Common.Configuration.ScalingFilter;
using Size = Avalonia.Size; using Size = Avalonia.Size;
using Switch = Ryujinx.HLE.Switch;
namespace Ryujinx.Ava namespace Ryujinx.Ava
{ {
@ -130,7 +129,7 @@ namespace Ryujinx.Ava
public ContentManager ContentManager { get; } public ContentManager ContentManager { get; }
public NpadManager NpadManager { get; } public NpadManager NpadManager { get; }
public TouchScreenManager TouchScreenManager { get; } public TouchScreenManager TouchScreenManager { get; }
public Switch Device { get; set; } public HLE.Switch Device { get; set; }
public int Width { get; private set; } public int Width { get; private set; }
public int Height { get; private set; } public int Height { get; private set; }
@ -849,7 +848,7 @@ namespace Ryujinx.Ava
// Initialize Configuration. // Initialize Configuration.
var memoryConfiguration = ConfigurationState.Instance.System.DramSize.Value; var memoryConfiguration = ConfigurationState.Instance.System.DramSize.Value;
Device = new Switch(new HLEConfiguration( Device = new HLE.Switch(new HLEConfiguration(
VirtualFileSystem, VirtualFileSystem,
_viewModel.LibHacHorizonManager, _viewModel.LibHacHorizonManager,
ContentManager, ContentManager,

View File

@ -99,6 +99,9 @@ namespace Ryujinx.Ava.Common.Locale
_ => false _ => false
}; };
public static string FormatDynamicValue(LocaleKeys key, params object[] values)
=> Instance.UpdateAndGetDynamicValue(key, values);
public string UpdateAndGetDynamicValue(LocaleKeys key, params object[] values) public string UpdateAndGetDynamicValue(LocaleKeys key, params object[] values)
{ {
_dynamicValues[key] = values; _dynamicValues[key] = values;
@ -127,9 +130,9 @@ namespace Ryujinx.Ava.Common.Locale
_localeLanguageCode = languageCode; _localeLanguageCode = languageCode;
} }
foreach (var item in locale) foreach ((LocaleKeys key, string val) in locale)
{ {
_localeStrings[item.Key] = item.Value; _localeStrings[key] = val;
} }
OnPropertyChanged("Item"); OnPropertyChanged("Item");
@ -150,11 +153,11 @@ namespace Ryujinx.Ava.Common.Locale
var strings = JsonHelper.Deserialize(languageJson, CommonJsonContext.Default.StringDictionary); var strings = JsonHelper.Deserialize(languageJson, CommonJsonContext.Default.StringDictionary);
foreach (var item in strings) foreach ((string key, string val) in strings)
{ {
if (Enum.TryParse<LocaleKeys>(item.Key, out var key)) if (Enum.TryParse<LocaleKeys>(key, out var localeKey))
{ {
localeStrings[key] = item.Value; localeStrings[localeKey] = val;
} }
} }

View File

@ -1,7 +1,7 @@
using ARMeilleure;
using Avalonia; using Avalonia;
using Avalonia.Threading; using Avalonia.Threading;
using DiscordRPC; using DiscordRPC;
using Gommon;
using Projektanker.Icons.Avalonia; using Projektanker.Icons.Avalonia;
using Projektanker.Icons.Avalonia.FontAwesome; using Projektanker.Icons.Avalonia.FontAwesome;
using Projektanker.Icons.Avalonia.MaterialDesign; using Projektanker.Icons.Avalonia.MaterialDesign;
@ -23,6 +23,7 @@ using Ryujinx.UI.Common.Helper;
using Ryujinx.UI.Common.SystemInfo; using Ryujinx.UI.Common.SystemInfo;
using System; using System;
using System.IO; using System.IO;
using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -103,8 +104,9 @@ namespace Ryujinx.Ava
Console.Title = $"Ryujinx Console {Version}"; Console.Title = $"Ryujinx Console {Version}";
// Hook unhandled exception and process exit events. // Hook unhandled exception and process exit events.
AppDomain.CurrentDomain.UnhandledException += (sender, e) => ProcessUnhandledException(e.ExceptionObject as Exception, e.IsTerminating); AppDomain.CurrentDomain.UnhandledException += (sender, e)
AppDomain.CurrentDomain.ProcessExit += (sender, e) => Exit(); => ProcessUnhandledException(sender, e.ExceptionObject as Exception, e.IsTerminating);
AppDomain.CurrentDomain.ProcessExit += (_, _) => Exit();
// Setup base data directory. // Setup base data directory.
AppDataManager.Initialize(CommandLineState.BaseDirPathArg); AppDataManager.Initialize(CommandLineState.BaseDirPathArg);
@ -189,7 +191,7 @@ namespace Ryujinx.Ava
} }
} }
UseHardwareAcceleration = ConfigurationState.Instance.EnableHardwareAcceleration.Value; UseHardwareAcceleration = ConfigurationState.Instance.EnableHardwareAcceleration;
// Check if graphics backend was overridden // Check if graphics backend was overridden
if (CommandLineState.OverrideGraphicsBackend is not null) if (CommandLineState.OverrideGraphicsBackend is not null)
@ -226,7 +228,13 @@ namespace Ryujinx.Ava
Logger.Notice.Print(LogClass.Application, $"Ryujinx Version: {Version}"); Logger.Notice.Print(LogClass.Application, $"Ryujinx Version: {Version}");
SystemInfo.Gather().Print(); SystemInfo.Gather().Print();
Logger.Notice.Print(LogClass.Application, $"Logs Enabled: {(Logger.GetEnabledLevels().Count == 0 ? "<None>" : string.Join(", ", Logger.GetEnabledLevels()))}"); var enabledLogLevels = Logger.GetEnabledLevels().ToArray();
Logger.Notice.Print(LogClass.Application, $"Logs Enabled: {
(enabledLogLevels.Length is 0
? "<None>"
: enabledLogLevels.JoinToString(", "))
}");
Logger.Notice.Print(LogClass.Application, Logger.Notice.Print(LogClass.Application,
AppDataManager.Mode == AppDataManager.LaunchMode.Custom AppDataManager.Mode == AppDataManager.LaunchMode.Custom
@ -234,22 +242,20 @@ namespace Ryujinx.Ava
: $"Launch Mode: {AppDataManager.Mode}"); : $"Launch Mode: {AppDataManager.Mode}");
} }
private static void ProcessUnhandledException(Exception ex, bool isTerminating) private static void ProcessUnhandledException(object sender, Exception ex, bool isTerminating)
{ {
Logger.Log log = Logger.Error ?? Logger.Notice;
string message = $"Unhandled exception caught: {ex}"; string message = $"Unhandled exception caught: {ex}";
Logger.Error?.PrintMsg(LogClass.Application, message); // ReSharper disable once ConstantConditionalAccessQualifier
if (sender?.GetType()?.AsPrettyString() is {} senderName)
if (Logger.Error == null) log.Print(LogClass.Application, message, senderName);
{ else
Logger.Notice.PrintMsg(LogClass.Application, message); log.PrintMsg(LogClass.Application, message);
}
if (isTerminating) if (isTerminating)
{
Exit(); Exit();
} }
}
public static void Exit() public static void Exit()
{ {

View File

@ -32,14 +32,10 @@ namespace Ryujinx.Ava.UI.Applet
{ {
ManualResetEvent dialogCloseEvent = new(false); ManualResetEvent dialogCloseEvent = new(false);
bool ignoreApplet = ConfigurationState.Instance.IgnoreApplet;
bool okPressed = false; bool okPressed = false;
if (ignoreApplet) if (ConfigurationState.Instance.IgnoreApplet)
{
return false; return false;
}
Dispatcher.UIThread.InvokeAsync(async () => Dispatcher.UIThread.InvokeAsync(async () =>
{ {
@ -74,9 +70,9 @@ namespace Ryujinx.Ava.UI.Applet
UserResult response = await ContentDialogHelper.ShowDeferredContentDialog(_parent, UserResult response = await ContentDialogHelper.ShowDeferredContentDialog(_parent,
title, title,
message, message,
"", string.Empty,
LocaleManager.Instance[LocaleKeys.DialogOpenSettingsWindowLabel], LocaleManager.Instance[LocaleKeys.DialogOpenSettingsWindowLabel],
"", string.Empty,
LocaleManager.Instance[LocaleKeys.SettingsButtonClose], LocaleManager.Instance[LocaleKeys.SettingsButtonClose],
(int)Symbol.Important, (int)Symbol.Important,
deferEvent, deferEvent,
@ -179,12 +175,12 @@ namespace Ryujinx.Ava.UI.Applet
{ {
Title = title, Title = title,
WindowStartupLocation = WindowStartupLocation.CenterScreen, WindowStartupLocation = WindowStartupLocation.CenterScreen,
Width = 400, Width = 400
}; };
object response = await msgDialog.Run(); object response = await msgDialog.Run();
if (response != null && buttons != null && buttons.Length > 1 && (int)response != buttons.Length - 1) if (response != null && buttons is { Length: > 1 } && (int)response != buttons.Length - 1)
{ {
showDetails = true; showDetails = true;
} }

View File

@ -25,9 +25,12 @@ namespace Ryujinx.Ava.UI.Applet
{ {
_parent = parent; _parent = parent;
(_parent.InputManager.KeyboardDriver as AvaloniaKeyboardDriver).KeyPressed += AvaloniaDynamicTextInputHandler_KeyPressed; if (_parent.InputManager.KeyboardDriver is AvaloniaKeyboardDriver avaloniaKeyboardDriver)
(_parent.InputManager.KeyboardDriver as AvaloniaKeyboardDriver).KeyRelease += AvaloniaDynamicTextInputHandler_KeyRelease; {
(_parent.InputManager.KeyboardDriver as AvaloniaKeyboardDriver).TextInput += AvaloniaDynamicTextInputHandler_TextInput; avaloniaKeyboardDriver.KeyPressed += AvaloniaDynamicTextInputHandler_KeyPressed;
avaloniaKeyboardDriver.KeyRelease += AvaloniaDynamicTextInputHandler_KeyRelease;
avaloniaKeyboardDriver.TextInput += AvaloniaDynamicTextInputHandler_TextInput;
}
_hiddenTextBox = _parent.HiddenTextBox; _hiddenTextBox = _parent.HiddenTextBox;
@ -44,7 +47,7 @@ namespace Ryujinx.Ava.UI.Applet
TextChangedEvent?.Invoke(text ?? string.Empty, _hiddenTextBox.SelectionStart, _hiddenTextBox.SelectionEnd, false); TextChangedEvent?.Invoke(text ?? string.Empty, _hiddenTextBox.SelectionStart, _hiddenTextBox.SelectionEnd, false);
} }
private void SelectionChanged(int selection) private void SelectionChanged(int _)
{ {
TextChangedEvent?.Invoke(_hiddenTextBox.Text ?? string.Empty, _hiddenTextBox.SelectionStart, _hiddenTextBox.SelectionEnd, false); TextChangedEvent?.Invoke(_hiddenTextBox.Text ?? string.Empty, _hiddenTextBox.SelectionStart, _hiddenTextBox.SelectionEnd, false);
} }
@ -112,9 +115,12 @@ namespace Ryujinx.Ava.UI.Applet
public void Dispose() public void Dispose()
{ {
(_parent.InputManager.KeyboardDriver as AvaloniaKeyboardDriver).KeyPressed -= AvaloniaDynamicTextInputHandler_KeyPressed; if (_parent.InputManager.KeyboardDriver is AvaloniaKeyboardDriver avaloniaKeyboardDriver)
(_parent.InputManager.KeyboardDriver as AvaloniaKeyboardDriver).KeyRelease -= AvaloniaDynamicTextInputHandler_KeyRelease; {
(_parent.InputManager.KeyboardDriver as AvaloniaKeyboardDriver).TextInput -= AvaloniaDynamicTextInputHandler_TextInput; avaloniaKeyboardDriver.KeyPressed -= AvaloniaDynamicTextInputHandler_KeyPressed;
avaloniaKeyboardDriver.KeyRelease -= AvaloniaDynamicTextInputHandler_KeyRelease;
avaloniaKeyboardDriver.TextInput -= AvaloniaDynamicTextInputHandler_TextInput;
}
_textChangedSubscription?.Dispose(); _textChangedSubscription?.Dispose();
_selectionStartChangedSubscription?.Dispose(); _selectionStartChangedSubscription?.Dispose();

View File

@ -47,42 +47,37 @@ namespace Ryujinx.Ava.UI.Controls
LoadProfiles(); LoadProfiles();
if (contentManager.GetCurrentFirmwareVersion() != null) if (contentManager.GetCurrentFirmwareVersion() != null)
{ Task.Run(() => UserFirmwareAvatarSelectorViewModel.PreloadAvatars(contentManager, virtualFileSystem));
Task.Run(() =>
{
UserFirmwareAvatarSelectorViewModel.PreloadAvatars(contentManager, virtualFileSystem);
});
}
InitializeComponent(); InitializeComponent();
} }
public void GoBack() public void GoBack()
{ {
if (ContentFrame.BackStack.Count > 0) if (ContentFrame.BackStack.Count > 0)
{
ContentFrame.GoBack(); ContentFrame.GoBack();
}
LoadProfiles(); LoadProfiles();
} }
public void Navigate(Type sourcePageType, object parameter) public void Navigate(Type sourcePageType, object parameter)
{ => ContentFrame.Navigate(sourcePageType, parameter);
ContentFrame.Navigate(sourcePageType, parameter);
}
public static async Task Show(AccountManager ownerAccountManager, ContentManager ownerContentManager, public static async Task Show(
VirtualFileSystem ownerVirtualFileSystem, HorizonClient ownerHorizonClient) AccountManager ownerAccountManager,
ContentManager ownerContentManager,
VirtualFileSystem ownerVirtualFileSystem,
HorizonClient ownerHorizonClient)
{ {
var content = new NavigationDialogHost(ownerAccountManager, ownerContentManager, ownerVirtualFileSystem, ownerHorizonClient); var content = new NavigationDialogHost(ownerAccountManager, ownerContentManager, ownerVirtualFileSystem, ownerHorizonClient);
ContentDialog contentDialog = new() ContentDialog contentDialog = new()
{ {
Title = LocaleManager.Instance[LocaleKeys.UserProfileWindowTitle], Title = LocaleManager.Instance[LocaleKeys.UserProfileWindowTitle],
PrimaryButtonText = "", PrimaryButtonText = string.Empty,
SecondaryButtonText = "", SecondaryButtonText = string.Empty,
CloseButtonText = "", CloseButtonText = string.Empty,
Content = content, Content = content,
Padding = new Thickness(0), Padding = new Thickness(0)
}; };
contentDialog.Closed += (_, _) => content.ViewModel.Dispose(); contentDialog.Closed += (_, _) => content.ViewModel.Dispose();
@ -160,14 +155,14 @@ namespace Ryujinx.Ava.UI.Controls
if (profile == null) if (profile == null)
{ {
Dispatcher.UIThread.Post(Action);
return;
static async void Action() static async void Action()
{ {
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogUserProfileDeletionWarningMessage]); await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogUserProfileDeletionWarningMessage]);
} }
Dispatcher.UIThread.Post(Action);
return;
} }
AccountManager.OpenUser(profile.UserId); AccountManager.OpenUser(profile.UserId);

View File

@ -42,7 +42,7 @@ namespace Ryujinx.Ava.UI.Helpers
PrimaryButtonCommand = MiniCommand.Create(() => PrimaryButtonCommand = MiniCommand.Create(() =>
{ {
result = primaryButtonResult; result = primaryButtonResult;
}), })
}; };
contentDialog.SecondaryButtonCommand = MiniCommand.Create(() => contentDialog.SecondaryButtonCommand = MiniCommand.Create(() =>

View File

@ -1,5 +1,6 @@
using Avalonia.Logging; using Avalonia.Logging;
using Avalonia.Utilities; using Avalonia.Utilities;
using Gommon;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using System; using System;
using System.Text; using System.Text;
@ -90,7 +91,7 @@ namespace Ryujinx.Ava.UI.Helpers
if (source != null) if (source != null)
{ {
result.Append(" ("); result.Append(" (");
result.Append(source.GetType().Name); result.Append(source.GetType().AsFullNamePrettyString());
result.Append(" #"); result.Append(" #");
result.Append(source.GetHashCode()); result.Append(source.GetHashCode());
result.Append(')'); result.Append(')');

View File

@ -35,7 +35,7 @@ namespace Ryujinx.Ava.UI.Helpers
{ {
Text = text, Text = text,
Source = this, Source = this,
RoutedEvent = TextInputEvent, RoutedEvent = TextInputEvent
}); });
} }
} }

View File

@ -10,19 +10,11 @@ namespace Ryujinx.Ava.UI.Helpers
public static TimeZoneConverter Instance = new(); public static TimeZoneConverter Instance = new();
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{ => value is TimeZone timeZone
if (value == null) ? $"{timeZone.UtcDifference} {timeZone.Location} {timeZone.Abbreviation}"
{ : null;
return null;
}
var timeZone = (TimeZone)value;
return string.Format("{0} {1} {2}", timeZone.UtcDifference, timeZone.Location, timeZone.Abbreviation);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{ => throw new NotImplementedException();
throw new NotImplementedException();
}
} }
} }

View File

@ -3,12 +3,12 @@ using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Media.Imaging;
using Avalonia.Platform.Storage; using Avalonia.Platform.Storage;
using Avalonia.Threading; using Avalonia.Threading;
using DynamicData; using DynamicData;
using DynamicData.Binding; using DynamicData.Binding;
using FluentAvalonia.UI.Controls; using FluentAvalonia.UI.Controls;
using Gommon;
using LibHac.Common; using LibHac.Common;
using Ryujinx.Ava.Common; using Ryujinx.Ava.Common;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
@ -41,6 +41,7 @@ using System.Collections.ObjectModel;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reflection;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Key = Ryujinx.Input.Key; using Key = Ryujinx.Input.Key;
@ -113,6 +114,9 @@ namespace Ryujinx.Ava.UI.ViewModels
public ApplicationData ListSelectedApplication; public ApplicationData ListSelectedApplication;
public ApplicationData GridSelectedApplication; public ApplicationData GridSelectedApplication;
public static readonly Bitmap IconBitmap =
new(Assembly.GetAssembly(typeof(ConfigurationState))!.GetManifestResourceStream("Ryujinx.UI.Common.Resources.Logo_Ryujinx.png")!);
public MainWindow Window { get; init; } public MainWindow Window { get; init; }
internal AppHost AppHost { get; set; } internal AppHost AppHost { get; set; }
@ -179,16 +183,14 @@ namespace Ryujinx.Ava.UI.ViewModels
_searchTimer?.Dispose(); _searchTimer?.Dispose();
_searchTimer = new Timer(TimerCallback, null, 1000, 0); _searchTimer = new Timer(_ =>
}
}
private void TimerCallback(object obj)
{ {
RefreshView(); RefreshView();
_searchTimer.Dispose(); _searchTimer.Dispose();
_searchTimer = null; _searchTimer = null;
}, null, 1000, 0);
}
} }
public bool CanUpdate public bool CanUpdate
@ -978,29 +980,26 @@ namespace Ryujinx.Ava.UI.ViewModels
#region PrivateMethods #region PrivateMethods
private static IComparer<ApplicationData> CreateComparer(bool ascending, Func<ApplicationData, IComparable> selector) =>
ascending
? SortExpressionComparer<ApplicationData>.Ascending(selector)
: SortExpressionComparer<ApplicationData>.Descending(selector);
private IComparer<ApplicationData> GetComparer() private IComparer<ApplicationData> GetComparer()
{ => SortMode switch
return SortMode switch
{ {
#pragma warning disable IDE0055 // Disable formatting #pragma warning disable IDE0055 // Disable formatting
ApplicationSort.Title => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.Name) ApplicationSort.Title => CreateComparer(IsAscending, app => app.Name),
: SortExpressionComparer<ApplicationData>.Descending(app => app.Name), ApplicationSort.Developer => CreateComparer(IsAscending, app => app.Developer),
ApplicationSort.Developer => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.Developer)
: SortExpressionComparer<ApplicationData>.Descending(app => app.Developer),
ApplicationSort.LastPlayed => new LastPlayedSortComparer(IsAscending), ApplicationSort.LastPlayed => new LastPlayedSortComparer(IsAscending),
ApplicationSort.TotalTimePlayed => new TimePlayedSortComparer(IsAscending), ApplicationSort.TotalTimePlayed => new TimePlayedSortComparer(IsAscending),
ApplicationSort.FileType => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.FileExtension) ApplicationSort.FileType => CreateComparer(IsAscending, app => app.FileExtension),
: SortExpressionComparer<ApplicationData>.Descending(app => app.FileExtension), ApplicationSort.FileSize => CreateComparer(IsAscending, app => app.FileSize),
ApplicationSort.FileSize => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.FileSize) ApplicationSort.Path => CreateComparer(IsAscending, app => app.Path),
: SortExpressionComparer<ApplicationData>.Descending(app => app.FileSize), ApplicationSort.Favorite => CreateComparer(IsAscending, app => new AppListFavoriteComparable(app)),
ApplicationSort.Path => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.Path)
: SortExpressionComparer<ApplicationData>.Descending(app => app.Path),
ApplicationSort.Favorite => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => new AppListFavoriteComparable(app))
: SortExpressionComparer<ApplicationData>.Descending(app => new AppListFavoriteComparable(app)),
_ => null, _ => null,
#pragma warning restore IDE0055 #pragma warning restore IDE0055
}; };
}
public void RefreshView() public void RefreshView()
{ {
@ -1125,7 +1124,7 @@ namespace Ryujinx.Ava.UI.ViewModels
} }
catch (MissingKeyException ex) catch (MissingKeyException ex)
{ {
if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime)
{ {
Logger.Error?.Print(LogClass.Application, ex.ToString()); Logger.Error?.Print(LogClass.Application, ex.ToString());
@ -1260,8 +1259,10 @@ namespace Ryujinx.Ava.UI.ViewModels
GameStatusText = args.GameStatus; GameStatusText = args.GameStatus;
VolumeStatusText = args.VolumeStatus; VolumeStatusText = args.VolumeStatus;
FifoStatusText = args.FifoStatus; FifoStatusText = args.FifoStatus;
ShaderCountText = args.ShaderCount > 0 ? $"Compiling shaders: {args.ShaderCount}" : string.Empty;
ShowRightmostSeparator = !ShaderCountText.IsNullOrEmpty(); ShaderCountText = (ShowRightmostSeparator = args.ShaderCount > 0)
? $"{LocaleManager.Instance[LocaleKeys.CompilingShaders]}: {args.ShaderCount}"
: string.Empty;
ShowStatusSeparator = true; ShowStatusSeparator = true;
}); });
@ -1641,8 +1642,7 @@ namespace Ryujinx.Ava.UI.ViewModels
gameThread.Start(); gameThread.Start();
} }
public void SwitchToRenderer(bool startFullscreen) public void SwitchToRenderer(bool startFullscreen) =>
{
Dispatcher.UIThread.Post(() => Dispatcher.UIThread.Post(() =>
{ {
SwitchToGameControl(startFullscreen); SwitchToGameControl(startFullscreen);
@ -1651,15 +1651,9 @@ namespace Ryujinx.Ava.UI.ViewModels
RendererHostControl.Focus(); RendererHostControl.Focus();
}); });
}
public static void UpdateGameMetadata(string titleId) public static void UpdateGameMetadata(string titleId)
{ => ApplicationLibrary.LoadAndSaveMetaData(titleId, appMetadata => appMetadata.UpdatePostGame());
ApplicationLibrary.LoadAndSaveMetaData(titleId, appMetadata =>
{
appMetadata.UpdatePostGame();
});
}
public void RefreshFirmwareStatus() public void RefreshFirmwareStatus()
{ {

View File

@ -287,11 +287,11 @@ namespace Ryujinx.Ava.UI.ViewModels
public SettingsViewModel() public SettingsViewModel()
{ {
GameDirectories = new AvaloniaList<string>(); GameDirectories = [];
AutoloadDirectories = new AvaloniaList<string>(); AutoloadDirectories = [];
TimeZones = new AvaloniaList<TimeZone>(); TimeZones = [];
AvailableGpus = new ObservableCollection<ComboBoxItem>(); AvailableGpus = [];
_validTzRegions = new List<string>(); _validTzRegions = [];
_networkInterfaces = new Dictionary<string, string>(); _networkInterfaces = new Dictionary<string, string>();
Task.Run(CheckSoundBackends); Task.Run(CheckSoundBackends);

View File

@ -238,7 +238,9 @@
ToolTip.Tip="{locale:Locale IgnoreMissingServicesTooltip}"> ToolTip.Tip="{locale:Locale IgnoreMissingServicesTooltip}">
<TextBlock Text="{locale:Locale SettingsTabSystemIgnoreMissingServices}" /> <TextBlock Text="{locale:Locale SettingsTabSystemIgnoreMissingServices}" />
</CheckBox> </CheckBox>
<CheckBox IsChecked="{Binding IgnoreApplet}"> <CheckBox
IsChecked="{Binding IgnoreApplet}"
ToolTip.Tip="{locale:Locale IgnoreAppletTooltip}">
<TextBlock Text="{locale:Locale SettingsTabSystemIgnoreApplet}" /> <TextBlock Text="{locale:Locale SettingsTabSystemIgnoreApplet}" />
</CheckBox> </CheckBox>
</StackPanel> </StackPanel>

View File

@ -17,13 +17,7 @@
<UserControl.Resources> <UserControl.Resources>
<helpers:DownloadableContentLabelConverter x:Key="DownloadableContentLabel" /> <helpers:DownloadableContentLabelConverter x:Key="DownloadableContentLabel" />
</UserControl.Resources> </UserControl.Resources>
<Grid> <Grid RowDefinitions="Auto,Auto,*,Auto">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel <StackPanel
Grid.Row="0" Grid.Row="0"
Margin="0 0 0 10" Margin="0 0 0 10"
@ -44,12 +38,7 @@
<Panel <Panel
Margin="0 0 0 10" Margin="0 0 0 10"
Grid.Row="1"> Grid.Row="1">
<Grid> <Grid ColumnDefinitions="Auto,Auto,*">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock <TextBlock
Grid.Column="0" Grid.Column="0"
Text="{Binding UpdateCount}" /> Text="{Binding UpdateCount}" />
@ -101,17 +90,9 @@
<DataTemplate <DataTemplate
DataType="models:DownloadableContentModel"> DataType="models:DownloadableContentModel">
<Panel Margin="10"> <Panel Margin="10">
<Grid> <Grid ColumnDefinitions="*,Auto">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid <Grid
Grid.Column="0"> Grid.Column="0" ColumnDefinitions="*,Auto">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock <TextBlock
Grid.Column="0" Grid.Column="0"
HorizontalAlignment="Left" HorizontalAlignment="Left"

View File

@ -21,10 +21,10 @@ namespace Ryujinx.Ava.UI.Windows
private readonly struct PaletteColor(int qck, byte r, byte g, byte b) private readonly struct PaletteColor(int qck, byte r, byte g, byte b)
{ {
public int Qck { get; } = qck; public int Qck => qck;
public byte R { get; } = r; public byte R => r;
public byte G { get; } = g; public byte G => g;
public byte B { get; } = b; public byte B => b;
} }
public static SKColor GetFilteredColor(SKBitmap image) public static SKColor GetFilteredColor(SKBitmap image)
@ -54,15 +54,6 @@ namespace Ryujinx.Ava.UI.Windows
var buffer = GetBuffer(image); var buffer = GetBuffer(image);
int w = image.Width;
int w8 = w << 8;
int h8 = image.Height << 8;
#pragma warning disable IDE0059 // Unnecessary assignment
int xStep = w8 / ColorsPerLine;
int yStep = h8 / ColorsPerLine;
#pragma warning restore IDE0059
int i = 0; int i = 0;
int maxHitCount = 0; int maxHitCount = 0;

View File

@ -21,7 +21,6 @@
x:DataType="viewModels:MainWindowViewModel" x:DataType="viewModels:MainWindowViewModel"
mc:Ignorable="d" mc:Ignorable="d"
WindowStartupLocation="Manual" WindowStartupLocation="Manual"
Icon="resm:Ryujinx.UI.Common.Resources.Logo_Ryujinx.png?assembly=Ryujinx.UI.Common"
Focusable="True"> Focusable="True">
<Window.Styles> <Window.Styles>
<Style Selector="TitleBar:fullscreen"> <Style Selector="TitleBar:fullscreen">

View File

@ -84,7 +84,6 @@ namespace Ryujinx.Ava.UI.Windows
TitleBar.ExtendsContentIntoTitleBar = true; TitleBar.ExtendsContentIntoTitleBar = true;
TitleBar.TitleBarHitTestType = TitleBarHitTestType.Complex; TitleBar.TitleBarHitTestType = TitleBarHitTestType.Complex;
// NOTE: Height of MenuBar and StatusBar is not usable here, since it would still be 0 at this point. // NOTE: Height of MenuBar and StatusBar is not usable here, since it would still be 0 at this point.
StatusBarHeight = StatusBarView.StatusBar.MinHeight; StatusBarHeight = StatusBarView.StatusBar.MinHeight;
MenuBarHeight = MenuBar.MinHeight; MenuBarHeight = MenuBar.MinHeight;
@ -98,7 +97,7 @@ namespace Ryujinx.Ava.UI.Windows
{ {
InputManager = new InputManager(new AvaloniaKeyboardDriver(this), new SDL2GamepadDriver()); InputManager = new InputManager(new AvaloniaKeyboardDriver(this), new SDL2GamepadDriver());
this.GetObservable(IsActiveProperty).Subscribe(IsActiveChanged); _ = this.GetObservable(IsActiveProperty).Subscribe(it => ViewModel.IsActive = it);
this.ScalingChanged += OnScalingChanged; this.ScalingChanged += OnScalingChanged;
} }
} }
@ -106,7 +105,7 @@ namespace Ryujinx.Ava.UI.Windows
/// <summary> /// <summary>
/// Event handler for detecting OS theme change when using "Follow OS theme" option /// Event handler for detecting OS theme change when using "Follow OS theme" option
/// </summary> /// </summary>
private void OnPlatformColorValuesChanged(object sender, PlatformColorValues e) private static void OnPlatformColorValuesChanged(object sender, PlatformColorValues e)
{ {
if (Application.Current is App app) if (Application.Current is App app)
app.ApplyConfiguredTheme(); app.ApplyConfiguredTheme();
@ -128,11 +127,6 @@ namespace Ryujinx.Ava.UI.Windows
NotificationHelper.SetNotificationManager(this); NotificationHelper.SetNotificationManager(this);
} }
private void IsActiveChanged(bool obj)
{
ViewModel.IsActive = obj;
}
private void OnScalingChanged(object sender, EventArgs e) private void OnScalingChanged(object sender, EventArgs e)
{ {
Program.DesktopScaleFactor = this.RenderScaling; Program.DesktopScaleFactor = this.RenderScaling;
@ -355,7 +349,7 @@ namespace Ryujinx.Ava.UI.Windows
await Dispatcher.UIThread.InvokeAsync(async () => await UserErrorDialog.ShowUserErrorDialog(UserError.NoKeys)); await Dispatcher.UIThread.InvokeAsync(async () => await UserErrorDialog.ShowUserErrorDialog(UserError.NoKeys));
} }
if (ConfigurationState.Instance.CheckUpdatesOnStart.Value && Updater.CanUpdate(false)) if (ConfigurationState.Instance.CheckUpdatesOnStart && Updater.CanUpdate(false))
{ {
await Updater.BeginParse(this, false).ContinueWith(task => await Updater.BeginParse(this, false).ContinueWith(task =>
{ {

View File

@ -4,6 +4,7 @@ using Avalonia.Media;
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.Ava.UI.ViewModels;
namespace Ryujinx.Ava.UI.Windows namespace Ryujinx.Ava.UI.Windows
{ {
@ -16,6 +17,8 @@ namespace Ryujinx.Ava.UI.Windows
LocaleManager.Instance.LocaleChanged += LocaleChanged; LocaleManager.Instance.LocaleChanged += LocaleChanged;
LocaleChanged(); LocaleChanged();
Icon = MainWindowViewModel.IconBitmap;
} }
private void LocaleChanged() private void LocaleChanged()
@ -40,6 +43,8 @@ namespace Ryujinx.Ava.UI.Windows
LocaleManager.Instance.LocaleChanged += LocaleChanged; LocaleManager.Instance.LocaleChanged += LocaleChanged;
LocaleChanged(); LocaleChanged();
Icon = new WindowIcon(MainWindowViewModel.IconBitmap);
} }
private void LocaleChanged() private void LocaleChanged()