Add theme import and export function

This commit is contained in:
Michael Bucari-Tovo 2025-03-19 16:59:58 -06:00 committed by MBucari
parent f183b587b8
commit aab4f1d9d6
5 changed files with 116 additions and 39 deletions

View File

@ -8,7 +8,7 @@
<ContentControl.Styles>
<Style Selector="controls|GroupBox">
<Setter Property="BorderBrush" Value="{DynamicResource SystemBaseMediumLowColor}" />
<Setter Property="BorderBrush" Value="{DynamicResource SystemBaseMediumColor}" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="CornerRadius" Value="3" />
<Setter Property="Template">

View File

@ -19,13 +19,13 @@
<TextBox Margin="5,0" Text="This is an editable text box" />
<TextBox Margin="5,0" Text="This is a read-only text box" IsReadOnly="True" />
<NumericUpDown Margin="5,0" Value="100" />
<controls:LinkLabel VerticalAlignment="Center" Margin="5,0" Text="This is an unvisited link" />
<controls:LinkLabel VerticalAlignment="Center" Margin="5,0" Text="This is a visited link" Foreground="{DynamicResource HyperlinkVisited}" />
<StackPanel Margin="5,0" Height="15" Orientation="Horizontal">
<controls:LinkLabel VerticalAlignment="Center" Margin="5,5" Text="This is an unvisited link" />
<controls:LinkLabel VerticalAlignment="Center" Margin="5,5" Text="This is a visited link" Foreground="{DynamicResource HyperlinkVisited}" />
<StackPanel Margin="5,0" Height="25" Orientation="Horizontal">
<StackPanel.Styles>
<Style Selector="Path">
<Setter Property="Stretch" Value="Uniform" />
<Setter Property="Margin" Value="3,0" />
<Setter Property="Margin" Value="3,5" />
<Setter Property="Fill" Value="{DynamicResource IconFill}" />
</Style>
</StackPanel.Styles>

View File

@ -2,8 +2,8 @@
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" d:DesignWidth="850" d:DesignHeight="850"
Width="450" Height="450"
mc:Ignorable="d" d:DesignWidth="965" d:DesignHeight="850"
Width="965" Height="850"
x:Class="LibationAvalonia.Dialogs.ThemePickerDialog"
xmlns:controls="clr-namespace:LibationAvalonia.Controls"
Title="Theme Editor">
@ -11,14 +11,21 @@
<Grid ColumnDefinitions="Auto,*">
<controls:ThemePreviewControl Name="ThemePickerPreviewControl" Margin="5" Grid.Column="1" />
<Grid
RowDefinitions="*,Auto">
RowDefinitions="*,Auto,Auto">
<Grid.Styles>
<Style Selector="Button">
<Setter Property="Height" Value="30" />
<Setter Property="Padding" Value="20,0" />
<Setter Property="Margin" Value="5" />
</Style>
</Grid.Styles>
<DataGrid
Grid.Row="0"
GridLinesVisibility="All"
Margin="5"
IsReadOnly="False"
ItemsSource="{Binding ThemeColors}">
<DataGrid.Columns>
<DataGridTemplateColumn Width="Auto" Header="Color">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
@ -27,48 +34,44 @@
Color="{Binding ThemeColor, Mode=TwoWay}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGridTemplateColumn>
<DataGridTextColumn
Width="Auto"
Binding="{Binding ThemeItemName, Mode=TwoWay}"
Header="Theme Item"/>
</DataGrid.Columns>
</DataGrid>
<Grid
Grid.Row="1"
ColumnDefinitions="Auto,Auto,Auto,*,Auto">
<Grid.Styles>
<Style Selector="Button">
<Setter Property="Height" Value="30" />
<Setter Property="Padding" Value="20,0" />
<Setter Property="Margin" Value="5" />
</Style>
</Grid.Styles>
ColumnDefinitions="Auto,*,Auto">
<Button
Grid.Column="0"
Content="Import Theme"
Command="{Binding ImportTheme}" />
<Button
Grid.Column="2"
Content="Export Theme"
Command="{Binding ExportTheme}" />
</Grid>
<Grid
Grid.Row="2"
ColumnDefinitions="Auto,Auto,Auto,*,Auto">
<Button
Grid.Column="0"
Content="Cancel"
Command="{Binding CancelAndClose}" />
Command="{Binding CancelAndClose}" />
<Button
Grid.Column="1"
Content="Reset"
Command="{Binding ResetColors}" />
Command="{Binding ResetColors}" />
<Button
Grid.Column="2"
Content="Defaults"
Command="{Binding LoadDefaultColors}" />
Command="{Binding LoadDefaultColors}" />
<Button
Grid.Column="4"
Content="Save"
Command="{Binding SaveAndCloseAsync}" />
</Grid>
</Grid>
</Grid>

View File

@ -7,6 +7,7 @@ using LibationAvalonia.Themes;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Linq;
using Avalonia.Platform.Storage;
#nullable enable
namespace LibationAvalonia.Dialogs;
@ -15,13 +16,14 @@ public partial class ThemePickerDialog : DialogWindow
{
protected DataGridCollectionView ThemeColors { get; }
private ChardonnayTheme ExistingTheme { get; } = ChardonnayTheme.GetLiveTheme();
private ChardonnayTheme WorkingTheme { get; }
public ThemePickerDialog()
{
InitializeComponent();
CancelOnEscape = false;
var workingTheme = (ChardonnayTheme)ExistingTheme.Clone();
ThemeColors = new(EnumerateThemeItemColors(workingTheme, ActualThemeVariant));
WorkingTheme = (ChardonnayTheme)ExistingTheme.Clone();
ThemeColors = new(EnumerateThemeItemColors());
DataContext = this;
Closing += ThemePickerDialog_Closing;
@ -36,6 +38,78 @@ public partial class ThemePickerDialog : DialogWindow
}
}
protected async Task ImportTheme()
{
try
{
var openFileDialogOptions = new FilePickerOpenOptions
{
Title = $"Select the ChardonnayTheme.json file",
AllowMultiple = false,
FileTypeFilter =
[
new("JSON files (*.json)")
{
Patterns = ["*.json"],
AppleUniformTypeIdentifiers = ["public.json"]
}
]
};
var selectedFiles = await StorageProvider.OpenFilePickerAsync(openFileDialogOptions);
var selectedFile = selectedFiles.SingleOrDefault()?.TryGetLocalPath();
if (selectedFile is null) return;
using (var theme = new ChardonnayThemePersister(selectedFile))
{
theme.Target.ApplyTheme(ActualThemeVariant);
}
await MessageBox.Show(this, "Theme imported and applied", "Theme Imported");
}
catch (Exception ex)
{
await MessageBox.ShowAdminAlert(this, "Error attempting to import your chardonnay theme.", "Error Importing", ex);
}
}
protected async Task ExportTheme()
{
try
{
var options = new FilePickerSaveOptions
{
Title = "Where to export Library",
SuggestedFileName = $"ChardonnayTheme",
DefaultExtension = "json",
ShowOverwritePrompt = true,
FileTypeChoices =
[
new("JSON files (*.json)")
{
Patterns = ["*.json"],
AppleUniformTypeIdentifiers = ["public.json"]
},
new("All files (*.*)") { Patterns = ["*"] }
]
};
var selectedFile = (await StorageProvider.SaveFilePickerAsync(options))?.TryGetLocalPath();
if (selectedFile is null) return;
using (var theme = new ChardonnayThemePersister(WorkingTheme, selectedFile))
theme.Target.Save();
await MessageBox.Show(this, "Theme exported to:\r\n" + selectedFile, "Theme Exported");
}
catch (Exception ex)
{
await MessageBox.ShowAdminAlert(this, "Error attempting to export your chardonnay theme.", "Error Exporting", ex);
}
}
protected override void CancelAndClose()
{
ExistingTheme.ApplyTheme(ActualThemeVariant);
@ -83,17 +157,17 @@ public partial class ThemePickerDialog : DialogWindow
}
}
private static IEnumerable<ThemeItemColor> EnumerateThemeItemColors(ChardonnayTheme workingTheme, ThemeVariant themeVariant)
=> workingTheme
.GetThemeColors(themeVariant)
private IEnumerable<ThemeItemColor> EnumerateThemeItemColors()
=> WorkingTheme
.GetThemeColors(ActualThemeVariant)
.Select(kvp => new ThemeItemColor
{
ThemeItemName = kvp.Key,
ThemeColor = kvp.Value,
ColorSetter = c =>
{
workingTheme.SetColor(themeVariant, kvp.Key, c);
workingTheme.ApplyTheme(themeVariant);
WorkingTheme.SetColor(ActualThemeVariant, kvp.Key, c);
WorkingTheme.ApplyTheme(ActualThemeVariant);
}
});

View File

@ -12,9 +12,9 @@ public class ChardonnayThemePersister : JsonFilePersister<ChardonnayTheme>
{
public static string jsonPath = System.IO.Path.Combine(Configuration.Instance.LibationFiles, "ChardonnayTheme.json");
private ChardonnayThemePersister(string path)
public ChardonnayThemePersister(string path)
: base(path, null) { }
private ChardonnayThemePersister(ChardonnayTheme target, string path)
public ChardonnayThemePersister(ChardonnayTheme target, string path)
: base(target, path, null) { }
protected override JsonSerializerSettings GetSerializerSettings()