diff --git a/Ryujinx.HLE/HOS/Services/Account/Acc/AccountManager.cs b/Ryujinx.HLE/HOS/Services/Account/Acc/AccountManager.cs
index d36ea93149..2cea57e9e5 100644
--- a/Ryujinx.HLE/HOS/Services/Account/Acc/AccountManager.cs
+++ b/Ryujinx.HLE/HOS/Services/Account/Acc/AccountManager.cs
@@ -1,41 +1,85 @@
-using Ryujinx.Common;
+using LibHac;
+using LibHac.Fs;
+using LibHac.Fs.Shim;
+using Ryujinx.Common;
+using Ryujinx.HLE.FileSystem;
+using Ryujinx.HLE.FileSystem.Content;
+using System;
 using System.Collections.Concurrent;
 using System.Collections.Generic;
+using System.IO;
 using System.Linq;
 
 namespace Ryujinx.HLE.HOS.Services.Account.Acc
 {
     public class AccountManager
     {
+        public static readonly UserId DefaultUserId = new UserId("00000000000000010000000000000000");
+
+        private readonly VirtualFileSystem      _virtualFileSystem;
+        private readonly AccountSaveDataManager _accountSaveDataManager;
+
         private ConcurrentDictionary<string, UserProfile> _profiles;
 
         public UserProfile LastOpenedUser { get; private set; }
 
-        public AccountManager()
+        public AccountManager(VirtualFileSystem virtualFileSystem)
         {
+            _virtualFileSystem = virtualFileSystem;
+
             _profiles = new ConcurrentDictionary<string, UserProfile>();
 
-            UserId defaultUserId    = new UserId("00000000000000010000000000000000");
-            byte[] defaultUserImage = EmbeddedResources.Read("Ryujinx.HLE/HOS/Services/Account/Acc/DefaultUserImage.jpg");
+            _accountSaveDataManager = new AccountSaveDataManager(_profiles);
 
-            AddUser(defaultUserId, "Player", defaultUserImage);
-            
-            OpenUser(defaultUserId);
+            if (!_profiles.TryGetValue(DefaultUserId.ToString(), out _))
+            {
+                byte[] defaultUserImage = EmbeddedResources.Read("Ryujinx.HLE/HOS/Services/Account/Acc/DefaultUserImage.jpg");
+
+                AddUser("RyuPlayer", defaultUserImage, DefaultUserId);
+
+                OpenUser(DefaultUserId);
+            }
+            else
+            {
+                OpenUser(_accountSaveDataManager.LastOpened);
+            }
         }
 
-        public void AddUser(UserId userId, string name, byte[] image)
+        public void AddUser(string name, byte[] image, UserId userId = new UserId())
         {
+            if (userId.IsNull)
+            {
+                userId = new UserId(Guid.NewGuid().ToString().Replace("-", ""));
+            }
+
             UserProfile profile = new UserProfile(userId, name, image);
 
             _profiles.AddOrUpdate(userId.ToString(), profile, (key, old) => profile);
+
+            _accountSaveDataManager.Save(_profiles);
         }
 
         public void OpenUser(UserId userId)
         {
             if (_profiles.TryGetValue(userId.ToString(), out UserProfile profile))
             {
+                // TODO: Support multiple open users ?
+                foreach (UserProfile userProfile in GetAllUsers())
+                {
+                    if (userProfile == LastOpenedUser)
+                    {
+                        userProfile.AccountState = AccountState.Closed;
+
+                        break;
+                    }
+                }
+
                 (LastOpenedUser = profile).AccountState = AccountState.Open;
+
+                _accountSaveDataManager.LastOpened = userId;
             }
+
+            _accountSaveDataManager.Save(_profiles);
         }
 
         public void CloseUser(UserId userId)
@@ -44,9 +88,117 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
             {
                 profile.AccountState = AccountState.Closed;
             }
+
+            _accountSaveDataManager.Save(_profiles);
         }
 
-        public int GetUserCount()
+        public void OpenUserOnlinePlay(UserId userId)
+        {
+            if (_profiles.TryGetValue(userId.ToString(), out UserProfile profile))
+            {
+                // TODO: Support multiple open online users ?
+                foreach (UserProfile userProfile in GetAllUsers())
+                {
+                    if (userProfile == LastOpenedUser)
+                    {
+                        userProfile.OnlinePlayState = AccountState.Closed;
+
+                        break;
+                    }
+                }
+
+                profile.OnlinePlayState = AccountState.Open;
+            }
+
+            _accountSaveDataManager.Save(_profiles);
+        }
+
+        public void CloseUserOnlinePlay(UserId userId)
+        {
+            if (_profiles.TryGetValue(userId.ToString(), out UserProfile profile))
+            {
+                profile.OnlinePlayState = AccountState.Closed;
+            }
+
+            _accountSaveDataManager.Save(_profiles);
+        }
+
+        public void SetUserImage(UserId userId, byte[] image)
+        {
+            foreach (UserProfile userProfile in GetAllUsers())
+            {
+                if (userProfile.UserId == userId)
+                {
+                    userProfile.Image = image;
+
+                    break;
+                }
+            }
+
+            _accountSaveDataManager.Save(_profiles);
+        }
+
+        public void SetUserName(UserId userId, string name)
+        {
+            foreach (UserProfile userProfile in GetAllUsers())
+            {
+                if (userProfile.UserId == userId)
+                {
+                    userProfile.Name = name;
+
+                    break;
+                }
+            }
+
+            _accountSaveDataManager.Save(_profiles);
+        }
+
+        public void DeleteUser(UserId userId)
+        {
+            DeleteSaveData(userId);
+
+            _profiles.Remove(userId.ToString(), out _);
+
+            OpenUser(DefaultUserId);
+
+            _accountSaveDataManager.Save(_profiles);
+        }
+
+        private void DeleteSaveData(UserId userId)
+        {
+            SaveDataFilter saveDataFilter = new SaveDataFilter();
+            saveDataFilter.SetUserId(new LibHac.Fs.UserId((ulong)userId.High, (ulong)userId.Low));
+
+            Result result = _virtualFileSystem.FsClient.OpenSaveDataIterator(out SaveDataIterator saveDataIterator, SaveDataSpaceId.User, ref saveDataFilter);
+            if (result.IsSuccess())
+            {
+                Span<SaveDataInfo> saveDataInfo = stackalloc SaveDataInfo[10];
+
+                while (true)
+                {
+                    saveDataIterator.ReadSaveDataInfo(out long readCount, saveDataInfo);
+
+                    if (readCount == 0)
+                    {
+                        break;
+                    }
+
+                    for (int i = 0; i < readCount; i++)
+                    {
+                        // TODO: We use Directory.Delete workaround because DeleteSaveData softlock without, due to a bug in LibHac 0.12.0.
+                        string savePath     = Path.Combine(_virtualFileSystem.GetNandPath(), $"user/save/{saveDataInfo[i].SaveDataId:x16}");
+                        string saveMetaPath = Path.Combine(_virtualFileSystem.GetNandPath(), $"user/saveMeta/{saveDataInfo[i].SaveDataId:x16}");
+
+                        Directory.Delete(savePath, true);
+                        Directory.Delete(saveMetaPath, true);
+
+                        _virtualFileSystem.FsClient.DeleteSaveData(SaveDataSpaceId.User, saveDataInfo[i].SaveDataId);
+                    }
+                }
+            }
+        }
+
+        internal int GetUserCount()
         {
             return _profiles.Count;
         }
@@ -56,7 +208,7 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
             return _profiles.TryGetValue(userId.ToString(), out profile);
         }
 
-        internal IEnumerable<UserProfile> GetAllUsers()
+        public IEnumerable<UserProfile> GetAllUsers()
         {
             return _profiles.Values;
         }
diff --git a/Ryujinx.HLE/HOS/Services/Account/Acc/AccountSaveDataManager.cs b/Ryujinx.HLE/HOS/Services/Account/Acc/AccountSaveDataManager.cs
new file mode 100644
index 0000000000..44ef3f335e
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Account/Acc/AccountSaveDataManager.cs
@@ -0,0 +1,87 @@
+using Ryujinx.Common.Configuration;
+using Ryujinx.Common.Utilities;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.IO;
+using System.Text.Json.Serialization;
+
+namespace Ryujinx.HLE.HOS.Services.Account.Acc
+{
+    class AccountSaveDataManager
+    {
+        private readonly string _profilesJsonPath = Path.Join(AppDataManager.BaseDirPath, "system", "Profiles.json");
+
+        private struct ProfilesJson
+        {
+            [JsonPropertyName("profiles")]
+            public List<UserProfileJson> Profiles { get; set; }
+            [JsonPropertyName("last_opened")]
+            public string LastOpened { get; set; }
+        }
+
+        private struct UserProfileJson
+        {
+            [JsonPropertyName("user_id")]
+            public string UserId { get; set; }
+            [JsonPropertyName("name")]
+            public string Name { get; set; }
+            [JsonPropertyName("account_state")]
+            public AccountState AccountState { get; set; }
+            [JsonPropertyName("online_play_state")]
+            public AccountState OnlinePlayState { get; set; }
+            [JsonPropertyName("last_modified_timestamp")]
+            public long LastModifiedTimestamp { get; set; }
+            [JsonPropertyName("image")]
+            public byte[] Image { get; set; }
+        }
+
+        public UserId LastOpened { get; set; }
+
+        public AccountSaveDataManager(ConcurrentDictionary<string, UserProfile> profiles)
+        {
+            // TODO: Use 0x8000000000000010 system savedata instead of a JSON file if needed.
+
+            if (File.Exists(_profilesJsonPath))
+            {
+                ProfilesJson profilesJson = JsonHelper.DeserializeFromFile<ProfilesJson>(_profilesJsonPath);
+
+                foreach (var profile in profilesJson.Profiles)
+                {
+                    UserProfile addedProfile = new UserProfile(new UserId(profile.UserId), profile.Name, profile.Image, profile.LastModifiedTimestamp);
+
+                    profiles.AddOrUpdate(profile.UserId, addedProfile, (key, old) => addedProfile);
+                }
+
+                LastOpened = new UserId(profilesJson.LastOpened);
+            }
+            else
+            {
+                LastOpened = AccountManager.DefaultUserId;
+            }
+        }
+
+        public void Save(ConcurrentDictionary<string, UserProfile> profiles)
+        {
+            ProfilesJson profilesJson = new ProfilesJson()
+            {
+                Profiles   = new List<UserProfileJson>(),
+                LastOpened = LastOpened.ToString()
+            };
+
+            foreach (var profile in profiles)
+            {
+                profilesJson.Profiles.Add(new UserProfileJson()
+                {
+                    UserId                = profile.Value.UserId.ToString(),
+                    Name                  = profile.Value.Name,
+                    AccountState          = profile.Value.AccountState,
+                    OnlinePlayState       = profile.Value.OnlinePlayState,
+                    LastModifiedTimestamp = profile.Value.LastModifiedTimestamp,
+                    Image                 = profile.Value.Image,
+                });
+            }
+
+            File.WriteAllText(_profilesJsonPath, JsonHelper.Serialize(profilesJson, true));
+        }
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Account/Acc/Types/UserProfile.cs b/Ryujinx.HLE/HOS/Services/Account/Acc/Types/UserProfile.cs
index a57796c99a..ef0a1a6452 100644
--- a/Ryujinx.HLE/HOS/Services/Account/Acc/Types/UserProfile.cs
+++ b/Ryujinx.HLE/HOS/Services/Account/Acc/Types/UserProfile.cs
@@ -8,31 +8,80 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
 
         public UserId UserId { get; }
 
-        public string Name { get; }
+        public long LastModifiedTimestamp { get; set; }
 
-        public byte[] Image { get; }
+        private string _name;
 
-        public long LastModifiedTimestamp { get; private set; }
+        public string Name
+        {
+            get => _name;
+            set
+            {
+                _name = value;
 
-        public AccountState AccountState { get; set; }
-        public AccountState OnlinePlayState { get; set; }
+                UpdateLastModifiedTimestamp();
+            }
+        }
 
-        public UserProfile(UserId userId, string name, byte[] image)
+        private byte[] _image;
+
+        public byte[] Image
+        {
+            get => _image;
+            set
+            {
+                _image = value;
+
+                UpdateLastModifiedTimestamp();
+            }
+        }
+
+        private AccountState _accountState;
+
+        public AccountState AccountState
+        {
+            get => _accountState;
+            set
+            {
+                _accountState = value;
+
+                UpdateLastModifiedTimestamp();
+            }
+        }
+
+        public AccountState _onlinePlayState;
+
+        public AccountState OnlinePlayState
+        {
+            get => _onlinePlayState;
+            set
+            {
+                _onlinePlayState = value;
+
+                UpdateLastModifiedTimestamp();
+            }
+        }
+
+        public UserProfile(UserId userId, string name, byte[] image, long lastModifiedTimestamp = 0)
         {
             UserId = userId;
             Name   = name;
-
-            Image = image;
-
-            LastModifiedTimestamp = 0;
+            Image  = image;
 
             AccountState    = AccountState.Closed;
             OnlinePlayState = AccountState.Closed;
 
-            UpdateTimestamp();
+            if (lastModifiedTimestamp != 0)
+            {
+                LastModifiedTimestamp = lastModifiedTimestamp;
+            }
+            else
+            {
+                UpdateLastModifiedTimestamp();
+            }
         }
 
-        private void UpdateTimestamp()
+        private void UpdateLastModifiedTimestamp()
         {
             LastModifiedTimestamp = (long)(DateTime.Now - Epoch).TotalSeconds;
         }
diff --git a/Ryujinx.HLE/HOS/Services/Caps/CaptureManager.cs b/Ryujinx.HLE/HOS/Services/Caps/CaptureManager.cs
index 37cc9bdab6..357815627d 100644
--- a/Ryujinx.HLE/HOS/Services/Caps/CaptureManager.cs
+++ b/Ryujinx.HLE/HOS/Services/Caps/CaptureManager.cs
@@ -1,7 +1,6 @@
 using Ryujinx.Common.Memory;
 using Ryujinx.HLE.HOS.Services.Caps.Types;
 using SixLabors.ImageSharp;
-using SixLabors.ImageSharp.Formats.Jpeg;
 using SixLabors.ImageSharp.PixelFormats;
 using System;
 using System.IO;
@@ -19,11 +18,6 @@ namespace Ryujinx.HLE.HOS.Services.Caps
         public CaptureManager(Switch device)
         {
             _sdCardPath = device.FileSystem.GetSdCardPath();
-
-            SixLabors.ImageSharp.Configuration.Default.ImageFormatsManager.SetEncoder(JpegFormat.Instance, new JpegEncoder()
-            {
-                Quality = 100
-            });
         }
 
         public ResultCode SetShimLibraryVersion(ServiceCtx context)
diff --git a/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IFriendService.cs b/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IFriendService.cs
index 1ae5d487bd..83b81e001a 100644
--- a/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IFriendService.cs
+++ b/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IFriendService.cs
@@ -150,12 +150,9 @@ namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator
                 return ResultCode.InvalidArgument;
             }
 
-            if (context.Device.System.AccountManager.TryGetUser(userId, out UserProfile profile))
-            {
-                profile.OnlinePlayState = AccountState.Open;
-            }
-
-            Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { UserId = userId.ToString(), profile.OnlinePlayState });
+            context.Device.System.AccountManager.OpenUserOnlinePlay(userId);
+            
+            Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { UserId = userId.ToString() });
 
             return ResultCode.Success;
         }
@@ -171,12 +168,9 @@ namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator
                 return ResultCode.InvalidArgument;
             }
 
-            if (context.Device.System.AccountManager.TryGetUser(userId, out UserProfile profile))
-            {
-                profile.OnlinePlayState = AccountState.Closed;
-            }
+            context.Device.System.AccountManager.CloseUserOnlinePlay(userId);
 
-            Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { UserId = userId.ToString(), profile.OnlinePlayState });
+            Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { UserId = userId.ToString() });
 
             return ResultCode.Success;
         }
diff --git a/Ryujinx/Program.cs b/Ryujinx/Program.cs
index 4df82da66a..16f3fd749e 100644
--- a/Ryujinx/Program.cs
+++ b/Ryujinx/Program.cs
@@ -8,6 +8,7 @@ using Ryujinx.Configuration;
 using Ryujinx.Modules;
 using Ryujinx.Ui;
 using Ryujinx.Ui.Widgets;
+using SixLabors.ImageSharp.Formats.Jpeg;
 using System;
 using System.IO;
 using System.Reflection;
@@ -97,6 +98,12 @@ namespace Ryujinx
             // Initialize Discord integration.
             DiscordIntegrationModule.Initialize();
 
+            // Sets ImageSharp Jpeg Encoder Quality.
+            SixLabors.ImageSharp.Configuration.Default.ImageFormatsManager.SetEncoder(JpegFormat.Instance, new JpegEncoder()
+            {
+                Quality = 100
+            });
+
             string localConfigurationPath   = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json");
             string appDataConfigurationPath = Path.Combine(AppDataManager.BaseDirPath,            "Config.json");
 
diff --git a/Ryujinx/Ui/MainWindow.cs b/Ryujinx/Ui/MainWindow.cs
index 433d23dc9a..08527ea359 100644
--- a/Ryujinx/Ui/MainWindow.cs
+++ b/Ryujinx/Ui/MainWindow.cs
@@ -78,6 +78,7 @@ namespace Ryujinx.Ui
         [GUI] Box             _footerBox;
         [GUI] Box             _statusBar;
         [GUI] MenuItem        _optionMenu;
+        [GUI] MenuItem        _manageUserProfiles;
         [GUI] MenuItem        _actionMenu;
         [GUI] MenuItem        _stopEmulation;
         [GUI] MenuItem        _simulateWakeUpMessage;
@@ -140,7 +141,7 @@ namespace Ryujinx.Ui
             // Instanciate HLE objects.
             _virtualFileSystem      = VirtualFileSystem.CreateInstance();
             _contentManager         = new ContentManager(_virtualFileSystem);
-            _accountManager         = new AccountManager();
+            _accountManager         = new AccountManager(_virtualFileSystem);
             _userChannelPersistence = new UserChannelPersistence();
 
             // Instanciate GUI objects.
@@ -155,6 +156,7 @@ namespace Ryujinx.Ui
             _applicationLibrary.ApplicationCountUpdated += ApplicationCount_Updated;
 
             _actionMenu.StateChanged += ActionMenu_StateChanged;
+            _optionMenu.StateChanged += OptionMenu_StateChanged;
 
             _gameTable.ButtonReleaseEvent += Row_Clicked;
             _fullScreen.Activated         += FullScreen_Toggled;
@@ -1192,6 +1194,11 @@ namespace Ryujinx.Ui
             SaveConfig();
         }
 
+        private void OptionMenu_StateChanged(object o, StateChangedArgs args)
+        {
+            _manageUserProfiles.Sensitive = _emulationContext == null;
+        }
+
         private void Settings_Pressed(object sender, EventArgs args)
         {
             SettingsWindow settingsWindow = new SettingsWindow(this, _virtualFileSystem, _contentManager);
@@ -1200,6 +1207,14 @@ namespace Ryujinx.Ui
             settingsWindow.Show();
         }
 
+        private void ManageUserProfiles_Pressed(object sender, EventArgs args)
+        {
+            UserProfilesManagerWindow userProfilesManagerWindow = new UserProfilesManagerWindow(_accountManager, _contentManager, _virtualFileSystem);
+
+            userProfilesManagerWindow.SetSizeRequest((int)(userProfilesManagerWindow.DefaultWidth * Program.WindowScaleFactor), (int)(userProfilesManagerWindow.DefaultHeight * Program.WindowScaleFactor));
+            userProfilesManagerWindow.Show();
+        }
+
         private void Simulate_WakeUp_Message_Pressed(object sender, EventArgs args)
         {
             if (_emulationContext != null)
diff --git a/Ryujinx/Ui/MainWindow.glade b/Ryujinx/Ui/MainWindow.glade
index beeed265a3..129b768ed5 100644
--- a/Ryujinx/Ui/MainWindow.glade
+++ b/Ryujinx/Ui/MainWindow.glade
@@ -248,6 +248,16 @@
                         <signal name="activate" handler="Settings_Pressed" swapped="no"/>
                       </object>
                     </child>
+                    <child>
+                      <object class="GtkMenuItem" id="_manageUserProfiles">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="tooltip_text" translatable="yes">Open User Profiles Manager window</property>
+                        <property name="label" translatable="yes">Manage User Profiles</property>
+                        <property name="use_underline">True</property>
+                        <signal name="activate" handler="ManageUserProfiles_Pressed" swapped="no"/>
+                      </object>
+                    </child>
                   </object>
                 </child>
               </object>
diff --git a/Ryujinx/Ui/Widgets/GameTableContextMenu.cs b/Ryujinx/Ui/Widgets/GameTableContextMenu.cs
index 4fdc666a46..eb3150cea2 100644
--- a/Ryujinx/Ui/Widgets/GameTableContextMenu.cs
+++ b/Ryujinx/Ui/Widgets/GameTableContextMenu.cs
@@ -115,7 +115,7 @@ namespace Ryujinx.Ui.Widgets
                     Logger.Warning?.Print(LogClass.Application, "No control file was found for this game. Using a dummy one instead. This may cause inaccuracies in some games.");
                 }
 
-                Uid user = new Uid(1, 0); // TODO: Remove Hardcoded value.
+                Uid user = new Uid((ulong)_accountManager.LastOpenedUser.UserId.High, (ulong)_accountManager.LastOpenedUser.UserId.Low);
 
                 result = EnsureApplicationSaveData(_virtualFileSystem.FsClient, out _, new LibHac.Ncm.ApplicationId(titleId), ref control, ref user);
 
diff --git a/Ryujinx/Ui/Widgets/GtkDialog.cs b/Ryujinx/Ui/Widgets/GtkDialog.cs
index 3d19724d6e..83f6bb2b77 100644
--- a/Ryujinx/Ui/Widgets/GtkDialog.cs
+++ b/Ryujinx/Ui/Widgets/GtkDialog.cs
@@ -1,6 +1,7 @@
 using Gtk;
 using System.Reflection;
 using Ryujinx.Common.Logging;
+using System.Collections.Generic;
 
 namespace Ryujinx.Ui.Widgets
 {
@@ -76,6 +77,34 @@ namespace Ryujinx.Ui.Widgets
             return response == ResponseType.Yes;
         }
 
+        internal static ResponseType CreateCustomDialog(string title, string mainText, string secondaryText, Dictionary<int, string> buttons, MessageType messageType = MessageType.Other)
+        {
+            GtkDialog gtkDialog = new GtkDialog(title, mainText, secondaryText, messageType, ButtonsType.None);
+
+            foreach (var button in buttons)
+            {
+                gtkDialog.AddButton(button.Value, button.Key);
+            }
+
+            return (ResponseType)gtkDialog.Run();
+        }
+
+        internal static string CreateInputDialog(Window parent, string title, string mainText, uint inputMax)
+        {
+            GtkInputDialog gtkDialog    = new GtkInputDialog(parent, title, mainText, inputMax);
+            ResponseType   response     = (ResponseType)gtkDialog.Run();
+            string         responseText = gtkDialog.InputEntry.Text.TrimEnd();
+
+            gtkDialog.Dispose();
+
+            if (response == ResponseType.Ok)
+            {
+                return responseText;
+            }
+
+            return "";
+        }
+
         internal static bool CreateExitDialog()
         {
             return CreateChoiceDialog("Ryujinx - Exit", "Are you sure you want to close Ryujinx?", "All unsaved data will be lost!");
diff --git a/Ryujinx/Ui/Widgets/GtkInputDialog.cs b/Ryujinx/Ui/Widgets/GtkInputDialog.cs
new file mode 100644
index 0000000000..21b3493733
--- /dev/null
+++ b/Ryujinx/Ui/Widgets/GtkInputDialog.cs
@@ -0,0 +1,37 @@
+using Gtk;
+
+namespace Ryujinx.Ui.Widgets
+{
+    public class GtkInputDialog : MessageDialog
+    {
+        public Entry InputEntry { get; }
+
+        public GtkInputDialog(Window parent, string title, string mainText, uint inputMax) : base(parent, DialogFlags.Modal | DialogFlags.DestroyWithParent, MessageType.Question, ButtonsType.OkCancel, null)
+        {
+            SetDefaultSize(300, 0);
+
+            Title = title;
+
+            Label mainTextLabel = new Label
+            {
+                Text = mainText
+            };
+
+            InputEntry = new Entry
+            {
+                MaxLength = (int)inputMax
+            };
+
+            Label inputMaxTextLabel = new Label
+            {
+                Text = $"(Max length: {inputMax})"
+            };
+
+            ((Box)MessageArea).PackStart(mainTextLabel,     true, true, 0);
+            ((Box)MessageArea).PackStart(InputEntry,        true, true, 5);
+            ((Box)MessageArea).PackStart(inputMaxTextLabel, true, true, 0);
+
+            ShowAll();
+        }
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx/Ui/Windows/AvatarWindow.cs b/Ryujinx/Ui/Windows/AvatarWindow.cs
new file mode 100644
index 0000000000..52e03d30b8
--- /dev/null
+++ b/Ryujinx/Ui/Windows/AvatarWindow.cs
@@ -0,0 +1,289 @@
+using Gtk;
+using LibHac.Common;
+using LibHac.Fs;
+using LibHac.Fs.Fsa;
+using LibHac.FsSystem;
+using LibHac.FsSystem.NcaUtils;
+using Ryujinx.HLE.FileSystem;
+using Ryujinx.HLE.FileSystem.Content;
+using SixLabors.ImageSharp;
+using SixLabors.ImageSharp.Formats.Png;
+using SixLabors.ImageSharp.PixelFormats;
+using SixLabors.ImageSharp.Processing;
+using System;
+using System.Buffers.Binary;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+
+using Image = SixLabors.ImageSharp.Image;
+
+namespace Ryujinx.Ui.Windows
+{
+    public class AvatarWindow : Window
+    {
+        public byte[] SelectedProfileImage;
+        public bool   NewUser;
+
+        private static Dictionary<string, byte[]> _avatarDict = new Dictionary<string, byte[]>();
+
+        private ListStore _listStore;
+        private IconView  _iconView;
+        private Button    _setBackgroungColorButton;
+        private Gdk.RGBA  _backgroundColor;
+
+        public AvatarWindow() : base($"Ryujinx {Program.Version} - Manage Accounts - Avatar")
+        {
+            Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.Resources.Logo_Ryujinx.png");
+
+            CanFocus  = false;
+            Resizable = false;
+            Modal     = true;
+            TypeHint  = Gdk.WindowTypeHint.Dialog;
+
+            SetDefaultSize(740, 400);
+            SetPosition(WindowPosition.Center);
+
+            VBox vbox = new VBox(false, 0);
+            Add(vbox);
+
+            ScrolledWindow scrolledWindow = new ScrolledWindow
+            {
+                ShadowType = ShadowType.EtchedIn
+            };
+            scrolledWindow.SetPolicy(PolicyType.Automatic, PolicyType.Automatic);
+
+            HBox hbox = new HBox(false, 0);
+
+            Button chooseButton = new Button()
+            {
+                Label           = "Choose",
+                CanFocus        = true,
+                ReceivesDefault = true
+            };
+            chooseButton.Clicked += ChooseButton_Pressed;
+
+            _setBackgroungColorButton = new Button()
+            {
+                Label    = "Set Background Color",
+                CanFocus = true
+            };
+            _setBackgroungColorButton.Clicked += SetBackgroungColorButton_Pressed;
+
+            _backgroundColor.Red   = 1;
+            _backgroundColor.Green = 1;
+            _backgroundColor.Blue  = 1;
+            _backgroundColor.Alpha = 1;
+
+            Button closeButton = new Button()
+            {
+                Label           = "Close",
+                CanFocus        = true
+            };
+            closeButton.Clicked += CloseButton_Pressed;
+
+            vbox.PackStart(scrolledWindow,            true,  true,  0);
+            hbox.PackStart(chooseButton,              true,  true,  0);
+            hbox.PackStart(_setBackgroungColorButton, true,  true,  0);
+            hbox.PackStart(closeButton,               true,  true,  0);
+            vbox.PackStart(hbox,                      false, false, 0);
+
+            _listStore = new ListStore(typeof(string), typeof(Gdk.Pixbuf));
+            _listStore.SetSortColumnId(0, SortType.Ascending);
+
+            _iconView              = new IconView(_listStore);
+            _iconView.ItemWidth    = 64;
+            _iconView.ItemPadding  = 10;
+            _iconView.PixbufColumn = 1;
+
+            _iconView.SelectionChanged += IconView_SelectionChanged;
+
+            scrolledWindow.Add(_iconView);
+
+            _iconView.GrabFocus();
+
+            ProcessAvatars();
+
+            ShowAll();
+        }
+
+        public static void PreloadAvatars(ContentManager contentManager, VirtualFileSystem virtualFileSystem)
+        {
+            if (_avatarDict.Count > 0)
+            {
+                return;
+            }
+
+            string contentPath = contentManager.GetInstalledContentPath(0x010000000000080A, StorageId.NandSystem, NcaContentType.Data);
+            string avatarPath  = virtualFileSystem.SwitchPathToSystemPath(contentPath);
+
+            if (!string.IsNullOrWhiteSpace(avatarPath))
+            {
+                using (IStorage ncaFileStream = new LocalStorage(avatarPath, FileAccess.Read, FileMode.Open))
+                {
+                    Nca         nca   = new Nca(virtualFileSystem.KeySet, ncaFileStream);
+                    IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid);
+
+                    foreach (var item in romfs.EnumerateEntries())
+                    {
+                        // TODO: Parse DatabaseInfo.bin and table.bin files for more accuracy.
+
+                        if (item.Type == DirectoryEntryType.File && item.FullPath.Contains("chara") && item.FullPath.Contains("szs"))
+                        {
+                            romfs.OpenFile(out IFile file, ("/" + item.FullPath).ToU8Span(), OpenMode.Read).ThrowIfFailure();
+
+                            using (MemoryStream stream    = new MemoryStream())
+                            using (MemoryStream streamPng = new MemoryStream())
+                            {
+                                file.AsStream().CopyTo(stream);
+
+                                stream.Position = 0;
+
+                                Image avatarImage = Image.LoadPixelData<Rgba32>(DecompressYaz0(stream), 256, 256);
+
+                                avatarImage.SaveAsPng(streamPng);
+
+                                _avatarDict.Add(item.FullPath, streamPng.ToArray());
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        private void ProcessAvatars()
+        {
+            _listStore.Clear();
+
+            foreach (var avatar in _avatarDict)
+            {
+                _listStore.AppendValues(avatar.Key, new Gdk.Pixbuf(ProcessImage(avatar.Value), 96, 96));
+            }
+
+            _iconView.SelectPath(new TreePath(new int[] { 0 }));
+        }
+
+        private byte[] ProcessImage(byte[] data)
+        {
+            using (MemoryStream streamJpg = new MemoryStream())
+            {
+                Image avatarImage = Image.Load(data, new PngDecoder());
+
+                avatarImage.Mutate(x => x.BackgroundColor(new Rgba32((byte)(_backgroundColor.Red   * 255),
+                                                                     (byte)(_backgroundColor.Green * 255),
+                                                                     (byte)(_backgroundColor.Blue  * 255),
+                                                                     (byte)(_backgroundColor.Alpha * 255))));
+                avatarImage.SaveAsJpeg(streamJpg);
+
+                return streamJpg.ToArray();
+            }
+        }
+
+        private void CloseButton_Pressed(object sender, EventArgs e)
+        {
+            SelectedProfileImage = null;
+
+            Close();
+        }
+
+        private void IconView_SelectionChanged(object sender, EventArgs e)
+        {
+            if (_iconView.SelectedItems.Length > 0)
+            {
+                _listStore.GetIter(out TreeIter iter, _iconView.SelectedItems[0]);
+
+                SelectedProfileImage = ProcessImage(_avatarDict[(string)_listStore.GetValue(iter, 0)]);
+            }
+        }
+
+        private void SetBackgroungColorButton_Pressed(object sender, EventArgs e)
+        {
+            using (ColorChooserDialog colorChooserDialog = new ColorChooserDialog("Set Background Color", this))
+            {
+                colorChooserDialog.UseAlpha = false;
+                colorChooserDialog.Rgba     = _backgroundColor;
+                
+                if (colorChooserDialog.Run() == (int)ResponseType.Ok)
+                {
+                    _backgroundColor = colorChooserDialog.Rgba;
+
+                    ProcessAvatars();
+                }
+
+                colorChooserDialog.Hide();
+            }
+        }
+
+        private void ChooseButton_Pressed(object sender, EventArgs e)
+        {
+            Close();
+        }
+
+        private static byte[] DecompressYaz0(Stream stream)
+        {
+            using (BinaryReader reader = new BinaryReader(stream))
+            {
+                reader.ReadInt32(); // Magic
+                
+                uint decodedLength = BinaryPrimitives.ReverseEndianness(reader.ReadUInt32());
+
+                reader.ReadInt64(); // Padding
+
+                byte[] input = new byte[stream.Length - stream.Position];
+                stream.Read(input, 0, input.Length);
+
+                long inputOffset = 0;
+
+                byte[] output       = new byte[decodedLength];
+                long   outputOffset = 0;
+
+                ushort mask   = 0;
+                byte   header = 0;
+
+                while (outputOffset < decodedLength)
+                {
+                    if ((mask >>= 1) == 0)
+                    {
+                        header = input[inputOffset++];
+                        mask   = 0x80;
+                    }
+
+                    if ((header & mask) > 0)
+                    {
+                        if (outputOffset == output.Length)
+                        {
+                            break;
+                        }
+
+                        output[outputOffset++] = input[inputOffset++];
+                    }
+                    else
+                    {
+                        byte byte1 = input[inputOffset++];
+                        byte byte2 = input[inputOffset++];
+
+                        int dist     = ((byte1 & 0xF) << 8) | byte2;
+                        int position = (int)outputOffset - (dist + 1);
+
+                        int length = byte1 >> 4;
+                        if (length == 0)
+                        {
+                            length = input[inputOffset++] + 0x12;
+                        }
+                        else
+                        {
+                            length += 2;
+                        }
+
+                        while (length-- > 0)
+                        {
+                            output[outputOffset++] = output[position++];
+                        }
+                    }
+                }
+
+                return output;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx/Ui/Windows/UserProfilesManagerWindow.Designer.cs b/Ryujinx/Ui/Windows/UserProfilesManagerWindow.Designer.cs
new file mode 100644
index 0000000000..7029129059
--- /dev/null
+++ b/Ryujinx/Ui/Windows/UserProfilesManagerWindow.Designer.cs
@@ -0,0 +1,255 @@
+using Gtk;
+using Pango;
+
+namespace Ryujinx.Ui.Windows
+{
+    public partial class UserProfilesManagerWindow : Window
+    {
+        private Box            _mainBox;
+        private Label          _selectedLabel;
+        private Box            _selectedUserBox;
+        private Image          _selectedUserImage;
+        private VBox           _selectedUserInfoBox;
+        private Entry          _selectedUserNameEntry;
+        private Label          _selectedUserIdLabel;
+        private VBox           _selectedUserButtonsBox;
+        private Button         _saveProfileNameButton;
+        private Button         _changeProfileImageButton;
+        private Box            _usersTreeViewBox;
+        private Label          _availableUsersLabel;
+        private ScrolledWindow _usersTreeViewWindow;
+        private ListStore      _tableStore;
+        private TreeView       _usersTreeView;
+        private Box            _bottomBox;
+        private Button         _addButton;
+        private Button         _deleteButton;
+        private Button         _closeButton;
+
+        private void InitializeComponent()
+        {
+
+#pragma warning disable CS0612
+
+            //
+            // UserProfilesManagerWindow
+            //
+            CanFocus       = false;
+            Resizable      = false;
+            Modal          = true;
+            WindowPosition = WindowPosition.Center;
+            DefaultWidth   = 620;
+            DefaultHeight  = 548;
+            TypeHint       = Gdk.WindowTypeHint.Dialog;
+
+            //
+            // _mainBox
+            //
+            _mainBox = new Box(Orientation.Vertical, 0);
+
+            //
+            // _selectedLabel
+            //
+            _selectedLabel = new Label("Selected User Profile:")
+            {
+                Margin     = 15,
+                Attributes = new AttrList()
+            };
+            _selectedLabel.Attributes.Insert(new Pango.AttrWeight(Weight.Bold));
+
+            //
+            // _viewBox
+            //
+            _usersTreeViewBox = new Box(Orientation.Vertical, 0);
+
+            //
+            // _SelectedUserBox
+            //
+            _selectedUserBox = new Box(Orientation.Horizontal, 0)
+            {
+                MarginLeft = 30
+            };
+
+            //
+            // _selectedUserImage
+            //
+            _selectedUserImage = new Image();
+
+            //
+            // _selectedUserInfoBox
+            //
+            _selectedUserInfoBox = new VBox(true, 0);
+
+            //
+            // _selectedUserNameEntry
+            //
+            _selectedUserNameEntry = new Entry("")
+            {
+                MarginLeft = 15,
+                MaxLength  = (int)MaxProfileNameLength
+            };
+            _selectedUserNameEntry.KeyReleaseEvent += SelectedUserNameEntry_KeyReleaseEvent;
+
+            //
+            // _selectedUserIdLabel
+            //
+            _selectedUserIdLabel = new Label("")
+            {
+                MarginTop  = 15,
+                MarginLeft = 15
+            };
+
+            //
+            // _selectedUserButtonsBox
+            //
+            _selectedUserButtonsBox = new VBox()
+            {
+                MarginRight = 30
+            };
+
+            //
+            // _saveProfileNameButton
+            //
+            _saveProfileNameButton = new Button()
+            {
+                Label           = "Save Profile Name",
+                CanFocus        = true,
+                ReceivesDefault = true,
+                Sensitive       = false
+            };
+            _saveProfileNameButton.Clicked += EditProfileNameButton_Pressed;
+
+            //
+            // _changeProfileImageButton
+            //
+            _changeProfileImageButton = new Button()
+            {
+                Label           = "Change Profile Image",
+                CanFocus        = true,
+                ReceivesDefault = true,
+                MarginTop       = 10
+            };
+            _changeProfileImageButton.Clicked += ChangeProfileImageButton_Pressed;
+
+            //
+            // _availableUsersLabel
+            //
+            _availableUsersLabel = new Label("Available User Profiles:")
+            {
+                Margin     = 15,
+                Attributes = new AttrList()
+            };
+            _availableUsersLabel.Attributes.Insert(new Pango.AttrWeight(Weight.Bold));
+
+            //
+            // _usersTreeViewWindow
+            //
+            _usersTreeViewWindow = new ScrolledWindow()
+            {
+                ShadowType   = ShadowType.In,
+                CanFocus     = true,
+                Expand       = true,
+                MarginLeft   = 30,
+                MarginRight  = 30,
+                MarginBottom = 15
+            };
+
+            //
+            // _tableStore
+            //
+            _tableStore = new ListStore(typeof(bool), typeof(Gdk.Pixbuf), typeof(string), typeof(Gdk.RGBA));
+
+            //
+            // _usersTreeView
+            //
+            _usersTreeView = new TreeView(_tableStore)
+            {
+                HoverSelection = true,
+                HeadersVisible = false,
+            };
+            _usersTreeView.RowActivated += UsersTreeView_Activated;
+
+            //
+            // _bottomBox
+            //
+            _bottomBox = new Box(Orientation.Horizontal, 0)
+            {
+                MarginLeft   = 30,
+                MarginRight  = 30,
+                MarginBottom = 15
+            };
+
+            //
+            // _addButton
+            //
+            _addButton = new Button()
+            {
+                Label           = "Add New Profile",
+                CanFocus        = true,
+                ReceivesDefault = true,
+                HeightRequest   = 35
+            };
+            _addButton.Clicked += AddButton_Pressed;
+
+            //
+            // _deleteButton
+            //
+            _deleteButton = new Button()
+            {
+                Label           = "Delete Selected Profile",
+                CanFocus        = true,
+                ReceivesDefault = true,
+                HeightRequest   = 35,
+                MarginLeft      = 10
+            };
+            _deleteButton.Clicked += DeleteButton_Pressed;
+
+            //
+            // _closeButton
+            //
+            _closeButton = new Button()
+            {
+                Label           = "Close",
+                CanFocus        = true,
+                ReceivesDefault = true,
+                HeightRequest   = 35,
+                WidthRequest    = 80
+            };
+            _closeButton.Clicked += CloseButton_Pressed;
+
+#pragma warning restore CS0612
+
+            ShowComponent();
+        }
+
+        private void ShowComponent()
+        {
+            _usersTreeViewWindow.Add(_usersTreeView);
+
+            _usersTreeViewBox.Add(_usersTreeViewWindow);
+
+            _bottomBox.PackStart(new Gtk.Alignment(-1, 0, 0, 0) { _addButton }, false, false, 0);
+            _bottomBox.PackStart(new Gtk.Alignment(-1, 0, 0, 0) { _deleteButton }, false, false, 0);
+            _bottomBox.PackEnd(new Gtk.Alignment(1, 0, 0, 0) { _closeButton }, false, false, 0);
+
+            _selectedUserInfoBox.Add(_selectedUserNameEntry);
+            _selectedUserInfoBox.Add(_selectedUserIdLabel);
+
+            _selectedUserButtonsBox.Add(_saveProfileNameButton);
+            _selectedUserButtonsBox.Add(_changeProfileImageButton);
+
+            _selectedUserBox.Add(_selectedUserImage);
+            _selectedUserBox.PackStart(new Gtk.Alignment(-1, 0, 0, 0) { _selectedUserInfoBox }, true, true, 0);
+            _selectedUserBox.Add(_selectedUserButtonsBox);
+
+            _mainBox.PackStart(new Gtk.Alignment(-1, 0, 0, 0) { _selectedLabel }, false, false, 0);
+            _mainBox.PackStart(_selectedUserBox, false, true, 0);
+            _mainBox.PackStart(new Gtk.Alignment(-1, 0, 0, 0) { _availableUsersLabel }, false, false, 0);
+            _mainBox.Add(_usersTreeViewBox);
+            _mainBox.Add(_bottomBox);
+
+            Add(_mainBox);
+
+            ShowAll();
+        }
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx/Ui/Windows/UserProfilesManagerWindow.cs b/Ryujinx/Ui/Windows/UserProfilesManagerWindow.cs
new file mode 100644
index 0000000000..6a4788b153
--- /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