From 934b5a64e5638ae5228acb52faf48efadefdea8d Mon Sep 17 00:00:00 2001
From: Isaac Marovitz <42140194+IsaacMarovitz@users.noreply.github.com>
Date: Wed, 11 Jan 2023 00:20:19 -0500
Subject: [PATCH] Ava GUI: User Profile Manager + Other Fixes (#4166)

* Fix redundancies

* Add back elses

* Loading Screen fixes

* Redesign User Profile Manager

- Backported long selection bar in Grid/List view not working
- Backported UserSelector is jank

* Fix SelectionIndicator

* Fix DataType

* Fix SaveManager bug

* Remove debug log

* Load saves on UIThread

* Reduce UI thread blocking

* Fix locale keys

* Use block namespaces

* Fix close button width

* Make UserProfile ordering consistent

* Alphabetical order

* Adjust layout, remove green circle for blue selector

* Fix some inconsistencies

* Fix no inital selected profile

* Adjust appearance of edit button

* Adjust SaveManager

* Remove redundant warning dialog

* Make firmware avatar selector clearer

* View redesign again :hero_depressed:

* Consistency adjustments

* Adjust margins

* Make `UserProfileImageSelector` consistent

* Make `UserFirmwareAvatarSelector` consistent

* Fix long grid view selector

* Switch case

* Remove long selection bar

Handled in #4178

* Consistency

* Started dialog titles

* Fixes

* Remaining titles

* Update Ryujinx.Ava/UI/Controls/NavigationDialogHost.axaml

Co-authored-by: Mary-nyan <thog@protonmail.com>

* Fix build

* Hide UserRecoverer if no LostProfiles are found

* UserEditor Avatar Placeholder

* Watermark + locale adjustment

* Border radius

* Remove unnecessary styles

* Fix firmware avatar image order

* Cleanup `ColorPickerButton`

* Make `UserId` copy/paste able

* Make `FirmwareAvatarSelector` 6 images wide

* Make selection bar better

* Unsaved changes dialogue

* Fix indentation

* Remove extra check

* Address suggestions

* Reorganise

- Remove unused views
- Rename views to match convention
- Fix weird namespacing

* Update Ryujinx.Ava/UI/Views/User/UserFirmwareAvatarSelectorView.axaml

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* Update Ryujinx.Ava/UI/Views/User/UserFirmwareAvatarSelectorView.axaml

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* UserRecovererView empty placeholder

* Update Ryujinx.Ava/UI/Views/User/UserSelectorView.axaml.cs

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* Update Ryujinx.Ava/UI/Views/User/UserSaveManagerView.axaml.cs

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* Update Ryujinx.Ava/UI/Views/User/UserSaveManagerView.axaml.cs

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* Update Ryujinx.Ava/UI/Views/User/UserSaveManagerView.axaml.cs

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* Update Ryujinx.Ava/UI/Views/User/UserRecovererView.axaml.cs

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* Update Ryujinx.Ava/UI/Views/User/UserFirmwareAvatarSelectorView.axaml.cs

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* Update Ryujinx.Ava/UI/ViewModels/UserFirmwareAvatarSelectorViewModel.cs

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* Update Ryujinx.Ava/UI/ViewModels/UserFirmwareAvatarSelectorViewModel.cs

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* Update Ryujinx.Ava/UI/ViewModels/UserFirmwareAvatarSelectorViewModel.cs

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* Update Ryujinx.Ava/UI/Models/UserProfile.cs

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* Update Ryujinx.Ava/UI/Controls/NavigationDialogHost.axaml.cs

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* Update Ryujinx.Ava/UI/Controls/NavigationDialogHost.axaml.cs

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* Remove AddModel

* Update Ryujinx.Ava/Assets/Locales/en_US.json

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* Fix bug

Co-authored-by: Mary-nyan <thog@protonmail.com>
Co-authored-by: Ac_K <Acoustik666@gmail.com>
---
 Ryujinx.Ava/Assets/Locales/de_DE.json         |   2 +-
 Ryujinx.Ava/Assets/Locales/el_GR.json         |   2 +-
 Ryujinx.Ava/Assets/Locales/en_US.json         |  18 +-
 Ryujinx.Ava/Assets/Locales/es_ES.json         |   2 +-
 Ryujinx.Ava/Assets/Locales/fr_FR.json         |   2 +-
 Ryujinx.Ava/Assets/Locales/ja_JP.json         |   2 +-
 Ryujinx.Ava/Assets/Locales/pl_PL.json         |   2 +-
 Ryujinx.Ava/Assets/Locales/pt_BR.json         |   2 +-
 Ryujinx.Ava/Assets/Locales/ru_RU.json         |   2 +-
 Ryujinx.Ava/Assets/Locales/tr_TR.json         |   2 +-
 Ryujinx.Ava/Assets/Locales/zh_TW.json         |   2 +-
 Ryujinx.Ava/Assets/Styles/Styles.xaml         |  32 +++
 Ryujinx.Ava/Program.cs                        |   2 +-
 Ryujinx.Ava/Ryujinx.Ava.csproj                |  12 +
 Ryujinx.Ava/UI/Controls/GameGridView.axaml    |  24 --
 Ryujinx.Ava/UI/Controls/GameListView.axaml    |  29 ---
 .../UI/Controls/NavigationDialogHost.axaml    |   3 +-
 .../UI/Controls/NavigationDialogHost.axaml.cs | 139 ++++++++++-
 .../ProfileImageSelectionDialog.axaml         |  57 -----
 Ryujinx.Ava/UI/Controls/SaveManager.axaml     | 175 -------------
 Ryujinx.Ava/UI/Controls/SaveManager.axaml.cs  | 160 ------------
 Ryujinx.Ava/UI/Controls/UserRecoverer.axaml   |  72 ------
 .../UI/Controls/UserRecoverer.axaml.cs        |  44 ----
 Ryujinx.Ava/UI/Controls/UserSelector.axaml    | 145 -----------
 Ryujinx.Ava/UI/Controls/UserSelector.axaml.cs |  77 ------
 Ryujinx.Ava/UI/Helpers/EmbeddedWindow.cs      |   5 +-
 .../{Helper => UI/Helpers}/LoggerAdapter.cs   |   2 +-
 .../{Helper => UI/Helpers}/MetalHelper.cs     |   2 +-
 Ryujinx.Ava/UI/Models/ProfileImageModel.cs    |  20 +-
 Ryujinx.Ava/UI/Models/SaveModel.cs            |  24 --
 Ryujinx.Ava/UI/Models/TempProfile.cs          |   9 +-
 Ryujinx.Ava/UI/Models/UserProfile.cs          |  42 +++-
 .../UserFirmwareAvatarSelectorViewModel.cs    | 230 ++++++++++++++++++
 .../UserProfileImageSelectorViewModel.cs      |  18 ++
 .../UI/ViewModels/UserProfileViewModel.cs     | 200 +--------------
 .../UI/ViewModels/UserSaveManagerViewModel.cs | 123 ++++++++++
 .../User/UserEditorView.axaml}                | 109 ++++++---
 .../User/UserEditorView.axaml.cs}             |  81 ++++--
 .../User/UserFirmwareAvatarSelectorView.axaml | 114 +++++++++
 .../UserFirmwareAvatarSelectorView.axaml.cs}  |  35 ++-
 .../User/UserProfileImageSelectorView.axaml   |  63 +++++
 .../UserProfileImageSelectorView.axaml.cs}    |  43 +++-
 .../UI/Views/User/UserRecovererView.axaml     |  83 +++++++
 .../UI/Views/User/UserRecovererView.axaml.cs  |  51 ++++
 .../UI/Views/User/UserSaveManagerView.axaml   | 199 +++++++++++++++
 .../Views/User/UserSaveManagerView.axaml.cs   | 148 +++++++++++
 .../UI/Views/User/UserSelectorView.axaml      | 165 +++++++++++++
 .../UI/Views/User/UserSelectorView.axaml.cs   | 128 ++++++++++
 Ryujinx.Ava/UI/Windows/AvatarWindow.axaml     |  54 ----
 49 files changed, 1787 insertions(+), 1170 deletions(-)
 delete mode 100644 Ryujinx.Ava/UI/Controls/ProfileImageSelectionDialog.axaml
 delete mode 100644 Ryujinx.Ava/UI/Controls/SaveManager.axaml
 delete mode 100644 Ryujinx.Ava/UI/Controls/SaveManager.axaml.cs
 delete mode 100644 Ryujinx.Ava/UI/Controls/UserRecoverer.axaml
 delete mode 100644 Ryujinx.Ava/UI/Controls/UserRecoverer.axaml.cs
 delete mode 100644 Ryujinx.Ava/UI/Controls/UserSelector.axaml
 delete mode 100644 Ryujinx.Ava/UI/Controls/UserSelector.axaml.cs
 rename Ryujinx.Ava/{Helper => UI/Helpers}/LoggerAdapter.cs (99%)
 rename Ryujinx.Ava/{Helper => UI/Helpers}/MetalHelper.cs (99%)
 create mode 100644 Ryujinx.Ava/UI/ViewModels/UserFirmwareAvatarSelectorViewModel.cs
 create mode 100644 Ryujinx.Ava/UI/ViewModels/UserProfileImageSelectorViewModel.cs
 create mode 100644 Ryujinx.Ava/UI/ViewModels/UserSaveManagerViewModel.cs
 rename Ryujinx.Ava/UI/{Controls/UserEditor.axaml => Views/User/UserEditorView.axaml} (52%)
 rename Ryujinx.Ava/UI/{Controls/UserEditor.axaml.cs => Views/User/UserEditorView.axaml.cs} (52%)
 create mode 100644 Ryujinx.Ava/UI/Views/User/UserFirmwareAvatarSelectorView.axaml
 rename Ryujinx.Ava/UI/{Windows/AvatarWindow.axaml.cs => Views/User/UserFirmwareAvatarSelectorView.axaml.cs} (55%)
 create mode 100644 Ryujinx.Ava/UI/Views/User/UserProfileImageSelectorView.axaml
 rename Ryujinx.Ava/UI/{Controls/ProfileImageSelectionDialog.axaml.cs => Views/User/UserProfileImageSelectorView.axaml.cs} (69%)
 create mode 100644 Ryujinx.Ava/UI/Views/User/UserRecovererView.axaml
 create mode 100644 Ryujinx.Ava/UI/Views/User/UserRecovererView.axaml.cs
 create mode 100644 Ryujinx.Ava/UI/Views/User/UserSaveManagerView.axaml
 create mode 100644 Ryujinx.Ava/UI/Views/User/UserSaveManagerView.axaml.cs
 create mode 100644 Ryujinx.Ava/UI/Views/User/UserSelectorView.axaml
 create mode 100644 Ryujinx.Ava/UI/Views/User/UserSelectorView.axaml.cs
 delete mode 100644 Ryujinx.Ava/UI/Windows/AvatarWindow.axaml

diff --git a/Ryujinx.Ava/Assets/Locales/de_DE.json b/Ryujinx.Ava/Assets/Locales/de_DE.json
index 671f369e78..4d656bc99e 100644
--- a/Ryujinx.Ava/Assets/Locales/de_DE.json
+++ b/Ryujinx.Ava/Assets/Locales/de_DE.json
@@ -260,7 +260,7 @@
   "UserProfilesChangeProfileImage": "Profilbild ändern",
   "UserProfilesAvailableUserProfiles": "Verfügbare Profile:",
   "UserProfilesAddNewProfile": "Neues Profil",
-  "UserProfilesDeleteSelectedProfile": "Profil löschen",
+  "UserProfilesDelete": "Löschen",
   "UserProfilesClose": "Schließen",
   "ProfileImageSelectionTitle": "Auswahl des Profilbildes",
   "ProfileImageSelectionHeader": "Wähle ein Profilbild aus",
diff --git a/Ryujinx.Ava/Assets/Locales/el_GR.json b/Ryujinx.Ava/Assets/Locales/el_GR.json
index 5cd7a55401..ca3be8b9ad 100644
--- a/Ryujinx.Ava/Assets/Locales/el_GR.json
+++ b/Ryujinx.Ava/Assets/Locales/el_GR.json
@@ -260,7 +260,7 @@
   "UserProfilesChangeProfileImage": "Αλλαγή Εικόνας Προφίλ",
   "UserProfilesAvailableUserProfiles": "Διαθέσιμα Προφίλ Χρηστών:",
   "UserProfilesAddNewProfile": "Προσθήκη Νέου Προφίλ",
-  "UserProfilesDeleteSelectedProfile": "Διαγραφή Επιλεγμένου Προφίλ",
+  "UserProfilesDelete": "Διαγράφω",
   "UserProfilesClose": "Κλείσιμο",
   "ProfileImageSelectionTitle": "Επιλογή Εικόνας Προφίλ",
   "ProfileImageSelectionHeader": "Επιλέξτε μία Εικόνα Προφίλ",
diff --git a/Ryujinx.Ava/Assets/Locales/en_US.json b/Ryujinx.Ava/Assets/Locales/en_US.json
index 46203463ac..0c767871ba 100644
--- a/Ryujinx.Ava/Assets/Locales/en_US.json
+++ b/Ryujinx.Ava/Assets/Locales/en_US.json
@@ -260,8 +260,9 @@
   "UserProfilesChangeProfileImage": "Change Profile Image",
   "UserProfilesAvailableUserProfiles": "Available User Profiles:",
   "UserProfilesAddNewProfile": "Create Profile",
-  "UserProfilesDeleteSelectedProfile": "Delete Selected",
+  "UserProfilesDelete": "Delete",
   "UserProfilesClose": "Close",
+  "ProfileNameSelectionWatermark": "Choose a nickname",
   "ProfileImageSelectionTitle": "Profile Image Selection",
   "ProfileImageSelectionHeader": "Choose a profile Image",
   "ProfileImageSelectionNote": "You may import a custom profile image, or select an avatar from system firmware",
@@ -273,7 +274,7 @@
   "InputDialogAddNewProfileTitle": "Choose the Profile Name",
   "InputDialogAddNewProfileHeader": "Please Enter a Profile Name",
   "InputDialogAddNewProfileSubtext": "(Max Length: {0})",
-  "AvatarChoose": "Choose",
+  "AvatarChoose": "Choose Avatar",
   "AvatarSetBackgroundColor": "Set Background Color",
   "AvatarClose": "Close",
   "ControllerSettingsLoadProfileToolTip": "Load Profile",
@@ -368,6 +369,9 @@
   "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "System version {0} successfully installed.",
   "DialogUserProfileDeletionWarningMessage": "There would be no other profiles to be opened if selected profile is deleted",
   "DialogUserProfileDeletionConfirmMessage": "Do you want to delete the selected profile",
+  "DialogUserProfileUnsavedChangesTitle": "Warning - Unsaved Changes",
+  "DialogUserProfileUnsavedChangesMessage": "You have made changes to this user profile that have not been saved.",
+  "DialogUserProfileUnsavedChangesSubMessage": "Do you want to discard your changes?",
   "DialogControllerSettingsModifiedConfirmMessage": "The current controller settings has been updated.",
   "DialogControllerSettingsModifiedConfirmSubMessage": "Do you want to save?",
   "DialogDlcLoadNcaErrorMessage": "{0}. Errored File: {1}",
@@ -584,7 +588,7 @@
   "SettingsTabHotkeysResScaleUpHotkey": "Increase resolution:",
   "SettingsTabHotkeysResScaleDownHotkey": "Decrease resolution:",
   "UserProfilesName": "Name:",
-  "UserProfilesUserId": "User Id:",
+  "UserProfilesUserId": "User ID:",
   "SettingsTabGraphicsBackend": "Graphics Backend",
   "SettingsTabGraphicsBackendTooltip": "Graphics Backend to use",
   "SettingsEnableTextureRecompression": "Enable Texture Recompression",
@@ -603,13 +607,15 @@
   "UserProfilesManageSaves": "Manage Saves",
   "DeleteUserSave": "Do you want to delete user save for this game?",
   "IrreversibleActionNote": "This action is not reversible.",
-  "SaveManagerHeading": "Manage Saves for {0}",
+  "SaveManagerHeading": "Manage Saves for {0} ({1})",
   "SaveManagerTitle": "Save Manager",
   "Name": "Name",
   "Size": "Size",
   "Search": "Search",
   "UserProfilesRecoverLostAccounts": "Recover Lost Accounts",
   "Recover": "Recover",
-  "UserProfilesRecoverHeading" : "Saves were found for the following accounts"
+  "UserProfilesRecoverHeading" : "Saves were found for the following accounts",
+  "UserProfilesRecoverEmptyList": "No profiles to recover",
+  "UserEditorTitle" : "Edit User",
+  "UserEditorTitleCreate" : "Create User"
 }
-
diff --git a/Ryujinx.Ava/Assets/Locales/es_ES.json b/Ryujinx.Ava/Assets/Locales/es_ES.json
index 1922318d0a..660d62a1eb 100644
--- a/Ryujinx.Ava/Assets/Locales/es_ES.json
+++ b/Ryujinx.Ava/Assets/Locales/es_ES.json
@@ -260,7 +260,7 @@
   "UserProfilesChangeProfileImage": "Cambiar imagen de perfil",
   "UserProfilesAvailableUserProfiles": "Perfiles de usuario disponibles:",
   "UserProfilesAddNewProfile": "Añadir nuevo perfil",
-  "UserProfilesDeleteSelectedProfile": "Eliminar perfil seleccionado",
+  "UserProfilesDelete": "Eliminar",
   "UserProfilesClose": "Cerrar",
   "ProfileImageSelectionTitle": "Selección de imagen de perfil",
   "ProfileImageSelectionHeader": "Elige una imagen de perfil",
diff --git a/Ryujinx.Ava/Assets/Locales/fr_FR.json b/Ryujinx.Ava/Assets/Locales/fr_FR.json
index 938d0cc77f..71f32c6ee6 100644
--- a/Ryujinx.Ava/Assets/Locales/fr_FR.json
+++ b/Ryujinx.Ava/Assets/Locales/fr_FR.json
@@ -260,7 +260,7 @@
   "UserProfilesChangeProfileImage": "Changer l'image du profil",
   "UserProfilesAvailableUserProfiles": "Profils utilisateurs disponible:",
   "UserProfilesAddNewProfile": "Ajouter un nouveau profil",
-  "UserProfilesDeleteSelectedProfile": "Supprimer le profil sélectionné",
+  "UserProfilesDelete": "Supprimer",
   "UserProfilesClose": "Fermer",
   "ProfileImageSelectionTitle": "Sélection de l'image du profil",
   "ProfileImageSelectionHeader": "Choisir l'image du profil",
diff --git a/Ryujinx.Ava/Assets/Locales/ja_JP.json b/Ryujinx.Ava/Assets/Locales/ja_JP.json
index c88477f968..b1e0a43bf5 100644
--- a/Ryujinx.Ava/Assets/Locales/ja_JP.json
+++ b/Ryujinx.Ava/Assets/Locales/ja_JP.json
@@ -260,7 +260,7 @@
   "UserProfilesChangeProfileImage": "プロファイル画像を変更",
   "UserProfilesAvailableUserProfiles": "利用可能なユーザプロファイル:",
   "UserProfilesAddNewProfile": "プロファイルを作成",
-  "UserProfilesDeleteSelectedProfile": "削除",
+  "UserProfilesDelete": "削除",
   "UserProfilesClose": "閉じる",
   "ProfileImageSelectionTitle": "プロファイル画像選択",
   "ProfileImageSelectionHeader": "プロファイル画像を選択",
diff --git a/Ryujinx.Ava/Assets/Locales/pl_PL.json b/Ryujinx.Ava/Assets/Locales/pl_PL.json
index 3c1b541edb..0cc0b4f917 100644
--- a/Ryujinx.Ava/Assets/Locales/pl_PL.json
+++ b/Ryujinx.Ava/Assets/Locales/pl_PL.json
@@ -260,7 +260,7 @@
   "UserProfilesChangeProfileImage": "Zmień Obraz Profilu",
   "UserProfilesAvailableUserProfiles": "Dostępne Profile Użytkowników:",
   "UserProfilesAddNewProfile": "Utwórz Profil",
-  "UserProfilesDeleteSelectedProfile": "Usuń Zaznaczone",
+  "UserProfilesDelete": "Usuwać",
   "UserProfilesClose": "Zamknij",
   "ProfileImageSelectionTitle": "Wybór Obrazu Profilu",
   "ProfileImageSelectionHeader": "Wybierz zdjęcie profilowe",
diff --git a/Ryujinx.Ava/Assets/Locales/pt_BR.json b/Ryujinx.Ava/Assets/Locales/pt_BR.json
index 036b0a4bf0..ded6cf95f3 100644
--- a/Ryujinx.Ava/Assets/Locales/pt_BR.json
+++ b/Ryujinx.Ava/Assets/Locales/pt_BR.json
@@ -260,7 +260,7 @@
   "UserProfilesChangeProfileImage": "Mudar imagem de perfil",
   "UserProfilesAvailableUserProfiles": "Perfis de usuário disponíveis:",
   "UserProfilesAddNewProfile": "Adicionar novo perfil",
-  "UserProfilesDeleteSelectedProfile": "Apagar perfil selecionado",
+  "UserProfilesDelete": "Apagar",
   "UserProfilesClose": "Fechar",
   "ProfileImageSelectionTitle": "Seleção da imagem de perfil",
   "ProfileImageSelectionHeader": "Escolha uma imagem de perfil",
diff --git a/Ryujinx.Ava/Assets/Locales/ru_RU.json b/Ryujinx.Ava/Assets/Locales/ru_RU.json
index b3ad82be73..7b25f45541 100644
--- a/Ryujinx.Ava/Assets/Locales/ru_RU.json
+++ b/Ryujinx.Ava/Assets/Locales/ru_RU.json
@@ -260,7 +260,7 @@
   "UserProfilesChangeProfileImage": "Изменить изображение профиля",
   "UserProfilesAvailableUserProfiles": "Доступные профили пользователей:",
   "UserProfilesAddNewProfile": "Добавить новый профиль",
-  "UserProfilesDeleteSelectedProfile": "Удалить выбранный профиль",
+  "UserProfilesDelete": "Удалить",
   "UserProfilesClose": "Закрыть",
   "ProfileImageSelectionTitle": "Выбор изображения профиля",
   "ProfileImageSelectionHeader": "Выберите изображение профиля",
diff --git a/Ryujinx.Ava/Assets/Locales/tr_TR.json b/Ryujinx.Ava/Assets/Locales/tr_TR.json
index ae14cdaf32..f277713ba1 100644
--- a/Ryujinx.Ava/Assets/Locales/tr_TR.json
+++ b/Ryujinx.Ava/Assets/Locales/tr_TR.json
@@ -260,7 +260,7 @@
   "UserProfilesChangeProfileImage": "Profil Resmini Değiştir",
   "UserProfilesAvailableUserProfiles": "Mevcut Kullanıcı Profilleri:",
   "UserProfilesAddNewProfile": "Yeni Profil Ekle",
-  "UserProfilesDeleteSelectedProfile": "Seçili Profili Sil",
+  "UserProfilesDelete": "Sil",
   "UserProfilesClose": "Kapat",
   "ProfileImageSelectionTitle": "Profil Resmi Seçimi",
   "ProfileImageSelectionHeader": "Profil Resmi Seç",
diff --git a/Ryujinx.Ava/Assets/Locales/zh_TW.json b/Ryujinx.Ava/Assets/Locales/zh_TW.json
index 963c0a8346..e683299575 100644
--- a/Ryujinx.Ava/Assets/Locales/zh_TW.json
+++ b/Ryujinx.Ava/Assets/Locales/zh_TW.json
@@ -260,7 +260,7 @@
   "UserProfilesChangeProfileImage": "更換頭貼",
   "UserProfilesAvailableUserProfiles": "現有的帳號:",
   "UserProfilesAddNewProfile": "建立帳號",
-  "UserProfilesDeleteSelectedProfile": "刪除選擇的帳號",
+  "UserProfilesDelete": "刪除",
   "UserProfilesClose": "關閉",
   "ProfileImageSelectionTitle": "頭貼選擇",
   "ProfileImageSelectionHeader": "選擇合適的頭貼圖片",
diff --git a/Ryujinx.Ava/Assets/Styles/Styles.xaml b/Ryujinx.Ava/Assets/Styles/Styles.xaml
index c5e760e81d..fc4e9ddd63 100644
--- a/Ryujinx.Ava/Assets/Styles/Styles.xaml
+++ b/Ryujinx.Ava/Assets/Styles/Styles.xaml
@@ -179,6 +179,9 @@
     <Style Selector="Button">
         <Setter Property="MinWidth" Value="80" />
     </Style>
+    <Style Selector="ProgressBar /template/ Border#ProgressBarTrack">
+        <Setter Property="IsVisible" Value="False" />
+    </Style>
     <Style Selector="ToggleButton">
         <Setter Property="Padding" Value="0,-5,0,0" />
     </Style>
@@ -234,6 +237,35 @@
     <Style Selector="TextBox.NumberBoxTextBoxStyle">
         <Setter Property="Foreground" Value="{DynamicResource ThemeForegroundColor}" />
     </Style>
+    <Style Selector="ListBox ListBoxItem">
+        <Setter Property="Padding" Value="0" />
+        <Setter Property="Margin" Value="0" />
+        <Setter Property="CornerRadius" Value="5" />
+        <Setter Property="Background" Value="{DynamicResource AppListBackgroundColor}" />
+        <Setter Property="BorderThickness" Value="2"/>
+        <Style.Animations>
+            <Animation Duration="0:0:0.7">
+                <KeyFrame Cue="0%">
+                    <Setter Property="MaxHeight" Value="0" />
+                    <Setter Property="Opacity" Value="0.0" />
+                </KeyFrame>
+                <KeyFrame Cue="50%">
+                    <Setter Property="MaxHeight" Value="1000" />
+                    <Setter Property="Opacity" Value="0.3" />
+                </KeyFrame>
+                <KeyFrame Cue="100%">
+                    <Setter Property="MaxHeight" Value="1000" />
+                    <Setter Property="Opacity" Value="1.0" />
+                </KeyFrame>
+            </Animation>
+        </Style.Animations>
+    </Style>
+    <Style Selector="ListBox ListBoxItem:selected /template/ ContentPresenter">
+        <Setter Property="Background" Value="{DynamicResource AppListBackgroundColor}" />
+    </Style>
+    <Style Selector="ListBox ListBoxItem:pointerover /template/ ContentPresenter">
+        <Setter Property="Background" Value="{DynamicResource AppListHoverBackgroundColor}" />
+    </Style>
     <Styles.Resources>
         <SolidColorBrush x:Key="ThemeAccentColorBrush" Color="{DynamicResource SystemAccentColor}" />
         <StaticResource x:Key="ListViewItemBackgroundSelected" ResourceKey="ThemeAccentColorBrush" />
diff --git a/Ryujinx.Ava/Program.cs b/Ryujinx.Ava/Program.cs
index 010aff5148..46e135a9ba 100644
--- a/Ryujinx.Ava/Program.cs
+++ b/Ryujinx.Ava/Program.cs
@@ -1,6 +1,6 @@
 using Avalonia;
 using Avalonia.Threading;
-using Ryujinx.Ava.UI.Helper;
+using Ryujinx.Ava.UI.Helpers;
 using Ryujinx.Ava.UI.Windows;
 using Ryujinx.Common;
 using Ryujinx.Common.Configuration;
diff --git a/Ryujinx.Ava/Ryujinx.Ava.csproj b/Ryujinx.Ava/Ryujinx.Ava.csproj
index 996817b9d5..88b60d0ba2 100644
--- a/Ryujinx.Ava/Ryujinx.Ava.csproj
+++ b/Ryujinx.Ava/Ryujinx.Ava.csproj
@@ -130,6 +130,18 @@
       <DependentUpon>GameListView.axaml</DependentUpon>
       <SubType>Code</SubType>
     </Compile>
+    <Compile Update="UI\Views\User\UserEditorView.axaml.cs">
+      <DependentUpon>UserEditor.axaml</DependentUpon>
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Update="UI\Views\User\UserRecovererView.axaml.cs">
+      <DependentUpon>UserRecoverer.axaml</DependentUpon>
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Update="UI\Views\User\UserSelectorView.axaml.cs">
+      <DependentUpon>UserSelector.axaml</DependentUpon>
+      <SubType>Code</SubType>
+    </Compile>
   </ItemGroup>
 
   <ItemGroup>
diff --git a/Ryujinx.Ava/UI/Controls/GameGridView.axaml b/Ryujinx.Ava/UI/Controls/GameGridView.axaml
index c757f066c1..862bc6d30e 100644
--- a/Ryujinx.Ava/UI/Controls/GameGridView.axaml
+++ b/Ryujinx.Ava/UI/Controls/GameGridView.axaml
@@ -112,32 +112,8 @@
             </ListBox.ItemsPanel>
             <ListBox.Styles>
                 <Style Selector="ListBoxItem">
-                    <Setter Property="Padding" Value="0" />
                     <Setter Property="Margin" Value="5" />
                     <Setter Property="CornerRadius" Value="4" />
-                    <Setter Property="Background" Value="{DynamicResource AppListBackgroundColor}" />
-                    <Style.Animations>
-                        <Animation Duration="0:0:0.7">
-                            <KeyFrame Cue="0%">
-                                <Setter Property="MaxWidth" Value="0" />
-                                <Setter Property="Opacity" Value="0.0" />
-                            </KeyFrame>
-                            <KeyFrame Cue="50%">
-                                <Setter Property="MaxWidth" Value="1000" />
-                                <Setter Property="Opacity" Value="0.3" />
-                            </KeyFrame>
-                            <KeyFrame Cue="100%">
-                                <Setter Property="MaxWidth" Value="1000" />
-                                <Setter Property="Opacity" Value="1.0" />
-                            </KeyFrame>
-                        </Animation>
-                    </Style.Animations>
-                </Style>
-                <Style Selector="ListBoxItem:selected /template/ ContentPresenter">
-                    <Setter Property="Background" Value="{DynamicResource AppListBackgroundColor}" />
-                </Style>
-                <Style Selector="ListBoxItem:pointerover /template/ ContentPresenter">
-                    <Setter Property="Background" Value="{DynamicResource AppListHoverBackgroundColor}" />
                 </Style>
                 <Style Selector="ListBoxItem:selected /template/ Border#SelectionIndicator">
                     <Setter Property="MinHeight" Value="{Binding $parent[UserControl].DataContext.GridItemSelectorSize}" />
diff --git a/Ryujinx.Ava/UI/Controls/GameListView.axaml b/Ryujinx.Ava/UI/Controls/GameListView.axaml
index 9fb5497b12..bb4e37b016 100644
--- a/Ryujinx.Ava/UI/Controls/GameListView.axaml
+++ b/Ryujinx.Ava/UI/Controls/GameListView.axaml
@@ -111,35 +111,6 @@
                 </ItemsPanelTemplate>
             </ListBox.ItemsPanel>
             <ListBox.Styles>
-                <Style Selector="ListBoxItem">
-                    <Setter Property="Padding" Value="0" />
-                    <Setter Property="Margin" Value="0" />
-                    <Setter Property="CornerRadius" Value="5" />
-                    <Setter Property="Background" Value="{DynamicResource AppListBackgroundColor}" />
-                    <Setter Property="BorderThickness" Value="2"/>
-                    <Style.Animations>
-                        <Animation Duration="0:0:0.7">
-                            <KeyFrame Cue="0%">
-                                <Setter Property="MaxHeight" Value="0" />
-                                <Setter Property="Opacity" Value="0.0" />
-                            </KeyFrame>
-                            <KeyFrame Cue="50%">
-                                <Setter Property="MaxHeight" Value="1000" />
-                                <Setter Property="Opacity" Value="0.3" />
-                            </KeyFrame>
-                            <KeyFrame Cue="100%">
-                                <Setter Property="MaxHeight" Value="1000" />
-                                <Setter Property="Opacity" Value="1.0" />
-                            </KeyFrame>
-                        </Animation>
-                    </Style.Animations>
-                </Style>
-                <Style Selector="ListBoxItem:selected /template/ ContentPresenter">
-                    <Setter Property="Background" Value="{DynamicResource AppListBackgroundColor}" />
-                </Style>
-                <Style Selector="ListBoxItem:pointerover /template/ ContentPresenter">
-                    <Setter Property="Background" Value="{DynamicResource AppListHoverBackgroundColor}" />
-                </Style>
                 <Style Selector="ListBoxItem:selected /template/ Border#SelectionIndicator">
                     <Setter Property="MinHeight" Value="{Binding $parent[UserControl].DataContext.ListItemSelectorSize}" />
                 </Style>
diff --git a/Ryujinx.Ava/UI/Controls/NavigationDialogHost.axaml b/Ryujinx.Ava/UI/Controls/NavigationDialogHost.axaml
index 90720478d9..bf34b303a7 100644
--- a/Ryujinx.Ava/UI/Controls/NavigationDialogHost.axaml
+++ b/Ryujinx.Ava/UI/Controls/NavigationDialogHost.axaml
@@ -12,5 +12,6 @@
     <ui:Frame 
         HorizontalAlignment="Stretch"
         VerticalAlignment="Stretch"
-        x:Name="ContentFrame" />
+        x:Name="ContentFrame">
+    </ui:Frame>
 </UserControl>
\ No newline at end of file
diff --git a/Ryujinx.Ava/UI/Controls/NavigationDialogHost.axaml.cs b/Ryujinx.Ava/UI/Controls/NavigationDialogHost.axaml.cs
index 0c30026756..6911a4d4c9 100644
--- a/Ryujinx.Ava/UI/Controls/NavigationDialogHost.axaml.cs
+++ b/Ryujinx.Ava/UI/Controls/NavigationDialogHost.axaml.cs
@@ -1,13 +1,25 @@
 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.Threading.Tasks;
+using System.Collections.Generic;
+using System.Linq;
+using UserProfile = Ryujinx.Ava.UI.Models.UserProfile;
 
 namespace Ryujinx.Ava.UI.Controls
 {
@@ -31,14 +43,14 @@ namespace Ryujinx.Ava.UI.Controls
             ContentManager = contentManager;
             VirtualFileSystem = virtualFileSystem;
             HorizonClient = horizonClient;
-            ViewModel = new UserProfileViewModel(this);
-
+            ViewModel = new UserProfileViewModel();
+            LoadProfiles();
 
             if (contentManager.GetCurrentFirmwareVersion() != null)
             {
                 Task.Run(() =>
                 {
-                    AvatarProfileViewModel.PreloadAvatars(contentManager, virtualFileSystem);
+                    UserFirmwareAvatarSelectorViewModel.PreloadAvatars(contentManager, virtualFileSystem);
                 });
             }
             InitializeComponent();
@@ -51,7 +63,7 @@ namespace Ryujinx.Ava.UI.Controls
                 ContentFrame.GoBack();
             }
 
-            ViewModel.LoadProfiles();
+            LoadProfiles();
         }
 
         public void Navigate(Type sourcePageType, object parameter)
@@ -68,7 +80,7 @@ namespace Ryujinx.Ava.UI.Controls
                 Title = LocaleManager.Instance[LocaleKeys.UserProfileWindowTitle],
                 PrimaryButtonText = "",
                 SecondaryButtonText = "",
-                CloseButtonText = LocaleManager.Instance[LocaleKeys.UserProfilesClose],
+                CloseButtonText = "",
                 Content = content,
                 Padding = new Thickness(0)
             };
@@ -78,6 +90,11 @@ namespace Ryujinx.Ava.UI.Controls
                 content.ViewModel.Dispose();
             };
 
+            Style footer = new(x => x.Name("DialogSpace").Child().OfType<Border>());
+            footer.Setters.Add(new Setter(IsVisibleProperty, false));
+
+            contentDialog.Styles.Add(footer);
+
             await contentDialog.ShowAsync();
         }
 
@@ -85,7 +102,117 @@ namespace Ryujinx.Ava.UI.Controls
         {
             base.OnAttachedToVisualTree(e);
 
-            Navigate(typeof(UserSelector), this);
+            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<SaveDataIterator>();
+
+            HorizonClient.Fs.OpenSaveDataIterator(ref saveDataIterator.Ref(), SaveDataSpaceId.User, in saveDataFilter).ThrowIfFailure();
+
+            Span<SaveDataInfo> saveDataInfo = stackalloc SaveDataInfo[10];
+
+            HashSet<HLE.HOS.Services.Account.Acc.UserId> 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<UserProfile>().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<UserProfile>().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/Ryujinx.Ava/UI/Controls/ProfileImageSelectionDialog.axaml b/Ryujinx.Ava/UI/Controls/ProfileImageSelectionDialog.axaml
deleted file mode 100644
index 56f8152ae4..0000000000
--- a/Ryujinx.Ava/UI/Controls/ProfileImageSelectionDialog.axaml
+++ /dev/null
@@ -1,57 +0,0 @@
-<UserControl 
-    xmlns="https://github.com/avaloniaui"
-    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
-    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
-    xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
-    mc:Ignorable="d"
-    x:Class="Ryujinx.Ava.UI.Controls.ProfileImageSelectionDialog"
-    Focusable="True">
-    <Grid 
-        HorizontalAlignment="Stretch" 
-        VerticalAlignment="Center" 
-        Margin="5,10,5, 5">
-        <Grid.RowDefinitions>
-            <RowDefinition Height="Auto" />
-            <RowDefinition Height="Auto" />
-            <RowDefinition Height="70" />
-            <RowDefinition Height="Auto" />
-            <RowDefinition Height="Auto" />
-        </Grid.RowDefinitions>
-        <TextBlock 
-            FontWeight="Bold" 
-            FontSize="18" 
-            HorizontalAlignment="Center"
-            Grid.Row="1"
-            Text="{locale:Locale ProfileImageSelectionHeader}" />
-        <TextBlock 
-            FontWeight="Bold" 
-            Grid.Row="2" 
-            Margin="10" 
-            MaxWidth="400" 
-            TextWrapping="Wrap"
-            HorizontalAlignment="Center" 
-            TextAlignment="Center" 
-            Text="{locale:Locale ProfileImageSelectionNote}" />
-        <StackPanel 
-            Margin="5,0" 
-            Spacing="10" 
-            Grid.Row="4" 
-            HorizontalAlignment="Center"
-            Orientation="Horizontal">
-            <Button 
-                Name="Import"
-                Click="Import_OnClick"
-                Width="200">
-                <TextBlock Text="{locale:Locale ProfileImageSelectionImportImage}" />
-            </Button>
-            <Button 
-                Name="SelectFirmwareImage" 
-                IsEnabled="{Binding FirmwareFound}" 
-                Click="SelectFirmwareImage_OnClick"
-                Width="200">
-                <TextBlock Text="{locale:Locale ProfileImageSelectionSelectAvatar}" />
-            </Button>
-        </StackPanel>
-    </Grid>
-</UserControl>
\ No newline at end of file
diff --git a/Ryujinx.Ava/UI/Controls/SaveManager.axaml b/Ryujinx.Ava/UI/Controls/SaveManager.axaml
deleted file mode 100644
index 64674b65bb..0000000000
--- a/Ryujinx.Ava/UI/Controls/SaveManager.axaml
+++ /dev/null
@@ -1,175 +0,0 @@
-<UserControl 
-    xmlns="https://github.com/avaloniaui"
-    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
-    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
-    xmlns:models="clr-namespace:Ryujinx.Ava.UI.Models"
-    xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
-    xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
-    xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
-    mc:Ignorable="d" 
-    d:DesignWidth="800" 
-    d:DesignHeight="450"
-    Height="400"
-    Width="550"
-    x:Class="Ryujinx.Ava.UI.Controls.SaveManager"
-    Focusable="True">
-    <UserControl.Resources>
-        <helpers:BitmapArrayValueConverter x:Key="ByteImage" />
-    </UserControl.Resources>
-    <Grid>
-        <Grid.RowDefinitions>
-            <RowDefinition Height="Auto" />
-            <RowDefinition />
-        </Grid.RowDefinitions>
-        <Grid 
-            Grid.Row="0" 
-            HorizontalAlignment="Stretch">
-            <Grid.ColumnDefinitions>
-                <ColumnDefinition Width="Auto" />
-                <ColumnDefinition />
-            </Grid.ColumnDefinitions>
-            <StackPanel 
-                Spacing="10" 
-                Orientation="Horizontal" 
-                HorizontalAlignment="Left" 
-                VerticalAlignment="Center">
-                <Label
-                    Content="{locale:Locale CommonSort}" 
-                    VerticalAlignment="Center" />
-                <ComboBox SelectedIndex="{Binding SortIndex}" Width="100">
-                    <ComboBoxItem>
-                        <Label 
-                            VerticalAlignment="Center" 
-                            HorizontalContentAlignment="Left"
-                            Content="{locale:Locale Name}" />
-                    </ComboBoxItem>
-                    <ComboBoxItem>
-                        <Label 
-                            VerticalAlignment="Center" 
-                            HorizontalContentAlignment="Left"
-                            Content="{locale:Locale Size}" />
-                    </ComboBoxItem>
-                </ComboBox>
-                <ComboBox SelectedIndex="{Binding OrderIndex}" Width="150">
-                    <ComboBoxItem>
-                        <Label 
-                            VerticalAlignment="Center" 
-                            HorizontalContentAlignment="Left"
-                            Content="{locale:Locale OrderAscending}" />
-                    </ComboBoxItem>
-                    <ComboBoxItem>
-                        <Label 
-                            VerticalAlignment="Center" 
-                            HorizontalContentAlignment="Left"
-                            Content="{locale:Locale OrderDescending}" />
-                    </ComboBoxItem>
-                </ComboBox>
-            </StackPanel>
-            <Grid 
-                Grid.Column="1" 
-                HorizontalAlignment="Stretch" 
-                Margin="10,0, 0, 0">
-                <Grid.ColumnDefinitions>
-                    <ColumnDefinition Width="Auto"/>
-                    <ColumnDefinition/>
-                </Grid.ColumnDefinitions>
-                <Label 
-                    Content="{locale:Locale Search}"
-                    VerticalAlignment="Center"/>
-                <TextBox 
-                    Margin="5,0,0,0" 
-                    Grid.Column="1" 
-                    HorizontalAlignment="Stretch" 
-                    Text="{Binding Search}"/>
-            </Grid>
-        </Grid>
-        <Border 
-            Grid.Row="1" 
-            Margin="0,5" 
-            BorderThickness="1" 
-            HorizontalAlignment="Stretch" 
-            VerticalAlignment="Stretch">
-            <ListBox 
-                Name="SaveList" 
-                Items="{Binding View}" 
-                HorizontalAlignment="Stretch" 
-                VerticalAlignment="Stretch">
-                <ListBox.ItemTemplate>
-                    <DataTemplate x:DataType="models:SaveModel">
-                        <Grid HorizontalAlignment="Stretch" Margin="0,5">
-                            <Grid.ColumnDefinitions>
-                                <ColumnDefinition />
-                                <ColumnDefinition Width="Auto" />
-                            </Grid.ColumnDefinitions>
-                            <StackPanel Grid.Column="0" Orientation="Horizontal">
-                                <Border 
-                                    Height="42" 
-                                    Margin="2" 
-                                    Width="42" 
-                                    Padding="10"
-                                    IsVisible="{Binding !InGameList}">
-                                    <ui:SymbolIcon 
-                                        Symbol="Help" 
-                                        FontSize="30" 
-                                        HorizontalAlignment="Center"
-                                        VerticalAlignment="Center" />
-                                </Border>
-                                <Image 
-                                    IsVisible="{Binding InGameList}"
-                                    Margin="2"
-                                    Width="42"
-                                    Height="42"
-                                    Source="{Binding Icon, 
-                                    Converter={StaticResource ByteImage}}" />
-                                <TextBlock 
-                                    MaxLines="3" 
-                                    Width="320"
-                                    Margin="5" 
-                                    TextWrapping="Wrap"
-                                    Text="{Binding  Title}" VerticalAlignment="Center" />
-                            </StackPanel>
-                            <StackPanel 
-                                Grid.Column="1" 
-                                Spacing="10" 
-                                HorizontalAlignment="Right"
-                                Orientation="Horizontal">
-                                <Label 
-                                    Content="{Binding SizeString}" 
-                                    IsVisible="{Binding SizeAvailable}"
-                                    VerticalAlignment="Center" 
-                                    HorizontalAlignment="Right" />
-                                <Button 
-                                    VerticalAlignment="Center" 
-                                    HorizontalAlignment="Right" 
-                                    Padding="10"
-                                    MinWidth="0" 
-                                    MinHeight="0" 
-                                    Name="OpenLocation" 
-                                    Command="{Binding OpenLocation}">
-                                    <ui:SymbolIcon 
-                                        Symbol="OpenFolder" 
-                                        HorizontalAlignment="Center"
-                                        VerticalAlignment="Center" />
-                                </Button>
-                                <Button 
-                                    VerticalAlignment="Center" 
-                                    HorizontalAlignment="Right" 
-                                    Padding="10"
-                                    MinWidth="0" 
-                                    MinHeight="0" 
-                                    Name="Delete" 
-                                    Command="{Binding Delete}">
-                                    <ui:SymbolIcon 
-                                        Symbol="Delete" 
-                                        HorizontalAlignment="Center"
-                                        VerticalAlignment="Center" />
-                                </Button>
-                            </StackPanel>
-                        </Grid>
-                    </DataTemplate>
-                </ListBox.ItemTemplate>
-            </ListBox>
-        </Border>
-    </Grid>
-</UserControl>
\ No newline at end of file
diff --git a/Ryujinx.Ava/UI/Controls/SaveManager.axaml.cs b/Ryujinx.Ava/UI/Controls/SaveManager.axaml.cs
deleted file mode 100644
index 9910481c5c..0000000000
--- a/Ryujinx.Ava/UI/Controls/SaveManager.axaml.cs
+++ /dev/null
@@ -1,160 +0,0 @@
-using Avalonia.Controls;
-using DynamicData;
-using DynamicData.Binding;
-using LibHac;
-using LibHac.Common;
-using LibHac.Fs;
-using LibHac.Fs.Shim;
-using Ryujinx.Ava.Common;
-using Ryujinx.Ava.Common.Locale;
-using Ryujinx.Ava.UI.Models;
-using Ryujinx.HLE.FileSystem;
-using Ryujinx.Ui.App.Common;
-using System;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.Threading.Tasks;
-using UserProfile = Ryujinx.Ava.UI.Models.UserProfile;
-
-namespace Ryujinx.Ava.UI.Controls
-{
-    public partial class SaveManager : UserControl
-    {
-        private readonly UserProfile _userProfile;
-        private readonly HorizonClient _horizonClient;
-        private readonly VirtualFileSystem _virtualFileSystem;
-        private int _sortIndex;
-        private int _orderIndex;
-        private ObservableCollection<SaveModel> _view = new ObservableCollection<SaveModel>();
-        private string _search;
-
-        public ObservableCollection<SaveModel> Saves { get; set; } = new ObservableCollection<SaveModel>();
-
-        public ObservableCollection<SaveModel> View
-        {
-            get => _view;
-            set => _view = value;
-        }
-
-        public int SortIndex
-        {
-            get => _sortIndex;
-            set
-            {
-                _sortIndex = value;
-                Sort();
-            }
-        }
-
-        public int OrderIndex
-        {
-            get => _orderIndex;
-            set
-            {
-                _orderIndex = value;
-                Sort();
-            }
-        }
-
-        public string Search
-        {
-            get => _search;
-            set
-            {
-                _search = value;
-                Sort();
-            }
-        }
-
-        public SaveManager()
-        {
-            InitializeComponent();
-        }
-
-        public SaveManager(UserProfile userProfile, HorizonClient horizonClient, VirtualFileSystem virtualFileSystem)
-        {
-            _userProfile = userProfile;
-            _horizonClient = horizonClient;
-            _virtualFileSystem = virtualFileSystem;
-            InitializeComponent();
-
-            DataContext = this;
-
-            Task.Run(LoadSaves);
-        }
-
-        public void LoadSaves()
-        {
-            Saves.Clear();
-            var saveDataFilter = SaveDataFilter.Make(programId: default, saveType: SaveDataType.Account,
-                new UserId((ulong)_userProfile.UserId.High, (ulong)_userProfile.UserId.Low), saveDataId: default, index: default);
-
-            using var saveDataIterator = new UniqueRef<SaveDataIterator>();
-
-            _horizonClient.Fs.OpenSaveDataIterator(ref saveDataIterator.Ref(), SaveDataSpaceId.User, in saveDataFilter).ThrowIfFailure();
-
-            Span<SaveDataInfo> saveDataInfo = stackalloc SaveDataInfo[10];
-
-            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];
-                    if (save.ProgramId.Value != 0)
-                    {
-                        var saveModel = new SaveModel(save, _horizonClient, _virtualFileSystem);
-                        Saves.Add(saveModel);
-                        saveModel.DeleteAction = () => { Saves.Remove(saveModel); };
-                    }
-                    
-                    Sort();
-                }
-            }
-        }
-
-        private void Sort()
-        {
-            Saves.AsObservableChangeSet()
-                .Filter(Filter)
-                .Sort(GetComparer())
-                .Bind(out var view).AsObservableList();
-            
-            _view.Clear();
-            _view.AddRange(view);
-        }
-
-        private IComparer<SaveModel> GetComparer()
-        {
-            switch (SortIndex)
-            {
-                case 0:
-                    return OrderIndex == 0
-                        ? SortExpressionComparer<SaveModel>.Ascending(save => save.Title)
-                        : SortExpressionComparer<SaveModel>.Descending(save => save.Title);
-                case 1:
-                    return OrderIndex == 0
-                        ? SortExpressionComparer<SaveModel>.Ascending(save => save.Size)
-                        : SortExpressionComparer<SaveModel>.Descending(save => save.Size);
-                default:
-                    return null;
-            }
-        }
-
-        private bool Filter(object arg)
-        {
-            if (arg is SaveModel save)
-            {
-                return string.IsNullOrWhiteSpace(_search) || save.Title.ToLower().Contains(_search.ToLower());
-            }
-
-            return false;
-        }
-    }
-}
\ No newline at end of file
diff --git a/Ryujinx.Ava/UI/Controls/UserRecoverer.axaml b/Ryujinx.Ava/UI/Controls/UserRecoverer.axaml
deleted file mode 100644
index 69f3d36a2d..0000000000
--- a/Ryujinx.Ava/UI/Controls/UserRecoverer.axaml
+++ /dev/null
@@ -1,72 +0,0 @@
-<UserControl 
-    xmlns="https://github.com/avaloniaui"
-    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
-    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
-    xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
-    xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
-    xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
-    mc:Ignorable="d"
-    d:DesignWidth="800"
-    d:DesignHeight="450"
-    MinWidth="500"
-    MinHeight="400"
-    x:Class="Ryujinx.Ava.UI.Controls.UserRecoverer"
-    Focusable="True">
-    <Design.DataContext>
-        <viewModels:UserProfileViewModel />
-    </Design.DataContext>
-    <Grid HorizontalAlignment="Stretch"
-          VerticalAlignment="Stretch">
-        <Grid.RowDefinitions>
-            <RowDefinition Height="Auto"/>
-            <RowDefinition Height="Auto"/>
-            <RowDefinition/>
-        </Grid.RowDefinitions>
-        <Button Grid.Row="0"
-                Margin="5"
-                Height="30"
-                Width="50"
-                MinWidth="50"
-                HorizontalAlignment="Left"
-                Command="{Binding GoBack}">
-            <ui:SymbolIcon Symbol="Back"/>
-        </Button>
-        <TextBlock Grid.Row="1"
-                   Text="{locale:Locale UserProfilesRecoverHeading}"/>
-        <ListBox
-            Margin="5"
-            Grid.Row="2"
-            HorizontalAlignment="Stretch"
-            VerticalAlignment="Stretch"
-            Items="{Binding LostProfiles}">
-            <ListBox.ItemTemplate>
-                <DataTemplate>
-                    <Border
-                        Margin="2"
-                        HorizontalAlignment="Stretch"
-                        VerticalAlignment="Stretch"
-                        ClipToBounds="True"
-                        CornerRadius="5">
-                        <Grid Margin="0">
-                            <Grid.ColumnDefinitions>
-                                <ColumnDefinition/>
-                                <ColumnDefinition Width="Auto"/>
-                            </Grid.ColumnDefinitions>
-                            <TextBlock
-                                HorizontalAlignment="Stretch"
-                                Text="{Binding UserId}"
-                                TextAlignment="Left"
-                                TextWrapping="Wrap" />
-                            <Button Grid.Column="1"
-                                    HorizontalAlignment="Right"
-                                    Command="{Binding Recover}"
-                                    CommandParameter="{Binding}"
-                                    Content="{locale:Locale Recover}"/>
-                        </Grid>
-                    </Border>
-                </DataTemplate>
-            </ListBox.ItemTemplate>
-        </ListBox>
-    </Grid>
-</UserControl>
diff --git a/Ryujinx.Ava/UI/Controls/UserRecoverer.axaml.cs b/Ryujinx.Ava/UI/Controls/UserRecoverer.axaml.cs
deleted file mode 100644
index 9f29fddbd6..0000000000
--- a/Ryujinx.Ava/UI/Controls/UserRecoverer.axaml.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-using Avalonia;
-using Avalonia.Controls;
-using Avalonia.Interactivity;
-using Avalonia.Markup.Xaml;
-using FluentAvalonia.UI.Controls;
-using FluentAvalonia.UI.Navigation;
-using Ryujinx.Ava.UI.Models;
-using Ryujinx.Ava.UI.ViewModels;
-
-namespace Ryujinx.Ava.UI.Controls
-{
-    public partial class UserRecoverer : UserControl
-    {
-        private UserProfileViewModel _viewModel;
-        private NavigationDialogHost _parent;
-
-        public UserRecoverer()
-        {
-            InitializeComponent();
-            AddHandler(Frame.NavigatedToEvent, (s, e) =>
-            {
-                NavigatedTo(e);
-            }, RoutingStrategies.Direct);
-        }
-
-        private void NavigatedTo(NavigationEventArgs arg)
-        {
-            if (Program.PreviewerDetached)
-            {
-                switch (arg.NavigationMode)
-                {
-                    case NavigationMode.New:
-                        var args = ((NavigationDialogHost parent, UserProfileViewModel viewModel))arg.Parameter;
-
-                        _viewModel = args.viewModel;
-                        _parent = args.parent;
-                        break;
-                }
-
-                DataContext = _viewModel;
-            }
-        }
-    }
-}
diff --git a/Ryujinx.Ava/UI/Controls/UserSelector.axaml b/Ryujinx.Ava/UI/Controls/UserSelector.axaml
deleted file mode 100644
index 002d27a064..0000000000
--- a/Ryujinx.Ava/UI/Controls/UserSelector.axaml
+++ /dev/null
@@ -1,145 +0,0 @@
-<UserControl
-    x:Class="Ryujinx.Ava.UI.Controls.UserSelector"
-    xmlns="https://github.com/avaloniaui"
-    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-    xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
-    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
-    xmlns:flex="clr-namespace:Avalonia.Flexbox;assembly=Avalonia.Flexbox"
-    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
-    xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
-    xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
-    d:DesignHeight="450"
-    MinWidth="500"
-    d:DesignWidth="800"
-    mc:Ignorable="d"
-    Focusable="True">
-    <UserControl.Resources>
-        <helpers:BitmapArrayValueConverter x:Key="ByteImage" />
-    </UserControl.Resources>
-    <Design.DataContext>
-        <viewModels:UserProfileViewModel />
-    </Design.DataContext>
-    <Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
-        <Grid.RowDefinitions>
-            <RowDefinition />
-            <RowDefinition Height="Auto" />
-        </Grid.RowDefinitions>
-        <ListBox
-            Margin="5"
-            MaxHeight="300"
-            HorizontalAlignment="Stretch"
-            VerticalAlignment="Center"
-            DoubleTapped="ProfilesList_DoubleTapped"
-            Items="{Binding Profiles}"
-            SelectionChanged="SelectingItemsControl_SelectionChanged">
-            <ListBox.ItemsPanel>
-                <ItemsPanelTemplate>
-                    <flex:FlexPanel
-                        HorizontalAlignment="Stretch"
-                        VerticalAlignment="Stretch"
-                        AlignContent="FlexStart"
-                        JustifyContent="Center" />
-                </ItemsPanelTemplate>
-            </ListBox.ItemsPanel>
-            <ListBox.ItemTemplate>
-                <DataTemplate>
-                    <Grid>
-                        <Border
-                            Margin="2"
-                            HorizontalAlignment="Stretch"
-                            VerticalAlignment="Stretch"
-                            ClipToBounds="True"
-                            CornerRadius="5">
-                            <Grid Margin="0">
-                                <Grid.RowDefinitions>
-                                    <RowDefinition Height="Auto" />
-                                    <RowDefinition Height="Auto" />
-                                </Grid.RowDefinitions>
-                                <Image
-                                    Grid.Row="0"
-                                    Width="96"
-                                    Height="96"
-                                    Margin="0"
-                                    HorizontalAlignment="Stretch"
-                                    VerticalAlignment="Top"
-                                    Source="{Binding Image, Converter={StaticResource ByteImage}}" />
-                                <StackPanel
-                                    Grid.Row="1"
-                                    Height="30"
-                                    Margin="5"
-                                    HorizontalAlignment="Stretch"
-                                    VerticalAlignment="Stretch">
-                                    <TextBlock
-                                        HorizontalAlignment="Stretch"
-                                        Text="{Binding Name}"
-                                        TextAlignment="Center"
-                                        TextWrapping="Wrap" />
-                                </StackPanel>
-                            </Grid>
-                        </Border>
-                        <Border
-                            Width="10"
-                            Height="10"
-                            Margin="5"
-                            HorizontalAlignment="Left"
-                            VerticalAlignment="Top"
-                            Background="LimeGreen"
-                            CornerRadius="5"
-                            IsVisible="{Binding IsOpened}" />
-                    </Grid>
-                </DataTemplate>
-            </ListBox.ItemTemplate>
-        </ListBox>
-        <Grid
-            Grid.Row="1"
-            HorizontalAlignment="Center">
-            <Grid.RowDefinitions>
-                <RowDefinition Height="Auto"/>
-                <RowDefinition Height="Auto"/>
-                <RowDefinition Height="Auto"/>
-            </Grid.RowDefinitions>
-            <Grid.ColumnDefinitions>
-                <ColumnDefinition Width="Auto"/>
-                <ColumnDefinition Width="Auto"/>
-            </Grid.ColumnDefinitions>
-            <Button 
-                HorizontalAlignment="Stretch"
-                Grid.Row="0"
-                Grid.Column="0"
-                Margin="2"
-                Command="{Binding AddUser}" 
-                Content="{locale:Locale UserProfilesAddNewProfile}" />
-            <Button
-                HorizontalAlignment="Stretch"
-                Grid.Row="0"
-                Margin="2"
-                Grid.Column="1"
-                Command="{Binding EditUser}"
-                Content="{locale:Locale UserProfilesEditProfile}"
-                IsEnabled="{Binding IsSelectedProfiledEditable}" />
-            <Button 
-                HorizontalAlignment="Stretch"
-                Grid.Row="1"
-                Grid.Column="0"
-                Margin="2"
-                Content="{locale:Locale UserProfilesManageSaves}" 
-                Command="{Binding ManageSaves}" />
-            <Button
-                HorizontalAlignment="Stretch"
-                Grid.Row="1"
-                Grid.Column="1"
-                Margin="2"
-                Command="{Binding DeleteUser}"
-                Content="{locale:Locale UserProfilesDeleteSelectedProfile}"
-                IsEnabled="{Binding IsSelectedProfileDeletable}" />
-            <Button
-                HorizontalAlignment="Stretch"
-                Grid.Row="2"
-                Grid.ColumnSpan="2"
-                Grid.Column="0"
-                Margin="2"
-                Command="{Binding RecoverLostAccounts}"
-                Content="{locale:Locale UserProfilesRecoverLostAccounts}" />
-        </Grid>
-    </Grid>
-</UserControl>
\ No newline at end of file
diff --git a/Ryujinx.Ava/UI/Controls/UserSelector.axaml.cs b/Ryujinx.Ava/UI/Controls/UserSelector.axaml.cs
deleted file mode 100644
index bd8c561e68..0000000000
--- a/Ryujinx.Ava/UI/Controls/UserSelector.axaml.cs
+++ /dev/null
@@ -1,77 +0,0 @@
-using Avalonia.Controls;
-using Avalonia.Interactivity;
-using FluentAvalonia.UI.Controls;
-using FluentAvalonia.UI.Navigation;
-using Ryujinx.Ava.UI.ViewModels;
-using UserProfile = Ryujinx.Ava.UI.Models.UserProfile;
-
-namespace Ryujinx.Ava.UI.Controls
-{
-    public partial class UserSelector : UserControl
-    {
-        private NavigationDialogHost _parent;
-        public UserProfileViewModel ViewModel { get; set; }
-
-        public UserSelector()
-        {
-            InitializeComponent();
-
-            if (Program.PreviewerDetached)
-            {
-                AddHandler(Frame.NavigatedToEvent, (s, e) =>
-                {
-                    NavigatedTo(e);
-                }, RoutingStrategies.Direct);
-            }
-        }
-
-        private void NavigatedTo(NavigationEventArgs arg)
-        {
-            if (Program.PreviewerDetached)
-            {
-                if (arg.NavigationMode == NavigationMode.New)
-                {
-                    _parent = (NavigationDialogHost)arg.Parameter;
-                    ViewModel = _parent.ViewModel;
-                }
-
-                DataContext = ViewModel;
-            }
-        }
-
-        private void ProfilesList_DoubleTapped(object sender, RoutedEventArgs e)
-        {
-            if (sender is ListBox listBox)
-            {
-                int selectedIndex = listBox.SelectedIndex;
-
-                if (selectedIndex >= 0 && selectedIndex < ViewModel.Profiles.Count)
-                {
-                    ViewModel.SelectedProfile = ViewModel.Profiles[selectedIndex];
-
-                    _parent?.AccountManager?.OpenUser(ViewModel.SelectedProfile.UserId);
-
-                    ViewModel.LoadProfiles();
-
-                    foreach (UserProfile profile in ViewModel.Profiles)
-                    {
-                        profile.UpdateState();
-                    }
-                }
-            }
-        }
-
-        private void SelectingItemsControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
-        {
-            if (sender is ListBox listBox)
-            {
-                int selectedIndex = listBox.SelectedIndex;
-
-                if (selectedIndex >= 0 && selectedIndex < ViewModel.Profiles.Count)
-                {
-                    ViewModel.HighlightedProfile = ViewModel.Profiles[selectedIndex];
-                }
-            }
-        }
-    }
-}
\ No newline at end of file
diff --git a/Ryujinx.Ava/UI/Helpers/EmbeddedWindow.cs b/Ryujinx.Ava/UI/Helpers/EmbeddedWindow.cs
index bdeceaeae6..8247a89b59 100644
--- a/Ryujinx.Ava/UI/Helpers/EmbeddedWindow.cs
+++ b/Ryujinx.Ava/UI/Helpers/EmbeddedWindow.cs
@@ -2,7 +2,6 @@ using Avalonia;
 using Avalonia.Controls;
 using Avalonia.Input;
 using Avalonia.Platform;
-using Ryujinx.Ava.UI.Helper;
 using SPB.Graphics;
 using SPB.Platform;
 using SPB.Platform.GLX;
@@ -148,9 +147,9 @@ namespace Ryujinx.Ava.UI.Helpers
                 IntPtr.Zero);
 
             WindowHandle = handle;
-            
+
             Marshal.FreeHGlobal(wndClassEx.lpszClassName);
-            
+
             return new PlatformHandle(WindowHandle, "HWND");
         }
 
diff --git a/Ryujinx.Ava/Helper/LoggerAdapter.cs b/Ryujinx.Ava/UI/Helpers/LoggerAdapter.cs
similarity index 99%
rename from Ryujinx.Ava/Helper/LoggerAdapter.cs
rename to Ryujinx.Ava/UI/Helpers/LoggerAdapter.cs
index c8f3fea149..ba251f6040 100644
--- a/Ryujinx.Ava/Helper/LoggerAdapter.cs
+++ b/Ryujinx.Ava/UI/Helpers/LoggerAdapter.cs
@@ -2,7 +2,7 @@ using Avalonia.Utilities;
 using System;
 using System.Text;
 
-namespace Ryujinx.Ava.UI.Helper
+namespace Ryujinx.Ava.UI.Helpers
 {
     using AvaLogger = Avalonia.Logging.Logger;
     using AvaLogLevel = Avalonia.Logging.LogEventLevel;
diff --git a/Ryujinx.Ava/Helper/MetalHelper.cs b/Ryujinx.Ava/UI/Helpers/MetalHelper.cs
similarity index 99%
rename from Ryujinx.Ava/Helper/MetalHelper.cs
rename to Ryujinx.Ava/UI/Helpers/MetalHelper.cs
index ea3477eb94..5eb8660a15 100644
--- a/Ryujinx.Ava/Helper/MetalHelper.cs
+++ b/Ryujinx.Ava/UI/Helpers/MetalHelper.cs
@@ -3,7 +3,7 @@ using System.Runtime.Versioning;
 using System.Runtime.InteropServices;
 using Avalonia;
 
-namespace Ryujinx.Ava.UI.Helper
+namespace Ryujinx.Ava.UI.Helpers
 {
     public delegate void UpdateBoundsCallbackDelegate(Rect rect);
 
diff --git a/Ryujinx.Ava/UI/Models/ProfileImageModel.cs b/Ryujinx.Ava/UI/Models/ProfileImageModel.cs
index 63da7b4498..8aa1940051 100644
--- a/Ryujinx.Ava/UI/Models/ProfileImageModel.cs
+++ b/Ryujinx.Ava/UI/Models/ProfileImageModel.cs
@@ -1,6 +1,9 @@
+using Avalonia.Media;
+using Ryujinx.Ava.UI.ViewModels;
+
 namespace Ryujinx.Ava.UI.Models
 {
-    public class ProfileImageModel
+    public class ProfileImageModel : BaseModel
     {
         public ProfileImageModel(string name, byte[] data)
         {
@@ -10,5 +13,20 @@ namespace Ryujinx.Ava.UI.Models
 
         public string Name { get; set; }
         public byte[] Data { get; set; }
+
+        private SolidColorBrush _backgroundColor = new(Colors.White);
+
+        public SolidColorBrush BackgroundColor
+        {
+            get
+            {
+                return _backgroundColor;
+            }
+            set
+            {
+                _backgroundColor = value;
+                OnPropertyChanged();
+            }
+        }
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.Ava/UI/Models/SaveModel.cs b/Ryujinx.Ava/UI/Models/SaveModel.cs
index 3c20741fc3..7096f9d794 100644
--- a/Ryujinx.Ava/UI/Models/SaveModel.cs
+++ b/Ryujinx.Ava/UI/Models/SaveModel.cs
@@ -4,13 +4,10 @@ using LibHac.Fs.Shim;
 using LibHac.Ncm;
 using Ryujinx.Ava.Common;
 using Ryujinx.Ava.Common.Locale;
-using Ryujinx.Ava.UI.Controls;
 using Ryujinx.Ava.UI.Helpers;
 using Ryujinx.Ava.UI.ViewModels;
 using Ryujinx.Ava.UI.Windows;
 using Ryujinx.HLE.FileSystem;
-using Ryujinx.Ui.App.Common;
-using System;
 using System.IO;
 using System.Linq;
 using System.Threading.Tasks;
@@ -22,7 +19,6 @@ namespace Ryujinx.Ava.UI.Models
         private readonly HorizonClient _horizonClient;
         private long _size;
 
-        public Action DeleteAction { get; set; }
         public ulong SaveId { get; }
         public ProgramId TitleId { get; }
         public string TitleIdString => $"{TitleId.Value:X16}";
@@ -99,25 +95,5 @@ namespace Ryujinx.Ava.UI.Models
             });
 
         }
-
-        public void OpenLocation()
-        {
-            ApplicationHelper.OpenSaveDir(SaveId);
-        }
-
-        public async void Delete()
-        {
-            var result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance[LocaleKeys.DeleteUserSave],
-                LocaleManager.Instance[LocaleKeys.IrreversibleActionNote],
-                LocaleManager.Instance[LocaleKeys.InputDialogYes],
-                LocaleManager.Instance[LocaleKeys.InputDialogNo], "");
-
-            if (result == UserResult.Yes)
-            {
-                _horizonClient.Fs.DeleteSaveData(SaveDataSpaceId.User, SaveId);
-
-                DeleteAction?.Invoke();
-            }
-        }
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.Ava/UI/Models/TempProfile.cs b/Ryujinx.Ava/UI/Models/TempProfile.cs
index 2dd7a6c828..05e16632d6 100644
--- a/Ryujinx.Ava/UI/Models/TempProfile.cs
+++ b/Ryujinx.Ava/UI/Models/TempProfile.cs
@@ -7,10 +7,12 @@ namespace Ryujinx.Ava.UI.Models
     public class TempProfile : BaseModel
     {
         private readonly UserProfile _profile;
-        private byte[] _image = null;
+        private byte[] _image;
         private string _name = String.Empty;
         private UserId _userId;
 
+        public uint MaxProfileNameLength => 0x20;
+
         public byte[] Image
         {
             get => _image;
@@ -28,9 +30,12 @@ namespace Ryujinx.Ava.UI.Models
             {
                 _userId = value;
                 OnPropertyChanged();
+                OnPropertyChanged(nameof(UserIdString));
             }
         }
 
+        public string UserIdString => _userId.ToString();
+
         public string Name
         {
             get => _name;
@@ -52,7 +57,5 @@ namespace Ryujinx.Ava.UI.Models
                 UserId = profile.UserId;
             }
         }
-
-        public TempProfile(){}
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.Ava/UI/Models/UserProfile.cs b/Ryujinx.Ava/UI/Models/UserProfile.cs
index 869db66106..e7cd53007a 100644
--- a/Ryujinx.Ava/UI/Models/UserProfile.cs
+++ b/Ryujinx.Ava/UI/Models/UserProfile.cs
@@ -1,5 +1,7 @@
+using Avalonia.Media;
 using Ryujinx.Ava.UI.Controls;
 using Ryujinx.Ava.UI.ViewModels;
+using Ryujinx.Ava.UI.Views.User;
 using Ryujinx.HLE.HOS.Services.Account.Acc;
 using Profile = Ryujinx.HLE.HOS.Services.Account.Acc.UserProfile;
 
@@ -12,6 +14,8 @@ namespace Ryujinx.Ava.UI.Models
         private byte[] _image;
         private string _name;
         private UserId _userId;
+        private bool _isPointerOver;
+        private IBrush _backgroundColor;
 
         public byte[] Image
         {
@@ -43,27 +47,57 @@ namespace Ryujinx.Ava.UI.Models
             }
         }
 
+        public bool IsPointerOver
+        {
+            get => _isPointerOver;
+            set
+            {
+                _isPointerOver = value;
+                OnPropertyChanged();
+            }
+        }
+
+        public IBrush BackgroundColor
+        {
+            get => _backgroundColor;
+            set
+            {
+                _backgroundColor = value;
+                OnPropertyChanged();
+            }
+        }
+
         public UserProfile(Profile profile, NavigationDialogHost owner)
         {
             _profile = profile;
             _owner = owner;
 
+            UpdateBackground();
+
             Image = profile.Image;
             Name = profile.Name;
             UserId = profile.UserId;
         }
 
-        public bool IsOpened => _profile.AccountState == AccountState.Open;
-
         public void UpdateState()
         {
-            OnPropertyChanged(nameof(IsOpened));
+            UpdateBackground();
             OnPropertyChanged(nameof(Name));
         }
 
+        private void UpdateBackground()
+        {
+            Avalonia.Application.Current.Styles.TryGetResource("ControlFillColorSecondary", out object color);
+
+            if (color is not null)
+            {
+                BackgroundColor = _profile.AccountState == AccountState.Open ? new SolidColorBrush((Color)color) : Brushes.Transparent;
+            }
+        }
+
         public void Recover(UserProfile userProfile)
         {
-            _owner.Navigate(typeof(UserEditor), (_owner, userProfile, true));
+            _owner.Navigate(typeof(UserEditorView), (_owner, userProfile, true));
         }
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.Ava/UI/ViewModels/UserFirmwareAvatarSelectorViewModel.cs b/Ryujinx.Ava/UI/ViewModels/UserFirmwareAvatarSelectorViewModel.cs
new file mode 100644
index 0000000000..9d981128c7
--- /dev/null
+++ b/Ryujinx.Ava/UI/ViewModels/UserFirmwareAvatarSelectorViewModel.cs
@@ -0,0 +1,230 @@
+using Avalonia.Media;
+using LibHac.Common;
+using LibHac.Fs;
+using LibHac.Fs.Fsa;
+using LibHac.FsSystem;
+using LibHac.Ncm;
+using LibHac.Tools.Fs;
+using LibHac.Tools.FsSystem;
+using LibHac.Tools.FsSystem.NcaUtils;
+using Ryujinx.Ava.UI.Models;
+using Ryujinx.HLE.FileSystem;
+using SixLabors.ImageSharp;
+using SixLabors.ImageSharp.PixelFormats;
+using System;
+using System.Buffers.Binary;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.IO;
+using Color = Avalonia.Media.Color;
+
+namespace Ryujinx.Ava.UI.ViewModels
+{
+    internal class UserFirmwareAvatarSelectorViewModel : BaseModel
+    {
+        private static readonly Dictionary<string, byte[]> _avatarStore = new();
+
+        private ObservableCollection<ProfileImageModel> _images;
+        private Color _backgroundColor = Colors.White;
+
+        private int _selectedIndex;
+        private byte[] _selectedImage;
+
+        public UserFirmwareAvatarSelectorViewModel()
+        {
+            _images = new ObservableCollection<ProfileImageModel>();
+
+            LoadImagesFromStore();
+        }
+
+        public Color BackgroundColor
+        {
+            get => _backgroundColor;
+            set
+            {
+                _backgroundColor = value;
+                OnPropertyChanged();
+                ChangeImageBackground();
+            }
+        }
+
+        public ObservableCollection<ProfileImageModel> Images
+        {
+            get => _images;
+            set
+            {
+                _images = value;
+                OnPropertyChanged();
+            }
+        }
+
+        public int SelectedIndex
+        {
+            get => _selectedIndex;
+            set
+            {
+                _selectedIndex = value;
+
+                if (_selectedIndex == -1)
+                {
+                    SelectedImage = null;
+                }
+                else
+                {
+                    SelectedImage = _images[_selectedIndex].Data;
+                }
+
+                OnPropertyChanged();
+            }
+        }
+
+        public byte[] SelectedImage
+        {
+            get => _selectedImage;
+            private set => _selectedImage = value;
+        }
+
+        private void LoadImagesFromStore()
+        {
+            Images.Clear();
+
+            foreach (var image in _avatarStore)
+            {
+                Images.Add(new ProfileImageModel(image.Key, image.Value));
+            }
+        }
+
+        private void ChangeImageBackground()
+        {
+            foreach (var image in Images)
+            {
+                image.BackgroundColor = new SolidColorBrush(BackgroundColor);
+            }
+        }
+
+        public static void PreloadAvatars(ContentManager contentManager, VirtualFileSystem virtualFileSystem)
+        {
+            if (_avatarStore.Count > 0)
+            {
+                return;
+            }
+
+            string contentPath = contentManager.GetInstalledContentPath(0x010000000000080A, StorageId.BuiltInSystem, NcaContentType.Data);
+            string avatarPath = virtualFileSystem.SwitchPathToSystemPath(contentPath);
+
+            if (!string.IsNullOrWhiteSpace(avatarPath))
+            {
+                using (IStorage ncaFileStream = new LocalStorage(avatarPath, FileAccess.Read, FileMode.Open))
+                {
+                    Nca nca = new(virtualFileSystem.KeySet, ncaFileStream);
+                    IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid);
+
+                    foreach (DirectoryEntryEx 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"))
+                        {
+                            using var file = new UniqueRef<IFile>();
+
+                            romfs.OpenFile(ref file.Ref(), ("/" + item.FullPath).ToU8Span(), OpenMode.Read).ThrowIfFailure();
+
+                            using (MemoryStream stream = new())
+                            using (MemoryStream streamPng = new())
+                            {
+                                file.Get.AsStream().CopyTo(stream);
+
+                                stream.Position = 0;
+
+                                Image avatarImage = Image.LoadPixelData<Rgba32>(DecompressYaz0(stream), 256, 256);
+
+                                avatarImage.SaveAsPng(streamPng);
+
+                                _avatarStore.Add(item.FullPath, streamPng.ToArray());
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        private static byte[] DecompressYaz0(Stream stream)
+        {
+            using (BinaryReader reader = new(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);
+
+                uint inputOffset = 0;
+
+                byte[] output = new byte[decodedLength];
+                uint 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++];
+
+                        uint dist = (uint)((byte1 & 0xF) << 8) | byte2;
+                        uint position = outputOffset - (dist + 1);
+
+                        uint length = (uint)byte1 >> 4;
+                        if (length == 0)
+                        {
+                            length = (uint)input[inputOffset++] + 0x12;
+                        }
+                        else
+                        {
+                            length += 2;
+                        }
+
+                        uint gap = outputOffset - position;
+                        uint nonOverlappingLength = length;
+
+                        if (nonOverlappingLength > gap)
+                        {
+                            nonOverlappingLength = gap;
+                        }
+
+                        Buffer.BlockCopy(output, (int)position, output, (int)outputOffset, (int)nonOverlappingLength);
+                        outputOffset += nonOverlappingLength;
+                        position += nonOverlappingLength;
+                        length -= nonOverlappingLength;
+
+                        while (length-- > 0)
+                        {
+                            output[outputOffset++] = output[position++];
+                        }
+                    }
+                }
+
+                return output;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.Ava/UI/ViewModels/UserProfileImageSelectorViewModel.cs b/Ryujinx.Ava/UI/ViewModels/UserProfileImageSelectorViewModel.cs
new file mode 100644
index 0000000000..7261631c16
--- /dev/null
+++ b/Ryujinx.Ava/UI/ViewModels/UserProfileImageSelectorViewModel.cs
@@ -0,0 +1,18 @@
+namespace Ryujinx.Ava.UI.ViewModels
+{
+    internal class UserProfileImageSelectorViewModel : BaseModel
+    {
+        private bool _firmwareFound;
+
+        public bool FirmwareFound
+        {
+            get => _firmwareFound;
+        
+            set
+            {
+                _firmwareFound = value;
+                OnPropertyChanged();
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.Ava/UI/ViewModels/UserProfileViewModel.cs b/Ryujinx.Ava/UI/ViewModels/UserProfileViewModel.cs
index 3f0a85c9d2..8f997efc1a 100644
--- a/Ryujinx.Ava/UI/ViewModels/UserProfileViewModel.cs
+++ b/Ryujinx.Ava/UI/ViewModels/UserProfileViewModel.cs
@@ -1,215 +1,25 @@
-using Avalonia;
-using Avalonia.Threading;
-using FluentAvalonia.UI.Controls;
-using LibHac.Common;
-using LibHac.Fs;
-using LibHac.Fs.Shim;
-using Ryujinx.Ava.Common.Locale;
-using Ryujinx.Ava.UI.Controls;
-using Ryujinx.Ava.UI.Helpers;
-using Ryujinx.HLE.HOS.Services.Account.Acc;
+using Microsoft.IdentityModel.Tokens;
 using System;
-using System.Collections.Generic;
 using System.Collections.ObjectModel;
-using System.Linq;
-using UserId = Ryujinx.HLE.HOS.Services.Account.Acc.UserId;
 using UserProfile = Ryujinx.Ava.UI.Models.UserProfile;
 
 namespace Ryujinx.Ava.UI.ViewModels
 {
     public class UserProfileViewModel : BaseModel, IDisposable
     {
-        private readonly NavigationDialogHost _owner;
-
-        private UserProfile _selectedProfile;
-        private UserProfile _highlightedProfile;
-
         public UserProfileViewModel()
         {
-            Profiles = new ObservableCollection<UserProfile>();
+            Profiles = new ObservableCollection<BaseModel>();
             LostProfiles = new ObservableCollection<UserProfile>();
+            IsEmpty = LostProfiles.IsNullOrEmpty();
         }
 
-        public UserProfileViewModel(NavigationDialogHost owner) : this()
-        {
-            _owner = owner;
-
-            LoadProfiles();
-        }
-
-        public ObservableCollection<UserProfile> Profiles { get; set; }
+        public ObservableCollection<BaseModel> Profiles { get; set; }
 
         public ObservableCollection<UserProfile> LostProfiles { get; set; }
 
-        public UserProfile SelectedProfile
-        {
-            get => _selectedProfile;
-            set
-            {
-                _selectedProfile = value;
-
-                OnPropertyChanged();
-                OnPropertyChanged(nameof(IsHighlightedProfileDeletable));
-                OnPropertyChanged(nameof(IsHighlightedProfileEditable));
-            }
-        }
-
-        public bool IsHighlightedProfileEditable => _highlightedProfile != null;
-
-        public bool IsHighlightedProfileDeletable => _highlightedProfile != null && _highlightedProfile.UserId != AccountManager.DefaultUserId;
-
-        public UserProfile HighlightedProfile
-        {
-            get => _highlightedProfile;
-            set
-            {
-                _highlightedProfile = value;
-
-                OnPropertyChanged();
-                OnPropertyChanged(nameof(IsHighlightedProfileDeletable));
-                OnPropertyChanged(nameof(IsHighlightedProfileEditable));
-            }
-        }
+        public bool IsEmpty { get; set; }
 
         public void Dispose() { }
-
-        public void LoadProfiles()
-        {
-            Profiles.Clear();
-            LostProfiles.Clear();
-
-            var profiles = _owner.AccountManager.GetAllUsers().OrderByDescending(x => x.AccountState == AccountState.Open);
-
-            foreach (var profile in profiles)
-            {
-                Profiles.Add(new UserProfile(profile, _owner));
-            }
-
-            SelectedProfile = Profiles.FirstOrDefault(x => x.UserId == _owner.AccountManager.LastOpenedUser.UserId);
-
-            if (SelectedProfile == null)
-            {
-                SelectedProfile = Profiles.First();
-
-                if (SelectedProfile != null)
-                {
-                    _owner.AccountManager.OpenUser(_selectedProfile.UserId);
-                }
-            }
-
-            var saveDataFilter = SaveDataFilter.Make(programId: default, saveType: SaveDataType.Account,
-                default, saveDataId: default, index: default);
-
-            using var saveDataIterator = new UniqueRef<SaveDataIterator>();
-
-            _owner.HorizonClient.Fs.OpenSaveDataIterator(ref saveDataIterator.Ref(), SaveDataSpaceId.User, in saveDataFilter).ThrowIfFailure();
-
-            Span<SaveDataInfo> saveDataInfo = stackalloc SaveDataInfo[10];
-
-            HashSet<UserId> lostAccounts = new HashSet<UserId>();
-
-            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 UserId((long)save.UserId.Id.Low, (long)save.UserId.Id.High);
-                    if (Profiles.FirstOrDefault( x=> x.UserId == id) == null)
-                    {
-                        lostAccounts.Add(id);
-                    }
-                }
-            }
-
-            foreach(var account in lostAccounts)
-            {
-                LostProfiles.Add(new UserProfile(new HLE.HOS.Services.Account.Acc.UserProfile(account, "", null), _owner));
-            }
-        }
-
-        public void AddUser()
-        {
-            UserProfile userProfile = null;
-
-            _owner.Navigate(typeof(UserEditor), (this._owner, userProfile, true));
-        }
-
-        public async void ManageSaves()
-        {
-            UserProfile userProfile = _highlightedProfile ?? SelectedProfile;
-
-            SaveManager manager = new SaveManager(userProfile, _owner.HorizonClient, _owner.VirtualFileSystem);
-            
-            ContentDialog contentDialog = new ContentDialog
-            {
-                Title = string.Format(LocaleManager.Instance[LocaleKeys.SaveManagerHeading], userProfile.Name),
-                PrimaryButtonText = "",
-                SecondaryButtonText = "",
-                CloseButtonText = LocaleManager.Instance[LocaleKeys.UserProfilesClose],
-                Content = manager,
-                Padding = new Thickness(0)
-            };
-
-            await contentDialog.ShowAsync();
-        }
-
-        public void EditUser()
-        {
-            _owner.Navigate(typeof(UserEditor), (this._owner, _highlightedProfile ?? SelectedProfile, false));
-        }
-
-        public async void DeleteUser()
-        {
-            if (_highlightedProfile != null)
-            {
-                var lastUserId = _owner.AccountManager.LastOpenedUser.UserId;
-
-                if (_highlightedProfile.UserId == lastUserId)
-                {
-                    // If we are deleting the currently open profile, then we must open something else before deleting.
-                    var profile = Profiles.FirstOrDefault(x => x.UserId != lastUserId);
-
-                    if (profile == null)
-                    {
-                        Dispatcher.UIThread.Post(async () =>
-                        {
-                            await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogUserProfileDeletionWarningMessage]);
-                        });
-
-                        return;
-                    }
-
-                    _owner.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)
-                {
-                    _owner.AccountManager.DeleteUser(_highlightedProfile.UserId);
-                }
-            }
-
-            LoadProfiles();
-        }
-
-        public void GoBack()
-        {
-            _owner.GoBack();
-        }
-
-        public void RecoverLostAccounts()
-        {
-            _owner.Navigate(typeof(UserRecoverer), (this._owner, this));
-        }
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.Ava/UI/ViewModels/UserSaveManagerViewModel.cs b/Ryujinx.Ava/UI/ViewModels/UserSaveManagerViewModel.cs
new file mode 100644
index 0000000000..bd37435084
--- /dev/null
+++ b/Ryujinx.Ava/UI/ViewModels/UserSaveManagerViewModel.cs
@@ -0,0 +1,123 @@
+using DynamicData;
+using DynamicData.Binding;
+using Ryujinx.Ava.Common.Locale;
+using Ryujinx.Ava.UI.Models;
+using Ryujinx.HLE.HOS.Services.Account.Acc;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+
+namespace Ryujinx.Ava.UI.ViewModels
+{
+    public class UserSaveManagerViewModel : BaseModel
+    {
+        private int _sortIndex;
+        private int _orderIndex;
+        private string _search;
+        private ObservableCollection<SaveModel> _saves;
+        private ObservableCollection<SaveModel> _views;
+        private AccountManager _accountManager;
+
+        public string SaveManagerHeading =>
+            string.Format(LocaleManager.Instance[LocaleKeys.SaveManagerHeading], _accountManager.LastOpenedUser.Name, _accountManager.LastOpenedUser.UserId);
+
+        public int SortIndex
+        {
+            get => _sortIndex;
+            set
+            {
+                _sortIndex = value;
+                OnPropertyChanged();
+                Sort();
+            }
+        }
+
+        public int OrderIndex
+        {
+            get => _orderIndex;
+            set
+            {
+                _orderIndex = value;
+                OnPropertyChanged();
+                Sort();
+            }
+        }
+
+        public string Search
+        {
+            get => _search;
+            set
+            {
+                _search = value;
+                OnPropertyChanged();
+                Sort();
+            }
+        }
+
+        public ObservableCollection<SaveModel> Saves
+        {
+            get => _saves;
+            set
+            {
+                _saves = value;
+                OnPropertyChanged();
+                Sort();
+            }
+        }
+
+        public ObservableCollection<SaveModel> Views
+        {
+            get => _views;
+            set
+            {
+                _views = value;
+                OnPropertyChanged();
+            }
+        }
+
+        public UserSaveManagerViewModel(AccountManager accountManager)
+        {
+            _accountManager = accountManager;
+            _saves = new ObservableCollection<SaveModel>();
+            _views = new ObservableCollection<SaveModel>();
+        }
+
+        public void Sort()
+        {
+            Saves.AsObservableChangeSet()
+                .Filter(Filter)
+                .Sort(GetComparer())
+                .Bind(out var view).AsObservableList();
+
+            _views.Clear();
+            _views.AddRange(view);
+            OnPropertyChanged(nameof(Views));
+        }
+
+        private bool Filter(object arg)
+        {
+            if (arg is SaveModel save)
+            {
+                return string.IsNullOrWhiteSpace(_search) || save.Title.ToLower().Contains(_search.ToLower());
+            }
+
+            return false;
+        }
+
+        private IComparer<SaveModel> GetComparer()
+        {
+            switch (SortIndex)
+            {
+                case 0:
+                    return OrderIndex == 0
+                        ? SortExpressionComparer<SaveModel>.Ascending(save => save.Title)
+                        : SortExpressionComparer<SaveModel>.Descending(save => save.Title);
+                case 1:
+                    return OrderIndex == 0
+                        ? SortExpressionComparer<SaveModel>.Ascending(save => save.Size)
+                        : SortExpressionComparer<SaveModel>.Descending(save => save.Size);
+                default:
+                    return null;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.Ava/UI/Controls/UserEditor.axaml b/Ryujinx.Ava/UI/Views/User/UserEditorView.axaml
similarity index 52%
rename from Ryujinx.Ava/UI/Controls/UserEditor.axaml
rename to Ryujinx.Ava/UI/Views/User/UserEditorView.axaml
index 155f1cfecf..7e55f25e49 100644
--- a/Ryujinx.Ava/UI/Controls/UserEditor.axaml
+++ b/Ryujinx.Ava/UI/Views/User/UserEditorView.axaml
@@ -1,16 +1,20 @@
 <UserControl
-    x:Class="Ryujinx.Ava.UI.Controls.UserEditor"
+    x:Class="Ryujinx.Ava.UI.Views.User.UserEditorView"
     xmlns="https://github.com/avaloniaui"
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+    xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
     xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
+    xmlns:models="clr-namespace:Ryujinx.Ava.UI.Models"
     Margin="0"
     MinWidth="500"
     Padding="0"
     mc:Ignorable="d"
-    Focusable="True">
+    Focusable="True"
+    x:CompileBindings="True"
+    x:DataType="models:TempProfile">
     <UserControl.Resources>
         <helpers:BitmapArrayValueConverter x:Key="ByteImage" />
     </UserControl.Resources>
@@ -23,35 +27,9 @@
             <RowDefinition Height="*" />
             <RowDefinition Height="Auto" />
         </Grid.RowDefinitions>
-        <StackPanel
-            HorizontalAlignment="Left"
-            VerticalAlignment="Stretch"
-            Orientation="Vertical">
-            <Image
-                Name="ProfileImage"
-                Width="96"
-                Height="96"
-                Margin="0"
-                HorizontalAlignment="Stretch"
-                VerticalAlignment="Top"
-                Source="{Binding Image, Converter={StaticResource ByteImage}}" />
-            <Button
-                Name="ChangePictureButton"
-                Margin="5"
-                HorizontalAlignment="Stretch"
-                Click="ChangePictureButton_Click"
-                Content="{locale:Locale UserProfilesChangeProfileImage}" />
-            <Button
-                Name="AddPictureButton"
-                Margin="5"
-                HorizontalAlignment="Stretch"
-                Click="ChangePictureButton_Click"
-                Content="{locale:Locale UserProfilesSetProfileImage}" />
-        </StackPanel>
         <StackPanel
             Grid.Row="0"
-            Grid.Column="1"
-            Margin="5,10"
+            Grid.Column="0"
             HorizontalAlignment="Stretch"
             Orientation="Vertical"
             Spacing="10">
@@ -61,9 +39,60 @@
                 Width="300"
                 HorizontalAlignment="Stretch"
                 MaxLength="{Binding MaxProfileNameLength}"
+                Watermark="{locale:Locale ProfileNameSelectionWatermark}"
                 Text="{Binding Name}" />
             <TextBlock Name="IdText" Text="{locale:Locale UserProfilesUserId}" />
-            <TextBlock Name="IdLabel" Text="{Binding UserId}" />
+            <TextBox
+                Name="IdLabel"
+                Width="300"
+                HorizontalAlignment="Stretch"
+                IsReadOnly="True"
+                Text="{Binding UserIdString}" />
+        </StackPanel>
+        <StackPanel
+            Grid.Row="0"
+            Grid.Column="1"
+            HorizontalAlignment="Right"
+            VerticalAlignment="Stretch"
+            Orientation="Vertical">
+            <Border
+                BorderBrush="{DynamicResource AppListHoverBackgroundColor}"
+                BorderThickness="1">
+                <Panel>
+                    <ui:SymbolIcon
+                        FontSize="60"
+                        Width="96"
+                        Height="96"
+                        Margin="0"
+                        Foreground="{DynamicResource AppListHoverBackgroundColor}"
+                        HorizontalAlignment="Stretch"
+                        VerticalAlignment="Top"
+                        Symbol="Camera" />
+                    <Image
+                        Name="ProfileImage"
+                        Width="96"
+                        Height="96"
+                        Margin="0"
+                        HorizontalAlignment="Stretch"
+                        VerticalAlignment="Top"
+                        Source="{Binding Image, Converter={StaticResource ByteImage}}" />
+                </Panel>
+            </Border>
+        </StackPanel>
+        <StackPanel
+            Grid.Row="1"
+            Grid.Column="0"
+            Grid.ColumnSpan="2"
+            HorizontalAlignment="Left"
+            Orientation="Horizontal"
+            Margin="0 24 0 0"
+            Spacing="10">
+            <Button
+                Width="50"
+                MinWidth="50"
+                Click="BackButton_Click">
+                <ui:SymbolIcon Symbol="Back" />
+            </Button>
         </StackPanel>
         <StackPanel
             Grid.Row="1"
@@ -71,16 +100,24 @@
             Grid.ColumnSpan="2"
             HorizontalAlignment="Right"
             Orientation="Horizontal"
+            Margin="0 24 0 0"
             Spacing="10">
+            <Button
+                Name="DeleteButton"
+                Click="DeleteButton_Click"
+                Content="{locale:Locale UserProfilesDelete}" />
+            <Button
+                Name="ChangePictureButton"
+                Click="ChangePictureButton_Click"
+                Content="{locale:Locale UserProfilesChangeProfileImage}" />
+            <Button
+                Name="AddPictureButton"
+                Click="ChangePictureButton_Click"
+                Content="{locale:Locale UserProfilesSetProfileImage}" />
             <Button
                 Name="SaveButton"
                 Click="SaveButton_Click"
                 Content="{locale:Locale Save}" />
-            <Button
-                Name="CloseButton"
-                HorizontalAlignment="Right"
-                Click="CloseButton_Click"
-                Content="{locale:Locale Discard}" />
         </StackPanel>
     </Grid>
-</UserControl>
+</UserControl>
\ No newline at end of file
diff --git a/Ryujinx.Ava/UI/Controls/UserEditor.axaml.cs b/Ryujinx.Ava/UI/Views/User/UserEditorView.axaml.cs
similarity index 52%
rename from Ryujinx.Ava/UI/Controls/UserEditor.axaml.cs
rename to Ryujinx.Ava/UI/Views/User/UserEditorView.axaml.cs
index 18bb8b22e8..fb33dcf8fd 100644
--- a/Ryujinx.Ava/UI/Controls/UserEditor.axaml.cs
+++ b/Ryujinx.Ava/UI/Views/User/UserEditorView.axaml.cs
@@ -4,13 +4,16 @@ using Avalonia.Interactivity;
 using FluentAvalonia.UI.Controls;
 using FluentAvalonia.UI.Navigation;
 using Ryujinx.Ava.Common.Locale;
-using Ryujinx.Ava.UI.Helpers;
+using Ryujinx.Ava.UI.Controls;
 using Ryujinx.Ava.UI.Models;
+using Ryujinx.Ava.UI.Helpers;
+using Ryujinx.HLE.HOS.Services.Account.Acc;
+using System;
 using UserProfile = Ryujinx.Ava.UI.Models.UserProfile;
 
-namespace Ryujinx.Ava.UI.Controls
+namespace Ryujinx.Ava.UI.Views.User
 {
-    public partial class UserEditor : UserControl
+    public partial class UserEditorView : UserControl
     {
         private NavigationDialogHost _parent;
         private UserProfile _profile;
@@ -18,8 +21,9 @@ namespace Ryujinx.Ava.UI.Controls
 
         public TempProfile TempProfile { get; set; }
         public uint MaxProfileNameLength => 0x20;
+        public bool IsDeletable => _profile.UserId != AccountManager.DefaultUserId;
 
-        public UserEditor()
+        public UserEditorView()
         {
             InitializeComponent();
             AddHandler(Frame.NavigatedToEvent, (s, e) =>
@@ -44,41 +48,84 @@ namespace Ryujinx.Ava.UI.Controls
                         break;
                 }
 
+                ((ContentDialog)_parent.Parent).Title = $"{LocaleManager.Instance[LocaleKeys.UserProfileWindowTitle]} - " +
+                                                        $"{ (_isNewUser ? LocaleManager.Instance[LocaleKeys.UserEditorTitleCreate] : LocaleManager.Instance[LocaleKeys.UserEditorTitle])}";
+
                 DataContext = TempProfile;
 
                 AddPictureButton.IsVisible = _isNewUser;
+                ChangePictureButton.IsVisible = !_isNewUser;
                 IdLabel.IsVisible = _profile != null;
                 IdText.IsVisible = _profile != null;
-                ChangePictureButton.IsVisible = !_isNewUser;
+                if (!_isNewUser && IsDeletable)
+                {
+                    DeleteButton.IsVisible = true;
+                }
+                else
+                {
+                    DeleteButton.IsVisible = false;
+                }
             }
         }
 
-        private void CloseButton_Click(object sender, RoutedEventArgs e)
+        private async void BackButton_Click(object sender, RoutedEventArgs e)
         {
-            _parent?.GoBack();
+            if (_isNewUser)
+            {
+                if (TempProfile.Name != String.Empty || TempProfile.Image != null)
+                {
+                    if (await ContentDialogHelper.CreateChoiceDialog(
+                            LocaleManager.Instance[LocaleKeys.DialogUserProfileUnsavedChangesTitle],
+                            LocaleManager.Instance[LocaleKeys.DialogUserProfileUnsavedChangesMessage],
+                            LocaleManager.Instance[LocaleKeys.DialogUserProfileUnsavedChangesSubMessage]))
+                    {
+                        _parent?.GoBack();
+                    }
+                }
+                else
+                {
+                    _parent?.GoBack();
+                }
+            }
+            else
+            {
+                if (_profile.Name != TempProfile.Name || _profile.Image != TempProfile.Image)
+                {
+                    if (await ContentDialogHelper.CreateChoiceDialog(
+                            LocaleManager.Instance[LocaleKeys.DialogUserProfileUnsavedChangesTitle],
+                            LocaleManager.Instance[LocaleKeys.DialogUserProfileUnsavedChangesMessage],
+                            LocaleManager.Instance[LocaleKeys.DialogUserProfileUnsavedChangesSubMessage]))
+                    {
+                        _parent?.GoBack();
+                    }
+                }
+                else
+                {
+                    _parent?.GoBack();
+                }
+            }
         }
 
-        private async void SaveButton_Click(object sender, RoutedEventArgs e)
+        private void DeleteButton_Click(object sender, RoutedEventArgs e)
+        {
+            _parent.DeleteUser(_profile);
+        }
+
+        private void SaveButton_Click(object sender, RoutedEventArgs e)
         {
             DataValidationErrors.ClearErrors(NameBox);
-            bool isInvalid = false;
 
             if (string.IsNullOrWhiteSpace(TempProfile.Name))
             {
                 DataValidationErrors.SetError(NameBox, new DataValidationException(LocaleManager.Instance[LocaleKeys.UserProfileEmptyNameError]));
 
-                isInvalid = true;
+                return;
             }
 
             if (TempProfile.Image == null)
             {
-                await ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance[LocaleKeys.UserProfileNoImageError], "");
+                _parent.Navigate(typeof(UserProfileImageSelectorView), (_parent, TempProfile));
 
-                isInvalid = true;
-            }
-
-            if(isInvalid)
-            {
                 return;
             }
 
@@ -104,7 +151,7 @@ namespace Ryujinx.Ava.UI.Controls
 
         public void SelectProfileImage()
         {
-            _parent.Navigate(typeof(ProfileImageSelectionDialog), (_parent, TempProfile));
+            _parent.Navigate(typeof(UserProfileImageSelectorView), (_parent, TempProfile));
         }
 
         private void ChangePictureButton_Click(object sender, RoutedEventArgs e)
diff --git a/Ryujinx.Ava/UI/Views/User/UserFirmwareAvatarSelectorView.axaml b/Ryujinx.Ava/UI/Views/User/UserFirmwareAvatarSelectorView.axaml
new file mode 100644
index 0000000000..d46fcefc23
--- /dev/null
+++ b/Ryujinx.Ava/UI/Views/User/UserFirmwareAvatarSelectorView.axaml
@@ -0,0 +1,114 @@
+<UserControl
+    xmlns="https://github.com/avaloniaui"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+    xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
+    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+    mc:Ignorable="d"
+    Width="528"
+    d:DesignWidth="578"
+    d:DesignHeight="350"
+    x:Class="Ryujinx.Ava.UI.Views.User.UserFirmwareAvatarSelectorView"
+    xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
+    xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
+    xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
+    x:CompileBindings="True"
+    x:DataType="viewModels:UserFirmwareAvatarSelectorViewModel"
+    Focusable="True">
+    <Design.DataContext>
+        <viewModels:UserFirmwareAvatarSelectorViewModel />
+    </Design.DataContext>
+	<UserControl.Resources>
+		<helpers:BitmapArrayValueConverter x:Key="ByteImage" />
+	</UserControl.Resources>
+    <Grid
+        Margin="0"
+        HorizontalAlignment="Stretch"
+        VerticalAlignment="Stretch">
+        <Grid.RowDefinitions>
+            <RowDefinition Height="Auto" />
+            <RowDefinition Height="*" />
+            <RowDefinition Height="Auto" />
+            <RowDefinition Height="Auto" />
+        </Grid.RowDefinitions>
+        <ListBox
+            Grid.Row="1"
+            BorderThickness="0"
+            SelectedIndex="{Binding SelectedIndex}"
+            Height="400"
+            Items="{Binding Images}"
+            HorizontalAlignment="Stretch"
+            VerticalAlignment="Center">
+            <ListBox.ItemsPanel>
+                <ItemsPanelTemplate>
+                    <WrapPanel
+                        Orientation="Horizontal"
+                        Margin="0"
+                        HorizontalAlignment="Center" />
+                </ItemsPanelTemplate>
+            </ListBox.ItemsPanel>
+            <ListBox.Styles>
+                <Style Selector="ListBoxItem">
+                    <Setter Property="CornerRadius" Value="4" />
+                    <Setter Property="Width" Value="85" />
+                    <Setter Property="MaxWidth" Value="85" />
+                    <Setter Property="MinWidth" Value="85" />
+                </Style>
+                <Style Selector="ListBoxItem /template/ Border#SelectionIndicator">
+                    <Setter Property="MinHeight" Value="70" />
+                </Style>
+            </ListBox.Styles>
+            <ListBox.ItemTemplate>
+                <DataTemplate>
+                    <Panel
+                        Background="{Binding BackgroundColor}"
+                        Margin="5">
+                        <Image Source="{Binding Data, Converter={StaticResource ByteImage}}" />
+                    </Panel>
+                </DataTemplate>
+            </ListBox.ItemTemplate>
+        </ListBox>
+        <StackPanel
+            Grid.Row="3"
+            Orientation="Horizontal"
+            Spacing="10"
+            Margin="0 24 0 0"
+            HorizontalAlignment="Left">
+            <Button
+                Width="50"
+                MinWidth="50"
+                Height="35"
+                Click="GoBack">
+                <ui:SymbolIcon Symbol="Back" />
+            </Button>
+        </StackPanel>
+        <StackPanel
+            Grid.Row="3"
+            Orientation="Horizontal"
+            Spacing="10"
+            Margin="0 24 0 0"
+            HorizontalAlignment="Right">
+            <ui:ColorPickerButton
+                FlyoutPlacement="Top"
+                IsMoreButtonVisible="False"
+                UseColorPalette="False"
+                UseColorTriangle="False"
+                UseColorWheel="False"
+                ShowAcceptDismissButtons="False"
+                IsAlphaEnabled="False"
+                Color="{Binding BackgroundColor, Mode=TwoWay}"
+                Name="ColorButton">
+                <ui:ColorPickerButton.Styles>
+                    <Style Selector="Grid#Root > DockPanel > Grid">
+                        <Setter Property="IsVisible" Value="False" />
+                    </Style>
+                </ui:ColorPickerButton.Styles>
+            </ui:ColorPickerButton>
+            <Button
+                Content="{locale:Locale AvatarChoose}"
+                Height="35"
+                Name="ChooseButton"
+                Click="ChooseButton_OnClick" />
+        </StackPanel>
+    </Grid>
+</UserControl>
\ No newline at end of file
diff --git a/Ryujinx.Ava/UI/Windows/AvatarWindow.axaml.cs b/Ryujinx.Ava/UI/Views/User/UserFirmwareAvatarSelectorView.axaml.cs
similarity index 55%
rename from Ryujinx.Ava/UI/Windows/AvatarWindow.axaml.cs
rename to Ryujinx.Ava/UI/Views/User/UserFirmwareAvatarSelectorView.axaml.cs
index e060d65e90..7c9191ab2d 100644
--- a/Ryujinx.Ava/UI/Windows/AvatarWindow.axaml.cs
+++ b/Ryujinx.Ava/UI/Views/User/UserFirmwareAvatarSelectorView.axaml.cs
@@ -6,15 +6,20 @@ using Ryujinx.Ava.UI.Controls;
 using Ryujinx.Ava.UI.Models;
 using Ryujinx.Ava.UI.ViewModels;
 using Ryujinx.HLE.FileSystem;
+using SixLabors.ImageSharp;
+using SixLabors.ImageSharp.Formats.Png;
+using SixLabors.ImageSharp.PixelFormats;
+using SixLabors.ImageSharp.Processing;
+using System.IO;
 
-namespace Ryujinx.Ava.UI.Windows
+namespace Ryujinx.Ava.UI.Views.User
 {
-    public partial class AvatarWindow : UserControl
+    public partial class UserFirmwareAvatarSelectorView : UserControl
     {
         private NavigationDialogHost _parent;
         private TempProfile _profile;
 
-        public AvatarWindow(ContentManager contentManager)
+        public UserFirmwareAvatarSelectorView(ContentManager contentManager)
         {
             ContentManager = contentManager;
 
@@ -23,7 +28,7 @@ namespace Ryujinx.Ava.UI.Windows
             InitializeComponent();
         }
 
-        public AvatarWindow()
+        public UserFirmwareAvatarSelectorView()
         {
             InitializeComponent();
 
@@ -43,7 +48,7 @@ namespace Ryujinx.Ava.UI.Windows
                     ContentManager = _parent.ContentManager;
                     if (Program.PreviewerDetached)
                     {
-                        ViewModel = new AvatarProfileViewModel(() => ViewModel.ReloadImages());
+                        ViewModel = new UserFirmwareAvatarSelectorViewModel();
                     }
 
                     DataContext = ViewModel;
@@ -53,22 +58,28 @@ namespace Ryujinx.Ava.UI.Windows
 
         public ContentManager ContentManager { get; private set; }
 
-        internal AvatarProfileViewModel ViewModel { get; set; }
+        internal UserFirmwareAvatarSelectorViewModel ViewModel { get; set; }
 
-        private void CloseButton_OnClick(object sender, RoutedEventArgs e)
+        private void GoBack(object sender, RoutedEventArgs e)
         {
-            ViewModel.Dispose();
-
             _parent.GoBack();
         }
 
         private void ChooseButton_OnClick(object sender, RoutedEventArgs e)
         {
-            if (ViewModel.SelectedIndex > -1)
+            if (ViewModel.SelectedImage != null)
             {
-                _profile.Image = ViewModel.SelectedImage;
+                MemoryStream streamJpg = new();
+                SixLabors.ImageSharp.Image avatarImage = SixLabors.ImageSharp.Image.Load(ViewModel.SelectedImage, new PngDecoder());
 
-                ViewModel.Dispose();
+                avatarImage.Mutate(x => x.BackgroundColor(new Rgba32(
+                    ViewModel.BackgroundColor.R,
+                    ViewModel.BackgroundColor.G,
+                    ViewModel.BackgroundColor.B,
+                    ViewModel.BackgroundColor.A)));
+                avatarImage.SaveAsJpeg(streamJpg);
+
+                _profile.Image = streamJpg.ToArray();
 
                 _parent.GoBack();
             }
diff --git a/Ryujinx.Ava/UI/Views/User/UserProfileImageSelectorView.axaml b/Ryujinx.Ava/UI/Views/User/UserProfileImageSelectorView.axaml
new file mode 100644
index 0000000000..b9f51fdc7a
--- /dev/null
+++ b/Ryujinx.Ava/UI/Views/User/UserProfileImageSelectorView.axaml
@@ -0,0 +1,63 @@
+<UserControl
+    xmlns="https://github.com/avaloniaui"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+    xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
+    xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
+    xmlns:viewModles="clr-namespace:Ryujinx.Ava.UI.ViewModels"
+    Focusable="True"
+    mc:Ignorable="d"
+    x:Class="Ryujinx.Ava.UI.Views.User.UserProfileImageSelectorView"
+    x:CompileBindings="True"
+    x:DataType="viewModles:UserProfileImageSelectorViewModel"
+    Width="500"
+    d:DesignWidth="500">
+    <Design.DataContext>
+        <viewModles:UserProfileImageSelectorViewModel />
+    </Design.DataContext>
+    <Grid
+        HorizontalAlignment="Stretch"
+        VerticalAlignment="Center">
+        <Grid.RowDefinitions>
+            <RowDefinition Height="Auto" />
+            <RowDefinition Height="70" />
+            <RowDefinition Height="Auto" />
+        </Grid.RowDefinitions>
+        <TextBlock
+            Grid.Row="0"
+            TextWrapping="Wrap"
+            HorizontalAlignment="Left"
+            TextAlignment="Left"
+            Text="{locale:Locale ProfileImageSelectionNote}" />
+        <StackPanel
+            Grid.Row="2"
+            Spacing="10"
+            HorizontalAlignment="Left"
+            Orientation="Horizontal">
+            <Button
+                Width="50"
+                MinWidth="50"
+                Click="GoBack">
+                <ui:SymbolIcon Symbol="Back" />
+            </Button>
+        </StackPanel>
+        <StackPanel
+            Grid.Row="2"
+            Spacing="10"
+            HorizontalAlignment="Right"
+            Orientation="Horizontal">
+            <Button
+                Name="Import"
+                Click="Import_OnClick">
+                <TextBlock Text="{locale:Locale ProfileImageSelectionImportImage}" />
+            </Button>
+            <Button
+                Name="SelectFirmwareImage"
+                IsEnabled="{Binding FirmwareFound}"
+                Click="SelectFirmwareImage_OnClick">
+                <TextBlock Text="{locale:Locale ProfileImageSelectionSelectAvatar}" />
+            </Button>
+        </StackPanel>
+    </Grid>
+</UserControl>
\ No newline at end of file
diff --git a/Ryujinx.Ava/UI/Controls/ProfileImageSelectionDialog.axaml.cs b/Ryujinx.Ava/UI/Views/User/UserProfileImageSelectorView.axaml.cs
similarity index 69%
rename from Ryujinx.Ava/UI/Controls/ProfileImageSelectionDialog.axaml.cs
rename to Ryujinx.Ava/UI/Views/User/UserProfileImageSelectorView.axaml.cs
index 46a2f5079b..18f76f805c 100644
--- a/Ryujinx.Ava/UI/Controls/ProfileImageSelectionDialog.axaml.cs
+++ b/Ryujinx.Ava/UI/Views/User/UserProfileImageSelectorView.axaml.cs
@@ -4,25 +4,26 @@ using Avalonia.VisualTree;
 using FluentAvalonia.UI.Controls;
 using FluentAvalonia.UI.Navigation;
 using Ryujinx.Ava.Common.Locale;
+using Ryujinx.Ava.UI.Controls;
 using Ryujinx.Ava.UI.Models;
-using Ryujinx.Ava.UI.Windows;
+using Ryujinx.Ava.UI.ViewModels;
 using Ryujinx.HLE.FileSystem;
 using SixLabors.ImageSharp;
 using SixLabors.ImageSharp.Processing;
 using System.IO;
 using Image = SixLabors.ImageSharp.Image;
 
-namespace Ryujinx.Ava.UI.Controls
+namespace Ryujinx.Ava.UI.Views.User
 {
-    public partial class ProfileImageSelectionDialog : UserControl
+    public partial class UserProfileImageSelectorView : UserControl
     {
         private ContentManager _contentManager;
         private NavigationDialogHost _parent;
         private TempProfile _profile;
 
-        public bool FirmwareFound => _contentManager.GetCurrentFirmwareVersion() != null;
+        internal UserProfileImageSelectorViewModel ViewModel { get; private set; }
 
-        public ProfileImageSelectionDialog()
+        public UserProfileImageSelectorView()
         {
             InitializeComponent();
             AddHandler(Frame.NavigatedToEvent, (s, e) =>
@@ -40,13 +41,23 @@ namespace Ryujinx.Ava.UI.Controls
                     case NavigationMode.New:
                         (_parent, _profile) = ((NavigationDialogHost, TempProfile))arg.Parameter;
                         _contentManager = _parent.ContentManager;
+
+                        ((ContentDialog)_parent.Parent).Title = $"{LocaleManager.Instance[LocaleKeys.UserProfileWindowTitle]} - {LocaleManager.Instance[LocaleKeys.ProfileImageSelectionHeader]}";
+
+                        if (Program.PreviewerDetached)
+                        {
+                            DataContext = ViewModel = new UserProfileImageSelectorViewModel();
+                            ViewModel.FirmwareFound = _contentManager.GetCurrentFirmwareVersion() != null;
+                        }
+
                         break;
                     case NavigationMode.Back:
-                        _parent.GoBack();
+                        if (_profile.Image != null)
+                        {
+                            _parent.GoBack();
+                        }
                         break;
                 }
-
-                DataContext = this;
             }
         }
 
@@ -73,17 +84,25 @@ namespace Ryujinx.Ava.UI.Controls
                     string imageFile = image[0];
 
                     _profile.Image = ProcessProfileImage(File.ReadAllBytes(imageFile));
-                }
 
-                _parent.GoBack();
+                    if (_profile.Image != null)
+                    {
+                        _parent.GoBack();
+                    }
+                }
             }
         }
 
+        private void GoBack(object sender, RoutedEventArgs e)
+        {
+            _parent.GoBack();
+        }
+
         private void SelectFirmwareImage_OnClick(object sender, RoutedEventArgs e)
         {
-            if (FirmwareFound)
+            if (ViewModel.FirmwareFound)
             {
-                _parent.Navigate(typeof(AvatarWindow), (_parent, _profile));
+                _parent.Navigate(typeof(UserFirmwareAvatarSelectorView), (_parent, _profile));
             }
         }
 
diff --git a/Ryujinx.Ava/UI/Views/User/UserRecovererView.axaml b/Ryujinx.Ava/UI/Views/User/UserRecovererView.axaml
new file mode 100644
index 0000000000..62b5e1840b
--- /dev/null
+++ b/Ryujinx.Ava/UI/Views/User/UserRecovererView.axaml
@@ -0,0 +1,83 @@
+<UserControl
+    xmlns="https://github.com/avaloniaui"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+    mc:Ignorable="d"
+    d:DesignWidth="550"
+    d:DesignHeight="450"
+    Width="500"
+    Height="400"
+    xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
+    xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
+    xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
+    x:Class="Ryujinx.Ava.UI.Views.User.UserRecovererView"
+    x:CompileBindings="True"
+    x:DataType="viewModels:UserProfileViewModel"
+    Focusable="True">
+    <Design.DataContext>
+        <viewModels:UserProfileViewModel />
+    </Design.DataContext>
+    <Grid HorizontalAlignment="Stretch"
+          VerticalAlignment="Stretch">
+        <Grid.RowDefinitions>
+            <RowDefinition/>
+            <RowDefinition Height="Auto"/>
+        </Grid.RowDefinitions>
+        <Border
+            CornerRadius="5"
+            BorderBrush="{DynamicResource AppListHoverBackgroundColor}"
+            BorderThickness="1"
+            Grid.Row="0">
+            <Panel>
+                <ListBox
+                    HorizontalAlignment="Stretch"
+                    VerticalAlignment="Stretch"
+                    Items="{Binding LostProfiles}">
+                    <ListBox.ItemTemplate>
+                        <DataTemplate>
+                            <Border
+                                Margin="2"
+                                HorizontalAlignment="Stretch"
+                                VerticalAlignment="Stretch"
+                                ClipToBounds="True"
+                                CornerRadius="5">
+                                <Grid Margin="0">
+                                    <Grid.ColumnDefinitions>
+                                        <ColumnDefinition/>
+                                        <ColumnDefinition Width="Auto"/>
+                                    </Grid.ColumnDefinitions>
+                                    <TextBlock
+                                        HorizontalAlignment="Stretch"
+                                        Text="{Binding UserId}"
+                                        TextAlignment="Left"
+                                        TextWrapping="Wrap" />
+                                    <Button Grid.Column="1"
+                                            HorizontalAlignment="Right"
+                                            Click="Recover"
+                                            CommandParameter="{Binding}"
+                                            Content="{locale:Locale Recover}"/>
+                                </Grid>
+                            </Border>
+                        </DataTemplate>
+                    </ListBox.ItemTemplate>
+                </ListBox>
+                <TextBlock
+                    IsVisible="{Binding IsEmpty}"
+                    TextAlignment="Center"
+                    Text="{locale:Locale UserProfilesRecoverEmptyList}"/>
+            </Panel>
+        </Border>
+        <StackPanel
+            Grid.Row="1"
+            Margin="0 24 0 0"
+            Orientation="Horizontal">
+            <Button
+                Width="50"
+                MinWidth="50"
+                Click="GoBack">
+                <ui:SymbolIcon Symbol="Back"/>
+            </Button>
+        </StackPanel>
+    </Grid>
+</UserControl>
\ No newline at end of file
diff --git a/Ryujinx.Ava/UI/Views/User/UserRecovererView.axaml.cs b/Ryujinx.Ava/UI/Views/User/UserRecovererView.axaml.cs
new file mode 100644
index 0000000000..0c53e53d70
--- /dev/null
+++ b/Ryujinx.Ava/UI/Views/User/UserRecovererView.axaml.cs
@@ -0,0 +1,51 @@
+using Avalonia.Controls;
+using Avalonia.Interactivity;
+using FluentAvalonia.UI.Controls;
+using FluentAvalonia.UI.Navigation;
+using Ryujinx.Ava.Common.Locale;
+using Ryujinx.Ava.UI.Controls;
+
+namespace Ryujinx.Ava.UI.Views.User
+{
+    public partial class UserRecovererView : UserControl
+    {
+        private NavigationDialogHost _parent;
+
+        public UserRecovererView()
+        {
+            InitializeComponent();
+            AddHandler(Frame.NavigatedToEvent, (s, e) =>
+            {
+                NavigatedTo(e);
+            }, RoutingStrategies.Direct);
+        }
+
+        private void NavigatedTo(NavigationEventArgs arg)
+        {
+            if (Program.PreviewerDetached)
+            {
+                switch (arg.NavigationMode)
+                {
+                    case NavigationMode.New:
+                        var parent = (NavigationDialogHost)arg.Parameter;
+
+                        _parent = parent;
+
+                        ((ContentDialog)_parent.Parent).Title = $"{LocaleManager.Instance[LocaleKeys.UserProfileWindowTitle]} - {LocaleManager.Instance[LocaleKeys.UserProfilesRecoverHeading]}";
+
+                        break;
+                }
+            }
+        }
+
+        private void GoBack(object sender, RoutedEventArgs e)
+        {
+            _parent?.GoBack();
+        }
+
+        private void Recover(object sender, RoutedEventArgs e)
+        {
+            _parent?.RecoverLostAccounts();
+        }
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.Ava/UI/Views/User/UserSaveManagerView.axaml b/Ryujinx.Ava/UI/Views/User/UserSaveManagerView.axaml
new file mode 100644
index 0000000000..cdf74d52f1
--- /dev/null
+++ b/Ryujinx.Ava/UI/Views/User/UserSaveManagerView.axaml
@@ -0,0 +1,199 @@
+<UserControl
+    xmlns="https://github.com/avaloniaui"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+    xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
+    xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
+    xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
+    xmlns:models="clr-namespace:Ryujinx.Ava.UI.Models"
+    xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
+    mc:Ignorable="d"
+    d:DesignWidth="600"
+    d:DesignHeight="500"
+    Height="450"
+    Width="550"
+    x:Class="Ryujinx.Ava.UI.Views.User.UserSaveManagerView"
+    x:CompileBindings="True"
+    x:DataType="viewModels:UserSaveManagerViewModel"
+    Focusable="True">
+    <Design.DataContext>
+        <viewModels:UserSaveManagerViewModel />
+    </Design.DataContext>
+    <UserControl.Resources>
+        <helpers:BitmapArrayValueConverter x:Key="ByteImage" />
+    </UserControl.Resources>
+    <Grid>
+        <Grid.RowDefinitions>
+            <RowDefinition Height="Auto" />
+            <RowDefinition />
+            <RowDefinition Height="Auto" />
+        </Grid.RowDefinitions>
+        <Grid
+            Grid.Row="0"
+            HorizontalAlignment="Stretch">
+            <Grid.ColumnDefinitions>
+                <ColumnDefinition Width="Auto" />
+                <ColumnDefinition />
+            </Grid.ColumnDefinitions>
+            <StackPanel
+                Spacing="10"
+                Orientation="Horizontal"
+                HorizontalAlignment="Left"
+                VerticalAlignment="Center">
+                <Label Content="{locale:Locale CommonSort}" VerticalAlignment="Center" />
+                <ComboBox SelectedIndex="{Binding SortIndex}" Width="100">
+                    <ComboBoxItem>
+                        <Label
+                            VerticalAlignment="Center"
+                            HorizontalContentAlignment="Left"
+                            Content="{locale:Locale Name}" />
+                    </ComboBoxItem>
+                    <ComboBoxItem>
+                        <Label
+                            VerticalAlignment="Center"
+                            HorizontalContentAlignment="Left"
+                            Content="{locale:Locale Size}" />
+                    </ComboBoxItem>
+                </ComboBox>
+                <ComboBox SelectedIndex="{Binding OrderIndex}" Width="150">
+                    <ComboBoxItem>
+                        <Label
+                            VerticalAlignment="Center"
+                            HorizontalContentAlignment="Left"
+                            Content="{locale:Locale OrderAscending}" />
+                    </ComboBoxItem>
+                    <ComboBoxItem>
+                        <Label
+                            VerticalAlignment="Center"
+                            HorizontalContentAlignment="Left"
+                            Content="{locale:Locale OrderDescending}" />
+                    </ComboBoxItem>
+                </ComboBox>
+            </StackPanel>
+            <Grid
+                Grid.Column="1"
+                HorizontalAlignment="Stretch"
+                Margin="10,0, 0, 0">
+                <Grid.ColumnDefinitions>
+                    <ColumnDefinition Width="Auto"/>
+                    <ColumnDefinition/>
+                </Grid.ColumnDefinitions>
+                <Label Content="{locale:Locale Search}" VerticalAlignment="Center" />
+                <TextBox
+                    Margin="5,0,0,0"
+                    Grid.Column="1"
+                    HorizontalAlignment="Stretch"
+                    Text="{Binding Search}" />
+            </Grid>
+        </Grid>
+        <Border
+            Grid.Row="1"
+            Margin="0,5"
+            BorderThickness="1"
+            BorderBrush="{DynamicResource AppListHoverBackgroundColor}"
+            CornerRadius="5"
+            HorizontalAlignment="Stretch"
+            VerticalAlignment="Stretch">
+            <ListBox
+                Name="SaveList"
+                Items="{Binding Views}"
+                HorizontalAlignment="Stretch"
+                VerticalAlignment="Stretch">
+                <ListBox.Styles>
+                    <Style Selector="ListBoxItem">
+                        <Setter Property="Padding" Value="10" />
+                        <Setter Property="Margin" Value="5" />
+                        <Setter Property="CornerRadius" Value="4" />
+                    </Style>
+                </ListBox.Styles>
+                <ListBox.ItemTemplate>
+                    <DataTemplate x:DataType="models:SaveModel">
+                        <Grid HorizontalAlignment="Stretch">
+                            <Grid.ColumnDefinitions>
+                                <ColumnDefinition />
+                                <ColumnDefinition Width="Auto" />
+                            </Grid.ColumnDefinitions>
+                            <StackPanel
+                                Grid.Column="0"
+                                Orientation="Horizontal"
+                                Spacing="5">
+                                <Border
+                                    Height="42"
+                                    Width="42"
+                                    Padding="10"
+                                    IsVisible="{Binding !InGameList}">
+                                    <ui:SymbolIcon
+                                        Symbol="Help"
+                                        FontSize="30"
+                                        HorizontalAlignment="Center"
+                                        VerticalAlignment="Center" />
+                                </Border>
+                                <Image
+                                    IsVisible="{Binding InGameList}"
+                                    Width="42"
+                                    Height="42"
+                                    Source="{Binding Icon, Converter={StaticResource ByteImage}}" />
+                                <TextBlock
+                                    MaxLines="3"
+                                    Width="320"
+                                    Margin="5"
+                                    TextWrapping="Wrap"
+                                    Text="{Binding  Title}"
+                                    VerticalAlignment="Center" />
+                            </StackPanel>
+                            <StackPanel
+                                Grid.Column="1"
+                                Spacing="10"
+                                HorizontalAlignment="Right"
+                                Orientation="Horizontal">
+                                <Label
+                                    Content="{Binding SizeString}"
+                                    IsVisible="{Binding SizeAvailable}"
+                                    VerticalAlignment="Center"
+                                    HorizontalAlignment="Right" />
+                                <Button
+                                    VerticalAlignment="Center"
+                                    HorizontalAlignment="Right"
+                                    Padding="10"
+                                    MinWidth="0"
+                                    MinHeight="0"
+                                    Name="OpenLocation"
+                                    Click="OpenLocation">
+                                    <ui:SymbolIcon
+                                        Symbol="OpenFolder"
+                                        HorizontalAlignment="Center"
+                                        VerticalAlignment="Center" />
+                                </Button>
+                                <Button
+                                    VerticalAlignment="Center"
+                                    HorizontalAlignment="Right"
+                                    Padding="10"
+                                    MinWidth="0"
+                                    MinHeight="0"
+                                    Name="Delete"
+                                    Click="Delete">
+                                    <ui:SymbolIcon
+                                        Symbol="Delete"
+                                        HorizontalAlignment="Center"
+                                        VerticalAlignment="Center" />
+                                </Button>
+                            </StackPanel>
+                        </Grid>
+                    </DataTemplate>
+                </ListBox.ItemTemplate>
+            </ListBox>
+        </Border>
+        <StackPanel
+            Grid.Row="2"
+            Margin="0 24 0 0"
+            Orientation="Horizontal">
+            <Button
+                Width="50"
+                MinWidth="50"
+                Click="GoBack">
+                <ui:SymbolIcon Symbol="Back" />
+            </Button>
+        </StackPanel>
+    </Grid>
+</UserControl>
\ No newline at end of file
diff --git a/Ryujinx.Ava/UI/Views/User/UserSaveManagerView.axaml.cs b/Ryujinx.Ava/UI/Views/User/UserSaveManagerView.axaml.cs
new file mode 100644
index 0000000000..9d955326f7
--- /dev/null
+++ b/Ryujinx.Ava/UI/Views/User/UserSaveManagerView.axaml.cs
@@ -0,0 +1,148 @@
+using Avalonia.Controls;
+using Avalonia.Interactivity;
+using Avalonia.Threading;
+using FluentAvalonia.UI.Controls;
+using FluentAvalonia.UI.Navigation;
+using LibHac;
+using LibHac.Common;
+using LibHac.Fs;
+using LibHac.Fs.Shim;
+using Ryujinx.Ava.Common;
+using Ryujinx.Ava.Common.Locale;
+using Ryujinx.Ava.UI.Controls;
+using Ryujinx.Ava.UI.Helpers;
+using Ryujinx.Ava.UI.Models;
+using Ryujinx.Ava.UI.ViewModels;
+using Ryujinx.HLE.FileSystem;
+using Ryujinx.HLE.HOS.Services.Account.Acc;
+using System;
+using System.Collections.ObjectModel;
+using System.Threading.Tasks;
+using UserId = LibHac.Fs.UserId;
+
+namespace Ryujinx.Ava.UI.Views.User
+{
+    public partial class UserSaveManagerView : UserControl
+    {
+        internal UserSaveManagerViewModel ViewModel { get; private set; }
+
+        private AccountManager _accountManager;
+        private HorizonClient _horizonClient;
+        private VirtualFileSystem _virtualFileSystem;
+        private NavigationDialogHost _parent;
+
+        public UserSaveManagerView()
+        {
+            InitializeComponent();
+            AddHandler(Frame.NavigatedToEvent, (s, e) =>
+            {
+                NavigatedTo(e);
+            }, RoutingStrategies.Direct);
+        }
+
+        private void NavigatedTo(NavigationEventArgs arg)
+        {
+            if (Program.PreviewerDetached)
+            {
+                switch (arg.NavigationMode)
+                {
+                    case NavigationMode.New:
+                        var args = ((NavigationDialogHost parent, AccountManager accountManager, HorizonClient client, VirtualFileSystem virtualFileSystem))arg.Parameter;
+                        _accountManager = args.accountManager;
+                        _horizonClient = args.client;
+                        _virtualFileSystem = args.virtualFileSystem;
+
+                        _parent = args.parent;
+                        break;
+                }
+
+                DataContext = ViewModel = new UserSaveManagerViewModel(_accountManager);
+                ((ContentDialog)_parent.Parent).Title = $"{LocaleManager.Instance[LocaleKeys.UserProfileWindowTitle]} - {ViewModel.SaveManagerHeading}";
+
+                Task.Run(LoadSaves);
+            }
+        }
+
+        public void LoadSaves()
+        {
+            ViewModel.Saves.Clear();
+            var saves = new ObservableCollection<SaveModel>();
+            var saveDataFilter = SaveDataFilter.Make(
+                programId: default,
+                saveType: SaveDataType.Account,
+                new UserId((ulong)_accountManager.LastOpenedUser.UserId.High, (ulong)_accountManager.LastOpenedUser.UserId.Low),
+                saveDataId: default,
+                index: default);
+
+            using var saveDataIterator = new UniqueRef<SaveDataIterator>();
+
+            _horizonClient.Fs.OpenSaveDataIterator(ref saveDataIterator.Ref(), SaveDataSpaceId.User, in saveDataFilter).ThrowIfFailure();
+
+            Span<SaveDataInfo> saveDataInfo = stackalloc SaveDataInfo[10];
+
+            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];
+                    if (save.ProgramId.Value != 0)
+                    {
+                        var saveModel = new SaveModel(save, _horizonClient, _virtualFileSystem);
+                        saves.Add(saveModel);
+                    }
+                }
+            }
+
+            Dispatcher.UIThread.Post(() =>
+            {
+                ViewModel.Saves = saves;
+                ViewModel.Sort();
+            });
+        }
+
+        private void GoBack(object sender, RoutedEventArgs e)
+        {
+            _parent?.GoBack();
+        }
+
+        private void OpenLocation(object sender, RoutedEventArgs e)
+        {
+            if (sender is Avalonia.Controls.Button button)
+            {
+                if (button.DataContext is SaveModel saveModel)
+                {
+                    ApplicationHelper.OpenSaveDir(saveModel.SaveId);
+                }
+            }
+        }
+
+        private async void Delete(object sender, RoutedEventArgs e)
+        {
+            if (sender is Avalonia.Controls.Button button)
+            {
+                if (button.DataContext is SaveModel saveModel)
+                {
+                    var result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance[LocaleKeys.DeleteUserSave],
+                        LocaleManager.Instance[LocaleKeys.IrreversibleActionNote],
+                        LocaleManager.Instance[LocaleKeys.InputDialogYes],
+                        LocaleManager.Instance[LocaleKeys.InputDialogNo], "");
+
+                    if (result == UserResult.Yes)
+                    {
+                        _horizonClient.Fs.DeleteSaveData(SaveDataSpaceId.User, saveModel.SaveId);
+                    }
+
+                    ViewModel.Saves.Remove(saveModel);
+                    ViewModel.Views.Remove(saveModel);
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.Ava/UI/Views/User/UserSelectorView.axaml b/Ryujinx.Ava/UI/Views/User/UserSelectorView.axaml
new file mode 100644
index 0000000000..9a6ba054e2
--- /dev/null
+++ b/Ryujinx.Ava/UI/Views/User/UserSelectorView.axaml
@@ -0,0 +1,165 @@
+<UserControl
+    x:Class="Ryujinx.Ava.UI.Views.User.UserSelectorViews"
+    xmlns="https://github.com/avaloniaui"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
+    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+    xmlns:flex="clr-namespace:Avalonia.Flexbox;assembly=Avalonia.Flexbox"
+    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+    xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
+    xmlns:models="clr-namespace:Ryujinx.Ava.UI.Models"
+    xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
+    xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
+    d:DesignHeight="450"
+    MinWidth="500"
+    d:DesignWidth="800"
+    mc:Ignorable="d"
+    Focusable="True"
+    x:CompileBindings="True"
+    x:DataType="viewModels:UserProfileViewModel">
+    <UserControl.Resources>
+        <helpers:BitmapArrayValueConverter x:Key="ByteImage" />
+    </UserControl.Resources>
+    <Design.DataContext>
+        <viewModels:UserProfileViewModel />
+    </Design.DataContext>
+    <Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
+        <Grid.RowDefinitions>
+            <RowDefinition />
+            <RowDefinition Height="Auto" />
+        </Grid.RowDefinitions>
+        <Border
+            CornerRadius="5"
+            BorderBrush="{DynamicResource AppListHoverBackgroundColor}"
+            BorderThickness="1">
+            <ListBox
+                MaxHeight="300"
+                HorizontalAlignment="Stretch"
+                VerticalAlignment="Center"
+                SelectionChanged="ProfilesList_SelectionChanged"
+                Background="Transparent"
+                Items="{Binding Profiles}">
+                <ListBox.ItemsPanel>
+                    <ItemsPanelTemplate>
+                        <flex:FlexPanel
+                            HorizontalAlignment="Stretch"
+                            VerticalAlignment="Stretch"
+                            AlignContent="FlexStart"
+                            JustifyContent="FlexStart" />
+                    </ItemsPanelTemplate>
+                </ListBox.ItemsPanel>
+                <ListBox.Styles>
+                    <Style Selector="ListBoxItem">
+                        <Setter Property="Margin" Value="5 5 0 5" />
+                        <Setter Property="CornerRadius" Value="5" />
+                    </Style>
+                    <Style Selector="Border#SelectionIndicator">
+                        <Setter Property="Opacity" Value="0" />
+                    </Style>
+                </ListBox.Styles>
+                <ListBox.DataTemplates>
+                    <DataTemplate
+                        DataType="models:UserProfile">
+                        <Grid
+                            PointerEnter="Grid_PointerEntered"
+                            PointerLeave="Grid_OnPointerExited">
+                            <Border
+                                HorizontalAlignment="Stretch"
+                                VerticalAlignment="Stretch"
+                                ClipToBounds="True"
+                                CornerRadius="5"
+                                Background="{Binding BackgroundColor}">
+                                <StackPanel
+                                    HorizontalAlignment="Stretch"
+                                    VerticalAlignment="Stretch">
+                                    <Image
+                                        Width="96"
+                                        Height="96"
+                                        HorizontalAlignment="Stretch"
+                                        VerticalAlignment="Top"
+                                        Source="{Binding Image, Converter={StaticResource ByteImage}}" />
+                                    <TextBlock
+                                        HorizontalAlignment="Stretch"
+                                        MaxWidth="90"
+                                        Text="{Binding Name}"
+                                        TextAlignment="Center"
+                                        TextWrapping="Wrap"
+                                        TextTrimming="CharacterEllipsis"
+                                        MaxLines="2"
+                                        Margin="5" />
+                                </StackPanel>
+                            </Border>
+                            <Border
+                                Margin="2"
+                                Height="24"
+                                Width="24"
+                                CornerRadius="12"
+                                HorizontalAlignment="Right"
+                                VerticalAlignment="Top"
+                                Background="{DynamicResource ThemeContentBackgroundColor}"
+                                IsVisible="{Binding IsPointerOver}">
+                                <Button
+                                    MaxHeight="24"
+                                    MaxWidth="24"
+                                    MinHeight="24"
+                                    MinWidth="24"
+                                    CornerRadius="12"
+                                    Padding="0"
+                                    Click="EditUser">
+                                    <ui:SymbolIcon Symbol="Edit" />
+                                </Button>
+                            </Border>
+                        </Grid>
+                    </DataTemplate>
+                    <DataTemplate
+                        DataType="viewModels:BaseModel">
+                        <Panel
+                            Height="118"
+                            Width="96">
+                            <Button
+                                MinWidth="50"
+                                MinHeight="50"
+                                MaxWidth="50"
+                                MaxHeight="50"
+                                CornerRadius="25"
+                                Margin="10"
+                                Padding="0"
+                                HorizontalAlignment="Center"
+                                VerticalAlignment="Center"
+                                Click="AddUser">
+                                <ui:SymbolIcon Symbol="Add" />
+                            </Button>
+                            <Panel.Styles>
+                                <Style Selector="Panel">
+                                    <Setter Property="Background" Value="{DynamicResource ListBoxBackground}"/>
+                                </Style>
+                            </Panel.Styles>
+                        </Panel>
+                    </DataTemplate>
+                </ListBox.DataTemplates>
+            </ListBox>
+        </Border>
+        <StackPanel
+            Grid.Row="1"
+            Margin="0 24 0 0"
+            HorizontalAlignment="Left"
+            Orientation="Horizontal"
+            Spacing="10">
+            <Button
+                Click="ManageSaves"
+                Content="{locale:Locale UserProfilesManageSaves}" />
+            <Button
+                Click="RecoverLostAccounts"
+                Content="{locale:Locale UserProfilesRecoverLostAccounts}" />
+        </StackPanel>
+        <StackPanel
+            Grid.Row="1"
+            Margin="0 24 0 0"
+            HorizontalAlignment="Right"
+            Orientation="Horizontal">
+            <Button
+                Click="Close"
+                Content="{locale:Locale UserProfilesClose}" />
+        </StackPanel>
+    </Grid>
+</UserControl>
\ No newline at end of file
diff --git a/Ryujinx.Ava/UI/Views/User/UserSelectorView.axaml.cs b/Ryujinx.Ava/UI/Views/User/UserSelectorView.axaml.cs
new file mode 100644
index 0000000000..aa89fea9ee
--- /dev/null
+++ b/Ryujinx.Ava/UI/Views/User/UserSelectorView.axaml.cs
@@ -0,0 +1,128 @@
+using Avalonia.Controls;
+using Avalonia.Input;
+using Avalonia.Interactivity;
+using FluentAvalonia.UI.Controls;
+using FluentAvalonia.UI.Navigation;
+using Ryujinx.Ava.Common.Locale;
+using Ryujinx.Ava.UI.Controls;
+using Ryujinx.Ava.UI.ViewModels;
+using UserProfile = Ryujinx.Ava.UI.Models.UserProfile;
+
+namespace Ryujinx.Ava.UI.Views.User
+{
+    public partial class UserSelectorViews : UserControl
+    {
+        private NavigationDialogHost _parent;
+
+        public UserProfileViewModel ViewModel { get; set; }
+
+        public UserSelectorViews()
+        {
+            InitializeComponent();
+
+            if (Program.PreviewerDetached)
+            {
+                AddHandler(Frame.NavigatedToEvent, (s, e) =>
+                {
+                    NavigatedTo(e);
+                }, RoutingStrategies.Direct);
+            }
+        }
+
+        private void NavigatedTo(NavigationEventArgs arg)
+        {
+            if (Program.PreviewerDetached)
+            {
+                if (arg.NavigationMode == NavigationMode.New)
+                {
+                    _parent = (NavigationDialogHost)arg.Parameter;
+                    ViewModel = _parent.ViewModel;
+                }
+
+                if (arg.NavigationMode == NavigationMode.Back)
+                {
+                    ((ContentDialog)_parent.Parent).Title = LocaleManager.Instance[LocaleKeys.UserProfileWindowTitle];
+                }
+
+                DataContext = ViewModel;
+            }
+        }
+
+        private void Grid_PointerEntered(object sender, PointerEventArgs e)
+        {
+            if (sender is Grid grid)
+            {
+                if (grid.DataContext is UserProfile profile)
+                {
+                    profile.IsPointerOver = true;
+                }
+            }
+        }
+
+        private void Grid_OnPointerExited(object sender, PointerEventArgs e)
+        {
+            if (sender is Grid grid)
+            {
+                if (grid.DataContext is UserProfile profile)
+                {
+                    profile.IsPointerOver = false;
+                }
+            }
+        }
+
+        private void ProfilesList_SelectionChanged(object sender, SelectionChangedEventArgs e)
+        {
+            if (sender is ListBox listBox)
+            {
+                int selectedIndex = listBox.SelectedIndex;
+
+                if (selectedIndex >= 0 && selectedIndex < ViewModel.Profiles.Count)
+                {
+                    if (ViewModel.Profiles[selectedIndex] is UserProfile userProfile)
+                    {
+                        _parent?.AccountManager?.OpenUser(userProfile.UserId);
+
+                        foreach (BaseModel profile in ViewModel.Profiles)
+                        {
+                            if (profile is UserProfile uProfile)
+                            {
+                                uProfile.UpdateState();
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        private void AddUser(object sender, RoutedEventArgs e)
+        {
+            _parent.AddUser();
+        }
+
+        private void EditUser(object sender, RoutedEventArgs e)
+        {
+            if (sender is Avalonia.Controls.Button button)
+            {
+                if (button.DataContext is UserProfile userProfile)
+                {
+                    _parent.EditUser(userProfile);
+                }
+            }
+        }
+
+        private void ManageSaves(object sender, RoutedEventArgs e)
+        {
+            _parent.ManageSaves();
+        }
+
+        private void RecoverLostAccounts(object sender, RoutedEventArgs e)
+        {
+            _parent.RecoverLostAccounts();
+        }
+
+        private void Close(object sender, RoutedEventArgs e)
+        {
+            ((ContentDialog)_parent.Parent).Hide();
+        }
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.Ava/UI/Windows/AvatarWindow.axaml b/Ryujinx.Ava/UI/Windows/AvatarWindow.axaml
deleted file mode 100644
index 1d30fff583..0000000000
--- a/Ryujinx.Ava/UI/Windows/AvatarWindow.axaml
+++ /dev/null
@@ -1,54 +0,0 @@
-<UserControl
-    xmlns="https://github.com/avaloniaui"
-    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
-    xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
-    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
-    xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
-    xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
-    xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
-    mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="350"
-    x:Class="Ryujinx.Ava.UI.Windows.AvatarWindow"
-    Margin="0"
-    Padding="0"
-    x:CompileBindings="True"
-    x:DataType="viewModels:AvatarProfileViewModel"
-    Focusable="True">
-    <Design.DataContext>
-        <viewModels:AvatarProfileViewModel />
-    </Design.DataContext>
-    <UserControl.Resources>
-        <helpers:BitmapArrayValueConverter x:Key="ByteImage" />
-    </UserControl.Resources>
-    <Grid Margin="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
-        <Grid.RowDefinitions>
-            <RowDefinition Height="Auto" />
-            <RowDefinition Height="*" />
-            <RowDefinition Height="Auto" />
-            <RowDefinition Height="Auto" />
-        </Grid.RowDefinitions>
-        <ListBox Grid.Row="1" BorderThickness="0" SelectedIndex="{Binding SelectedIndex}" Height="400"
-                 Items="{Binding Images}" HorizontalAlignment="Stretch" VerticalAlignment="Center">
-            <ListBox.ItemsPanel>
-                <ItemsPanelTemplate>
-                    <WrapPanel Orientation="Horizontal" MaxWidth="700" Margin="0" HorizontalAlignment="Center" />
-                </ItemsPanelTemplate>
-            </ListBox.ItemsPanel>
-            <ListBox.ItemTemplate>
-                <DataTemplate>
-                    <Image Margin="5" Height="96" Width="96"
-                           Source="{Binding Data, Converter={StaticResource ByteImage}}" />
-                </DataTemplate>
-            </ListBox.ItemTemplate>
-        </ListBox>
-        <ProgressBar Grid.Row="2" IsIndeterminate="{Binding IsIndeterminate}" Value="{Binding ImagesLoaded}" HorizontalAlignment="Stretch" Margin="5"
-                     Maximum="{Binding ImageCount}" Minimum="0" />
-        <StackPanel Grid.Row="3" Orientation="Horizontal" Spacing="10" Margin="10" HorizontalAlignment="Center">
-            <Button Content="{locale:Locale AvatarChoose}" Width="200" Name="ChooseButton" Click="ChooseButton_OnClick" />
-            <ui:ColorPickerButton Color="{Binding BackgroundColor, Mode=TwoWay}" Name="ColorButton" />
-            <Button HorizontalAlignment="Right" Content="{locale:Locale Discard}" Click="CloseButton_OnClick"
-                    Name="CloseButton"
-                    Width="200" />
-        </StackPanel>
-    </Grid>
-</UserControl>
\ No newline at end of file