From cee712105850ac3385cd0091a923438167433f9f Mon Sep 17 00:00:00 2001
From: TSR Berry <20988865+TSRBerry@users.noreply.github.com>
Date: Sat, 8 Apr 2023 01:22:00 +0200
Subject: Move solution and projects to src
---
src/Ryujinx.Ava/UI/Controls/GameGridView.axaml | 177 ++++++++++++++++
src/Ryujinx.Ava/UI/Controls/GameGridView.axaml.cs | 57 +++++
src/Ryujinx.Ava/UI/Controls/GameListView.axaml | 233 +++++++++++++++++++++
src/Ryujinx.Ava/UI/Controls/GameListView.axaml.cs | 57 +++++
.../UI/Controls/NavigationDialogHost.axaml | 17 ++
.../UI/Controls/NavigationDialogHost.axaml.cs | 218 +++++++++++++++++++
src/Ryujinx.Ava/UI/Controls/UpdateWaitWindow.axaml | 42 ++++
.../UI/Controls/UpdateWaitWindow.axaml.cs | 31 +++
8 files changed, 832 insertions(+)
create mode 100644 src/Ryujinx.Ava/UI/Controls/GameGridView.axaml
create mode 100644 src/Ryujinx.Ava/UI/Controls/GameGridView.axaml.cs
create mode 100644 src/Ryujinx.Ava/UI/Controls/GameListView.axaml
create mode 100644 src/Ryujinx.Ava/UI/Controls/GameListView.axaml.cs
create mode 100644 src/Ryujinx.Ava/UI/Controls/NavigationDialogHost.axaml
create mode 100644 src/Ryujinx.Ava/UI/Controls/NavigationDialogHost.axaml.cs
create mode 100644 src/Ryujinx.Ava/UI/Controls/UpdateWaitWindow.axaml
create mode 100644 src/Ryujinx.Ava/UI/Controls/UpdateWaitWindow.axaml.cs
(limited to 'src/Ryujinx.Ava/UI/Controls')
diff --git a/src/Ryujinx.Ava/UI/Controls/GameGridView.axaml b/src/Ryujinx.Ava/UI/Controls/GameGridView.axaml
new file mode 100644
index 00000000..32cabfaa
--- /dev/null
+++ b/src/Ryujinx.Ava/UI/Controls/GameGridView.axaml
@@ -0,0 +1,177 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Ryujinx.Ava/UI/Controls/GameGridView.axaml.cs b/src/Ryujinx.Ava/UI/Controls/GameGridView.axaml.cs
new file mode 100644
index 00000000..aa76b7c9
--- /dev/null
+++ b/src/Ryujinx.Ava/UI/Controls/GameGridView.axaml.cs
@@ -0,0 +1,57 @@
+using Avalonia.Controls;
+using Avalonia.Input;
+using Avalonia.Interactivity;
+using Avalonia.Markup.Xaml;
+using Ryujinx.Ava.UI.Helpers;
+using Ryujinx.Ava.UI.ViewModels;
+using Ryujinx.Ui.App.Common;
+using System;
+
+namespace Ryujinx.Ava.UI.Controls
+{
+ public partial class GameGridView : UserControl
+ {
+ public static readonly RoutedEvent ApplicationOpenedEvent =
+ RoutedEvent.Register(nameof(ApplicationOpened), RoutingStrategies.Bubble);
+
+ public event EventHandler ApplicationOpened
+ {
+ add { AddHandler(ApplicationOpenedEvent, value); }
+ remove { RemoveHandler(ApplicationOpenedEvent, value); }
+ }
+
+ public GameGridView()
+ {
+ InitializeComponent();
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+
+ public void GameList_DoubleTapped(object sender, RoutedEventArgs args)
+ {
+ if (sender is ListBox listBox)
+ {
+ if (listBox.SelectedItem is ApplicationData selected)
+ {
+ RaiseEvent(new ApplicationOpenedEventArgs(selected, ApplicationOpenedEvent));
+ }
+ }
+ }
+
+ public void GameList_SelectionChanged(object sender, SelectionChangedEventArgs args)
+ {
+ if (sender is ListBox listBox)
+ {
+ (DataContext as MainWindowViewModel).GridSelectedApplication = listBox.SelectedItem as ApplicationData;
+ }
+ }
+
+ private void SearchBox_OnKeyUp(object sender, KeyEventArgs e)
+ {
+ (DataContext as MainWindowViewModel).SearchText = (sender as TextBox).Text;
+ }
+ }
+}
diff --git a/src/Ryujinx.Ava/UI/Controls/GameListView.axaml b/src/Ryujinx.Ava/UI/Controls/GameListView.axaml
new file mode 100644
index 00000000..c13eaae8
--- /dev/null
+++ b/src/Ryujinx.Ava/UI/Controls/GameListView.axaml
@@ -0,0 +1,233 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Ryujinx.Ava/UI/Controls/GameListView.axaml.cs b/src/Ryujinx.Ava/UI/Controls/GameListView.axaml.cs
new file mode 100644
index 00000000..a6449709
--- /dev/null
+++ b/src/Ryujinx.Ava/UI/Controls/GameListView.axaml.cs
@@ -0,0 +1,57 @@
+using Avalonia.Controls;
+using Avalonia.Input;
+using Avalonia.Interactivity;
+using Avalonia.Markup.Xaml;
+using Ryujinx.Ava.UI.Helpers;
+using Ryujinx.Ava.UI.ViewModels;
+using Ryujinx.Ui.App.Common;
+using System;
+
+namespace Ryujinx.Ava.UI.Controls
+{
+ public partial class GameListView : UserControl
+ {
+ public static readonly RoutedEvent ApplicationOpenedEvent =
+ RoutedEvent.Register(nameof(ApplicationOpened), RoutingStrategies.Bubble);
+
+ public event EventHandler ApplicationOpened
+ {
+ add { AddHandler(ApplicationOpenedEvent, value); }
+ remove { RemoveHandler(ApplicationOpenedEvent, value); }
+ }
+
+ public GameListView()
+ {
+ InitializeComponent();
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+
+ public void GameList_DoubleTapped(object sender, RoutedEventArgs args)
+ {
+ if (sender is ListBox listBox)
+ {
+ if (listBox.SelectedItem is ApplicationData selected)
+ {
+ RaiseEvent(new ApplicationOpenedEventArgs(selected, ApplicationOpenedEvent));
+ }
+ }
+ }
+
+ public void GameList_SelectionChanged(object sender, SelectionChangedEventArgs args)
+ {
+ if (sender is ListBox listBox)
+ {
+ (DataContext as MainWindowViewModel).ListSelectedApplication = listBox.SelectedItem as ApplicationData;
+ }
+ }
+
+ private void SearchBox_OnKeyUp(object sender, KeyEventArgs e)
+ {
+ (DataContext as MainWindowViewModel).SearchText = (sender as TextBox).Text;
+ }
+ }
+}
diff --git a/src/Ryujinx.Ava/UI/Controls/NavigationDialogHost.axaml b/src/Ryujinx.Ava/UI/Controls/NavigationDialogHost.axaml
new file mode 100644
index 00000000..bf34b303
--- /dev/null
+++ b/src/Ryujinx.Ava/UI/Controls/NavigationDialogHost.axaml
@@ -0,0 +1,17 @@
+
+
+
+
\ No newline at end of file
diff --git a/src/Ryujinx.Ava/UI/Controls/NavigationDialogHost.axaml.cs b/src/Ryujinx.Ava/UI/Controls/NavigationDialogHost.axaml.cs
new file mode 100644
index 00000000..1b857fae
--- /dev/null
+++ b/src/Ryujinx.Ava/UI/Controls/NavigationDialogHost.axaml.cs
@@ -0,0 +1,218 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Styling;
+using Avalonia.Threading;
+using FluentAvalonia.Core;
+using FluentAvalonia.UI.Controls;
+using LibHac;
+using LibHac.Common;
+using LibHac.Fs;
+using LibHac.Fs.Shim;
+using Ryujinx.Ava.Common.Locale;
+using Ryujinx.Ava.UI.Helpers;
+using Ryujinx.Ava.UI.Models;
+using Ryujinx.Ava.UI.ViewModels;
+using Ryujinx.Ava.UI.Views.User;
+using Ryujinx.HLE.FileSystem;
+using Ryujinx.HLE.HOS.Services.Account.Acc;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using UserProfile = Ryujinx.Ava.UI.Models.UserProfile;
+
+namespace Ryujinx.Ava.UI.Controls
+{
+ public partial class NavigationDialogHost : UserControl
+ {
+ public AccountManager AccountManager { get; }
+ public ContentManager ContentManager { get; }
+ public VirtualFileSystem VirtualFileSystem { get; }
+ public HorizonClient HorizonClient { get; }
+ public UserProfileViewModel ViewModel { get; set; }
+
+ public NavigationDialogHost()
+ {
+ InitializeComponent();
+ }
+
+ public NavigationDialogHost(AccountManager accountManager, ContentManager contentManager,
+ VirtualFileSystem virtualFileSystem, HorizonClient horizonClient)
+ {
+ AccountManager = accountManager;
+ ContentManager = contentManager;
+ VirtualFileSystem = virtualFileSystem;
+ HorizonClient = horizonClient;
+ ViewModel = new UserProfileViewModel();
+ LoadProfiles();
+
+ if (contentManager.GetCurrentFirmwareVersion() != null)
+ {
+ Task.Run(() =>
+ {
+ UserFirmwareAvatarSelectorViewModel.PreloadAvatars(contentManager, virtualFileSystem);
+ });
+ }
+ InitializeComponent();
+ }
+
+ public void GoBack(object parameter = null)
+ {
+ if (ContentFrame.BackStack.Count > 0)
+ {
+ ContentFrame.GoBack();
+ }
+
+ LoadProfiles();
+ }
+
+ public void Navigate(Type sourcePageType, object parameter)
+ {
+ ContentFrame.Navigate(sourcePageType, parameter);
+ }
+
+ public static async Task Show(AccountManager ownerAccountManager, ContentManager ownerContentManager,
+ VirtualFileSystem ownerVirtualFileSystem, HorizonClient ownerHorizonClient)
+ {
+ var content = new NavigationDialogHost(ownerAccountManager, ownerContentManager, ownerVirtualFileSystem, ownerHorizonClient);
+ ContentDialog contentDialog = new ContentDialog
+ {
+ Title = LocaleManager.Instance[LocaleKeys.UserProfileWindowTitle],
+ PrimaryButtonText = "",
+ SecondaryButtonText = "",
+ CloseButtonText = "",
+ Content = content,
+ Padding = new Thickness(0)
+ };
+
+ contentDialog.Closed += (sender, args) =>
+ {
+ content.ViewModel.Dispose();
+ };
+
+ Style footer = new(x => x.Name("DialogSpace").Child().OfType());
+ footer.Setters.Add(new Setter(IsVisibleProperty, false));
+
+ contentDialog.Styles.Add(footer);
+
+ await contentDialog.ShowAsync();
+ }
+
+ protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
+ {
+ base.OnAttachedToVisualTree(e);
+
+ Navigate(typeof(UserSelectorViews), this);
+ }
+
+ public void LoadProfiles()
+ {
+ ViewModel.Profiles.Clear();
+ ViewModel.LostProfiles.Clear();
+
+ var profiles = AccountManager.GetAllUsers().OrderBy(x => x.Name);
+
+ foreach (var profile in profiles)
+ {
+ ViewModel.Profiles.Add(new UserProfile(profile, this));
+ }
+
+ var saveDataFilter = SaveDataFilter.Make(programId: default, saveType: SaveDataType.Account, default, saveDataId: default, index: default);
+
+ using var saveDataIterator = new UniqueRef();
+
+ HorizonClient.Fs.OpenSaveDataIterator(ref saveDataIterator.Ref, SaveDataSpaceId.User, in saveDataFilter).ThrowIfFailure();
+
+ Span saveDataInfo = stackalloc SaveDataInfo[10];
+
+ HashSet lostAccounts = new();
+
+ while (true)
+ {
+ saveDataIterator.Get.ReadSaveDataInfo(out long readCount, saveDataInfo).ThrowIfFailure();
+
+ if (readCount == 0)
+ {
+ break;
+ }
+
+ for (int i = 0; i < readCount; i++)
+ {
+ var save = saveDataInfo[i];
+ var id = new HLE.HOS.Services.Account.Acc.UserId((long)save.UserId.Id.Low, (long)save.UserId.Id.High);
+ if (ViewModel.Profiles.Cast().FirstOrDefault( x=> x.UserId == id) == null)
+ {
+ lostAccounts.Add(id);
+ }
+ }
+ }
+
+ foreach(var account in lostAccounts)
+ {
+ ViewModel.LostProfiles.Add(new UserProfile(new HLE.HOS.Services.Account.Acc.UserProfile(account, "", null), this));
+ }
+
+ ViewModel.Profiles.Add(new BaseModel());
+ }
+
+ public async void DeleteUser(UserProfile userProfile)
+ {
+ var lastUserId = AccountManager.LastOpenedUser.UserId;
+
+ if (userProfile.UserId == lastUserId)
+ {
+ // If we are deleting the currently open profile, then we must open something else before deleting.
+ var profile = ViewModel.Profiles.Cast().FirstOrDefault(x => x.UserId != lastUserId);
+
+ if (profile == null)
+ {
+ async void Action()
+ {
+ await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogUserProfileDeletionWarningMessage]);
+ }
+
+ Dispatcher.UIThread.Post(Action);
+
+ return;
+ }
+
+ AccountManager.OpenUser(profile.UserId);
+ }
+
+ var result = await ContentDialogHelper.CreateConfirmationDialog(
+ LocaleManager.Instance[LocaleKeys.DialogUserProfileDeletionConfirmMessage],
+ "",
+ LocaleManager.Instance[LocaleKeys.InputDialogYes],
+ LocaleManager.Instance[LocaleKeys.InputDialogNo],
+ "");
+
+ if (result == UserResult.Yes)
+ {
+ GoBack();
+ AccountManager.DeleteUser(userProfile.UserId);
+ }
+
+ LoadProfiles();
+ }
+
+ public void AddUser()
+ {
+ Navigate(typeof(UserEditorView), (this, (UserProfile)null, true));
+ }
+
+ public void EditUser(UserProfile userProfile)
+ {
+ Navigate(typeof(UserEditorView), (this, userProfile, false));
+ }
+
+ public void RecoverLostAccounts()
+ {
+ Navigate(typeof(UserRecovererView), this);
+ }
+
+ public void ManageSaves()
+ {
+ Navigate(typeof(UserSaveManagerView), (this, AccountManager, HorizonClient, VirtualFileSystem));
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Ryujinx.Ava/UI/Controls/UpdateWaitWindow.axaml b/src/Ryujinx.Ava/UI/Controls/UpdateWaitWindow.axaml
new file mode 100644
index 00000000..c5041230
--- /dev/null
+++ b/src/Ryujinx.Ava/UI/Controls/UpdateWaitWindow.axaml
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Ryujinx.Ava/UI/Controls/UpdateWaitWindow.axaml.cs b/src/Ryujinx.Ava/UI/Controls/UpdateWaitWindow.axaml.cs
new file mode 100644
index 00000000..80a437e3
--- /dev/null
+++ b/src/Ryujinx.Ava/UI/Controls/UpdateWaitWindow.axaml.cs
@@ -0,0 +1,31 @@
+using Avalonia.Controls;
+using Ryujinx.Ava.UI.Windows;
+using System.Threading;
+
+namespace Ryujinx.Ava.UI.Controls
+{
+ public partial class UpdateWaitWindow : StyleableWindow
+ {
+ public UpdateWaitWindow(string primaryText, string secondaryText, CancellationTokenSource cancellationToken) : this(primaryText, secondaryText)
+ {
+ SystemDecorations = SystemDecorations.Full;
+ ShowInTaskbar = true;
+
+ Closing += (_, _) => cancellationToken.Cancel();
+ }
+
+ public UpdateWaitWindow(string primaryText, string secondaryText) : this()
+ {
+ PrimaryText.Text = primaryText;
+ SecondaryText.Text = secondaryText;
+ WindowStartupLocation = WindowStartupLocation.CenterOwner;
+ SystemDecorations = SystemDecorations.BorderOnly;
+ ShowInTaskbar = false;
+ }
+
+ public UpdateWaitWindow()
+ {
+ InitializeComponent();
+ }
+ }
+}
\ No newline at end of file
--
cgit v1.2.3