NavigationDialogHost.axaml.cs 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. using Avalonia;
  2. using Avalonia.Controls;
  3. using Avalonia.Styling;
  4. using Avalonia.Threading;
  5. using FluentAvalonia.Core;
  6. using FluentAvalonia.UI.Controls;
  7. using LibHac;
  8. using LibHac.Common;
  9. using LibHac.Fs;
  10. using LibHac.Fs.Shim;
  11. using Ryujinx.Ava.Common.Locale;
  12. using Ryujinx.Ava.UI.Helpers;
  13. using Ryujinx.Ava.UI.Models;
  14. using Ryujinx.Ava.UI.ViewModels;
  15. using Ryujinx.Ava.UI.Views.User;
  16. using Ryujinx.HLE.FileSystem;
  17. using Ryujinx.HLE.HOS.Services.Account.Acc;
  18. using System;
  19. using System.Threading.Tasks;
  20. using System.Collections.Generic;
  21. using System.Linq;
  22. using UserProfile = Ryujinx.Ava.UI.Models.UserProfile;
  23. namespace Ryujinx.Ava.UI.Controls
  24. {
  25. public partial class NavigationDialogHost : UserControl
  26. {
  27. public AccountManager AccountManager { get; }
  28. public ContentManager ContentManager { get; }
  29. public VirtualFileSystem VirtualFileSystem { get; }
  30. public HorizonClient HorizonClient { get; }
  31. public UserProfileViewModel ViewModel { get; set; }
  32. public NavigationDialogHost()
  33. {
  34. InitializeComponent();
  35. }
  36. public NavigationDialogHost(AccountManager accountManager, ContentManager contentManager,
  37. VirtualFileSystem virtualFileSystem, HorizonClient horizonClient)
  38. {
  39. AccountManager = accountManager;
  40. ContentManager = contentManager;
  41. VirtualFileSystem = virtualFileSystem;
  42. HorizonClient = horizonClient;
  43. ViewModel = new UserProfileViewModel();
  44. LoadProfiles();
  45. if (contentManager.GetCurrentFirmwareVersion() != null)
  46. {
  47. Task.Run(() =>
  48. {
  49. UserFirmwareAvatarSelectorViewModel.PreloadAvatars(contentManager, virtualFileSystem);
  50. });
  51. }
  52. InitializeComponent();
  53. }
  54. public void GoBack(object parameter = null)
  55. {
  56. if (ContentFrame.BackStack.Count > 0)
  57. {
  58. ContentFrame.GoBack();
  59. }
  60. LoadProfiles();
  61. }
  62. public void Navigate(Type sourcePageType, object parameter)
  63. {
  64. ContentFrame.Navigate(sourcePageType, parameter);
  65. }
  66. public static async Task Show(AccountManager ownerAccountManager, ContentManager ownerContentManager,
  67. VirtualFileSystem ownerVirtualFileSystem, HorizonClient ownerHorizonClient)
  68. {
  69. var content = new NavigationDialogHost(ownerAccountManager, ownerContentManager, ownerVirtualFileSystem, ownerHorizonClient);
  70. ContentDialog contentDialog = new ContentDialog
  71. {
  72. Title = LocaleManager.Instance[LocaleKeys.UserProfileWindowTitle],
  73. PrimaryButtonText = "",
  74. SecondaryButtonText = "",
  75. CloseButtonText = "",
  76. Content = content,
  77. Padding = new Thickness(0)
  78. };
  79. contentDialog.Closed += (sender, args) =>
  80. {
  81. content.ViewModel.Dispose();
  82. };
  83. Style footer = new(x => x.Name("DialogSpace").Child().OfType<Border>());
  84. footer.Setters.Add(new Setter(IsVisibleProperty, false));
  85. contentDialog.Styles.Add(footer);
  86. await contentDialog.ShowAsync();
  87. }
  88. protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
  89. {
  90. base.OnAttachedToVisualTree(e);
  91. Navigate(typeof(UserSelectorViews), this);
  92. }
  93. public void LoadProfiles()
  94. {
  95. ViewModel.Profiles.Clear();
  96. ViewModel.LostProfiles.Clear();
  97. var profiles = AccountManager.GetAllUsers().OrderBy(x => x.Name);
  98. foreach (var profile in profiles)
  99. {
  100. ViewModel.Profiles.Add(new UserProfile(profile, this));
  101. }
  102. var saveDataFilter = SaveDataFilter.Make(programId: default, saveType: SaveDataType.Account, default, saveDataId: default, index: default);
  103. using var saveDataIterator = new UniqueRef<SaveDataIterator>();
  104. HorizonClient.Fs.OpenSaveDataIterator(ref saveDataIterator.Ref(), SaveDataSpaceId.User, in saveDataFilter).ThrowIfFailure();
  105. Span<SaveDataInfo> saveDataInfo = stackalloc SaveDataInfo[10];
  106. HashSet<HLE.HOS.Services.Account.Acc.UserId> lostAccounts = new();
  107. while (true)
  108. {
  109. saveDataIterator.Get.ReadSaveDataInfo(out long readCount, saveDataInfo).ThrowIfFailure();
  110. if (readCount == 0)
  111. {
  112. break;
  113. }
  114. for (int i = 0; i < readCount; i++)
  115. {
  116. var save = saveDataInfo[i];
  117. var id = new HLE.HOS.Services.Account.Acc.UserId((long)save.UserId.Id.Low, (long)save.UserId.Id.High);
  118. if (ViewModel.Profiles.Cast<UserProfile>().FirstOrDefault( x=> x.UserId == id) == null)
  119. {
  120. lostAccounts.Add(id);
  121. }
  122. }
  123. }
  124. foreach(var account in lostAccounts)
  125. {
  126. ViewModel.LostProfiles.Add(new UserProfile(new HLE.HOS.Services.Account.Acc.UserProfile(account, "", null), this));
  127. }
  128. ViewModel.Profiles.Add(new BaseModel());
  129. }
  130. public async void DeleteUser(UserProfile userProfile)
  131. {
  132. var lastUserId = AccountManager.LastOpenedUser.UserId;
  133. if (userProfile.UserId == lastUserId)
  134. {
  135. // If we are deleting the currently open profile, then we must open something else before deleting.
  136. var profile = ViewModel.Profiles.Cast<UserProfile>().FirstOrDefault(x => x.UserId != lastUserId);
  137. if (profile == null)
  138. {
  139. async void Action()
  140. {
  141. await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogUserProfileDeletionWarningMessage]);
  142. }
  143. Dispatcher.UIThread.Post(Action);
  144. return;
  145. }
  146. AccountManager.OpenUser(profile.UserId);
  147. }
  148. var result = await ContentDialogHelper.CreateConfirmationDialog(
  149. LocaleManager.Instance[LocaleKeys.DialogUserProfileDeletionConfirmMessage],
  150. "",
  151. LocaleManager.Instance[LocaleKeys.InputDialogYes],
  152. LocaleManager.Instance[LocaleKeys.InputDialogNo],
  153. "");
  154. if (result == UserResult.Yes)
  155. {
  156. GoBack();
  157. AccountManager.DeleteUser(userProfile.UserId);
  158. }
  159. LoadProfiles();
  160. }
  161. public void AddUser()
  162. {
  163. Navigate(typeof(UserEditorView), (this, (UserProfile)null, true));
  164. }
  165. public void EditUser(UserProfile userProfile)
  166. {
  167. Navigate(typeof(UserEditorView), (this, userProfile, false));
  168. }
  169. public void RecoverLostAccounts()
  170. {
  171. Navigate(typeof(UserRecovererView), this);
  172. }
  173. public void ManageSaves()
  174. {
  175. Navigate(typeof(UserSaveManagerView), (this, AccountManager, HorizonClient, VirtualFileSystem));
  176. }
  177. }
  178. }