diff --git a/src/Ryujinx.HLE/FileSystem/ContentManager.cs b/src/Ryujinx.HLE/FileSystem/ContentManager.cs index 9bda759a5..ec0f58b01 100644 --- a/src/Ryujinx.HLE/FileSystem/ContentManager.cs +++ b/src/Ryujinx.HLE/FileSystem/ContentManager.cs @@ -1034,16 +1034,16 @@ namespace Ryujinx.HLE.FileSystem switch (fileName) { case "prod.keys": - verified = verifyKeys(lines, genericPattern); + verified = VerifyKeys(lines, genericPattern); break; case "title.keys": - verified = verifyKeys(lines, titlePattern); + verified = VerifyKeys(lines, titlePattern); break; case "console.keys": - verified = verifyKeys(lines, genericPattern); + verified = VerifyKeys(lines, genericPattern); break; case "dev.keys": - verified = verifyKeys(lines, genericPattern); + verified = VerifyKeys(lines, genericPattern); break; default: throw new FormatException($"Keys file name \"{fileName}\" not supported. Only \"prod.keys\", \"title.keys\", \"console.keys\", \"dev.keys\" are supported."); @@ -1056,20 +1056,22 @@ namespace Ryujinx.HLE.FileSystem { throw new FileNotFoundException($"Keys file not found at \"{filePath}\"."); } - } - private bool verifyKeys(string[] lines, string regex) - { - foreach (string line in lines) + return; + + bool VerifyKeys(string[] lines, string regex) { - if (!Regex.IsMatch(line, regex)) + foreach (string line in lines) { - return false; + if (!Regex.IsMatch(line, regex)) + { + return false; + } } + return true; } - return true; } - + public bool AreKeysAlredyPresent(string pathToCheck) { string[] fileNames = { "prod.keys", "title.keys", "console.keys", "dev.keys" }; diff --git a/src/Ryujinx.UI.Common/Helper/AppletMetadata.cs b/src/Ryujinx.UI.Common/Helper/AppletMetadata.cs new file mode 100644 index 000000000..644b7fe74 --- /dev/null +++ b/src/Ryujinx.UI.Common/Helper/AppletMetadata.cs @@ -0,0 +1,64 @@ +using LibHac.Common; +using LibHac.Ncm; +using LibHac.Ns; +using LibHac.Tools.FsSystem.NcaUtils; +using Ryujinx.HLE; +using Ryujinx.HLE.FileSystem; +using Ryujinx.UI.App.Common; + +namespace Ryujinx.UI.Common.Helper +{ + public readonly struct AppletMetadata + { + private readonly ContentManager _contentManager; + + public string Name { get; } + public ulong ProgramId { get; } + + public string Version { get; } + + public AppletMetadata(ContentManager contentManager, string name, ulong programId, string version = "1.0.0") + : this(name, programId, version) + { + _contentManager = contentManager; + } + + public AppletMetadata(string name, ulong programId, string version = "1.0.0") + { + Name = name; + ProgramId = programId; + Version = version; + } + + public string GetContentPath(ContentManager contentManager) + => (contentManager ?? _contentManager) + .GetInstalledContentPath(ProgramId, StorageId.BuiltInSystem, NcaContentType.Program); + + public bool CanStart(ContentManager contentManager, out ApplicationData appData, out BlitStruct appControl) + { + contentManager ??= _contentManager; + if (contentManager == null) + { + appData = null; + appControl = new BlitStruct(0); + return false; + } + + appData = new() + { + Name = Name, + Id = ProgramId, + Path = GetContentPath(contentManager) + }; + + if (string.IsNullOrEmpty(appData.Path)) + { + appControl = new BlitStruct(0); + return false; + } + + appControl = StructHelpers.CreateCustomNacpData(Name, Version); + return true; + } + } +} diff --git a/src/Ryujinx.UI.Common/Resources/Logo_Ryujinx_AntiAlias.png b/src/Ryujinx.UI.Common/Resources/Logo_Ryujinx_AntiAlias.png new file mode 100644 index 000000000..a00c7ce68 Binary files /dev/null and b/src/Ryujinx.UI.Common/Resources/Logo_Ryujinx_AntiAlias.png differ diff --git a/src/Ryujinx.UI.Common/Resources/Logo_Thiccjinx.png b/src/Ryujinx.UI.Common/Resources/Logo_Thiccjinx.png deleted file mode 100644 index be807a40a..000000000 Binary files a/src/Ryujinx.UI.Common/Resources/Logo_Thiccjinx.png and /dev/null differ diff --git a/src/Ryujinx.UI.Common/Ryujinx.UI.Common.csproj b/src/Ryujinx.UI.Common/Ryujinx.UI.Common.csproj index c43f95e4a..1ee9a4aa0 100644 --- a/src/Ryujinx.UI.Common/Ryujinx.UI.Common.csproj +++ b/src/Ryujinx.UI.Common/Ryujinx.UI.Common.csproj @@ -33,7 +33,7 @@ - + diff --git a/src/Ryujinx/Common/ApplicationHelper.cs b/src/Ryujinx/Common/ApplicationHelper.cs index db5961347..1c6b53dee 100644 --- a/src/Ryujinx/Common/ApplicationHelper.cs +++ b/src/Ryujinx/Common/ApplicationHelper.cs @@ -146,7 +146,7 @@ namespace Ryujinx.Ava.Common var cancellationToken = new CancellationTokenSource(); UpdateWaitWindow waitingDialog = new( - App.FormatTitle(LocaleKeys.DialogNcaExtractionTitle), + RyujinxApp.FormatTitle(LocaleKeys.DialogNcaExtractionTitle), LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogNcaExtractionMessage, ncaSectionType, Path.GetFileName(titleFilePath)), cancellationToken); @@ -268,10 +268,9 @@ namespace Ryujinx.Ava.Common { Dispatcher.UIThread.Post(waitingDialog.Close); - NotificationHelper.Show( - App.FormatTitle(LocaleKeys.DialogNcaExtractionTitle), - $"{titleName}\n\n{LocaleManager.Instance[LocaleKeys.DialogNcaExtractionSuccessMessage]}", - NotificationType.Information); + NotificationHelper.ShowInformation( + RyujinxApp.FormatTitle(LocaleKeys.DialogNcaExtractionTitle), + $"{titleName}\n\n{LocaleManager.Instance[LocaleKeys.DialogNcaExtractionSuccessMessage]}"); } } diff --git a/src/Ryujinx/Common/LocaleManager.cs b/src/Ryujinx/Common/LocaleManager.cs index f29efb15a..70b04ec95 100644 --- a/src/Ryujinx/Common/LocaleManager.cs +++ b/src/Ryujinx/Common/LocaleManager.cs @@ -1,7 +1,6 @@ using Gommon; using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Common; -using Ryujinx.Common.Logging; using Ryujinx.Common.Utilities; using Ryujinx.UI.Common.Configuration; using System; @@ -17,7 +16,6 @@ namespace Ryujinx.Ava.Common.Locale private const string DefaultLanguageCode = "en_US"; private readonly Dictionary _localeStrings; - private Dictionary _localeDefaultStrings; private readonly ConcurrentDictionary _dynamicValues; private string _localeLanguageCode; @@ -27,7 +25,6 @@ namespace Ryujinx.Ava.Common.Locale public LocaleManager() { _localeStrings = new Dictionary(); - _localeDefaultStrings = new Dictionary(); _dynamicValues = new ConcurrentDictionary(); Load(); @@ -37,9 +34,7 @@ namespace Ryujinx.Ava.Common.Locale { var localeLanguageCode = !string.IsNullOrEmpty(ConfigurationState.Instance.UI.LanguageCode.Value) ? ConfigurationState.Instance.UI.LanguageCode.Value : CultureInfo.CurrentCulture.Name.Replace('-', '_'); - - // Load en_US as default, if the target language translation is missing or incomplete. - LoadDefaultLanguage(); + LoadLanguage(localeLanguageCode); // Save whatever we ended up with. @@ -66,26 +61,14 @@ namespace Ryujinx.Ava.Common.Locale } catch { - // If formatting failed use the default text instead. - if (_localeDefaultStrings.TryGetValue(key, out value)) - try - { - return string.Format(value, dynamicValue); - } - catch - { - // If formatting the default text failed return the key. - return key.ToString(); - } + // If formatting the text failed, + // continue to the below line & return the text without formatting. } return value; } - - // If the locale doesn't contain the key return the default one. - return _localeDefaultStrings.TryGetValue(key, out string defaultValue) - ? defaultValue - : key.ToString(); // If the locale text doesn't exist return the key. + + return key.ToString(); // If the locale text doesn't exist return the key. } set { @@ -109,16 +92,11 @@ namespace Ryujinx.Ava.Common.Locale { _dynamicValues[key] = values; - OnPropertyChanged("Item"); + OnPropertyChanged("Translation"); return this[key]; } - private void LoadDefaultLanguage() - { - _localeDefaultStrings = LoadJsonLanguage(DefaultLanguageCode); - } - public void LoadLanguage(string languageCode) { var locale = LoadJsonLanguage(languageCode); @@ -126,7 +104,7 @@ namespace Ryujinx.Ava.Common.Locale if (locale == null) { _localeLanguageCode = DefaultLanguageCode; - locale = _localeDefaultStrings; + locale = LoadJsonLanguage(_localeLanguageCode); } else { @@ -138,16 +116,12 @@ namespace Ryujinx.Ava.Common.Locale _localeStrings[key] = val; } - OnPropertyChanged("Item"); + OnPropertyChanged("Translation"); LocaleChanged?.Invoke(); } - #nullable enable - private static LocalesJson? _localeData; - - #nullable disable private static Dictionary LoadJsonLanguage(string languageCode) { @@ -158,18 +132,29 @@ namespace Ryujinx.Ava.Common.Locale foreach (LocalesEntry locale in _localeData.Value.Locales) { - if (locale.Translations.Count != _localeData.Value.Languages.Count) + if (locale.Translations.Count < _localeData.Value.Languages.Count) { throw new Exception($"Locale key {{{locale.ID}}} is missing languages! Has {locale.Translations.Count} translations, expected {_localeData.Value.Languages.Count}!"); + } + + if (locale.Translations.Count > _localeData.Value.Languages.Count) + { + throw new Exception($"Locale key {{{locale.ID}}} has too many languages! Has {locale.Translations.Count} translations, expected {_localeData.Value.Languages.Count}!"); } if (!Enum.TryParse(locale.ID, out var localeKey)) continue; - localeStrings[localeKey] = - locale.Translations.TryGetValue(languageCode, out string val) && val != string.Empty - ? val - : locale.Translations[DefaultLanguageCode]; + var str = locale.Translations.TryGetValue(languageCode, out string val) && !string.IsNullOrEmpty(val) + ? val + : locale.Translations[DefaultLanguageCode]; + + if (string.IsNullOrEmpty(str)) + { + throw new Exception($"Locale key '{locale.ID}' has no valid translations for desired language {languageCode}! {DefaultLanguageCode} is an empty string or null"); + } + + localeStrings[localeKey] = str; } return localeStrings; diff --git a/src/Ryujinx/Common/Markup/BasicMarkupExtension.cs b/src/Ryujinx/Common/Markup/BasicMarkupExtension.cs index b1b7361a6..364c08c0b 100644 --- a/src/Ryujinx/Common/Markup/BasicMarkupExtension.cs +++ b/src/Ryujinx/Common/Markup/BasicMarkupExtension.cs @@ -14,7 +14,7 @@ namespace Ryujinx.Ava.Common.Markup { internal abstract class BasicMarkupExtension : MarkupExtension { - public virtual string Name => "Item"; + public abstract string Name { get; } public virtual Action? Setter => null; protected abstract T? Value { get; } diff --git a/src/Ryujinx/Common/Markup/MarkupExtensions.cs b/src/Ryujinx/Common/Markup/MarkupExtensions.cs index cae6d8c2c..9e8ff00ef 100644 --- a/src/Ryujinx/Common/Markup/MarkupExtensions.cs +++ b/src/Ryujinx/Common/Markup/MarkupExtensions.cs @@ -6,16 +6,19 @@ namespace Ryujinx.Ava.Common.Markup { internal class IconExtension(string iconString) : BasicMarkupExtension { + public override string Name => "Icon"; protected override Icon Value => new() { Value = iconString }; } internal class SpinningIconExtension(string iconString) : BasicMarkupExtension { + public override string Name => "SIcon"; protected override Icon Value => new() { Value = iconString, Animation = IconAnimation.Spin }; } internal class LocaleExtension(LocaleKeys key) : BasicMarkupExtension { + public override string Name => "Translation"; protected override string Value => LocaleManager.Instance[key]; protected override void ConfigureBindingExtension(CompiledBindingExtension bindingExtension) diff --git a/src/Ryujinx/Program.cs b/src/Ryujinx/Program.cs index 3c24b8e27..2ec60ac70 100644 --- a/src/Ryujinx/Program.cs +++ b/src/Ryujinx/Program.cs @@ -65,7 +65,7 @@ namespace Ryujinx.Ava } public static AppBuilder BuildAvaloniaApp() => - AppBuilder.Configure() + AppBuilder.Configure() .UsePlatformDetect() .With(new X11PlatformOptions { @@ -100,7 +100,7 @@ namespace Ryujinx.Ava // Delete backup files after updating. Task.Run(Updater.CleanupUpdate); - Console.Title = $"{App.FullAppName} Console {Version}"; + Console.Title = $"{RyujinxApp.FullAppName} Console {Version}"; // Hook unhandled exception and process exit events. AppDomain.CurrentDomain.UnhandledException += (sender, e) @@ -225,7 +225,7 @@ namespace Ryujinx.Ava private static void PrintSystemInfo() { - Logger.Notice.Print(LogClass.Application, $"{App.FullAppName} Version: {Version}"); + Logger.Notice.Print(LogClass.Application, $"{RyujinxApp.FullAppName} Version: {Version}"); SystemInfo.Gather().Print(); var enabledLogLevels = Logger.GetEnabledLevels().ToArray(); diff --git a/src/Ryujinx/App.axaml b/src/Ryujinx/RyujinxApp.axaml similarity index 94% rename from src/Ryujinx/App.axaml rename to src/Ryujinx/RyujinxApp.axaml index 5c96f97f2..e07d7ff26 100644 --- a/src/Ryujinx/App.axaml +++ b/src/Ryujinx/RyujinxApp.axaml @@ -1,5 +1,5 @@ diff --git a/src/Ryujinx/App.axaml.cs b/src/Ryujinx/RyujinxApp.axaml.cs similarity index 94% rename from src/Ryujinx/App.axaml.cs rename to src/Ryujinx/RyujinxApp.axaml.cs index 15ada201c..bbef20aa0 100644 --- a/src/Ryujinx/App.axaml.cs +++ b/src/Ryujinx/RyujinxApp.axaml.cs @@ -1,5 +1,6 @@ using Avalonia; using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Input.Platform; using Avalonia.Markup.Xaml; using Avalonia.Platform; using Avalonia.Styling; @@ -19,7 +20,7 @@ using System.Diagnostics; namespace Ryujinx.Ava { - public class App : Application + public class RyujinxApp : Application { internal static string FormatTitle(LocaleKeys? windowTitleKey = null) => windowTitleKey is null @@ -32,6 +33,12 @@ namespace Ryujinx.Ava .ApplicationLifetime.Cast() .MainWindow.Cast(); + public static bool IsClipboardAvailable(out IClipboard clipboard) + { + clipboard = MainWindow.Clipboard; + return clipboard != null; + } + public static void SetTaskbarProgress(TaskBarProgressBarState state) => MainWindow.PlatformFeatures.SetTaskBarProgressBarState(state); public static void SetTaskbarProgressValue(ulong current, ulong total) => MainWindow.PlatformFeatures.SetTaskBarProgressBarValue(current, total); public static void SetTaskbarProgressValue(long current, long total) => SetTaskbarProgressValue(Convert.ToUInt64(current), Convert.ToUInt64(total)); @@ -132,7 +139,7 @@ namespace Ryujinx.Ava }; public static ThemeVariant DetectSystemTheme() => - Current is App { PlatformSettings: not null } app + Current is RyujinxApp { PlatformSettings: not null } app ? ConvertThemeVariant(app.PlatformSettings.GetColorValues().ThemeVariant) : ThemeVariant.Default; } diff --git a/src/Ryujinx/UI/Controls/ApplicationListView.axaml b/src/Ryujinx/UI/Controls/ApplicationListView.axaml index 8a72ebfbf..90b657ee0 100644 --- a/src/Ryujinx/UI/Controls/ApplicationListView.axaml +++ b/src/Ryujinx/UI/Controls/ApplicationListView.axaml @@ -101,11 +101,21 @@ VerticalAlignment="Top" Orientation="Vertical" Spacing="5"> - + it.IdString == idText.Text); + if (appData is null) + return; + + await clipboard.SetTextAsync(appData.IdString); + + NotificationHelper.ShowInformation( + "Copied Title ID", + $"{appData.Name} ({appData.IdString})"); + } } } diff --git a/src/Ryujinx/UI/Controls/SliderScroll.axaml.cs b/src/Ryujinx/UI/Controls/SliderScroll.cs similarity index 100% rename from src/Ryujinx/UI/Controls/SliderScroll.axaml.cs rename to src/Ryujinx/UI/Controls/SliderScroll.cs diff --git a/src/Ryujinx/UI/Controls/StatusBarSeparator.cs b/src/Ryujinx/UI/Controls/StatusBarSeparator.cs new file mode 100644 index 000000000..7888879f5 --- /dev/null +++ b/src/Ryujinx/UI/Controls/StatusBarSeparator.cs @@ -0,0 +1,19 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Media; + +namespace Ryujinx.Ava.UI.Controls +{ + public class MiniVerticalSeparator : Border + { + public MiniVerticalSeparator() + { + Width = 2; + Height = 12; + Margin = new Thickness(); + BorderBrush = Brushes.Gray; + Background = Brushes.Gray; + BorderThickness = new Thickness(1); + } + } +} diff --git a/src/Ryujinx/UI/Helpers/NotificationHelper.cs b/src/Ryujinx/UI/Helpers/NotificationHelper.cs index 656a8b52f..74029a4b1 100644 --- a/src/Ryujinx/UI/Helpers/NotificationHelper.cs +++ b/src/Ryujinx/UI/Helpers/NotificationHelper.cs @@ -62,9 +62,46 @@ namespace Ryujinx.Ava.UI.Helpers _notifications.Add(new Notification(title, text, type, delay, onClick, onClose)); } - public static void ShowError(string message) - { - Show(LocaleManager.Instance[LocaleKeys.DialogErrorTitle], $"{LocaleManager.Instance[LocaleKeys.DialogErrorMessage]}\n\n{message}", NotificationType.Error); - } + public static void ShowError(string message) => + ShowError( + LocaleManager.Instance[LocaleKeys.DialogErrorTitle], + $"{LocaleManager.Instance[LocaleKeys.DialogErrorMessage]}\n\n{message}" + ); + + public static void ShowInformation(string title, string text, bool waitingExit = false, Action onClick = null, Action onClose = null) => + Show( + title, + text, + NotificationType.Information, + waitingExit, + onClick, + onClose); + + public static void ShowSuccess(string title, string text, bool waitingExit = false, Action onClick = null, Action onClose = null) => + Show( + title, + text, + NotificationType.Success, + waitingExit, + onClick, + onClose); + + public static void ShowWarning(string title, string text, bool waitingExit = false, Action onClick = null, Action onClose = null) => + Show( + title, + text, + NotificationType.Warning, + waitingExit, + onClick, + onClose); + + public static void ShowError(string title, string text, bool waitingExit = false, Action onClick = null, Action onClose = null) => + Show( + title, + text, + NotificationType.Error, + waitingExit, + onClick, + onClose); } } diff --git a/src/Ryujinx/UI/Helpers/XCITrimmerFileSpaceSavingsConverter.cs b/src/Ryujinx/UI/Helpers/XCITrimmerFileSpaceSavingsConverter.cs index c6e814e90..14e8e178a 100644 --- a/src/Ryujinx/UI/Helpers/XCITrimmerFileSpaceSavingsConverter.cs +++ b/src/Ryujinx/UI/Helpers/XCITrimmerFileSpaceSavingsConverter.cs @@ -1,6 +1,7 @@ using Avalonia; using Avalonia.Data; using Avalonia.Data.Converters; +using Gommon; using Ryujinx.Ava.Common.Locale; using Ryujinx.UI.Common.Models; using System; @@ -32,11 +33,11 @@ namespace Ryujinx.Ava.UI.Helpers if (app.CurrentSavingsB < app.PotentialSavingsB) { - return LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.TitleXCICanSaveLabel, (app.PotentialSavingsB - app.CurrentSavingsB) / _bytesPerMB); + return LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.TitleXCICanSaveLabel, ((app.PotentialSavingsB - app.CurrentSavingsB) / _bytesPerMB).CoerceAtLeast(0)); } else { - return LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.TitleXCISavingLabel, app.CurrentSavingsB / _bytesPerMB); + return LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.TitleXCISavingLabel, (app.CurrentSavingsB / _bytesPerMB).CoerceAtLeast(0)); } } diff --git a/src/Ryujinx/UI/ViewModels/AboutWindowViewModel.cs b/src/Ryujinx/UI/ViewModels/AboutWindowViewModel.cs index 23d0f963c..607bff792 100644 --- a/src/Ryujinx/UI/ViewModels/AboutWindowViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/AboutWindowViewModel.cs @@ -51,7 +51,7 @@ namespace Ryujinx.Ava.UI.ViewModels public AboutWindowViewModel() { - Version = App.FullAppName + "\n" + Program.Version; + Version = RyujinxApp.FullAppName + "\n" + Program.Version; UpdateLogoTheme(ConfigurationState.Instance.UI.BaseStyle.Value); ThemeManager.ThemeChanged += ThemeManager_ThemeChanged; @@ -64,7 +64,7 @@ namespace Ryujinx.Ava.UI.ViewModels private void UpdateLogoTheme(string theme) { - bool isDarkTheme = theme == "Dark" || (theme == "Auto" && App.DetectSystemTheme() == ThemeVariant.Dark); + bool isDarkTheme = theme == "Dark" || (theme == "Auto" && RyujinxApp.DetectSystemTheme() == ThemeVariant.Dark); string basePath = "resm:Ryujinx.UI.Common.Resources."; string themeSuffix = isDarkTheme ? "Dark.png" : "Light.png"; diff --git a/src/Ryujinx/UI/ViewModels/BaseModel.cs b/src/Ryujinx/UI/ViewModels/BaseModel.cs index 4db9cf812..d8f2e9096 100644 --- a/src/Ryujinx/UI/ViewModels/BaseModel.cs +++ b/src/Ryujinx/UI/ViewModels/BaseModel.cs @@ -1,3 +1,4 @@ +using System; using System.ComponentModel; using System.Runtime.CompilerServices; @@ -11,5 +12,13 @@ namespace Ryujinx.Ava.UI.ViewModels { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } + + protected void OnPropertiesChanged(params ReadOnlySpan propertyNames) + { + foreach (var propertyName in propertyNames) + { + OnPropertyChanged(propertyName); + } + } } } diff --git a/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs b/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs index f7cd83ed6..04881b58d 100644 --- a/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs @@ -131,7 +131,7 @@ namespace Ryujinx.Ava.UI.ViewModels // For an example of this, download canary 1.2.95, then open the settings menu, and look at the icon in the top-left. // The border gets reduced to colored pixels in the 4 corners. public static readonly Bitmap IconBitmap = - new(Assembly.GetAssembly(typeof(ConfigurationState))!.GetManifestResourceStream("Ryujinx.UI.Common.Resources.Logo_Thiccjinx.png")!); + new(Assembly.GetAssembly(typeof(ConfigurationState))!.GetManifestResourceStream("Ryujinx.UI.Common.Resources.Logo_Ryujinx_AntiAlias.png")!); public MainWindow Window { get; init; } @@ -2051,7 +2051,7 @@ namespace Ryujinx.Ava.UI.ViewModels Dispatcher.UIThread.InvokeAsync(() => { - Title = App.FormatTitle(); + Title = RyujinxApp.FormatTitle(); }); } diff --git a/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs b/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs index 85ba203f9..7504147b2 100644 --- a/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs @@ -71,8 +71,7 @@ namespace Ryujinx.Ava.UI.ViewModels { _resolutionScale = value; - OnPropertyChanged(nameof(CustomResolutionScale)); - OnPropertyChanged(nameof(IsCustomResolutionScaleActive)); + OnPropertiesChanged(nameof(CustomResolutionScale), nameof(IsCustomResolutionScaleActive)); } } @@ -181,8 +180,9 @@ namespace Ryujinx.Ava.UI.ViewModels int newInterval = (int)((value / 100f) * 60); _customVSyncInterval = newInterval; _customVSyncIntervalPercentageProxy = value; - OnPropertyChanged((nameof(CustomVSyncInterval))); - OnPropertyChanged((nameof(CustomVSyncIntervalPercentageText))); + OnPropertiesChanged( + nameof(CustomVSyncInterval), + nameof(CustomVSyncIntervalPercentageText)); } } @@ -190,7 +190,7 @@ namespace Ryujinx.Ava.UI.ViewModels { get { - string text = CustomVSyncIntervalPercentageProxy.ToString() + "%"; + string text = CustomVSyncIntervalPercentageProxy + "%"; return text; } } @@ -221,8 +221,9 @@ namespace Ryujinx.Ava.UI.ViewModels _customVSyncInterval = value; int newPercent = (int)((value / 60f) * 100); _customVSyncIntervalPercentageProxy = newPercent; - OnPropertyChanged(nameof(CustomVSyncIntervalPercentageProxy)); - OnPropertyChanged(nameof(CustomVSyncIntervalPercentageText)); + OnPropertiesChanged( + nameof(CustomVSyncIntervalPercentageProxy), + nameof(CustomVSyncIntervalPercentageText)); OnPropertyChanged(); } } diff --git a/src/Ryujinx/UI/ViewModels/XCITrimmerViewModel.cs b/src/Ryujinx/UI/ViewModels/XCITrimmerViewModel.cs index e1f9eead5..402b182af 100644 --- a/src/Ryujinx/UI/ViewModels/XCITrimmerViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/XCITrimmerViewModel.cs @@ -91,39 +91,42 @@ namespace Ryujinx.Ava.UI.ViewModels private void SortingChanged() { - OnPropertyChanged(nameof(IsSortedByName)); - OnPropertyChanged(nameof(IsSortedBySaved)); - OnPropertyChanged(nameof(SortingAscending)); - OnPropertyChanged(nameof(SortingField)); - OnPropertyChanged(nameof(SortingFieldName)); + OnPropertiesChanged( + nameof(IsSortedByName), + nameof(IsSortedBySaved), + nameof(SortingAscending), + nameof(SortingField), + nameof(SortingFieldName)); + SortAndFilter(); } private void DisplayedChanged() { - OnPropertyChanged(nameof(Status)); - OnPropertyChanged(nameof(DisplayedXCIFiles)); - OnPropertyChanged(nameof(SelectedDisplayedXCIFiles)); + OnPropertiesChanged(nameof(Status), nameof(DisplayedXCIFiles), nameof(SelectedDisplayedXCIFiles)); } private void ApplicationsChanged() { - OnPropertyChanged(nameof(AllXCIFiles)); - OnPropertyChanged(nameof(Status)); - OnPropertyChanged(nameof(PotentialSavings)); - OnPropertyChanged(nameof(ActualSavings)); - OnPropertyChanged(nameof(CanTrim)); - OnPropertyChanged(nameof(CanUntrim)); + OnPropertiesChanged( + nameof(AllXCIFiles), + nameof(Status), + nameof(PotentialSavings), + nameof(ActualSavings), + nameof(CanTrim), + nameof(CanUntrim)); + DisplayedChanged(); SortAndFilter(); } private void SelectionChanged(bool displayedChanged = true) { - OnPropertyChanged(nameof(Status)); - OnPropertyChanged(nameof(CanTrim)); - OnPropertyChanged(nameof(CanUntrim)); - OnPropertyChanged(nameof(SelectedXCIFiles)); + OnPropertiesChanged( + nameof(Status), + nameof(CanTrim), + nameof(CanUntrim), + nameof(SelectedXCIFiles)); if (displayedChanged) OnPropertyChanged(nameof(SelectedDisplayedXCIFiles)); @@ -131,11 +134,12 @@ namespace Ryujinx.Ava.UI.ViewModels private void ProcessingChanged() { - OnPropertyChanged(nameof(Processing)); - OnPropertyChanged(nameof(Cancel)); - OnPropertyChanged(nameof(Status)); - OnPropertyChanged(nameof(CanTrim)); - OnPropertyChanged(nameof(CanUntrim)); + OnPropertiesChanged( + nameof(Processing), + nameof(Cancel), + nameof(Status), + nameof(CanTrim), + nameof(CanUntrim)); } private IEnumerable GetSelectedDisplayedXCIFiles() @@ -360,7 +364,7 @@ namespace Ryujinx.Ava.UI.ViewModels value = _processingApplication.Value with { PercentageProgress = null }; if (value.HasValue) - _displayedXCIFiles.ReplaceWith(value.Value); + _displayedXCIFiles.ReplaceWith(value); _processingApplication = value; OnPropertyChanged(); diff --git a/src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml b/src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml index 7d8135dcf..8207f8e03 100644 --- a/src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml +++ b/src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml @@ -18,7 +18,7 @@ Height="25" Width="25" ToolTip.Tip="{Binding Title}" - Source="resm:Ryujinx.UI.Common.Resources.Logo_Thiccjinx.png?assembly=Ryujinx.UI.Common" /> + Source="resm:Ryujinx.UI.Common.Resources.Logo_Ryujinx_AntiAlias.png?assembly=Ryujinx.UI.Common" /> - + - + - + - + - + - + - + - + 0, - > 1 => 1, - _ => newValue, - }; + Window.ViewModel.Volume = Math.Clamp(newValue, 0, 1); e.Handled = true; } diff --git a/src/Ryujinx/UI/Windows/AmiiboWindow.axaml.cs b/src/Ryujinx/UI/Windows/AmiiboWindow.axaml.cs index 6182e6b50..9a940c938 100644 --- a/src/Ryujinx/UI/Windows/AmiiboWindow.axaml.cs +++ b/src/Ryujinx/UI/Windows/AmiiboWindow.axaml.cs @@ -16,7 +16,7 @@ namespace Ryujinx.Ava.UI.Windows InitializeComponent(); - Title = App.FormatTitle(LocaleKeys.Amiibo); + Title = RyujinxApp.FormatTitle(LocaleKeys.Amiibo); } public AmiiboWindow() @@ -27,7 +27,7 @@ namespace Ryujinx.Ava.UI.Windows if (Program.PreviewerDetached) { - Title = App.FormatTitle(LocaleKeys.Amiibo); + Title = RyujinxApp.FormatTitle(LocaleKeys.Amiibo); } } diff --git a/src/Ryujinx/UI/Windows/CheatWindow.axaml.cs b/src/Ryujinx/UI/Windows/CheatWindow.axaml.cs index 8c8d56b34..2fc9617fb 100644 --- a/src/Ryujinx/UI/Windows/CheatWindow.axaml.cs +++ b/src/Ryujinx/UI/Windows/CheatWindow.axaml.cs @@ -28,7 +28,7 @@ namespace Ryujinx.Ava.UI.Windows InitializeComponent(); - Title = App.FormatTitle(LocaleKeys.CheatWindowTitle); + Title = RyujinxApp.FormatTitle(LocaleKeys.CheatWindowTitle); } public CheatWindow(VirtualFileSystem virtualFileSystem, string titleId, string titleName, string titlePath) @@ -93,7 +93,7 @@ namespace Ryujinx.Ava.UI.Windows DataContext = this; - Title = App.FormatTitle(LocaleKeys.CheatWindowTitle); + Title = RyujinxApp.FormatTitle(LocaleKeys.CheatWindowTitle); } public void Save() diff --git a/src/Ryujinx/UI/Windows/MainWindow.axaml.cs b/src/Ryujinx/UI/Windows/MainWindow.axaml.cs index c433d7fdb..660caa605 100644 --- a/src/Ryujinx/UI/Windows/MainWindow.axaml.cs +++ b/src/Ryujinx/UI/Windows/MainWindow.axaml.cs @@ -86,17 +86,22 @@ namespace Ryujinx.Ava.UI.Windows UiHandler = new AvaHostUIHandler(this); - ViewModel.Title = App.FormatTitle(); + ViewModel.Title = RyujinxApp.FormatTitle(); TitleBar.ExtendsContentIntoTitleBar = !ConfigurationState.Instance.ShowTitleBar; TitleBar.TitleBarHitTestType = (ConfigurationState.Instance.ShowTitleBar) ? TitleBarHitTestType.Simple : TitleBarHitTestType.Complex; - // Correctly size window when 'TitleBar' is enabled (Nov. 14, 2024) - TitleBarHeight = (ConfigurationState.Instance.ShowTitleBar ? TitleBar.Height : 0); - // NOTE: Height of MenuBar and StatusBar is not usable here, since it would still be 0 at this point. StatusBarHeight = StatusBarView.StatusBar.MinHeight; MenuBarHeight = MenuBar.MinHeight; + + TitleBar.Height = MenuBarHeight; + + // Correctly size window when 'TitleBar' is enabled (Nov. 14, 2024) + TitleBarHeight = (ConfigurationState.Instance.ShowTitleBar ? TitleBar.Height : 0); + + ApplicationList.DataContext = DataContext; + ApplicationGrid.DataContext = DataContext; SetWindowSizePosition(); @@ -114,7 +119,7 @@ namespace Ryujinx.Ava.UI.Windows /// private static void OnPlatformColorValuesChanged(object sender, PlatformColorValues e) { - if (Application.Current is App app) + if (Application.Current is RyujinxApp app) app.ApplyConfiguredTheme(ConfigurationState.Instance.UI.BaseStyle); } diff --git a/src/Ryujinx/UI/Windows/SettingsWindow.axaml.cs b/src/Ryujinx/UI/Windows/SettingsWindow.axaml.cs index b004d9fba..0c0345107 100644 --- a/src/Ryujinx/UI/Windows/SettingsWindow.axaml.cs +++ b/src/Ryujinx/UI/Windows/SettingsWindow.axaml.cs @@ -14,7 +14,7 @@ namespace Ryujinx.Ava.UI.Windows public SettingsWindow(VirtualFileSystem virtualFileSystem, ContentManager contentManager) { - Title = App.FormatTitle(LocaleKeys.Settings); + Title = RyujinxApp.FormatTitle(LocaleKeys.Settings); DataContext = ViewModel = new SettingsViewModel(virtualFileSystem, contentManager); diff --git a/src/Ryujinx/Updater.cs b/src/Ryujinx/Updater.cs index 21d991d97..3d4f11317 100644 --- a/src/Ryujinx/Updater.cs +++ b/src/Ryujinx/Updater.cs @@ -76,7 +76,7 @@ namespace Ryujinx.Ava if (!Version.TryParse(Program.Version, out Version currentVersion)) { - Logger.Error?.Print(LogClass.Application, $"Failed to convert the current {App.FullAppName} version!"); + Logger.Error?.Print(LogClass.Application, $"Failed to convert the current {RyujinxApp.FullAppName} version!"); await ContentDialogHelper.CreateWarningDialog( LocaleManager.Instance[LocaleKeys.DialogUpdaterConvertFailedMessage], @@ -159,7 +159,7 @@ namespace Ryujinx.Ava if (!Version.TryParse(_buildVer, out Version newVersion)) { - Logger.Error?.Print(LogClass.Application, $"Failed to convert the received {App.FullAppName} version from GitHub!"); + Logger.Error?.Print(LogClass.Application, $"Failed to convert the received {RyujinxApp.FullAppName} version from GitHub!"); await ContentDialogHelper.CreateWarningDialog( LocaleManager.Instance[LocaleKeys.DialogUpdaterConvertFailedGithubMessage], @@ -266,7 +266,7 @@ namespace Ryujinx.Ava SubHeader = LocaleManager.Instance[LocaleKeys.UpdaterDownloading], IconSource = new SymbolIconSource { Symbol = Symbol.Download }, ShowProgressBar = true, - XamlRoot = App.MainWindow, + XamlRoot = RyujinxApp.MainWindow, }; taskDialog.Opened += (s, e) => @@ -490,7 +490,7 @@ namespace Ryujinx.Ava bytesWritten += readSize; taskDialog.SetProgressBarState(GetPercentage(bytesWritten, totalBytes), TaskDialogProgressState.Normal); - App.SetTaskbarProgressValue(bytesWritten, totalBytes); + RyujinxApp.SetTaskbarProgressValue(bytesWritten, totalBytes); updateFileStream.Write(buffer, 0, readSize); }