ryujinx/Ryujinx.Ava/Ui/Controls/ContentDialogHelper.cs
Emmanuel Hansen 594246ea47
UI - Avalonia Part 2 (#3351)
* add settings windows and children views

* Expose hotkeys configuration on the UI

* Remove double spacing from locale JSON

* simplify button assigner

* add cemuhook buttons and title to locale

* move common button assigner to own class

* cancel button assigner when window is closed

* remove unused setting

* address review. fix controller profile not loading default when switching devices

* fix updater file name

* Input cleanup (#37)

* addressed review

* add device type to controller device checks

* change accessibility modifier of public classes to internal

* Update Ryujinx.Ava/Ui/ViewModels/ControllerSettingsViewModel.cs

Co-authored-by: gdkchan <gab.dark.100@gmail.com>

* Update de_DE.json

* Update de_DE.json

* Update tr_TR.json

Translated newly added lines

* Update it_IT.json

* fix rebase

* update avalonia

* fix wrong key used for button text

* Align settings window elements

* Tabs to spaces

* Update brazilian portuguese translation

* Minor improvement on brazilian portuguese translation

* fix turkish translation

* remove unused text

* change view related classes to public

* unsubscribe from deferred event if dialog is closed

* Load the default language before loading any other when switching languages

* Make controller settings more compact

* increase default width of settings window, reduce profile buttons width

Co-authored-by: gdk <gab.dark.100@gmail.com>
Co-authored-by: MutantAura <44103205+MutantAura@users.noreply.github.com>
Co-authored-by: Niwu34 <67392333+Niwu34@users.noreply.github.com>
Co-authored-by: aegiff <99728970+aegiff@users.noreply.github.com>
Co-authored-by: Antonio Brugnolo <36473846+AntoSkate@users.noreply.github.com>
2022-07-05 20:06:31 +02:00

361 lines
12 KiB
C#

using Avalonia.Controls;
using Avalonia.Threading;
using FluentAvalonia.UI.Controls;
using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.Ui.Models;
using Ryujinx.Ava.Ui.Windows;
using Ryujinx.Common.Logging;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Ryujinx.Ava.Ui.Controls
{
public static class ContentDialogHelper
{
private static bool _isChoiceDialogOpen;
private async static Task<UserResult> ShowContentDialog(
StyleableWindow window,
string title,
string primaryText,
string secondaryText,
string primaryButton,
string secondaryButton,
string closeButton,
int iconSymbol,
UserResult primaryButtonResult = UserResult.Ok)
{
UserResult result = UserResult.None;
ContentDialog contentDialog = window.ContentDialog;
await ShowDialog();
async Task ShowDialog()
{
if (contentDialog != null)
{
contentDialog.Title = title;
contentDialog.PrimaryButtonText = primaryButton;
contentDialog.SecondaryButtonText = secondaryButton;
contentDialog.CloseButtonText = closeButton;
contentDialog.Content = CreateDialogTextContent(primaryText, secondaryText, iconSymbol);
contentDialog.PrimaryButtonCommand = MiniCommand.Create(() =>
{
result = primaryButtonResult;
});
contentDialog.SecondaryButtonCommand = MiniCommand.Create(() =>
{
result = UserResult.No;
});
contentDialog.CloseButtonCommand = MiniCommand.Create(() =>
{
result = UserResult.Cancel;
});
await contentDialog.ShowAsync(ContentDialogPlacement.Popup);
};
}
return result;
}
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;
UserResult result = UserResult.None;
ContentDialog contentDialog = window.ContentDialog;
Window overlay = window;
if (contentDialog != null)
{
contentDialog.PrimaryButtonClick += DeferClose;
contentDialog.Title = title;
contentDialog.PrimaryButtonText = primaryButton;
contentDialog.SecondaryButtonText = secondaryButton;
contentDialog.CloseButtonText = closeButton;
contentDialog.Content = CreateDialogTextContent(primaryText, secondaryText, iconSymbol);
contentDialog.PrimaryButtonCommand = MiniCommand.Create(() =>
{
result = primaryButton == LocaleManager.Instance["InputDialogYes"] ? UserResult.Yes : UserResult.Ok;
});
contentDialog.SecondaryButtonCommand = MiniCommand.Create(() =>
{
contentDialog.PrimaryButtonClick -= DeferClose;
result = UserResult.No;
});
contentDialog.CloseButtonCommand = MiniCommand.Create(() =>
{
contentDialog.PrimaryButtonClick -= DeferClose;
result = UserResult.Cancel;
});
await contentDialog.ShowAsync(ContentDialogPlacement.Popup);
};
return result;
async void DeferClose(ContentDialog sender, ContentDialogButtonClickEventArgs args)
{
if (startedDeferring)
{
return;
}
contentDialog.PrimaryButtonClick -= DeferClose;
startedDeferring = true;
var deferral = args.GetDeferral();
result = primaryButton == LocaleManager.Instance["InputDialogYes"] ? UserResult.Yes : UserResult.Ok;
contentDialog.PrimaryButtonClick -= DeferClose;
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
Task.Run(() =>
{
deferResetEvent.WaitOne();
Dispatcher.UIThread.Post(() =>
{
deferral.Complete();
});
});
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
if (doWhileDeferred != null)
{
await doWhileDeferred(overlay);
deferResetEvent.Set();
}
}
}
private static Grid CreateDialogTextContent(string primaryText, string secondaryText, int symbol)
{
Grid content = new Grid();
content.RowDefinitions = new RowDefinitions() { new RowDefinition(), new RowDefinition() };
content.ColumnDefinitions = new ColumnDefinitions() { new ColumnDefinition(GridLength.Auto), new ColumnDefinition() };
content.MinHeight = 80;
SymbolIcon icon = new SymbolIcon { Symbol = (Symbol)symbol, Margin = new Avalonia.Thickness(10) };
icon.FontSize = 40;
icon.VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center;
Grid.SetColumn(icon, 0);
Grid.SetRowSpan(icon, 2);
Grid.SetRow(icon, 0);
TextBlock primaryLabel = new TextBlock()
{
Text = primaryText,
Margin = new Avalonia.Thickness(5),
TextWrapping = Avalonia.Media.TextWrapping.Wrap,
MaxWidth = 450
};
TextBlock secondaryLabel = new TextBlock()
{
Text = secondaryText,
Margin = new Avalonia.Thickness(5),
TextWrapping = Avalonia.Media.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(
StyleableWindow window,
string primary,
string secondaryText,
string acceptButton,
string closeButton,
string title)
{
return await ShowContentDialog(
window,
title,
primary,
secondaryText,
acceptButton,
"",
closeButton,
(int)Symbol.Important);
}
internal static async Task<UserResult> CreateConfirmationDialog(
StyleableWindow window,
string primaryText,
string secondaryText,
string acceptButtonText,
string cancelButtonText,
string title,
UserResult primaryButtonResult = UserResult.Yes)
{
return await ShowContentDialog(
window,
string.IsNullOrWhiteSpace(title) ? LocaleManager.Instance["DialogConfirmationTitle"] : title,
primaryText,
secondaryText,
acceptButtonText,
"",
cancelButtonText,
(int)Symbol.Help,
primaryButtonResult);
}
internal static UpdateWaitWindow CreateWaitingDialog(string mainText, string secondaryText)
{
return new(mainText, secondaryText);
}
internal static async void CreateUpdaterInfoDialog(StyleableWindow window, string primary, string secondaryText)
{
await ShowContentDialog(
window,
LocaleManager.Instance["DialogUpdaterTitle"],
primary,
secondaryText,
"",
"",
LocaleManager.Instance["InputDialogOk"],
(int)Symbol.Important);
}
internal static async void ShowNotAvailableMessage(StyleableWindow window)
{
// Temporary placeholder for features to be added
await ShowContentDialog(
window,
"Feature Not Available",
"The selected feature is not available in this version.",
"",
"",
"",
LocaleManager.Instance["InputDialogOk"],
(int)Symbol.Important);
}
internal static async void CreateWarningDialog(StyleableWindow window, string primary, string secondaryText)
{
await ShowContentDialog(
window,
LocaleManager.Instance["DialogWarningTitle"],
primary,
secondaryText,
"",
"",
LocaleManager.Instance["InputDialogOk"],
(int)Symbol.Important);
}
internal static async void CreateErrorDialog(StyleableWindow owner, string errorMessage, string secondaryErrorMessage = "")
{
Logger.Error?.Print(LogClass.Application, errorMessage);
await ShowContentDialog(
owner,
LocaleManager.Instance["DialogErrorTitle"],
LocaleManager.Instance["DialogErrorMessage"],
errorMessage,
secondaryErrorMessage,
"",
LocaleManager.Instance["InputDialogOk"],
(int)Symbol.Dismiss);
}
internal static async Task<bool> CreateChoiceDialog(StyleableWindow window, string title, string primary, string secondaryText)
{
if (_isChoiceDialogOpen)
{
return false;
}
_isChoiceDialogOpen = true;
UserResult response =
await ShowContentDialog(
window,
title,
primary,
secondaryText,
LocaleManager.Instance["InputDialogYes"],
"",
LocaleManager.Instance["InputDialogNo"],
(int)Symbol.Help,
UserResult.Yes);
_isChoiceDialogOpen = false;
return response == UserResult.Yes;
}
internal static async Task<bool> CreateExitDialog(StyleableWindow owner)
{
return await CreateChoiceDialog(
owner,
LocaleManager.Instance["DialogExitTitle"],
LocaleManager.Instance["DialogExitMessage"],
LocaleManager.Instance["DialogExitSubMessage"]);
}
internal static async Task<bool> CreateStopEmulationDialog(StyleableWindow owner)
{
return await CreateChoiceDialog(
owner,
LocaleManager.Instance["DialogStopEmulationTitle"],
LocaleManager.Instance["DialogStopEmulationMessage"],
LocaleManager.Instance["DialogExitSubMessage"]);
}
internal static async Task<string> CreateInputDialog(
string title,
string mainText,
string subText,
StyleableWindow owner,
uint maxLength = int.MaxValue,
string input = "")
{
var result = await InputDialog.ShowInputDialog(
owner,
title,
mainText,
input,
subText,
maxLength);
if (result.Result == UserResult.Ok)
{
return result.Input;
}
return string.Empty;
}
}
}