From 02c991b8e7c529169ebab490f0037173ab886af9 Mon Sep 17 00:00:00 2001 From: Tom Bayley Date: Wed, 28 Aug 2024 14:20:55 +0100 Subject: [PATCH] Add option to show popup when changing brightness/temperature --- NightGlow/App.config | 3 + NightGlow/App.xaml | 7 + NightGlow/App.xaml.cs | 2 + NightGlow/Assets/popup-brightness.svg | 12 ++ NightGlow/Assets/popup-temperature.svg | 12 ++ NightGlow/NightGlow.csproj | 5 + NightGlow/Properties/Settings.Designer.cs | 14 +- NightGlow/Properties/Settings.settings | 3 + NightGlow/Services/NightGlowService.cs | 13 +- NightGlow/Services/SettingsService.cs | 11 ++ NightGlow/ViewModels/NotifyIconViewModel.cs | 5 +- NightGlow/ViewModels/PopupViewModel.cs | 21 +++ .../Views/Controls/PopupDisplayInfoView.xaml | 61 ++++++++ .../Controls/PopupDisplayInfoView.xaml.cs | 40 ++++++ NightGlow/Views/PopupWindow.xaml | 73 ++++++++++ NightGlow/Views/PopupWindow.xaml.cs | 136 ++++++++++++++++++ NightGlow/Views/SettingsGeneralView.xaml | 7 + 17 files changed, 422 insertions(+), 3 deletions(-) create mode 100644 NightGlow/Assets/popup-brightness.svg create mode 100644 NightGlow/Assets/popup-temperature.svg create mode 100644 NightGlow/ViewModels/PopupViewModel.cs create mode 100644 NightGlow/Views/Controls/PopupDisplayInfoView.xaml create mode 100644 NightGlow/Views/Controls/PopupDisplayInfoView.xaml.cs create mode 100644 NightGlow/Views/PopupWindow.xaml create mode 100644 NightGlow/Views/PopupWindow.xaml.cs diff --git a/NightGlow/App.config b/NightGlow/App.config index a2985f4..c8c160e 100644 --- a/NightGlow/App.config +++ b/NightGlow/App.config @@ -52,6 +52,9 @@ + + False + \ No newline at end of file diff --git a/NightGlow/App.xaml b/NightGlow/App.xaml index 7587f70..bd19b08 100644 --- a/NightGlow/App.xaml +++ b/NightGlow/App.xaml @@ -29,6 +29,13 @@ + + + + + + + + + + \ No newline at end of file diff --git a/NightGlow/Assets/popup-temperature.svg b/NightGlow/Assets/popup-temperature.svg new file mode 100644 index 0000000..fa291e5 --- /dev/null +++ b/NightGlow/Assets/popup-temperature.svg @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/NightGlow/NightGlow.csproj b/NightGlow/NightGlow.csproj index bc95177..8e5ff29 100644 --- a/NightGlow/NightGlow.csproj +++ b/NightGlow/NightGlow.csproj @@ -12,6 +12,8 @@ + + @@ -21,11 +23,14 @@ + + + diff --git a/NightGlow/Properties/Settings.Designer.cs b/NightGlow/Properties/Settings.Designer.cs index ddcac2f..b938c6a 100644 --- a/NightGlow/Properties/Settings.Designer.cs +++ b/NightGlow/Properties/Settings.Designer.cs @@ -12,7 +12,7 @@ namespace NightGlow.Properties { [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.7.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.10.0.0")] internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); @@ -202,5 +202,17 @@ public string DdcConfigJson { this["DdcConfigJson"] = value; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool ShowBrightTempPopup { + get { + return ((bool)(this["ShowBrightTempPopup"])); + } + set { + this["ShowBrightTempPopup"] = value; + } + } } } diff --git a/NightGlow/Properties/Settings.settings b/NightGlow/Properties/Settings.settings index 52d1689..924803a 100644 --- a/NightGlow/Properties/Settings.settings +++ b/NightGlow/Properties/Settings.settings @@ -47,5 +47,8 @@ + + False + \ No newline at end of file diff --git a/NightGlow/Services/NightGlowService.cs b/NightGlow/Services/NightGlowService.cs index 737c287..abb272a 100644 --- a/NightGlow/Services/NightGlowService.cs +++ b/NightGlow/Services/NightGlowService.cs @@ -9,6 +9,8 @@ using System.Linq; using System.Reactive.Disposables; using System.Threading.Tasks; +using NightGlow.Views; +using Microsoft.Extensions.DependencyInjection; namespace NightGlow.Services; @@ -21,6 +23,8 @@ public class NightGlowService : ObservableObject, IDisposable private readonly GammaService _gammaService; private readonly DdcService _ddcService; + private readonly IServiceProvider _serviceProvider; + private readonly IDisposable _eventRegistration; public double Brightness @@ -41,13 +45,15 @@ public NightGlowService( SettingsService settingsService, HotKeyService hotKeyService, GammaService gammaService, - DdcService ddcService + DdcService ddcService, + IServiceProvider serviceProvider ) { _settingsService = settingsService; _hotKeyService = hotKeyService; _gammaService = gammaService; _ddcService = ddcService; + _serviceProvider = serviceProvider; RegisterHotKeys(); @@ -184,6 +190,11 @@ private void ChangeConfig(double brightnessOffset, int temperatureOffset) OnPropertyChanged(nameof(Temperature)); UpdateConfiguration(); + + if (_settingsService.ShowBrightTempPopup) + { + _serviceProvider.GetRequiredService().ShowPopup(); + } } // Using the brightness value, check wheter to use ddc/gamma to set the brightness diff --git a/NightGlow/Services/SettingsService.cs b/NightGlow/Services/SettingsService.cs index 9fc9e05..436fa82 100644 --- a/NightGlow/Services/SettingsService.cs +++ b/NightGlow/Services/SettingsService.cs @@ -37,6 +37,17 @@ public bool ExtendedGammaRange set => _extendedGammaRange.Set = value; } + public bool ShowBrightTempPopup + { + get => Settings.Default.ShowBrightTempPopup; + set + { + Settings.Default.ShowBrightTempPopup = value; + Settings.Default.Save(); + OnPropertyChanged(nameof(ShowBrightTempPopup)); + } + } + public bool FirstLaunch { get => Settings.Default.FirstLaunch; diff --git a/NightGlow/ViewModels/NotifyIconViewModel.cs b/NightGlow/ViewModels/NotifyIconViewModel.cs index 5356b8d..4b80a2a 100644 --- a/NightGlow/ViewModels/NotifyIconViewModel.cs +++ b/NightGlow/ViewModels/NotifyIconViewModel.cs @@ -35,7 +35,10 @@ NightGlowService nightGlowService public void ShowWindow() { - Application.Current.MainWindow ??= _serviceProvider.GetRequiredService(); + if (!(Application.Current.MainWindow is MainWindow)) + { + Application.Current.MainWindow = _serviceProvider.GetRequiredService(); + } Application.Current.MainWindow.Show(); Application.Current.MainWindow.Activate(); } diff --git a/NightGlow/ViewModels/PopupViewModel.cs b/NightGlow/ViewModels/PopupViewModel.cs new file mode 100644 index 0000000..add5e81 --- /dev/null +++ b/NightGlow/ViewModels/PopupViewModel.cs @@ -0,0 +1,21 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using NightGlow.Services; + +namespace NightGlow.ViewModels; + +public partial class PopupViewModel : ObservableObject +{ + + private readonly SettingsService _settingsService; + private readonly NightGlowService _nightGlowService; + + public SettingsService SettingsService { get => _settingsService; } + public NightGlowService NightGlowService { get => _nightGlowService; } + + public PopupViewModel(SettingsService settingsService, NightGlowService nightGlowService) + { + _settingsService = settingsService; + _nightGlowService = nightGlowService; + } + +} diff --git a/NightGlow/Views/Controls/PopupDisplayInfoView.xaml b/NightGlow/Views/Controls/PopupDisplayInfoView.xaml new file mode 100644 index 0000000..be01ac5 --- /dev/null +++ b/NightGlow/Views/Controls/PopupDisplayInfoView.xaml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/NightGlow/Views/Controls/PopupDisplayInfoView.xaml.cs b/NightGlow/Views/Controls/PopupDisplayInfoView.xaml.cs new file mode 100644 index 0000000..e94e662 --- /dev/null +++ b/NightGlow/Views/Controls/PopupDisplayInfoView.xaml.cs @@ -0,0 +1,40 @@ +using System.Windows; +using System.Windows.Controls; + +namespace NightGlow.Views.Controls; + +public partial class PopupDisplayInfoView : UserControl +{ + + public static readonly DependencyProperty SliderValueProperty = DependencyProperty.Register(nameof(SliderValue), typeof(double), typeof(PopupDisplayInfoView), null); + + public double SliderValue + { + get => (double)GetValue(SliderValueProperty); + set => SetValue(SliderValueProperty, value); + } + + public static readonly DependencyProperty SliderValueMinProperty = DependencyProperty.Register(nameof(SliderValueMin), typeof(double), typeof(PopupDisplayInfoView), null); + + public double SliderValueMin + { + get => (double)GetValue(SliderValueMinProperty); + set => SetValue(SliderValueMinProperty, value); + } + + public static readonly DependencyProperty SliderValueMaxProperty = DependencyProperty.Register(nameof(SliderValueMax), typeof(double), typeof(PopupDisplayInfoView), null); + + public double SliderValueMax + { + get => (double)GetValue(SliderValueMaxProperty); + set => SetValue(SliderValueMaxProperty, value); + } + + public string Icon { get; set; } + + public PopupDisplayInfoView() + { + InitializeComponent(); + } + +} diff --git a/NightGlow/Views/PopupWindow.xaml b/NightGlow/Views/PopupWindow.xaml new file mode 100644 index 0000000..4618fd7 --- /dev/null +++ b/NightGlow/Views/PopupWindow.xaml @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/NightGlow/Views/PopupWindow.xaml.cs b/NightGlow/Views/PopupWindow.xaml.cs new file mode 100644 index 0000000..1a379b2 --- /dev/null +++ b/NightGlow/Views/PopupWindow.xaml.cs @@ -0,0 +1,136 @@ +using NightGlow.ViewModels; +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Windows; +using System.Windows.Interop; +using System.Windows.Media; +using System.Windows.Media.Animation; +using System.Windows.Threading; + +namespace NightGlow.Views; + +public partial class PopupWindow : Window +{ + + private const double ANIM_TIME = 0.3; + private const double DISPLAY_TIME = 2; + private const int BOTTOM_OFFSET = 16; // Offest above the taskbar / bottom of screen + + private DispatcherTimer hideTimer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(DISPLAY_TIME) }; + + private DoubleAnimation _slideDownAnimation; + private EventHandler _slideDownCompleteHandler; + + private STATE state = STATE.HIDDEN; + + private enum STATE + { + HIDDEN = 1, + APPEARING = 2, + ACTIVE = 3, + HIDING = 4 + } + + public PopupWindow(PopupViewModel viewModel) + { + DataContext = viewModel; + InitializeComponent(); + + hideTimer.Tick += (s, args) => + { + hideTimer.Stop(); + AnimateOut(); + }; + + this.Loaded += Window_Loaded; + } + + public void ShowPopup() + { + switch (state) + { + case STATE.HIDDEN: + Debug.WriteLine("Show()"); + Show(); + AnimateIn(); + break; + case STATE.APPEARING: + case STATE.ACTIVE: + ResetHideTimer(); + break; + case STATE.HIDING: + _slideDownAnimation.Completed -= _slideDownCompleteHandler; + AnimateIn(); + break; + } + } + + private void ResetHideTimer() + { + hideTimer.Interval = TimeSpan.FromSeconds(DISPLAY_TIME); + } + + private void AnimateIn() + { + state = STATE.APPEARING; + ResetHideTimer(); + + var workArea = SystemParameters.WorkArea; + this.Left = (workArea.Width - this.Width) / 2; + this.Top = workArea.Bottom - this.Height - BOTTOM_OFFSET; + + var slideAnimation = new DoubleAnimation + { + From = this.ActualHeight, + To = 0, + Duration = TimeSpan.FromSeconds(ANIM_TIME), + EasingFunction = new CircleEase { EasingMode = EasingMode.EaseOut } + }; + slideAnimation.Completed += (s, args) => state = STATE.ACTIVE; + AnimatedContainerTransform.BeginAnimation(TranslateTransform.YProperty, slideAnimation); + + hideTimer.Start(); + } + + private void AnimateOut() + { + state = STATE.HIDING; + + _slideDownAnimation = new DoubleAnimation + { + From = 0, + To = this.ActualHeight, + Duration = TimeSpan.FromSeconds(ANIM_TIME), + EasingFunction = new CircleEase { EasingMode = EasingMode.EaseIn } + }; + _slideDownCompleteHandler = (s, args) => HideNow(); + _slideDownAnimation.Completed += _slideDownCompleteHandler; + AnimatedContainerTransform.BeginAnimation(TranslateTransform.YProperty, _slideDownAnimation); + } + + private void HideNow() + { + state = STATE.HIDDEN; + this.Hide(); + } + + private const int GWL_EX_STYLE = -20, WS_EX_APPWINDOW = 0x00040000, WS_EX_TOOLWINDOW = 0x00000080, WS_EX_NOACTIVATE = 0x08000000; + + [DllImport("user32.dll", SetLastError = true)] + static extern int GetWindowLong(IntPtr hWnd, int nIndex); + + [DllImport("user32.dll")] + static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong); + + private void Window_Loaded(object sender, RoutedEventArgs e) + { + var helper = new WindowInteropHelper(this).Handle; + int currentStyle = GetWindowLong(helper, GWL_EX_STYLE); + // Hide from Alt + Tab (WS_EX_TOOLWINDOW & WS_EX_APPWINDOW) + // Prevent Window from taking focus when showing (WS_EX_NOACTIVATE) + int newStyle = (currentStyle | WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE) & ~WS_EX_APPWINDOW; + SetWindowLong(helper, GWL_EX_STYLE, newStyle); + } + +} diff --git a/NightGlow/Views/SettingsGeneralView.xaml b/NightGlow/Views/SettingsGeneralView.xaml index f6cf8bf..b34fa20 100644 --- a/NightGlow/Views/SettingsGeneralView.xaml +++ b/NightGlow/Views/SettingsGeneralView.xaml @@ -26,6 +26,13 @@ Margin="0,0,0,10" /> + +