mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2026-03-12 01:21:07 +00:00
feat: add ability to change app icon
Add ability to change application icon to any image file inside the src\Ryujinx\Assets\Icons\AppIcons directory. The app should automatically load any resource in that folder as a selectable icon.
This commit is contained in:
@@ -12217,6 +12217,31 @@
|
||||
"zh_TW": "淺色"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "SettingsTabGeneralIcon",
|
||||
"Translations": {
|
||||
"ar_SA": "",
|
||||
"de_DE": "",
|
||||
"el_GR": "",
|
||||
"en_US": "Application icon:",
|
||||
"es_ES": "Icono de aplicación:",
|
||||
"fr_FR": "",
|
||||
"he_IL": "",
|
||||
"it_IT": "",
|
||||
"ja_JP": "",
|
||||
"ko_KR": "",
|
||||
"no_NO": "",
|
||||
"pl_PL": "",
|
||||
"pt_BR": "",
|
||||
"ru_RU": "",
|
||||
"sv_SE": "",
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "",
|
||||
"zh_CN": "",
|
||||
"zh_TW": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "ControllerSettingsConfigureGeneral",
|
||||
"Translations": {
|
||||
|
||||
BIN
src/Ryujinx/Assets/Icons/AppIcons/Classic Ryugay.ico
Normal file
BIN
src/Ryujinx/Assets/Icons/AppIcons/Classic Ryugay.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 189 KiB |
BIN
src/Ryujinx/Assets/Icons/AppIcons/Ryufluid.webp
Normal file
BIN
src/Ryujinx/Assets/Icons/AppIcons/Ryufluid.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.4 KiB |
BIN
src/Ryujinx/Assets/Icons/AppIcons/Ryugay.webp
Normal file
BIN
src/Ryujinx/Assets/Icons/AppIcons/Ryugay.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.8 KiB |
BIN
src/Ryujinx/Assets/Icons/AppIcons/Ryulesbian.webp
Normal file
BIN
src/Ryujinx/Assets/Icons/AppIcons/Ryulesbian.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.8 KiB |
BIN
src/Ryujinx/Assets/Icons/AppIcons/Ryupan.webp
Normal file
BIN
src/Ryujinx/Assets/Icons/AppIcons/Ryupan.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.2 KiB |
BIN
src/Ryujinx/Assets/Icons/AppIcons/Ryutrans.webp
Normal file
BIN
src/Ryujinx/Assets/Icons/AppIcons/Ryutrans.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.1 KiB |
12
src/Ryujinx/Common/Models/ApplicationIcon.cs
Normal file
12
src/Ryujinx/Common/Models/ApplicationIcon.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
namespace Ryujinx.Ava.Common.Models
|
||||
{
|
||||
public class ApplicationIcon
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Filename { get; set; }
|
||||
public string FullPath
|
||||
{
|
||||
get => $"Ryujinx/Assets/Icons/AppIcons/{Filename}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -164,6 +164,7 @@
|
||||
<EmbeddedResource Include="Assets\Icons\Controller_JoyConPair.svg" />
|
||||
<EmbeddedResource Include="Assets\Icons\Controller_JoyConRight.svg" />
|
||||
<EmbeddedResource Include="Assets\Icons\Controller_ProCon.svg" />
|
||||
<EmbeddedResource Include="Assets\Icons\AppIcons\*" />
|
||||
<EmbeddedResource Include="Assets\UIImages\Icon_NCA.png" />
|
||||
<EmbeddedResource Include="Assets\UIImages\Icon_NRO.png" />
|
||||
<EmbeddedResource Include="Assets\UIImages\Icon_NSO.png" />
|
||||
|
||||
@@ -354,6 +354,11 @@ namespace Ryujinx.Ava.Systems.Configuration
|
||||
/// </summary>
|
||||
public string BaseStyle { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The name of the currently selected window icon
|
||||
/// </summary>
|
||||
public string SelectedWindowIcon { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Chooses the view mode of the game list // Not Used
|
||||
/// </summary>
|
||||
|
||||
@@ -129,6 +129,7 @@ namespace Ryujinx.Ava.Systems.Configuration
|
||||
UI.ShownFileTypes.NSO.Value = shouldLoadFromFile ? cff.ShownFileTypes.NSO : UI.ShownFileTypes.NSO.Value;
|
||||
UI.LanguageCode.Value = shouldLoadFromFile ? cff.LanguageCode : UI.LanguageCode.Value;
|
||||
UI.BaseStyle.Value = shouldLoadFromFile ? cff.BaseStyle : UI.BaseStyle.Value;
|
||||
UI.SelectedWindowIcon.Value = shouldLoadFromFile ? cff.SelectedWindowIcon : UI.SelectedWindowIcon.Value;
|
||||
UI.GameListViewMode.Value = shouldLoadFromFile ? cff.GameListViewMode : UI.GameListViewMode.Value;
|
||||
UI.ShowNames.Value = shouldLoadFromFile ? cff.ShowNames : UI.ShowNames.Value;
|
||||
UI.IsAscendingOrder.Value = shouldLoadFromFile ? cff.IsAscendingOrder : UI.IsAscendingOrder.Value;
|
||||
|
||||
@@ -150,6 +150,11 @@ namespace Ryujinx.Ava.Systems.Configuration
|
||||
/// </summary>
|
||||
public ReactiveObject<string> BaseStyle { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The currently selected window icon.
|
||||
/// </summary>
|
||||
public ReactiveObject<string> SelectedWindowIcon { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Start games in fullscreen mode
|
||||
/// </summary>
|
||||
@@ -199,6 +204,7 @@ namespace Ryujinx.Ava.Systems.Configuration
|
||||
ShownFileTypes = new ShownFileTypeSettings();
|
||||
WindowStartup = new WindowStartupSettings();
|
||||
BaseStyle = new ReactiveObject<string>();
|
||||
SelectedWindowIcon = new ReactiveObject<string>();
|
||||
StartFullscreen = new ReactiveObject<bool>();
|
||||
StartNoUI = new ReactiveObject<bool>();
|
||||
GameListViewMode = new ReactiveObject<int>();
|
||||
|
||||
@@ -126,6 +126,7 @@ namespace Ryujinx.Ava.Systems.Configuration
|
||||
},
|
||||
LanguageCode = UI.LanguageCode,
|
||||
BaseStyle = UI.BaseStyle,
|
||||
SelectedWindowIcon = UI.SelectedWindowIcon,
|
||||
GameListViewMode = UI.GameListViewMode,
|
||||
ShowNames = UI.ShowNames,
|
||||
GridSize = UI.GridSize,
|
||||
|
||||
@@ -2,12 +2,14 @@ using Avalonia;
|
||||
using Avalonia.Controls.ApplicationLifetimes;
|
||||
using Avalonia.Input.Platform;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.Media.Imaging;
|
||||
using Avalonia.Platform;
|
||||
using Avalonia.Styling;
|
||||
using Avalonia.Threading;
|
||||
using FluentAvalonia.UI.Windowing;
|
||||
using Gommon;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.Common.Models;
|
||||
using Ryujinx.Ava.Systems.Configuration;
|
||||
using Ryujinx.Ava.UI.Helpers;
|
||||
using Ryujinx.Ava.UI.Views.Dialog;
|
||||
@@ -16,7 +18,10 @@ using Ryujinx.Ava.Utilities;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Ryujinx.Ava
|
||||
{
|
||||
@@ -52,6 +57,8 @@ namespace Ryujinx.Ava
|
||||
{
|
||||
Name = FormatTitle();
|
||||
|
||||
RetrieveAvailableAppIcons();
|
||||
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
|
||||
if (OperatingSystem.IsMacOS())
|
||||
@@ -72,8 +79,10 @@ namespace Ryujinx.Ava
|
||||
if (Program.PreviewerDetached)
|
||||
{
|
||||
ApplyConfiguredTheme(ConfigurationState.Instance.UI.BaseStyle);
|
||||
|
||||
ConfigurationState.Instance.UI.BaseStyle.Event += ThemeChanged_Event;
|
||||
|
||||
UpdateAppIcon(ConfigurationState.Instance.UI.SelectedWindowIcon);
|
||||
ConfigurationState.Instance.UI.SelectedWindowIcon.Event += WindowIconChanged_Event;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,5 +160,39 @@ namespace Ryujinx.Ava
|
||||
{
|
||||
await AboutView.Show();
|
||||
}
|
||||
|
||||
public static List<ApplicationIcon> AvailableApplicationIcons { get; set; } = [];
|
||||
private static void RetrieveAvailableAppIcons()
|
||||
{
|
||||
AvailableApplicationIcons.Clear();
|
||||
string resourceAssemblyPrefix = "Ryujinx.Assets.Icons.AppIcons.";
|
||||
|
||||
IEnumerable<string> availableAppIconResources = EmbeddedResources
|
||||
.GetAllAvailableResources("Ryujinx/Assets")
|
||||
.Where(x => x.StartsWith(resourceAssemblyPrefix));
|
||||
|
||||
foreach (string resource in availableAppIconResources)
|
||||
{
|
||||
string filename = resource.Remove(0, resourceAssemblyPrefix.Length);
|
||||
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(filename);
|
||||
AvailableApplicationIcons.Add(new ApplicationIcon()
|
||||
{
|
||||
Name = fileNameWithoutExtension,
|
||||
Filename = filename
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static void UpdateAppIcon(string newIconName)
|
||||
{
|
||||
ApplicationIcon selectedIcon = AvailableApplicationIcons.First(x => x.Name == newIconName);
|
||||
Stream activeIconStream = EmbeddedResources.GetStream(selectedIcon.FullPath);
|
||||
if (activeIconStream != null)
|
||||
{
|
||||
MainWindow.Icon = new Bitmap(activeIconStream);
|
||||
}
|
||||
}
|
||||
|
||||
private void WindowIconChanged_Event(object _, ReactiveEventArgs<string> rArgs) => UpdateAppIcon(rArgs.NewValue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,12 +9,14 @@ using Ryujinx.Audio.Backends.OpenAL;
|
||||
using Ryujinx.Audio.Backends.SDL2;
|
||||
using Ryujinx.Audio.Backends.SoundIo;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.Common.Models;
|
||||
using Ryujinx.Ava.Systems.Configuration;
|
||||
using Ryujinx.Ava.Systems.Configuration.System;
|
||||
using Ryujinx.Ava.Systems.Configuration.UI;
|
||||
using Ryujinx.Ava.UI.Helpers;
|
||||
using Ryujinx.Ava.UI.Models.Input;
|
||||
using Ryujinx.Ava.UI.Windows;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.Configuration.Multiplayer;
|
||||
using Ryujinx.Common.GraphicsDriver;
|
||||
@@ -496,6 +498,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
|
||||
Task.Run(CheckSoundBackends);
|
||||
Task.Run(PopulateNetworkInterfaces);
|
||||
ApplicationIcons = new(RyujinxApp.AvailableApplicationIcons);
|
||||
|
||||
if (Program.PreviewerDetached)
|
||||
{
|
||||
@@ -621,6 +624,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
HideCursor = (int)config.HideCursor.Value;
|
||||
UpdateCheckerType = (int)config.UpdateCheckerType.Value;
|
||||
FocusLostActionType = (int)config.FocusLostActionType.Value;
|
||||
AppIconSelectedIndex = _appIcons.ToList().FindIndex(x => x.Name == config.UI.SelectedWindowIcon.Value);
|
||||
|
||||
GameDirectories.Clear();
|
||||
GameDirectories.AddRange(config.UI.GameDirs.Value);
|
||||
@@ -740,6 +744,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
config.FocusLostActionType.Value = (FocusLostType)FocusLostActionType;
|
||||
config.UI.GameDirs.Value = [.. GameDirectories];
|
||||
config.UI.AutoloadDirs.Value = [.. AutoloadDirectories];
|
||||
config.UI.SelectedWindowIcon.Value = _appIcons[_appIconSelectedIndex].Name;
|
||||
|
||||
config.UI.BaseStyle.Value = BaseStyleIndex switch
|
||||
{
|
||||
@@ -935,5 +940,27 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
RevertIfNotSaved();
|
||||
CloseWindow?.Invoke();
|
||||
}
|
||||
|
||||
private AvaloniaList<ApplicationIcon> _appIcons = [];
|
||||
public AvaloniaList<ApplicationIcon> ApplicationIcons
|
||||
{
|
||||
get => _appIcons;
|
||||
set
|
||||
{
|
||||
_appIcons = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private int _appIconSelectedIndex;
|
||||
public int AppIconSelectedIndex
|
||||
{
|
||||
get => _appIconSelectedIndex;
|
||||
set
|
||||
{
|
||||
_appIconSelectedIndex = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,6 +156,28 @@
|
||||
</ComboBoxItem>
|
||||
</ComboBox>
|
||||
<TextBlock Classes="globalConfigMarker" IsVisible="{Binding IsGameTitleNotNull}" />
|
||||
</StackPanel>
|
||||
<StackPanel
|
||||
IsEnabled="{Binding !IsGameTitleNotNull}"
|
||||
Opacity="{Binding PanelOpacity}"
|
||||
Margin="0, 15, 0, 10"
|
||||
Orientation="Horizontal">
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
Text="{ext:Locale SettingsTabGeneralIcon}"
|
||||
Width="150" />
|
||||
<ComboBox
|
||||
MinWidth="100"
|
||||
HorizontalAlignment="Left"
|
||||
ItemsSource="{Binding ApplicationIcons}"
|
||||
SelectedIndex="{Binding AppIconSelectedIndex}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Name}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
<TextBlock Classes="globalConfigMarker" IsVisible="{Binding IsGameTitleNotNull}" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
||||
Reference in New Issue
Block a user