Start working on settings UI

This commit is contained in:
2024-09-29 21:00:13 -04:00
parent 3a87285e58
commit 5631bc87be
9 changed files with 267 additions and 62 deletions

View File

@@ -1,12 +1,16 @@
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using NuGet.Versioning;
using Serilog; using Serilog;
using System; using System;
using Velopack; using Velopack;
using Velopack.Sources;
namespace WorldClockStatusWindow; namespace WorldClockStatusWindow;
internal class Program internal class Program
{ {
private static UpdateManager _updateManager;
[STAThread] [STAThread]
public static void Main(string[] args) public static void Main(string[] args)
{ {
@@ -24,4 +28,8 @@ internal class Program
Log.Logger.Information("End"); Log.Logger.Information("End");
} }
public static UpdateManager UpdateManager => _updateManager ??= new UpdateManager(new GithubSource("https://github.com/ckaczor/WorldClockStatusWindow", null, false));
public static string LocalVersion => (UpdateManager.CurrentVersion ?? new SemanticVersion(0, 0, 0)).ToString();
} }

View File

@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <auto-generated> // <auto-generated>
// This code was generated by a tool. // This code was generated by a tool.
// Runtime Version:4.0.30319.34014 // Runtime Version:4.0.30319.42000
// //
// Changes to this file may cause incorrect behavior and will be lost if // Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated. // the code is regenerated.
@@ -19,10 +19,10 @@ namespace WorldClockStatusWindow.Properties {
// class via a tool like ResGen or Visual Studio. // class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen // To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project. // with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources { public class Resources {
private static global::System.Resources.ResourceManager resourceMan; private static global::System.Resources.ResourceManager resourceMan;
@@ -36,7 +36,7 @@ namespace WorldClockStatusWindow.Properties {
/// Returns the cached ResourceManager instance used by this class. /// Returns the cached ResourceManager instance used by this class.
/// </summary> /// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager { public static global::System.Resources.ResourceManager ResourceManager {
get { get {
if (object.ReferenceEquals(resourceMan, null)) { if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WorldClockStatusWindow.Properties.Resources", typeof(Resources).Assembly); global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WorldClockStatusWindow.Properties.Resources", typeof(Resources).Assembly);
@@ -51,7 +51,7 @@ namespace WorldClockStatusWindow.Properties {
/// resource lookups using this strongly typed resource class. /// resource lookups using this strongly typed resource class.
/// </summary> /// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture { public static global::System.Globalization.CultureInfo Culture {
get { get {
return resourceCulture; return resourceCulture;
} }
@@ -63,11 +63,83 @@ namespace WorldClockStatusWindow.Properties {
/// <summary> /// <summary>
/// Looks up a localized resource of type System.Drawing.Icon similar to (Icon). /// Looks up a localized resource of type System.Drawing.Icon similar to (Icon).
/// </summary> /// </summary>
internal static System.Drawing.Icon ApplicationIcon { public static System.Drawing.Icon ApplicationIcon {
get { get {
object obj = ResourceManager.GetObject("ApplicationIcon", resourceCulture); object obj = ResourceManager.GetObject("ApplicationIcon", resourceCulture);
return ((System.Drawing.Icon)(obj)); return ((System.Drawing.Icon)(obj));
} }
} }
/// <summary>
/// Looks up a localized string similar to World Clock Status Window.
/// </summary>
public static string ApplicationName {
get {
return ResourceManager.GetString("ApplicationName", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to _Check for Update.
/// </summary>
public static string CheckUpdate {
get {
return ResourceManager.GetString("CheckUpdate", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Close.
/// </summary>
public static string CloseButtonText {
get {
return ResourceManager.GetString("CloseButtonText", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to About.
/// </summary>
public static string optionCategoryAbout {
get {
return ResourceManager.GetString("optionCategoryAbout", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to General.
/// </summary>
public static string optionCategoryGeneral {
get {
return ResourceManager.GetString("optionCategoryGeneral", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Settings.
/// </summary>
public static string SettingsTitle {
get {
return ResourceManager.GetString("SettingsTitle", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to _Start when Windows starts.
/// </summary>
public static string startWithWindowsCheckBox {
get {
return ResourceManager.GetString("startWithWindowsCheckBox", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Version {0}.
/// </summary>
public static string Version {
get {
return ResourceManager.GetString("Version", resourceCulture);
}
}
} }
} }

View File

@@ -121,4 +121,28 @@
<data name="ApplicationIcon" type="System.Resources.ResXFileRef, System.Windows.Forms"> <data name="ApplicationIcon" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\Application.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> <value>..\Resources\Application.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data> </data>
<data name="ApplicationName" xml:space="preserve">
<value>World Clock Status Window</value>
</data>
<data name="optionCategoryAbout" xml:space="preserve">
<value>About</value>
</data>
<data name="CheckUpdate" xml:space="preserve">
<value>_Check for Update</value>
</data>
<data name="startWithWindowsCheckBox" xml:space="preserve">
<value>_Start when Windows starts</value>
</data>
<data name="optionCategoryGeneral" xml:space="preserve">
<value>General</value>
</data>
<data name="SettingsTitle" xml:space="preserve">
<value>Settings</value>
</data>
<data name="CloseButtonText" xml:space="preserve">
<value>Close</value>
</data>
<data name="Version" xml:space="preserve">
<value>Version {0}</value>
</data>
</root> </root>

View File

@@ -0,0 +1,21 @@
<windows:CategoryPanelBase x:Class="WorldClockStatusWindow.SettingsWindow.AboutSettingsPanel"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:properties="clr-namespace:WorldClockStatusWindow.Properties"
xmlns:worldClockStatusWindow="clr-namespace:WorldClockStatusWindow"
xmlns:windows="clr-namespace:ChrisKaczor.Wpf.Windows;assembly=ChrisKaczor.Wpf.Windows.CategoryWindow"
mc:Ignorable="d"
d:DesignHeight="150"
d:DesignWidth="300">
<Grid>
<StackPanel windows:Spacing.Vertical="10">
<TextBlock Text="{x:Static properties:Resources.ApplicationName}"
FontWeight="Bold" />
<TextBlock Text="{Binding Source={x:Static worldClockStatusWindow:Program.LocalVersion}, StringFormat={x:Static properties:Resources.Version}}"
Name="VersionLabel" />
<TextBlock Text="Chris Kaczor" />
</StackPanel>
</Grid>
</windows:CategoryPanelBase>

View File

@@ -0,0 +1,12 @@
namespace WorldClockStatusWindow.SettingsWindow
{
public partial class AboutSettingsPanel
{
public AboutSettingsPanel()
{
InitializeComponent();
}
public override string CategoryName => Properties.Resources.optionCategoryAbout;
}
}

View File

@@ -0,0 +1,16 @@
<windows:CategoryPanelBase x:Class="WorldClockStatusWindow.SettingsWindow.GeneralSettingsPanel"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:properties="clr-namespace:WorldClockStatusWindow.Properties"
xmlns:windows="clr-namespace:ChrisKaczor.Wpf.Windows;assembly=ChrisKaczor.Wpf.Windows.CategoryWindow"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="300">
<StackPanel windows:Spacing.Vertical="10">
<CheckBox Content="{x:Static properties:Resources.startWithWindowsCheckBox}"
IsChecked="{Binding Source={x:Static properties:Settings.Default}, Path=AutoStart}"
Click="OnSaveSettings" />
</StackPanel>
</windows:CategoryPanelBase>

View File

@@ -0,0 +1,36 @@
using ChrisKaczor.Wpf.Application;
using System.Windows;
using WorldClockStatusWindow.Properties;
namespace WorldClockStatusWindow.SettingsWindow;
public partial class GeneralSettingsPanel
{
public GeneralSettingsPanel()
{
InitializeComponent();
}
public override string CategoryName => Properties.Resources.optionCategoryGeneral;
public override void LoadPanel(Window parentWindow)
{
base.LoadPanel(parentWindow);
MarkLoaded();
}
private void OnSaveSettings(object sender, RoutedEventArgs e)
{
SaveSettings();
}
private void SaveSettings()
{
if (!HasLoaded) return;
Settings.Default.Save();
Application.Current.SetStartWithWindows(Settings.Default.AutoStart);
}
}

View File

@@ -9,8 +9,8 @@ using System.Text.Json;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Timers; using System.Timers;
using System.Windows.Threading; using System.Windows.Threading;
using Velopack; using ChrisKaczor.Wpf.Windows;
using Velopack.Sources; using WorldClockStatusWindow.SettingsWindow;
namespace WorldClockStatusWindow; namespace WorldClockStatusWindow;
@@ -20,8 +20,6 @@ internal class WindowSource : IWindowSource, IDisposable
private readonly Timer _timer; private readonly Timer _timer;
private readonly Dispatcher _dispatcher; private readonly Dispatcher _dispatcher;
private readonly UpdateManager _updateManager;
private List<TimeZoneEntry> _timeZoneEntries; private List<TimeZoneEntry> _timeZoneEntries;
internal WindowSource() internal WindowSource()
@@ -31,8 +29,6 @@ internal class WindowSource : IWindowSource, IDisposable
_dispatcher = Dispatcher.CurrentDispatcher; _dispatcher = Dispatcher.CurrentDispatcher;
_updateManager = new UpdateManager(new GithubSource("https://github.com/ckaczor/WorldClockStatusWindow", null, false));
_timer = new Timer(1000); _timer = new Timer(1000);
Task.Factory.StartNew(UpdateApp).ContinueWith(task => Start(task.Result.Result)); Task.Factory.StartNew(UpdateApp).ContinueWith(task => Start(task.Result.Result));
@@ -42,14 +38,14 @@ internal class WindowSource : IWindowSource, IDisposable
{ {
try try
{ {
if (!_updateManager.IsInstalled) if (!Program.UpdateManager.IsInstalled)
return false; return false;
Log.Logger.Information("Checking for update"); Log.Logger.Information("Checking for update");
await _dispatcher.InvokeAsync(() => _floatingStatusWindow.SetText("Checking for update...")); await _dispatcher.InvokeAsync(() => _floatingStatusWindow.SetText("Checking for update..."));
var newVersion = await _updateManager.CheckForUpdatesAsync(); var newVersion = await Program.UpdateManager.CheckForUpdatesAsync();
if (newVersion == null) if (newVersion == null)
return false; return false;
@@ -58,13 +54,13 @@ internal class WindowSource : IWindowSource, IDisposable
await _dispatcher.InvokeAsync(() => _floatingStatusWindow.SetText("Downloading update...")); await _dispatcher.InvokeAsync(() => _floatingStatusWindow.SetText("Downloading update..."));
await _updateManager.DownloadUpdatesAsync(newVersion); await Program.UpdateManager.DownloadUpdatesAsync(newVersion);
Log.Logger.Information("Installing update"); Log.Logger.Information("Installing update");
await _dispatcher.InvokeAsync(() => _floatingStatusWindow.SetText("Installing update...")); await _dispatcher.InvokeAsync(() => _floatingStatusWindow.SetText("Installing update..."));
_updateManager.ApplyUpdatesAndRestart(newVersion); Program.UpdateManager.ApplyUpdatesAndRestart(newVersion);
} }
catch (Exception e) catch (Exception e)
{ {
@@ -130,10 +126,6 @@ internal class WindowSource : IWindowSource, IDisposable
text.Append($"{timeZoneEntry.Label.PadLeft(labelLength)}: {TimeZoneInfo.ConvertTime(now, timeZone).ToString(Properties.Settings.Default.TimeFormat)}"); text.Append($"{timeZoneEntry.Label.PadLeft(labelLength)}: {TimeZoneInfo.ConvertTime(now, timeZone).ToString(Properties.Settings.Default.TimeFormat)}");
} }
text.AppendLine();
text.AppendLine();
text.Append(_updateManager.CurrentVersion);
_dispatcher.Invoke(() => _floatingStatusWindow.SetText(text.ToString())); _dispatcher.Invoke(() => _floatingStatusWindow.SetText(text.ToString()));
} }
@@ -163,6 +155,18 @@ internal class WindowSource : IWindowSource, IDisposable
public void ShowSettings() public void ShowSettings()
{ {
var categoryPanels = new List<CategoryPanelBase>
{
new GeneralSettingsPanel(),
new AboutSettingsPanel()
};
var settingsWindow = new CategoryWindow(categoryPanels, Properties.Resources.SettingsTitle, Properties.Resources.CloseButtonText);
var dialogResult = settingsWindow.ShowDialog();
if (!dialogResult.GetValueOrDefault(false))
return;
Save(); Save();
} }

View File

@@ -1,44 +1,56 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0-windows7.0</TargetFramework> <TargetFramework>net8.0-windows7.0</TargetFramework>
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<UseWPF>true</UseWPF> <UseWPF>true</UseWPF>
<ImportWindowsDesktopTargets>true</ImportWindowsDesktopTargets> <ImportWindowsDesktopTargets>true</ImportWindowsDesktopTargets>
<StartupObject>WorldClockStatusWindow.Program</StartupObject> <StartupObject>WorldClockStatusWindow.Program</StartupObject>
<ApplicationIcon>Resources\Application.ico</ApplicationIcon> <ApplicationIcon>Resources\Application.ico</ApplicationIcon>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<AppDesigner Include="Properties\" /> <AppDesigner Include="Properties\" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="Resources\Application.ico" /> <Content Include="Resources\Application.ico" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="ChrisKaczor.Wpf.Application.StartWithWindows" Version="1.0.5" /> <PackageReference Include="ChrisKaczor.Wpf.Application.StartWithWindows" Version="1.0.5" />
<PackageReference Include="ChrisKaczor.Wpf.Windows.FloatingStatusWindow" Version="2.0.0.5" /> <PackageReference Include="ChrisKaczor.Wpf.Windows.CategoryWindow" Version="1.0.2" />
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" /> <PackageReference Include="ChrisKaczor.Wpf.Windows.FloatingStatusWindow" Version="2.0.0.5" />
<PackageReference Include="Serilog" Version="4.0.1" /> <PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="Serilog.Extensions.Logging" Version="8.0.0" /> <PackageReference Include="Serilog" Version="4.0.2" />
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" /> <PackageReference Include="Serilog.Extensions.Logging" Version="8.0.0" />
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" /> <PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
<PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" /> <PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
<PackageReference Include="Velopack" Version="0.0.626" /> <PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" />
</ItemGroup> <PackageReference Include="Velopack" Version="0.0.626" />
<ItemGroup> </ItemGroup>
<Compile Update="Properties\Settings.Designer.cs"> <ItemGroup>
<DesignTimeSharedInput>True</DesignTimeSharedInput> <Compile Update="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen> <DesignTime>True</DesignTime>
<DependentUpon>Settings.settings</DependentUpon> <AutoGen>True</AutoGen>
</Compile> <DependentUpon>Resources.resx</DependentUpon>
</ItemGroup> </Compile>
<ItemGroup> <Compile Update="Properties\Settings.Designer.cs">
<None Update="Properties\Settings.settings"> <DesignTimeSharedInput>True</DesignTimeSharedInput>
<Generator>SettingsSingleFileGenerator</Generator> <AutoGen>True</AutoGen>
<LastGenOutput>Settings.Designer.cs</LastGenOutput> <DependentUpon>Settings.settings</DependentUpon>
</None> </Compile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include=".github\workflows\main.yml" /> <None Update="Properties\Settings.settings">
</ItemGroup> <Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
</ItemGroup>
<ItemGroup>
<None Include=".github\workflows\main.yml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Properties\Resources.resx">
<Generator>PublicResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
</Project> </Project>