This commit is contained in:
2025-12-14 17:30:54 +01:00
commit c9816297d7
46 changed files with 1756 additions and 0 deletions

16
Candelator/App.axaml Normal file
View File

@@ -0,0 +1,16 @@
<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Candelator"
x:Class="Candelator.App"
RequestedThemeVariant="Default">
<!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. -->
<Application.DataTemplates>
<local:ViewLocator/>
</Application.DataTemplates>
<Application.Styles>
<FluentTheme />
<StyleInclude Source="avares://Pilz.UI.AvaloniaUI/Assets/Styles/EnhancedDefaults.axaml"/>
</Application.Styles>
</Application>

54
Candelator/App.axaml.cs Normal file
View File

@@ -0,0 +1,54 @@
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Data.Core;
using Avalonia.Data.Core.Plugins;
using System.Linq;
using Avalonia.Markup.Xaml;
using Candelator.ViewModels;
using Candelator.Views;
namespace Candelator;
public partial class App : Application
{
public override void Initialize()
{
AvaloniaXamlLoader.Load(this);
}
public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
// Avoid duplicate validations from both Avalonia and the CommunityToolkit.
// More info: https://docs.avaloniaui.net/docs/guides/development-guides/data-validation#manage-validationplugins
DisableAvaloniaDataAnnotationValidation();
desktop.MainWindow = new MainWindow
{
DataContext = new MainViewModel()
};
}
else if (ApplicationLifetime is ISingleViewApplicationLifetime singleViewPlatform)
{
singleViewPlatform.MainView = new MainView
{
DataContext = new MainViewModel()
};
}
base.OnFrameworkInitializationCompleted();
}
private void DisableAvaloniaDataAnnotationValidation()
{
// Get an array of plugins to remove
var dataValidationPluginsToRemove =
BindingPlugins.DataValidators.OfType<DataAnnotationsValidationPlugin>().ToArray();
// remove each entry found
foreach (var plugin in dataValidationPluginsToRemove)
{
BindingPlugins.DataValidators.Remove(plugin);
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

View File

@@ -0,0 +1,40 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<LangVersion>latest</LangVersion>
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
</PropertyGroup>
<ItemGroup>
<AvaloniaResource Include="Assets\**"/>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Avalonia"/>
<PackageReference Include="Avalonia.Themes.Fluent"/>
<PackageReference Include="Avalonia.Fonts.Inter"/>
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
<PackageReference Include="Avalonia.Diagnostics">
<IncludeAssets Condition="'$(Configuration)' != 'Debug'">None</IncludeAssets>
<PrivateAssets Condition="'$(Configuration)' != 'Debug'">All</PrivateAssets>
</PackageReference>
<PackageReference Include="CommunityToolkit.Mvvm"/>
<PackageReference Include="Pilz.UI.AvaloniaUI" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="LangRes\GeneralLangRes.resx">
<Generator>PublicResXFileCodeGenerator</Generator>
<LastGenOutput>GeneralLangRes.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Compile Update="LangRes\GeneralLangRes.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>GeneralLangRes.resx</DependentUpon>
</Compile>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,96 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Candelator.LangRes {
using System;
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class GeneralLangRes {
private static System.Resources.ResourceManager resourceMan;
private static System.Globalization.CultureInfo resourceCulture;
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal GeneralLangRes() {
}
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
public static System.Resources.ResourceManager ResourceManager {
get {
if (object.Equals(null, resourceMan)) {
System.Resources.ResourceManager temp = new System.Resources.ResourceManager("Candelator.LangRes.GeneralLangRes", typeof(GeneralLangRes).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
public static System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
public static string Wax {
get {
return ResourceManager.GetString("Wax", resourceCulture);
}
}
public static string Additive {
get {
return ResourceManager.GetString("Additive", resourceCulture);
}
}
public static string Color {
get {
return ResourceManager.GetString("Color", resourceCulture);
}
}
public static string Oil {
get {
return ResourceManager.GetString("Oil", resourceCulture);
}
}
public static string Count {
get {
return ResourceManager.GetString("Count", resourceCulture);
}
}
public static string OilFactorTooltipStringFormat {
get {
return ResourceManager.GetString("OilFactorTooltipStringFormat", resourceCulture);
}
}
public static string ColorFactorTooltipStringFormat {
get {
return ResourceManager.GetString("ColorFactorTooltipStringFormat", resourceCulture);
}
}
public static string AdditiveFactorTooltipStringFormat {
get {
return ResourceManager.GetString("AdditiveFactorTooltipStringFormat", resourceCulture);
}
}
}
}

View File

@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Wax" xml:space="preserve">
<value>Wax</value>
</data>
<data name="Additive" xml:space="preserve">
<value>Additive</value>
</data>
<data name="Color" xml:space="preserve">
<value>Color</value>
</data>
<data name="Oil" xml:space="preserve">
<value>Oil</value>
</data>
<data name="Count" xml:space="preserve">
<value>Count</value>
</data>
<data name="OilFactorTooltipStringFormat" xml:space="preserve">
<value>{0:0%} to {1:0%}</value>
</data>
<data name="ColorFactorTooltipStringFormat" xml:space="preserve">
<value>{0:0.###%} to {1:0.###%}</value>
</data>
<data name="AdditiveFactorTooltipStringFormat" xml:space="preserve">
<value>{0:0.#%} to {1:0.#%}</value>
</data>
</root>

37
Candelator/ViewLocator.cs Normal file
View File

@@ -0,0 +1,37 @@
using System;
using System.Diagnostics.CodeAnalysis;
using Avalonia.Controls;
using Avalonia.Controls.Templates;
using Candelator.ViewModels;
namespace Candelator;
/// <summary>
/// Given a view model, returns the corresponding view if possible.
/// </summary>
[RequiresUnreferencedCode(
"Default implementation of ViewLocator involves reflection which may be trimmed away.",
Url = "https://docs.avaloniaui.net/docs/concepts/view-locator")]
public class ViewLocator : IDataTemplate
{
public Control? Build(object? param)
{
if (param is null)
return null;
var name = param.GetType().FullName!.Replace("ViewModel", "View", StringComparison.Ordinal);
var type = Type.GetType(name);
if (type != null)
{
return (Control)Activator.CreateInstance(type)!;
}
return new TextBlock { Text = "Not Found: " + name };
}
public bool Match(object? data)
{
return data is ViewModelBase;
}
}

View File

@@ -0,0 +1,68 @@
using System.ComponentModel;
using CommunityToolkit.Mvvm.ComponentModel;
namespace Candelator.ViewModels;
public partial class MainViewModel : ViewModelBase
{
[ObservableProperty] private double inputContainerVolume = 100;
[ObservableProperty] private double outputWaxWeight;
[ObservableProperty] private double inputCandleCount = 1;
[ObservableProperty] private bool useAdditive;
[ObservableProperty] private double inputAdditiveFactor = 0.002;
[ObservableProperty] private double outputAdditiveWeight;
[ObservableProperty] private bool useColor;
[ObservableProperty] private double inputColorFactor = 0.0001;
[ObservableProperty] private double outputColorWeight;
[ObservableProperty] private bool useOil;
[ObservableProperty] private double inputOilFactor = 0.05;
[ObservableProperty] private double outputOilWeight;
public MainViewModel()
{
Calculate();
}
protected override void OnPropertyChanged(PropertyChangedEventArgs e)
{
base.OnPropertyChanged(e);
if (e.PropertyName != null && (e.PropertyName.StartsWith("Use") || e.PropertyName.StartsWith("Input")))
Calculate();
}
private void Calculate()
{
var outputWaxWeightTotal = InputContainerVolume * InputCandleCount * 0.8;
var outputWaxWeight = outputWaxWeightTotal;
if (UseAdditive)
{
OutputAdditiveWeight = outputWaxWeightTotal * InputAdditiveFactor;
outputWaxWeight -= OutputAdditiveWeight;
}
else
OutputAdditiveWeight = 0;
if (UseColor)
{
OutputColorWeight = outputWaxWeightTotal * InputColorFactor;
outputWaxWeight -= OutputColorWeight;
}
else
OutputColorWeight = 0;
if (UseOil)
{
OutputOilWeight = outputWaxWeightTotal * InputOilFactor;
outputWaxWeight -= OutputOilWeight;
}
else
OutputOilWeight = 0;
OutputWaxWeight = outputWaxWeight;
}
}

View File

@@ -0,0 +1,7 @@
using CommunityToolkit.Mvvm.ComponentModel;
namespace Candelator.ViewModels;
public abstract class ViewModelBase : ObservableObject
{
}

View File

@@ -0,0 +1,166 @@
<UserControl 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"
xmlns:vm="using:Candelator.ViewModels"
xmlns:langRes="clr-namespace:Candelator.LangRes"
mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="600"
x:Class="Candelator.Views.MainView"
x:DataType="vm:MainViewModel">
<Design.DataContext>
<vm:MainViewModel/>
</Design.DataContext>
<Grid
RowSpacing="6"
ColumnSpacing="6"
RowDefinitions="Auto,Auto,Auto,Auto,Auto"
ColumnDefinitions="Auto,80*,20*"
Margin="3">
<!-- Wax -->
<TextBlock
Grid.Row="0"
Grid.Column="0"
Text="{x:Static langRes:GeneralLangRes.Wax}"/>
<NumericUpDown
Grid.Row="0"
Grid.Column="1"
FormatString="0.## ml"
Value="{Binding InputContainerVolume}"/>
<TextBlock
Grid.Row="0"
Grid.Column="2"
HorizontalAlignment="Right"
Text="{Binding OutputWaxWeight, StringFormat=0.## g}"/>
<!-- Candle count -->
<TextBlock
Grid.Row="1"
Grid.Column="0"
Text="{x:Static langRes:GeneralLangRes.Count}"/>
<NumericUpDown
Grid.Row="1"
Grid.Column="1"
FormatString="#"
Minimum="1"
Value="{Binding InputCandleCount}"/>
<!-- Additive -->
<CheckBox
Grid.Row="2"
Grid.Column="0"
Content="{x:Static langRes:GeneralLangRes.Additive}"
IsChecked="{Binding UseAdditive}"/>
<NumericUpDown
Grid.Row="2"
Grid.Column="1"
x:Name="NumericUpDownInputAdditiveFactor"
FormatString="0.#%"
Increment="0.001"
Minimum="0.001"
Maximum="0.003"
Value="{Binding InputAdditiveFactor}"
IsEnabled="{Binding UseAdditive}">
<ToolTip.Tip>
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{x:Static langRes:GeneralLangRes.AdditiveFactorTooltipStringFormat}">
<Binding ElementName="NumericUpDownInputAdditiveFactor" Path="Minimum"/>
<Binding ElementName="NumericUpDownInputAdditiveFactor" Path="Maximum"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</ToolTip.Tip>
</NumericUpDown>
<TextBlock
Grid.Row="2"
Grid.Column="2"
HorizontalAlignment="Right"
Text="{Binding OutputAdditiveWeight, StringFormat=0.## g}"/>
<!-- Color -->
<CheckBox
Grid.Row="3"
Grid.Column="0"
Content="{x:Static langRes:GeneralLangRes.Color}"
IsChecked="{Binding UseColor}"/>
<NumericUpDown
Grid.Row="3"
Grid.Column="1"
x:Name="NumericUpDownInputColorFactor"
FormatString="0.###%"
Increment="0.0001"
Minimum="0.00002"
Maximum="0.0006"
Value="{Binding InputColorFactor}"
IsEnabled="{Binding UseColor}">
<ToolTip.Tip>
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{x:Static langRes:GeneralLangRes.ColorFactorTooltipStringFormat}">
<Binding ElementName="NumericUpDownInputColorFactor" Path="Minimum"/>
<Binding ElementName="NumericUpDownInputColorFactor" Path="Maximum"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</ToolTip.Tip>
</NumericUpDown>
<TextBlock
Grid.Row="3"
Grid.Column="2"
HorizontalAlignment="Right"
Text="{Binding OutputColorWeight, StringFormat=0.## g}"/>
<!-- Oil -->
<CheckBox
Grid.Row="4"
Grid.Column="0"
Content="{x:Static langRes:GeneralLangRes.Oil}"
IsChecked="{Binding UseOil}"/>
<NumericUpDown
Grid.Row="4"
Grid.Column="1"
x:Name="NumericUpDownInputOilFactor"
FormatString="0.#%"
Increment="0.01"
Minimum="0.03"
Maximum="0.12"
Value="{Binding InputOilFactor}"
IsEnabled="{Binding UseOil}">
<ToolTip.Tip>
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{x:Static langRes:GeneralLangRes.OilFactorTooltipStringFormat}">
<Binding ElementName="NumericUpDownInputOilFactor" Path="Minimum"/>
<Binding ElementName="NumericUpDownInputOilFactor" Path="Maximum"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</ToolTip.Tip>
</NumericUpDown>
<TextBlock
Grid.Row="4"
Grid.Column="2"
HorizontalAlignment="Right"
Text="{Binding OutputOilWeight, StringFormat=0.## g}"/>
</Grid>
</UserControl>

View File

@@ -0,0 +1,11 @@
using Avalonia.Controls;
namespace Candelator.Views;
public partial class MainView : UserControl
{
public MainView()
{
InitializeComponent();
}
}

View File

@@ -0,0 +1,15 @@
<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"
xmlns:views="using:Candelator.Views"
mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="600"
x:Class="Candelator.Views.MainWindow"
Width="400"
SizeToContent="Height"
CanMaximize="False"
Icon="/Assets/avalonia-logo.ico"
Title="Candelator">
<views:MainView/>
</Window>

View File

@@ -0,0 +1,11 @@
using Avalonia.Controls;
namespace Candelator.Views;
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}