diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml new file mode 100644 index 0000000..e569ecc --- /dev/null +++ b/.github/workflows/dotnet.yml @@ -0,0 +1,66 @@ +name: NativeAOT Build + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build-on-linux: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup NativeAOT pre-requisites + run: sudo apt-get install clang zlib1g-dev libkrb5-dev --assume-yes + - name: Setup .NET + uses: actions/setup-dotnet@v1 + with: + dotnet-version: 6.0.x + - name: Publish + run: | + sudo chmod +x ./test.sh + ./test.sh + - uses: actions/upload-artifact@v2 + with: + name: Linux-Artifact + path: | + ./src/bin/x64/Release/net6.0/linux-x64/publish/*.bin + ./src/bin/x64/Release/net6.0/linux-x64/publish/*.so + ./src/bin/x64/Release/net6.0/linux-x64/publish/*.png + build-on-windows: + runs-on: windows-latest + steps: + - uses: actions/checkout@v2 + - name: Setup .NET + uses: actions/setup-dotnet@v1 + with: + dotnet-version: 6.0.x + - name: Publish + run: ./test.cmd + - uses: actions/upload-artifact@v2 + with: + name: Windows-Artifact + path: | + .\src\bin\x64\Release\net6.0\win-x64\publish\*.exe + .\src\bin\x64\Release\net6.0\win-x64\publish\*.dll + .\src\bin\x64\Release\net6.0\win-x64\publish\*.png + build-on-macos: + runs-on: macos-latest + steps: + - uses: actions/checkout@v2 + - name: Setup .NET + uses: actions/setup-dotnet@v1 + with: + dotnet-version: 6.0.x + - name: Publish + run: | + sudo chmod +x ./test.command + ./test.command + cd ./src/bin/x64/Release/net6.0/osx-x64/publish + zip -r -0 macOS-Artifact.zip *.app + mv *.zip ../../../../../../../. + - uses: actions/upload-artifact@v2 + with: + name: macOS-Artifact + path: macOS-Artifact.zip diff --git a/AvaloniaCoreRTDemo.sln b/AvaloniaCoreRTDemo.sln index e12cf41..24fd18d 100644 --- a/AvaloniaCoreRTDemo.sln +++ b/AvaloniaCoreRTDemo.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29911.98 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31912.275 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AvaloniaCoreRTDemo", "src\AvaloniaCoreRTDemo.csproj", "{41A52A04-F7D8-4981-9546-DB020E54851D}" EndProject @@ -13,12 +13,12 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {41A52A04-F7D8-4981-9546-DB020E54851D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {41A52A04-F7D8-4981-9546-DB020E54851D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {41A52A04-F7D8-4981-9546-DB020E54851D}.Debug|Any CPU.ActiveCfg = Debug|x64 + {41A52A04-F7D8-4981-9546-DB020E54851D}.Debug|Any CPU.Build.0 = Debug|x64 {41A52A04-F7D8-4981-9546-DB020E54851D}.Debug|x64.ActiveCfg = Debug|x64 {41A52A04-F7D8-4981-9546-DB020E54851D}.Debug|x64.Build.0 = Debug|x64 - {41A52A04-F7D8-4981-9546-DB020E54851D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {41A52A04-F7D8-4981-9546-DB020E54851D}.Release|Any CPU.Build.0 = Release|Any CPU + {41A52A04-F7D8-4981-9546-DB020E54851D}.Release|Any CPU.ActiveCfg = Release|x64 + {41A52A04-F7D8-4981-9546-DB020E54851D}.Release|Any CPU.Build.0 = Release|x64 {41A52A04-F7D8-4981-9546-DB020E54851D}.Release|x64.ActiveCfg = Release|x64 {41A52A04-F7D8-4981-9546-DB020E54851D}.Release|x64.Build.0 = Release|x64 EndGlobalSection diff --git a/src/AboutWindow.xaml b/src/AboutWindow.xaml deleted file mode 100644 index 14a606e..0000000 --- a/src/AboutWindow.xaml +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/AboutWindow.xaml.cs b/src/AboutWindow.xaml.cs deleted file mode 100644 index e749cf2..0000000 --- a/src/AboutWindow.xaml.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Avalonia; -using Avalonia.Controls; -using Avalonia.Markup.Xaml; - -namespace AvaloniaCoreRTDemo -{ - public class AboutWindow : Window - { - public AboutWindow() - { - this.InitializeComponent(); - this.DataContext = new AboutWindowViewModel(); - } - - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); - } - } -} diff --git a/src/AboutWindowViewModel.cs b/src/AboutWindowViewModel.cs deleted file mode 100644 index 424a18d..0000000 --- a/src/AboutWindowViewModel.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Runtime.InteropServices; -using Avalonia.Media.Imaging; -using ReactiveUI; - -namespace AvaloniaCoreRTDemo -{ - public class AboutWindowViewModel : ReactiveObject - { - private readonly IBitmap computerImage; - - public IBitmap ComputerImage => computerImage; - public String NCores => Environment.ProcessorCount.ToString(); - public String OS => RuntimeInformation.OSDescription; - public String OSArch => RuntimeInformation.OSArchitecture.ToString(); - public String OSVersion => Environment.OSVersion.ToString(); - public String ComputerName => Environment.MachineName; - public String UserName => Environment.UserName; - public String SystemPath => Environment.SystemDirectory; - public String CurrentPath => Environment.CurrentDirectory; - public String ProcessArch => RuntimeInformation.ProcessArchitecture.ToString(); - public String RuntimeName => RuntimeInformation.FrameworkDescription; - public String RuntimePath => RuntimeEnvironment.GetRuntimeDirectory(); - public String RuntimeVersion => RuntimeEnvironment.GetSystemVersion(); - public String FrameworkVersion => Environment.Version.ToString(); - - private String ComputerImageName - { - get - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - return "windows.png"; - else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - return "macos.png"; - else - return "linux.png"; - } - } - - public AboutWindowViewModel() - { - this.computerImage = GetImageFromResources(this.ComputerImageName); - } - - ~AboutWindowViewModel() - { - this.computerImage.Dispose(); - } - - private static Bitmap GetImageFromResources(String fileName) - { - Assembly asm = Assembly.GetExecutingAssembly(); - String resourceName = asm.GetManifestResourceNames().FirstOrDefault(str => str.EndsWith(fileName)); - if (resourceName != null) - using (Stream a = asm.GetManifestResourceStream(resourceName)) - return new Bitmap(a); - else - return null; - } - } -} diff --git a/src/App.axaml b/src/App.axaml new file mode 100644 index 0000000..e058919 --- /dev/null +++ b/src/App.axaml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/App.axaml.cs b/src/App.axaml.cs new file mode 100644 index 0000000..42529d0 --- /dev/null +++ b/src/App.axaml.cs @@ -0,0 +1,87 @@ +using Avalonia; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Markup.Xaml; +using Avalonia.Styling; +using Avalonia.Themes.Fluent; + +using AvaloniaCoreRTDemo.Interfaces; +using AvaloniaCoreRTDemo.Windows; + +namespace AvaloniaCoreRTDemo +{ + public sealed class App : Application, IThemeSwitch + { + private IStyle _baseLight; + private IStyle _baseDark; + + private IStyle _fluentLight; + private IStyle _fluentDark; + + private ApplicationTheme _currentTheme; + + public override void Initialize() + { + AvaloniaXamlLoader.Load(this); + this.Name = "AvaloniaCoreRTDemo"; + } + + public override void OnFrameworkInitializationCompleted() + { + this.InitializeThemes(); + if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + { + desktop.MainWindow = +#if !OSX + new MainWindow(); +#else + new MainWindowMacOS(); +#endif + this.DataContext = desktop.MainWindow.DataContext; + } + base.OnFrameworkInitializationCompleted(); + } + + private void InitializeThemes() + { + this._baseDark = this.Styles[0]; + this._baseLight = this.Styles[1]; + + this.Styles.Remove(this._baseDark); + + this._fluentLight = (FluentTheme)this.Resources["fluentLight"]!; + this._fluentDark = (FluentTheme)this.Resources["fluentDark"]!; + + this._currentTheme = ApplicationTheme.DefaultLight; + } + + ApplicationTheme IThemeSwitch.Current => this._currentTheme; + + void IThemeSwitch.ChangeTheme(ApplicationTheme theme) + { + this._currentTheme = theme; + switch (theme) + { + case ApplicationTheme.DefaultLight: + this.Styles[0] = this._baseLight; + this.Styles.Remove(this._baseDark); + break; + case ApplicationTheme.DefaultDark: + this.Styles[0] = this._baseDark; + this.Styles.Remove(this._baseLight); + break; + case ApplicationTheme.FluentLight: + this.Styles[0] = this._fluentLight; + this.Styles.Remove(this._fluentDark); + if (!this.Styles.Contains(this._baseLight)) + this.Styles.Add(this._baseLight); + break; + case ApplicationTheme.FluentDark: + this.Styles[0] = this._fluentDark; + this.Styles.Remove(this._baseLight); + if (!this.Styles.Contains(this._baseDark)) + this.Styles.Add(this._baseDark); + break; + } + } + } +} \ No newline at end of file diff --git a/src/App.xaml b/src/App.xaml deleted file mode 100644 index 6029ed9..0000000 --- a/src/App.xaml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - diff --git a/src/App.xaml.cs b/src/App.xaml.cs deleted file mode 100644 index 2610577..0000000 --- a/src/App.xaml.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Avalonia; -using Avalonia.Controls.ApplicationLifetimes; -using Avalonia.Markup.Xaml; - -namespace AvaloniaCoreRTDemo -{ - public 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(); - } - } -} \ No newline at end of file diff --git a/src/ApplicationTheme.cs b/src/ApplicationTheme.cs new file mode 100644 index 0000000..2323998 --- /dev/null +++ b/src/ApplicationTheme.cs @@ -0,0 +1,12 @@ +using System; + +namespace AvaloniaCoreRTDemo +{ + public enum ApplicationTheme : Byte + { + DefaultLight = 0, + DefaultDark = 1, + FluentLight = 2, + FluentDark = 3, + } +} diff --git a/src/Assets/about.ico b/src/Assets/about.ico new file mode 100644 index 0000000..b8d8f38 Binary files /dev/null and b/src/Assets/about.ico differ diff --git a/src/app.icns b/src/Assets/app.icns similarity index 100% rename from src/app.icns rename to src/Assets/app.icns diff --git a/src/app.ico b/src/Assets/app.ico similarity index 100% rename from src/app.ico rename to src/Assets/app.ico diff --git a/src/AvaloniaCoreRTDemo.csproj b/src/AvaloniaCoreRTDemo.csproj index a4682c4..26a4b5f 100644 --- a/src/AvaloniaCoreRTDemo.csproj +++ b/src/AvaloniaCoreRTDemo.csproj @@ -1,61 +1,61 @@ - + + - + WinExe - net5.0 - AnyCPU;x64 - app.ico + net6.0 + x64 + Assets/app.ico + true + + link + true + true + true + OSX - + - link false false true - - - + + + - - %(Filename) - - - Designer - - - - - - - - - - - - - - - - - - + + PreserveNewest PreserveNewest - - + + PreserveNewest - + + + + + + + + + + + + + + + $(AssemblyName) $(AssemblyName) com.$(username).$(AssemblyName) @@ -63,18 +63,51 @@ APPL $(AssemblyName) - app.icns + Assets/app.icns NSApplication true 1.0 true - - - - - link - - - - + + + + + + + + + + + + + App.axaml + + + + + + + MainControl.axaml + + + AboutWindow.axaml + + + + + + MainWindow.axaml + + + + + + + + MainWindowMacOS.axaml + + + + + \ No newline at end of file diff --git a/src/Controls/MainControl.axaml b/src/Controls/MainControl.axaml new file mode 100644 index 0000000..cdf5d75 --- /dev/null +++ b/src/Controls/MainControl.axaml @@ -0,0 +1,9 @@ + + + Welcome to Avalonia UI + NativeAOT! + + + + + diff --git a/src/MainWindow.xaml.cs b/src/Controls/MainControl.axaml.cs similarity index 50% rename from src/MainWindow.xaml.cs rename to src/Controls/MainControl.axaml.cs index d170c3e..59d7185 100644 --- a/src/MainWindow.xaml.cs +++ b/src/Controls/MainControl.axaml.cs @@ -1,21 +1,21 @@ -using Avalonia; using Avalonia.Controls; -using Avalonia.Controls.Shapes; using Avalonia.Markup.Xaml; -namespace AvaloniaCoreRTDemo +using AvaloniaCoreRTDemo.Controls.ViewModels; + +namespace AvaloniaCoreRTDemo.Controls { - public class MainWindow : Window + public sealed partial class MainControl : UserControl { - public MainWindow() + public MainControl() { InitializeComponent(); - this.DataContext = new MainWindowViewModel(this); } private void InitializeComponent() { AvaloniaXamlLoader.Load(this); + this.DataContext = new MainViewModel(); } } -} \ No newline at end of file +} diff --git a/src/Controls/ViewModels/MainViewModel.cs b/src/Controls/ViewModels/MainViewModel.cs new file mode 100644 index 0000000..ee69584 --- /dev/null +++ b/src/Controls/ViewModels/MainViewModel.cs @@ -0,0 +1,34 @@ +using System; +using System.IO; +using System.Runtime.CompilerServices; + +using Avalonia.Media.Imaging; + +using ReactiveUI; + +namespace AvaloniaCoreRTDemo.Controls.ViewModels +{ + internal sealed class MainViewModel : ReactiveObject + { + private readonly IBitmap _dotNetImage; + private readonly IBitmap _avaloniaImage; + + public IBitmap DotNetImage + { + get { return _dotNetImage; } + set { this.RaiseAndSetIfChanged(ref Unsafe.AsRef(this._dotNetImage), value); } + } + + public IBitmap AvaloniaImage + { + get { return _avaloniaImage; } + set { this.RaiseAndSetIfChanged(ref Unsafe.AsRef(this._avaloniaImage), value); } + } + + public MainViewModel() + { + this._dotNetImage = new Bitmap(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "dotnet.png")); + this._avaloniaImage = new Bitmap(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "avalonia.png")); + } + } +} diff --git a/src/linux.png b/src/Images/linux.png similarity index 100% rename from src/linux.png rename to src/Images/linux.png diff --git a/src/Images/linux_d.png b/src/Images/linux_d.png new file mode 100644 index 0000000..1ab908b Binary files /dev/null and b/src/Images/linux_d.png differ diff --git a/src/macos.png b/src/Images/macos.png similarity index 100% rename from src/macos.png rename to src/Images/macos.png diff --git a/src/Images/macos_d.png b/src/Images/macos_d.png new file mode 100644 index 0000000..3166c5d Binary files /dev/null and b/src/Images/macos_d.png differ diff --git a/src/windows.png b/src/Images/windows.png similarity index 100% rename from src/windows.png rename to src/Images/windows.png diff --git a/src/Images/windows_d.png b/src/Images/windows_d.png new file mode 100644 index 0000000..a9890c9 Binary files /dev/null and b/src/Images/windows_d.png differ diff --git a/src/Interfaces/IMainWindow.cs b/src/Interfaces/IMainWindow.cs new file mode 100644 index 0000000..2f8b2a8 --- /dev/null +++ b/src/Interfaces/IMainWindow.cs @@ -0,0 +1,9 @@ +using AvaloniaCoreRTDemo.Interfaces; + +namespace AvaloniaCoreRTDemo +{ + public interface IMainWindow + { + IThemeSwitch ThemeSwitch { get; } + } +} diff --git a/src/Interfaces/IThemeSwitch.cs b/src/Interfaces/IThemeSwitch.cs new file mode 100644 index 0000000..45815dc --- /dev/null +++ b/src/Interfaces/IThemeSwitch.cs @@ -0,0 +1,8 @@ +namespace AvaloniaCoreRTDemo.Interfaces +{ + public interface IThemeSwitch + { + ApplicationTheme Current { get; } + void ChangeTheme(ApplicationTheme theme); + } +} diff --git a/src/MainWindow.xaml b/src/MainWindow.xaml deleted file mode 100644 index 915b90a..0000000 --- a/src/MainWindow.xaml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - Welcome to Avalonia UI + CoreRT! - - - - - - - diff --git a/src/MainWindowViewModel.cs b/src/MainWindowViewModel.cs deleted file mode 100644 index fad3eb4..0000000 --- a/src/MainWindowViewModel.cs +++ /dev/null @@ -1,50 +0,0 @@ -using Avalonia.Media.Imaging; -using ReactiveUI; -using System; -using System.Reactive; -using Path = System.IO.Path; - -namespace AvaloniaCoreRTDemo -{ - public class MainWindowViewModel: ReactiveObject - { - public MainWindowViewModel(MainWindow window) - { - _window = window; - - DotNetImage = new Bitmap(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "dotnet.png")); - AvaloniaImage = new Bitmap(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "avalonia.png")); - - FileExitCommand = ReactiveCommand.Create(RunFileExit); - } - - public IBitmap DotNetImage - { - get { return dotNetImage; } - set { this.RaiseAndSetIfChanged(ref this.dotNetImage, value); } - } - - public IBitmap AvaloniaImage - { - get { return avaloniaImage; } - set { this.RaiseAndSetIfChanged(ref this.avaloniaImage, value); } - } - - public ReactiveCommand FileExitCommand { get; } - public void HelpAboutMethod() => RunHelpAbout(); - - void RunFileExit() - { - Environment.Exit(0); - } - - void RunHelpAbout() - { - new AboutWindow().ShowDialog(_window); - } - - private IBitmap dotNetImage; - private IBitmap avaloniaImage; - private readonly MainWindow _window; - } -} \ No newline at end of file diff --git a/src/Program.cs b/src/Program.cs index a90b6af..0bde694 100644 --- a/src/Program.cs +++ b/src/Program.cs @@ -1,4 +1,5 @@ -using Avalonia; + +using Avalonia; namespace AvaloniaCoreRTDemo { @@ -7,13 +8,14 @@ namespace AvaloniaCoreRTDemo // 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. - public static void Main(string[] args) => BuildAvaloniaApp() - .StartWithClassicDesktopLifetime(args); + public static void Main(string[] args) => BuildAvaloniaApp().StartWithClassicDesktopLifetime(args); // Avalonia configuration, don't remove; also used by visual designer. public static AppBuilder BuildAvaloniaApp() - => AppBuilder.Configure() - .UsePlatformDetect() - .LogToTrace(); + => AppBuilder.Configure().UsePlatformDetect() +#if OSX + .UseAvaloniaNative() +#endif + .LogToTrace(); } } diff --git a/src/Windows/AboutWindow.axaml b/src/Windows/AboutWindow.axaml new file mode 100644 index 0000000..8ef32d8 --- /dev/null +++ b/src/Windows/AboutWindow.axaml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Windows/AboutWindow.axaml.cs b/src/Windows/AboutWindow.axaml.cs new file mode 100644 index 0000000..4b9ca92 --- /dev/null +++ b/src/Windows/AboutWindow.axaml.cs @@ -0,0 +1,28 @@ +using System; + +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +using AvaloniaCoreRTDemo.Windows.ViewModels; + +namespace AvaloniaCoreRTDemo.Windows +{ + public sealed partial class AboutWindow : Window + { + public AboutWindow() + { + this.InitializeComponent(); + } + + public AboutWindow(Boolean darkTheme) + { + this.InitializeComponent(darkTheme); + } + + private void InitializeComponent(Boolean darkTheme = default) + { + AvaloniaXamlLoader.Load(this); + this.DataContext = new AboutViewModel(darkTheme); + } + } +} diff --git a/src/Windows/MainWindow.axaml b/src/Windows/MainWindow.axaml new file mode 100644 index 0000000..f912199 --- /dev/null +++ b/src/Windows/MainWindow.axaml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + diff --git a/src/Windows/MainWindow.axaml.cs b/src/Windows/MainWindow.axaml.cs new file mode 100644 index 0000000..a846014 --- /dev/null +++ b/src/Windows/MainWindow.axaml.cs @@ -0,0 +1,28 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +using AvaloniaCoreRTDemo.Interfaces; +using AvaloniaCoreRTDemo.Windows.ViewModels; + +namespace AvaloniaCoreRTDemo.Windows +{ + public sealed partial class MainWindow : Window, IMainWindow + { + public MainWindow() + { + InitializeComponent(); +#if DEBUG + this.AttachDevTools(); +#endif + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + this.DataContext = new MainViewModel(this); + } + + IThemeSwitch IMainWindow.ThemeSwitch => App.Current as IThemeSwitch; + } +} diff --git a/src/Windows/MainWindowMacOS.axaml b/src/Windows/MainWindowMacOS.axaml new file mode 100644 index 0000000..4ea0793 --- /dev/null +++ b/src/Windows/MainWindowMacOS.axaml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Windows/MainWindowMacOS.axaml.cs b/src/Windows/MainWindowMacOS.axaml.cs new file mode 100644 index 0000000..9c25bcc --- /dev/null +++ b/src/Windows/MainWindowMacOS.axaml.cs @@ -0,0 +1,28 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +using AvaloniaCoreRTDemo.Interfaces; +using AvaloniaCoreRTDemo.Windows.ViewModels; + +namespace AvaloniaCoreRTDemo.Windows +{ + public partial class MainWindowMacOS : Window, IMainWindow + { + public MainWindowMacOS() + { + InitializeComponent(); +#if DEBUG + this.AttachDevTools(); +#endif + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + this.DataContext = new MainViewModel(this); + } + + IThemeSwitch IMainWindow.ThemeSwitch => App.Current as IThemeSwitch; + } +} diff --git a/src/Windows/ViewModels/AboutViewModel.cs b/src/Windows/ViewModels/AboutViewModel.cs new file mode 100644 index 0000000..ee4b0a9 --- /dev/null +++ b/src/Windows/ViewModels/AboutViewModel.cs @@ -0,0 +1,68 @@ +using System; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; + +using Avalonia.Media.Imaging; + +using ReactiveUI; + +namespace AvaloniaCoreRTDemo.Windows.ViewModels +{ + internal sealed class AboutViewModel : ReactiveObject + { + private readonly IBitmap _computerImage; + private readonly Boolean _darkTheme; + + public IBitmap ComputerImage => _computerImage; + public static String NCores => Environment.ProcessorCount.ToString(); + public static String OS => RuntimeInformation.OSDescription; + public static String OSArch => RuntimeInformation.OSArchitecture.ToString(); + public static String OSVersion => Environment.OSVersion.ToString(); + public static String ComputerName => Environment.MachineName; + public static String UserName => Environment.UserName; + public static String SystemPath => Environment.SystemDirectory; + public static String CurrentPath => Environment.CurrentDirectory; + public static String ProcessArch => RuntimeInformation.ProcessArchitecture.ToString(); + public static String RuntimeName => RuntimeInformation.FrameworkDescription; + public static String RuntimePath => RuntimeEnvironment.GetRuntimeDirectory(); + public static String RuntimeVersion => RuntimeEnvironment.GetSystemVersion(); + public static String FrameworkVersion => Environment.Version.ToString(); + + private String ComputerImageName + { + get + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + return !_darkTheme ? "windows.png" : "windows_d.png"; + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + return !_darkTheme ? "macos.png" : "macos_d.png"; + else + return !_darkTheme ? "linux.png" : "linux_d.png"; + } + } + + public AboutViewModel(Boolean darkTheme) + { + this._darkTheme = darkTheme; + this._computerImage = GetImageFromResources(this.ComputerImageName); + } + + ~AboutViewModel() + { + this._computerImage.Dispose(); + } + + private static Bitmap GetImageFromResources(String fileName) + { + Assembly asm = Assembly.GetExecutingAssembly(); + String resourceName = asm.GetManifestResourceNames().FirstOrDefault(str => str.EndsWith(fileName)); + if (resourceName != null) + using (Stream bitmapStream = asm.GetManifestResourceStream(resourceName)) + return new Bitmap(bitmapStream); + else + return default; + } + } +} diff --git a/src/Windows/ViewModels/MainViewModel.cs b/src/Windows/ViewModels/MainViewModel.cs new file mode 100644 index 0000000..1a72964 --- /dev/null +++ b/src/Windows/ViewModels/MainViewModel.cs @@ -0,0 +1,72 @@ +using System; +using System.Reactive; + +using Avalonia.Controls; + +using ReactiveUI; + +namespace AvaloniaCoreRTDemo.Windows.ViewModels +{ + internal sealed class MainViewModel : MainViewModelBase + where TWindow : Window, IMainWindow + { + private readonly TWindow _window; + + private Boolean _defaultLightEnable = true; + private Boolean _defaultDarkEnable = true; + private Boolean _fluentLightEnable = true; + private Boolean _fluentDarkEnable = true; + + public Boolean DefaultLightEnabled + { + get => this._defaultLightEnable; + set => this.RaiseAndSetIfChanged(ref this._defaultLightEnable, value); + } + + public Boolean DefaultDarkEnabled + { + get => this._defaultDarkEnable; + set => this.RaiseAndSetIfChanged(ref this._defaultDarkEnable, value); + } + + public Boolean FluentLightEnabled + { + get => this._fluentLightEnable; + set => this.RaiseAndSetIfChanged(ref this._fluentLightEnable, value); + } + + public Boolean FluentDarkEnabled + { + get => this._fluentDarkEnable; + set => this.RaiseAndSetIfChanged(ref this._fluentDarkEnable, value); + } + + public ReactiveCommand FileExitCommand { get; } + + public MainViewModel(TWindow window) + : base(window.ThemeSwitch) + { + this._window = window; + this.FileExitCommand = ReactiveCommand.Create(RunFileExit); + this.ChangeTheme(window.ThemeSwitch.Current); + } + + public void DefaultLightMethod() => this.ChangeTheme(ApplicationTheme.DefaultLight); + public void DefaultDarkMethod() => this.ChangeTheme(ApplicationTheme.DefaultDark); + public void FluentLightMethod() => this.ChangeTheme(ApplicationTheme.FluentLight); + public void FluentDarkMethod() => this.ChangeTheme(ApplicationTheme.FluentDark); + public void HelpAboutMethod() => base.RunHelpAbout(this._window); + + private void RunFileExit() + => Environment.Exit(0); + + private void ChangeTheme(ApplicationTheme theme) + { + this.DefaultLightEnabled = theme != ApplicationTheme.DefaultLight && theme != ApplicationTheme.FluentLight; + this.DefaultDarkEnabled = theme != ApplicationTheme.DefaultDark && theme != ApplicationTheme.FluentDark; + this.FluentLightEnabled = theme != ApplicationTheme.FluentLight; + this.FluentDarkEnabled = theme != ApplicationTheme.FluentDark; + this._window.ThemeSwitch?.ChangeTheme(theme); + } + } +} diff --git a/src/Windows/ViewModels/MainViewModelBase.cs b/src/Windows/ViewModels/MainViewModelBase.cs new file mode 100644 index 0000000..9c9f2c6 --- /dev/null +++ b/src/Windows/ViewModels/MainViewModelBase.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using Avalonia.Controls; + +using AvaloniaCoreRTDemo.Interfaces; + +using ReactiveUI; + +namespace AvaloniaCoreRTDemo.Windows.ViewModels +{ + internal abstract class MainViewModelBase : ReactiveObject + { + private readonly IThemeSwitch _themeSwitch; + private Boolean _aboutEnable = true; + + public Boolean AboutEnabled + { + get => this._aboutEnable; + set => this.RaiseAndSetIfChanged(ref this._aboutEnable, value); + } + + public MainViewModelBase(IThemeSwitch window) + => this._themeSwitch = window; + + protected async void RunHelpAbout(Window currentWindow) + { + if (this.AboutEnabled) + try + { + this.AboutEnabled = false; + await new AboutWindow(IsDarkTheme(this._themeSwitch.Current)).ShowDialog(currentWindow); + } + finally + { + this.AboutEnabled = true; + } + } + + private static Boolean IsDarkTheme(ApplicationTheme? theme) + => theme switch + { + ApplicationTheme.DefaultDark => true, + ApplicationTheme.FluentDark => true, + _ => false, + }; + } +} diff --git a/src/nuget.config b/src/nuget.config index 8afae99..1dfbeae 100644 --- a/src/nuget.config +++ b/src/nuget.config @@ -1,11 +1,7 @@ - - - - - + diff --git a/src/rd.xml b/src/rd.xml index fa7ccfe..8e5aae8 100644 --- a/src/rd.xml +++ b/src/rd.xml @@ -9,6 +9,9 @@ + + +