diff options
| author | Mary Guillemard <mary@mary.zone> | 2024-03-02 12:51:05 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-03-02 12:51:05 +0100 |
| commit | ec6cb0abb4b7669895b6e96fd7581c93b5abd691 (patch) | |
| tree | 128c862ff5faea0b219467656d4023bee7faefb5 /src/Ryujinx.Ava/UI/Helpers | |
| parent | 53b5985da6b9d7b281d9fc25b93bfd1d1918a107 (diff) | |
infra: Make Avalonia the default UI (#6375)
* misc: Move Ryujinx project to Ryujinx.Gtk3
This breaks release CI for now but that's fine.
Signed-off-by: Mary Guillemard <mary@mary.zone>
* misc: Move Ryujinx.Ava project to Ryujinx
This breaks CI for now, but it's fine.
Signed-off-by: Mary Guillemard <mary@mary.zone>
* infra: Make Avalonia the default UI
Should fix CI after the previous changes.
GTK3 isn't build by the release job anymore, only by PR CI.
This also ensure that the test-ava update package is still generated to
allow update from the old testing channel.
Signed-off-by: Mary Guillemard <mary@mary.zone>
* Fix missing copy in create_app_bundle.sh
Signed-off-by: Mary Guillemard <mary@mary.zone>
* Fix syntax error
Signed-off-by: Mary Guillemard <mary@mary.zone>
---------
Signed-off-by: Mary Guillemard <mary@mary.zone>
Diffstat (limited to 'src/Ryujinx.Ava/UI/Helpers')
| -rw-r--r-- | src/Ryujinx.Ava/UI/Helpers/ApplicationOpenedEventArgs.cs | 16 | ||||
| -rw-r--r-- | src/Ryujinx.Ava/UI/Helpers/BitmapArrayValueConverter.cs | 36 | ||||
| -rw-r--r-- | src/Ryujinx.Ava/UI/Helpers/ButtonKeyAssigner.cs | 118 | ||||
| -rw-r--r-- | src/Ryujinx.Ava/UI/Helpers/ContentDialogHelper.cs | 425 | ||||
| -rw-r--r-- | src/Ryujinx.Ava/UI/Helpers/Glyph.cs | 9 | ||||
| -rw-r--r-- | src/Ryujinx.Ava/UI/Helpers/GlyphValueConverter.cs | 42 | ||||
| -rw-r--r-- | src/Ryujinx.Ava/UI/Helpers/KeyValueConverter.cs | 46 | ||||
| -rw-r--r-- | src/Ryujinx.Ava/UI/Helpers/LocalizedNeverConverter.cs | 43 | ||||
| -rw-r--r-- | src/Ryujinx.Ava/UI/Helpers/LoggerAdapter.cs | 102 | ||||
| -rw-r--r-- | src/Ryujinx.Ava/UI/Helpers/MiniCommand.cs | 71 | ||||
| -rw-r--r-- | src/Ryujinx.Ava/UI/Helpers/NotificationHelper.cs | 70 | ||||
| -rw-r--r-- | src/Ryujinx.Ava/UI/Helpers/OffscreenTextBox.cs | 39 | ||||
| -rw-r--r-- | src/Ryujinx.Ava/UI/Helpers/TimeZoneConverter.cs | 28 | ||||
| -rw-r--r-- | src/Ryujinx.Ava/UI/Helpers/UserErrorDialog.cs | 90 | ||||
| -rw-r--r-- | src/Ryujinx.Ava/UI/Helpers/UserResult.cs | 12 | ||||
| -rw-r--r-- | src/Ryujinx.Ava/UI/Helpers/Win32NativeInterop.cs | 125 |
16 files changed, 0 insertions, 1272 deletions
diff --git a/src/Ryujinx.Ava/UI/Helpers/ApplicationOpenedEventArgs.cs b/src/Ryujinx.Ava/UI/Helpers/ApplicationOpenedEventArgs.cs deleted file mode 100644 index bc5622b5..00000000 --- a/src/Ryujinx.Ava/UI/Helpers/ApplicationOpenedEventArgs.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Avalonia.Interactivity; -using Ryujinx.UI.App.Common; - -namespace Ryujinx.Ava.UI.Helpers -{ - public class ApplicationOpenedEventArgs : RoutedEventArgs - { - public ApplicationData Application { get; } - - public ApplicationOpenedEventArgs(ApplicationData application, RoutedEvent routedEvent) - { - Application = application; - RoutedEvent = routedEvent; - } - } -} diff --git a/src/Ryujinx.Ava/UI/Helpers/BitmapArrayValueConverter.cs b/src/Ryujinx.Ava/UI/Helpers/BitmapArrayValueConverter.cs deleted file mode 100644 index 42bd8d5a..00000000 --- a/src/Ryujinx.Ava/UI/Helpers/BitmapArrayValueConverter.cs +++ /dev/null @@ -1,36 +0,0 @@ -using Avalonia.Data.Converters; -using Avalonia.Media; -using Avalonia.Media.Imaging; -using System; -using System.Globalization; -using System.IO; - -namespace Ryujinx.Ava.UI.Helpers -{ - internal class BitmapArrayValueConverter : IValueConverter - { - public static BitmapArrayValueConverter Instance = new(); - - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - if (value == null) - { - return null; - } - - if (value is byte[] buffer && targetType == typeof(IImage)) - { - MemoryStream mem = new(buffer); - - return new Bitmap(mem); - } - - throw new NotSupportedException(); - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - throw new NotSupportedException(); - } - } -} diff --git a/src/Ryujinx.Ava/UI/Helpers/ButtonKeyAssigner.cs b/src/Ryujinx.Ava/UI/Helpers/ButtonKeyAssigner.cs deleted file mode 100644 index 7e8ba734..00000000 --- a/src/Ryujinx.Ava/UI/Helpers/ButtonKeyAssigner.cs +++ /dev/null @@ -1,118 +0,0 @@ -using Avalonia.Controls; -using Avalonia.Controls.Primitives; -using Avalonia.LogicalTree; -using Avalonia.Threading; -using Ryujinx.Input; -using Ryujinx.Input.Assigner; -using System; -using System.Linq; -using System.Threading.Tasks; - -namespace Ryujinx.Ava.UI.Helpers -{ - internal class ButtonKeyAssigner - { - internal class ButtonAssignedEventArgs : EventArgs - { - public ToggleButton Button { get; } - public bool IsAssigned { get; } - - public ButtonAssignedEventArgs(ToggleButton button, bool isAssigned) - { - Button = button; - IsAssigned = isAssigned; - } - } - - public ToggleButton ToggledButton { get; set; } - - private bool _isWaitingForInput; - private bool _shouldUnbind; - public event EventHandler<ButtonAssignedEventArgs> ButtonAssigned; - - public ButtonKeyAssigner(ToggleButton toggleButton) - { - ToggledButton = toggleButton; - } - - public async void GetInputAndAssign(IButtonAssigner assigner, IKeyboard keyboard = null) - { - Dispatcher.UIThread.Post(() => - { - ToggledButton.IsChecked = true; - }); - - if (_isWaitingForInput) - { - Dispatcher.UIThread.Post(() => - { - Cancel(); - }); - - return; - } - - _isWaitingForInput = true; - - assigner.Initialize(); - - await Task.Run(async () => - { - while (true) - { - if (!_isWaitingForInput) - { - return; - } - - await Task.Delay(10); - - assigner.ReadInput(); - - if (assigner.HasAnyButtonPressed() || assigner.ShouldCancel() || (keyboard != null && keyboard.IsPressed(Key.Escape))) - { - break; - } - } - }); - - await Dispatcher.UIThread.InvokeAsync(() => - { - string pressedButton = assigner.GetPressedButton(); - - if (_shouldUnbind) - { - SetButtonText(ToggledButton, "Unbound"); - } - else if (pressedButton != "") - { - SetButtonText(ToggledButton, pressedButton); - } - - _shouldUnbind = false; - _isWaitingForInput = false; - - ToggledButton.IsChecked = false; - - ButtonAssigned?.Invoke(this, new ButtonAssignedEventArgs(ToggledButton, pressedButton != null)); - - static void SetButtonText(ToggleButton button, string text) - { - ILogical textBlock = button.GetLogicalDescendants().First(x => x is TextBlock); - - if (textBlock != null && textBlock is TextBlock block) - { - block.Text = text; - } - } - }); - } - - public void Cancel(bool shouldUnbind = false) - { - _isWaitingForInput = false; - ToggledButton.IsChecked = false; - _shouldUnbind = shouldUnbind; - } - } -} diff --git a/src/Ryujinx.Ava/UI/Helpers/ContentDialogHelper.cs b/src/Ryujinx.Ava/UI/Helpers/ContentDialogHelper.cs deleted file mode 100644 index 15b7ddd1..00000000 --- a/src/Ryujinx.Ava/UI/Helpers/ContentDialogHelper.cs +++ /dev/null @@ -1,425 +0,0 @@ -using Avalonia; -using Avalonia.Controls; -using Avalonia.Controls.ApplicationLifetimes; -using Avalonia.Layout; -using Avalonia.Media; -using Avalonia.Threading; -using FluentAvalonia.Core; -using FluentAvalonia.UI.Controls; -using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.UI.Windows; -using Ryujinx.Common.Logging; -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace Ryujinx.Ava.UI.Helpers -{ - public static class ContentDialogHelper - { - private static bool _isChoiceDialogOpen; - private static ContentDialogOverlayWindow _contentDialogOverlayWindow; - - private async static Task<UserResult> ShowContentDialog( - string title, - object content, - string primaryButton, - string secondaryButton, - string closeButton, - UserResult primaryButtonResult = UserResult.Ok, - ManualResetEvent deferResetEvent = null, - TypedEventHandler<ContentDialog, ContentDialogButtonClickEventArgs> deferCloseAction = null) - { - UserResult result = UserResult.None; - - ContentDialog contentDialog = new() - { - Title = title, - PrimaryButtonText = primaryButton, - SecondaryButtonText = secondaryButton, - CloseButtonText = closeButton, - Content = content, - PrimaryButtonCommand = MiniCommand.Create(() => - { - result = primaryButtonResult; - }), - }; - - contentDialog.SecondaryButtonCommand = MiniCommand.Create(() => - { - result = UserResult.No; - contentDialog.PrimaryButtonClick -= deferCloseAction; - }); - - contentDialog.CloseButtonCommand = MiniCommand.Create(() => - { - result = UserResult.Cancel; - contentDialog.PrimaryButtonClick -= deferCloseAction; - }); - - if (deferResetEvent != null) - { - contentDialog.PrimaryButtonClick += deferCloseAction; - } - - await ShowAsync(contentDialog); - - return result; - } - - public async static Task<UserResult> ShowTextDialog( - string title, - string primaryText, - string secondaryText, - string primaryButton, - string secondaryButton, - string closeButton, - int iconSymbol, - UserResult primaryButtonResult = UserResult.Ok, - ManualResetEvent deferResetEvent = null, - TypedEventHandler<ContentDialog, ContentDialogButtonClickEventArgs> deferCloseAction = null) - { - Grid content = CreateTextDialogContent(primaryText, secondaryText, iconSymbol); - - return await ShowContentDialog(title, content, primaryButton, secondaryButton, closeButton, primaryButtonResult, deferResetEvent, deferCloseAction); - } - - public async static Task<UserResult> ShowDeferredContentDialog( - StyleableWindow window, - string title, - string primaryText, - string secondaryText, - string primaryButton, - string secondaryButton, - string closeButton, - int iconSymbol, - ManualResetEvent deferResetEvent, - Func<Window, Task> doWhileDeferred = null) - { - bool startedDeferring = false; - - return await ShowTextDialog( - title, - primaryText, - secondaryText, - primaryButton, - secondaryButton, - closeButton, - iconSymbol, - primaryButton == LocaleManager.Instance[LocaleKeys.InputDialogYes] ? UserResult.Yes : UserResult.Ok, - deferResetEvent, - DeferClose); - - async void DeferClose(ContentDialog sender, ContentDialogButtonClickEventArgs args) - { - if (startedDeferring) - { - return; - } - - sender.PrimaryButtonClick -= DeferClose; - - startedDeferring = true; - - var deferral = args.GetDeferral(); - - sender.PrimaryButtonClick -= DeferClose; - - _ = Task.Run(() => - { - deferResetEvent.WaitOne(); - - Dispatcher.UIThread.Post(() => - { - deferral.Complete(); - }); - }); - - if (doWhileDeferred != null) - { - await doWhileDeferred(window); - - deferResetEvent.Set(); - } - } - } - - private static Grid CreateTextDialogContent(string primaryText, string secondaryText, int symbol) - { - Grid content = new() - { - RowDefinitions = new RowDefinitions { new(), new() }, - ColumnDefinitions = new ColumnDefinitions { new(GridLength.Auto), new() }, - - MinHeight = 80, - }; - - SymbolIcon icon = new() - { - Symbol = (Symbol)symbol, - Margin = new Thickness(10), - FontSize = 40, - VerticalAlignment = VerticalAlignment.Center, - }; - - Grid.SetColumn(icon, 0); - Grid.SetRowSpan(icon, 2); - Grid.SetRow(icon, 0); - - TextBlock primaryLabel = new() - { - Text = primaryText, - Margin = new Thickness(5), - TextWrapping = TextWrapping.Wrap, - MaxWidth = 450, - }; - - TextBlock secondaryLabel = new() - { - Text = secondaryText, - Margin = new Thickness(5), - TextWrapping = TextWrapping.Wrap, - MaxWidth = 450, - }; - - Grid.SetColumn(primaryLabel, 1); - Grid.SetColumn(secondaryLabel, 1); - Grid.SetRow(primaryLabel, 0); - Grid.SetRow(secondaryLabel, 1); - - content.Children.Add(icon); - content.Children.Add(primaryLabel); - content.Children.Add(secondaryLabel); - - return content; - } - - public static async Task<UserResult> CreateInfoDialog( - string primary, - string secondaryText, - string acceptButton, - string closeButton, - string title) - { - return await ShowTextDialog( - title, - primary, - secondaryText, - acceptButton, - "", - closeButton, - (int)Symbol.Important); - } - - internal static async Task<UserResult> CreateConfirmationDialog( - string primaryText, - string secondaryText, - string acceptButtonText, - string cancelButtonText, - string title, - UserResult primaryButtonResult = UserResult.Yes) - { - return await ShowTextDialog( - string.IsNullOrWhiteSpace(title) ? LocaleManager.Instance[LocaleKeys.DialogConfirmationTitle] : title, - primaryText, - secondaryText, - acceptButtonText, - "", - cancelButtonText, - (int)Symbol.Help, - primaryButtonResult); - } - - internal static async Task CreateUpdaterInfoDialog(string primary, string secondaryText) - { - await ShowTextDialog( - LocaleManager.Instance[LocaleKeys.DialogUpdaterTitle], - primary, - secondaryText, - "", - "", - LocaleManager.Instance[LocaleKeys.InputDialogOk], - (int)Symbol.Important); - } - - internal static async Task CreateWarningDialog(string primary, string secondaryText) - { - await ShowTextDialog( - LocaleManager.Instance[LocaleKeys.DialogWarningTitle], - primary, - secondaryText, - "", - "", - LocaleManager.Instance[LocaleKeys.InputDialogOk], - (int)Symbol.Important); - } - - internal static async Task CreateErrorDialog(string errorMessage, string secondaryErrorMessage = "") - { - Logger.Error?.Print(LogClass.Application, errorMessage); - - await ShowTextDialog( - LocaleManager.Instance[LocaleKeys.DialogErrorTitle], - LocaleManager.Instance[LocaleKeys.DialogErrorMessage], - errorMessage, - secondaryErrorMessage, - "", - LocaleManager.Instance[LocaleKeys.InputDialogOk], - (int)Symbol.Dismiss); - } - - internal static async Task<bool> CreateChoiceDialog(string title, string primary, string secondaryText) - { - if (_isChoiceDialogOpen) - { - return false; - } - - _isChoiceDialogOpen = true; - - UserResult response = await ShowTextDialog( - title, - primary, - secondaryText, - LocaleManager.Instance[LocaleKeys.InputDialogYes], - "", - LocaleManager.Instance[LocaleKeys.InputDialogNo], - (int)Symbol.Help, - UserResult.Yes); - - _isChoiceDialogOpen = false; - - return response == UserResult.Yes; - } - - internal static async Task<bool> CreateExitDialog() - { - return await CreateChoiceDialog( - LocaleManager.Instance[LocaleKeys.DialogExitTitle], - LocaleManager.Instance[LocaleKeys.DialogExitMessage], - LocaleManager.Instance[LocaleKeys.DialogExitSubMessage]); - } - - internal static async Task<bool> CreateStopEmulationDialog() - { - return await CreateChoiceDialog( - LocaleManager.Instance[LocaleKeys.DialogStopEmulationTitle], - LocaleManager.Instance[LocaleKeys.DialogStopEmulationMessage], - LocaleManager.Instance[LocaleKeys.DialogExitSubMessage]); - } - - public static async Task<ContentDialogResult> ShowAsync(ContentDialog contentDialog) - { - ContentDialogResult result; - bool isTopDialog = true; - - Window parent = GetMainWindow(); - - if (_contentDialogOverlayWindow != null) - { - isTopDialog = false; - } - - if (parent is MainWindow window) - { - parent.Activate(); - - _contentDialogOverlayWindow = new ContentDialogOverlayWindow - { - Height = parent.Bounds.Height, - Width = parent.Bounds.Width, - Position = parent.PointToScreen(new Point()), - ShowInTaskbar = false, - }; - - parent.PositionChanged += OverlayOnPositionChanged; - - void OverlayOnPositionChanged(object sender, PixelPointEventArgs e) - { - if (_contentDialogOverlayWindow is null) - { - return; - } - - _contentDialogOverlayWindow.Position = parent.PointToScreen(new Point()); - } - - _contentDialogOverlayWindow.ContentDialog = contentDialog; - - bool opened = false; - - _contentDialogOverlayWindow.Opened += OverlayOnActivated; - - async void OverlayOnActivated(object sender, EventArgs e) - { - if (opened) - { - return; - } - - opened = true; - - _contentDialogOverlayWindow.Position = parent.PointToScreen(new Point()); - - result = await ShowDialog(); - } - - result = await _contentDialogOverlayWindow.ShowDialog<ContentDialogResult>(parent); - } - else - { - result = await ShowDialog(); - } - - async Task<ContentDialogResult> ShowDialog() - { - if (_contentDialogOverlayWindow is not null) - { - result = await contentDialog.ShowAsync(_contentDialogOverlayWindow); - - _contentDialogOverlayWindow!.Close(); - } - else - { - result = ContentDialogResult.None; - - Logger.Warning?.Print(LogClass.UI, "Content dialog overlay failed to populate. Default value has been returned."); - } - - return result; - } - - if (isTopDialog && _contentDialogOverlayWindow is not null) - { - _contentDialogOverlayWindow.Content = null; - _contentDialogOverlayWindow.Close(); - _contentDialogOverlayWindow = null; - } - - return result; - } - - public static Task ShowWindowAsync(Window dialogWindow, Window mainWindow = null) - { - mainWindow ??= GetMainWindow(); - - return dialogWindow.ShowDialog(_contentDialogOverlayWindow ?? mainWindow); - } - - private static Window GetMainWindow() - { - if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime al) - { - foreach (Window item in al.Windows) - { - if (item is MainWindow window) - { - return window; - } - } - } - - return null; - } - } -} diff --git a/src/Ryujinx.Ava/UI/Helpers/Glyph.cs b/src/Ryujinx.Ava/UI/Helpers/Glyph.cs deleted file mode 100644 index f257dc02..00000000 --- a/src/Ryujinx.Ava/UI/Helpers/Glyph.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ryujinx.Ava.UI.Helpers -{ - public enum Glyph - { - List, - Grid, - Chip, - } -} diff --git a/src/Ryujinx.Ava/UI/Helpers/GlyphValueConverter.cs b/src/Ryujinx.Ava/UI/Helpers/GlyphValueConverter.cs deleted file mode 100644 index 7da23648..00000000 --- a/src/Ryujinx.Ava/UI/Helpers/GlyphValueConverter.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Avalonia.Markup.Xaml; -using FluentAvalonia.UI.Controls; -using System; -using System.Collections.Generic; - -namespace Ryujinx.Ava.UI.Helpers -{ - public class GlyphValueConverter : MarkupExtension - { - private readonly string _key; - - private static readonly Dictionary<Glyph, string> _glyphs = new() - { - { Glyph.List, char.ConvertFromUtf32((int)Symbol.List) }, - { Glyph.Grid, char.ConvertFromUtf32((int)Symbol.ViewAll) }, - { Glyph.Chip, char.ConvertFromUtf32(59748) }, - }; - - public GlyphValueConverter(string key) - { - _key = key; - } - - public string this[string key] - { - get - { - if (_glyphs.TryGetValue(Enum.Parse<Glyph>(key), out var val)) - { - return val; - } - - return string.Empty; - } - } - - public override object ProvideValue(IServiceProvider serviceProvider) - { - return this[_key]; - } - } -} diff --git a/src/Ryujinx.Ava/UI/Helpers/KeyValueConverter.cs b/src/Ryujinx.Ava/UI/Helpers/KeyValueConverter.cs deleted file mode 100644 index 028ed6bf..00000000 --- a/src/Ryujinx.Ava/UI/Helpers/KeyValueConverter.cs +++ /dev/null @@ -1,46 +0,0 @@ -using Avalonia.Data.Converters; -using Ryujinx.Common.Configuration.Hid; -using Ryujinx.Common.Configuration.Hid.Controller; -using System; -using System.Globalization; - -namespace Ryujinx.Ava.UI.Helpers -{ - internal class KeyValueConverter : IValueConverter - { - public static KeyValueConverter Instance = new(); - - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - if (value == null) - { - return null; - } - - return value.ToString(); - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - object key = null; - - if (value != null) - { - if (targetType == typeof(Key)) - { - key = Enum.Parse<Key>(value.ToString()); - } - else if (targetType == typeof(GamepadInputId)) - { - key = Enum.Parse<GamepadInputId>(value.ToString()); - } - else if (targetType == typeof(StickInputId)) - { - key = Enum.Parse<StickInputId>(value.ToString()); - } - } - - return key; - } - } -} diff --git a/src/Ryujinx.Ava/UI/Helpers/LocalizedNeverConverter.cs b/src/Ryujinx.Ava/UI/Helpers/LocalizedNeverConverter.cs deleted file mode 100644 index 26fe36c4..00000000 --- a/src/Ryujinx.Ava/UI/Helpers/LocalizedNeverConverter.cs +++ /dev/null @@ -1,43 +0,0 @@ -using Avalonia.Data.Converters; -using Avalonia.Markup.Xaml; -using Ryujinx.Ava.Common.Locale; -using Ryujinx.UI.Common.Helper; -using System; -using System.Globalization; - -namespace Ryujinx.Ava.UI.Helpers -{ - /// <summary> - /// This <see cref="IValueConverter"/> makes sure that the string "Never" that's returned by <see cref="ValueFormatUtils.FormatDateTime"/> is properly localized in the Avalonia UI. - /// After the Avalonia UI has been made the default and the GTK UI is removed, <see cref="ValueFormatUtils"/> should be updated to directly return a localized string. - /// </summary> - internal class LocalizedNeverConverter : MarkupExtension, IValueConverter - { - private static readonly LocalizedNeverConverter _instance = new(); - - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - if (value is not string valStr) - { - return ""; - } - - if (valStr == "Never") - { - return LocaleManager.Instance[LocaleKeys.Never]; - } - - return valStr; - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - throw new NotSupportedException(); - } - - public override object ProvideValue(IServiceProvider serviceProvider) - { - return _instance; - } - } -} diff --git a/src/Ryujinx.Ava/UI/Helpers/LoggerAdapter.cs b/src/Ryujinx.Ava/UI/Helpers/LoggerAdapter.cs deleted file mode 100644 index fc714541..00000000 --- a/src/Ryujinx.Ava/UI/Helpers/LoggerAdapter.cs +++ /dev/null @@ -1,102 +0,0 @@ -using Avalonia.Logging; -using Avalonia.Utilities; -using Ryujinx.Common.Logging; -using System; -using System.Text; - -namespace Ryujinx.Ava.UI.Helpers -{ - using AvaLogger = Avalonia.Logging.Logger; - using AvaLogLevel = LogEventLevel; - using RyuLogClass = LogClass; - using RyuLogger = Ryujinx.Common.Logging.Logger; - - internal class LoggerAdapter : ILogSink - { - public static void Register() - { - AvaLogger.Sink = new LoggerAdapter(); - } - - private static RyuLogger.Log? GetLog(AvaLogLevel level) - { - return level switch - { - AvaLogLevel.Verbose => RyuLogger.Debug, - AvaLogLevel.Debug => RyuLogger.Debug, - AvaLogLevel.Information => RyuLogger.Debug, - AvaLogLevel.Warning => RyuLogger.Debug, - AvaLogLevel.Error => RyuLogger.Error, - AvaLogLevel.Fatal => RyuLogger.Error, - _ => throw new ArgumentOutOfRangeException(nameof(level), level, null), - }; - } - - public bool IsEnabled(AvaLogLevel level, string area) - { - return GetLog(level) != null; - } - - public void Log(AvaLogLevel level, string area, object source, string messageTemplate) - { - GetLog(level)?.PrintMsg(RyuLogClass.UI, Format(level, area, messageTemplate, source, null)); - } - - public void Log(AvaLogLevel level, string area, object source, string messageTemplate, params object[] propertyValues) - { - GetLog(level)?.PrintMsg(RyuLogClass.UI, Format(level, area, messageTemplate, source, propertyValues)); - } - - private static string Format(AvaLogLevel level, string area, string template, object source, object[] v) - { - var result = new StringBuilder(); - var r = new CharacterReader(template.AsSpan()); - int i = 0; - - result.Append('['); - result.Append(level); - result.Append("] "); - - result.Append('['); - result.Append(area); - result.Append("] "); - - while (!r.End) - { - var c = r.Take(); - - if (c != '{') - { - result.Append(c); - } - else - { - if (r.Peek != '{') - { - result.Append('\''); - result.Append(i < v.Length ? v[i++] : null); - result.Append('\''); - r.TakeUntil('}'); - r.Take(); - } - else - { - result.Append('{'); - r.Take(); - } - } - } - - if (source != null) - { - result.Append(" ("); - result.Append(source.GetType().Name); - result.Append(" #"); - result.Append(source.GetHashCode()); - result.Append(')'); - } - - return result.ToString(); - } - } -} diff --git a/src/Ryujinx.Ava/UI/Helpers/MiniCommand.cs b/src/Ryujinx.Ava/UI/Helpers/MiniCommand.cs deleted file mode 100644 index 7e1bb9a6..00000000 --- a/src/Ryujinx.Ava/UI/Helpers/MiniCommand.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System; -using System.Threading.Tasks; -using System.Windows.Input; - -namespace Ryujinx.Ava.UI.Helpers -{ - public sealed class MiniCommand<T> : MiniCommand, ICommand - { - private readonly Action<T> _callback; - private bool _busy; - private readonly Func<T, Task> _asyncCallback; - - public MiniCommand(Action<T> callback) - { - _callback = callback; - } - - public MiniCommand(Func<T, Task> callback) - { - _asyncCallback = callback; - } - - private bool Busy - { - get => _busy; - set - { - _busy = value; - CanExecuteChanged?.Invoke(this, EventArgs.Empty); - } - } - - public override event EventHandler CanExecuteChanged; - public override bool CanExecute(object parameter) => !_busy; - - public override async void Execute(object parameter) - { - if (Busy) - { - return; - } - try - { - Busy = true; - if (_callback != null) - { - _callback((T)parameter); - } - else - { - await _asyncCallback((T)parameter); - } - } - finally - { - Busy = false; - } - } - } - - public abstract class MiniCommand : ICommand - { - public static MiniCommand Create(Action callback) => new MiniCommand<object>(_ => callback()); - public static MiniCommand Create<TArg>(Action<TArg> callback) => new MiniCommand<TArg>(callback); - public static MiniCommand CreateFromTask(Func<Task> callback) => new MiniCommand<object>(_ => callback()); - - public abstract bool CanExecute(object parameter); - public abstract void Execute(object parameter); - public abstract event EventHandler CanExecuteChanged; - } -} diff --git a/src/Ryujinx.Ava/UI/Helpers/NotificationHelper.cs b/src/Ryujinx.Ava/UI/Helpers/NotificationHelper.cs deleted file mode 100644 index 656a8b52..00000000 --- a/src/Ryujinx.Ava/UI/Helpers/NotificationHelper.cs +++ /dev/null @@ -1,70 +0,0 @@ -using Avalonia; -using Avalonia.Controls; -using Avalonia.Controls.Notifications; -using Avalonia.Threading; -using Ryujinx.Ava.Common.Locale; -using Ryujinx.Common; -using System; -using System.Collections.Concurrent; -using System.Threading; - -namespace Ryujinx.Ava.UI.Helpers -{ - public static class NotificationHelper - { - private const int MaxNotifications = 4; - private const int NotificationDelayInMs = 5000; - - private static WindowNotificationManager _notificationManager; - - private static readonly BlockingCollection<Notification> _notifications = new(); - - public static void SetNotificationManager(Window host) - { - _notificationManager = new WindowNotificationManager(host) - { - Position = NotificationPosition.BottomRight, - MaxItems = MaxNotifications, - Margin = new Thickness(0, 0, 15, 40), - }; - - var maybeAsyncWorkQueue = new Lazy<AsyncWorkQueue<Notification>>( - () => new AsyncWorkQueue<Notification>(notification => - { - Dispatcher.UIThread.Post(() => - { - _notificationManager.Show(notification); - }); - }, - "UI.NotificationThread", - _notifications), - LazyThreadSafetyMode.ExecutionAndPublication); - - _notificationManager.TemplateApplied += (sender, args) => - { - // NOTE: Force creation of the AsyncWorkQueue. - _ = maybeAsyncWorkQueue.Value; - }; - - host.Closing += (sender, args) => - { - if (maybeAsyncWorkQueue.IsValueCreated) - { - maybeAsyncWorkQueue.Value.Dispose(); - } - }; - } - - public static void Show(string title, string text, NotificationType type, bool waitingExit = false, Action onClick = null, Action onClose = null) - { - var delay = waitingExit ? TimeSpan.FromMilliseconds(0) : TimeSpan.FromMilliseconds(NotificationDelayInMs); - - _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); - } - } -} diff --git a/src/Ryujinx.Ava/UI/Helpers/OffscreenTextBox.cs b/src/Ryujinx.Ava/UI/Helpers/OffscreenTextBox.cs deleted file mode 100644 index a055f335..00000000 --- a/src/Ryujinx.Ava/UI/Helpers/OffscreenTextBox.cs +++ /dev/null @@ -1,39 +0,0 @@ -using Avalonia.Controls; -using Avalonia.Input; -using Avalonia.Interactivity; - -namespace Ryujinx.Ava.UI.Helpers -{ - public class OffscreenTextBox : TextBox - { - public static RoutedEvent<KeyEventArgs> GetKeyDownRoutedEvent() - { - return KeyDownEvent; - } - - public static RoutedEvent<KeyEventArgs> GetKeyUpRoutedEvent() - { - return KeyUpEvent; - } - - public void SendKeyDownEvent(KeyEventArgs keyEvent) - { - OnKeyDown(keyEvent); - } - - public void SendKeyUpEvent(KeyEventArgs keyEvent) - { - OnKeyUp(keyEvent); - } - - public void SendText(string text) - { - OnTextInput(new TextInputEventArgs - { - Text = text, - Source = this, - RoutedEvent = TextInputEvent, - }); - } - } -} diff --git a/src/Ryujinx.Ava/UI/Helpers/TimeZoneConverter.cs b/src/Ryujinx.Ava/UI/Helpers/TimeZoneConverter.cs deleted file mode 100644 index 876d51f7..00000000 --- a/src/Ryujinx.Ava/UI/Helpers/TimeZoneConverter.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Avalonia.Data.Converters; -using System; -using System.Globalization; -using TimeZone = Ryujinx.Ava.UI.Models.TimeZone; - -namespace Ryujinx.Ava.UI.Helpers -{ - internal class TimeZoneConverter : IValueConverter - { - public static TimeZoneConverter Instance = new(); - - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - if (value == 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) - { - throw new NotImplementedException(); - } - } -} diff --git a/src/Ryujinx.Ava/UI/Helpers/UserErrorDialog.cs b/src/Ryujinx.Ava/UI/Helpers/UserErrorDialog.cs deleted file mode 100644 index 9a44b862..00000000 --- a/src/Ryujinx.Ava/UI/Helpers/UserErrorDialog.cs +++ /dev/null @@ -1,90 +0,0 @@ -using Ryujinx.Ava.Common.Locale; -using Ryujinx.UI.Common; -using Ryujinx.UI.Common.Helper; -using System.Threading.Tasks; - -namespace Ryujinx.Ava.UI.Helpers -{ - internal class UserErrorDialog - { - private const string SetupGuideUrl = "https://github.com/Ryujinx/Ryujinx/wiki/Ryujinx-Setup-&-Configuration-Guide"; - - private static string GetErrorCode(UserError error) - { - return $"RYU-{(uint)error:X4}"; - } - - private static string GetErrorTitle(UserError error) - { - return error switch - { - UserError.NoKeys => LocaleManager.Instance[LocaleKeys.UserErrorNoKeys], - UserError.NoFirmware => LocaleManager.Instance[LocaleKeys.UserErrorNoFirmware], - UserError.FirmwareParsingFailed => LocaleManager.Instance[LocaleKeys.UserErrorFirmwareParsingFailed], - UserError.ApplicationNotFound => LocaleManager.Instance[LocaleKeys.UserErrorApplicationNotFound], - UserError.Unknown => LocaleManager.Instance[LocaleKeys.UserErrorUnknown], - _ => LocaleManager.Instance[LocaleKeys.UserErrorUndefined], - }; - } - - private static string GetErrorDescription(UserError error) - { - return error switch - { - UserError.NoKeys => LocaleManager.Instance[LocaleKeys.UserErrorNoKeysDescription], - UserError.NoFirmware => LocaleManager.Instance[LocaleKeys.UserErrorNoFirmwareDescription], - UserError.FirmwareParsingFailed => LocaleManager.Instance[LocaleKeys.UserErrorFirmwareParsingFailedDescription], - UserError.ApplicationNotFound => LocaleManager.Instance[LocaleKeys.UserErrorApplicationNotFoundDescription], - UserError.Unknown => LocaleManager.Instance[LocaleKeys.UserErrorUnknownDescription], - _ => LocaleManager.Instance[LocaleKeys.UserErrorUndefinedDescription], - }; - } - - private static bool IsCoveredBySetupGuide(UserError error) - { - return error switch - { - UserError.NoKeys or - UserError.NoFirmware or - UserError.FirmwareParsingFailed => true, - _ => false, - }; - } - - private static string GetSetupGuideUrl(UserError error) - { - if (!IsCoveredBySetupGuide(error)) - { - return null; - } - - return error switch - { - UserError.NoKeys => SetupGuideUrl + "#initial-setup---placement-of-prodkeys", - UserError.NoFirmware => SetupGuideUrl + "#initial-setup-continued---installation-of-firmware", - _ => SetupGuideUrl, - }; - } - - public static async Task ShowUserErrorDialog(UserError error) - { - string errorCode = GetErrorCode(error); - - bool isInSetupGuide = IsCoveredBySetupGuide(error); - - string setupButtonLabel = isInSetupGuide ? LocaleManager.Instance[LocaleKeys.OpenSetupGuideMessage] : ""; - - var result = await ContentDialogHelper.CreateInfoDialog( - LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogUserErrorDialogMessage, errorCode, GetErrorTitle(error)), - GetErrorDescription(error) + (isInSetupGuide - ? LocaleManager.Instance[LocaleKeys.DialogUserErrorDialogInfoMessage] - : ""), setupButtonLabel, LocaleManager.Instance[LocaleKeys.InputDialogOk], - LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogUserErrorDialogTitle, errorCode)); - - if (result == UserResult.Ok) - { - OpenHelper.OpenUrl(GetSetupGuideUrl(error)); - } - } - } -} diff --git a/src/Ryujinx.Ava/UI/Helpers/UserResult.cs b/src/Ryujinx.Ava/UI/Helpers/UserResult.cs deleted file mode 100644 index 2fcd35ae..00000000 --- a/src/Ryujinx.Ava/UI/Helpers/UserResult.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Ryujinx.Ava.UI.Helpers -{ - public enum UserResult - { - Ok, - Yes, - No, - Abort, - Cancel, - None, - } -} diff --git a/src/Ryujinx.Ava/UI/Helpers/Win32NativeInterop.cs b/src/Ryujinx.Ava/UI/Helpers/Win32NativeInterop.cs deleted file mode 100644 index 4834df80..00000000 --- a/src/Ryujinx.Ava/UI/Helpers/Win32NativeInterop.cs +++ /dev/null @@ -1,125 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; -using System.Runtime.Versioning; - -namespace Ryujinx.Ava.UI.Helpers -{ - [SupportedOSPlatform("windows")] - internal partial class Win32NativeInterop - { - [Flags] - public enum ClassStyles : uint - { - CsClassdc = 0x40, - CsOwndc = 0x20, - } - - [Flags] - public enum WindowStyles : uint - { - WsChild = 0x40000000, - } - - public enum Cursors : uint - { - IdcArrow = 32512, - } - - [SuppressMessage("Design", "CA1069: Enums values should not be duplicated")] - public enum WindowsMessages : uint - { - Mousemove = 0x0200, - Lbuttondown = 0x0201, - Lbuttonup = 0x0202, - Lbuttondblclk = 0x0203, - Rbuttondown = 0x0204, - Rbuttonup = 0x0205, - Rbuttondblclk = 0x0206, - Mbuttondown = 0x0207, - Mbuttonup = 0x0208, - Mbuttondblclk = 0x0209, - Mousewheel = 0x020A, - Xbuttondown = 0x020B, - Xbuttonup = 0x020C, - Xbuttondblclk = 0x020D, - Mousehwheel = 0x020E, - Mouselast = 0x020E, - } - - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - internal delegate IntPtr WindowProc(IntPtr hWnd, WindowsMessages msg, IntPtr wParam, IntPtr lParam); - - [StructLayout(LayoutKind.Sequential)] - public struct WndClassEx - { - public int cbSize; - public ClassStyles style; - public IntPtr lpfnWndProc; // not WndProc - public int cbClsExtra; - public int cbWndExtra; - public IntPtr hInstance; - public IntPtr hIcon; - public IntPtr hCursor; - public IntPtr hbrBackground; - public IntPtr lpszMenuName; - public IntPtr lpszClassName; - public IntPtr hIconSm; - - public WndClassEx() - { - cbSize = Marshal.SizeOf<WndClassEx>(); - } - } - - public static IntPtr CreateEmptyCursor() - { - return CreateCursor(IntPtr.Zero, 0, 0, 1, 1, new byte[] { 0xFF }, new byte[] { 0x00 }); - } - - public static IntPtr CreateArrowCursor() - { - return LoadCursor(IntPtr.Zero, (IntPtr)Cursors.IdcArrow); - } - - [LibraryImport("user32.dll")] - public static partial IntPtr SetCursor(IntPtr handle); - - [LibraryImport("user32.dll")] - public static partial IntPtr CreateCursor(IntPtr hInst, int xHotSpot, int yHotSpot, int nWidth, int nHeight, [In] byte[] pvAndPlane, [In] byte[] pvXorPlane); - - [LibraryImport("user32.dll", SetLastError = true, EntryPoint = "RegisterClassExW")] - public static partial ushort RegisterClassEx(ref WndClassEx param); - - [LibraryImport("user32.dll", SetLastError = true, EntryPoint = "UnregisterClassW")] - public static partial short UnregisterClass([MarshalAs(UnmanagedType.LPWStr)] string lpClassName, IntPtr instance); - - [LibraryImport("user32.dll", EntryPoint = "DefWindowProcW")] - public static partial IntPtr DefWindowProc(IntPtr hWnd, WindowsMessages msg, IntPtr wParam, IntPtr lParam); - - [LibraryImport("kernel32.dll", EntryPoint = "GetModuleHandleA")] - public static partial IntPtr GetModuleHandle([MarshalAs(UnmanagedType.LPStr)] string lpModuleName); - - [LibraryImport("user32.dll", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static partial bool DestroyWindow(IntPtr hwnd); - - [LibraryImport("user32.dll", SetLastError = true, EntryPoint = "LoadCursorA")] - public static partial IntPtr LoadCursor(IntPtr hInstance, IntPtr lpCursorName); - - [LibraryImport("user32.dll", SetLastError = true, EntryPoint = "CreateWindowExW")] - public static partial IntPtr CreateWindowEx( - uint dwExStyle, - [MarshalAs(UnmanagedType.LPWStr)] string lpClassName, - [MarshalAs(UnmanagedType.LPWStr)] string lpWindowName, - WindowStyles dwStyle, - int x, - int y, - int nWidth, - int nHeight, - IntPtr hWndParent, - IntPtr hMenu, - IntPtr hInstance, - IntPtr lpParam); - } -} |
