Add example cross platform avalonia project

This commit is contained in:
Caelan Sayler
2024-01-01 11:57:46 +00:00
parent 716d7d93d9
commit ef5b3a9d6f
10 changed files with 294 additions and 1 deletions

View File

@@ -12,9 +12,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionLevel", "SolutionLe
.editorconfig = .editorconfig
.github\workflows\build.yml = .github\workflows\build.yml
src\Directory.Build.props = src\Directory.Build.props
README.md = README.md
Velopack.entitlements = Velopack.entitlements
version.json = version.json
README.md = README.md
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Velopack.Packaging", "src\Velopack.Packaging\Velopack.Packaging.csproj", "{352C15EA-622F-4132-80D8-9B6E3C83404E}"
@@ -35,6 +35,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Velopack.Packaging.Tests",
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestApp", "test\TestApp\TestApp.csproj", "{784B5987-2E71-4AEE-81B9-E0CC7F1DBEB3}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "examples", "examples", "{3EBFA551-780C-473D-A197-0EE56F2CBA82}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AvaloniaCrossPlat", "examples\AvaloniaCrossPlat\AvaloniaCrossPlat.csproj", "{1FF6A262-13D0-45DF-B818-77AC84C52C6F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -81,6 +85,10 @@ Global
{784B5987-2E71-4AEE-81B9-E0CC7F1DBEB3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{784B5987-2E71-4AEE-81B9-E0CC7F1DBEB3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{784B5987-2E71-4AEE-81B9-E0CC7F1DBEB3}.Release|Any CPU.Build.0 = Release|Any CPU
{1FF6A262-13D0-45DF-B818-77AC84C52C6F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1FF6A262-13D0-45DF-B818-77AC84C52C6F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1FF6A262-13D0-45DF-B818-77AC84C52C6F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1FF6A262-13D0-45DF-B818-77AC84C52C6F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -90,6 +98,7 @@ Global
{519EAB50-47B8-425F-8B20-AB9548F220B4} = {7AC3A776-B582-4B65-9D03-BD52332B5CA3}
{175B06A5-5C09-4DAB-A6AF-C8A2257BD1B6} = {7AC3A776-B582-4B65-9D03-BD52332B5CA3}
{784B5987-2E71-4AEE-81B9-E0CC7F1DBEB3} = {7AC3A776-B582-4B65-9D03-BD52332B5CA3}
{1FF6A262-13D0-45DF-B818-77AC84C52C6F} = {3EBFA551-780C-473D-A197-0EE56F2CBA82}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {68CA987A-9BAB-4C75-8EEB-4596BA6BBD07}

View File

@@ -0,0 +1,10 @@
<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="AvaloniaCrossPlat.App"
RequestedThemeVariant="Default">
<!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. -->
<Application.Styles>
<FluentTheme />
</Application.Styles>
</Application>

View File

@@ -0,0 +1,23 @@
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
namespace AvaloniaCrossPlat;
public partial class App : Application
{
public override void Initialize()
{
AvaloniaXamlLoader.Load(this);
}
public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
desktop.MainWindow = new MainWindow();
}
base.OnFrameworkInitializationCompleted();
}
}

View File

@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
<ApplicationManifest>app.manifest</ApplicationManifest>
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
<NoWarn>$(NoWarn);CA2007</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Avalonia" Version="11.0.6" />
<PackageReference Include="Avalonia.Desktop" Version="11.0.6" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.6" />
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.0.6" />
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.0.6" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Velopack\Velopack.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1 @@
class Const { public const string RELEASES_DIR = @"{REPLACE_ME}"; }

View File

@@ -0,0 +1,27 @@
<Window xmlns="https://github.com/avaloniaui"
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" Width="600" Height="600"
x:Class="AvaloniaCrossPlat.MainWindow"
WindowStartupLocation="CenterScreen"
Title="AvaloniaCrossPlat">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="15" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel>
<TextBlock Margin="10" Name="TextStatus" />
<StackPanel Orientation="Horizontal" Margin="10">
<Button Name="BtnCheckUpdate" Content="Check for Updates" Click="BtnCheckUpdateClick" />
<Button Margin="10,0" Name="BtnDownloadUpdate" Content="Download" Click="BtnDownloadUpdateClick" IsEnabled="False" />
<Button Name="BtnRestartApply" Content="Restart &amp; Apply" Click="BtnRestartApplyClick" IsEnabled="False" />
</StackPanel>
</StackPanel>
<ScrollViewer Name="ScrollLog" Grid.Row="2" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<TextBlock Name="TextLog" Background="BlueViolet" Foreground="White" TextWrapping="Wrap" />
</ScrollViewer>
</Grid>
</Window>

View File

@@ -0,0 +1,120 @@
using System;
using System.IO;
using System.Text;
using System.Xml.Linq;
using Avalonia.Controls;
using Avalonia.Threading;
using Microsoft.Extensions.Logging;
using Velopack;
using static System.Net.Mime.MediaTypeNames;
namespace AvaloniaCrossPlat;
public partial class MainWindow : Window
{
private UpdateManager _um;
private UpdateInfo _update;
public MainWindow()
{
InitializeComponent();
var channel = VelopackRuntimeInfo.SystemOs.GetOsShortName();
_um = new UpdateManager(Const.RELEASES_DIR, channel, new TextBoxLogger(Log));
UpdateStatus();
}
private async void BtnCheckUpdateClick(object sender, Avalonia.Interactivity.RoutedEventArgs e)
{
Working();
try {
_update = await _um.CheckForUpdatesAsync();
} catch (Exception ex) {
Log("ERROR: " + ex.Message);
}
UpdateStatus();
}
private async void BtnDownloadUpdateClick(object sender, Avalonia.Interactivity.RoutedEventArgs e)
{
Working();
try {
await _um.DownloadUpdatesAsync(_update, Progress);
} catch (Exception ex) {
Log("ERROR: " + ex.Message);
}
UpdateStatus();
}
private void Log(string text)
{
TextLog.Text += text + Environment.NewLine;
ScrollLog.ScrollToEnd();
}
private void BtnRestartApplyClick(object sender, Avalonia.Interactivity.RoutedEventArgs e)
{
_um.ApplyUpdatesAndRestart();
}
private void Progress(int percent)
{
Dispatcher.UIThread.Post(() => {
TextStatus.Text = $"Downloading ({percent}%)...";
});
}
private void Working()
{
BtnCheckUpdate.IsEnabled = false;
BtnDownloadUpdate.IsEnabled = false;
BtnRestartApply.IsEnabled = false;
TextStatus.Text = "Working...";
}
private void UpdateStatus()
{
StringBuilder sb = new StringBuilder();
sb.AppendLine($"Velopack version: {VelopackRuntimeInfo.VelopackNugetVersion}");
sb.AppendLine($"This app version: {(_um.IsInstalled ? _um.CurrentVersion : "(n/a - not installed)")}");
if (_update != null) {
sb.AppendLine($"Update available: {_update.TargetFullRelease.Version}");
BtnDownloadUpdate.IsEnabled = true;
} else {
BtnDownloadUpdate.IsEnabled = false;
}
if (_um.IsUpdatePendingRestart) {
sb.AppendLine("Update ready, pending restart to install");
BtnRestartApply.IsEnabled = true;
} else {
BtnRestartApply.IsEnabled = false;
}
TextStatus.Text = sb.ToString();
BtnCheckUpdate.IsEnabled = true;
}
private class TextBoxLogger : ILogger
{
private readonly Action<string> _textBox;
public TextBoxLogger(Action<string> textBox)
{
_textBox = textBox;
}
public IDisposable BeginScope<TState>(TState state) => null;
public bool IsEnabled(LogLevel logLevel) => true;
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state,
Exception exception, Func<TState, Exception, string> formatter)
{
var text = formatter(state, exception);
Dispatcher.UIThread.Post(() => {
_textBox(text);
});
}
}
}

View File

@@ -0,0 +1,28 @@
using Avalonia;
using System;
using Velopack;
namespace AvaloniaCrossPlat;
class Program
{
// Initialization code. Don't use any Avalonia, third-party APIs or any
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
// yet and stuff might break.
[STAThread]
public static void Main(string[] args)
{
VelopackApp.Build()
.Run();
BuildAvaloniaApp()
.StartWithClassicDesktopLifetime(args);
}
// Avalonia configuration, don't remove; also used by visual designer.
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.UsePlatformDetect()
.WithInterFont()
.LogToTrace();
}

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<!-- This manifest is used on Windows only.
Don't remove it as it might cause problems with window transparency and embedded controls.
For more details visit https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests -->
<assemblyIdentity version="1.0.0.0" name="AvaloniaCrossPlat.Desktop"/>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- A list of the Windows versions that this application has been tested on
and is designed to work with. Uncomment the appropriate elements
and Windows will automatically select the most compatible environment. -->
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
</assembly>

View File

@@ -0,0 +1,32 @@
@echo off
setlocal enabledelayedexpansion
:: Check if version parameter is provided
if "%~1"=="" (
echo Please provide a version number.
echo Usage: build.bat version_number
exit /b 1
)
echo Building Velopack
cd %~dp0..\..\src\Rust
cargo build --features windows
cd %~dp0..\..\
dotnet build
cd %~dp0
set "version=%~1"
set "releasesDir=%~dp0releases"
:: Write to Const.cs
echo class Const { public const string RELEASES_DIR = @"%releasesDir%"; } > "%~dp0Const.cs"
echo Const.cs file updated with releases directory (%releasesDir%).
echo Compiling AvaloniaCrossPlatTest with dotnet...
dotnet publish -c Release --no-self-contained -r win-x64 -o %~dp0publish
echo class Const { public const string RELEASES_DIR = @"{REPLACE_ME}"; } > "%~dp0Const.cs"
echo Const.cs file reset
echo Building Velopack Release v%version%
%~dp0..\..\build\Debug\net8.0\vpk.exe pack -u AvaloniaCrossPlatTest -v %version% -o %releasesDir% -r win-x64 -e AvaloniaCrossPlat.exe -p %~dp0publish -c win