forked from Mirror/Ryujinx
Ava: Fix nca extraction window never closing & minor cleanup (#4569)
* ava: Remove unused doWhileDeferred parameters * ava: Minimally improve swkbd dialog It's currently impossible to get the dialog to redirect focus to the InputBox. * ava: Fix nca extraction dialog never closing Also contains some minor cleanup
This commit is contained in:
parent
c5258cf082
commit
6dbcdfea47
9 changed files with 45 additions and 184 deletions
|
@ -13,6 +13,7 @@ using LibHac.Tools.Fs;
|
||||||
using LibHac.Tools.FsSystem;
|
using LibHac.Tools.FsSystem;
|
||||||
using LibHac.Tools.FsSystem.NcaUtils;
|
using LibHac.Tools.FsSystem.NcaUtils;
|
||||||
using Ryujinx.Ava.Common.Locale;
|
using Ryujinx.Ava.Common.Locale;
|
||||||
|
using Ryujinx.Ava.UI.Controls;
|
||||||
using Ryujinx.Ava.UI.Helpers;
|
using Ryujinx.Ava.UI.Helpers;
|
||||||
using Ryujinx.Ava.UI.Windows;
|
using Ryujinx.Ava.UI.Windows;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
|
@ -152,24 +153,16 @@ namespace Ryujinx.Ava.Common
|
||||||
string destination = await folderDialog.ShowAsync(_owner);
|
string destination = await folderDialog.ShowAsync(_owner);
|
||||||
var cancellationToken = new CancellationTokenSource();
|
var cancellationToken = new CancellationTokenSource();
|
||||||
|
|
||||||
|
UpdateWaitWindow waitingDialog = new(
|
||||||
|
LocaleManager.Instance[LocaleKeys.DialogNcaExtractionTitle],
|
||||||
|
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogNcaExtractionMessage, ncaSectionType, Path.GetFileName(titleFilePath)),
|
||||||
|
cancellationToken);
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(destination))
|
if (!string.IsNullOrWhiteSpace(destination))
|
||||||
{
|
{
|
||||||
Thread extractorThread = new(() =>
|
Thread extractorThread = new(() =>
|
||||||
{
|
{
|
||||||
Dispatcher.UIThread.Post(async () =>
|
Dispatcher.UIThread.Post(waitingDialog.Show);
|
||||||
{
|
|
||||||
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
|
|
||||||
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogNcaExtractionMessage, ncaSectionType, Path.GetFileName(titleFilePath)),
|
|
||||||
"",
|
|
||||||
"",
|
|
||||||
LocaleManager.Instance[LocaleKeys.InputDialogCancel],
|
|
||||||
LocaleManager.Instance[LocaleKeys.DialogNcaExtractionTitle]);
|
|
||||||
|
|
||||||
if (result == UserResult.Cancel)
|
|
||||||
{
|
|
||||||
cancellationToken.Cancel();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
using FileStream file = new(titleFilePath, FileMode.Open, FileAccess.Read);
|
using FileStream file = new(titleFilePath, FileMode.Open, FileAccess.Read);
|
||||||
|
|
||||||
|
@ -222,6 +215,8 @@ namespace Ryujinx.Ava.Common
|
||||||
|
|
||||||
Dispatcher.UIThread.InvokeAsync(async () =>
|
Dispatcher.UIThread.InvokeAsync(async () =>
|
||||||
{
|
{
|
||||||
|
waitingDialog.Close();
|
||||||
|
|
||||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogNcaExtractionMainNcaNotFoundErrorMessage]);
|
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogNcaExtractionMainNcaNotFoundErrorMessage]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -263,11 +258,15 @@ namespace Ryujinx.Ava.Common
|
||||||
|
|
||||||
Dispatcher.UIThread.InvokeAsync(async () =>
|
Dispatcher.UIThread.InvokeAsync(async () =>
|
||||||
{
|
{
|
||||||
|
waitingDialog.Close();
|
||||||
|
|
||||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogNcaExtractionCheckLogErrorMessage]);
|
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogNcaExtractionCheckLogErrorMessage]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else if (resultCode.Value.IsSuccess())
|
else if (resultCode.Value.IsSuccess())
|
||||||
{
|
{
|
||||||
|
Dispatcher.UIThread.Post(waitingDialog.Close);
|
||||||
|
|
||||||
NotificationHelper.Show(
|
NotificationHelper.Show(
|
||||||
LocaleManager.Instance[LocaleKeys.DialogNcaExtractionTitle],
|
LocaleManager.Instance[LocaleKeys.DialogNcaExtractionTitle],
|
||||||
$"{titleName}\n\n{LocaleManager.Instance[LocaleKeys.DialogNcaExtractionSuccessMessage]}",
|
$"{titleName}\n\n{LocaleManager.Instance[LocaleKeys.DialogNcaExtractionSuccessMessage]}",
|
||||||
|
@ -284,6 +283,8 @@ namespace Ryujinx.Ava.Common
|
||||||
|
|
||||||
Dispatcher.UIThread.InvokeAsync(async () =>
|
Dispatcher.UIThread.InvokeAsync(async () =>
|
||||||
{
|
{
|
||||||
|
waitingDialog.Close();
|
||||||
|
|
||||||
await ContentDialogHelper.CreateErrorDialog(ex.Message);
|
await ContentDialogHelper.CreateErrorDialog(ex.Message);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,7 @@
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
|
Focusable="True"
|
||||||
KeyUp="Message_KeyUp"
|
KeyUp="Message_KeyUp"
|
||||||
Text="{Binding Message}"
|
Text="{Binding Message}"
|
||||||
TextInput="Message_TextInput"
|
TextInput="Message_TextInput"
|
||||||
|
|
|
@ -45,6 +45,13 @@ namespace Ryujinx.Ava.UI.Controls
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void OnGotFocus(GotFocusEventArgs e)
|
||||||
|
{
|
||||||
|
// FIXME: This does not work. Might be a bug in Avalonia with DialogHost
|
||||||
|
// Currently focus will be redirected to the overlay window instead.
|
||||||
|
Input.Focus();
|
||||||
|
}
|
||||||
|
|
||||||
public string Message { get; set; } = "";
|
public string Message { get; set; } = "";
|
||||||
public string MainText { get; set; } = "";
|
public string MainText { get; set; } = "";
|
||||||
public string SecondaryText { get; set; } = "";
|
public string SecondaryText { get; set; } = "";
|
||||||
|
@ -59,24 +66,6 @@ namespace Ryujinx.Ava.UI.Controls
|
||||||
|
|
||||||
string input = string.Empty;
|
string input = string.Empty;
|
||||||
|
|
||||||
var overlay = new ContentDialogOverlayWindow()
|
|
||||||
{
|
|
||||||
Height = window.Bounds.Height,
|
|
||||||
Width = window.Bounds.Width,
|
|
||||||
Position = window.PointToScreen(new Point())
|
|
||||||
};
|
|
||||||
|
|
||||||
window.PositionChanged += OverlayOnPositionChanged;
|
|
||||||
|
|
||||||
void OverlayOnPositionChanged(object sender, PixelPointEventArgs e)
|
|
||||||
{
|
|
||||||
overlay.Position = window.PointToScreen(new Point());
|
|
||||||
}
|
|
||||||
|
|
||||||
contentDialog = overlay.ContentDialog;
|
|
||||||
|
|
||||||
bool opened = false;
|
|
||||||
|
|
||||||
content.SetInputLengthValidation(args.StringLengthMin, args.StringLengthMax);
|
content.SetInputLengthValidation(args.StringLengthMin, args.StringLengthMax);
|
||||||
|
|
||||||
content._host = contentDialog;
|
content._host = contentDialog;
|
||||||
|
@ -97,25 +86,7 @@ namespace Ryujinx.Ava.UI.Controls
|
||||||
};
|
};
|
||||||
contentDialog.Closed += handler;
|
contentDialog.Closed += handler;
|
||||||
|
|
||||||
overlay.Opened += OverlayOnActivated;
|
await ContentDialogHelper.ShowAsync(contentDialog);
|
||||||
|
|
||||||
async void OverlayOnActivated(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
if (opened)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
opened = true;
|
|
||||||
|
|
||||||
overlay.Position = window.PointToScreen(new Point());
|
|
||||||
|
|
||||||
await contentDialog.ShowAsync(overlay);
|
|
||||||
contentDialog.Closed -= handler;
|
|
||||||
overlay.Close();
|
|
||||||
};
|
|
||||||
|
|
||||||
await overlay.ShowDialog(window);
|
|
||||||
|
|
||||||
return (result, input);
|
return (result, input);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
<UserControl
|
|
||||||
x:Class="Ryujinx.Ava.UI.Controls.InputDialog"
|
|
||||||
xmlns="https://github.com/avaloniaui"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
|
||||||
mc:Ignorable="d"
|
|
||||||
Focusable="True">
|
|
||||||
<Grid
|
|
||||||
Margin="5,10,5,5"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
VerticalAlignment="Center">
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
<TextBlock HorizontalAlignment="Center" Text="{Binding Message}" />
|
|
||||||
<TextBox
|
|
||||||
Grid.Row="1"
|
|
||||||
Width="300"
|
|
||||||
Margin="10"
|
|
||||||
HorizontalAlignment="Center"
|
|
||||||
MaxLength="{Binding MaxLength}"
|
|
||||||
Text="{Binding Input, Mode=TwoWay}" />
|
|
||||||
<TextBlock
|
|
||||||
Grid.Row="2"
|
|
||||||
Margin="5,5,5,10"
|
|
||||||
HorizontalAlignment="Center"
|
|
||||||
Text="{Binding SubMessage}" />
|
|
||||||
</Grid>
|
|
||||||
</UserControl>
|
|
|
@ -1,57 +0,0 @@
|
||||||
using Avalonia.Controls;
|
|
||||||
using FluentAvalonia.UI.Controls;
|
|
||||||
using Ryujinx.Ava.Common.Locale;
|
|
||||||
using Ryujinx.Ava.UI.Helpers;
|
|
||||||
using Ryujinx.Ava.UI.Models;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.UI.Controls
|
|
||||||
{
|
|
||||||
public partial class InputDialog : UserControl
|
|
||||||
{
|
|
||||||
public string Message { get; set; }
|
|
||||||
public string Input { get; set; }
|
|
||||||
public string SubMessage { get; set; }
|
|
||||||
|
|
||||||
public uint MaxLength { get; }
|
|
||||||
|
|
||||||
public InputDialog(string message, string input = "", string subMessage = "", uint maxLength = int.MaxValue)
|
|
||||||
{
|
|
||||||
Message = message;
|
|
||||||
Input = input;
|
|
||||||
SubMessage = subMessage;
|
|
||||||
MaxLength = maxLength;
|
|
||||||
|
|
||||||
DataContext = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public InputDialog()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task<(UserResult Result, string Input)> ShowInputDialog(string title, string message,
|
|
||||||
string input = "", string subMessage = "", uint maxLength = int.MaxValue)
|
|
||||||
{
|
|
||||||
UserResult result = UserResult.Cancel;
|
|
||||||
|
|
||||||
InputDialog content = new InputDialog(message, input, subMessage, maxLength);
|
|
||||||
ContentDialog contentDialog = new ContentDialog
|
|
||||||
{
|
|
||||||
Title = title,
|
|
||||||
PrimaryButtonText = LocaleManager.Instance[LocaleKeys.InputDialogOk],
|
|
||||||
SecondaryButtonText = "",
|
|
||||||
CloseButtonText = LocaleManager.Instance[LocaleKeys.InputDialogCancel],
|
|
||||||
Content = content,
|
|
||||||
PrimaryButtonCommand = MiniCommand.Create(() =>
|
|
||||||
{
|
|
||||||
result = UserResult.Ok;
|
|
||||||
input = content.Input;
|
|
||||||
})
|
|
||||||
};
|
|
||||||
await contentDialog.ShowAsync();
|
|
||||||
|
|
||||||
return (result, input);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +1,26 @@
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Ryujinx.Ava.UI.Windows;
|
using Ryujinx.Ava.UI.Windows;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
namespace Ryujinx.Ava.UI.Controls
|
namespace Ryujinx.Ava.UI.Controls
|
||||||
{
|
{
|
||||||
public partial class UpdateWaitWindow : StyleableWindow
|
public partial class UpdateWaitWindow : StyleableWindow
|
||||||
{
|
{
|
||||||
|
public UpdateWaitWindow(string primaryText, string secondaryText, CancellationTokenSource cancellationToken) : this(primaryText, secondaryText)
|
||||||
|
{
|
||||||
|
SystemDecorations = SystemDecorations.Full;
|
||||||
|
ShowInTaskbar = true;
|
||||||
|
|
||||||
|
Closing += (_, _) => cancellationToken.Cancel();
|
||||||
|
}
|
||||||
|
|
||||||
public UpdateWaitWindow(string primaryText, string secondaryText) : this()
|
public UpdateWaitWindow(string primaryText, string secondaryText) : this()
|
||||||
{
|
{
|
||||||
PrimaryText.Text = primaryText;
|
PrimaryText.Text = primaryText;
|
||||||
SecondaryText.Text = secondaryText;
|
SecondaryText.Text = secondaryText;
|
||||||
WindowStartupLocation = WindowStartupLocation.CenterOwner;
|
WindowStartupLocation = WindowStartupLocation.CenterOwner;
|
||||||
|
SystemDecorations = SystemDecorations.BorderOnly;
|
||||||
|
ShowInTaskbar = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UpdateWaitWindow()
|
public UpdateWaitWindow()
|
||||||
|
|
|
@ -27,7 +27,6 @@ namespace Ryujinx.Ava.UI.Helpers
|
||||||
string closeButton,
|
string closeButton,
|
||||||
UserResult primaryButtonResult = UserResult.Ok,
|
UserResult primaryButtonResult = UserResult.Ok,
|
||||||
ManualResetEvent deferResetEvent = null,
|
ManualResetEvent deferResetEvent = null,
|
||||||
Func<Window, Task> doWhileDeferred = null,
|
|
||||||
TypedEventHandler<ContentDialog, ContentDialogButtonClickEventArgs> deferCloseAction = null)
|
TypedEventHandler<ContentDialog, ContentDialogButtonClickEventArgs> deferCloseAction = null)
|
||||||
{
|
{
|
||||||
UserResult result = UserResult.None;
|
UserResult result = UserResult.None;
|
||||||
|
@ -78,12 +77,11 @@ namespace Ryujinx.Ava.UI.Helpers
|
||||||
int iconSymbol,
|
int iconSymbol,
|
||||||
UserResult primaryButtonResult = UserResult.Ok,
|
UserResult primaryButtonResult = UserResult.Ok,
|
||||||
ManualResetEvent deferResetEvent = null,
|
ManualResetEvent deferResetEvent = null,
|
||||||
Func<Window, Task> doWhileDeferred = null,
|
|
||||||
TypedEventHandler<ContentDialog, ContentDialogButtonClickEventArgs> deferCloseAction = null)
|
TypedEventHandler<ContentDialog, ContentDialogButtonClickEventArgs> deferCloseAction = null)
|
||||||
{
|
{
|
||||||
Grid content = CreateTextDialogContent(primaryText, secondaryText, iconSymbol);
|
Grid content = CreateTextDialogContent(primaryText, secondaryText, iconSymbol);
|
||||||
|
|
||||||
return await ShowContentDialog(title, content, primaryButton, secondaryButton, closeButton, primaryButtonResult, deferResetEvent, doWhileDeferred, deferCloseAction);
|
return await ShowContentDialog(title, content, primaryButton, secondaryButton, closeButton, primaryButtonResult, deferResetEvent, deferCloseAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async static Task<UserResult> ShowDeferredContentDialog(
|
public async static Task<UserResult> ShowDeferredContentDialog(
|
||||||
|
@ -111,7 +109,6 @@ namespace Ryujinx.Ava.UI.Helpers
|
||||||
iconSymbol,
|
iconSymbol,
|
||||||
primaryButton == LocaleManager.Instance[LocaleKeys.InputDialogYes] ? UserResult.Yes : UserResult.Ok,
|
primaryButton == LocaleManager.Instance[LocaleKeys.InputDialogYes] ? UserResult.Yes : UserResult.Ok,
|
||||||
deferResetEvent,
|
deferResetEvent,
|
||||||
doWhileDeferred,
|
|
||||||
DeferClose);
|
DeferClose);
|
||||||
|
|
||||||
async void DeferClose(ContentDialog sender, ContentDialogButtonClickEventArgs args)
|
async void DeferClose(ContentDialog sender, ContentDialogButtonClickEventArgs args)
|
||||||
|
@ -236,11 +233,6 @@ namespace Ryujinx.Ava.UI.Helpers
|
||||||
primaryButtonResult);
|
primaryButtonResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static UpdateWaitWindow CreateWaitingDialog(string mainText, string secondaryText)
|
|
||||||
{
|
|
||||||
return new(mainText, secondaryText);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static async Task CreateUpdaterInfoDialog(string primary, string secondaryText)
|
internal static async Task CreateUpdaterInfoDialog(string primary, string secondaryText)
|
||||||
{
|
{
|
||||||
await ShowTextDialog(
|
await ShowTextDialog(
|
||||||
|
@ -319,28 +311,6 @@ namespace Ryujinx.Ava.UI.Helpers
|
||||||
LocaleManager.Instance[LocaleKeys.DialogExitSubMessage]);
|
LocaleManager.Instance[LocaleKeys.DialogExitSubMessage]);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static async Task<string> CreateInputDialog(
|
|
||||||
string title,
|
|
||||||
string mainText,
|
|
||||||
string subText,
|
|
||||||
uint maxLength = int.MaxValue,
|
|
||||||
string input = "")
|
|
||||||
{
|
|
||||||
var result = await InputDialog.ShowInputDialog(
|
|
||||||
title,
|
|
||||||
mainText,
|
|
||||||
input,
|
|
||||||
subText,
|
|
||||||
maxLength);
|
|
||||||
|
|
||||||
if (result.Result == UserResult.Ok)
|
|
||||||
{
|
|
||||||
return result.Input;
|
|
||||||
}
|
|
||||||
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task<ContentDialogResult> ShowAsync(ContentDialog contentDialog)
|
public static async Task<ContentDialogResult> ShowAsync(ContentDialog contentDialog)
|
||||||
{
|
{
|
||||||
ContentDialogResult result;
|
ContentDialogResult result;
|
||||||
|
|
|
@ -972,7 +972,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
LocaleManager.Instance[LocaleKeys.InputDialogNo],
|
LocaleManager.Instance[LocaleKeys.InputDialogNo],
|
||||||
LocaleManager.Instance[LocaleKeys.RyujinxConfirm]);
|
LocaleManager.Instance[LocaleKeys.RyujinxConfirm]);
|
||||||
|
|
||||||
UpdateWaitWindow waitingDialog = ContentDialogHelper.CreateWaitingDialog(dialogTitle, LocaleManager.Instance[LocaleKeys.DialogFirmwareInstallerFirmwareInstallWaitMessage]);
|
UpdateWaitWindow waitingDialog = new(dialogTitle, LocaleManager.Instance[LocaleKeys.DialogFirmwareInstallerFirmwareInstallWaitMessage]);
|
||||||
|
|
||||||
if (result == UserResult.Yes)
|
if (result == UserResult.Yes)
|
||||||
{
|
{
|
||||||
|
|
|
@ -10,20 +10,16 @@
|
||||||
d:DesignHeight="450"
|
d:DesignHeight="450"
|
||||||
x:Class="Ryujinx.Ava.UI.Windows.ContentDialogOverlayWindow"
|
x:Class="Ryujinx.Ava.UI.Windows.ContentDialogOverlayWindow"
|
||||||
Title="ContentDialogOverlayWindow"
|
Title="ContentDialogOverlayWindow"
|
||||||
Focusable="True">
|
Focusable="False">
|
||||||
<window:StyleableWindow.Styles>
|
<window:StyleableWindow.Styles>
|
||||||
<Style Selector="ui|ContentDialog /template/ Panel#LayoutRoot">
|
<Style Selector="ui|ContentDialog /template/ Panel#LayoutRoot">
|
||||||
<Setter Property="Background"
|
<Setter Property="Background"
|
||||||
Value="Transparent" />
|
Value="Transparent" />
|
||||||
</Style>
|
</Style>
|
||||||
</window:StyleableWindow.Styles>
|
</window:StyleableWindow.Styles>
|
||||||
<ContentControl
|
|
||||||
Focusable="False"
|
|
||||||
IsVisible="False"
|
|
||||||
KeyboardNavigation.IsTabStop="False">
|
|
||||||
<ui:ContentDialog Name="ContentDialog"
|
<ui:ContentDialog Name="ContentDialog"
|
||||||
IsPrimaryButtonEnabled="True"
|
IsPrimaryButtonEnabled="True"
|
||||||
IsSecondaryButtonEnabled="True"
|
IsSecondaryButtonEnabled="True"
|
||||||
IsVisible="False" />
|
IsVisible="False"
|
||||||
</ContentControl>
|
Focusable="True"/>
|
||||||
</window:StyleableWindow>
|
</window:StyleableWindow>
|
||||||
|
|
Reference in a new issue