Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion DesktopClock/DesktopClock.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.1" />
<PackageReference Include="Costura.Fody" Version="6.0.0" PrivateAssets="All" />
<PackageReference Include="H.NotifyIcon.Wpf" Version="2.4.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
Expand Down
33 changes: 21 additions & 12 deletions DesktopClock/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using DesktopClock.Properties;
using DesktopClock.Utilities;
using H.NotifyIcon;
Expand All @@ -22,8 +20,7 @@ namespace DesktopClock;
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
[ObservableObject]
public partial class MainWindow : Window
public partial class MainWindow : Window, INotifyPropertyChanged
{
private readonly SystemClockTimer _systemClockTimer;
private TaskbarIcon _trayIcon;
Expand All @@ -38,14 +35,32 @@ public partial class MainWindow : Window
private DesktopPinner _desktopPinner;
private readonly WheelNotches _wheelNotches = new();

#pragma warning disable CS0067 // The event 'MainWindow.PropertyChanged' is never used. Handled by Fody.
public event PropertyChangedEventHandler PropertyChanged;
#pragma warning restore CS0067

/// <summary>
/// The current date and time in the selected time zone, or the formatted countdown text.
/// </summary>
[ObservableProperty]
private string _currentTimeOrCountdownString;
public string CurrentTimeOrCountdownString { get; set; }

// The menu shared by the clock and the tray icon binds to these.
public ICommand CopyToClipboardCommand { get; }
public ICommand HideForNowCommand { get; }
public ICommand OpenSettingsWindowCommand { get; }
public ICommand OpenReleasesPageCommand { get; }
public ICommand OpenIssueTrackerCommand { get; }
public ICommand ExitCommand { get; }

public MainWindow()
{
CopyToClipboardCommand = new RelayCommand(CopyToClipboard);
HideForNowCommand = new RelayCommand(HideForNow);
OpenSettingsWindowCommand = new RelayCommand(OpenSettingsWindow);
OpenReleasesPageCommand = new RelayCommand(OpenReleasesPage);
OpenIssueTrackerCommand = new RelayCommand(OpenIssueTracker);
ExitCommand = new RelayCommand(Exit);

InitializeComponent();
DataContext = this;

Expand Down Expand Up @@ -144,7 +159,6 @@ private void ThemeManager_ThemeChanged(object sender, EventArgs e)
/// <summary>
/// Copies the current time string to the clipboard.
/// </summary>
[RelayCommand]
public void CopyToClipboard()
{
try
Expand All @@ -160,7 +174,6 @@ public void CopyToClipboard()
/// <summary>
/// Minimizes the window.
/// </summary>
[RelayCommand]
public void HideForNow()
{
this.HideFromScreen();
Expand Down Expand Up @@ -195,19 +208,16 @@ public void ShowClockAndSettings()
/// <summary>
/// Opens a new settings window or activates the existing one.
/// </summary>
[RelayCommand]
public void OpenSettingsWindow()
{
App.ShowSingletonWindow<SettingsWindow>();
}

[RelayCommand]
public void OpenReleasesPage()
{
OpenUrl("https://github.com/danielchalmers/DesktopClock/releases");
}

[RelayCommand]
public void OpenIssueTracker()
{
OpenUrl("https://github.com/danielchalmers/DesktopClock/issues");
Expand All @@ -216,7 +226,6 @@ public void OpenIssueTracker()
/// <summary>
/// Closes the app.
/// </summary>
[RelayCommand]
public void Exit()
{
Application.Current.Shutdown();
Expand Down
6 changes: 0 additions & 6 deletions DesktopClock/SettingsWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -671,12 +671,6 @@
Style="{StaticResource CardGroupBox}">
<StackPanel Style="{StaticResource CardBodyPanel}">
<StackPanel>
<TextBlock>
<Hyperlink NavigateUri="https://github.com/CommunityToolkit/dotnet"
RequestNavigate="Hyperlink_RequestNavigate">
CommunityToolkit
</Hyperlink>
</TextBlock>
<TextBlock>
<Hyperlink NavigateUri="https://github.com/Fody/Costura"
RequestNavigate="Hyperlink_RequestNavigate">
Expand Down
20 changes: 14 additions & 6 deletions DesktopClock/SettingsWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,9 @@
using System.Windows;
using System.Windows.Automation;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Navigation;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using DesktopClock.Properties;
using Microsoft.Win32;

Expand Down Expand Up @@ -335,8 +334,13 @@ public static class NavButton
public static void SetIsActive(DependencyObject obj, bool value) => obj.SetValue(IsActiveProperty, value);
}

public partial class SettingsWindowViewModel : ObservableObject
public sealed class SettingsWindowViewModel : INotifyPropertyChanged
{
// Nothing here changes after it's created, but bindings to an object without this event fall back to PropertyDescriptor change tracking, which is slower and can keep the object alive after the window closes.
#pragma warning disable CS0067 // The event 'SettingsWindowViewModel.PropertyChanged' is never used.
public event PropertyChangedEventHandler PropertyChanged;
#pragma warning restore CS0067

// Enumerating fonts and time zones costs ~100 ms and the results don't change within a session, so they're fetched once on a background thread that the app kicks off while idle after startup.
private static readonly Lazy<Task<(IList<string> Fonts, IList<TimeZoneInfo> TimeZones)>> _systemLists =
new(() => Task.Run(() => (
Expand All @@ -350,9 +354,16 @@ public partial class SettingsWindowViewModel : ObservableObject
/// </summary>
public string AppVersion { get; }

public ICommand ResetWavFilePathCommand { get; }
public ICommand ResetWavFileIntervalCommand { get; }
public ICommand ResetBackgroundImagePathCommand { get; }

public SettingsWindowViewModel(Settings settings)
{
Settings = settings;
ResetWavFilePathCommand = new RelayCommand(ResetWavFilePath);
ResetWavFileIntervalCommand = new RelayCommand(ResetWavFileInterval);
ResetBackgroundImagePathCommand = new RelayCommand(ResetBackgroundImagePath);
AppVersion = FileVersionInfo.GetVersionInfo(App.MainFileInfo.FullName).FileVersion;
FontStyles =
[
Expand Down Expand Up @@ -450,7 +461,6 @@ public IList<string> FontFamilies
/// <summary>
/// Clears the chime sound file path.
/// </summary>
[RelayCommand]
public void ResetWavFilePath()
{
Settings.WavFilePath = string.Empty;
Expand All @@ -459,7 +469,6 @@ public void ResetWavFilePath()
/// <summary>
/// Resets the chime interval to the default value.
/// </summary>
[RelayCommand]
public void ResetWavFileInterval()
{
Settings.WavFileInterval = default;
Expand All @@ -468,7 +477,6 @@ public void ResetWavFileInterval()
/// <summary>
/// Clears the background image path.
/// </summary>
[RelayCommand]
public void ResetBackgroundImagePath()
{
Settings.BackgroundImagePath = string.Empty;
Expand Down
17 changes: 17 additions & 0 deletions DesktopClock/Utilities/RelayCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System;
using System.Windows.Input;

namespace DesktopClock;

/// <summary>
/// A command that runs an action, for binding menu items and buttons to methods.
/// </summary>
public sealed class RelayCommand(Action execute) : ICommand
{
// The commands can always run, so there's never a change to report.
public event EventHandler CanExecuteChanged { add { } remove { } }

public bool CanExecute(object parameter) => true;

public void Execute(object parameter) => execute();
}