Skip to content

Commit

Permalink
UI - Avalonia Part 3 (#3441)
Browse files Browse the repository at this point in the history
* Add all other windows

* addreesed review

* Prevent "No Update" option from being deleted

* Select no update is the current update is removed from the title update window

* fix amiibo crash
  • Loading branch information
emmauss authored Jul 8, 2022
1 parent bccf5e8 commit 3af42d6
Show file tree
Hide file tree
Showing 26 changed files with 2,901 additions and 23 deletions.
18 changes: 16 additions & 2 deletions Ryujinx.Ava/Assets/Locales/en_US.json
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,20 @@
"SettingsTabHotkeysToggleMuteHotkey": "Mute:",
"ControllerMotionTitle": "Motion Control Settings",
"ControllerRumbleTitle": "Rumble Settings",
"SettingsSelectThemeFileDialogTitle" : "Select Theme File",
"SettingsXamlThemeFile" : "Xaml Theme File"
"SettingsSelectThemeFileDialogTitle": "Select Theme File",
"SettingsXamlThemeFile": "Xaml Theme File",
"AvatarWindowTitle": "Manage Accounts - Avatar",
"Amiibo": "Amiibo",
"Unknown": "Unknown",
"Usage": "Usage",
"Writable": "Writable",
"SelectDlcDialogTitle": "Select DLC files",
"SelectUpdateDialogTitle": "Select update files",
"UserProfileWindowTitle": "Manage User Profiles",
"CheatWindowTitle": "Manage Game Cheats",
"DlcWindowTitle": "Manage Game DLC",
"UpdateWindowTitle": "Manage Game Updates",
"CheatWindowHeading": "Cheats Available for {0} [{1}]",
"DlcWindowHeading": "DLC Available for {0} [{1}]",
"GameUpdateWindowHeading": "DLC Available for {0} [{1}]"
}
35 changes: 35 additions & 0 deletions Ryujinx.Ava/Ui/Controls/ProfileImageSelectionDialog.axaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<Window 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"
xmlns:Locale="clr-namespace:Ryujinx.Ava.Common.Locale"
x:Class="Ryujinx.Ava.Ui.Controls.ProfileImageSelectionDialog"
SizeToContent="WidthAndHeight"
WindowStartupLocation="CenterOwner"
Title="{Locale:Locale ProfileImageSelectionTitle}"
CanResize="false">
<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>
</Window>
105 changes: 105 additions & 0 deletions Ryujinx.Ava/Ui/Controls/ProfileImageSelectionDialog.axaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.Ui.Windows;
using Ryujinx.HLE.FileSystem;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;
using System.IO;
using Image = SixLabors.ImageSharp.Image;

namespace Ryujinx.Ava.Ui.Controls
{
public class ProfileImageSelectionDialog : StyleableWindow
{
private readonly ContentManager _contentManager;

public bool FirmwareFound => _contentManager.GetCurrentFirmwareVersion() != null;

public byte[] BufferImageProfile { get; set; }

public ProfileImageSelectionDialog(ContentManager contentManager)
{
_contentManager = contentManager;
DataContext = this;
InitializeComponent();
#if DEBUG
this.AttachDevTools();
#endif
}

public ProfileImageSelectionDialog()
{
DataContext = this;
InitializeComponent();
#if DEBUG
this.AttachDevTools();
#endif
}

private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}

private async void Import_OnClick(object sender, RoutedEventArgs e)
{
OpenFileDialog dialog = new();
dialog.Filters.Add(new FileDialogFilter
{
Name = LocaleManager.Instance["AllSupportedFormats"],
Extensions = { "jpg", "jpeg", "png", "bmp" }
});
dialog.Filters.Add(new FileDialogFilter { Name = "JPEG", Extensions = { "jpg", "jpeg" } });
dialog.Filters.Add(new FileDialogFilter { Name = "PNG", Extensions = { "png" } });
dialog.Filters.Add(new FileDialogFilter { Name = "BMP", Extensions = { "bmp" } });

dialog.AllowMultiple = false;

string[] image = await dialog.ShowAsync(this);

if (image != null)
{
if (image.Length > 0)
{
string imageFile = image[0];

ProcessProfileImage(File.ReadAllBytes(imageFile));
}

Close();
}
}

private async void SelectFirmwareImage_OnClick(object sender, RoutedEventArgs e)
{
if (FirmwareFound)
{
AvatarWindow window = new(_contentManager);

await window.ShowDialog(this);

BufferImageProfile = window.SelectedImage;

Close();
}
}

private void ProcessProfileImage(byte[] buffer)
{
using (Image image = Image.Load(buffer))
{
image.Mutate(x => x.Resize(256, 256));

using (MemoryStream streamJpg = new())
{
image.SaveAsJpeg(streamJpg);

BufferImageProfile = streamJpg.ToArray();
}
}
}
}
}
72 changes: 72 additions & 0 deletions Ryujinx.Ava/Ui/Models/Amiibo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;

namespace Ryujinx.Ava.Ui.Models
{
public class Amiibo
{
public struct AmiiboJson
{
[JsonPropertyName("amiibo")] public List<AmiiboApi> Amiibo { get; set; }
[JsonPropertyName("lastUpdated")] public DateTime LastUpdated { get; set; }
}

public struct AmiiboApi
{
[JsonPropertyName("name")] public string Name { get; set; }
[JsonPropertyName("head")] public string Head { get; set; }
[JsonPropertyName("tail")] public string Tail { get; set; }
[JsonPropertyName("image")] public string Image { get; set; }
[JsonPropertyName("amiiboSeries")] public string AmiiboSeries { get; set; }
[JsonPropertyName("character")] public string Character { get; set; }
[JsonPropertyName("gameSeries")] public string GameSeries { get; set; }
[JsonPropertyName("type")] public string Type { get; set; }

[JsonPropertyName("release")] public Dictionary<string, string> Release { get; set; }

[JsonPropertyName("gamesSwitch")] public List<AmiiboApiGamesSwitch> GamesSwitch { get; set; }

public override string ToString()
{
return Name;
}

public string GetId()
{
return Head + Tail;
}

public override bool Equals(object obj)
{
if (obj is AmiiboApi amiibo)
{
return amiibo.Head + amiibo.Tail == Head + Tail;
}

return false;
}

public override int GetHashCode()
{
return base.GetHashCode();
}
}

public class AmiiboApiGamesSwitch
{
[JsonPropertyName("amiiboUsage")] public List<AmiiboApiUsage> AmiiboUsage { get; set; }

[JsonPropertyName("gameID")] public List<string> GameId { get; set; }

[JsonPropertyName("gameName")] public string GameName { get; set; }
}

public class AmiiboApiUsage
{
[JsonPropertyName("Usage")] public string Usage { get; set; }

[JsonPropertyName("write")] public bool Write { get; set; }
}
}
}
37 changes: 37 additions & 0 deletions Ryujinx.Ava/Ui/Models/CheatModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using Ryujinx.Ava.Ui.ViewModels;
using System;

namespace Ryujinx.Ava.Ui.Models
{
public class CheatModel : BaseModel
{
private bool _isEnabled;

public event EventHandler<bool> EnableToggled;

public CheatModel(string name, string buildId, bool isEnabled)
{
Name = name;
BuildId = buildId;
IsEnabled = isEnabled;
}

public bool IsEnabled
{
get => _isEnabled;
set
{
_isEnabled = value;
EnableToggled?.Invoke(this, _isEnabled);
OnPropertyChanged();
}
}

public string BuildId { get; }

public string BuildIdKey => $"{BuildId}-{Name}";
public string Name { get; }

public string CleanName => Name.Substring(1, Name.Length - 8);
}
}
51 changes: 51 additions & 0 deletions Ryujinx.Ava/Ui/Models/CheatsList.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;

namespace Ryujinx.Ava.Ui.Models
{
public class CheatsList : ObservableCollection<CheatModel>
{
public CheatsList(string buildId, string path)
{
BuildId = buildId;
Path = path;
CollectionChanged += CheatsList_CollectionChanged;
}

private void CheatsList_CollectionChanged(object sender,
NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add)
{
(e.NewItems[0] as CheatModel).EnableToggled += Item_EnableToggled;
}
}

private void Item_EnableToggled(object sender, bool e)
{
OnPropertyChanged(new PropertyChangedEventArgs(nameof(IsEnabled)));
}

public string BuildId { get; }
public string Path { get; }

public bool IsEnabled
{
get
{
return this.ToList().TrueForAll(x => x.IsEnabled);
}
set
{
foreach (var cheat in this)
{
cheat.IsEnabled = value;
}

OnPropertyChanged(new PropertyChangedEventArgs(nameof(IsEnabled)));
}
}
}
}
18 changes: 18 additions & 0 deletions Ryujinx.Ava/Ui/Models/DlcModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
namespace Ryujinx.Ava.Ui.Models
{
public class DlcModel
{
public bool IsEnabled { get; set; }
public string TitleId { get; }
public string ContainerPath { get; }
public string FullPath { get; }

public DlcModel(string titleId, string containerPath, string fullPath, bool isEnabled)
{
TitleId = titleId;
ContainerPath = containerPath;
FullPath = fullPath;
IsEnabled = isEnabled;
}
}
}
2 changes: 1 addition & 1 deletion Ryujinx.Ava/Ui/Models/ProfileImageModel.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace Ryujinx.Ava.Ui.Models
{
internal class ProfileImageModel
public class ProfileImageModel
{
public ProfileImageModel(string name, byte[] data)
{
Expand Down
7 changes: 5 additions & 2 deletions Ryujinx.Ava/Ui/Models/TitleUpdateModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@ internal class TitleUpdateModel
public bool IsNoUpdate { get; }
public ApplicationControlProperty Control { get; }
public string Path { get; }
public string Label => IsNoUpdate ? LocaleManager.Instance["NoUpdate"] :
string.Format(LocaleManager.Instance["TitleUpdateVersionLabel"], Control.DisplayVersionString.ToString(), Path);

public string Label => IsNoUpdate
? LocaleManager.Instance["NoUpdate"]
: string.Format(LocaleManager.Instance["TitleUpdateVersionLabel"], Control.DisplayVersionString.ToString(),
Path);

public TitleUpdateModel(ApplicationControlProperty control, string path, bool isNoUpdate = false)
{
Expand Down
Loading

0 comments on commit 3af42d6

Please sign in to comment.