Compare commits

..

5 Commits

Author SHA1 Message Date
Evan Husted
9f53b07491 misc: chore: Fix shader cache & CPU cache being in different folders on non-Windows
fixes #565
2025-01-22 08:52:21 -06:00
Evan Husted
cd8113dadf misc: chore: Collapse adding a game/autoload dir into a single reusable method. 2025-01-21 18:59:56 -06:00
Evan Husted
9089c4ffe5 misc: chore: Multi/Single file/folder picker extensions (for convenience)
The result of these extensions is an empty Optional when the user hits Cancel on the shown file picker.
2025-01-21 18:59:19 -06:00
Evan Husted
fe9d8d05bd UI: Fixed the Amiibo keybind only working when the UI had been updated. 2025-01-21 18:00:51 -06:00
Evan Husted
880a8ae748 misc: chore: Remove duplicated styling blocks in MainMenuBarView in favor of a reusable Avalonia Style. 2025-01-21 17:50:55 -06:00
10 changed files with 121 additions and 157 deletions

View File

@@ -118,7 +118,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
private static string GetDiskCachePath() private static string GetDiskCachePath()
{ {
return GraphicsConfig.EnableShaderCache && GraphicsConfig.TitleId != null return GraphicsConfig.EnableShaderCache && GraphicsConfig.TitleId != null
? Path.Combine(AppDataManager.GamesDirPath, GraphicsConfig.TitleId, "cache", "shader") ? Path.Combine(AppDataManager.GamesDirPath, GraphicsConfig.TitleId.ToLower(), "cache", "shader")
: null; : null;
} }

View File

@@ -0,0 +1,13 @@
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style Selector="MenuItem.withCheckbox Viewbox#PART_IconPresenter">
<Setter Property="MaxHeight" Value="36" />
<Setter Property="MinHeight" Value="36" />
<Setter Property="MaxWidth" Value="36" />
<Setter Property="MinWidth" Value="36" />
</Style>
<Style Selector="MenuItem.withCheckbox ContentPresenter#PART_HeaderPresenter">
<Setter Property="Padding" Value="-10,0,0,0" />
</Style>
</Styles>

View File

@@ -1,6 +1,6 @@
using Avalonia.Controls.Notifications;
using Avalonia.Platform.Storage; using Avalonia.Platform.Storage;
using Avalonia.Threading; using Avalonia.Threading;
using Gommon;
using LibHac; using LibHac;
using LibHac.Account; using LibHac.Account;
using LibHac.Common; using LibHac.Common;
@@ -15,6 +15,7 @@ using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Controls; using Ryujinx.Ava.UI.Controls;
using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.Utilities;
using Ryujinx.Ava.Utilities.Configuration; using Ryujinx.Ava.Utilities.Configuration;
using Ryujinx.Common.Helper; using Ryujinx.Common.Helper;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
@@ -418,35 +419,27 @@ namespace Ryujinx.Ava.Common
public static async Task ExtractAoc(IStorageProvider storageProvider, string updateFilePath, string updateName) 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], Title = LocaleManager.Instance[LocaleKeys.FolderDialogExtractTitle]
AllowMultiple = false,
}); });
if (result.Count == 0) if (!result.HasValue) return;
{
return; ExtractAoc(result.Value.Path.LocalPath, updateFilePath, updateName);
}
ExtractAoc(result[0].Path.LocalPath, updateFilePath, updateName);
} }
public static async Task ExtractSection(IStorageProvider storageProvider, NcaSectionType ncaSectionType, string titleFilePath, string titleName, int programIndex = 0) 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], Title = LocaleManager.Instance[LocaleKeys.FolderDialogExtractTitle]
AllowMultiple = false,
}); });
if (result.Count == 0) if (!result.HasValue) return;
{
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) public static (Result? result, bool canceled) CopyDirectory(FileSystemClient fs, string sourcePath, string destPath, CancellationToken token)

View File

@@ -123,12 +123,13 @@
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</AvaloniaResource> </AvaloniaResource>
<AvaloniaResource Include="Assets\Styles\Styles.xaml" /> <AvaloniaResource Include="Assets\Styles\Styles.xaml" />
<AvaloniaResource Include="Assets\Styles\CheckboxMenuItemStyle.axaml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Remove="Assets\locales.json" /> <None Remove="Assets\locales.json" />
<None Remove="Assets\Styles\Styles.xaml" />
<None Remove="Assets\Styles\Themes.xaml" /> <None Remove="Assets\Styles\Themes.xaml" />
<None Remove="Assets\Styles\CheckboxMenuItemStyle.xaml" />
<None Remove="Assets\Icons\Controller_JoyConLeft.svg" /> <None Remove="Assets\Icons\Controller_JoyConLeft.svg" />
<None Remove="Assets\Icons\Controller_JoyConPair.svg" /> <None Remove="Assets\Icons\Controller_JoyConPair.svg" />
<None Remove="Assets\Icons\Controller_JoyConRight.svg" /> <None Remove="Assets\Icons\Controller_JoyConRight.svg" />
@@ -150,6 +151,7 @@
</EmbeddedResource> </EmbeddedResource>
<EmbeddedResource Include="Assets\locales.json" /> <EmbeddedResource Include="Assets\locales.json" />
<EmbeddedResource Include="Assets\Styles\Styles.xaml" /> <EmbeddedResource Include="Assets\Styles\Styles.xaml" />
<EmbeddedResource Include="Assets\Styles\CheckboxMenuItemStyle.axaml" />
<EmbeddedResource Include="Assets\Icons\Controller_JoyConLeft.svg" /> <EmbeddedResource Include="Assets\Icons\Controller_JoyConLeft.svg" />
<EmbeddedResource Include="Assets\Icons\Controller_JoyConPair.svg" /> <EmbeddedResource Include="Assets\Icons\Controller_JoyConPair.svg" />
<EmbeddedResource Include="Assets\Icons\Controller_JoyConRight.svg" /> <EmbeddedResource Include="Assets\Icons\Controller_JoyConRight.svg" />

View File

@@ -16,5 +16,6 @@
<Application.Styles> <Application.Styles>
<sty:FluentAvaloniaTheme PreferUserAccentColor="True" PreferSystemTheme="False" /> <sty:FluentAvaloniaTheme PreferUserAccentColor="True" PreferSystemTheme="False" />
<StyleInclude Source="/Assets/Styles/Styles.xaml" /> <StyleInclude Source="/Assets/Styles/Styles.xaml" />
<StyleInclude Source="/Assets/Styles/CheckboxMenuItemStyle.axaml"/>
</Application.Styles> </Application.Styles>
</Application> </Application>

View File

@@ -1662,10 +1662,7 @@ namespace Ryujinx.Ava.UI.ViewModels
public async Task OpenAmiiboWindow() public async Task OpenAmiiboWindow()
{ {
if (!IsAmiiboRequested) if (AppHost.Device.System.SearchingForAmiibo(out int deviceId) && IsGameRunning)
return;
if (AppHost.Device.System.SearchingForAmiibo(out int deviceId))
{ {
string titleId = AppHost.Device.Processes.ActiveApplication.ProgramIdText.ToUpper(); string titleId = AppHost.Device.Processes.ActiveApplication.ProgramIdText.ToUpper();
AmiiboWindow window = new(ShowAll, LastScannedAmiiboId, titleId); AmiiboWindow window = new(ShowAll, LastScannedAmiiboId, titleId);
@@ -1683,10 +1680,7 @@ namespace Ryujinx.Ava.UI.ViewModels
} }
public async Task OpenBinFile() public async Task OpenBinFile()
{ {
if (!IsAmiiboRequested) if (AppHost.Device.System.SearchingForAmiibo(out _) && IsGameRunning)
return;
if (AppHost.Device.System.SearchingForAmiibo(out int deviceId))
{ {
var result = await StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions var result = await StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
{ {

View File

@@ -81,25 +81,16 @@
<MenuItem <MenuItem
Command="{Binding ToggleFullscreen}" Command="{Binding ToggleFullscreen}"
Header="{ext:Locale MenuBarOptionsToggleFullscreen}" Header="{ext:Locale MenuBarOptionsToggleFullscreen}"
Classes="withCheckbox"
Padding="0" Padding="0"
Icon="{ext:Icon fa-solid fa-expand}" Icon="{ext:Icon fa-solid fa-expand}"
InputGesture="F11"> InputGesture="F11">
<MenuItem.Styles>
<Style Selector="Viewbox#PART_IconPresenter">
<Setter Property="MaxHeight" Value="36" />
<Setter Property="MinHeight" Value="36" />
<Setter Property="MaxWidth" Value="36" />
<Setter Property="MinWidth" Value="36" />
</Style>
<Style Selector="ContentPresenter#PART_HeaderPresenter">
<Setter Property="Padding" Value="-10,0,0,0" />
</Style>
</MenuItem.Styles>
</MenuItem> </MenuItem>
<MenuItem <MenuItem
Padding="0" Padding="0"
Command="{Binding ToggleStartGamesInFullscreen}" Command="{Binding ToggleStartGamesInFullscreen}"
Header="{ext:Locale MenuBarOptionsStartGamesInFullscreen}"> Header="{ext:Locale MenuBarOptionsStartGamesInFullscreen}"
Classes="withCheckbox">
<MenuItem.Icon> <MenuItem.Icon>
<CheckBox <CheckBox
MinWidth="{DynamicResource CheckBoxSize}" MinWidth="{DynamicResource CheckBoxSize}"
@@ -107,22 +98,12 @@
IsChecked="{Binding StartGamesInFullscreen, Mode=TwoWay}" IsChecked="{Binding StartGamesInFullscreen, Mode=TwoWay}"
Padding="0" /> Padding="0" />
</MenuItem.Icon> </MenuItem.Icon>
<MenuItem.Styles>
<Style Selector="Viewbox#PART_IconPresenter">
<Setter Property="MaxHeight" Value="36" />
<Setter Property="MinHeight" Value="36" />
<Setter Property="MaxWidth" Value="36" />
<Setter Property="MinWidth" Value="36" />
</Style>
<Style Selector="ContentPresenter#PART_HeaderPresenter">
<Setter Property="Padding" Value="-10,0,0,0" />
</Style>
</MenuItem.Styles>
</MenuItem> </MenuItem>
<MenuItem <MenuItem
Padding="0" Padding="0"
Command="{Binding ToggleStartGamesWithoutUI}" Command="{Binding ToggleStartGamesWithoutUI}"
Header="{ext:Locale MenuBarOptionsStartGamesWithoutUI}"> Header="{ext:Locale MenuBarOptionsStartGamesWithoutUI}"
Classes="withCheckbox">
<MenuItem.Icon> <MenuItem.Icon>
<CheckBox <CheckBox
MinWidth="{DynamicResource CheckBoxSize}" MinWidth="{DynamicResource CheckBoxSize}"
@@ -130,23 +111,13 @@
IsChecked="{Binding StartGamesWithoutUI, Mode=TwoWay}" IsChecked="{Binding StartGamesWithoutUI, Mode=TwoWay}"
Padding="0" /> Padding="0" />
</MenuItem.Icon> </MenuItem.Icon>
<MenuItem.Styles>
<Style Selector="Viewbox#PART_IconPresenter">
<Setter Property="MaxHeight" Value="36" />
<Setter Property="MinHeight" Value="36" />
<Setter Property="MaxWidth" Value="36" />
<Setter Property="MinWidth" Value="36" />
</Style>
<Style Selector="ContentPresenter#PART_HeaderPresenter">
<Setter Property="Padding" Value="-10,0,0,0" />
</Style>
</MenuItem.Styles>
</MenuItem> </MenuItem>
<MenuItem <MenuItem
Padding="0" Padding="0"
IsVisible="{Binding ShowConsoleVisible}" IsVisible="{Binding ShowConsoleVisible}"
Command="{Binding ToggleShowConsole}" Command="{Binding ToggleShowConsole}"
Header="{ext:Locale MenuBarOptionsShowConsole}"> Header="{ext:Locale MenuBarOptionsShowConsole}"
Classes="withCheckbox">
<MenuItem.Icon> <MenuItem.Icon>
<CheckBox <CheckBox
MinWidth="{DynamicResource CheckBoxSize}" MinWidth="{DynamicResource CheckBoxSize}"
@@ -154,35 +125,14 @@
IsChecked="{Binding ShowConsole, Mode=TwoWay}" IsChecked="{Binding ShowConsole, Mode=TwoWay}"
Padding="0" /> Padding="0" />
</MenuItem.Icon> </MenuItem.Icon>
<MenuItem.Styles>
<Style Selector="Viewbox#PART_IconPresenter">
<Setter Property="MaxHeight" Value="36" />
<Setter Property="MinHeight" Value="36" />
<Setter Property="MaxWidth" Value="36" />
<Setter Property="MinWidth" Value="36" />
</Style>
<Style Selector="ContentPresenter#PART_HeaderPresenter">
<Setter Property="Padding" Value="-10,0,0,0" />
</Style>
</MenuItem.Styles>
</MenuItem> </MenuItem>
<Separator/> <Separator/>
<MenuItem <MenuItem
Name="ChangeLanguageMenuItem" Name="ChangeLanguageMenuItem"
Padding="0" Padding="0"
Header="{ext:Locale MenuBarOptionsChangeLanguage}" Header="{ext:Locale MenuBarOptionsChangeLanguage}"
Icon="{ext:Icon fa-solid fa-language}"> Icon="{ext:Icon fa-solid fa-language}"
<MenuItem.Styles> Classes="withCheckbox">
<Style Selector="Viewbox#PART_IconPresenter">
<Setter Property="MaxHeight" Value="36" />
<Setter Property="MinHeight" Value="36" />
<Setter Property="MaxWidth" Value="36" />
<Setter Property="MinWidth" Value="36" />
</Style>
<Style Selector="ContentPresenter#PART_HeaderPresenter">
<Setter Property="Padding" Value="-10,0,0,0" />
</Style>
</MenuItem.Styles>
</MenuItem> </MenuItem>
<MenuItem <MenuItem
Name="ToggleFileTypesMenuItem" Name="ToggleFileTypesMenuItem"
@@ -194,18 +144,8 @@
Padding="0" Padding="0"
Header="{ext:Locale MenuBarOptionsSettings}" Header="{ext:Locale MenuBarOptionsSettings}"
Icon="{ext:Icon fa-solid fa-gear}" Icon="{ext:Icon fa-solid fa-gear}"
ToolTip.Tip="{ext:Locale OpenSettingsTooltip}"> ToolTip.Tip="{ext:Locale OpenSettingsTooltip}"
<MenuItem.Styles> Classes="withCheckbox">
<Style Selector="Viewbox#PART_IconPresenter">
<Setter Property="MaxHeight" Value="36" />
<Setter Property="MinHeight" Value="36" />
<Setter Property="MaxWidth" Value="36" />
<Setter Property="MinWidth" Value="36" />
</Style>
<Style Selector="ContentPresenter#PART_HeaderPresenter">
<Setter Property="Padding" Value="-10,0,0,0" />
</Style>
</MenuItem.Styles>
</MenuItem> </MenuItem>
<MenuItem <MenuItem
Command="{Binding ManageProfiles}" Command="{Binding ManageProfiles}"
@@ -213,18 +153,8 @@
Header="{ext:Locale MenuBarOptionsManageUserProfiles}" Header="{ext:Locale MenuBarOptionsManageUserProfiles}"
Icon="{ext:Icon mdi-account}" Icon="{ext:Icon mdi-account}"
IsEnabled="{Binding EnableNonGameRunningControls}" IsEnabled="{Binding EnableNonGameRunningControls}"
ToolTip.Tip="{ext:Locale OpenProfileManagerTooltip}"> ToolTip.Tip="{ext:Locale OpenProfileManagerTooltip}"
<MenuItem.Styles> Classes="withCheckbox">
<Style Selector="Viewbox#PART_IconPresenter">
<Setter Property="MaxHeight" Value="36" />
<Setter Property="MinHeight" Value="36" />
<Setter Property="MaxWidth" Value="36" />
<Setter Property="MinWidth" Value="36" />
</Style>
<Style Selector="ContentPresenter#PART_HeaderPresenter">
<Setter Property="Padding" Value="-10,0,0,0" />
</Style>
</MenuItem.Styles>
</MenuItem> </MenuItem>
</MenuItem> </MenuItem>
<MenuItem <MenuItem

View File

@@ -114,8 +114,7 @@
Grid.Column="1" Grid.Column="1"
MinWidth="90" MinWidth="90"
Margin="10,0,0,0" Margin="10,0,0,0"
ToolTip.Tip="{ext:Locale AddGameDirTooltip}" ToolTip.Tip="{ext:Locale AddGameDirTooltip}">
Click="AddGameDirButton_OnClick">
<TextBlock HorizontalAlignment="Center" <TextBlock HorizontalAlignment="Center"
Text="{ext:Locale SettingsTabGeneralAdd}" /> Text="{ext:Locale SettingsTabGeneralAdd}" />
</Button> </Button>
@@ -168,8 +167,7 @@
Grid.Column="1" Grid.Column="1"
MinWidth="90" MinWidth="90"
Margin="10,0,0,0" Margin="10,0,0,0"
ToolTip.Tip="{ext:Locale AddAutoloadDirTooltip}" ToolTip.Tip="{ext:Locale AddAutoloadDirTooltip}">
Click="AddAutoloadDirButton_OnClick">
<TextBlock HorizontalAlignment="Center" <TextBlock HorizontalAlignment="Center"
Text="{ext:Locale SettingsTabGeneralAdd}" /> Text="{ext:Locale SettingsTabGeneralAdd}" />
</Button> </Button>

View File

@@ -1,12 +1,17 @@
using Avalonia.Collections;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.Platform.Storage; using Avalonia.Platform.Storage;
using Avalonia.VisualTree; using Avalonia.VisualTree;
using Gommon;
using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.Ava.Utilities;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
namespace Ryujinx.Ava.UI.Views.Settings namespace Ryujinx.Ava.UI.Views.Settings
{ {
@@ -18,31 +23,39 @@ namespace Ryujinx.Ava.UI.Views.Settings
{ {
InitializeComponent(); InitializeComponent();
ShowTitleBarBox.IsVisible = OperatingSystem.IsWindows(); 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); directories.Add(path);
ViewModel.GameDirectoryChanged = true;
addDirBox.Clear();
if (isGameList)
ViewModel.GameDirectoryChanged = true;
else
ViewModel.AutoloadDirectoryChanged = true;
} }
else else
{ {
if (this.GetVisualRoot() is Window window) Optional<IStorageFolder> folder = await RyujinxApp.MainWindow.ViewModel.StorageProvider.OpenSingleFolderPickerAsync();
{
var result = await window.StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
{
AllowMultiple = false,
});
if (result.Count > 0) if (folder.HasValue)
{ {
ViewModel.GameDirectories.Add(result[0].Path.LocalPath); directories.Add(folder.Value.Path.LocalPath);
if (isGameList)
ViewModel.GameDirectoryChanged = true; 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) private void RemoveAutoloadDirButton_OnClick(object sender, RoutedEventArgs e)
{ {
int oldIndex = AutoloadDirsList.SelectedIndex; int oldIndex = AutoloadDirsList.SelectedIndex;

View 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;
}
}
}