diff --git a/src/Ryujinx/UI/Models/TempProfile.cs b/src/Ryujinx/UI/Models/TempProfile.cs
index a4a4fe32f..d6d0adf83 100644
--- a/src/Ryujinx/UI/Models/TempProfile.cs
+++ b/src/Ryujinx/UI/Models/TempProfile.cs
@@ -10,6 +10,9 @@ namespace Ryujinx.Ava.UI.Models
[ObservableProperty]
public partial byte[] Image { get; set; }
+ [ObservableProperty]
+ public partial bool FirmwareFound { get; set; }
+
[ObservableProperty]
public partial string Name { get; set; } = string.Empty;
diff --git a/src/Ryujinx/UI/Views/User/UserEditorView.axaml b/src/Ryujinx/UI/Views/User/UserEditorView.axaml
index 4155ae6f2..5c1e7d427 100644
--- a/src/Ryujinx/UI/Views/User/UserEditorView.axaml
+++ b/src/Ryujinx/UI/Views/User/UserEditorView.axaml
@@ -65,6 +65,37 @@
HorizontalAlignment="Stretch"
VerticalAlignment="Top"
Source="{Binding Image, Converter={x:Static helpers:BitmapArrayValueConverter.Instance}}" />
+
+
+
diff --git a/src/Ryujinx/UI/Views/User/UserEditorView.axaml.cs b/src/Ryujinx/UI/Views/User/UserEditorView.axaml.cs
index c2d52a905..c0d141188 100644
--- a/src/Ryujinx/UI/Views/User/UserEditorView.axaml.cs
+++ b/src/Ryujinx/UI/Views/User/UserEditorView.axaml.cs
@@ -9,13 +9,21 @@ using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.Models;
using Ryujinx.HLE.HOS.Services.Account.Acc;
using UserProfile = Ryujinx.Ava.UI.Models.UserProfile;
+using Avalonia.Platform.Storage;
+using Ryujinx.HLE.FileSystem;
+using SkiaSharp;
+using System.Collections.Generic;
+using System.IO;
+using Avalonia.VisualTree;
namespace Ryujinx.Ava.UI.Views.User
{
public partial class UserEditorView : RyujinxControl
{
private NavigationDialogHost _parent;
+ private ContentManager _contentManager;
private UserProfile _profile;
+ private TempProfile _tempProfile;
private bool _isNewUser;
public static uint MaxProfileNameLength => 0x20;
public bool IsDeletable => _profile.UserId != AccountManager.DefaultUserId;
@@ -40,8 +48,13 @@ namespace Ryujinx.Ava.UI.Views.User
_isNewUser = isNewUser;
_profile = profile;
ViewModel = new TempProfile(_profile);
+ _tempProfile = ViewModel; // <-- this is critical
_parent = parent;
+
+ _contentManager = _parent.ContentManager;
+ ViewModel.FirmwareFound = _contentManager.GetCurrentFirmwareVersion() != null;
+
break;
}
@@ -156,5 +169,85 @@ namespace Ryujinx.Ava.UI.Views.User
SelectProfileImage();
}
}
+
+ private async void SelectFirmwareImage_OnClick(object sender, RoutedEventArgs e)
+ {
+ if (ViewModel.FirmwareFound)
+ {
+ _parent.Navigate(typeof(UserFirmwareAvatarSelectorView), (_parent, _tempProfile));
+ }
+ }
+
+ private async void Import_OnClick(object sender, RoutedEventArgs e)
+ {
+ var result = await ((Window)this.GetVisualRoot()!).StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
+ {
+ Title = LocaleManager.Instance[LocaleKeys.LoadSupportedImageFormatDialogTitle],
+ AllowMultiple = false,
+ FileTypeFilter = new List
+ {
+ new(LocaleManager.Instance[LocaleKeys.AllSupportedFormats])
+ {
+ Patterns = ["*.jpg", "*.jpeg", "*.png", "*.bmp"],
+ AppleUniformTypeIdentifiers = ["public.jpeg", "public.png", "com.microsoft.bmp"],
+ MimeTypes = ["image/jpeg", "image/png", "image/bmp"],
+ },
+ new("JPG")
+ {
+ Patterns = ["*.jpg"],
+ AppleUniformTypeIdentifiers = ["public.jpeg"],
+ MimeTypes = ["image/jpeg"],
+ },
+ new("JPEG")
+ {
+ Patterns = ["*.jpeg"],
+ AppleUniformTypeIdentifiers = ["public.jpeg"],
+ MimeTypes = ["image/jpeg"],
+ },
+ new("PNG")
+ {
+ Patterns = ["*.png"],
+ AppleUniformTypeIdentifiers = ["public.png"],
+ MimeTypes = ["image/png"],
+ },
+ new("BMP")
+ {
+ Patterns = ["*.bmp"],
+ AppleUniformTypeIdentifiers = ["com.microsoft.bmp"],
+ MimeTypes = ["image/bmp"],
+ },
+ },
+ });
+
+ if (result.Count == 0)
+ return;
+
+ if (DataContext is not TempProfile temp)
+ return;
+
+ temp.Image = ProcessProfileImage(File.ReadAllBytes(result[0].Path.LocalPath));
+
+ if (_profile != null)
+ _profile.Image = temp.Image;
+ }
+
+ private static byte[] ProcessProfileImage(byte[] buffer)
+ {
+ using SKBitmap bitmap = SKBitmap.Decode(buffer);
+
+ SKBitmap resizedBitmap = bitmap.Resize(new SKImageInfo(256, 256), SKFilterQuality.High);
+
+ using MemoryStream streamJpg = new();
+
+ if (resizedBitmap != null)
+ {
+ using SKImage image = SKImage.FromBitmap(resizedBitmap);
+ using SKData dataJpeg = image.Encode(SKEncodedImageFormat.Jpeg, 100);
+
+ dataJpeg.SaveTo(streamJpg);
+ }
+
+ return streamJpg.ToArray();
+ }
}
-}
+}
\ No newline at end of file
diff --git a/src/Ryujinx/UI/Views/User/UserFirmwareAvatarSelectorView.axaml.cs b/src/Ryujinx/UI/Views/User/UserFirmwareAvatarSelectorView.axaml.cs
index f34d8f603..f05feb98c 100644
--- a/src/Ryujinx/UI/Views/User/UserFirmwareAvatarSelectorView.axaml.cs
+++ b/src/Ryujinx/UI/Views/User/UserFirmwareAvatarSelectorView.axaml.cs
@@ -3,6 +3,7 @@ using FluentAvalonia.UI.Controls;
using FluentAvalonia.UI.Navigation;
using Ryujinx.Ava.UI.Controls;
using Ryujinx.Ava.UI.Models;
+using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.HLE.FileSystem;
using SkiaSharp;
@@ -14,12 +15,14 @@ namespace Ryujinx.Ava.UI.Views.User
{
private NavigationDialogHost _parent;
private TempProfile _profile;
+ private ContentManager _contentManager;
public UserFirmwareAvatarSelectorView(ContentManager contentManager)
{
ContentManager = contentManager;
InitializeComponent();
+ AddHandler(Frame.NavigatedToEvent, (s, e) => NavigatedTo(e), RoutingStrategies.Direct);
}
public UserFirmwareAvatarSelectorView()
@@ -40,9 +43,13 @@ namespace Ryujinx.Ava.UI.Views.User
{
(_parent, _profile) = ((NavigationDialogHost, TempProfile))arg.Parameter;
ContentManager = _parent.ContentManager;
+
+ ((ContentDialog)_parent.Parent).Title = $"{LocaleManager.Instance[LocaleKeys.UserProfileWindowTitle]} - {LocaleManager.Instance[LocaleKeys.ProfileImageSelectionHeader]}";
+
if (Program.PreviewerDetached)
{
ViewModel = new UserFirmwareAvatarSelectorViewModel();
+ ViewModel.FirmwareFound = ContentManager.GetCurrentFirmwareVersion() != null;
}
DataContext = ViewModel;