Compare commits
7 Commits
Canary-1.2
...
Canary-1.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c03cd50fa3 | ||
|
|
069f630776 | ||
|
|
13d411e4de | ||
|
|
9f53b07491 | ||
|
|
cd8113dadf | ||
|
|
9089c4ffe5 | ||
|
|
fe9d8d05bd |
@@ -1070,6 +1070,7 @@
|
||||
010017B0102A8000,"Emma: Lost in Memories",nvdec,playable,2021-01-28 16:19:10
|
||||
010068300E08E000,"Enchanted in the Moonlight - Kiryu, Chikage & Yukinojo -",gpu;nvdec,ingame,2022-11-20 16:18:45
|
||||
01007A4008486000,"Enchanting Mahjong Match",gpu,ingame,2020-04-17 22:01:31
|
||||
0100EF901E552000,"ENDER MAGNOLIA: Bloom in the Mist",deadlock,boots,2025-01-22 17:59:00
|
||||
01004F3011F92000,"Endless Fables: Dark Moor",gpu;nvdec,ingame,2021-03-07 15:31:03
|
||||
010067B017588000,"Endless Ocean™ Luminous",services-horizon;crash,ingame,2024-05-30 02:05:57
|
||||
0100B8700BD14000,"Energy Cycle Edge",services,ingame,2021-11-30 05:02:31
|
||||
|
||||
|
@@ -78,5 +78,10 @@ namespace Ryujinx.Common.Configuration.Hid.Controller
|
||||
/// Controller Rumble Settings
|
||||
/// </summary>
|
||||
public RumbleConfigController Rumble { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Controller LED Settings
|
||||
/// </summary>
|
||||
public LedConfigController Led { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
namespace Ryujinx.Common.Configuration.Hid.Controller
|
||||
{
|
||||
public class LedConfigController
|
||||
{
|
||||
/// <summary>
|
||||
/// Packed RGB int of the color
|
||||
/// </summary>
|
||||
public uint LedColor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Enable LED color changing by the emulator
|
||||
/// </summary>
|
||||
public bool EnableLed { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -118,7 +118,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
private static string GetDiskCachePath()
|
||||
{
|
||||
return GraphicsConfig.EnableShaderCache && GraphicsConfig.TitleId != null
|
||||
? Path.Combine(AppDataManager.GamesDirPath, GraphicsConfig.TitleId, "cache", "shader")
|
||||
? Path.Combine(AppDataManager.GamesDirPath, GraphicsConfig.TitleId.ToLower(), "cache", "shader")
|
||||
: null;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Ryujinx.Common.Configuration.Hid;
|
||||
using Ryujinx.Common.Configuration.Hid.Controller;
|
||||
using Ryujinx.Common.Logging;
|
||||
using SDL2;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
@@ -118,6 +119,11 @@ namespace Ryujinx.Input.SDL2
|
||||
result |= GamepadFeaturesFlag.Rumble;
|
||||
}
|
||||
|
||||
if (SDL_GameControllerHasLED(_gamepadHandle) == SDL_bool.SDL_TRUE)
|
||||
{
|
||||
result |= GamepadFeaturesFlag.Led;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,5 +24,10 @@ namespace Ryujinx.Input
|
||||
/// <remarks>Also named sixaxis</remarks>
|
||||
/// </summary>
|
||||
Motion,
|
||||
|
||||
/// <summary>
|
||||
/// The LED on the back of modern PlayStation controllers (DualSense & DualShock 4).
|
||||
/// </summary>
|
||||
Led,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using Avalonia.Controls.Notifications;
|
||||
using Avalonia.Platform.Storage;
|
||||
using Avalonia.Threading;
|
||||
using Gommon;
|
||||
using LibHac;
|
||||
using LibHac.Account;
|
||||
using LibHac.Common;
|
||||
@@ -15,6 +15,7 @@ using LibHac.Tools.FsSystem.NcaUtils;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.UI.Controls;
|
||||
using Ryujinx.Ava.UI.Helpers;
|
||||
using Ryujinx.Ava.Utilities;
|
||||
using Ryujinx.Ava.Utilities.Configuration;
|
||||
using Ryujinx.Common.Helper;
|
||||
using Ryujinx.Common.Logging;
|
||||
@@ -418,35 +419,27 @@ namespace Ryujinx.Ava.Common
|
||||
|
||||
public static async Task ExtractAoc(IStorageProvider storageProvider, string updateFilePath, string updateName)
|
||||
{
|
||||
var result = await storageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
|
||||
Optional<IStorageFolder> result = await storageProvider.OpenSingleFolderPickerAsync(new FolderPickerOpenOptions
|
||||
{
|
||||
Title = LocaleManager.Instance[LocaleKeys.FolderDialogExtractTitle],
|
||||
AllowMultiple = false,
|
||||
Title = LocaleManager.Instance[LocaleKeys.FolderDialogExtractTitle]
|
||||
});
|
||||
|
||||
if (result.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ExtractAoc(result[0].Path.LocalPath, updateFilePath, updateName);
|
||||
if (!result.HasValue) return;
|
||||
|
||||
ExtractAoc(result.Value.Path.LocalPath, updateFilePath, updateName);
|
||||
}
|
||||
|
||||
|
||||
public static async Task ExtractSection(IStorageProvider storageProvider, NcaSectionType ncaSectionType, string titleFilePath, string titleName, int programIndex = 0)
|
||||
{
|
||||
var result = await storageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
|
||||
Optional<IStorageFolder> result = await storageProvider.OpenSingleFolderPickerAsync(new FolderPickerOpenOptions
|
||||
{
|
||||
Title = LocaleManager.Instance[LocaleKeys.FolderDialogExtractTitle],
|
||||
AllowMultiple = false,
|
||||
Title = LocaleManager.Instance[LocaleKeys.FolderDialogExtractTitle]
|
||||
});
|
||||
|
||||
if (result.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!result.HasValue) return;
|
||||
|
||||
ExtractSection(result[0].Path.LocalPath, ncaSectionType, titleFilePath, titleName, programIndex);
|
||||
ExtractSection(result.Value.Path.LocalPath, ncaSectionType, titleFilePath, titleName, programIndex);
|
||||
}
|
||||
|
||||
public static (Result? result, bool canceled) CopyDirectory(FileSystemClient fs, string sourcePath, string destPath, CancellationToken token)
|
||||
|
||||
@@ -251,7 +251,7 @@ namespace Ryujinx.Ava.UI.Controls
|
||||
{
|
||||
if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
|
||||
{
|
||||
string shaderCacheDir = Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.IdString, "cache", "shader");
|
||||
string shaderCacheDir = Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.IdString.ToLower(), "cache", "shader");
|
||||
|
||||
if (!Directory.Exists(shaderCacheDir))
|
||||
{
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Avalonia.Media;
|
||||
using Ryujinx.Ava.UI.ViewModels;
|
||||
using Ryujinx.Common.Configuration.Hid;
|
||||
using Ryujinx.Common.Configuration.Hid.Controller;
|
||||
@@ -387,6 +388,30 @@ namespace Ryujinx.Ava.UI.Models.Input
|
||||
}
|
||||
}
|
||||
|
||||
private bool _enableLedChanging;
|
||||
|
||||
public bool EnableLedChanging
|
||||
{
|
||||
get => _enableLedChanging;
|
||||
set
|
||||
{
|
||||
_enableLedChanging = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private Color _ledColor;
|
||||
|
||||
public Color LedColor
|
||||
{
|
||||
get => _ledColor;
|
||||
set
|
||||
{
|
||||
_ledColor = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private bool _enableMotion;
|
||||
public bool EnableMotion
|
||||
{
|
||||
@@ -483,12 +508,23 @@ namespace Ryujinx.Ava.UI.Models.Input
|
||||
WeakRumble = controllerInput.Rumble.WeakRumble;
|
||||
StrongRumble = controllerInput.Rumble.StrongRumble;
|
||||
}
|
||||
|
||||
if (controllerInput.Led != null)
|
||||
{
|
||||
EnableLedChanging = controllerInput.Led.EnableLed;
|
||||
uint rawColor = controllerInput.Led.LedColor;
|
||||
byte alpha = (byte)(rawColor >> 24);
|
||||
byte red = (byte)(rawColor >> 16);
|
||||
byte green = (byte)(rawColor >> 8);
|
||||
byte blue = (byte)(rawColor % 256);
|
||||
LedColor = new Color(alpha, red, green, blue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public InputConfig GetConfig()
|
||||
{
|
||||
var config = new StandardControllerInputConfig
|
||||
StandardControllerInputConfig config = new()
|
||||
{
|
||||
Id = Id,
|
||||
Backend = InputBackendType.GamepadSDL2,
|
||||
@@ -540,6 +576,11 @@ namespace Ryujinx.Ava.UI.Models.Input
|
||||
WeakRumble = WeakRumble,
|
||||
StrongRumble = StrongRumble,
|
||||
},
|
||||
Led = new LedConfigController
|
||||
{
|
||||
EnableLed = EnableLedChanging,
|
||||
LedColor = LedColor.ToUInt32()
|
||||
},
|
||||
Version = InputConfig.CurrentVersion,
|
||||
DeadzoneLeft = DeadzoneLeft,
|
||||
DeadzoneRight = DeadzoneRight,
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
||||
|
||||
[ObservableProperty] private SvgImage _image;
|
||||
|
||||
public readonly InputViewModel ParentModel;
|
||||
public InputViewModel ParentModel { get; }
|
||||
|
||||
public ControllerInputViewModel(InputViewModel model, GamepadInputConfig config)
|
||||
{
|
||||
|
||||
@@ -68,6 +68,8 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
||||
public bool IsKeyboard => !IsController;
|
||||
public bool IsRight { get; set; }
|
||||
public bool IsLeft { get; set; }
|
||||
|
||||
public bool HasLed => SelectedGamepad.Features.HasFlag(GamepadFeaturesFlag.Led);
|
||||
|
||||
public bool IsModified { get; set; }
|
||||
public event Action NotifyChangesEvent;
|
||||
|
||||
@@ -1662,10 +1662,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
|
||||
public async Task OpenAmiiboWindow()
|
||||
{
|
||||
if (!IsAmiiboRequested)
|
||||
return;
|
||||
|
||||
if (AppHost.Device.System.SearchingForAmiibo(out int deviceId))
|
||||
if (AppHost.Device.System.SearchingForAmiibo(out int deviceId) && IsGameRunning)
|
||||
{
|
||||
string titleId = AppHost.Device.Processes.ActiveApplication.ProgramIdText.ToUpper();
|
||||
AmiiboWindow window = new(ShowAll, LastScannedAmiiboId, titleId);
|
||||
@@ -1683,10 +1680,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
}
|
||||
public async Task OpenBinFile()
|
||||
{
|
||||
if (!IsAmiiboRequested)
|
||||
return;
|
||||
|
||||
if (AppHost.Device.System.SearchingForAmiibo(out int deviceId))
|
||||
if (AppHost.Device.System.SearchingForAmiibo(out _) && IsGameRunning)
|
||||
{
|
||||
var result = await StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
|
||||
{
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
xmlns:ext="clr-namespace:Ryujinx.Ava.Common.Markup"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||
xmlns:controls="clr-namespace:Ryujinx.Ava.UI.Controls"
|
||||
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels.Input"
|
||||
xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
|
||||
@@ -486,6 +487,37 @@
|
||||
</Button>
|
||||
</Grid>
|
||||
</Border>
|
||||
<Border
|
||||
BorderBrush="{DynamicResource ThemeControlBorderColor}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="5"
|
||||
HorizontalAlignment="Stretch"
|
||||
Margin="0,-1,0,0">
|
||||
<Grid IsVisible="{Binding ParentModel.HasLed}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<CheckBox
|
||||
Margin="10"
|
||||
MinWidth="0"
|
||||
Grid.Column="0"
|
||||
IsChecked="{Binding Config.EnableLedChanging, Mode=TwoWay}">
|
||||
<TextBlock Text="Custom LED color" />
|
||||
</CheckBox>
|
||||
<ui:ColorPickerButton
|
||||
Grid.Column="1"
|
||||
Margin="10"
|
||||
IsMoreButtonVisible="False"
|
||||
UseColorPalette="False"
|
||||
UseColorTriangle="False"
|
||||
UseColorWheel="False"
|
||||
ShowAcceptDismissButtons="False"
|
||||
IsAlphaEnabled="False"
|
||||
Color="{Binding Config.LedColor, Mode=TwoWay}">
|
||||
</ui:ColorPickerButton>
|
||||
</Grid>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
<!-- Right Controls -->
|
||||
|
||||
@@ -4,14 +4,11 @@ using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.LogicalTree;
|
||||
using DiscordRPC;
|
||||
using Ryujinx.Ava.UI.Helpers;
|
||||
using Ryujinx.Ava.UI.ViewModels.Input;
|
||||
using Ryujinx.Common.Configuration.Hid.Controller;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Input;
|
||||
using Ryujinx.Input.Assigner;
|
||||
using System;
|
||||
using StickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Views.Input
|
||||
|
||||
@@ -114,8 +114,7 @@
|
||||
Grid.Column="1"
|
||||
MinWidth="90"
|
||||
Margin="10,0,0,0"
|
||||
ToolTip.Tip="{ext:Locale AddGameDirTooltip}"
|
||||
Click="AddGameDirButton_OnClick">
|
||||
ToolTip.Tip="{ext:Locale AddGameDirTooltip}">
|
||||
<TextBlock HorizontalAlignment="Center"
|
||||
Text="{ext:Locale SettingsTabGeneralAdd}" />
|
||||
</Button>
|
||||
@@ -168,8 +167,7 @@
|
||||
Grid.Column="1"
|
||||
MinWidth="90"
|
||||
Margin="10,0,0,0"
|
||||
ToolTip.Tip="{ext:Locale AddAutoloadDirTooltip}"
|
||||
Click="AddAutoloadDirButton_OnClick">
|
||||
ToolTip.Tip="{ext:Locale AddAutoloadDirTooltip}">
|
||||
<TextBlock HorizontalAlignment="Center"
|
||||
Text="{ext:Locale SettingsTabGeneralAdd}" />
|
||||
</Button>
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
using Avalonia.Collections;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Platform.Storage;
|
||||
using Avalonia.VisualTree;
|
||||
using Gommon;
|
||||
using Ryujinx.Ava.UI.Helpers;
|
||||
using Ryujinx.Ava.UI.ViewModels;
|
||||
using Ryujinx.Ava.Utilities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Views.Settings
|
||||
{
|
||||
@@ -18,31 +23,39 @@ namespace Ryujinx.Ava.UI.Views.Settings
|
||||
{
|
||||
InitializeComponent();
|
||||
ShowTitleBarBox.IsVisible = OperatingSystem.IsWindows();
|
||||
AddGameDirButton.Command =
|
||||
Commands.Create(() => AddDirButton(GameDirPathBox, ViewModel.GameDirectories, true));
|
||||
AddAutoloadDirButton.Command =
|
||||
Commands.Create(() => AddDirButton(AutoloadDirPathBox, ViewModel.AutoloadDirectories, false));
|
||||
}
|
||||
|
||||
private async void AddGameDirButton_OnClick(object sender, RoutedEventArgs e)
|
||||
private async Task AddDirButton(TextBox addDirBox, AvaloniaList<string> directories, bool isGameList)
|
||||
{
|
||||
string path = GameDirPathBox.Text;
|
||||
string path = addDirBox.Text;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(path) && Directory.Exists(path) && !ViewModel.GameDirectories.Contains(path))
|
||||
if (!string.IsNullOrWhiteSpace(path) && Directory.Exists(path) && !directories.Contains(path))
|
||||
{
|
||||
ViewModel.GameDirectories.Add(path);
|
||||
ViewModel.GameDirectoryChanged = true;
|
||||
directories.Add(path);
|
||||
|
||||
addDirBox.Clear();
|
||||
|
||||
if (isGameList)
|
||||
ViewModel.GameDirectoryChanged = true;
|
||||
else
|
||||
ViewModel.AutoloadDirectoryChanged = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.GetVisualRoot() is Window window)
|
||||
{
|
||||
var result = await window.StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
|
||||
{
|
||||
AllowMultiple = false,
|
||||
});
|
||||
Optional<IStorageFolder> folder = await RyujinxApp.MainWindow.ViewModel.StorageProvider.OpenSingleFolderPickerAsync();
|
||||
|
||||
if (result.Count > 0)
|
||||
{
|
||||
ViewModel.GameDirectories.Add(result[0].Path.LocalPath);
|
||||
if (folder.HasValue)
|
||||
{
|
||||
directories.Add(folder.Value.Path.LocalPath);
|
||||
|
||||
if (isGameList)
|
||||
ViewModel.GameDirectoryChanged = true;
|
||||
}
|
||||
else
|
||||
ViewModel.AutoloadDirectoryChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -63,33 +76,6 @@ namespace Ryujinx.Ava.UI.Views.Settings
|
||||
}
|
||||
}
|
||||
|
||||
private async void AddAutoloadDirButton_OnClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
string path = AutoloadDirPathBox.Text;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(path) && Directory.Exists(path) && !ViewModel.AutoloadDirectories.Contains(path))
|
||||
{
|
||||
ViewModel.AutoloadDirectories.Add(path);
|
||||
ViewModel.AutoloadDirectoryChanged = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.GetVisualRoot() is Window window)
|
||||
{
|
||||
var result = await window.StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
|
||||
{
|
||||
AllowMultiple = false,
|
||||
});
|
||||
|
||||
if (result.Count > 0)
|
||||
{
|
||||
ViewModel.AutoloadDirectories.Add(result[0].Path.LocalPath);
|
||||
ViewModel.AutoloadDirectoryChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveAutoloadDirButton_OnClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
int oldIndex = AutoloadDirsList.SelectedIndex;
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Ryujinx.Ava.Utilities.Configuration
|
||||
/// <summary>
|
||||
/// The current version of the file format
|
||||
/// </summary>
|
||||
public const int CurrentVersion = 60;
|
||||
public const int CurrentVersion = 61;
|
||||
|
||||
/// <summary>
|
||||
/// Version of the configuration file format
|
||||
|
||||
@@ -263,15 +263,12 @@ namespace Ryujinx.Ava.Utilities.Configuration
|
||||
}),
|
||||
(30, static cff =>
|
||||
{
|
||||
foreach (InputConfig config in cff.InputConfig)
|
||||
foreach (StandardControllerInputConfig config in cff.InputConfig.OfType<StandardControllerInputConfig>())
|
||||
{
|
||||
if (config is StandardControllerInputConfig controllerConfig)
|
||||
config.Rumble = new RumbleConfigController
|
||||
{
|
||||
controllerConfig.Rumble = new RumbleConfigController
|
||||
{
|
||||
EnableRumble = false, StrongRumble = 1f, WeakRumble = 1f,
|
||||
};
|
||||
}
|
||||
EnableRumble = false, StrongRumble = 1f, WeakRumble = 1f,
|
||||
};
|
||||
}
|
||||
}),
|
||||
(31, static cff => cff.BackendThreading = BackendThreading.Auto),
|
||||
@@ -416,7 +413,18 @@ namespace Ryujinx.Ava.Utilities.Configuration
|
||||
// so as a compromise users who want to use it will simply need to re-enable it once after updating.
|
||||
cff.IgnoreApplet = false;
|
||||
}),
|
||||
(60, static cff => cff.StartNoUI = false)
|
||||
(60, static cff => cff.StartNoUI = false),
|
||||
(61, static cff =>
|
||||
{
|
||||
foreach (StandardControllerInputConfig config in cff.InputConfig.OfType<StandardControllerInputConfig>())
|
||||
{
|
||||
config.Led = new LedConfigController
|
||||
{
|
||||
EnableLed = false,
|
||||
LedColor = 328189
|
||||
};
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
47
src/Ryujinx/Utilities/StorageProviderExtensions.cs
Normal file
47
src/Ryujinx/Utilities/StorageProviderExtensions.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using Avalonia.Platform.Storage;
|
||||
using Gommon;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ryujinx.Ava.Utilities
|
||||
{
|
||||
public static class StorageProviderExtensions
|
||||
{
|
||||
public static async Task<Optional<IStorageFolder>> OpenSingleFolderPickerAsync(this IStorageProvider storageProvider, FolderPickerOpenOptions openOptions = null) =>
|
||||
await storageProvider.OpenFolderPickerAsync(FixOpenOptions(openOptions, false))
|
||||
.Then(folders => folders.FindFirst());
|
||||
|
||||
public static async Task<Optional<IStorageFile>> OpenSingleFilePickerAsync(this IStorageProvider storageProvider, FilePickerOpenOptions openOptions = null) =>
|
||||
await storageProvider.OpenFilePickerAsync(FixOpenOptions(openOptions, false))
|
||||
.Then(files => files.FindFirst());
|
||||
|
||||
public static async Task<Optional<IReadOnlyList<IStorageFolder>>> OpenMultiFolderPickerAsync(this IStorageProvider storageProvider, FolderPickerOpenOptions openOptions = null) =>
|
||||
await storageProvider.OpenFolderPickerAsync(FixOpenOptions(openOptions, true))
|
||||
.Then(folders => folders.Count > 0 ? Optional.Of(folders) : default);
|
||||
|
||||
public static async Task<Optional<IReadOnlyList<IStorageFile>>> OpenMultiFilePickerAsync(this IStorageProvider storageProvider, FilePickerOpenOptions openOptions = null) =>
|
||||
await storageProvider.OpenFilePickerAsync(FixOpenOptions(openOptions, true))
|
||||
.Then(files => files.Count > 0 ? Optional.Of(files) : default);
|
||||
|
||||
private static FilePickerOpenOptions FixOpenOptions(this FilePickerOpenOptions openOptions, bool allowMultiple)
|
||||
{
|
||||
if (openOptions is null)
|
||||
return new FilePickerOpenOptions { AllowMultiple = allowMultiple };
|
||||
|
||||
openOptions.AllowMultiple = allowMultiple;
|
||||
|
||||
return openOptions;
|
||||
}
|
||||
|
||||
private static FolderPickerOpenOptions FixOpenOptions(this FolderPickerOpenOptions openOptions, bool allowMultiple)
|
||||
{
|
||||
if (openOptions is null)
|
||||
return new FolderPickerOpenOptions { AllowMultiple = allowMultiple };
|
||||
|
||||
openOptions.AllowMultiple = allowMultiple;
|
||||
|
||||
return openOptions;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user