This commit is contained in:
Luke 2024-04-06 12:51:47 -04:00 committed by GitHub
commit 14307df5c8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 251 additions and 19 deletions

View file

@ -215,6 +215,8 @@ namespace Ryujinx.UI
_startFullScreen.Active = true;
}
ConfigurationState.Instance.UI.UseSystemGameFolders.Value = false;
_showConsole.Active = ConfigurationState.Instance.UI.ShowConsole.Value;
_showConsole.Visible = ConsoleHelper.SetConsoleWindowStateSupported;

View file

@ -36,6 +36,10 @@ namespace Ryujinx.UI.App.Common
public string FileSizeString => ValueFormatUtils.FormatFileSize(FileSize);
public bool IsGame => FileExtension != "Folder";
public bool IsFolder => FileExtension == "Folder";
public static string GetApplicationBuildId(VirtualFileSystem virtualFileSystem, string titleFilePath)
{
using FileStream file = new(titleFilePath, FileMode.Open, FileAccess.Read);

View file

@ -45,6 +45,7 @@ namespace Ryujinx.UI.App.Common
private readonly VirtualFileSystem _virtualFileSystem;
private Language _desiredTitleLanguage;
private CancellationTokenSource _cancellationToken;
private bool _isLoading;
private static readonly ApplicationJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
private static readonly TitleUpdateMetadataJsonSerializerContext _titleSerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
@ -62,6 +63,11 @@ namespace Ryujinx.UI.App.Common
private static byte[] GetResourceBytes(string resourceName)
{
if (resourceName == "")
{
return Array.Empty<byte>();
}
Stream resourceStream = Assembly.GetCallingAssembly().GetManifestResourceStream(resourceName);
byte[] resourceByteArray = new byte[resourceStream.Length];
@ -84,6 +90,28 @@ namespace Ryujinx.UI.App.Common
}
public void LoadApplications(List<string> appDirs, Language desiredTitleLanguage)
{
if (_isLoading)
{
return;
}
_isLoading = true;
Thread applicationLibraryThread = new(() =>
{
LoadApplicationsReal(appDirs, desiredTitleLanguage);
_isLoading = false;
})
{
Name = "GUI.ApplicationLibraryThread",
IsBackground = true,
};
applicationLibraryThread.Start();
}
private void LoadApplicationsReal(List<string> appDirs, Language desiredTitleLanguage)
{
int numApplicationsFound = 0;
int numApplicationsLoaded = 0;
@ -113,7 +141,37 @@ namespace Ryujinx.UI.App.Common
try
{
IEnumerable<string> files = Directory.EnumerateFiles(appDir, "*", SearchOption.AllDirectories).Where(file =>
var FileSearchOption = SearchOption.AllDirectories;
if (ConfigurationState.Instance.UI.UseSystemGameFolders)
{
IEnumerable<string> folders = Directory.EnumerateDirectories(appDir, "*", SearchOption.TopDirectoryOnly);
foreach (string folder in folders)
{
if (_cancellationToken.Token.IsCancellationRequested)
{
return;
}
var fileInfo = new FileInfo(folder);
var fullPath = fileInfo.ResolveLinkTarget(true)?.FullName ?? fileInfo.FullName;
ApplicationData folderData = new()
{
TitleName = fileInfo.Name,
FileExtension = "Folder",
Path = fullPath,
};
OnApplicationAdded(new ApplicationAddedEventArgs
{
AppData = folderData,
});
}
FileSearchOption = SearchOption.TopDirectoryOnly;
}
IEnumerable<string> files = Directory.EnumerateFiles(appDir, "*", FileSearchOption).Where(file =>
{
return
(Path.GetExtension(file).ToLower() is ".nsp" && ConfigurationState.Instance.UI.ShownFileTypes.NSP.Value) ||

View file

@ -15,7 +15,7 @@ namespace Ryujinx.UI.Common.Configuration
/// <summary>
/// The current version of the file format
/// </summary>
public const int CurrentVersion = 49;
public const int CurrentVersion = 50;
/// <summary>
/// Version of the configuration file format
@ -317,6 +317,11 @@ namespace Ryujinx.UI.Common.Configuration
/// </summary>
public bool ShowConsole { get; set; }
/// <summary>
/// use system directories when listing games
/// </summary>
public bool UseSystemGameFolders { get; set; }
/// <summary>
/// Enable or disable keyboard support (Independent from controllers binding)
/// </summary>

View file

@ -186,6 +186,11 @@ namespace Ryujinx.UI.Common.Configuration
/// </summary>
public ReactiveObject<bool> IsAscendingOrder { get; private set; }
/// <summary>
/// use system directories when listing games
/// </summary>
public ReactiveObject<bool> UseSystemGameFolders { get; private set; }
public UISection()
{
GuiColumns = new Columns();
@ -204,6 +209,7 @@ namespace Ryujinx.UI.Common.Configuration
IsAscendingOrder = new ReactiveObject<bool>();
LanguageCode = new ReactiveObject<string>();
ShowConsole = new ReactiveObject<bool>();
UseSystemGameFolders = new ReactiveObject<bool>();
ShowConsole.Event += static (s, e) => { ConsoleHelper.SetConsoleWindowState(e.NewValue); };
}
}
@ -741,6 +747,7 @@ namespace Ryujinx.UI.Common.Configuration
IsAscendingOrder = UI.IsAscendingOrder,
StartFullscreen = UI.StartFullscreen,
ShowConsole = UI.ShowConsole,
UseSystemGameFolders = UI.UseSystemGameFolders,
EnableKeyboard = Hid.EnableKeyboard,
EnableMouse = Hid.EnableMouse,
Hotkeys = Hid.Hotkeys,
@ -836,6 +843,7 @@ namespace Ryujinx.UI.Common.Configuration
UI.IsAscendingOrder.Value = true;
UI.StartFullscreen.Value = false;
UI.ShowConsole.Value = true;
UI.UseSystemGameFolders.Value = true;
UI.WindowStartup.WindowSizeWidth.Value = 1280;
UI.WindowStartup.WindowSizeHeight.Value = 760;
UI.WindowStartup.WindowPositionX.Value = 0;
@ -1442,6 +1450,15 @@ namespace Ryujinx.UI.Common.Configuration
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 50)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 50.");
configurationFileFormat.UseSystemGameFolders = true;
configurationFileUpdated = true;
}
Logger.EnableFileLog.Value = configurationFileFormat.EnableFileLog;
Graphics.ResScale.Value = configurationFileFormat.ResScale;
Graphics.ResScaleCustom.Value = configurationFileFormat.ResScaleCustom;
@ -1518,6 +1535,7 @@ namespace Ryujinx.UI.Common.Configuration
UI.ApplicationSort.Value = configurationFileFormat.ApplicationSort;
UI.StartFullscreen.Value = configurationFileFormat.StartFullscreen;
UI.ShowConsole.Value = configurationFileFormat.ShowConsole;
UI.UseSystemGameFolders.Value = configurationFileFormat.UseSystemGameFolders;
UI.WindowStartup.WindowSizeWidth.Value = configurationFileFormat.WindowStartup.WindowSizeWidth;
UI.WindowStartup.WindowSizeHeight.Value = configurationFileFormat.WindowStartup.WindowSizeHeight;
UI.WindowStartup.WindowPositionX.Value = configurationFileFormat.WindowStartup.WindowPositionX;

View file

@ -90,6 +90,7 @@
"SettingsTabGeneral": "User Interface",
"SettingsTabGeneralGeneral": "General",
"SettingsTabGeneralEnableDiscordRichPresence": "Enable Discord Rich Presence",
"SettingsTabGeneralUseSystemGameFolders": "Show Folders",
"SettingsTabGeneralCheckUpdatesOnLaunch": "Check for Updates on Launch",
"SettingsTabGeneralShowConfirmExitDialog": "Show \"Confirm Exit\" Dialog",
"SettingsTabGeneralHideCursor": "Hide Cursor:",

View file

@ -86,6 +86,38 @@
<Setter Property="Width"
Value="120" />
</Style>
<Style Selector="ui|SymbolIcon.listSmall">
<Setter Property="FontSize"
Value="50" />
</Style>
<Style Selector="ui|SymbolIcon.listNormal">
<Setter Property="FontSize"
Value="80" />
</Style>
<Style Selector="ui|SymbolIcon.listLarge">
<Setter Property="FontSize"
Value="100" />
</Style>
<Style Selector="ui|SymbolIcon.listHuge">
<Setter Property="FontSize"
Value="120" />
</Style>
<Style Selector="ui|SymbolIcon.gridSmall">
<Setter Property="FontSize"
Value="100" />
</Style>
<Style Selector="ui|SymbolIcon.gridNormal">
<Setter Property="FontSize"
Value="120" />
</Style>
<Style Selector="ui|SymbolIcon.gridLarge">
<Setter Property="FontSize"
Value="160" />
</Style>
<Style Selector="ui|SymbolIcon.gridHuge">
<Setter Property="FontSize"
Value="200" />
</Style>
<Style Selector="#TitleBarHost &gt; Image">
<Setter Property="Margin"
Value="10" />

View file

@ -69,7 +69,16 @@
Grid.Row="0"
HorizontalAlignment="Stretch"
VerticalAlignment="Top"
IsVisible="{Binding IsGame}"
Source="{Binding Icon, Converter={StaticResource ByteImage}}" />
<ui:SymbolIcon
Grid.Row="0"
Classes.gridHuge="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridHuge}"
Classes.gridLarge="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridLarge}"
Classes.gridNormal="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridMedium}"
Classes.gridSmall="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridSmall}"
IsVisible="{Binding IsFolder}"
Symbol="Folder" />
<Panel
Grid.Row="1"
Height="50"

View file

@ -71,7 +71,17 @@
Classes.large="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridLarge}"
Classes.normal="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridMedium}"
Classes.small="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridSmall}"
IsVisible="{Binding IsGame}"
Source="{Binding Icon, Converter={StaticResource ByteImage}}" />
<ui:SymbolIcon
Grid.RowSpan="3"
Grid.Column="0"
Classes.listHuge="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridHuge}"
Classes.listLarge="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridLarge}"
Classes.listNormal="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridMedium}"
Classes.listSmall="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridSmall}"
IsVisible="{Binding IsFolder}"
Symbol="Folder" />
<Border
Grid.Column="2"
Margin="0,0,5,0"
@ -123,6 +133,7 @@
HorizontalAlignment="Right"
VerticalAlignment="Top"
Orientation="Vertical"
IsVisible="{Binding IsGame}"
Spacing="5">
<TextBlock
HorizontalAlignment="Stretch"

View file

@ -52,6 +52,7 @@ namespace Ryujinx.Ava.UI.ViewModels
private const int HotKeyPressDelayMs = 500;
private ObservableCollection<ApplicationData> _applications;
private readonly Stack<string> _pathHistory;
private string _aspectStatusText;
private string _loadHeading;
@ -85,6 +86,8 @@ namespace Ryujinx.Ava.UI.ViewModels
private bool _showAll;
private string _lastScannedAmiiboId;
private bool _statusBarVisible;
private bool _isInFolder;
private bool _foldersEnabled;
private ReadOnlyObservableCollection<ApplicationData> _appsObservableList;
private string _showUiKey = "F4";
@ -121,6 +124,8 @@ namespace Ryujinx.Ava.UI.ViewModels
.Bind(out _appsObservableList).AsObservableList();
_rendererWaitEvent = new AutoResetEvent(false);
_pathHistory = new Stack<string>();
FoldersEnabled = ConfigurationState.Instance.UI.UseSystemGameFolders;
if (Program.PreviewerDetached)
{
@ -215,6 +220,8 @@ namespace Ryujinx.Ava.UI.ViewModels
}
}
public Stack<string> PathHistory => _pathHistory;
public bool IsPaused
{
get => _isPaused;
@ -669,6 +676,26 @@ namespace Ryujinx.Ava.UI.ViewModels
public bool IsGrid => Glyph == Glyph.Grid;
public bool IsList => Glyph == Glyph.List;
public bool IsInFolder
{
get => _isInFolder;
set
{
_isInFolder = value;
OnPropertyChanged();
}
}
public bool FoldersEnabled
{
get => _foldersEnabled;
set
{
_foldersEnabled = value;
OnPropertyChanged();
}
}
internal void Sort(bool isAscending)
{
@ -1289,6 +1316,37 @@ namespace Ryujinx.Ava.UI.ViewModels
ShowConsole = !ShowConsole;
}
public void OpenFolder(string path)
{
_pathHistory.Push(path);
IsInFolder = _pathHistory.Count != 0;
Applications.Clear();
List<string> SearchPaths = new List<string>();
SearchPaths.Add(path);
ApplicationLibrary.LoadApplications(SearchPaths, ConfigurationState.Instance.System.Language);
}
public void NavigateBack()
{
if (_pathHistory.Count != 0)
{
_pathHistory.Pop();
Applications.Clear();
if (_pathHistory.Count == 0)
{
ApplicationLibrary.LoadApplications(ConfigurationState.Instance.UI.GameDirs, ConfigurationState.Instance.System.Language);
}
else
{
List<string> SearchPaths = new();
SearchPaths.Add(_pathHistory.Peek());
ApplicationLibrary.LoadApplications(SearchPaths, ConfigurationState.Instance.System.Language);
}
}
IsInFolder = _pathHistory.Count != 0;
}
public void SetListMode()
{
Glyph = Glyph.List;

View file

@ -116,6 +116,7 @@ namespace Ryujinx.Ava.UI.ViewModels
public bool IsHypervisorAvailable => OperatingSystem.IsMacOS() && RuntimeInformation.ProcessArchitecture == Architecture.Arm64;
public bool FolderModeChanged;
public bool DirectoryChanged
{
get => _directoryChanged;
@ -132,6 +133,7 @@ namespace Ryujinx.Ava.UI.ViewModels
public bool EnableDiscordIntegration { get; set; }
public bool CheckUpdatesOnStart { get; set; }
public bool ShowConfirmExit { get; set; }
public bool UseSystemGameFolders { get; set; }
public int HideCursor { get; set; }
public bool EnableDockedMode { get; set; }
public bool EnableKeyboard { get; set; }
@ -400,6 +402,7 @@ namespace Ryujinx.Ava.UI.ViewModels
EnableDiscordIntegration = config.EnableDiscordIntegration;
CheckUpdatesOnStart = config.CheckUpdatesOnStart;
ShowConfirmExit = config.ShowConfirmExit;
UseSystemGameFolders = config.UI.UseSystemGameFolders;
HideCursor = (int)config.HideCursor.Value;
GameDirectories.Clear();
@ -492,6 +495,12 @@ namespace Ryujinx.Ava.UI.ViewModels
config.UI.GameDirs.Value = gameDirs;
}
if (UseSystemGameFolders != config.UI.UseSystemGameFolders.Value)
{
FolderModeChanged = true;
}
config.UI.UseSystemGameFolders.Value = UseSystemGameFolders;
config.UI.BaseStyle.Value = BaseStyleIndex == 0 ? "Light" : "Dark";
// Input
@ -582,6 +591,7 @@ namespace Ryujinx.Ava.UI.ViewModels
SaveSettingsEvent?.Invoke();
_directoryChanged = false;
FolderModeChanged = false;
}
private static void RevertIfNotSaved()

View file

@ -18,6 +18,16 @@
Margin="0,0,0,5"
Height="35"
HorizontalAlignment="Stretch">
<Button
Width="80"
MinWidth="80"
Margin="5,2,0,2"
VerticalAlignment="Stretch"
Command="{Binding NavigateBack}"
IsVisible="{Binding FoldersEnabled}"
IsEnabled="{Binding IsInFolder}">
<ui:SymbolIcon Symbol="Back" />
</Button>
<Button
Width="40"
MinWidth="40"

View file

@ -36,6 +36,9 @@
<CheckBox IsChecked="{Binding ShowConfirmExit}">
<TextBlock Text="{locale:Locale SettingsTabGeneralShowConfirmExitDialog}" />
</CheckBox>
<CheckBox IsChecked="{Binding UseSystemGameFolders}">
<TextBlock Text="{locale:Locale SettingsTabGeneralUseSystemGameFolders}" />
</CheckBox>
<StackPanel Margin="0, 15, 0, 0" Orientation="Horizontal">
<TextBlock VerticalAlignment="Center"
Text="{locale:Locale SettingsTabGeneralHideCursor}"

View file

@ -23,6 +23,7 @@ using Ryujinx.UI.Common;
using Ryujinx.UI.Common.Configuration;
using Ryujinx.UI.Common.Helper;
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Versioning;
using System.Threading;
@ -34,8 +35,6 @@ namespace Ryujinx.Ava.UI.Windows
{
internal static MainWindowViewModel MainWindowViewModel { get; private set; }
private bool _isLoading;
private UserChannelPersistence _userChannelPersistence;
private static bool _deferLoad;
private static string _launchPath;
@ -137,6 +136,11 @@ namespace Ryujinx.Ava.UI.Windows
{
if (args.Application != null)
{
if (args.Application.FileExtension == "Folder")
{
ViewModel.OpenFolder(args.Application.Path);
return;
}
ViewModel.SelectedIcon = args.Application.Icon;
string path = new FileInfo(args.Application.Path).FullName;
@ -528,24 +532,22 @@ namespace Ryujinx.Ava.UI.Windows
private void ReloadGameList()
{
if (_isLoading)
if (ViewModel.IsInFolder && !ConfigurationState.Instance.UI.UseSystemGameFolders)
{
return;
ViewModel.PathHistory.Clear();
ViewModel.IsInFolder = false;
}
_isLoading = true;
Thread applicationLibraryThread = new(() =>
if (ViewModel.IsInFolder)
{
List<string> SearchPaths = new();
SearchPaths.Add(ViewModel.PathHistory.Peek());
ApplicationLibrary.LoadApplications(SearchPaths, ConfigurationState.Instance.System.Language);
}
else
{
ApplicationLibrary.LoadApplications(ConfigurationState.Instance.UI.GameDirs, ConfigurationState.Instance.System.Language);
_isLoading = false;
})
{
Name = "GUI.ApplicationLibraryThread",
IsBackground = true,
};
applicationLibraryThread.Start();
}
}
}
}

View file

@ -39,9 +39,18 @@ namespace Ryujinx.Ava.UI.Windows
{
InputPage.ControllerSettings?.SaveCurrentProfile();
if (Owner is MainWindow window && ViewModel.DirectoryChanged)
if (Owner is MainWindow window)
{
window.LoadApplications();
if (ViewModel.DirectoryChanged)
{
window.LoadApplications();
}
if (ViewModel.FolderModeChanged)
{
window.LoadApplications();
window.ViewModel.FoldersEnabled = ViewModel.UseSystemGameFolders;
}
}
}