UserProfileViewModel.cs 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. using Avalonia;
  2. using Avalonia.Threading;
  3. using FluentAvalonia.UI.Controls;
  4. using LibHac.Common;
  5. using LibHac.Fs;
  6. using LibHac.Fs.Shim;
  7. using Ryujinx.Ava.Common.Locale;
  8. using Ryujinx.Ava.Ui.Controls;
  9. using Ryujinx.HLE.HOS.Services.Account.Acc;
  10. using System;
  11. using System.Collections.Generic;
  12. using System.Collections.ObjectModel;
  13. using System.Linq;
  14. using UserProfile = Ryujinx.Ava.Ui.Models.UserProfile;
  15. namespace Ryujinx.Ava.Ui.ViewModels
  16. {
  17. public class UserProfileViewModel : BaseModel, IDisposable
  18. {
  19. private readonly NavigationDialogHost _owner;
  20. private UserProfile _selectedProfile;
  21. private UserProfile _highlightedProfile;
  22. public UserProfileViewModel()
  23. {
  24. Profiles = new ObservableCollection<UserProfile>();
  25. LostProfiles = new ObservableCollection<UserProfile>();
  26. }
  27. public UserProfileViewModel(NavigationDialogHost owner) : this()
  28. {
  29. _owner = owner;
  30. LoadProfiles();
  31. }
  32. public ObservableCollection<UserProfile> Profiles { get; set; }
  33. public ObservableCollection<UserProfile> LostProfiles { get; set; }
  34. public UserProfile SelectedProfile
  35. {
  36. get => _selectedProfile;
  37. set
  38. {
  39. _selectedProfile = value;
  40. OnPropertyChanged(nameof(SelectedProfile));
  41. OnPropertyChanged(nameof(IsHighlightedProfileDeletable));
  42. OnPropertyChanged(nameof(IsHighlightedProfileEditable));
  43. }
  44. }
  45. public bool IsHighlightedProfileEditable => _highlightedProfile != null;
  46. public bool IsHighlightedProfileDeletable => _highlightedProfile != null && _highlightedProfile.UserId != AccountManager.DefaultUserId;
  47. public UserProfile HighlightedProfile
  48. {
  49. get => _highlightedProfile;
  50. set
  51. {
  52. _highlightedProfile = value;
  53. OnPropertyChanged(nameof(HighlightedProfile));
  54. OnPropertyChanged(nameof(IsHighlightedProfileDeletable));
  55. OnPropertyChanged(nameof(IsHighlightedProfileEditable));
  56. }
  57. }
  58. public void Dispose() { }
  59. public void LoadProfiles()
  60. {
  61. Profiles.Clear();
  62. LostProfiles.Clear();
  63. var profiles = _owner.AccountManager.GetAllUsers().OrderByDescending(x => x.AccountState == AccountState.Open);
  64. foreach (var profile in profiles)
  65. {
  66. Profiles.Add(new UserProfile(profile, _owner));
  67. }
  68. SelectedProfile = Profiles.FirstOrDefault(x => x.UserId == _owner.AccountManager.LastOpenedUser.UserId);
  69. if (SelectedProfile == null)
  70. {
  71. SelectedProfile = Profiles.First();
  72. if (SelectedProfile != null)
  73. {
  74. _owner.AccountManager.OpenUser(_selectedProfile.UserId);
  75. }
  76. }
  77. var saveDataFilter = SaveDataFilter.Make(programId: default, saveType: SaveDataType.Account,
  78. default, saveDataId: default, index: default);
  79. using var saveDataIterator = new UniqueRef<SaveDataIterator>();
  80. _owner.HorizonClient.Fs.OpenSaveDataIterator(ref saveDataIterator.Ref(), SaveDataSpaceId.User, in saveDataFilter).ThrowIfFailure();
  81. Span<SaveDataInfo> saveDataInfo = stackalloc SaveDataInfo[10];
  82. HashSet<HLE.HOS.Services.Account.Acc.UserId> lostAccounts = new HashSet<HLE.HOS.Services.Account.Acc.UserId>();
  83. while (true)
  84. {
  85. saveDataIterator.Get.ReadSaveDataInfo(out long readCount, saveDataInfo).ThrowIfFailure();
  86. if (readCount == 0)
  87. {
  88. break;
  89. }
  90. for (int i = 0; i < readCount; i++)
  91. {
  92. var save = saveDataInfo[i];
  93. var id = new HLE.HOS.Services.Account.Acc.UserId((long)save.UserId.Id.Low, (long)save.UserId.Id.High);
  94. if (Profiles.FirstOrDefault( x=> x.UserId == id) == null)
  95. {
  96. lostAccounts.Add(id);
  97. }
  98. }
  99. }
  100. foreach(var account in lostAccounts)
  101. {
  102. LostProfiles.Add(new UserProfile(new HLE.HOS.Services.Account.Acc.UserProfile(account, "", null), _owner));
  103. }
  104. }
  105. public void AddUser()
  106. {
  107. UserProfile userProfile = null;
  108. _owner.Navigate(typeof(UserEditor), (this._owner, userProfile, true));
  109. }
  110. public async void ManageSaves()
  111. {
  112. UserProfile userProfile = _highlightedProfile ?? SelectedProfile;
  113. SaveManager manager = new SaveManager(userProfile, _owner.HorizonClient, _owner.VirtualFileSystem);
  114. ContentDialog contentDialog = new ContentDialog
  115. {
  116. Title = string.Format(LocaleManager.Instance["SaveManagerHeading"], userProfile.Name),
  117. PrimaryButtonText = "",
  118. SecondaryButtonText = "",
  119. CloseButtonText = LocaleManager.Instance["UserProfilesClose"],
  120. Content = manager,
  121. Padding = new Thickness(0)
  122. };
  123. await contentDialog.ShowAsync();
  124. }
  125. public void EditUser()
  126. {
  127. _owner.Navigate(typeof(UserEditor), (this._owner, _highlightedProfile ?? SelectedProfile, false));
  128. }
  129. public async void DeleteUser()
  130. {
  131. if (_highlightedProfile != null)
  132. {
  133. var lastUserId = _owner.AccountManager.LastOpenedUser.UserId;
  134. if (_highlightedProfile.UserId == lastUserId)
  135. {
  136. // If we are deleting the currently open profile, then we must open something else before deleting.
  137. var profile = Profiles.FirstOrDefault(x => x.UserId != lastUserId);
  138. if (profile == null)
  139. {
  140. Dispatcher.UIThread.Post(async () =>
  141. {
  142. await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogUserProfileDeletionWarningMessage"]);
  143. });
  144. return;
  145. }
  146. _owner.AccountManager.OpenUser(profile.UserId);
  147. }
  148. var result =
  149. await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance["DialogUserProfileDeletionConfirmMessage"], "",
  150. LocaleManager.Instance["InputDialogYes"], LocaleManager.Instance["InputDialogNo"], "");
  151. if (result == UserResult.Yes)
  152. {
  153. _owner.AccountManager.DeleteUser(_highlightedProfile.UserId);
  154. }
  155. }
  156. LoadProfiles();
  157. }
  158. public void GoBack()
  159. {
  160. _owner.GoBack();
  161. }
  162. public void RecoverLostAccounts()
  163. {
  164. _owner.Navigate(typeof(UserRecoverer), (this._owner, this));
  165. }
  166. }
  167. }