mirror of
https://github.com/wabbajack-tools/wabbajack.git
synced 2024-08-30 18:42:17 +00:00
Merge pull request #1709 from wabbajack-tools/style-play-buttons
Style play buttons
This commit is contained in:
commit
09667841e9
@ -62,6 +62,22 @@
|
|||||||
<Setter Property="CornerRadius" Value="4"></Setter>
|
<Setter Property="CornerRadius" Value="4"></Setter>
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector=".InstalledList Border">
|
||||||
|
<Setter Property="BorderThickness" Value="2"></Setter>
|
||||||
|
<Setter Property="BorderBrush" Value="DarkGray"></Setter>
|
||||||
|
<Setter Property="CornerRadius" Value="4"></Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector=".InstalledList TextBlock">
|
||||||
|
<Setter Property="FontWeight" Value="Bold"></Setter>
|
||||||
|
<Setter Property="FontSize" Value="18"></Setter>
|
||||||
|
<Setter Property="Margin" Value="4"/>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="Button.InstalledList">
|
||||||
|
<Setter Property="Margin" Value="4"></Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</Styles>
|
</Styles>
|
@ -5,11 +5,15 @@
|
|||||||
xmlns:i="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
|
xmlns:i="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
|
||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
x:Class="Wabbajack.App.Controls.InstalledListView">
|
x:Class="Wabbajack.App.Controls.InstalledListView">
|
||||||
<Grid RowDefinitions="Auto, Auto" ColumnDefinitions="*, Auto">
|
<Button Name="ListButton" Classes="InstalledList" HorizontalAlignment="Stretch">
|
||||||
<TextBlock Grid.Row="0" Grid.Column="0" x:Name="Title" />
|
<Border Classes="InstalledList">
|
||||||
<TextBlock Grid.Row="1" Grid.Column="0" x:Name="InstallationPath" />
|
<Grid RowDefinitions="Auto, Auto Auto, Auto" ColumnDefinitions="Auto, *">
|
||||||
<Button Grid.Row="0" Grid.Column="1" Grid.RowSpan="2" x:Name="PlayButton">
|
<Image x:Name="ListImage" Grid.RowSpan="4" Grid.Row="0" Grid.Column="0" Width="270" Height="150"></Image>
|
||||||
<i:MaterialIcon Kind="PlayArrow" />
|
<TextBlock Grid.Row="0" Grid.Column="1" x:Name="Title" />
|
||||||
</Button>
|
<TextBlock Grid.Row="1" Grid.Column="1" x:Name="Version" />
|
||||||
</Grid>
|
<TextBlock Grid.Row="2" Grid.Column="1" x:Name="Author"></TextBlock>
|
||||||
|
<TextBlock Grid.Row="3" Grid.Column="1" x:Name="InstallationPath" />
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
</Button>
|
||||||
</UserControl>
|
</UserControl>
|
@ -12,14 +12,23 @@ public partial class InstalledListView : ReactiveUserControl<InstalledListViewMo
|
|||||||
|
|
||||||
this.WhenActivated(disposables =>
|
this.WhenActivated(disposables =>
|
||||||
{
|
{
|
||||||
|
this.OneWayBind(ViewModel, vm => vm.Image, view => view.ListImage.Source)
|
||||||
|
.DisposeWith(disposables);
|
||||||
|
|
||||||
this.OneWayBind(ViewModel, vm => vm.Name, view => view.Title.Text)
|
this.OneWayBind(ViewModel, vm => vm.Name, view => view.Title.Text)
|
||||||
.DisposeWith(disposables);
|
.DisposeWith(disposables);
|
||||||
|
|
||||||
this.OneWayBind(ViewModel, vm => vm.InstallPath, view => view.Title.Text,
|
this.OneWayBind(ViewModel, vm => vm.Author, view => view.Author.Text)
|
||||||
|
.DisposeWith(disposables);
|
||||||
|
|
||||||
|
this.OneWayBind(ViewModel, vm => vm.Version, view => view.Version.Text)
|
||||||
|
.DisposeWith(disposables);
|
||||||
|
|
||||||
|
this.OneWayBind(ViewModel, vm => vm.InstallPath, view => view.InstallationPath.Text,
|
||||||
p => p.ToString())
|
p => p.ToString())
|
||||||
.DisposeWith(disposables);
|
.DisposeWith(disposables);
|
||||||
|
|
||||||
this.BindCommand(ViewModel, vm => vm.Play, view => view.PlayButton)
|
this.BindCommand(ViewModel, vm => vm.Play, view => view.ListButton)
|
||||||
.DisposeWith(disposables);
|
.DisposeWith(disposables);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,14 @@
|
|||||||
using System.Reactive;
|
using System.Reactive;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Avalonia.Media.Imaging;
|
||||||
|
using Avalonia.Threading;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
using ReactiveUI.Fody.Helpers;
|
||||||
using Wabbajack.App.Messages;
|
using Wabbajack.App.Messages;
|
||||||
|
using Wabbajack.App.Models;
|
||||||
using Wabbajack.App.Screens;
|
using Wabbajack.App.Screens;
|
||||||
using Wabbajack.App.ViewModels;
|
using Wabbajack.App.ViewModels;
|
||||||
|
using Wabbajack.Common;
|
||||||
using Wabbajack.DTOs.SavedSettings;
|
using Wabbajack.DTOs.SavedSettings;
|
||||||
using Wabbajack.Paths;
|
using Wabbajack.Paths;
|
||||||
|
|
||||||
@ -12,7 +18,7 @@ public class InstalledListViewModel : ViewModelBase
|
|||||||
{
|
{
|
||||||
private readonly InstallationConfigurationSetting _setting;
|
private readonly InstallationConfigurationSetting _setting;
|
||||||
|
|
||||||
public InstalledListViewModel(InstallationConfigurationSetting setting)
|
public InstalledListViewModel(InstallationConfigurationSetting setting, ImageCache imageCache)
|
||||||
{
|
{
|
||||||
Activator = new ViewModelActivator();
|
Activator = new ViewModelActivator();
|
||||||
_setting = setting;
|
_setting = setting;
|
||||||
@ -22,10 +28,28 @@ public class InstalledListViewModel : ViewModelBase
|
|||||||
MessageBus.Current.SendMessage(new ConfigureLauncher(InstallPath));
|
MessageBus.Current.SendMessage(new ConfigureLauncher(InstallPath));
|
||||||
MessageBus.Current.SendMessage(new NavigateTo(typeof(LauncherViewModel)));
|
MessageBus.Current.SendMessage(new NavigateTo(typeof(LauncherViewModel)));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
LoadImage(imageCache).FireAndForget();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task LoadImage(ImageCache cache)
|
||||||
|
{
|
||||||
|
var img = await cache.From(_setting.Install.Combine("modlist-image.png"), 270, 150);
|
||||||
|
Dispatcher.UIThread.Post(() =>
|
||||||
|
{
|
||||||
|
Image = img;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public AbsolutePath InstallPath => _setting.Install;
|
public AbsolutePath InstallPath => _setting.Install;
|
||||||
|
|
||||||
public string Name => _setting.Metadata?.Title ?? "";
|
public string Name => _setting.Metadata?.Title ?? "";
|
||||||
|
|
||||||
|
public string Version => _setting.Metadata?.Version?.ToString() ?? "";
|
||||||
|
|
||||||
|
public string Author => _setting.Metadata?.Author ?? "";
|
||||||
public ReactiveCommand<Unit, Unit> Play { get; }
|
public ReactiveCommand<Unit, Unit> Play { get; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public IBitmap Image { get; set; }
|
||||||
}
|
}
|
@ -9,21 +9,16 @@
|
|||||||
<Grid RowDefinitions="Auto, *, Auto" Classes="LogView">
|
<Grid RowDefinitions="Auto, *, Auto" Classes="LogView">
|
||||||
<TextBlock Grid.Row="0" Classes="Title">Current Log Contents</TextBlock>
|
<TextBlock Grid.Row="0" Classes="Title">Current Log Contents</TextBlock>
|
||||||
<Border Grid.Row="1">
|
<Border Grid.Row="1">
|
||||||
<ScrollViewer ScrollChanged="ScrollViewer_OnScrollChanged" x:Name="ScrollViewer"
|
<ItemsRepeater x:Name="Messages">
|
||||||
HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible">
|
<ItemsRepeater.Layout>
|
||||||
<ItemsControl x:Name="Messages">
|
<StackLayout></StackLayout>
|
||||||
<ItemsControl.ItemsPanel>
|
</ItemsRepeater.Layout>
|
||||||
<ItemsPanelTemplate>
|
<ItemsRepeater.ItemTemplate>
|
||||||
<StackPanel />
|
<DataTemplate>
|
||||||
</ItemsPanelTemplate>
|
<controls:LogViewItem />
|
||||||
</ItemsControl.ItemsPanel>
|
</DataTemplate>
|
||||||
<ItemsControl.ItemTemplate>
|
</ItemsRepeater.ItemTemplate>
|
||||||
<DataTemplate>
|
</ItemsRepeater>
|
||||||
<controls:LogViewItem />
|
|
||||||
</DataTemplate>
|
|
||||||
</ItemsControl.ItemTemplate>
|
|
||||||
</ItemsControl>
|
|
||||||
</ScrollViewer>
|
|
||||||
</Border>
|
</Border>
|
||||||
<StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Right">
|
<StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Right">
|
||||||
<Button x:Name="CopyLog">
|
<Button x:Name="CopyLog">
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
using System.Linq;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Controls.Mixins;
|
using Avalonia.Controls.Mixins;
|
||||||
using Avalonia.ReactiveUI;
|
using Avalonia.ReactiveUI;
|
||||||
@ -14,15 +15,11 @@ public partial class LogView : ReactiveUserControl<LogViewModel>
|
|||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
this.WhenActivated(disposables =>
|
this.WhenActivated(disposables =>
|
||||||
{
|
{
|
||||||
this.OneWayBind(ViewModel, vm => vm.Messages, view => view.Messages.Items)
|
this.OneWayBind(ViewModel, vm => vm.Messages, view => view.Messages.Items,
|
||||||
|
items => items.Reverse().ToArray())
|
||||||
.DisposeWith(disposables);
|
.DisposeWith(disposables);
|
||||||
this.BindCommand(ViewModel, vm => vm.CopyLogFile, view => view.CopyLog)
|
this.BindCommand(ViewModel, vm => vm.CopyLogFile, view => view.CopyLog)
|
||||||
.DisposeWith(disposables);
|
.DisposeWith(disposables);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ScrollViewer_OnScrollChanged(object? sender, ScrollChangedEventArgs e)
|
|
||||||
{
|
|
||||||
ScrollViewer.ScrollToEnd();
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -6,6 +6,8 @@ using System.Reactive.Subjects;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
using Wabbajack.App.Controls;
|
||||||
|
using Wabbajack.Paths;
|
||||||
|
|
||||||
namespace Wabbajack.App.Extensions;
|
namespace Wabbajack.App.Extensions;
|
||||||
|
|
||||||
@ -40,4 +42,22 @@ public static class IObservableExtensions
|
|||||||
|
|
||||||
return Disposable.Create(() => d.Dispose());
|
return Disposable.Create(() => d.Dispose());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static IDisposable BindFileSelectionBox<TViewModel>(this FileSelectionBox box, TViewModel viewModel,
|
||||||
|
Expression<Func<TViewModel, AbsolutePath>> vmProperty)
|
||||||
|
where TViewModel: class?
|
||||||
|
{
|
||||||
|
var disposables = new CompositeDisposable();
|
||||||
|
|
||||||
|
box.WhenAnyValue(view => view.SelectedPath)
|
||||||
|
.BindTo(viewModel, vmProperty)
|
||||||
|
.DisposeWith(disposables);
|
||||||
|
|
||||||
|
viewModel.WhenAnyValue(vmProperty)
|
||||||
|
.Where(p => p != default)
|
||||||
|
.Subscribe(box.Load)
|
||||||
|
.DisposeWith(disposables);
|
||||||
|
|
||||||
|
return disposables;
|
||||||
|
}
|
||||||
}
|
}
|
@ -9,8 +9,10 @@ using Avalonia.Media;
|
|||||||
using Avalonia.Media.Imaging;
|
using Avalonia.Media.Imaging;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
using Wabbajack.Hashing.xxHash64;
|
using Wabbajack.Hashing.xxHash64;
|
||||||
|
using Wabbajack.Paths;
|
||||||
using Wabbajack.Paths.IO;
|
using Wabbajack.Paths.IO;
|
||||||
using Wabbajack.RateLimiter;
|
using Wabbajack.RateLimiter;
|
||||||
|
using Wabbajack.VFS;
|
||||||
|
|
||||||
namespace Wabbajack.App.Models;
|
namespace Wabbajack.App.Models;
|
||||||
|
|
||||||
@ -19,13 +21,15 @@ public class ImageCache
|
|||||||
private readonly Configuration _configuration;
|
private readonly Configuration _configuration;
|
||||||
private readonly HttpClient _client;
|
private readonly HttpClient _client;
|
||||||
private readonly IResource<HttpClient> _limiter;
|
private readonly IResource<HttpClient> _limiter;
|
||||||
|
private readonly FileHashCache _hashCache;
|
||||||
|
|
||||||
public ImageCache(Configuration configuration, HttpClient client, IResource<HttpClient> limiter)
|
public ImageCache(Configuration configuration, HttpClient client, IResource<HttpClient> limiter, FileHashCache hashCache)
|
||||||
{
|
{
|
||||||
_configuration = configuration;
|
_configuration = configuration;
|
||||||
_configuration.ImageCacheLocation.CreateDirectory();
|
_configuration.ImageCacheLocation.CreateDirectory();
|
||||||
_client = client;
|
_client = client;
|
||||||
_limiter = limiter;
|
_limiter = limiter;
|
||||||
|
_hashCache = hashCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IBitmap> From(Uri uri, int width, int height)
|
public async Task<IBitmap> From(Uri uri, int width, int height)
|
||||||
@ -46,4 +50,18 @@ public class ImageCache
|
|||||||
return new Bitmap(new MemoryStream(data));
|
return new Bitmap(new MemoryStream(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<IBitmap> From(AbsolutePath image, int width, int height)
|
||||||
|
{
|
||||||
|
var hash = await _hashCache.FileHashCachedAsync(image, CancellationToken.None);
|
||||||
|
var file = _configuration.ImageCacheLocation.Combine(hash + $"_{width}_{height}");
|
||||||
|
|
||||||
|
if (!file.FileExists())
|
||||||
|
{
|
||||||
|
var resized = SKBitmap.Decode(image.ToString()).Resize(new SKSizeI(width, height), SKFilterQuality.High);
|
||||||
|
await file.WriteAllBytesAsync(resized.Encode(SKEncodedImageFormat.Webp, 90).ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
var data = await file.ReadAllBytesAsync();
|
||||||
|
return new Bitmap(new MemoryStream(data));
|
||||||
|
}
|
||||||
}
|
}
|
@ -62,7 +62,7 @@ public class CompilationViewModel : ViewModelBase
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _compiler.Begin(CancellationToken.None);
|
var result = await Task.Run(async () => await _compiler.Begin(CancellationToken.None));
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
xmlns:i="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
|
xmlns:i="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
|
||||||
xmlns:controls="clr-namespace:Wabbajack.App.Controls"
|
xmlns:controls="clr-namespace:Wabbajack.App.Controls"
|
||||||
x:Class="Wabbajack.App.Screens.CompilerConfigurationView">
|
x:Class="Wabbajack.App.Screens.CompilerConfigurationView">
|
||||||
<Grid RowDefinitions="40, *, 40">
|
<Grid RowDefinitions="40, *, 40" Margin="8">
|
||||||
<TextBlock Grid.Row="0" x:Name="StatusText" FontSize="20" FontWeight="Bold">Compiler Configuration</TextBlock>
|
<TextBlock Grid.Row="0" x:Name="StatusText" FontSize="20" FontWeight="Bold">Compiler Configuration</TextBlock>
|
||||||
<Grid Grid.Row="1" ColumnDefinitions="Auto, *" RowDefinitions="Auto, Auto, Auto, Auto, Auto, Auto, Auto"
|
<Grid Grid.Row="1" ColumnDefinitions="Auto, *" RowDefinitions="Auto, Auto, Auto, Auto, Auto, Auto, Auto, Auto"
|
||||||
Margin="4">
|
Margin="4">
|
||||||
<Label Grid.Column="0" Grid.Row="0" HorizontalAlignment="Right">Title:</Label>
|
<Label Grid.Column="0" Grid.Row="0" HorizontalAlignment="Right">Title:</Label>
|
||||||
<TextBox Grid.Column="1" Grid.Row="0" x:Name="Title" />
|
<TextBox Grid.Column="1" Grid.Row="0" x:Name="Title" />
|
||||||
@ -29,9 +29,28 @@
|
|||||||
</ComboBox>
|
</ComboBox>
|
||||||
<Label Grid.Column="0" Grid.Row="5" HorizontalAlignment="Right">Output Folder:</Label>
|
<Label Grid.Column="0" Grid.Row="5" HorizontalAlignment="Right">Output Folder:</Label>
|
||||||
<controls:FileSelectionBox Grid.Column="1" Grid.Row="5" x:Name="OutputFolder" SelectFolder="True" />
|
<controls:FileSelectionBox Grid.Column="1" Grid.Row="5" x:Name="OutputFolder" SelectFolder="True" />
|
||||||
|
|
||||||
<Label Grid.Column="0" Grid.Row="6" HorizontalAlignment="Right" VerticalAlignment="Top">Always Enabled:</Label>
|
<Label Grid.Column="0" Grid.Row="6" HorizontalAlignment="Right" VerticalAlignment="Top">Other Profiles:</Label>
|
||||||
<StackPanel Grid.Column="1" Grid.Row="6" Orientation="Vertical">
|
<StackPanel Grid.Column="1" Grid.Row="6" Orientation="Vertical">
|
||||||
|
<Button x:Name="AddOtherProfile">
|
||||||
|
<i:MaterialIcon Kind="AddCircle" />
|
||||||
|
</Button>
|
||||||
|
<ItemsControl x:Name="OtherProfilesList">
|
||||||
|
<ItemsControl.ItemsPanel>
|
||||||
|
<ItemsPanelTemplate>
|
||||||
|
<StackPanel Orientation="Vertical" />
|
||||||
|
</ItemsPanelTemplate>
|
||||||
|
</ItemsControl.ItemsPanel>
|
||||||
|
<ItemsControl.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<controls:RemovableListItem />
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsControl.ItemTemplate>
|
||||||
|
</ItemsControl>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<Label Grid.Column="0" Grid.Row="7" HorizontalAlignment="Right" VerticalAlignment="Top">Always Enabled:</Label>
|
||||||
|
<StackPanel Grid.Column="1" Grid.Row="7" Orientation="Vertical">
|
||||||
<Button x:Name="AddAlwaysEnabled">
|
<Button x:Name="AddAlwaysEnabled">
|
||||||
<i:MaterialIcon Kind="AddCircle" />
|
<i:MaterialIcon Kind="AddCircle" />
|
||||||
</Button>
|
</Button>
|
||||||
@ -48,6 +67,8 @@
|
|||||||
</ItemsControl.ItemTemplate>
|
</ItemsControl.ItemTemplate>
|
||||||
</ItemsControl>
|
</ItemsControl>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</Grid>
|
</Grid>
|
||||||
|
@ -7,6 +7,7 @@ using Avalonia.Interactivity;
|
|||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using Wabbajack.App.Controls;
|
using Wabbajack.App.Controls;
|
||||||
|
using Wabbajack.App.Extensions;
|
||||||
using Wabbajack.App.Views;
|
using Wabbajack.App.Views;
|
||||||
using Wabbajack.Common;
|
using Wabbajack.Common;
|
||||||
using Wabbajack.Paths;
|
using Wabbajack.Paths;
|
||||||
@ -19,25 +20,23 @@ public partial class CompilerConfigurationView : ScreenBase<CompilerConfiguratio
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
AddAlwaysEnabled.Command = ReactiveCommand.Create(() => AddAlwaysEnabled_Command().FireAndForget());
|
AddAlwaysEnabled.Command = ReactiveCommand.Create(() => AddAlwaysEnabled_Command().FireAndForget());
|
||||||
|
AddOtherProfile.Command = ReactiveCommand.Create(() => AddOtherProfile_Command().FireAndForget());
|
||||||
|
|
||||||
this.WhenActivated(disposables =>
|
this.WhenActivated(disposables =>
|
||||||
{
|
{
|
||||||
this.Bind(ViewModel, vm => vm.SettingsFile, view => view.SettingsFile.SelectedPath)
|
|
||||||
.DisposeWith(disposables);
|
|
||||||
|
|
||||||
this.Bind(ViewModel, vm => vm.Title, view => view.Title.Text)
|
this.Bind(ViewModel, vm => vm.Title, view => view.Title.Text)
|
||||||
.DisposeWith(disposables);
|
.DisposeWith(disposables);
|
||||||
|
|
||||||
this.Bind(ViewModel, vm => vm.SettingsFile, view => view.SettingsFile.SelectedPath)
|
SettingsFile.BindFileSelectionBox(ViewModel, vm => vm.SettingsFile)
|
||||||
.DisposeWith(disposables);
|
.DisposeWith(disposables);
|
||||||
|
|
||||||
this.Bind(ViewModel, vm => vm.Source, view => view.Source.SelectedPath)
|
Source.BindFileSelectionBox(ViewModel, vm => vm.Source)
|
||||||
|
.DisposeWith(disposables);
|
||||||
|
|
||||||
|
DownloadsFolder.BindFileSelectionBox(ViewModel, vm => vm.Downloads)
|
||||||
.DisposeWith(disposables);
|
.DisposeWith(disposables);
|
||||||
|
|
||||||
this.Bind(ViewModel, vm => vm.Downloads, view => view.DownloadsFolder.SelectedPath)
|
OutputFolder.BindFileSelectionBox(ViewModel, vm => vm.OutputFolder)
|
||||||
.DisposeWith(disposables);
|
|
||||||
|
|
||||||
this.Bind(ViewModel, vm => vm.OutputFolder, view => view.OutputFolder.SelectedPath)
|
|
||||||
.DisposeWith(disposables);
|
.DisposeWith(disposables);
|
||||||
|
|
||||||
this.OneWayBind(ViewModel, vm => vm.AllGames, view => view.BaseGame.Items)
|
this.OneWayBind(ViewModel, vm => vm.AllGames, view => view.BaseGame.Items)
|
||||||
@ -56,8 +55,27 @@ public partial class CompilerConfigurationView : ScreenBase<CompilerConfiguratio
|
|||||||
DeleteCommand = ReactiveCommand.Create(() => { ViewModel?.RemoveAlwaysExcluded(itm); })
|
DeleteCommand = ReactiveCommand.Create(() => { ViewModel?.RemoveAlwaysExcluded(itm); })
|
||||||
}))
|
}))
|
||||||
.DisposeWith(disposables);
|
.DisposeWith(disposables);
|
||||||
|
|
||||||
|
this.OneWayBind(ViewModel, vm => vm.OtherProfiles, view => view.OtherProfilesList.Items,
|
||||||
|
d => d!.Select(itm => new RemovableItemViewModel
|
||||||
|
{
|
||||||
|
Text = itm.ToString(),
|
||||||
|
DeleteCommand = ReactiveCommand.Create(() => { ViewModel?.RemoveOtherProfile(itm); })
|
||||||
|
}))
|
||||||
|
.DisposeWith(disposables);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task AddOtherProfile_Command()
|
||||||
|
{
|
||||||
|
var dialog = new OpenFolderDialog
|
||||||
|
{
|
||||||
|
Title = "Select a profile folder"
|
||||||
|
};
|
||||||
|
var result = await dialog.ShowAsync(App.MainWindow);
|
||||||
|
if (!string.IsNullOrWhiteSpace(result))
|
||||||
|
ViewModel!.AddOtherProfile(result.ToAbsolutePath());
|
||||||
|
}
|
||||||
|
|
||||||
private async Task AddAlwaysEnabled_Command()
|
private async Task AddAlwaysEnabled_Command()
|
||||||
{
|
{
|
||||||
|
@ -71,6 +71,9 @@ public class CompilerConfigurationViewModel : ViewModelBase
|
|||||||
|
|
||||||
[Reactive] public IEnumerable<RelativePath> AlwaysEnabled { get; set; } = Array.Empty<RelativePath>();
|
[Reactive] public IEnumerable<RelativePath> AlwaysEnabled { get; set; } = Array.Empty<RelativePath>();
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public string[] OtherProfiles { get; set; } = Array.Empty<string>();
|
||||||
|
|
||||||
public AbsolutePath SettingsOutputLocation => Source.Combine(Title)
|
public AbsolutePath SettingsOutputLocation => Source.Combine(Title)
|
||||||
.WithExtension(IsMO2Compilation ? Ext.MO2CompilerSettings : Ext.CompilerSettings);
|
.WithExtension(IsMO2Compilation ? Ext.MO2CompilerSettings : Ext.CompilerSettings);
|
||||||
|
|
||||||
@ -102,16 +105,31 @@ public class CompilerConfigurationViewModel : ViewModelBase
|
|||||||
{
|
{
|
||||||
return new MO2CompilerSettings
|
return new MO2CompilerSettings
|
||||||
{
|
{
|
||||||
|
ModListName = Title,
|
||||||
Downloads = Downloads,
|
Downloads = Downloads,
|
||||||
Source = Source,
|
Source = Source,
|
||||||
Game = BaseGame.Game,
|
Game = BaseGame.Game,
|
||||||
Profile = SelectedProfile,
|
Profile = SelectedProfile,
|
||||||
UseGamePaths = true,
|
UseGamePaths = true,
|
||||||
OutputFile = OutputFolder.Combine(SelectedProfile).WithExtension(Ext.Wabbajack),
|
OutputFile = OutputFolder.Combine(SelectedProfile).WithExtension(Ext.Wabbajack),
|
||||||
AlwaysEnabled = AlwaysEnabled.ToArray()
|
AlwaysEnabled = AlwaysEnabled.ToArray(),
|
||||||
|
OtherProfiles = OtherProfiles.ToArray()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool AddOtherProfile(AbsolutePath path)
|
||||||
|
{
|
||||||
|
if (!path.InFolder(Source.Combine(Consts.MO2Profiles))) return false;
|
||||||
|
var relative = path.RelativeTo(Source.Combine(Consts.MO2Profiles)).ToString();
|
||||||
|
OtherProfiles = OtherProfiles.Append(relative).Distinct().ToArray();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveOtherProfile(string profile)
|
||||||
|
{
|
||||||
|
OtherProfiles = OtherProfiles.Where(p => p != profile).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
public bool AddAlwaysExcluded(AbsolutePath path)
|
public bool AddAlwaysExcluded(AbsolutePath path)
|
||||||
{
|
{
|
||||||
if (!path.InFolder(Source)) return false;
|
if (!path.InFolder(Source)) return false;
|
||||||
@ -149,6 +167,8 @@ public class CompilerConfigurationViewModel : ViewModelBase
|
|||||||
IsMO2Compilation = true;
|
IsMO2Compilation = true;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
AlwaysEnabled = Array.Empty<RelativePath>();
|
||||||
// Find Always Enabled mods
|
// Find Always Enabled mods
|
||||||
foreach (var modFolder in mo2Folder.Combine("mods").EnumerateDirectories())
|
foreach (var modFolder in mo2Folder.Combine("mods").EnumerateDirectories())
|
||||||
{
|
{
|
||||||
@ -162,6 +182,12 @@ public class CompilerConfigurationViewModel : ViewModelBase
|
|||||||
AlwaysEnabled = AlwaysEnabled.Append(modFolder.RelativeTo(mo2Folder)).ToArray();
|
AlwaysEnabled = AlwaysEnabled.Append(modFolder.RelativeTo(mo2Folder)).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var otherProfilesFile = settingsFile.Parent.Combine("otherprofiles.txt");
|
||||||
|
if (otherProfilesFile.FileExists())
|
||||||
|
{
|
||||||
|
OtherProfiles = await otherProfilesFile.ReadAllLinesAsync().ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
if (mo2Folder.Depth > 1)
|
if (mo2Folder.Depth > 1)
|
||||||
OutputFolder = mo2Folder.Parent;
|
OutputFolder = mo2Folder.Parent;
|
||||||
|
|
||||||
@ -171,6 +197,8 @@ public class CompilerConfigurationViewModel : ViewModelBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private async Task SaveSettingsFile()
|
private async Task SaveSettingsFile()
|
||||||
{
|
{
|
||||||
await using var st = SettingsOutputLocation.Open(FileMode.Create, FileAccess.Write, FileShare.None);
|
await using var st = SettingsOutputLocation.Open(FileMode.Create, FileAccess.Write, FileShare.None);
|
||||||
@ -187,6 +215,7 @@ public class CompilerConfigurationViewModel : ViewModelBase
|
|||||||
{
|
{
|
||||||
var mo2 = await LoadSettingsFile<MO2CompilerSettings>(path);
|
var mo2 = await LoadSettingsFile<MO2CompilerSettings>(path);
|
||||||
AlwaysEnabled = mo2.AlwaysEnabled;
|
AlwaysEnabled = mo2.AlwaysEnabled;
|
||||||
|
OtherProfiles = mo2.OtherProfiles;
|
||||||
SelectedProfile = mo2.Profile;
|
SelectedProfile = mo2.Profile;
|
||||||
s = mo2;
|
s = mo2;
|
||||||
}
|
}
|
||||||
@ -195,6 +224,7 @@ public class CompilerConfigurationViewModel : ViewModelBase
|
|||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Title = s.ModListName;
|
||||||
Source = s.Source;
|
Source = s.Source;
|
||||||
Downloads = s.Downloads;
|
Downloads = s.Downloads;
|
||||||
OutputFolder = s.OutputFile.Depth > 1 ? s.OutputFile.Parent : s.OutputFile;
|
OutputFolder = s.OutputFile.Depth > 1 ? s.OutputFile.Parent : s.OutputFile;
|
||||||
|
@ -6,17 +6,15 @@
|
|||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
x:Class="Wabbajack.App.Screens.PlaySelectView">
|
x:Class="Wabbajack.App.Screens.PlaySelectView">
|
||||||
<Grid RowDefinitions="*">
|
<Grid RowDefinitions="*">
|
||||||
<ItemsControl x:Name="Lists">
|
<ItemsRepeater x:Name="Lists">
|
||||||
<ItemsControl.ItemsPanel>
|
<ItemsRepeater.Layout>
|
||||||
<ItemsPanelTemplate>
|
<StackLayout></StackLayout>
|
||||||
<StackPanel />
|
</ItemsRepeater.Layout>
|
||||||
</ItemsPanelTemplate>
|
<ItemsRepeater.ItemTemplate>
|
||||||
</ItemsControl.ItemsPanel>
|
|
||||||
<ItemsControl.ItemTemplate>
|
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<controls:InstalledListView />
|
<controls:InstalledListView />
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ItemsControl.ItemTemplate>
|
</ItemsRepeater.ItemTemplate>
|
||||||
</ItemsControl>
|
</ItemsRepeater>
|
||||||
</Grid>
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
@ -14,9 +14,11 @@ namespace Wabbajack.App.Screens;
|
|||||||
public class PlaySelectViewModel : ViewModelBase, IActivatableViewModel
|
public class PlaySelectViewModel : ViewModelBase, IActivatableViewModel
|
||||||
{
|
{
|
||||||
private readonly InstallationStateManager _manager;
|
private readonly InstallationStateManager _manager;
|
||||||
|
private readonly ImageCache _imageCache;
|
||||||
|
|
||||||
public PlaySelectViewModel(InstallationStateManager manager)
|
public PlaySelectViewModel(InstallationStateManager manager, ImageCache imageCache)
|
||||||
{
|
{
|
||||||
|
_imageCache = imageCache;
|
||||||
_manager = manager;
|
_manager = manager;
|
||||||
Activator = new ViewModelActivator();
|
Activator = new ViewModelActivator();
|
||||||
|
|
||||||
@ -32,6 +34,6 @@ public class PlaySelectViewModel : ViewModelBase, IActivatableViewModel
|
|||||||
public async Task LoadAndSetItems()
|
public async Task LoadAndSetItems()
|
||||||
{
|
{
|
||||||
var items = await _manager.GetAll();
|
var items = await _manager.GetAll();
|
||||||
Items = items.Settings.Select(a => new InstalledListViewModel(a)).ToArray();
|
Items = items.Settings.Select(a => new InstalledListViewModel(a, _imageCache)).ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -7,4 +7,5 @@ public class MO2CompilerSettings : CompilerSettings
|
|||||||
{
|
{
|
||||||
public string Profile { get; set; } = "";
|
public string Profile { get; set; } = "";
|
||||||
public RelativePath[] AlwaysEnabled { get; set; } = Array.Empty<RelativePath>();
|
public RelativePath[] AlwaysEnabled { get; set; } = Array.Empty<RelativePath>();
|
||||||
|
public string[] OtherProfiles { get; set; }
|
||||||
}
|
}
|
@ -20,4 +20,5 @@ public class InstallationConfigurationSetting
|
|||||||
public ModlistMetadata? Metadata { get; set; }
|
public ModlistMetadata? Metadata { get; set; }
|
||||||
|
|
||||||
public AbsolutePath Image { get; set; }
|
public AbsolutePath Image { get; set; }
|
||||||
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user