diff options
author | Ac_K <Acoustik666@gmail.com> | 2021-04-23 22:26:31 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-04-23 22:26:31 +0200 |
commit | c46f6879ff9171a1e024965618242e8bad373b6b (patch) | |
tree | b1ce4b4ce61831797377f39be2089aaeecc3c58b /Ryujinx/Ui/Windows/UserProfilesManagerWindow.cs | |
parent | 3e61fb0268ea0f52a37c4513dde0ec1f5a6463a2 (diff) |
account: add Custom User Profiles support (#2227)
* Initial Impl
* Fix names
* remove useless ContentManager
* Support backgrounds and improve avatar loading
* Fix firmware checks
* Addresses gdkchan feedback
Diffstat (limited to 'Ryujinx/Ui/Windows/UserProfilesManagerWindow.cs')
-rw-r--r-- | Ryujinx/Ui/Windows/UserProfilesManagerWindow.cs | 327 |
1 files changed, 327 insertions, 0 deletions
diff --git a/Ryujinx/Ui/Windows/UserProfilesManagerWindow.cs b/Ryujinx/Ui/Windows/UserProfilesManagerWindow.cs new file mode 100644 index 00000000..6a4788b1 --- /dev/null +++ b/Ryujinx/Ui/Windows/UserProfilesManagerWindow.cs @@ -0,0 +1,327 @@ +using Gtk; +using Ryujinx.HLE.FileSystem; +using Ryujinx.HLE.FileSystem.Content; +using Ryujinx.HLE.HOS.Services.Account.Acc; +using Ryujinx.Ui.Widgets; +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.Processing; +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; + +using Image = SixLabors.ImageSharp.Image; +using UserId = Ryujinx.HLE.HOS.Services.Account.Acc.UserId; + +namespace Ryujinx.Ui.Windows +{ + public partial class UserProfilesManagerWindow : Window + { + private const uint MaxProfileNameLength = 0x20; + + private readonly AccountManager _accountManager; + private readonly ContentManager _contentManager; + + private byte[] _bufferImageProfile; + private string _tempNewProfileName; + + private Gdk.RGBA _selectedColor; + + private ManualResetEvent _avatarsPreloadingEvent = new ManualResetEvent(false); + + public UserProfilesManagerWindow(AccountManager accountManager, ContentManager contentManager, VirtualFileSystem virtualFileSystem) : base($"Ryujinx {Program.Version} - Manage User Profiles") + { + Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.Resources.Logo_Ryujinx.png"); + + InitializeComponent(); + + _selectedColor.Red = 0.212; + _selectedColor.Green = 0.843; + _selectedColor.Blue = 0.718; + _selectedColor.Alpha = 1; + + _accountManager = accountManager; + _contentManager = contentManager; + + CellRendererToggle userSelectedToggle = new CellRendererToggle(); + userSelectedToggle.Toggled += UserSelectedToggle_Toggled; + + // NOTE: Uncomment following line when multiple selection of user profiles is supported. + //_usersTreeView.AppendColumn("Selected", userSelectedToggle, "active", 0); + _usersTreeView.AppendColumn("User Icon", new CellRendererPixbuf(), "pixbuf", 1); + _usersTreeView.AppendColumn("User Info", new CellRendererText(), "text", 2, "background-rgba", 3); + + _tableStore.SetSortColumnId(0, SortType.Descending); + + RefreshList(); + + if (_contentManager.GetCurrentFirmwareVersion() != null) + { + Task.Run(() => + { + AvatarWindow.PreloadAvatars(contentManager, virtualFileSystem); + _avatarsPreloadingEvent.Set(); + }); + } + } + + public void RefreshList() + { + _tableStore.Clear(); + + foreach (UserProfile userProfile in _accountManager.GetAllUsers()) + { + _tableStore.AppendValues(userProfile.AccountState == AccountState.Open, new Gdk.Pixbuf(userProfile.Image, 96, 96), $"{userProfile.Name}\n{userProfile.UserId}", Gdk.RGBA.Zero); + + if (userProfile.AccountState == AccountState.Open) + { + _selectedUserImage.Pixbuf = new Gdk.Pixbuf(userProfile.Image, 96, 96); + _selectedUserIdLabel.Text = userProfile.UserId.ToString(); + _selectedUserNameEntry.Text = userProfile.Name; + + _deleteButton.Sensitive = userProfile.UserId != AccountManager.DefaultUserId; + + _usersTreeView.Model.GetIterFirst(out TreeIter firstIter); + _tableStore.SetValue(firstIter, 3, _selectedColor); + } + } + } + + // + // Events + // + + private void UsersTreeView_Activated(object o, RowActivatedArgs args) + { + SelectUserTreeView(); + } + + private void UserSelectedToggle_Toggled(object o, ToggledArgs args) + { + SelectUserTreeView(); + } + + private void SelectUserTreeView() + { + // Get selected item informations. + _usersTreeView.Selection.GetSelected(out TreeIter selectedIter); + + Gdk.Pixbuf userPicture = (Gdk.Pixbuf)_tableStore.GetValue(selectedIter, 1); + + string userName = _tableStore.GetValue(selectedIter, 2).ToString().Split("\n")[0]; + string userId = _tableStore.GetValue(selectedIter, 2).ToString().Split("\n")[1]; + + // Unselect the first user. + _usersTreeView.Model.GetIterFirst(out TreeIter firstIter); + _tableStore.SetValue(firstIter, 0, false); + _tableStore.SetValue(firstIter, 3, Gdk.RGBA.Zero); + + // Set new informations. + _tableStore.SetValue(selectedIter, 0, true); + + _selectedUserImage.Pixbuf = userPicture; + _selectedUserNameEntry.Text = userName; + _selectedUserIdLabel.Text = userId; + _saveProfileNameButton.Sensitive = false; + + // Open the selected one. + _accountManager.OpenUser(new UserId(userId)); + + _deleteButton.Sensitive = userId != AccountManager.DefaultUserId.ToString(); + + _tableStore.SetValue(selectedIter, 3, _selectedColor); + } + + private void SelectedUserNameEntry_KeyReleaseEvent(object o, KeyReleaseEventArgs args) + { + if (_saveProfileNameButton.Sensitive == false) + { + _saveProfileNameButton.Sensitive = true; + } + } + + private void AddButton_Pressed(object sender, EventArgs e) + { + _tempNewProfileName = GtkDialog.CreateInputDialog(this, "Choose the Profile Name", "Please Enter a Profile Name", MaxProfileNameLength); + + if (_tempNewProfileName != "") + { + SelectProfileImage(true); + + if (_bufferImageProfile != null) + { + AddUser(); + } + } + } + + private void DeleteButton_Pressed(object sender, EventArgs e) + { + if (GtkDialog.CreateChoiceDialog("Delete User Profile", "Are you sure you want to delete the profile ?", "Deleting this profile will also delete all associated save data.")) + { + _accountManager.DeleteUser(GetSelectedUserId()); + + RefreshList(); + } + } + + private void EditProfileNameButton_Pressed(object sender, EventArgs e) + { + _saveProfileNameButton.Sensitive = false; + + _accountManager.SetUserName(GetSelectedUserId(), _selectedUserNameEntry.Text); + + RefreshList(); + } + + private void ProcessProfileImage(byte[] buffer) + { + using (Image image = Image.Load(buffer)) + { + image.Mutate(x => x.Resize(256, 256)); + + using (MemoryStream streamJpg = new MemoryStream()) + { + image.SaveAsJpeg(streamJpg); + + _bufferImageProfile = streamJpg.ToArray(); + } + } + } + + private void ProfileImageFileChooser() + { + FileChooserDialog fileChooser = new FileChooserDialog("Import Custom Profile Image", this, FileChooserAction.Open, "Cancel", ResponseType.Cancel, "Import", ResponseType.Accept) + { + SelectMultiple = false, + Filter = new FileFilter() + }; + + fileChooser.SetPosition(WindowPosition.Center); + fileChooser.Filter.AddPattern("*.jpg"); + fileChooser.Filter.AddPattern("*.jpeg"); + fileChooser.Filter.AddPattern("*.png"); + fileChooser.Filter.AddPattern("*.bmp"); + + if (fileChooser.Run() == (int)ResponseType.Accept) + { + ProcessProfileImage(File.ReadAllBytes(fileChooser.Filename)); + } + + fileChooser.Dispose(); + } + + private void SelectProfileImage(bool newUser = false) + { + if (_contentManager.GetCurrentFirmwareVersion() == null) + { + ProfileImageFileChooser(); + } + else + { + Dictionary<int, string> buttons = new Dictionary<int, string>() + { + { 0, "Import Image File" }, + { 1, "Select Firmware Avatar" } + }; + + ResponseType responseDialog = GtkDialog.CreateCustomDialog("Profile Image Selection", + "Choose a Profile Image", + "You may import a custom profile image, or select an avatar from the system firmware.", + buttons, MessageType.Question); + + if (responseDialog == 0) + { + ProfileImageFileChooser(); + } + else if (responseDialog == (ResponseType)1) + { + AvatarWindow avatarWindow = new AvatarWindow() + { + NewUser = newUser + }; + + avatarWindow.DeleteEvent += AvatarWindow_DeleteEvent; + + avatarWindow.SetSizeRequest((int)(avatarWindow.DefaultWidth * Program.WindowScaleFactor), (int)(avatarWindow.DefaultHeight * Program.WindowScaleFactor)); + avatarWindow.Show(); + } + } + } + + private void ChangeProfileImageButton_Pressed(object sender, EventArgs e) + { + if (_contentManager.GetCurrentFirmwareVersion() != null) + { + _avatarsPreloadingEvent.WaitOne(); + } + + SelectProfileImage(); + + if (_bufferImageProfile != null) + { + SetUserImage(); + } + } + + private void AvatarWindow_DeleteEvent(object sender, DeleteEventArgs args) + { + _bufferImageProfile = ((AvatarWindow)sender).SelectedProfileImage; + + if (_bufferImageProfile != null) + { + if (((AvatarWindow)sender).NewUser) + { + AddUser(); + } + else + { + SetUserImage(); + } + } + } + + private void AddUser() + { + _accountManager.AddUser(_tempNewProfileName, _bufferImageProfile); + + _bufferImageProfile = null; + _tempNewProfileName = ""; + + RefreshList(); + } + + private void SetUserImage() + { + _accountManager.SetUserImage(GetSelectedUserId(), _bufferImageProfile); + + _bufferImageProfile = null; + + RefreshList(); + } + + private UserId GetSelectedUserId() + { + if (_usersTreeView.Model.GetIterFirst(out TreeIter iter)) + { + do + { + if ((bool)_tableStore.GetValue(iter, 0)) + { + break; + } + } + while (_usersTreeView.Model.IterNext(ref iter)); + } + + return new UserId(_tableStore.GetValue(iter, 2).ToString().Split("\n")[1]); + } + + private void CloseButton_Pressed(object sender, EventArgs e) + { + Close(); + } + } +}
\ No newline at end of file |