Skip to content

Commit 79416b9

Browse files
Codes UI rework
1 parent 13b3476 commit 79416b9

17 files changed

Lines changed: 653 additions & 143 deletions

File tree

Source/HedgeModManager.Console/Program.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using HedgeModManager;
22
using HedgeModManager.CodeCompiler;
3+
using HedgeModManager.CoreLib;
34
using HedgeModManager.Foundation;
45
using HedgeModManager.Text;
56

@@ -139,10 +140,10 @@ async Task PrintUpdates()
139140
{
140141
Console.WriteLine($"Checking for {mod.Title} updates");
141142
var updates = await mod.Updater.CheckForUpdatesAsync();
142-
if (updates)
143+
if (updates == true)
143144
{
144145
var info = await mod.Updater.GetUpdateInfoAsync();
145-
Console.WriteLine($"[{mod.Title}] {mod.Version} -> {info.Version}");
146+
Console.WriteLine($"[{mod.Title}] {mod.Version} -> {info?.Version}");
146147
}
147148
}
148149
catch

Source/HedgeModManager.UI/App.axaml.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,10 @@ public override void OnFrameworkInitializationCompleted()
9797

9898
Logger.Information($"Loading config...");
9999
viewModel.Config.Load();
100+
101+
// TODO: Check for new languages
102+
viewModel.Config.LastSeenLanguages = [.. languages.Select(x => x.Code)];
103+
100104
RequestedThemeVariant = Themes.Themes.GetTheme(viewModel.Config.Theme);
101105

102106
ChangeLanguage(viewModel.SelectedLanguage =
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
using HedgeModManager.Foundation;
2+
using HedgeModManager.UI.ViewModels;
3+
using System.Text.Json;
4+
5+
namespace HedgeModManager.UI.Config;
6+
7+
public abstract class ConfigBase : ViewModelBase
8+
{
9+
public virtual void Load()
10+
{
11+
string filePath = GetConfigFilePath();
12+
if (!File.Exists(filePath))
13+
return;
14+
15+
string jsonData = File.ReadAllText(filePath);
16+
17+
var config = JsonSerializer.Deserialize(jsonData, GetType(), Program.JsonSerializerOptions);
18+
19+
// Copy data
20+
if (config != null)
21+
{
22+
foreach (var property in GetType().GetProperties())
23+
if (property.CanWrite)
24+
property.SetValue(this, property.GetValue(config));
25+
}
26+
}
27+
28+
public virtual async Task LoadAsync()
29+
{
30+
string filePath = GetConfigFilePath();
31+
if (!File.Exists(filePath))
32+
return;
33+
34+
string jsonData = await File.ReadAllTextAsync(filePath);
35+
36+
var config = JsonSerializer.Deserialize(jsonData, GetType(), Program.JsonSerializerOptions);
37+
38+
// Copy data
39+
if (config != null)
40+
{
41+
foreach (var property in GetType().GetProperties())
42+
if (property.CanWrite)
43+
property.SetValue(this, property.GetValue(config));
44+
}
45+
}
46+
47+
public virtual async Task SaveAsync()
48+
{
49+
string filePath = GetConfigFilePath();
50+
51+
string jsonData = JsonSerializer.Serialize(this, GetType(), Program.JsonSerializerOptions);
52+
try
53+
{
54+
Directory.CreateDirectory(Path.GetDirectoryName(filePath)!);
55+
await File.WriteAllTextAsync(filePath, jsonData);
56+
}
57+
catch
58+
{
59+
Logger.Error($"Failed to save config file: {filePath} [{GetType().FullName}]");
60+
}
61+
}
62+
63+
public virtual void Reset()
64+
{
65+
var config = Activator.CreateInstance(GetType());
66+
foreach (var property in GetType().GetProperties())
67+
if (property.CanWrite)
68+
property.SetValue(this, property.GetValue(config));
69+
}
70+
71+
protected abstract string GetConfigFilePath();
72+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using CommunityToolkit.Mvvm.ComponentModel;
2+
using HedgeModManager.Foundation;
3+
using System.Text.Json.Serialization;
4+
5+
namespace HedgeModManager.UI.Config;
6+
7+
public partial class GameConfig : ConfigBase
8+
{
9+
private string _gameName = "GameName";
10+
11+
[ObservableProperty] private List<string> _expandedCodes = [];
12+
13+
[JsonIgnore] public string GameName => _gameName;
14+
15+
public GameConfig() : base() { }
16+
17+
public GameConfig(string gameName) : this()
18+
{
19+
_gameName = gameName;
20+
}
21+
22+
public GameConfig(IGame game) : this(game.Name) { }
23+
24+
protected override string GetConfigFilePath()
25+
{
26+
return Path.Combine(Paths.GetConfigPath(), "Games", $"{GameName}.json");
27+
}
28+
}
Lines changed: 4 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
using Avalonia.Controls;
22
using CommunityToolkit.Mvvm.ComponentModel;
3-
using HedgeModManager.UI.ViewModels;
4-
using System.Text.Json;
3+
using HedgeModManager.Foundation;
54

65
namespace HedgeModManager.UI.Config;
76

8-
public partial class ProgramConfig : ViewModelBase
7+
public partial class ProgramConfig : ConfigBase
98
{
109
// TODO: Make use of setup
1110
[ObservableProperty] private bool _isSetupCompleted = true;
@@ -19,75 +18,13 @@ public partial class ProgramConfig : ViewModelBase
1918
[ObservableProperty] private string? _language;
2019
[ObservableProperty] private DateTime _lastUpdateCheck = DateTime.MinValue;
2120
[ObservableProperty] private WindowState _lastWindowState = WindowState.Normal;
22-
[ObservableProperty] private string[] _lastSeenLanguages = [];
21+
[ObservableProperty] private List<string> _lastSeenLanguages = [];
2322

2423
// Test Flags
2524
[ObservableProperty] private bool _testKeyboardInput = false;
2625

27-
private string GetConfigFilePath()
26+
protected override string GetConfigFilePath()
2827
{
2928
return Path.Combine(Paths.GetConfigPath(), "ProgramConfig.json");
3029
}
31-
32-
public void Load()
33-
{
34-
string filePath = GetConfigFilePath();
35-
if (!File.Exists(filePath))
36-
return;
37-
38-
string jsonData = File.ReadAllText(filePath);
39-
40-
var config = JsonSerializer.Deserialize<ProgramConfig>(jsonData, Program.JsonSerializerOptions);
41-
42-
// Copy data
43-
if (config != null)
44-
{
45-
foreach (var property in GetType().GetProperties())
46-
if (property.CanWrite)
47-
property.SetValue(this, property.GetValue(config));
48-
}
49-
}
50-
51-
public async Task LoadAsync()
52-
{
53-
string filePath = GetConfigFilePath();
54-
if (!File.Exists(filePath))
55-
return;
56-
57-
string jsonData = await File.ReadAllTextAsync(filePath);
58-
59-
var config = JsonSerializer.Deserialize<ProgramConfig>(jsonData, Program.JsonSerializerOptions);
60-
61-
// Copy data
62-
if (config != null)
63-
{
64-
foreach (var property in GetType().GetProperties())
65-
if (property.CanWrite)
66-
property.SetValue(this, property.GetValue(config));
67-
}
68-
}
69-
70-
public async Task SaveAsync()
71-
{
72-
string filePath = GetConfigFilePath();
73-
74-
string jsonData = JsonSerializer.Serialize(this, Program.JsonSerializerOptions);
75-
try
76-
{
77-
Directory.CreateDirectory(Path.GetDirectoryName(filePath)!);
78-
await File.WriteAllTextAsync(filePath, jsonData);
79-
}
80-
catch
81-
{
82-
// TODO: Log error
83-
}
84-
}
85-
86-
public void Reset()
87-
{
88-
var config = new ProgramConfig();
89-
foreach (var property in GetType().GetProperties())
90-
if (property.CanWrite)
91-
property.SetValue(this, property.GetValue(config));
92-
}
9330
}
Lines changed: 106 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,107 @@
1-
<UserControl xmlns="https://github.com/avaloniaui"
2-
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
3-
xmlns:cb="using:HedgeModManager.UI.Controls.Basic"
4-
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
5-
xmlns:cc="using:HedgeModManager.UI.Controls.Codes"
6-
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
7-
xmlns:vmc="using:HedgeModManager.UI.ViewModels.Codes"
8-
mc:Ignorable="d" d:DesignWidth="720" d:DesignHeight="390"
9-
x:Class="HedgeModManager.UI.Controls.Codes.CodeCategory"
10-
x:DataType="vmc:CodeCategoryViewModel">
11-
<StackPanel Orientation="Horizontal" Margin="0,4,0,0">
12-
<TextBlock Text="&#x21B3;" FontWeight="Bold" />
13-
<StackPanel Margin="16,0,0,0">
14-
<TextBlock Text="{Binding Name}" Margin="0,0,0,2" FontWeight="Bold" />
15-
<ItemsControl ItemsSource="{Binding Categories}">
16-
<ItemsControl.ItemTemplate>
17-
<DataTemplate>
18-
<cc:CodeCategory />
19-
</DataTemplate>
20-
</ItemsControl.ItemTemplate>
21-
</ItemsControl>
22-
<ItemsControl ItemsSource="{Binding Codes}">
23-
<ItemsControl.ItemTemplate>
24-
<DataTemplate>
25-
<cb:CheckBox Text="{Binding Code.Name}" IsChecked="{Binding Enabled}" />
26-
</DataTemplate>
27-
</ItemsControl.ItemTemplate>
28-
</ItemsControl>
29-
</StackPanel>
1+
<cp:ButtonUserControl xmlns="https://github.com/avaloniaui"
2+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
3+
xmlns:cb="using:HedgeModManager.UI.Controls.Basic"
4+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
5+
xmlns:cc="using:HedgeModManager.UI.Controls.Codes"
6+
xmlns:cp="using:HedgeModManager.UI.Controls.Primitives"
7+
xmlns:materialIcons="using:Material.Icons.Avalonia"
8+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
9+
xmlns:vmc="using:HedgeModManager.UI.ViewModels.Codes"
10+
mc:Ignorable="d" d:DesignWidth="300" d:DesignHeight="500"
11+
x:Class="HedgeModManager.UI.Controls.Codes.CodeCategory"
12+
x:DataType="vmc:CodeCategoryViewModel"
13+
Background="{DynamicResource BackgroundL0Brush}"
14+
Initialized="OnInitialized"
15+
Loaded="OnLoaded">
16+
<StackPanel>
17+
<Border Classes.codeCategory="True"
18+
Classes.pressed="{Binding Pressed, RelativeSource={RelativeSource AncestorType=cc:CodeCategory}}"
19+
Height="38" Margin="4" Cursor="Hand"
20+
CornerRadius="12" BorderThickness="1"
21+
PointerPressed="OnPointerPressed"
22+
PointerReleased="OnPointerReleased"
23+
PointerEntered="OnPointerEntered">
24+
<StackPanel Margin="0,0,24,0" Orientation="Horizontal">
25+
<materialIcons:MaterialIcon Kind="ChevronRight" Width="30" Height="30" Foreground="{DynamicResource Text.SubBrush}">
26+
<materialIcons:MaterialIcon.RenderTransform>
27+
<RotateTransform Angle="{Binding RotationAngle, RelativeSource={RelativeSource AncestorType=cc:CodeCategory}}" />
28+
</materialIcons:MaterialIcon.RenderTransform>
29+
</materialIcons:MaterialIcon>
30+
<TextBlock Text="{Binding Name, Converter={StaticResource StringLocalizeConverter}}" VerticalAlignment="Center"/>
31+
</StackPanel>
32+
<Border.Transitions>
33+
<Transitions>
34+
<BrushTransition Property="Background" Duration="0:0:0.1"/>
35+
<BrushTransition Property="BorderBrush" Duration="0:0:0.1"/>
36+
<DoubleTransition Property="Opacity" Duration="0:0:0.1"/>
37+
</Transitions>
38+
</Border.Transitions>
39+
<Border.Styles>
40+
<Style Selector="Border.codeCategory">
41+
<Setter Property="Opacity" Value="0.6" />
42+
<Setter Property="Background" Value="{DynamicResource BackgroundL1Brush}" />
43+
<Style Selector="^:pointerover">
44+
<Setter Property="Background" Value="{DynamicResource Button.HoverBrush}"/>
45+
</Style>
46+
<Style Selector="^.pressed">
47+
<Setter Property="Background" Value="{DynamicResource Button.PressedBrush}"/>
48+
</Style>
49+
</Style>
50+
</Border.Styles>
51+
</Border>
52+
<ItemsControl ItemsSource="{Binding Categories}" IsVisible="{Binding Expanded}">
53+
<ItemsControl.ItemTemplate>
54+
<DataTemplate>
55+
<Grid ColumnDefinitions="32,*">
56+
<Grid Grid.Column="0" VerticalAlignment="Stretch">
57+
<Border Classes.treeElement="True"
58+
Classes.isLastElement="{Binding IsLastElement}"
59+
Width="2"
60+
Background="{DynamicResource BackgroundL1Brush}">
61+
<Border.Styles>
62+
<Style Selector="Border.treeElement">
63+
<Setter Property="Margin" Value="8,0,0,0" />
64+
</Style>
65+
<Style Selector="Border.treeElement.isLastElement">
66+
<Setter Property="Margin" Value="8,0,0,24" />
67+
</Style>
68+
</Border.Styles>
69+
</Border>
70+
<Border Margin="22,22,0,0" Width="16" Height="2"
71+
VerticalAlignment="Top"
72+
Background="{DynamicResource BackgroundL1Brush}"/>
73+
</Grid>
74+
<cc:CodeCategory Grid.Column="1" />
75+
</Grid>
76+
</DataTemplate>
77+
</ItemsControl.ItemTemplate>
78+
</ItemsControl>
79+
<ItemsControl ItemsSource="{Binding Codes}" IsVisible="{Binding Expanded}">
80+
<ItemsControl.ItemTemplate>
81+
<DataTemplate>
82+
<Grid ColumnDefinitions="32,*">
83+
<Grid Grid.Column="0" VerticalAlignment="Stretch">
84+
<Border Classes.treeElement="True"
85+
Classes.isLastElement="{Binding IsLastElement}"
86+
Width="2"
87+
Background="{DynamicResource BackgroundL1Brush}">
88+
<Border.Styles>
89+
<Style Selector="Border.treeElement">
90+
<Setter Property="Margin" Value="8,0,0,0" />
91+
</Style>
92+
<Style Selector="Border.treeElement.isLastElement">
93+
<Setter Property="Margin" Value="8,0,0,24" />
94+
</Style>
95+
</Border.Styles>
96+
</Border>
97+
<Border Margin="22,22,0,0" Width="16" Height="2"
98+
VerticalAlignment="Top"
99+
Background="{DynamicResource BackgroundL1Brush}"/>
100+
</Grid>
101+
<cc:CodeEntry Grid.Column="1" />
102+
</Grid>
103+
</DataTemplate>
104+
</ItemsControl.ItemTemplate>
105+
</ItemsControl>
30106
</StackPanel>
31-
</UserControl>
107+
</cp:ButtonUserControl>

0 commit comments

Comments
 (0)