mirror of
https://github.com/GreemDev/Ryujinx.git
synced 2025-01-09 03:07:45 -03:00
UI: stop using async voids in MainMenuBarView; use RelayCommands
This commit is contained in:
parent
323c356d9c
commit
b5fafb6394
4 changed files with 88 additions and 102 deletions
|
@ -56,7 +56,7 @@
|
|||
ToolTip.Tip="{ext:Locale LoadTitleUpdatesFromFolderTooltip}" />
|
||||
<MenuItem Header="{ext:Locale MenuBarFileOpenApplet}" IsEnabled="{Binding IsAppletMenuActive}" Icon="{ext:Icon mdi-launch}">
|
||||
<MenuItem
|
||||
Click="OpenMiiApplet"
|
||||
Name="MiiAppletMenuItem"
|
||||
Header="{ext:Locale MenuBarFileOpenAppletOpenMiiApplet}"
|
||||
Icon="{ext:Icon fa-solid fa-person}"
|
||||
ToolTip.Tip="{ext:Locale MenuBarFileOpenAppletOpenMiiAppletToolTip}" />
|
||||
|
@ -72,7 +72,7 @@
|
|||
ToolTip.Tip="{ext:Locale OpenRyujinxLogsTooltip}" />
|
||||
<Separator />
|
||||
<MenuItem
|
||||
Click="CloseWindow"
|
||||
Name="CloseRyujinxMenuItem"
|
||||
Header="{ext:Locale MenuBarFileExit}"
|
||||
Icon="{ext:Icon fa-solid fa-xmark}"
|
||||
ToolTip.Tip="{ext:Locale ExitTooltip}" />
|
||||
|
@ -167,7 +167,7 @@
|
|||
Header="{ext:Locale MenuBarShowFileTypes}" />
|
||||
<Separator />
|
||||
<MenuItem
|
||||
Click="OpenSettings"
|
||||
Name="OpenSettingsMenuItem"
|
||||
Padding="0"
|
||||
Header="{ext:Locale MenuBarOptionsSettings}"
|
||||
Icon="{ext:Icon fa-solid fa-gear}"
|
||||
|
@ -210,21 +210,21 @@
|
|||
Header="{ext:Locale MenuBarActions}"
|
||||
IsEnabled="{Binding IsGameRunning}">
|
||||
<MenuItem
|
||||
Click="PauseEmulation_Click"
|
||||
Name="PauseEmulationMenuItem"
|
||||
Header="{ext:Locale MenuBarOptionsPauseEmulation}"
|
||||
Icon="{ext:Icon fa-solid fa-pause}"
|
||||
InputGesture="{Binding PauseKey}"
|
||||
IsEnabled="{Binding !IsPaused}"
|
||||
IsVisible="{Binding !IsPaused}" />
|
||||
<MenuItem
|
||||
Click="ResumeEmulation_Click"
|
||||
Name="ResumeEmulationMenuItem"
|
||||
Header="{ext:Locale MenuBarOptionsResumeEmulation}"
|
||||
Icon="{ext:Icon fa-solid fa-play}"
|
||||
InputGesture="{Binding PauseKey}"
|
||||
IsEnabled="{Binding IsPaused}"
|
||||
IsVisible="{Binding IsPaused}" />
|
||||
<MenuItem
|
||||
Click="StopEmulation_Click"
|
||||
Name="StopEmulationMenuItem"
|
||||
Header="{ext:Locale MenuBarOptionsStopEmulation}"
|
||||
Icon="{ext:Icon fa-solid fa-stop}"
|
||||
InputGesture="Escape"
|
||||
|
@ -233,17 +233,15 @@
|
|||
<MenuItem Command="{Binding SimulateWakeUpMessage}" Header="{ext:Locale MenuBarOptionsSimulateWakeUpMessage}" />
|
||||
<Separator />
|
||||
<MenuItem
|
||||
Name="ScanAmiiboMenuItem"
|
||||
Command="{Binding OpenAmiiboWindow}"
|
||||
AttachedToVisualTree="ScanAmiiboMenuItem_AttachedToVisualTree"
|
||||
Click="OpenAmiiboWindow"
|
||||
Header="{ext:Locale MenuBarActionsScanAmiibo}"
|
||||
Icon="{ext:Icon mdi-cube-scan}"
|
||||
InputGesture="Ctrl + A"
|
||||
IsEnabled="{Binding IsAmiiboRequested}" />
|
||||
<MenuItem
|
||||
Name="ScanAmiiboMenuItemFromBin"
|
||||
Command="{Binding OpenBinFile}"
|
||||
AttachedToVisualTree="ScanBinAmiiboMenuItem_AttachedToVisualTree"
|
||||
Click="OpenBinFile"
|
||||
Header="{ext:Locale MenuBarActionsScanAmiiboBin}"
|
||||
Icon="{ext:Icon mdi-cube-scan}"
|
||||
IsVisible="{Binding CanScanAmiiboBinaries}"
|
||||
|
@ -262,7 +260,7 @@
|
|||
InputGesture="{Binding ShowUiKey}"
|
||||
IsEnabled="{Binding IsGameRunning}" />
|
||||
<MenuItem
|
||||
Click="OpenCheatManagerForCurrentApp"
|
||||
Name="CheatManagerMenuItem"
|
||||
Header="{ext:Locale GameListContextMenuManageCheat}"
|
||||
Icon="{ext:Icon fa-solid fa-code}"
|
||||
IsEnabled="{Binding IsGameRunning}" />
|
||||
|
@ -277,56 +275,55 @@
|
|||
<MenuItem Command="{Binding InstallFirmwareFromFolder}" Header="{ext:Locale MenuBarFileToolsInstallFirmwareFromDirectory}" Icon="{ext:Icon mdi-folder-cog}" />
|
||||
</MenuItem>
|
||||
<MenuItem Header="{ext:Locale MenuBarToolsManageFileTypes}" IsVisible="{Binding ManageFileTypesVisible}">
|
||||
<MenuItem Header="{ext:Locale MenuBarToolsInstallFileTypes}" Click="InstallFileTypes_Click" IsEnabled="{Binding AreMimeTypesRegistered, Converter={x:Static BoolConverters.Not}}" />
|
||||
<MenuItem Header="{ext:Locale MenuBarToolsUninstallFileTypes}" Click="UninstallFileTypes_Click" IsEnabled="{Binding AreMimeTypesRegistered}" />
|
||||
<MenuItem Name="InstallFileTypesMenuItem" Header="{ext:Locale MenuBarToolsInstallFileTypes}" IsEnabled="{Binding AreMimeTypesRegistered, Converter={x:Static BoolConverters.Not}}" />
|
||||
<MenuItem Name="UninstallFileTypesMenuItem" Header="{ext:Locale MenuBarToolsUninstallFileTypes}" IsEnabled="{Binding AreMimeTypesRegistered}" />
|
||||
</MenuItem>
|
||||
<Separator />
|
||||
<MenuItem Header="{ext:Locale MenuBarToolsXCITrimmer}" IsEnabled="{Binding EnableNonGameRunningControls}" Click="OpenXCITrimmerWindow" Icon="{ext:Icon fa-solid fa-scissors}" />
|
||||
<MenuItem Name="XciTrimmerMenuItem" Header="{ext:Locale MenuBarToolsXCITrimmer}" IsEnabled="{Binding EnableNonGameRunningControls}" Icon="{ext:Icon fa-solid fa-scissors}" />
|
||||
</MenuItem>
|
||||
<MenuItem VerticalAlignment="Center" Header="{ext:Locale MenuBarView}">
|
||||
<MenuItem VerticalAlignment="Center" Header="{ext:Locale MenuBarViewWindow}">
|
||||
<MenuItem Header="{ext:Locale MenuBarViewWindow720}" Tag="1280 720" Click="ChangeWindowSize_Click" />
|
||||
<MenuItem Header="{ext:Locale MenuBarViewWindow1080}" Tag="1920 1080" Click="ChangeWindowSize_Click" />
|
||||
<MenuItem Header="{ext:Locale MenuBarViewWindow1440}" Tag="2560 1440" Click="ChangeWindowSize_Click" />
|
||||
<MenuItem Header="{ext:Locale MenuBarViewWindow2160}" Tag="3840 2160" Click="ChangeWindowSize_Click" />
|
||||
<MenuItem Name="WindowSize720PMenuItem" Header="{ext:Locale MenuBarViewWindow720}" CommandParameter="1280 720" />
|
||||
<MenuItem Name="WindowSize1080PMenuItem" Header="{ext:Locale MenuBarViewWindow1080}" CommandParameter="1920 1080" />
|
||||
<MenuItem Name="WindowSize1440PMenuItem" Header="{ext:Locale MenuBarViewWindow1440}" CommandParameter="2560 1440" />
|
||||
<MenuItem Name="WindowSize2160PMenuItem" Header="{ext:Locale MenuBarViewWindow2160}" CommandParameter="3840 2160" />
|
||||
</MenuItem>
|
||||
</MenuItem>
|
||||
<MenuItem VerticalAlignment="Center" Header="{ext:Locale MenuBarHelp}">
|
||||
<MenuItem
|
||||
Click="OpenAboutWindow"
|
||||
Name="AboutWindowMenuItem"
|
||||
Header="{ext:Locale MenuBarHelpAbout}"
|
||||
Icon="{ext:Icon fa-solid fa-circle-info}"
|
||||
ToolTip.Tip="{ext:Locale OpenAboutTooltip}" />
|
||||
<MenuItem
|
||||
Name="UpdateMenuItem"
|
||||
IsEnabled="{Binding CanUpdate}"
|
||||
Click="CheckForUpdates"
|
||||
Header="{ext:Locale MenuBarHelpCheckForUpdates}"
|
||||
Icon="{ext:Icon mdi-update}"
|
||||
ToolTip.Tip="{ext:Locale CheckUpdatesTooltip}" />
|
||||
<MenuItem
|
||||
Click="OpenCompatibilityList"
|
||||
Name="CompatibilityListMenuItem"
|
||||
Header="{ext:Locale CompatibilityListOpen}"
|
||||
Icon="{ext:Icon mdi-gamepad}"/>
|
||||
<Separator />
|
||||
<MenuItem VerticalAlignment="Center" Header="{ext:Locale MenuBarHelpFaqAndGuides}" Icon="{ext:Icon fa-solid fa-question}" >
|
||||
<MenuItem
|
||||
Click="MenuItem_OnClick"
|
||||
Name="FaqMenuItem"
|
||||
Header="{ext:Locale MenuBarHelpFaq}"
|
||||
Icon="{ext:Icon fa-github}"
|
||||
Tag="https://github.com/GreemDev/Ryujinx/wiki/FAQ-and-Troubleshooting"
|
||||
CommandParameter="https://github.com/GreemDev/Ryujinx/wiki/FAQ-and-Troubleshooting"
|
||||
ToolTip.Tip="{ext:Locale MenuBarHelpFaqTooltip}" />
|
||||
<MenuItem
|
||||
Click="MenuItem_OnClick"
|
||||
Name="SetupGuideMenuItem"
|
||||
Header="{ext:Locale MenuBarHelpSetup}"
|
||||
Icon="{ext:Icon fa-github}"
|
||||
Tag="https://github.com/GreemDev/Ryujinx/wiki/Ryujinx-Setup-&-Configuration-Guide"
|
||||
CommandParameter="https://github.com/GreemDev/Ryujinx/wiki/Ryujinx-Setup-&-Configuration-Guide"
|
||||
ToolTip.Tip="{ext:Locale MenuBarHelpSetupTooltip}" />
|
||||
<MenuItem
|
||||
Click="MenuItem_OnClick"
|
||||
Name="LdnGuideMenuItem"
|
||||
Header="{ext:Locale MenuBarHelpMultiplayer}"
|
||||
Icon="{ext:Icon fa-github}"
|
||||
Tag="https://github.com/GreemDev/Ryujinx/wiki/Multiplayer%E2%80%90(LDN%E2%80%90Local%E2%80%90Wireless)%E2%80%90Guide"
|
||||
CommandParameter="https://github.com/GreemDev/Ryujinx/wiki/Multiplayer%E2%80%90(LDN%E2%80%90Local%E2%80%90Wireless)%E2%80%90Guide"
|
||||
ToolTip.Tip="{ext:Locale MenuBarHelpMultiplayerTooltip}" />
|
||||
</MenuItem>
|
||||
</MenuItem>
|
||||
|
|
|
@ -2,6 +2,7 @@ using Avalonia;
|
|||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Threading;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Gommon;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.UI.Helpers;
|
||||
|
@ -17,6 +18,7 @@ using Ryujinx.HLE.HOS.Services.Nfc.AmiiboDecryption;
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Views.Main
|
||||
{
|
||||
|
@ -34,6 +36,34 @@ namespace Ryujinx.Ava.UI.Views.Main
|
|||
|
||||
ToggleFileTypesMenuItem.ItemsSource = GenerateToggleFileTypeItems();
|
||||
ChangeLanguageMenuItem.ItemsSource = GenerateLanguageMenuItems();
|
||||
|
||||
MiiAppletMenuItem.Command = new AsyncRelayCommand(OpenMiiApplet);
|
||||
CloseRyujinxMenuItem.Command = new RelayCommand(CloseWindow);
|
||||
OpenSettingsMenuItem.Command = new AsyncRelayCommand(OpenSettings);
|
||||
PauseEmulationMenuItem.Command = new RelayCommand(() => ViewModel.AppHost?.Pause());
|
||||
ResumeEmulationMenuItem.Command = new RelayCommand(() => ViewModel.AppHost?.Resume());
|
||||
StopEmulationMenuItem.Command = new AsyncRelayCommand(() => ViewModel.AppHost?.ShowExitPrompt().OrCompleted()!);
|
||||
CheatManagerMenuItem.Command = new AsyncRelayCommand(OpenCheatManagerForCurrentApp);
|
||||
InstallFileTypesMenuItem.Command = new AsyncRelayCommand(InstallFileTypes);
|
||||
UninstallFileTypesMenuItem.Command = new AsyncRelayCommand(UninstallFileTypes);
|
||||
XciTrimmerMenuItem.Command = new AsyncRelayCommand(() => XCITrimmerWindow.Show(ViewModel));
|
||||
AboutWindowMenuItem.Command = new AsyncRelayCommand(AboutWindow.Show);
|
||||
CompatibilityListMenuItem.Command = new AsyncRelayCommand(CompatibilityList.Show);
|
||||
|
||||
UpdateMenuItem.Command = new AsyncRelayCommand(async () =>
|
||||
{
|
||||
if (Updater.CanUpdate(true))
|
||||
await Updater.BeginUpdateAsync(true);
|
||||
});
|
||||
|
||||
FaqMenuItem.Command =
|
||||
SetupGuideMenuItem.Command =
|
||||
LdnGuideMenuItem.Command = new RelayCommand<string>(OpenHelper.OpenUrl);
|
||||
|
||||
WindowSize720PMenuItem.Command =
|
||||
WindowSize1080PMenuItem.Command =
|
||||
WindowSize1440PMenuItem.Command =
|
||||
WindowSize2160PMenuItem.Command = new RelayCommand<string>(ChangeWindowSize);
|
||||
}
|
||||
|
||||
private CheckBox[] GenerateToggleFileTypeItems() =>
|
||||
|
@ -96,22 +126,7 @@ namespace Ryujinx.Ava.UI.Views.Main
|
|||
}
|
||||
}
|
||||
|
||||
private async void StopEmulation_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
await ViewModel.AppHost?.ShowExitPrompt().OrCompleted()!;
|
||||
}
|
||||
|
||||
private void PauseEmulation_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ViewModel.AppHost?.Pause();
|
||||
}
|
||||
|
||||
private void ResumeEmulation_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ViewModel.AppHost?.Resume();
|
||||
}
|
||||
|
||||
public async void OpenSettings(object sender, RoutedEventArgs e)
|
||||
public async Task OpenSettings()
|
||||
{
|
||||
Window.SettingsWindow = new(Window.VirtualFileSystem, Window.ContentManager);
|
||||
|
||||
|
@ -124,7 +139,7 @@ namespace Ryujinx.Ava.UI.Views.Main
|
|||
|
||||
public static readonly AppletMetadata MiiApplet = new("miiEdit", 0x0100000000001009);
|
||||
|
||||
public async void OpenMiiApplet(object sender, RoutedEventArgs e)
|
||||
public async Task OpenMiiApplet()
|
||||
{
|
||||
if (MiiApplet.CanStart(ViewModel.ContentManager, out var appData, out var nacpData))
|
||||
{
|
||||
|
@ -132,13 +147,7 @@ namespace Ryujinx.Ava.UI.Views.Main
|
|||
}
|
||||
}
|
||||
|
||||
public async void OpenAmiiboWindow(object sender, RoutedEventArgs e)
|
||||
=> await ViewModel.OpenAmiiboWindow();
|
||||
|
||||
public async void OpenBinFile(object sender, RoutedEventArgs e)
|
||||
=> await ViewModel.OpenBinFile();
|
||||
|
||||
public async void OpenCheatManagerForCurrentApp(object sender, RoutedEventArgs e)
|
||||
public async Task OpenCheatManagerForCurrentApp()
|
||||
{
|
||||
if (!ViewModel.IsGameRunning)
|
||||
return;
|
||||
|
@ -166,7 +175,7 @@ namespace Ryujinx.Ava.UI.Views.Main
|
|||
ViewModel.IsAmiiboBinRequested = ViewModel.IsAmiiboRequested && AmiiboBinReader.HasAmiiboKeyFile;
|
||||
}
|
||||
|
||||
private async void InstallFileTypes_Click(object sender, RoutedEventArgs e)
|
||||
private async Task InstallFileTypes()
|
||||
{
|
||||
ViewModel.AreMimeTypesRegistered = FileAssociationHelper.Install();
|
||||
if (ViewModel.AreMimeTypesRegistered)
|
||||
|
@ -175,7 +184,7 @@ namespace Ryujinx.Ava.UI.Views.Main
|
|||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogInstallFileTypesErrorMessage]);
|
||||
}
|
||||
|
||||
private async void UninstallFileTypes_Click(object sender, RoutedEventArgs e)
|
||||
private async Task UninstallFileTypes()
|
||||
{
|
||||
ViewModel.AreMimeTypesRegistered = !FileAssociationHelper.Uninstall();
|
||||
if (!ViewModel.AreMimeTypesRegistered)
|
||||
|
@ -184,11 +193,8 @@ namespace Ryujinx.Ava.UI.Views.Main
|
|||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogUninstallFileTypesErrorMessage]);
|
||||
}
|
||||
|
||||
private async void ChangeWindowSize_Click(object sender, RoutedEventArgs e)
|
||||
private void ChangeWindowSize(string resolution)
|
||||
{
|
||||
if (sender is not MenuItem { Tag: string resolution })
|
||||
return;
|
||||
|
||||
(int resolutionWidth, int resolutionHeight) = resolution.Split(' ', 2)
|
||||
.Into(parts =>
|
||||
(int.Parse(parts[0]), int.Parse(parts[1]))
|
||||
|
@ -201,7 +207,7 @@ namespace Ryujinx.Ava.UI.Views.Main
|
|||
double windowWidthScaled = (resolutionWidth * Program.WindowScaleFactor);
|
||||
double windowHeightScaled = ((resolutionHeight + barsHeight) * Program.WindowScaleFactor);
|
||||
|
||||
await Dispatcher.UIThread.InvokeAsync(() =>
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
ViewModel.WindowState = WindowState.Normal;
|
||||
|
||||
|
@ -209,24 +215,7 @@ namespace Ryujinx.Ava.UI.Views.Main
|
|||
});
|
||||
}
|
||||
|
||||
public async void CheckForUpdates(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (Updater.CanUpdate(true))
|
||||
await Updater.BeginUpdateAsync(true);
|
||||
}
|
||||
|
||||
private void MenuItem_OnClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is MenuItem { Tag: string url })
|
||||
OpenHelper.OpenUrl(url);
|
||||
}
|
||||
|
||||
public async void OpenXCITrimmerWindow(object sender, RoutedEventArgs e) => await XCITrimmerWindow.Show(ViewModel);
|
||||
|
||||
public async void OpenAboutWindow(object sender, RoutedEventArgs e) => await AboutWindow.Show();
|
||||
|
||||
public void CloseWindow(object sender, RoutedEventArgs e) => Window.Close();
|
||||
|
||||
private async void OpenCompatibilityList(object sender, RoutedEventArgs e) => await CompatibilityContentDialog.Show();
|
||||
public void CloseWindow() => Window.Close();
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,35 +1,11 @@
|
|||
using Avalonia.Styling;
|
||||
using FluentAvalonia.UI.Controls;
|
||||
using Ryujinx.Ava.UI.Helpers;
|
||||
using FluentAvalonia.UI.Controls;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ryujinx.Ava.Utilities.Compat
|
||||
{
|
||||
public partial class CompatibilityContentDialog : ContentDialog
|
||||
{
|
||||
protected override Type StyleKeyOverride => typeof(ContentDialog);
|
||||
|
||||
public static async Task Show()
|
||||
{
|
||||
await CompatibilityHelper.InitAsync();
|
||||
|
||||
CompatibilityContentDialog contentDialog = new()
|
||||
{
|
||||
Content = new CompatibilityList { DataContext = new CompatibilityViewModel(RyujinxApp.MainWindow.ViewModel.ApplicationLibrary) }
|
||||
};
|
||||
|
||||
Style closeButton = new(x => x.Name("CloseButton"));
|
||||
closeButton.Setters.Add(new Setter(WidthProperty, 80d));
|
||||
|
||||
Style closeButtonParent = new(x => x.Name("CommandSpace"));
|
||||
closeButtonParent.Setters.Add(new Setter(HorizontalAlignmentProperty, Avalonia.Layout.HorizontalAlignment.Right));
|
||||
|
||||
contentDialog.Styles.Add(closeButton);
|
||||
contentDialog.Styles.Add(closeButtonParent);
|
||||
|
||||
await ContentDialogHelper.ShowAsync(contentDialog);
|
||||
}
|
||||
|
||||
public CompatibilityContentDialog() => InitializeComponent();
|
||||
}
|
||||
|
|
|
@ -1,9 +1,33 @@
|
|||
using Avalonia.Controls;
|
||||
using Avalonia.Styling;
|
||||
using Ryujinx.Ava.UI.Helpers;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ryujinx.Ava.Utilities.Compat
|
||||
{
|
||||
public partial class CompatibilityList : UserControl
|
||||
{
|
||||
public static async Task Show()
|
||||
{
|
||||
await CompatibilityHelper.InitAsync();
|
||||
|
||||
CompatibilityContentDialog contentDialog = new()
|
||||
{
|
||||
Content = new CompatibilityList { DataContext = new CompatibilityViewModel(RyujinxApp.MainWindow.ViewModel.ApplicationLibrary) }
|
||||
};
|
||||
|
||||
Style closeButton = new(x => x.Name("CloseButton"));
|
||||
closeButton.Setters.Add(new Setter(WidthProperty, 80d));
|
||||
|
||||
Style closeButtonParent = new(x => x.Name("CommandSpace"));
|
||||
closeButtonParent.Setters.Add(new Setter(HorizontalAlignmentProperty, Avalonia.Layout.HorizontalAlignment.Right));
|
||||
|
||||
contentDialog.Styles.Add(closeButton);
|
||||
contentDialog.Styles.Add(closeButtonParent);
|
||||
|
||||
await ContentDialogHelper.ShowAsync(contentDialog);
|
||||
}
|
||||
|
||||
public CompatibilityList()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
|
Loading…
Reference in a new issue