ava: Rework DLC Manager, Add various fixes and cleanup (#3896)
* Fixes Everything Part.2 * Change sorting, fix remove and heading
This commit is contained in:
parent
7aa6abc120
commit
3fbacd0f49
10 changed files with 411 additions and 339 deletions
|
@ -410,6 +410,8 @@
|
||||||
"DlcManagerTableHeadingContainerPathLabel": "Container Path",
|
"DlcManagerTableHeadingContainerPathLabel": "Container Path",
|
||||||
"DlcManagerTableHeadingFullPathLabel": "Full Path",
|
"DlcManagerTableHeadingFullPathLabel": "Full Path",
|
||||||
"DlcManagerRemoveAllButton": "Remove All",
|
"DlcManagerRemoveAllButton": "Remove All",
|
||||||
|
"DlcManagerEnableAllButton": "Enable All",
|
||||||
|
"DlcManagerDisableAllButton": "Disable All",
|
||||||
"MenuBarOptionsChangeLanguage": "Change Language",
|
"MenuBarOptionsChangeLanguage": "Change Language",
|
||||||
"CommonSort": "Sort",
|
"CommonSort": "Sort",
|
||||||
"CommonShowNames": "Show Names",
|
"CommonShowNames": "Show Names",
|
||||||
|
@ -567,7 +569,7 @@
|
||||||
"DlcWindowTitle": "Manage Game DLC",
|
"DlcWindowTitle": "Manage Game DLC",
|
||||||
"UpdateWindowTitle": "Manage Game Updates",
|
"UpdateWindowTitle": "Manage Game Updates",
|
||||||
"CheatWindowHeading": "Cheats Available for {0} [{1}]",
|
"CheatWindowHeading": "Cheats Available for {0} [{1}]",
|
||||||
"DlcWindowHeading": "DLC Available for {0} [{1}]",
|
"DlcWindowHeading": "{0} Downloadable Content(s) available for {1} ({2})",
|
||||||
"UserProfilesEditProfile": "Edit Selected",
|
"UserProfilesEditProfile": "Edit Selected",
|
||||||
"Cancel": "Cancel",
|
"Cancel": "Cancel",
|
||||||
"Save": "Save",
|
"Save": "Save",
|
||||||
|
|
|
@ -28,7 +28,6 @@ namespace Ryujinx.Ava
|
||||||
public static string Version { get; private set; }
|
public static string Version { get; private set; }
|
||||||
public static string ConfigurationPath { get; private set; }
|
public static string ConfigurationPath { get; private set; }
|
||||||
public static bool PreviewerDetached { get; private set; }
|
public static bool PreviewerDetached { get; private set; }
|
||||||
|
|
||||||
public static RenderTimer RenderTimer { get; private set; }
|
public static RenderTimer RenderTimer { get; private set; }
|
||||||
|
|
||||||
[DllImport("user32.dll", SetLastError = true)]
|
[DllImport("user32.dll", SetLastError = true)]
|
||||||
|
@ -43,7 +42,7 @@ namespace Ryujinx.Ava
|
||||||
|
|
||||||
if (OperatingSystem.IsWindows() && !OperatingSystem.IsWindowsVersionAtLeast(10, 0, 17134))
|
if (OperatingSystem.IsWindows() && !OperatingSystem.IsWindowsVersionAtLeast(10, 0, 17134))
|
||||||
{
|
{
|
||||||
MessageBoxA(IntPtr.Zero, "You are running an outdated version of Windows.\n\nStarting on June 1st 2022, Ryujinx will only support Windows 10 1803 and newer.\n", $"Ryujinx {Version}", MB_ICONWARNING);
|
_ = MessageBoxA(IntPtr.Zero, "You are running an outdated version of Windows.\n\nStarting on June 1st 2022, Ryujinx will only support Windows 10 1803 and newer.\n", $"Ryujinx {Version}", MB_ICONWARNING);
|
||||||
}
|
}
|
||||||
|
|
||||||
PreviewerDetached = true;
|
PreviewerDetached = true;
|
||||||
|
@ -73,7 +72,7 @@ namespace Ryujinx.Ava
|
||||||
EnableMultitouch = true,
|
EnableMultitouch = true,
|
||||||
UseWgl = false,
|
UseWgl = false,
|
||||||
AllowEglInitialization = false,
|
AllowEglInitialization = false,
|
||||||
CompositionBackdropCornerRadius = 8f,
|
CompositionBackdropCornerRadius = 8.0f,
|
||||||
})
|
})
|
||||||
.UseSkia()
|
.UseSkia()
|
||||||
.AfterSetup(_ =>
|
.AfterSetup(_ =>
|
||||||
|
@ -122,12 +121,10 @@ namespace Ryujinx.Ava
|
||||||
PrintSystemInfo();
|
PrintSystemInfo();
|
||||||
|
|
||||||
// Enable OGL multithreading on the driver, when available.
|
// Enable OGL multithreading on the driver, when available.
|
||||||
BackendThreading threadingMode = ConfigurationState.Instance.Graphics.BackendThreading;
|
DriverUtilities.ToggleOGLThreading(ConfigurationState.Instance.Graphics.BackendThreading == BackendThreading.Off);
|
||||||
DriverUtilities.ToggleOGLThreading(threadingMode == BackendThreading.Off);
|
|
||||||
|
|
||||||
// Check if keys exists.
|
// Check if keys exists.
|
||||||
bool hasSystemProdKeys = File.Exists(Path.Combine(AppDataManager.KeysDirPath, "prod.keys"));
|
if (!File.Exists(Path.Combine(AppDataManager.KeysDirPath, "prod.keys")))
|
||||||
if (!hasSystemProdKeys)
|
|
||||||
{
|
{
|
||||||
if (!(AppDataManager.Mode == AppDataManager.LaunchMode.UserProfile && File.Exists(Path.Combine(AppDataManager.KeysDirPathUser, "prod.keys"))))
|
if (!(AppDataManager.Mode == AppDataManager.LaunchMode.UserProfile && File.Exists(Path.Combine(AppDataManager.KeysDirPathUser, "prod.keys"))))
|
||||||
{
|
{
|
||||||
|
@ -197,8 +194,7 @@ namespace Ryujinx.Ava
|
||||||
Logger.Notice.Print(LogClass.Application, $"Ryujinx Version: {Version}");
|
Logger.Notice.Print(LogClass.Application, $"Ryujinx Version: {Version}");
|
||||||
SystemInfo.Gather().Print();
|
SystemInfo.Gather().Print();
|
||||||
|
|
||||||
var enabledLogs = Logger.GetEnabledLevels();
|
Logger.Notice.Print(LogClass.Application, $"Logs Enabled: {(Logger.GetEnabledLevels().Count == 0 ? "<None>" : string.Join(", ", Logger.GetEnabledLevels()))}");
|
||||||
Logger.Notice.Print(LogClass.Application, $"Logs Enabled: {(enabledLogs.Count == 0 ? "<None>" : string.Join(", ", enabledLogs))}");
|
|
||||||
|
|
||||||
if (AppDataManager.Mode == AppDataManager.LaunchMode.Custom)
|
if (AppDataManager.Mode == AppDataManager.LaunchMode.Custom)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,8 +1,22 @@
|
||||||
namespace Ryujinx.Ava.Ui.Models
|
using Ryujinx.Ava.Ui.ViewModels;
|
||||||
|
|
||||||
|
namespace Ryujinx.Ava.Ui.Models
|
||||||
{
|
{
|
||||||
public class DownloadableContentModel
|
public class DownloadableContentModel : BaseModel
|
||||||
{
|
{
|
||||||
public bool Enabled { get; set; }
|
private bool _enabled;
|
||||||
|
|
||||||
|
public bool Enabled
|
||||||
|
{
|
||||||
|
get => _enabled;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_enabled = value;
|
||||||
|
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public string TitleId { get; }
|
public string TitleId { get; }
|
||||||
public string ContainerPath { get; }
|
public string ContainerPath { get; }
|
||||||
public string FullPath { get; }
|
public string FullPath { get; }
|
||||||
|
|
|
@ -19,6 +19,7 @@ using Ryujinx.Common.Configuration;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.HLE;
|
using Ryujinx.HLE;
|
||||||
using Ryujinx.HLE.FileSystem;
|
using Ryujinx.HLE.FileSystem;
|
||||||
|
using Ryujinx.HLE.HOS;
|
||||||
using Ryujinx.Modules;
|
using Ryujinx.Modules;
|
||||||
using Ryujinx.Ui.App.Common;
|
using Ryujinx.Ui.App.Common;
|
||||||
using Ryujinx.Ui.Common;
|
using Ryujinx.Ui.Common;
|
||||||
|
@ -47,6 +48,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||||
private string _loadHeading;
|
private string _loadHeading;
|
||||||
private string _cacheLoadStatus;
|
private string _cacheLoadStatus;
|
||||||
private string _searchText;
|
private string _searchText;
|
||||||
|
private Timer _searchTimer;
|
||||||
private string _dockedStatusText;
|
private string _dockedStatusText;
|
||||||
private string _fifoStatusText;
|
private string _fifoStatusText;
|
||||||
private string _gameStatusText;
|
private string _gameStatusText;
|
||||||
|
@ -115,10 +117,20 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||||
{
|
{
|
||||||
_searchText = value;
|
_searchText = value;
|
||||||
|
|
||||||
RefreshView();
|
_searchTimer?.Dispose();
|
||||||
|
|
||||||
|
_searchTimer = new Timer(TimerCallback, null, 1000, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void TimerCallback(object obj)
|
||||||
|
{
|
||||||
|
RefreshView();
|
||||||
|
|
||||||
|
_searchTimer.Dispose();
|
||||||
|
_searchTimer = null;
|
||||||
|
}
|
||||||
|
|
||||||
public ReadOnlyObservableCollection<ApplicationData> AppsObservableList
|
public ReadOnlyObservableCollection<ApplicationData> AppsObservableList
|
||||||
{
|
{
|
||||||
get => _appsObservableList;
|
get => _appsObservableList;
|
||||||
|
@ -207,15 +219,12 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
switch (Glyph)
|
return Glyph switch
|
||||||
{
|
{
|
||||||
case Glyph.List:
|
Glyph.List => _owner.GameList.SelectedApplication,
|
||||||
return _owner.GameList.SelectedApplication;
|
Glyph.Grid => _owner.GameGrid.SelectedApplication,
|
||||||
case Glyph.Grid:
|
_ => null,
|
||||||
return _owner.GameGrid.SelectedApplication;
|
};
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -408,6 +417,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||||
{
|
{
|
||||||
_owner.AppHost.Device.SetVolume(_volume);
|
_owner.AppHost.Device.SetVolume(_volume);
|
||||||
}
|
}
|
||||||
|
|
||||||
OnPropertyChanged(nameof(VolumeStatusText));
|
OnPropertyChanged(nameof(VolumeStatusText));
|
||||||
OnPropertyChanged(nameof(VolumeMuted));
|
OnPropertyChanged(nameof(VolumeMuted));
|
||||||
OnPropertyChanged();
|
OnPropertyChanged();
|
||||||
|
@ -477,38 +487,36 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||||
internal void Sort(bool isAscending)
|
internal void Sort(bool isAscending)
|
||||||
{
|
{
|
||||||
IsAscending = isAscending;
|
IsAscending = isAscending;
|
||||||
|
|
||||||
RefreshView();
|
RefreshView();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Sort(ApplicationSort sort)
|
internal void Sort(ApplicationSort sort)
|
||||||
{
|
{
|
||||||
SortMode = sort;
|
SortMode = sort;
|
||||||
|
|
||||||
RefreshView();
|
RefreshView();
|
||||||
}
|
}
|
||||||
|
|
||||||
private IComparer<ApplicationData> GetComparer()
|
private IComparer<ApplicationData> GetComparer()
|
||||||
{
|
{
|
||||||
switch (SortMode)
|
return SortMode switch
|
||||||
{
|
{
|
||||||
case ApplicationSort.LastPlayed:
|
ApplicationSort.LastPlayed => new Models.Generic.LastPlayedSortComparer(IsAscending),
|
||||||
return new Models.Generic.LastPlayedSortComparer(IsAscending);
|
ApplicationSort.FileSize => new Models.Generic.FileSizeSortComparer(IsAscending),
|
||||||
case ApplicationSort.FileSize:
|
ApplicationSort.TotalTimePlayed => new Models.Generic.TimePlayedSortComparer(IsAscending),
|
||||||
return new Models.Generic.FileSizeSortComparer(IsAscending);
|
ApplicationSort.Title => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.TitleName)
|
||||||
case ApplicationSort.TotalTimePlayed:
|
: SortExpressionComparer<ApplicationData>.Descending(app => app.TitleName),
|
||||||
return new Models.Generic.TimePlayedSortComparer(IsAscending);
|
ApplicationSort.Favorite => !IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.Favorite)
|
||||||
case ApplicationSort.Title:
|
: SortExpressionComparer<ApplicationData>.Descending(app => app.Favorite),
|
||||||
return IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.TitleName) : SortExpressionComparer<ApplicationData>.Descending(app => app.TitleName);
|
ApplicationSort.Developer => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.Developer)
|
||||||
case ApplicationSort.Favorite:
|
: SortExpressionComparer<ApplicationData>.Descending(app => app.Developer),
|
||||||
return !IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.Favorite) : SortExpressionComparer<ApplicationData>.Descending(app => app.Favorite);
|
ApplicationSort.FileType => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.FileExtension)
|
||||||
case ApplicationSort.Developer:
|
: SortExpressionComparer<ApplicationData>.Descending(app => app.FileExtension),
|
||||||
return IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.Developer) : SortExpressionComparer<ApplicationData>.Descending(app => app.Developer);
|
ApplicationSort.Path => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.Path)
|
||||||
case ApplicationSort.FileType:
|
: SortExpressionComparer<ApplicationData>.Descending(app => app.Path),
|
||||||
return IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.FileExtension) : SortExpressionComparer<ApplicationData>.Descending(app => app.FileExtension);
|
_ => null,
|
||||||
case ApplicationSort.Path:
|
};
|
||||||
return IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.Path) : SortExpressionComparer<ApplicationData>.Descending(app => app.Path);
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RefreshView()
|
private void RefreshView()
|
||||||
|
@ -624,27 +632,18 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
switch (SortMode)
|
return SortMode switch
|
||||||
{
|
{
|
||||||
case ApplicationSort.Title:
|
ApplicationSort.Title => LocaleManager.Instance["GameListHeaderApplication"],
|
||||||
return LocaleManager.Instance["GameListHeaderApplication"];
|
ApplicationSort.Developer => LocaleManager.Instance["GameListHeaderDeveloper"],
|
||||||
case ApplicationSort.Developer:
|
ApplicationSort.LastPlayed => LocaleManager.Instance["GameListHeaderLastPlayed"],
|
||||||
return LocaleManager.Instance["GameListHeaderDeveloper"];
|
ApplicationSort.TotalTimePlayed => LocaleManager.Instance["GameListHeaderTimePlayed"],
|
||||||
case ApplicationSort.LastPlayed:
|
ApplicationSort.FileType => LocaleManager.Instance["GameListHeaderFileExtension"],
|
||||||
return LocaleManager.Instance["GameListHeaderLastPlayed"];
|
ApplicationSort.FileSize => LocaleManager.Instance["GameListHeaderFileSize"],
|
||||||
case ApplicationSort.TotalTimePlayed:
|
ApplicationSort.Path => LocaleManager.Instance["GameListHeaderPath"],
|
||||||
return LocaleManager.Instance["GameListHeaderTimePlayed"];
|
ApplicationSort.Favorite => LocaleManager.Instance["CommonFavorite"],
|
||||||
case ApplicationSort.FileType:
|
_ => string.Empty,
|
||||||
return LocaleManager.Instance["GameListHeaderFileExtension"];
|
};
|
||||||
case ApplicationSort.FileSize:
|
|
||||||
return LocaleManager.Instance["GameListHeaderFileSize"];
|
|
||||||
case ApplicationSort.Path:
|
|
||||||
return LocaleManager.Instance["GameListHeaderPath"];
|
|
||||||
case ApplicationSort.Favorite:
|
|
||||||
return LocaleManager.Instance["CommonFavorite"];
|
|
||||||
}
|
|
||||||
|
|
||||||
return string.Empty;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -668,6 +667,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||||
get => KeyGesture.Parse(_showUikey); set
|
get => KeyGesture.Parse(_showUikey); set
|
||||||
{
|
{
|
||||||
_showUikey = value.ToString();
|
_showUikey = value.ToString();
|
||||||
|
|
||||||
OnPropertyChanged();
|
OnPropertyChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -677,6 +677,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||||
get => KeyGesture.Parse(_screenshotkey); set
|
get => KeyGesture.Parse(_screenshotkey); set
|
||||||
{
|
{
|
||||||
_screenshotkey = value.ToString();
|
_screenshotkey = value.ToString();
|
||||||
|
|
||||||
OnPropertyChanged();
|
OnPropertyChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -686,6 +687,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||||
get => KeyGesture.Parse(_pauseKey); set
|
get => KeyGesture.Parse(_pauseKey); set
|
||||||
{
|
{
|
||||||
_pauseKey = value.ToString();
|
_pauseKey = value.ToString();
|
||||||
|
|
||||||
OnPropertyChanged();
|
OnPropertyChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -768,6 +770,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||||
{
|
{
|
||||||
StatusBarProgressValue = e.NumAppsLoaded;
|
StatusBarProgressValue = e.NumAppsLoaded;
|
||||||
StatusBarProgressMaximum = e.NumAppsFound;
|
StatusBarProgressMaximum = e.NumAppsFound;
|
||||||
|
|
||||||
LocaleManager.Instance.UpdateDynamicValue("StatusBarGamesLoaded", StatusBarProgressValue, StatusBarProgressMaximum);
|
LocaleManager.Instance.UpdateDynamicValue("StatusBarGamesLoaded", StatusBarProgressValue, StatusBarProgressMaximum);
|
||||||
|
|
||||||
Dispatcher.UIThread.Post(() =>
|
Dispatcher.UIThread.Post(() =>
|
||||||
|
@ -792,9 +795,11 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||||
await Dispatcher.UIThread.InvokeAsync(() =>
|
await Dispatcher.UIThread.InvokeAsync(() =>
|
||||||
{
|
{
|
||||||
Applications.Clear();
|
Applications.Clear();
|
||||||
|
|
||||||
_owner.LoadProgressBar.IsVisible = true;
|
_owner.LoadProgressBar.IsVisible = true;
|
||||||
StatusBarProgressMaximum = 0;
|
StatusBarProgressMaximum = 0;
|
||||||
StatusBarProgressValue = 0;
|
StatusBarProgressValue = 0;
|
||||||
|
|
||||||
LocaleManager.Instance.UpdateDynamicValue("StatusBarGamesLoaded", 0, 0);
|
LocaleManager.Instance.UpdateDynamicValue("StatusBarGamesLoaded", 0, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -878,10 +883,12 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||||
{
|
{
|
||||||
ShowUiKey = new KeyGesture(showUiKey, KeyModifiers.None);
|
ShowUiKey = new KeyGesture(showUiKey, KeyModifiers.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AvaloniaMappingHelper.TryGetAvaKey((Ryujinx.Input.Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Screenshot, out var screenshotKey))
|
if (AvaloniaMappingHelper.TryGetAvaKey((Ryujinx.Input.Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Screenshot, out var screenshotKey))
|
||||||
{
|
{
|
||||||
ScreenshotKey = new KeyGesture(screenshotKey, KeyModifiers.None);
|
ScreenshotKey = new KeyGesture(screenshotKey, KeyModifiers.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AvaloniaMappingHelper.TryGetAvaKey((Ryujinx.Input.Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Pause, out var pauseKey))
|
if (AvaloniaMappingHelper.TryGetAvaKey((Ryujinx.Input.Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Pause, out var pauseKey))
|
||||||
{
|
{
|
||||||
PauseKey = new KeyGesture(pauseKey, KeyModifiers.None);
|
PauseKey = new KeyGesture(pauseKey, KeyModifiers.None);
|
||||||
|
@ -941,9 +948,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||||
|
|
||||||
_lastFullscreenToggle = Environment.TickCount64;
|
_lastFullscreenToggle = Environment.TickCount64;
|
||||||
|
|
||||||
WindowState state = _owner.WindowState;
|
if (_owner.WindowState == WindowState.FullScreen)
|
||||||
|
|
||||||
if (state == WindowState.FullScreen)
|
|
||||||
{
|
{
|
||||||
_owner.WindowState = WindowState.Normal;
|
_owner.WindowState = WindowState.Normal;
|
||||||
|
|
||||||
|
@ -971,8 +976,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||||
{
|
{
|
||||||
if (IsGameRunning)
|
if (IsGameRunning)
|
||||||
{
|
{
|
||||||
ConfigurationState.Instance.System.EnableDockedMode.Value =
|
ConfigurationState.Instance.System.EnableDockedMode.Value = !ConfigurationState.Instance.System.EnableDockedMode.Value;
|
||||||
!ConfigurationState.Instance.System.EnableDockedMode.Value;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -985,6 +989,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||||
else if (IsGameRunning)
|
else if (IsGameRunning)
|
||||||
{
|
{
|
||||||
await Task.Delay(100);
|
await Task.Delay(100);
|
||||||
|
|
||||||
_owner.AppHost?.ShowExitPrompt();
|
_owner.AppHost?.ShowExitPrompt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -994,6 +999,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||||
_owner.SettingsWindow = new(_owner.VirtualFileSystem, _owner.ContentManager);
|
_owner.SettingsWindow = new(_owner.VirtualFileSystem, _owner.ContentManager);
|
||||||
|
|
||||||
await _owner.SettingsWindow.ShowDialog(_owner);
|
await _owner.SettingsWindow.ShowDialog(_owner);
|
||||||
|
|
||||||
LoadConfigurableHotKeys();
|
LoadConfigurableHotKeys();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1004,9 +1010,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||||
|
|
||||||
public async void OpenAboutWindow()
|
public async void OpenAboutWindow()
|
||||||
{
|
{
|
||||||
AboutWindow window = new();
|
await new AboutWindow().ShowDialog(_owner);
|
||||||
|
|
||||||
await window.ShowDialog(_owner);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ChangeLanguage(object obj)
|
public void ChangeLanguage(object obj)
|
||||||
|
@ -1065,14 +1069,12 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||||
|
|
||||||
public void OpenUserSaveDirectory()
|
public void OpenUserSaveDirectory()
|
||||||
{
|
{
|
||||||
var selection = SelectedApplication;
|
ApplicationData selection = SelectedApplication;
|
||||||
|
|
||||||
if (selection != null)
|
if (selection != null)
|
||||||
{
|
{
|
||||||
Task.Run(() =>
|
Task.Run(() =>
|
||||||
{
|
{
|
||||||
if (!ulong.TryParse(selection.TitleId, NumberStyles.HexNumber, CultureInfo.InvariantCulture,
|
if (!ulong.TryParse(selection.TitleId, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out ulong titleIdNumber))
|
||||||
out ulong titleIdNumber))
|
|
||||||
{
|
{
|
||||||
Dispatcher.UIThread.Post(async () =>
|
Dispatcher.UIThread.Post(async () =>
|
||||||
{
|
{
|
||||||
|
@ -1082,8 +1084,8 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var userId = new LibHac.Fs.UserId((ulong)_owner.AccountManager.LastOpenedUser.UserId.High, (ulong)_owner.AccountManager.LastOpenedUser.UserId.Low);
|
UserId userId = new((ulong)_owner.AccountManager.LastOpenedUser.UserId.High, (ulong)_owner.AccountManager.LastOpenedUser.UserId.Low);
|
||||||
var saveDataFilter = SaveDataFilter.Make(titleIdNumber, saveType: default, userId, saveDataId: default, index: default);
|
SaveDataFilter saveDataFilter = SaveDataFilter.Make(titleIdNumber, saveType: default, userId, saveDataId: default, index: default);
|
||||||
OpenSaveDirectory(in saveDataFilter, selection, titleIdNumber);
|
OpenSaveDirectory(in saveDataFilter, selection, titleIdNumber);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1091,8 +1093,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||||
|
|
||||||
public void ToggleFavorite()
|
public void ToggleFavorite()
|
||||||
{
|
{
|
||||||
var selection = SelectedApplication;
|
ApplicationData selection = SelectedApplication;
|
||||||
|
|
||||||
if (selection != null)
|
if (selection != null)
|
||||||
{
|
{
|
||||||
selection.Favorite = !selection.Favorite;
|
selection.Favorite = !selection.Favorite;
|
||||||
|
@ -1108,8 +1109,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||||
|
|
||||||
public void OpenModsDirectory()
|
public void OpenModsDirectory()
|
||||||
{
|
{
|
||||||
var selection = SelectedApplication;
|
ApplicationData selection = SelectedApplication;
|
||||||
|
|
||||||
if (selection != null)
|
if (selection != null)
|
||||||
{
|
{
|
||||||
string modsBasePath = _owner.VirtualFileSystem.ModLoader.GetModsBasePath();
|
string modsBasePath = _owner.VirtualFileSystem.ModLoader.GetModsBasePath();
|
||||||
|
@ -1121,7 +1121,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||||
|
|
||||||
public void OpenSdModsDirectory()
|
public void OpenSdModsDirectory()
|
||||||
{
|
{
|
||||||
var selection = SelectedApplication;
|
ApplicationData selection = SelectedApplication;
|
||||||
|
|
||||||
if (selection != null)
|
if (selection != null)
|
||||||
{
|
{
|
||||||
|
@ -1134,12 +1134,10 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||||
|
|
||||||
public void OpenPtcDirectory()
|
public void OpenPtcDirectory()
|
||||||
{
|
{
|
||||||
var selection = SelectedApplication;
|
ApplicationData selection = SelectedApplication;
|
||||||
|
|
||||||
if (selection != null)
|
if (selection != null)
|
||||||
{
|
{
|
||||||
string ptcDir = Path.Combine(AppDataManager.GamesDirPath, selection.TitleId, "cache", "cpu");
|
string ptcDir = Path.Combine(AppDataManager.GamesDirPath, selection.TitleId, "cache", "cpu");
|
||||||
|
|
||||||
string mainPath = Path.Combine(ptcDir, "0");
|
string mainPath = Path.Combine(ptcDir, "0");
|
||||||
string backupPath = Path.Combine(ptcDir, "1");
|
string backupPath = Path.Combine(ptcDir, "1");
|
||||||
|
|
||||||
|
@ -1156,8 +1154,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||||
|
|
||||||
public async void PurgePtcCache()
|
public async void PurgePtcCache()
|
||||||
{
|
{
|
||||||
var selection = SelectedApplication;
|
ApplicationData selection = SelectedApplication;
|
||||||
|
|
||||||
if (selection != null)
|
if (selection != null)
|
||||||
{
|
{
|
||||||
DirectoryInfo mainDir = new(Path.Combine(AppDataManager.GamesDirPath, selection.TitleId, "cache", "cpu", "0"));
|
DirectoryInfo mainDir = new(Path.Combine(AppDataManager.GamesDirPath, selection.TitleId, "cache", "cpu", "0"));
|
||||||
|
@ -1165,7 +1162,10 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||||
|
|
||||||
// FIXME: Found a way to reproduce the bold effect on the title name (fork?).
|
// FIXME: Found a way to reproduce the bold effect on the title name (fork?).
|
||||||
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance["DialogWarning"],
|
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance["DialogWarning"],
|
||||||
string.Format(LocaleManager.Instance["DialogPPTCDeletionMessage"], selection.TitleName), LocaleManager.Instance["InputDialogYes"], LocaleManager.Instance["InputDialogNo"], LocaleManager.Instance["RyujinxConfirm"]);
|
string.Format(LocaleManager.Instance["DialogPPTCDeletionMessage"], selection.TitleName),
|
||||||
|
LocaleManager.Instance["InputDialogYes"],
|
||||||
|
LocaleManager.Instance["InputDialogNo"],
|
||||||
|
LocaleManager.Instance["RyujinxConfirm"]);
|
||||||
|
|
||||||
List<FileInfo> cacheFiles = new();
|
List<FileInfo> cacheFiles = new();
|
||||||
|
|
||||||
|
@ -1198,8 +1198,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||||
|
|
||||||
public void OpenShaderCacheDirectory()
|
public void OpenShaderCacheDirectory()
|
||||||
{
|
{
|
||||||
var selection = SelectedApplication;
|
ApplicationData selection = SelectedApplication;
|
||||||
|
|
||||||
if (selection != null)
|
if (selection != null)
|
||||||
{
|
{
|
||||||
string shaderCacheDir = Path.Combine(AppDataManager.GamesDirPath, selection.TitleId, "cache", "shader");
|
string shaderCacheDir = Path.Combine(AppDataManager.GamesDirPath, selection.TitleId, "cache", "shader");
|
||||||
|
@ -1220,18 +1219,20 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||||
|
|
||||||
public async void PurgeShaderCache()
|
public async void PurgeShaderCache()
|
||||||
{
|
{
|
||||||
var selection = SelectedApplication;
|
ApplicationData selection = SelectedApplication;
|
||||||
|
|
||||||
if (selection != null)
|
if (selection != null)
|
||||||
{
|
{
|
||||||
DirectoryInfo shaderCacheDir = new(Path.Combine(AppDataManager.GamesDirPath, selection.TitleId, "cache", "shader"));
|
DirectoryInfo shaderCacheDir = new(Path.Combine(AppDataManager.GamesDirPath, selection.TitleId, "cache", "shader"));
|
||||||
|
|
||||||
// FIXME: Found a way to reproduce the bold effect on the title name (fork?).
|
// FIXME: Found a way to reproduce the bold effect on the title name (fork?).
|
||||||
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance["DialogWarning"],
|
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance["DialogWarning"],
|
||||||
string.Format(LocaleManager.Instance["DialogShaderDeletionMessage"], selection.TitleName), LocaleManager.Instance["InputDialogYes"], LocaleManager.Instance["InputDialogNo"], LocaleManager.Instance["RyujinxConfirm"]);
|
string.Format(LocaleManager.Instance["DialogShaderDeletionMessage"], selection.TitleName),
|
||||||
|
LocaleManager.Instance["InputDialogYes"],
|
||||||
|
LocaleManager.Instance["InputDialogNo"],
|
||||||
|
LocaleManager.Instance["RyujinxConfirm"]);
|
||||||
|
|
||||||
List<DirectoryInfo> oldCacheDirectories = new List<DirectoryInfo>();
|
List<DirectoryInfo> oldCacheDirectories = new();
|
||||||
List<FileInfo> newCacheFiles = new List<FileInfo>();
|
List<FileInfo> newCacheFiles = new();
|
||||||
|
|
||||||
if (shaderCacheDir.Exists)
|
if (shaderCacheDir.Exists)
|
||||||
{
|
{
|
||||||
|
@ -1279,38 +1280,28 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||||
|
|
||||||
public async void OpenTitleUpdateManager()
|
public async void OpenTitleUpdateManager()
|
||||||
{
|
{
|
||||||
var selection = SelectedApplication;
|
ApplicationData selection = SelectedApplication;
|
||||||
|
|
||||||
if (selection != null)
|
if (selection != null)
|
||||||
{
|
{
|
||||||
TitleUpdateWindow titleUpdateManager =
|
await new TitleUpdateWindow(_owner.VirtualFileSystem, selection.TitleId, selection.TitleName).ShowDialog(_owner);
|
||||||
new(_owner.VirtualFileSystem, selection.TitleId, selection.TitleName);
|
|
||||||
|
|
||||||
await titleUpdateManager.ShowDialog(_owner);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void OpenDownloadableContentManager()
|
public async void OpenDownloadableContentManager()
|
||||||
{
|
{
|
||||||
var selection = SelectedApplication;
|
ApplicationData selection = SelectedApplication;
|
||||||
|
|
||||||
if (selection != null)
|
if (selection != null)
|
||||||
{
|
{
|
||||||
DownloadableContentManagerWindow downloadableContentManager = new(_owner.VirtualFileSystem, ulong.Parse(selection.TitleId, NumberStyles.HexNumber), selection.TitleName);
|
await new DownloadableContentManagerWindow(_owner.VirtualFileSystem, ulong.Parse(selection.TitleId, NumberStyles.HexNumber), selection.TitleName).ShowDialog(_owner);
|
||||||
|
|
||||||
await downloadableContentManager.ShowDialog(_owner);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void OpenCheatManager()
|
public async void OpenCheatManager()
|
||||||
{
|
{
|
||||||
var selection = SelectedApplication;
|
ApplicationData selection = SelectedApplication;
|
||||||
|
|
||||||
if (selection != null)
|
if (selection != null)
|
||||||
{
|
{
|
||||||
CheatWindow cheatManager = new(_owner.VirtualFileSystem, selection.TitleId, selection.TitleName);
|
await new CheatWindow(_owner.VirtualFileSystem, selection.TitleId, selection.TitleName).ShowDialog(_owner);
|
||||||
|
|
||||||
await cheatManager.ShowDialog(_owner);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1321,13 +1312,10 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var application = _owner.AppHost.Device.Application;
|
ApplicationLoader application = _owner.AppHost.Device.Application;
|
||||||
|
|
||||||
if (application != null)
|
if (application != null)
|
||||||
{
|
{
|
||||||
CheatWindow cheatManager = new(_owner.VirtualFileSystem, application.TitleIdText, application.TitleName);
|
await new CheatWindow(_owner.VirtualFileSystem, application.TitleIdText, application.TitleName).ShowDialog(_owner);
|
||||||
|
|
||||||
await cheatManager.ShowDialog(_owner);
|
|
||||||
|
|
||||||
_owner.AppHost.Device.EnableCheats();
|
_owner.AppHost.Device.EnableCheats();
|
||||||
}
|
}
|
||||||
|
@ -1335,14 +1323,12 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||||
|
|
||||||
public void OpenDeviceSaveDirectory()
|
public void OpenDeviceSaveDirectory()
|
||||||
{
|
{
|
||||||
var selection = SelectedApplication;
|
ApplicationData selection = SelectedApplication;
|
||||||
|
|
||||||
if (selection != null)
|
if (selection != null)
|
||||||
{
|
{
|
||||||
Task.Run(() =>
|
Task.Run(() =>
|
||||||
{
|
{
|
||||||
if (!ulong.TryParse(selection.TitleId, NumberStyles.HexNumber, CultureInfo.InvariantCulture,
|
if (!ulong.TryParse(selection.TitleId, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out ulong titleIdNumber))
|
||||||
out ulong titleIdNumber))
|
|
||||||
{
|
{
|
||||||
Dispatcher.UIThread.Post(async () =>
|
Dispatcher.UIThread.Post(async () =>
|
||||||
{
|
{
|
||||||
|
@ -1360,14 +1346,12 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||||
|
|
||||||
public void OpenBcatSaveDirectory()
|
public void OpenBcatSaveDirectory()
|
||||||
{
|
{
|
||||||
var selection = SelectedApplication;
|
ApplicationData selection = SelectedApplication;
|
||||||
|
|
||||||
if (selection != null)
|
if (selection != null)
|
||||||
{
|
{
|
||||||
Task.Run(() =>
|
Task.Run(() =>
|
||||||
{
|
{
|
||||||
if (!ulong.TryParse(selection.TitleId, NumberStyles.HexNumber, CultureInfo.InvariantCulture,
|
if (!ulong.TryParse(selection.TitleId, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out ulong titleIdNumber))
|
||||||
out ulong titleIdNumber))
|
|
||||||
{
|
{
|
||||||
Dispatcher.UIThread.Post(async () =>
|
Dispatcher.UIThread.Post(async () =>
|
||||||
{
|
{
|
||||||
|
@ -1420,12 +1404,10 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||||
_owner.Close();
|
_owner.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task HandleFirmwareInstallation(string path)
|
private async Task HandleFirmwareInstallation(string filename)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
string filename = path;
|
|
||||||
|
|
||||||
SystemVersion firmwareVersion = _owner.ContentManager.VerifyFirmwarePackage(filename);
|
SystemVersion firmwareVersion = _owner.ContentManager.VerifyFirmwarePackage(filename);
|
||||||
|
|
||||||
if (firmwareVersion == null)
|
if (firmwareVersion == null)
|
||||||
|
@ -1437,7 +1419,6 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||||
|
|
||||||
string dialogTitle = string.Format(LocaleManager.Instance["DialogFirmwareInstallerFirmwareInstallTitle"], firmwareVersion.VersionString);
|
string dialogTitle = string.Format(LocaleManager.Instance["DialogFirmwareInstallerFirmwareInstallTitle"], firmwareVersion.VersionString);
|
||||||
|
|
||||||
|
|
||||||
SystemVersion currentVersion = _owner.ContentManager.GetCurrentFirmwareVersion();
|
SystemVersion currentVersion = _owner.ContentManager.GetCurrentFirmwareVersion();
|
||||||
|
|
||||||
string dialogMessage = string.Format(LocaleManager.Instance["DialogFirmwareInstallerFirmwareInstallMessage"], firmwareVersion.VersionString);
|
string dialogMessage = string.Format(LocaleManager.Instance["DialogFirmwareInstallerFirmwareInstallMessage"], firmwareVersion.VersionString);
|
||||||
|
@ -1480,11 +1461,12 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||||
string message = string.Format(LocaleManager.Instance["DialogFirmwareInstallerFirmwareInstallSuccessMessage"], firmwareVersion.VersionString);
|
string message = string.Format(LocaleManager.Instance["DialogFirmwareInstallerFirmwareInstallSuccessMessage"], firmwareVersion.VersionString);
|
||||||
|
|
||||||
await ContentDialogHelper.CreateInfoDialog(dialogTitle, message, LocaleManager.Instance["InputDialogOk"], "", LocaleManager.Instance["RyujinxInfo"]);
|
await ContentDialogHelper.CreateInfoDialog(dialogTitle, message, LocaleManager.Instance["InputDialogOk"], "", LocaleManager.Instance["RyujinxInfo"]);
|
||||||
|
|
||||||
Logger.Info?.Print(LogClass.Application, message);
|
Logger.Info?.Print(LogClass.Application, message);
|
||||||
|
|
||||||
// Purge Applet Cache.
|
// Purge Applet Cache.
|
||||||
|
|
||||||
DirectoryInfo miiEditorCacheFolder = new DirectoryInfo(System.IO.Path.Combine(AppDataManager.GamesDirPath, "0100000000001009", "cache"));
|
DirectoryInfo miiEditorCacheFolder = new DirectoryInfo(Path.Combine(AppDataManager.GamesDirPath, "0100000000001009", "cache"));
|
||||||
|
|
||||||
if (miiEditorCacheFolder.Exists)
|
if (miiEditorCacheFolder.Exists)
|
||||||
{
|
{
|
||||||
|
@ -1514,8 +1496,8 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||||
catch (LibHac.Common.Keys.MissingKeyException ex)
|
catch (LibHac.Common.Keys.MissingKeyException ex)
|
||||||
{
|
{
|
||||||
Logger.Error?.Print(LogClass.Application, ex.ToString());
|
Logger.Error?.Print(LogClass.Application, ex.ToString());
|
||||||
Dispatcher.UIThread.Post(async () => await
|
|
||||||
UserErrorDialog.ShowUserErrorDialog(UserError.NoKeys, _owner));
|
Dispatcher.UIThread.Post(async () => await UserErrorDialog.ShowUserErrorDialog(UserError.NoKeys, _owner));
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,45 +3,90 @@
|
||||||
xmlns="https://github.com/avaloniaui"
|
xmlns="https://github.com/avaloniaui"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
|
||||||
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows"
|
xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows"
|
||||||
SizeToContent="Height"
|
Width="800"
|
||||||
Width="600" MinHeight="500" Height="500"
|
Height="500"
|
||||||
WindowStartupLocation="CenterOwner"
|
|
||||||
MinWidth="600"
|
MinWidth="600"
|
||||||
|
MinHeight="500"
|
||||||
|
SizeToContent="Height"
|
||||||
|
WindowStartupLocation="CenterOwner"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
<Grid Name="DownloadableContentGrid" Margin="15">
|
<Grid Name="DownloadableContentGrid" Margin="15">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<TextBlock
|
<TextBlock
|
||||||
|
Name="Heading"
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
|
MaxWidth="500"
|
||||||
Margin="20,15,20,20"
|
Margin="20,15,20,20"
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
MaxWidth="500"
|
|
||||||
LineHeight="18"
|
LineHeight="18"
|
||||||
TextWrapping="Wrap"
|
TextAlignment="Center"
|
||||||
Text="{Binding Heading}"
|
TextWrapping="Wrap" />
|
||||||
TextAlignment="Center" />
|
<DockPanel
|
||||||
<Border
|
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
|
Margin="0"
|
||||||
|
HorizontalAlignment="Left">
|
||||||
|
<Button
|
||||||
|
Name="EnableAllButton"
|
||||||
|
MinWidth="90"
|
||||||
|
Margin="5"
|
||||||
|
Command="{Binding EnableAll}">
|
||||||
|
<TextBlock Text="{locale:Locale DlcManagerEnableAllButton}" />
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
Name="DisableAllButton"
|
||||||
|
MinWidth="90"
|
||||||
|
Margin="5"
|
||||||
|
Command="{Binding DisableAll}">
|
||||||
|
<TextBlock Text="{locale:Locale DlcManagerDisableAllButton}" />
|
||||||
|
</Button>
|
||||||
|
</DockPanel>
|
||||||
|
<Border
|
||||||
|
Grid.Row="3"
|
||||||
Margin="5"
|
Margin="5"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
VerticalAlignment="Stretch"
|
VerticalAlignment="Stretch"
|
||||||
BorderBrush="Gray"
|
BorderBrush="Gray"
|
||||||
BorderThickness="1">
|
BorderThickness="1">
|
||||||
|
<ScrollViewer
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
|
HorizontalScrollBarVisibility="Auto"
|
||||||
|
VerticalScrollBarVisibility="Auto">
|
||||||
<DataGrid
|
<DataGrid
|
||||||
|
Name="DlcDataGrid"
|
||||||
MinHeight="200"
|
MinHeight="200"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
VerticalAlignment="Stretch"
|
VerticalAlignment="Stretch"
|
||||||
|
CanUserReorderColumns="False"
|
||||||
|
CanUserResizeColumns="True"
|
||||||
|
CanUserSortColumns="True"
|
||||||
HorizontalScrollBarVisibility="Auto"
|
HorizontalScrollBarVisibility="Auto"
|
||||||
Items="{Binding DownloadableContents}"
|
Items="{Binding _downloadableContents}"
|
||||||
|
SelectionMode="Extended"
|
||||||
VerticalScrollBarVisibility="Auto">
|
VerticalScrollBarVisibility="Auto">
|
||||||
|
<DataGrid.Styles>
|
||||||
|
<Styles>
|
||||||
|
<Style Selector="DataGridCell:nth-child(3), DataGridCell:nth-child(4)">
|
||||||
|
<Setter Property="HorizontalAlignment" Value="Left" />
|
||||||
|
<Setter Property="HorizontalContentAlignment" Value="Left" />
|
||||||
|
</Style>
|
||||||
|
</Styles>
|
||||||
|
<Styles>
|
||||||
|
<Style Selector="DataGridCell:nth-child(1)">
|
||||||
|
<Setter Property="HorizontalAlignment" Value="Right" />
|
||||||
|
<Setter Property="HorizontalContentAlignment" Value="Right" />
|
||||||
|
</Style>
|
||||||
|
</Styles>
|
||||||
|
</DataGrid.Styles>
|
||||||
<DataGrid.Columns>
|
<DataGrid.Columns>
|
||||||
<DataGridTemplateColumn Width="90">
|
<DataGridTemplateColumn Width="90">
|
||||||
<DataGridTemplateColumn.CellTemplate>
|
<DataGridTemplateColumn.CellTemplate>
|
||||||
|
@ -49,7 +94,7 @@
|
||||||
<CheckBox
|
<CheckBox
|
||||||
Width="50"
|
Width="50"
|
||||||
MinWidth="40"
|
MinWidth="40"
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Center"
|
||||||
IsChecked="{Binding Enabled}" />
|
IsChecked="{Binding Enabled}" />
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</DataGridTemplateColumn.CellTemplate>
|
</DataGridTemplateColumn.CellTemplate>
|
||||||
|
@ -57,35 +102,27 @@
|
||||||
<TextBlock Text="{locale:Locale DlcManagerTableHeadingEnabledLabel}" />
|
<TextBlock Text="{locale:Locale DlcManagerTableHeadingEnabledLabel}" />
|
||||||
</DataGridTemplateColumn.Header>
|
</DataGridTemplateColumn.Header>
|
||||||
</DataGridTemplateColumn>
|
</DataGridTemplateColumn>
|
||||||
<DataGridTextColumn
|
<DataGridTextColumn Width="140" Binding="{Binding TitleId}">
|
||||||
Width="190"
|
|
||||||
Binding="{Binding TitleId}"
|
|
||||||
CanUserResize="True">
|
|
||||||
<DataGridTextColumn.Header>
|
<DataGridTextColumn.Header>
|
||||||
<TextBlock Text="{locale:Locale DlcManagerTableHeadingTitleIdLabel}" />
|
<TextBlock Text="{locale:Locale DlcManagerTableHeadingTitleIdLabel}" />
|
||||||
</DataGridTextColumn.Header>
|
</DataGridTextColumn.Header>
|
||||||
</DataGridTextColumn>
|
</DataGridTextColumn>
|
||||||
<DataGridTextColumn
|
<DataGridTextColumn Width="280" Binding="{Binding FullPath}">
|
||||||
Width="*"
|
|
||||||
Binding="{Binding ContainerPath}"
|
|
||||||
CanUserResize="True">
|
|
||||||
<DataGridTextColumn.Header>
|
|
||||||
<TextBlock Text="{locale:Locale DlcManagerTableHeadingContainerPathLabel}" />
|
|
||||||
</DataGridTextColumn.Header>
|
|
||||||
</DataGridTextColumn>
|
|
||||||
<DataGridTextColumn
|
|
||||||
Width="*"
|
|
||||||
Binding="{Binding FullPath}"
|
|
||||||
CanUserResize="True">
|
|
||||||
<DataGridTextColumn.Header>
|
<DataGridTextColumn.Header>
|
||||||
<TextBlock Text="{locale:Locale DlcManagerTableHeadingFullPathLabel}" />
|
<TextBlock Text="{locale:Locale DlcManagerTableHeadingFullPathLabel}" />
|
||||||
</DataGridTextColumn.Header>
|
</DataGridTextColumn.Header>
|
||||||
</DataGridTextColumn>
|
</DataGridTextColumn>
|
||||||
|
<DataGridTextColumn Binding="{Binding ContainerPath}">
|
||||||
|
<DataGridTextColumn.Header>
|
||||||
|
<TextBlock Text="{locale:Locale DlcManagerTableHeadingContainerPathLabel}" />
|
||||||
|
</DataGridTextColumn.Header>
|
||||||
|
</DataGridTextColumn>
|
||||||
</DataGrid.Columns>
|
</DataGrid.Columns>
|
||||||
</DataGrid>
|
</DataGrid>
|
||||||
|
</ScrollViewer>
|
||||||
</Border>
|
</Border>
|
||||||
<DockPanel
|
<DockPanel
|
||||||
Grid.Row="3"
|
Grid.Row="4"
|
||||||
Margin="0"
|
Margin="0"
|
||||||
HorizontalAlignment="Stretch">
|
HorizontalAlignment="Stretch">
|
||||||
<DockPanel Margin="0" HorizontalAlignment="Left">
|
<DockPanel Margin="0" HorizontalAlignment="Left">
|
||||||
|
|
|
@ -8,6 +8,7 @@ using LibHac.FsSystem;
|
||||||
using LibHac.Tools.Fs;
|
using LibHac.Tools.Fs;
|
||||||
using LibHac.Tools.FsSystem;
|
using LibHac.Tools.FsSystem;
|
||||||
using LibHac.Tools.FsSystem.NcaUtils;
|
using LibHac.Tools.FsSystem.NcaUtils;
|
||||||
|
using LibHac.Tools.FsSystem.Save;
|
||||||
using Ryujinx.Ava.Common.Locale;
|
using Ryujinx.Ava.Common.Locale;
|
||||||
using Ryujinx.Ava.Ui.Controls;
|
using Ryujinx.Ava.Ui.Controls;
|
||||||
using Ryujinx.Ava.Ui.Models;
|
using Ryujinx.Ava.Ui.Models;
|
||||||
|
@ -16,8 +17,11 @@ using Ryujinx.Common.Utilities;
|
||||||
using Ryujinx.HLE.FileSystem;
|
using Ryujinx.HLE.FileSystem;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.ComponentModel;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Reactive.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Path = System.IO.Path;
|
using Path = System.IO.Path;
|
||||||
|
@ -29,12 +33,11 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||||
private readonly List<DownloadableContentContainer> _downloadableContentContainerList;
|
private readonly List<DownloadableContentContainer> _downloadableContentContainerList;
|
||||||
private readonly string _downloadableContentJsonPath;
|
private readonly string _downloadableContentJsonPath;
|
||||||
|
|
||||||
public VirtualFileSystem VirtualFileSystem { get; }
|
private VirtualFileSystem _virtualFileSystem { get; }
|
||||||
public AvaloniaList<DownloadableContentModel> DownloadableContents { get; set; } = new AvaloniaList<DownloadableContentModel>();
|
private AvaloniaList<DownloadableContentModel> _downloadableContents { get; set; }
|
||||||
public ulong TitleId { get; }
|
|
||||||
public string TitleName { get; }
|
|
||||||
|
|
||||||
public string Heading => string.Format(LocaleManager.Instance["DlcWindowHeading"], TitleName, TitleId.ToString("X16"));
|
private ulong TitleId { get; }
|
||||||
|
private string TitleName { get; }
|
||||||
|
|
||||||
public DownloadableContentManagerWindow()
|
public DownloadableContentManagerWindow()
|
||||||
{
|
{
|
||||||
|
@ -42,12 +45,13 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
Title = $"Ryujinx {Program.Version} - " + LocaleManager.Instance["DlcWindowTitle"];
|
Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance["DlcWindowTitle"]} - {TitleName} ({TitleId:X16})";
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownloadableContentManagerWindow(VirtualFileSystem virtualFileSystem, ulong titleId, string titleName)
|
public DownloadableContentManagerWindow(VirtualFileSystem virtualFileSystem, ulong titleId, string titleName)
|
||||||
{
|
{
|
||||||
VirtualFileSystem = virtualFileSystem;
|
_virtualFileSystem = virtualFileSystem;
|
||||||
|
_downloadableContents = new AvaloniaList<DownloadableContentModel>();
|
||||||
TitleId = titleId;
|
TitleId = titleId;
|
||||||
TitleName = titleName;
|
TitleName = titleName;
|
||||||
|
|
||||||
|
@ -66,9 +70,24 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
Title = $"Ryujinx {Program.Version} - " + LocaleManager.Instance["DlcWindowTitle"];
|
RemoveButton.IsEnabled = false;
|
||||||
|
|
||||||
|
DlcDataGrid.SelectionChanged += DlcDataGrid_SelectionChanged;
|
||||||
|
|
||||||
|
Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance["DlcWindowTitle"]} - {TitleName} ({TitleId:X16})";
|
||||||
|
|
||||||
LoadDownloadableContents();
|
LoadDownloadableContents();
|
||||||
|
PrintHeading();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DlcDataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
RemoveButton.IsEnabled = (DlcDataGrid.SelectedItems.Count > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PrintHeading()
|
||||||
|
{
|
||||||
|
Heading.Text = string.Format(LocaleManager.Instance["DlcWindowHeading"], _downloadableContents.Count, TitleName, TitleId.ToString("X16"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LoadDownloadableContents()
|
private void LoadDownloadableContents()
|
||||||
|
@ -79,20 +98,20 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||||
{
|
{
|
||||||
using FileStream containerFile = File.OpenRead(downloadableContentContainer.ContainerPath);
|
using FileStream containerFile = File.OpenRead(downloadableContentContainer.ContainerPath);
|
||||||
|
|
||||||
PartitionFileSystem pfs = new PartitionFileSystem(containerFile.AsStorage());
|
PartitionFileSystem pfs = new(containerFile.AsStorage());
|
||||||
|
|
||||||
VirtualFileSystem.ImportTickets(pfs);
|
_virtualFileSystem.ImportTickets(pfs);
|
||||||
|
|
||||||
foreach (DownloadableContentNca downloadableContentNca in downloadableContentContainer.DownloadableContentNcaList)
|
foreach (DownloadableContentNca downloadableContentNca in downloadableContentContainer.DownloadableContentNcaList)
|
||||||
{
|
{
|
||||||
using var ncaFile = new UniqueRef<IFile>();
|
using UniqueRef<IFile> ncaFile = new();
|
||||||
|
|
||||||
pfs.OpenFile(ref ncaFile.Ref(), downloadableContentNca.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
pfs.OpenFile(ref ncaFile.Ref(), downloadableContentNca.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
||||||
|
|
||||||
Nca nca = TryCreateNca(ncaFile.Get.AsStorage(), downloadableContentContainer.ContainerPath);
|
Nca nca = TryOpenNca(ncaFile.Get.AsStorage(), downloadableContentContainer.ContainerPath);
|
||||||
if (nca != null)
|
if (nca != null)
|
||||||
{
|
{
|
||||||
DownloadableContents.Add(new DownloadableContentModel(nca.Header.TitleId.ToString("X16"),
|
_downloadableContents.Add(new DownloadableContentModel(nca.Header.TitleId.ToString("X16"),
|
||||||
downloadableContentContainer.ContainerPath,
|
downloadableContentContainer.ContainerPath,
|
||||||
downloadableContentNca.FullPath,
|
downloadableContentNca.FullPath,
|
||||||
downloadableContentNca.Enabled));
|
downloadableContentNca.Enabled));
|
||||||
|
@ -105,11 +124,11 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||||
Save();
|
Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Nca TryCreateNca(IStorage ncaStorage, string containerPath)
|
private Nca TryOpenNca(IStorage ncaStorage, string containerPath)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return new Nca(VirtualFileSystem.KeySet, ncaStorage);
|
return new Nca(_virtualFileSystem.KeySet, ncaStorage);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -124,26 +143,25 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||||
|
|
||||||
private async Task AddDownloadableContent(string path)
|
private async Task AddDownloadableContent(string path)
|
||||||
{
|
{
|
||||||
if (!File.Exists(path) || DownloadableContents.FirstOrDefault(x => x.ContainerPath == path) != null)
|
if (!File.Exists(path) || _downloadableContents.FirstOrDefault(x => x.ContainerPath == path) != null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
using (FileStream containerFile = File.OpenRead(path))
|
using FileStream containerFile = File.OpenRead(path);
|
||||||
{
|
|
||||||
PartitionFileSystem pfs = new PartitionFileSystem(containerFile.AsStorage());
|
PartitionFileSystem partitionFileSystem = new(containerFile.AsStorage());
|
||||||
bool containsDownloadableContent = false;
|
bool containsDownloadableContent = false;
|
||||||
|
|
||||||
VirtualFileSystem.ImportTickets(pfs);
|
_virtualFileSystem.ImportTickets(partitionFileSystem);
|
||||||
|
|
||||||
foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca"))
|
foreach (DirectoryEntryEx fileEntry in partitionFileSystem.EnumerateEntries("/", "*.nca"))
|
||||||
{
|
{
|
||||||
using var ncaFile = new UniqueRef<IFile>();
|
using var ncaFile = new UniqueRef<IFile>();
|
||||||
|
|
||||||
pfs.OpenFile(ref ncaFile.Ref(), fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
partitionFileSystem.OpenFile(ref ncaFile.Ref(), fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
||||||
|
|
||||||
Nca nca = TryCreateNca(ncaFile.Get.AsStorage(), path);
|
|
||||||
|
|
||||||
|
Nca nca = TryOpenNca(ncaFile.Get.AsStorage(), path);
|
||||||
if (nca == null)
|
if (nca == null)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
@ -156,7 +174,7 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
DownloadableContents.Add(new DownloadableContentModel(nca.Header.TitleId.ToString("X16"), path, fileEntry.FullPath, true));
|
_downloadableContents.Add(new DownloadableContentModel(nca.Header.TitleId.ToString("X16"), path, fileEntry.FullPath, true));
|
||||||
|
|
||||||
containsDownloadableContent = true;
|
containsDownloadableContent = true;
|
||||||
}
|
}
|
||||||
|
@ -167,18 +185,31 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogDlcNoDlcErrorMessage"]);
|
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogDlcNoDlcErrorMessage"]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void RemoveDownloadableContents(bool removeSelectedOnly = false)
|
private void RemoveDownloadableContents(bool removeSelectedOnly = false)
|
||||||
{
|
{
|
||||||
if (removeSelectedOnly)
|
if (removeSelectedOnly)
|
||||||
{
|
{
|
||||||
DownloadableContents.RemoveAll(DownloadableContents.Where(x => x.Enabled).ToList());
|
AvaloniaList<DownloadableContentModel> removedItems = new();
|
||||||
|
|
||||||
|
foreach (var item in DlcDataGrid.SelectedItems)
|
||||||
|
{
|
||||||
|
removedItems.Add(item as DownloadableContentModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
DlcDataGrid.SelectedItems.Clear();
|
||||||
|
|
||||||
|
foreach (var item in removedItems)
|
||||||
|
{
|
||||||
|
_downloadableContents.RemoveAll(_downloadableContents.Where(x => x.TitleId == item.TitleId).ToList());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DownloadableContents.Clear();
|
_downloadableContents.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PrintHeading();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveSelected()
|
public void RemoveSelected()
|
||||||
|
@ -191,6 +222,22 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||||
RemoveDownloadableContents();
|
RemoveDownloadableContents();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void EnableAll()
|
||||||
|
{
|
||||||
|
foreach(var item in _downloadableContents)
|
||||||
|
{
|
||||||
|
item.Enabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DisableAll()
|
||||||
|
{
|
||||||
|
foreach (var item in _downloadableContents)
|
||||||
|
{
|
||||||
|
item.Enabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async void Add()
|
public async void Add()
|
||||||
{
|
{
|
||||||
OpenFileDialog dialog = new OpenFileDialog()
|
OpenFileDialog dialog = new OpenFileDialog()
|
||||||
|
@ -214,6 +261,8 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||||
await AddDownloadableContent(file);
|
await AddDownloadableContent(file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PrintHeading();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Save()
|
public void Save()
|
||||||
|
@ -222,7 +271,7 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||||
|
|
||||||
DownloadableContentContainer container = default;
|
DownloadableContentContainer container = default;
|
||||||
|
|
||||||
foreach (DownloadableContentModel downloadableContent in DownloadableContents)
|
foreach (DownloadableContentModel downloadableContent in _downloadableContents)
|
||||||
{
|
{
|
||||||
if (container.ContainerPath != downloadableContent.ContainerPath)
|
if (container.ContainerPath != downloadableContent.ContainerPath)
|
||||||
{
|
{
|
||||||
|
|
|
@ -90,8 +90,8 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||||
|
|
||||||
Title = $"Ryujinx {Program.Version}";
|
Title = $"Ryujinx {Program.Version}";
|
||||||
|
|
||||||
Height = Height / Program.WindowScaleFactor;
|
Height /= Program.WindowScaleFactor;
|
||||||
Width = Width / Program.WindowScaleFactor;
|
Width /= Program.WindowScaleFactor;
|
||||||
|
|
||||||
if (Program.PreviewerDetached)
|
if (Program.PreviewerDetached)
|
||||||
{
|
{
|
||||||
|
@ -523,10 +523,7 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||||
|
|
||||||
public static void UpdateGraphicsConfig()
|
public static void UpdateGraphicsConfig()
|
||||||
{
|
{
|
||||||
int resScale = ConfigurationState.Instance.Graphics.ResScale;
|
GraphicsConfig.ResScale = ConfigurationState.Instance.Graphics.ResScale == -1 ? ConfigurationState.Instance.Graphics.ResScaleCustom : ConfigurationState.Instance.Graphics.ResScale;
|
||||||
float resScaleCustom = ConfigurationState.Instance.Graphics.ResScaleCustom;
|
|
||||||
|
|
||||||
GraphicsConfig.ResScale = resScale == -1 ? resScaleCustom : resScale;
|
|
||||||
GraphicsConfig.MaxAnisotropy = ConfigurationState.Instance.Graphics.MaxAnisotropy;
|
GraphicsConfig.MaxAnisotropy = ConfigurationState.Instance.Graphics.MaxAnisotropy;
|
||||||
GraphicsConfig.ShadersDumpPath = ConfigurationState.Instance.Graphics.ShadersDumpPath;
|
GraphicsConfig.ShadersDumpPath = ConfigurationState.Instance.Graphics.ShadersDumpPath;
|
||||||
GraphicsConfig.EnableShaderCache = ConfigurationState.Instance.Graphics.EnableShaderCache;
|
GraphicsConfig.EnableShaderCache = ConfigurationState.Instance.Graphics.EnableShaderCache;
|
||||||
|
|
|
@ -75,7 +75,7 @@
|
||||||
Spacing="10">
|
Spacing="10">
|
||||||
<ListBox
|
<ListBox
|
||||||
Name="GameList"
|
Name="GameList"
|
||||||
MinHeight="150"
|
MinHeight="250"
|
||||||
Items="{Binding GameDirectories}" />
|
Items="{Binding GameDirectories}" />
|
||||||
<Grid HorizontalAlignment="Stretch">
|
<Grid HorizontalAlignment="Stretch">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
|
|
|
@ -16,7 +16,6 @@ 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;
|
|
||||||
using TimeZone = Ryujinx.Ava.Ui.Models.TimeZone;
|
using TimeZone = Ryujinx.Ava.Ui.Models.TimeZone;
|
||||||
|
|
||||||
namespace Ryujinx.Ava.Ui.Windows
|
namespace Ryujinx.Ava.Ui.Windows
|
||||||
|
@ -92,6 +91,7 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||||
|
|
||||||
_currentAssigner.Cancel();
|
_currentAssigner.Cancel();
|
||||||
_currentAssigner = null;
|
_currentAssigner = null;
|
||||||
|
|
||||||
button.IsChecked = false;
|
button.IsChecked = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -122,36 +122,19 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||||
{
|
{
|
||||||
if (e.SelectedItem is NavigationViewItem navitem)
|
if (e.SelectedItem is NavigationViewItem navitem)
|
||||||
{
|
{
|
||||||
switch (navitem.Tag.ToString())
|
NavPanel.Content = navitem.Tag.ToString() switch
|
||||||
{
|
{
|
||||||
case "UiPage":
|
"UiPage" => UiPage,
|
||||||
NavPanel.Content = UiPage;
|
"InputPage" => InputPage,
|
||||||
break;
|
"HotkeysPage" => HotkeysPage,
|
||||||
case "InputPage":
|
"SystemPage" => SystemPage,
|
||||||
NavPanel.Content = InputPage;
|
"CpuPage" => CpuPage,
|
||||||
break;
|
"GraphicsPage" => GraphicsPage,
|
||||||
case "HotkeysPage":
|
"AudioPage" => AudioPage,
|
||||||
NavPanel.Content = HotkeysPage;
|
"NetworkPage" => NetworkPage,
|
||||||
break;
|
"LoggingPage" => LoggingPage,
|
||||||
case "SystemPage":
|
_ => throw new NotImplementedException()
|
||||||
NavPanel.Content = SystemPage;
|
};
|
||||||
break;
|
|
||||||
case "CpuPage":
|
|
||||||
NavPanel.Content = CpuPage;
|
|
||||||
break;
|
|
||||||
case "GraphicsPage":
|
|
||||||
NavPanel.Content = GraphicsPage;
|
|
||||||
break;
|
|
||||||
case "AudioPage":
|
|
||||||
NavPanel.Content = AudioPage;
|
|
||||||
break;
|
|
||||||
case "NetworkPage":
|
|
||||||
NavPanel.Content = NetworkPage;
|
|
||||||
break;
|
|
||||||
case "LoggingPage":
|
|
||||||
NavPanel.Content = LoggingPage;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,13 +161,18 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||||
|
|
||||||
private void RemoveButton_OnClick(object sender, RoutedEventArgs e)
|
private void RemoveButton_OnClick(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
List<string> selected = new(GameList.SelectedItems.Cast<string>());
|
int oldIndex = GameList.SelectedIndex;
|
||||||
|
|
||||||
foreach (string path in selected)
|
foreach (string path in new List<string>(GameList.SelectedItems.Cast<string>()))
|
||||||
{
|
{
|
||||||
ViewModel.GameDirectories.Remove(path);
|
ViewModel.GameDirectories.Remove(path);
|
||||||
ViewModel.DirectoryChanged = true;
|
ViewModel.DirectoryChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (GameList.ItemCount > 0)
|
||||||
|
{
|
||||||
|
GameList.SelectedIndex = oldIndex < GameList.ItemCount ? oldIndex : 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TimeZoneBox_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
|
private void TimeZoneBox_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||||
|
@ -214,7 +202,6 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||||
private void SaveButton_Clicked(object sender, RoutedEventArgs e)
|
private void SaveButton_Clicked(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
SaveSettings();
|
SaveSettings();
|
||||||
|
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,7 +219,6 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||||
private void SaveSettings()
|
private void SaveSettings()
|
||||||
{
|
{
|
||||||
ViewModel.SaveSettings();
|
ViewModel.SaveSettings();
|
||||||
|
|
||||||
ControllerSettings?.SaveCurrentProfile();
|
ControllerSettings?.SaveCurrentProfile();
|
||||||
|
|
||||||
if (Owner is MainWindow window && ViewModel.DirectoryChanged)
|
if (Owner is MainWindow window && ViewModel.DirectoryChanged)
|
||||||
|
@ -246,8 +232,10 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||||
protected override void OnClosed(EventArgs e)
|
protected override void OnClosed(EventArgs e)
|
||||||
{
|
{
|
||||||
ControllerSettings.Dispose();
|
ControllerSettings.Dispose();
|
||||||
|
|
||||||
_currentAssigner?.Cancel();
|
_currentAssigner?.Cancel();
|
||||||
_currentAssigner = null;
|
_currentAssigner = null;
|
||||||
|
|
||||||
base.OnClosed(e);
|
base.OnClosed(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,6 +131,13 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||||
nacpFile.Get.Read(out _, 0, SpanHelpers.AsByteSpan(ref controlData), ReadOption.None).ThrowIfFailure();
|
nacpFile.Get.Read(out _, 0, SpanHelpers.AsByteSpan(ref controlData), ReadOption.None).ThrowIfFailure();
|
||||||
|
|
||||||
TitleUpdates.Add(new TitleUpdateModel(controlData, path));
|
TitleUpdates.Add(new TitleUpdateModel(controlData, path));
|
||||||
|
|
||||||
|
foreach (var update in TitleUpdates)
|
||||||
|
{
|
||||||
|
update.IsEnabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
TitleUpdates.Last().IsEnabled = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue