Skip to content

Commit 3951661

Browse files
authored
Feat/avalonia v12 (#19)
* feat: add Avalonia v12 rewrite (GeneralUpdate.Tools.V12) - net10.0 + Avalonia 12.0.3 + Semi 12.0.1 + Ursa 2.0.0 - Simplified Patch: 2 folder pickers + manual fields, no csproj/update_config - Extension package with manifest.json support - OSS config with SHA256 + JSON export - Semi theme (zh-CN), SideNav navigation, MVVM architecture * fix: button-based navigation, add UseSkia for render backend - Replace ListBox with Button-based ItemsControl for reliable page switching - Add UseSkia() in Program.cs for Avalonia v12 rendering - Semi theme confirmed working
1 parent eedf225 commit 3951661

25 files changed

Lines changed: 591 additions & 0 deletions
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<Application xmlns="https://github.com/avaloniaui"
2+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
3+
x:Class="GeneralUpdate.Tools.V12.App"
4+
xmlns:local="using:GeneralUpdate.Tools.V12"
5+
xmlns:semi="https://irihi.tech/semi"
6+
RequestedThemeVariant="Default">
7+
8+
<Application.DataTemplates>
9+
<local:ViewLocator/>
10+
</Application.DataTemplates>
11+
12+
<Application.Styles>
13+
<FluentTheme />
14+
<semi:SemiTheme Locale="zh-CN" />
15+
</Application.Styles>
16+
</Application>
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using Avalonia;
2+
using Avalonia.Controls.ApplicationLifetimes;
3+
using Avalonia.Markup.Xaml;
4+
using GeneralUpdate.Tools.V12.ViewModels;
5+
using GeneralUpdate.Tools.V12.Views;
6+
7+
namespace GeneralUpdate.Tools.V12;
8+
9+
public partial class App : Application
10+
{
11+
public override void Initialize() { AvaloniaXamlLoader.Load(this); }
12+
public override void OnFrameworkInitializationCompleted()
13+
{
14+
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
15+
desktop.MainWindow = new MainWindow { DataContext = new MainWindowViewModel() };
16+
base.OnFrameworkInitializationCompleted();
17+
}
18+
}
172 KB
Binary file not shown.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<OutputType>WinExe</OutputType>
4+
<TargetFramework>net10.0</TargetFramework>
5+
<Nullable>enable</Nullable>
6+
<ApplicationManifest>app.manifest</ApplicationManifest>
7+
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
8+
<RootNamespace>GeneralUpdate.Tools.V12</RootNamespace>
9+
</PropertyGroup>
10+
11+
<ItemGroup>
12+
<AvaloniaResource Include="Assets\**" />
13+
</ItemGroup>
14+
15+
<ItemGroup>
16+
<PackageReference Include="Avalonia" Version="12.0.3" />
17+
<PackageReference Include="Avalonia.Desktop" Version="12.0.3" />
18+
<PackageReference Include="Avalonia.Themes.Fluent" Version="12.0.3" />
19+
<PackageReference Include="Avalonia.Fonts.Inter" Version="12.0.3" />
20+
<PackageReference Include="AvaloniaUI.DiagnosticsSupport" Version="2.2.1">
21+
<IncludeAssets Condition="'$(Configuration)' != 'Debug'">None</IncludeAssets>
22+
<PrivateAssets Condition="'$(Configuration)' != 'Debug'">All</PrivateAssets>
23+
</PackageReference>
24+
<PackageReference Include="Semi.Avalonia" Version="12.0.1" />
25+
<PackageReference Include="Semi.Avalonia.DataGrid" Version="12.0.0" />
26+
<PackageReference Include="Irihi.Ursa" Version="2.0.0" />
27+
<PackageReference Include="Irihi.Ursa.Themes.Semi" Version="2.0.0" />
28+
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.1" />
29+
<PackageReference Include="GeneralUpdate.Core" Version="10.4.6" />
30+
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
31+
</ItemGroup>
32+
</Project>
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using CommunityToolkit.Mvvm.ComponentModel;
2+
3+
namespace GeneralUpdate.Tools.V12.Models;
4+
5+
public partial class ExtensionConfigModel : ObservableObject
6+
{
7+
[ObservableProperty] private string _name = "";
8+
[ObservableProperty] private string _version = "1.0.0.0";
9+
[ObservableProperty] private string _description = "";
10+
[ObservableProperty] private string _extensionDirectory = "";
11+
[ObservableProperty] private string _exportPath = "";
12+
[ObservableProperty] private string _dependencies = "";
13+
[ObservableProperty] private string _publisher = "";
14+
[ObservableProperty] private string _license = "";
15+
[ObservableProperty] private string _categoriesText = "";
16+
[ObservableProperty] private string _minHostVersion = "";
17+
[ObservableProperty] private string _maxHostVersion = "";
18+
[ObservableProperty] private int _platformValue = 1;
19+
[ObservableProperty] private bool _isPreRelease;
20+
[ObservableProperty] private string _outputPath = "";
21+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using CommunityToolkit.Mvvm.ComponentModel;
2+
3+
namespace GeneralUpdate.Tools.V12.Models;
4+
5+
public partial class OSSConfigModel : ObservableObject
6+
{
7+
[ObservableProperty] private string _packetName = "Packet";
8+
[ObservableProperty] private string _hash = "";
9+
[ObservableProperty] private string _version = "1.0.0.0";
10+
[ObservableProperty] private string _url = "http://127.0.0.1";
11+
[ObservableProperty] private string _releaseDate = "";
12+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using CommunityToolkit.Mvvm.ComponentModel;
2+
3+
namespace GeneralUpdate.Tools.V12.Models;
4+
5+
public partial class PatchConfigModel : ObservableObject
6+
{
7+
[ObservableProperty] private string _oldDirectory = "";
8+
[ObservableProperty] private string _newDirectory = "";
9+
[ObservableProperty] private string _packageName = "";
10+
[ObservableProperty] private string _version = "1.0.0.0";
11+
[ObservableProperty] private string _format = ".zip";
12+
[ObservableProperty] private string _outputPath = "";
13+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using Avalonia;
2+
using System;
3+
4+
namespace GeneralUpdate.Tools.V12;
5+
6+
sealed class Program
7+
{
8+
[STAThread]
9+
public static void Main(string[] args) => BuildAvaloniaApp()
10+
.StartWithClassicDesktopLifetime(args);
11+
12+
public static AppBuilder BuildAvaloniaApp()
13+
=> AppBuilder.Configure<App>()
14+
.UsePlatformDetect()
15+
.WithInterFont()
16+
.LogToTrace()
17+
.UseSkia();
18+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System;
2+
using System.IO;
3+
using System.Threading.Tasks;
4+
using GeneralUpdate.Differential;
5+
6+
namespace GeneralUpdate.Tools.V12.Services;
7+
8+
public class DiffService
9+
{
10+
public async Task GeneratePatchAsync(string oldDir, string newDir, string patchDir)
11+
{
12+
if (!Directory.Exists(oldDir)) throw new DirectoryNotFoundException("Old: " + oldDir);
13+
if (!Directory.Exists(newDir)) throw new DirectoryNotFoundException("New: " + newDir);
14+
Directory.CreateDirectory(patchDir);
15+
await Task.Run(() => DifferentialCore.Clean(oldDir, newDir, patchDir).GetAwaiter().GetResult());
16+
}
17+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using System;
2+
using System.IO;
3+
using System.IO.Compression;
4+
using System.Security.Cryptography;
5+
using System.Text;
6+
using System.Threading.Tasks;
7+
using Newtonsoft.Json;
8+
9+
namespace GeneralUpdate.Tools.V12.Services;
10+
11+
public class PackageService
12+
{
13+
public async Task CompressDirectoryAsync(string sourceDir, string outputPath)
14+
{
15+
await Task.Run(() => { if (File.Exists(outputPath)) File.Delete(outputPath); ZipFile.CreateFromDirectory(sourceDir, outputPath, CompressionLevel.Optimal, false); });
16+
}
17+
public async Task CreateManifestAsync(string zipPath, object manifest)
18+
{
19+
await Task.Run(() => {
20+
var json = JsonConvert.SerializeObject(manifest, Formatting.Indented, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
21+
using var archive = ZipFile.Open(zipPath, ZipArchiveMode.Update);
22+
var entry = archive.CreateEntry("manifest.json", CompressionLevel.Optimal);
23+
using var writer = new StreamWriter(entry.Open(), Encoding.UTF8);
24+
writer.Write(json);
25+
});
26+
}
27+
}
28+
29+
public class HashService
30+
{
31+
public async Task<string> ComputeHashAsync(string filePath)
32+
{
33+
return await Task.Run(() => {
34+
using var sha256 = SHA256.Create();
35+
using var stream = File.OpenRead(filePath);
36+
var hash = sha256.ComputeHash(stream);
37+
return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
38+
});
39+
}
40+
}

0 commit comments

Comments
 (0)