diff options
| author | Isaac Marovitz <42140194+IsaacMarovitz@users.noreply.github.com> | 2023-01-15 06:11:52 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-01-15 11:11:52 +0000 |
| commit | 719dc97bbd321e98083f47267feb01db769e5fa6 (patch) | |
| tree | ba249fdf3b41bb5636f183cdcb4134ef1703049c /Ryujinx.Ava/UI/Windows | |
| parent | 41bba5310a5324f54fa5c0200aff2bf697ced000 (diff) | |
Ava UI: `TitleUpdateWindow` Refactor (#4276)
* Start Refactor
* Dialogue opens
* Changes
* Switch to ListBox
* Fix bugs and stuff
* Fix spacing
* Implement OpenLocation
* Change icon
* Color
* Color
* Remove background
* Make no update the same height
* Fix height and smooth scroll
* Height
* Fix update selection
* Make window smaller
* Add back remove all button
* Make selection more obvious
* Hide selection bar on SaveManager
* Fix autoscroll
* Fix no update not staying selected
* Better file opener
* Fix
* Revert that
* Update Ryujinx.Ava/UI/ViewModels/TitleUpdateViewModel.cs
Co-authored-by: Ac_K <Acoustik666@gmail.com>
* Update Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs
Co-authored-by: Ac_K <Acoustik666@gmail.com>
* Update Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs
Co-authored-by: Ac_K <Acoustik666@gmail.com>
* Log warning
* Update Ryujinx.Ava/UI/ViewModels/TitleUpdateViewModel.cs
Co-authored-by: Ac_K <Acoustik666@gmail.com>
Co-authored-by: Ac_K <Acoustik666@gmail.com>
Diffstat (limited to 'Ryujinx.Ava/UI/Windows')
| -rw-r--r-- | Ryujinx.Ava/UI/Windows/TitleUpdateWindow.axaml | 172 | ||||
| -rw-r--r-- | Ryujinx.Ava/UI/Windows/TitleUpdateWindow.axaml.cs | 255 |
2 files changed, 146 insertions, 281 deletions
diff --git a/Ryujinx.Ava/UI/Windows/TitleUpdateWindow.axaml b/Ryujinx.Ava/UI/Windows/TitleUpdateWindow.axaml index 5a69be9b..e9858038 100644 --- a/Ryujinx.Ava/UI/Windows/TitleUpdateWindow.axaml +++ b/Ryujinx.Ava/UI/Windows/TitleUpdateWindow.axaml @@ -1,115 +1,135 @@ -<window:StyleableWindow +<UserControl x:Class="Ryujinx.Ava.UI.Windows.TitleUpdateWindow" xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:window="clr-namespace:Ryujinx.Ava.UI.Windows" - Width="600" - Height="400" - MinWidth="600" - MinHeight="400" - MaxWidth="600" - MaxHeight="400" - SizeToContent="Height" - WindowStartupLocation="CenterOwner" + xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" + xmlns:models="clr-namespace:Ryujinx.Ava.UI.Models" + xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" + Width="500" + Height="300" mc:Ignorable="d" + x:CompileBindings="True" + x:DataType="viewModels:TitleUpdateViewModel" Focusable="True"> - <Grid Margin="15"> + <Grid> <Grid.RowDefinitions> - <RowDefinition Height="Auto" /> - <RowDefinition Height="Auto" /> <RowDefinition Height="*" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> - <TextBlock - Name="Heading" - Grid.Row="1" - MaxWidth="500" - Margin="20,15,20,20" - HorizontalAlignment="Center" - VerticalAlignment="Center" - LineHeight="18" - TextAlignment="Center" - TextWrapping="Wrap" /> <Border - Grid.Row="2" - Margin="5" + Grid.Row="0" + Margin="0 0 0 24" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" - BorderBrush="Gray" - BorderThickness="1"> - <ScrollViewer - VerticalAlignment="Stretch" - HorizontalScrollBarVisibility="Auto" - VerticalScrollBarVisibility="Auto"> - <ItemsControl - Margin="10" - HorizontalAlignment="Stretch" - VerticalAlignment="Stretch" - Items="{Binding _titleUpdates}"> - <ItemsControl.ItemTemplate> - <DataTemplate> - <RadioButton - Padding="8,0" - VerticalContentAlignment="Center" - GroupName="Update" - IsChecked="{Binding IsEnabled, Mode=TwoWay}"> - <Label - Margin="0" + BorderBrush="{DynamicResource AppListHoverBackgroundColor}" + BorderThickness="1" + CornerRadius="5" + Padding="2.5"> + <ListBox + VirtualizationMode="None" + Background="Transparent" + SelectedItem="{Binding SelectedUpdate, Mode=TwoWay}" + Items="{Binding Views}"> + <ListBox.DataTemplates> + <DataTemplate + DataType="models:TitleUpdateModel"> + <Panel Margin="10"> + <TextBlock + HorizontalAlignment="Left" + VerticalAlignment="Center" + TextWrapping="Wrap" + Text="{Binding Label}" /> + <StackPanel + Spacing="10" + Orientation="Horizontal" + HorizontalAlignment="Right"> + <Button + VerticalAlignment="Center" + HorizontalAlignment="Right" + Padding="10" + MinWidth="0" + MinHeight="0" + Click="OpenLocation"> + <ui:SymbolIcon + Symbol="OpenFolder" + HorizontalAlignment="Center" + VerticalAlignment="Center" /> + </Button> + <Button VerticalAlignment="Center" - Content="{Binding Label}" - FontSize="12" /> - </RadioButton> - </DataTemplate> - </ItemsControl.ItemTemplate> - </ItemsControl> - </ScrollViewer> + HorizontalAlignment="Right" + Padding="10" + MinWidth="0" + MinHeight="0" + Click="RemoveUpdate"> + <ui:SymbolIcon + Symbol="Cancel" + HorizontalAlignment="Center" + VerticalAlignment="Center" /> + </Button> + </StackPanel> + </Panel> + </DataTemplate> + <DataTemplate + DataType="viewModels:BaseModel"> + <Panel + Height="33" + Margin="10"> + <TextBlock + HorizontalAlignment="Left" + VerticalAlignment="Center" + TextWrapping="Wrap" + Text="{locale:Locale NoUpdate}" /> + </Panel> + </DataTemplate> + </ListBox.DataTemplates> + <ListBox.Styles> + <Style Selector="ListBoxItem"> + <Setter Property="Background" Value="Transparent" /> + </Style> + </ListBox.Styles> + </ListBox> </Border> - <DockPanel - Grid.Row="3" - Margin="0" + <Panel + Grid.Row="1" HorizontalAlignment="Stretch"> - <DockPanel Margin="0" HorizontalAlignment="Left"> + <StackPanel + Orientation="Horizontal" + Spacing="10" + HorizontalAlignment="Left"> <Button Name="AddButton" MinWidth="90" - Margin="5" - Command="{Binding Add}"> + Command="{ReflectionBinding Add}"> <TextBlock Text="{locale:Locale SettingsTabGeneralAdd}" /> </Button> <Button - Name="RemoveButton" - MinWidth="90" - Margin="5" - Command="{Binding RemoveSelected}"> - <TextBlock Text="{locale:Locale SettingsTabGeneralRemove}" /> - </Button> - <Button Name="RemoveAllButton" MinWidth="90" - Margin="5" - Command="{Binding RemoveAll}"> + Click="RemoveAll"> <TextBlock Text="{locale:Locale DlcManagerRemoveAllButton}" /> </Button> - </DockPanel> - <DockPanel Margin="0" HorizontalAlignment="Right"> + </StackPanel> + <StackPanel + Orientation="Horizontal" + Spacing="10" + HorizontalAlignment="Right"> <Button Name="SaveButton" MinWidth="90" - Margin="5" - Command="{Binding Save}"> + Click="Save"> <TextBlock Text="{locale:Locale SettingsButtonSave}" /> </Button> <Button Name="CancelButton" MinWidth="90" - Margin="5" - Command="{Binding Close}"> + Click="Close"> <TextBlock Text="{locale:Locale InputDialogCancel}" /> </Button> - </DockPanel> - </DockPanel> + </StackPanel> + </Panel> </Grid> -</window:StyleableWindow>
\ No newline at end of file +</UserControl>
\ No newline at end of file diff --git a/Ryujinx.Ava/UI/Windows/TitleUpdateWindow.axaml.cs b/Ryujinx.Ava/UI/Windows/TitleUpdateWindow.axaml.cs index 848c5587..9d8b9a7b 100644 --- a/Ryujinx.Ava/UI/Windows/TitleUpdateWindow.axaml.cs +++ b/Ryujinx.Ava/UI/Windows/TitleUpdateWindow.axaml.cs @@ -1,271 +1,116 @@ -using Avalonia.Collections; using Avalonia.Controls; -using Avalonia.Threading; -using LibHac.Common; -using LibHac.Fs; -using LibHac.Fs.Fsa; -using LibHac.FsSystem; -using LibHac.Ns; -using LibHac.Tools.FsSystem; -using LibHac.Tools.FsSystem.NcaUtils; +using Avalonia.Interactivity; +using Avalonia.Styling; +using FluentAvalonia.UI.Controls; using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.UI.Controls; using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Models; -using Ryujinx.Common.Configuration; +using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Common.Utilities; using Ryujinx.HLE.FileSystem; -using Ryujinx.HLE.HOS; -using System; -using System.Collections.Generic; +using Ryujinx.Ui.Common.Helper; using System.IO; -using System.Linq; using System.Text; -using Path = System.IO.Path; -using SpanHelpers = LibHac.Common.SpanHelpers; +using System.Threading.Tasks; +using Button = Avalonia.Controls.Button; namespace Ryujinx.Ava.UI.Windows { - public partial class TitleUpdateWindow : StyleableWindow + public partial class TitleUpdateWindow : UserControl { - private readonly string _titleUpdateJsonPath; - private TitleUpdateMetadata _titleUpdateWindowData; - - private VirtualFileSystem _virtualFileSystem { get; } - private AvaloniaList<TitleUpdateModel> _titleUpdates { get; set; } - - private ulong _titleId { get; } - private string _titleName { get; } + public TitleUpdateViewModel ViewModel; public TitleUpdateWindow() { DataContext = this; InitializeComponent(); - - Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance[LocaleKeys.UpdateWindowTitle]} - {_titleName} ({_titleId:X16})"; } public TitleUpdateWindow(VirtualFileSystem virtualFileSystem, ulong titleId, string titleName) { - _virtualFileSystem = virtualFileSystem; - _titleUpdates = new AvaloniaList<TitleUpdateModel>(); - - _titleId = titleId; - _titleName = titleName; + DataContext = ViewModel = new TitleUpdateViewModel(virtualFileSystem, titleId, titleName); - _titleUpdateJsonPath = Path.Combine(AppDataManager.GamesDirPath, titleId.ToString("x16"), "updates.json"); + InitializeComponent(); + } - try - { - _titleUpdateWindowData = JsonHelper.DeserializeFromFile<TitleUpdateMetadata>(_titleUpdateJsonPath); - } - catch + public static async Task Show(VirtualFileSystem virtualFileSystem, ulong titleId, string titleName) + { + ContentDialog contentDialog = new() { - _titleUpdateWindowData = new TitleUpdateMetadata - { - Selected = "", - Paths = new List<string>() - }; - } + PrimaryButtonText = "", + SecondaryButtonText = "", + CloseButtonText = "", + Content = new TitleUpdateWindow(virtualFileSystem, titleId, titleName), + Title = string.Format(LocaleManager.Instance[LocaleKeys.GameUpdateWindowHeading], titleName, titleId.ToString("X16")) + }; - DataContext = this; + Style bottomBorder = new(x => x.OfType<Grid>().Name("DialogSpace").Child().OfType<Border>()); + bottomBorder.Setters.Add(new Setter(IsVisibleProperty, false)); - InitializeComponent(); + contentDialog.Styles.Add(bottomBorder); - Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance[LocaleKeys.UpdateWindowTitle]} - {_titleName} ({_titleId:X16})"; - - LoadUpdates(); - PrintHeading(); + await ContentDialogHelper.ShowAsync(contentDialog); } - private void PrintHeading() + private void Close(object sender, RoutedEventArgs e) { - Heading.Text = string.Format(LocaleManager.Instance[LocaleKeys.GameUpdateWindowHeading], _titleUpdates.Count - 1, _titleName, _titleId.ToString("X16")); + ((ContentDialog)Parent).Hide(); } - private void LoadUpdates() + public void Save(object sender, RoutedEventArgs e) { - _titleUpdates.Add(new TitleUpdateModel(default, string.Empty, true)); + ViewModel._titleUpdateWindowData.Paths.Clear(); - foreach (string path in _titleUpdateWindowData.Paths) - { - AddUpdate(path); - } + ViewModel._titleUpdateWindowData.Selected = ""; - if (_titleUpdateWindowData.Selected == "") - { - _titleUpdates[0].IsEnabled = true; - } - else + foreach (TitleUpdateModel update in ViewModel.TitleUpdates) { - TitleUpdateModel selected = _titleUpdates.FirstOrDefault(x => x.Path == _titleUpdateWindowData.Selected); - List<TitleUpdateModel> enabled = _titleUpdates.Where(x => x.IsEnabled).ToList(); - - foreach (TitleUpdateModel update in enabled) - { - update.IsEnabled = false; - } + ViewModel._titleUpdateWindowData.Paths.Add(update.Path); - if (selected != null) + if (update == ViewModel.SelectedUpdate) { - selected.IsEnabled = true; + ViewModel._titleUpdateWindowData.Selected = update.Path; } } - SortUpdates(); - } - - private void AddUpdate(string path) - { - if (File.Exists(path) && !_titleUpdates.Any(x => x.Path == path)) + using (FileStream titleUpdateJsonStream = File.Create(ViewModel._titleUpdateJsonPath, 4096, FileOptions.WriteThrough)) { - using FileStream file = new(path, FileMode.Open, FileAccess.Read); - - try - { - (Nca patchNca, Nca controlNca) = ApplicationLoader.GetGameUpdateDataFromPartition(_virtualFileSystem, new PartitionFileSystem(file.AsStorage()), _titleId.ToString("x16"), 0); - - if (controlNca != null && patchNca != null) - { - ApplicationControlProperty controlData = new(); - - using UniqueRef<IFile> nacpFile = new(); - - controlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None).OpenFile(ref nacpFile.Ref(), "/control.nacp".ToU8Span(), OpenMode.Read).ThrowIfFailure(); - nacpFile.Get.Read(out _, 0, SpanHelpers.AsByteSpan(ref controlData), ReadOption.None).ThrowIfFailure(); - - _titleUpdates.Add(new TitleUpdateModel(controlData, path)); - - foreach (var update in _titleUpdates) - { - update.IsEnabled = false; - } - - _titleUpdates.Last().IsEnabled = true; - } - else - { - Dispatcher.UIThread.Post(async () => - { - await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogUpdateAddUpdateErrorMessage]); - }); - } - } - catch (Exception ex) - { - Dispatcher.UIThread.Post(async () => - { - await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance[LocaleKeys.DialogDlcLoadNcaErrorMessage], ex.Message, path)); - }); - } + titleUpdateJsonStream.Write(Encoding.UTF8.GetBytes(JsonHelper.Serialize(ViewModel._titleUpdateWindowData, true))); } - } - private void RemoveUpdates(bool removeSelectedOnly = false) - { - if (removeSelectedOnly) - { - _titleUpdates.RemoveAll(_titleUpdates.Where(x => x.IsEnabled && !x.IsNoUpdate).ToList()); - } - else + if (VisualRoot is MainWindow window) { - _titleUpdates.RemoveAll(_titleUpdates.Where(x => !x.IsNoUpdate).ToList()); + window.ViewModel.LoadApplications(); } - _titleUpdates.FirstOrDefault(x => x.IsNoUpdate).IsEnabled = true; - - SortUpdates(); - PrintHeading(); - } - - public void RemoveSelected() - { - RemoveUpdates(true); + ((ContentDialog)Parent).Hide(); } - public void RemoveAll() + private void OpenLocation(object sender, RoutedEventArgs e) { - RemoveUpdates(); - } - - public async void Add() - { - OpenFileDialog dialog = new() + if (sender is Button button) { - Title = LocaleManager.Instance[LocaleKeys.SelectUpdateDialogTitle], - AllowMultiple = true - }; - - dialog.Filters.Add(new FileDialogFilter - { - Name = "NSP", - Extensions = { "nsp" } - }); - - string[] files = await dialog.ShowAsync(this); - - if (files != null) - { - foreach (string file in files) + if (button.DataContext is TitleUpdateModel model) { - AddUpdate(file); + OpenHelper.LocateFile(model.Path); } } - - SortUpdates(); - PrintHeading(); } - private void SortUpdates() + private void RemoveUpdate(object sender, RoutedEventArgs e) { - var list = _titleUpdates.ToList(); - - list.Sort((first, second) => + if (sender is Button button) { - if (string.IsNullOrEmpty(first.Control.DisplayVersionString.ToString())) - { - return -1; - } - else if (string.IsNullOrEmpty(second.Control.DisplayVersionString.ToString())) - { - return 1; - } - - return Version.Parse(first.Control.DisplayVersionString.ToString()).CompareTo(Version.Parse(second.Control.DisplayVersionString.ToString())) * -1; - }); - - _titleUpdates.Clear(); - _titleUpdates.AddRange(list); + ViewModel.RemoveUpdate((TitleUpdateModel)button.DataContext); + } } - public void Save() + private void RemoveAll(object sender, RoutedEventArgs e) { - _titleUpdateWindowData.Paths.Clear(); - - _titleUpdateWindowData.Selected = ""; - - foreach (TitleUpdateModel update in _titleUpdates) - { - _titleUpdateWindowData.Paths.Add(update.Path); - - if (update.IsEnabled) - { - _titleUpdateWindowData.Selected = update.Path; - } - } - - using (FileStream titleUpdateJsonStream = File.Create(_titleUpdateJsonPath, 4096, FileOptions.WriteThrough)) - { - titleUpdateJsonStream.Write(Encoding.UTF8.GetBytes(JsonHelper.Serialize(_titleUpdateWindowData, true))); - } - - if (Owner is MainWindow window) - { - window.ViewModel.LoadApplications(); - } + ViewModel.TitleUpdates.Clear(); - Close(); + ViewModel.SortUpdates(); } } }
\ No newline at end of file |
