mirror of
https://github.com/ckaczor/WorkIndicator.git
synced 2026-01-13 17:23:18 -05:00
WIP - microphone in use detection
This commit is contained in:
92
AudioWatcher.cs
Normal file
92
AudioWatcher.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
using CSCore.CoreAudioAPI;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
|
||||
namespace WorkIndicator
|
||||
{
|
||||
public static class AudioWatcher
|
||||
{
|
||||
public delegate void MicrophoneInUseChangedDelegate(bool microphoneInUse);
|
||||
|
||||
private static ManualResetEvent _manualResetEvent;
|
||||
|
||||
private static int _activeSessionCount;
|
||||
|
||||
public static event MicrophoneInUseChangedDelegate MicrophoneInUseChanged;
|
||||
|
||||
public static void Start()
|
||||
{
|
||||
_manualResetEvent = new ManualResetEvent(false);
|
||||
|
||||
var thread = new Thread(delegate ()
|
||||
{
|
||||
var deviceEnumerator = new MMDeviceEnumerator();
|
||||
|
||||
foreach (var device in deviceEnumerator.EnumAudioEndpoints(DataFlow.Capture, DeviceState.Active))
|
||||
{
|
||||
var sessionManager = AudioSessionManager2.FromMMDevice(device);
|
||||
|
||||
var sessionEnumerator = sessionManager.GetSessionEnumerator();
|
||||
|
||||
sessionManager.SessionCreated += HandleAudioSessionCreated;
|
||||
|
||||
foreach (var audioSessionControl in sessionEnumerator)
|
||||
{
|
||||
HandleAudioStateChanged(audioSessionControl, new AudioSessionStateChangedEventArgs(audioSessionControl.SessionState));
|
||||
|
||||
audioSessionControl.StateChanged += HandleAudioStateChanged;
|
||||
}
|
||||
}
|
||||
|
||||
_manualResetEvent.WaitOne();
|
||||
});
|
||||
|
||||
thread.SetApartmentState(ApartmentState.MTA);
|
||||
thread.Start();
|
||||
}
|
||||
|
||||
public static void Stop()
|
||||
{
|
||||
_manualResetEvent?.Set();
|
||||
}
|
||||
|
||||
private static void HandleAudioSessionCreated(object sender, SessionCreatedEventArgs e)
|
||||
{
|
||||
HandleAudioStateChanged(null, new AudioSessionStateChangedEventArgs(e.NewSession.SessionState));
|
||||
|
||||
e.NewSession.StateChanged += HandleAudioStateChanged;
|
||||
}
|
||||
|
||||
private static void HandleAudioStateChanged(object sender, AudioSessionStateChangedEventArgs e)
|
||||
{
|
||||
Debug.WriteLine($"{e.NewState}");
|
||||
|
||||
switch (e.NewState)
|
||||
{
|
||||
case AudioSessionState.AudioSessionStateActive:
|
||||
_activeSessionCount++;
|
||||
break;
|
||||
case AudioSessionState.AudioSessionStateInactive:
|
||||
_activeSessionCount--;
|
||||
break;
|
||||
case AudioSessionState.AudioSessionStateExpired:
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
if (_activeSessionCount < 0)
|
||||
_activeSessionCount = 0;
|
||||
|
||||
Debug.WriteLine($"{_activeSessionCount}");
|
||||
|
||||
MicrophoneInUseChanged?.Invoke(MicrophoneInUse());
|
||||
}
|
||||
|
||||
public static bool MicrophoneInUse()
|
||||
{
|
||||
return _activeSessionCount > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -154,7 +154,7 @@ namespace WorkIndicator.Delcom
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!_deviceHandle.IsClosed)
|
||||
if (_deviceHandle != null && !_deviceHandle.IsClosed)
|
||||
_deviceHandle.Close();
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
using Common.Extensions;
|
||||
using Common.Extensions;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace WorkIndicator.Delcom
|
||||
{
|
||||
@@ -80,6 +80,8 @@ namespace WorkIndicator.Delcom
|
||||
_yellow = yellow;
|
||||
_green = green;
|
||||
|
||||
Debug.WriteLine($"Red: {_red}, Yellow: {_yellow}, Green: {_green}");
|
||||
|
||||
port1 = port1.SetBitValue((int) Light.Green, green == LightState.Off);
|
||||
port1 = port1.SetBitValue((int) Light.Yellow, yellow == LightState.Off);
|
||||
port1 = port1.SetBitValue((int) Light.Red, red == LightState.Off);
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
using Common.Native;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System;
|
||||
using WorkIndicator.Delcom;
|
||||
|
||||
namespace WorkIndicator
|
||||
@@ -18,46 +14,32 @@ namespace WorkIndicator
|
||||
|
||||
public static class LightController
|
||||
{
|
||||
private static WindowPatterns _windowPatterns;
|
||||
private static StoplightIndicator _stoplightIndicator;
|
||||
private static bool _initialized;
|
||||
private static Status _status = Status.Auto;
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
WindowPatterns.Changed += HandleWindowPatternsChanged;
|
||||
|
||||
_stoplightIndicator = new StoplightIndicator();
|
||||
_stoplightIndicator.SetLight(StoplightIndicator.Light.Green, StoplightIndicator.LightState.On);
|
||||
_stoplightIndicator.SetLight(StoplightIndicator.Light.Yellow, StoplightIndicator.LightState.On);
|
||||
|
||||
LoadPatterns();
|
||||
AudioWatcher.MicrophoneInUseChanged += AudioWatcher_MicrophoneInUseChanged;
|
||||
AudioWatcher.Start();
|
||||
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
private static void LoadPatterns()
|
||||
private static void AudioWatcher_MicrophoneInUseChanged(bool microphoneInUse)
|
||||
{
|
||||
_windowPatterns = WindowPatterns.Load();
|
||||
|
||||
if (_initialized)
|
||||
TerminateWindowDetection();
|
||||
|
||||
InitializeWindowDetection();
|
||||
|
||||
UpdateLights();
|
||||
}
|
||||
|
||||
private static void HandleWindowPatternsChanged(object sender, EventArgs e)
|
||||
{
|
||||
LoadPatterns();
|
||||
}
|
||||
|
||||
public static void Dispose()
|
||||
{
|
||||
if (!_initialized)
|
||||
return;
|
||||
|
||||
TerminateWindowDetection();
|
||||
AudioWatcher.Stop();
|
||||
|
||||
_stoplightIndicator.SetLights(StoplightIndicator.LightState.Off, StoplightIndicator.LightState.Off, StoplightIndicator.LightState.Off);
|
||||
_stoplightIndicator.Dispose();
|
||||
@@ -83,13 +65,13 @@ namespace WorkIndicator
|
||||
|
||||
if (_status == Status.Auto)
|
||||
{
|
||||
if (WindowHandles.Count > 0)
|
||||
if (AudioWatcher.MicrophoneInUse())
|
||||
{
|
||||
yellow = StoplightIndicator.LightState.On;
|
||||
red = StoplightIndicator.LightState.On;
|
||||
}
|
||||
else
|
||||
{
|
||||
green = StoplightIndicator.LightState.On;
|
||||
yellow = StoplightIndicator.LightState.On;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -115,87 +97,5 @@ namespace WorkIndicator
|
||||
|
||||
_stoplightIndicator.SetLights(red, yellow, green);
|
||||
}
|
||||
|
||||
#region Window detection
|
||||
|
||||
private static readonly WinEvent.WinEventDelegate ProcDelegate = WinEventProc;
|
||||
|
||||
private static readonly List<IntPtr> WindowEventHooks = new List<IntPtr>();
|
||||
private static readonly List<IntPtr> WindowHandles = new List<IntPtr>();
|
||||
|
||||
private static readonly List<Regex> WindowMatchRegexList = new List<Regex>();
|
||||
|
||||
private static string WildcardToRegexPattern(string value)
|
||||
{
|
||||
return "^" + Regex.Escape(value).Replace("\\?", ".").Replace("\\*", ".*") + "$";
|
||||
}
|
||||
|
||||
private static void InitializeWindowDetection()
|
||||
{
|
||||
foreach (var windowPattern in _windowPatterns.Where(w => w.Enabled))
|
||||
WindowMatchRegexList.Add(new Regex(WildcardToRegexPattern(windowPattern.Pattern)));
|
||||
|
||||
Functions.User32.EnumWindows(EnumWindowProc, IntPtr.Zero);
|
||||
|
||||
IntPtr hook = WinEvent.SetWinEventHook(WinEvent.Event.ObjectCreate, WinEvent.Event.ObjectDestroy, IntPtr.Zero, ProcDelegate, 0, 0, WinEvent.SetWinEventHookFlags.OutOfContext | WinEvent.SetWinEventHookFlags.SkipOwnProcess);
|
||||
if (hook != IntPtr.Zero)
|
||||
WindowEventHooks.Add(hook);
|
||||
|
||||
hook = WinEvent.SetWinEventHook(WinEvent.Event.ObjectNameChange, WinEvent.Event.ObjectNameChange, IntPtr.Zero, ProcDelegate, 0, 0, WinEvent.SetWinEventHookFlags.OutOfContext | WinEvent.SetWinEventHookFlags.SkipOwnProcess);
|
||||
if (hook != IntPtr.Zero)
|
||||
WindowEventHooks.Add(hook);
|
||||
}
|
||||
|
||||
private static void TerminateWindowDetection()
|
||||
{
|
||||
WindowEventHooks.ForEach(h => WinEvent.UnhookWinEvent(h));
|
||||
|
||||
WindowMatchRegexList.Clear();
|
||||
|
||||
WindowHandles.Clear();
|
||||
}
|
||||
|
||||
private static bool EnumWindowProc(IntPtr hWnd, IntPtr lParam)
|
||||
{
|
||||
WinEventProc(IntPtr.Zero, WinEvent.Event.ObjectCreate, hWnd, WinEvent.ObjectIdentifier.Window, 0, 0, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void WinEventProc(IntPtr hWinEventHook, WinEvent.Event eventType, IntPtr hwnd, WinEvent.ObjectIdentifier idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
|
||||
{
|
||||
if (idObject == WinEvent.ObjectIdentifier.Window && idChild == (int) WinEvent.ChildIdentifier.Self)
|
||||
{
|
||||
switch (eventType)
|
||||
{
|
||||
case WinEvent.Event.ObjectCreate:
|
||||
case WinEvent.Event.ObjectNameChange:
|
||||
|
||||
if (WindowHandles.Contains(hwnd))
|
||||
WindowHandles.Remove(hwnd);
|
||||
|
||||
foreach (var regex in WindowMatchRegexList)
|
||||
{
|
||||
if (regex.IsMatch(Functions.Window.GetText(hwnd)))
|
||||
{
|
||||
WindowHandles.Add(hwnd);
|
||||
UpdateLights();
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case WinEvent.Event.ObjectDestroy:
|
||||
if (WindowHandles.Contains(hwnd))
|
||||
{
|
||||
WindowHandles.Remove(hwnd);
|
||||
UpdateLights();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
<Window x:Class="WorkIndicator.Options.WindowPatternWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
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:properties="clr-namespace:WorkIndicator.Properties"
|
||||
mc:Ignorable="d"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
Title="WindowPatternWindow"
|
||||
Height="160"
|
||||
Width="350"
|
||||
FocusManager.FocusedElement="{Binding ElementName=NameTextBox}">
|
||||
<Grid>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Content="{x:Static properties:Resources.WindowPatternNameLabel}"
|
||||
VerticalContentAlignment="Center"
|
||||
Target="{Binding ElementName=NameTextBox}"
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Margin="6"
|
||||
Padding="0" />
|
||||
<TextBox Name="NameTextBox"
|
||||
Grid.Column="1"
|
||||
Text="{Binding Path=Name, UpdateSourceTrigger=Explicit, ValidatesOnExceptions=true}"
|
||||
Grid.Row="0"
|
||||
VerticalAlignment="Center"
|
||||
Margin="6,0,6,0" />
|
||||
|
||||
<Label Content="{x:Static properties:Resources.WindowPatternPatternLabel}"
|
||||
VerticalContentAlignment="Center"
|
||||
Target="{Binding ElementName=PatternTextBox}"
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Margin="6"
|
||||
Padding="0" />
|
||||
<TextBox Name="PatternTextBox"
|
||||
Grid.Column="1"
|
||||
Text="{Binding Path=Pattern, UpdateSourceTrigger=Explicit, ValidatesOnExceptions=true}"
|
||||
Grid.Row="1"
|
||||
VerticalAlignment="Center"
|
||||
Margin="6,0,6,0" />
|
||||
|
||||
|
||||
<Label Content="{x:Static properties:Resources.WindowPatternEnabledLabel}"
|
||||
VerticalContentAlignment="Center"
|
||||
Target="{Binding ElementName=NameTextBox}"
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Margin="6"
|
||||
Padding="0" />
|
||||
<CheckBox Grid.Column="1"
|
||||
IsChecked="{Binding Path=Enabled, UpdateSourceTrigger=Explicit, ValidatesOnExceptions=true}"
|
||||
Grid.Row="2"
|
||||
Margin="5,0,5,0"
|
||||
VerticalAlignment="Center" />
|
||||
<StackPanel Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Grid.Row="3"
|
||||
Orientation="Horizontal"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="6">
|
||||
<Button Content="{x:Static properties:Resources.OkayButton}"
|
||||
Height="23"
|
||||
VerticalAlignment="Bottom"
|
||||
Width="75"
|
||||
IsDefault="True"
|
||||
Click="HandleOkayButtonClick"
|
||||
Margin="0,0,8,0" />
|
||||
<Button Content="{x:Static properties:Resources.CancelButton}"
|
||||
Height="23"
|
||||
VerticalAlignment="Bottom"
|
||||
Width="75"
|
||||
IsCancel="True" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -1,66 +0,0 @@
|
||||
using Common.Wpf.Extensions;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace WorkIndicator.Options
|
||||
{
|
||||
public partial class WindowPatternWindow
|
||||
{
|
||||
public WindowPatternWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
Icon = ((Icon)Properties.Resources.ResourceManager.GetObject("ApplicationIcon")).ToImageSource();
|
||||
}
|
||||
|
||||
public bool? Display(WindowPattern windowPattern, Window owner)
|
||||
{
|
||||
// Set the data context
|
||||
DataContext = windowPattern;
|
||||
|
||||
// Set the title based on the state of the item
|
||||
Title = string.IsNullOrWhiteSpace(windowPattern.Name) ? Properties.Resources.WindowPatternWindowAdd : Properties.Resources.WindowPatternWindowEdit;
|
||||
|
||||
// Set the window owner
|
||||
Owner = owner;
|
||||
|
||||
// Show the dialog and result the result
|
||||
return ShowDialog();
|
||||
}
|
||||
|
||||
private void HandleOkayButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Get a list of all framework elements and explicit binding expressions
|
||||
var bindingExpressions = this.GetBindingExpressions(new[] { UpdateSourceTrigger.Explicit });
|
||||
|
||||
// Loop over each binding expression and clear any existing error
|
||||
this.ClearAllValidationErrors(bindingExpressions);
|
||||
|
||||
// Force all explicit bindings to update the source
|
||||
this.UpdateAllSources(bindingExpressions);
|
||||
|
||||
// See if there are any errors
|
||||
var hasError = bindingExpressions.Any(b => b.BindingExpression.HasError);
|
||||
|
||||
// If there was an error then set focus to the bad controls
|
||||
if (hasError)
|
||||
{
|
||||
// Get the first framework element with an error
|
||||
var firstErrorElement = bindingExpressions.First(b => b.BindingExpression.HasError).FrameworkElement;
|
||||
|
||||
// Set focus
|
||||
firstErrorElement.Focus();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Dialog is good
|
||||
DialogResult = true;
|
||||
|
||||
// Close the dialog
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
<windows:CategoryPanel x:Class="WorkIndicator.Options.WindowPatternsOptionsPanel"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
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:windows="clr-namespace:Common.Wpf.Windows;assembly=Common.Wpf"
|
||||
xmlns:linkControl="clr-namespace:Common.Wpf.LinkControl;assembly=Common.Wpf"
|
||||
xmlns:properties="clr-namespace:WorkIndicator.Properties"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="300"
|
||||
d:DesignWidth="300">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<DataGrid x:Name="WindowPatternsGrid"
|
||||
SelectionMode="Extended"
|
||||
Grid.Column="0"
|
||||
Grid.Row="0"
|
||||
AutoGenerateColumns="False"
|
||||
GridLinesVisibility="None"
|
||||
CanUserResizeRows="False"
|
||||
IsReadOnly="True"
|
||||
HeadersVisibility="Column"
|
||||
SelectionUnit="FullRow"
|
||||
SelectionChanged="HandleWindowPatternsSelectionChanged"
|
||||
Background="{x:Null}"
|
||||
MouseDoubleClick="HandleWindowPatternsDoubleClick">
|
||||
<DataGrid.Columns>
|
||||
<DataGridCheckBoxColumn Binding="{Binding Enabled}"
|
||||
Header="{x:Static properties:Resources.ColumnHeader_Enabled}" />
|
||||
<DataGridTextColumn Binding="{Binding Name}"
|
||||
Header="{x:Static properties:Resources.ColumnHeader_Name}"
|
||||
SortDirection="Ascending"
|
||||
Width="*" />
|
||||
<DataGridTextColumn Binding="{Binding Pattern}"
|
||||
Header="{x:Static properties:Resources.ColumnHeader_Pattern}"
|
||||
Width="2*" />
|
||||
</DataGrid.Columns>
|
||||
<DataGrid.CellStyle>
|
||||
<Style TargetType="DataGridCell">
|
||||
<Setter Property="BorderThickness"
|
||||
Value="0"></Setter>
|
||||
<Setter Property="FocusVisualStyle"
|
||||
Value="{x:Null}" />
|
||||
</Style>
|
||||
</DataGrid.CellStyle>
|
||||
</DataGrid>
|
||||
<Border Grid.Column="0"
|
||||
Grid.Row="1"
|
||||
BorderThickness="1,0,1,1"
|
||||
BorderBrush="{DynamicResource {x:Static SystemColors.ActiveBorderBrushKey}}">
|
||||
<StackPanel Orientation="Horizontal"
|
||||
Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}">
|
||||
<linkControl:LinkControl Margin="2"
|
||||
Click="HandleAddWindowPatternButtonClick"
|
||||
Text="{x:Static properties:Resources.AddWindowPattern}"
|
||||
ToolTip="{x:Static properties:Resources.AddWindowPattern_ToolTip}">
|
||||
</linkControl:LinkControl>
|
||||
<linkControl:LinkControl Name="EditWindowPatternButton"
|
||||
Margin="2"
|
||||
Click="HandleEditWindowPatternButtonClick"
|
||||
Text="{x:Static properties:Resources.EditWindowPattern}"
|
||||
ToolTip="{x:Static properties:Resources.EditWindowPattern_ToolTip}">
|
||||
</linkControl:LinkControl>
|
||||
<linkControl:LinkControl Name="DeleteWindowPatternButton"
|
||||
Margin="2"
|
||||
Click="HandleDeleteWindowPatternButtonClick"
|
||||
Text="{x:Static properties:Resources.DeleteWindowPattern}"
|
||||
ToolTip="{x:Static properties:Resources.DeleteWindowPattern_ToolTip}">
|
||||
</linkControl:LinkControl>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</windows:CategoryPanel>
|
||||
@@ -1,114 +0,0 @@
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace WorkIndicator.Options
|
||||
{
|
||||
public partial class WindowPatternsOptionsPanel
|
||||
{
|
||||
public WindowPatternsOptionsPanel()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private WindowPatterns WindowPatterns => Data as WindowPatterns;
|
||||
|
||||
public override void LoadPanel(object data)
|
||||
{
|
||||
base.LoadPanel(data);
|
||||
|
||||
WindowPatternsGrid.ItemsSource = WindowPatterns;
|
||||
|
||||
WindowPatternsGrid.SelectedItem = WindowPatterns.FirstOrDefault();
|
||||
SetButtonStates();
|
||||
}
|
||||
|
||||
public override bool ValidatePanel()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void SavePanel()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override string CategoryName => Properties.Resources.OptionCategory_WindowPatterns;
|
||||
|
||||
private void SetButtonStates()
|
||||
{
|
||||
EditWindowPatternButton.IsEnabled = (WindowPatternsGrid.SelectedItems.Count == 1);
|
||||
DeleteWindowPatternButton.IsEnabled = (WindowPatternsGrid.SelectedItems.Count > 0);
|
||||
}
|
||||
|
||||
private void AddWindowPattern()
|
||||
{
|
||||
var windowPattern = new WindowPattern();
|
||||
|
||||
var windowPatternWindow = new WindowPatternWindow();
|
||||
|
||||
var result = windowPatternWindow.Display(windowPattern, Window.GetWindow(this));
|
||||
|
||||
if (result.HasValue && result.Value)
|
||||
{
|
||||
WindowPatterns.Add(windowPattern);
|
||||
|
||||
WindowPatternsGrid.SelectedItem = windowPattern;
|
||||
|
||||
SetButtonStates();
|
||||
}
|
||||
}
|
||||
|
||||
private void EditSelectedWindowPattern()
|
||||
{
|
||||
if (WindowPatternsGrid.SelectedItem == null)
|
||||
return;
|
||||
|
||||
var windowPattern = WindowPatternsGrid.SelectedItem as WindowPattern;
|
||||
|
||||
var windowPatternWindow = new WindowPatternWindow();
|
||||
|
||||
windowPatternWindow.Display(windowPattern, Window.GetWindow(this));
|
||||
}
|
||||
|
||||
private void DeleteSelectedWindowPattern()
|
||||
{
|
||||
var windowPattern = WindowPatternsGrid.SelectedItem as WindowPattern;
|
||||
var index = WindowPatternsGrid.SelectedIndex;
|
||||
|
||||
WindowPatterns.Remove(windowPattern);
|
||||
|
||||
if (WindowPatternsGrid.Items.Count == index)
|
||||
WindowPatternsGrid.SelectedIndex = WindowPatternsGrid.Items.Count - 1;
|
||||
else if (WindowPatternsGrid.Items.Count >= index)
|
||||
WindowPatternsGrid.SelectedIndex = index;
|
||||
|
||||
SetButtonStates();
|
||||
}
|
||||
|
||||
private void HandleAddWindowPatternButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
AddWindowPattern();
|
||||
}
|
||||
|
||||
private void HandleEditWindowPatternButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
EditSelectedWindowPattern();
|
||||
}
|
||||
|
||||
private void HandleDeleteWindowPatternButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
DeleteSelectedWindowPattern();
|
||||
}
|
||||
|
||||
private void HandleWindowPatternsSelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
SetButtonStates();
|
||||
}
|
||||
|
||||
private void HandleWindowPatternsDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e)
|
||||
{
|
||||
EditSelectedWindowPattern();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -113,20 +113,17 @@ namespace WorkIndicator
|
||||
_initialized = false;
|
||||
}
|
||||
|
||||
public static void ShowSettings()
|
||||
private static void ShowSettings()
|
||||
{
|
||||
var panels = new List<CategoryPanel>
|
||||
{
|
||||
new GeneralOptionsPanel(),
|
||||
new WindowPatternsOptionsPanel(),
|
||||
new AboutOptionsPanel()
|
||||
};
|
||||
|
||||
var windowPatterns = WindowPatterns.Load();
|
||||
|
||||
if (_optionsWindow == null)
|
||||
{
|
||||
_optionsWindow = new CategoryWindow(windowPatterns, panels, Resources.ResourceManager, "OptionsWindow");
|
||||
_optionsWindow = new CategoryWindow(null, panels, Resources.ResourceManager, "OptionsWindow");
|
||||
_optionsWindow.Closed += (o, args) => { _optionsWindow = null; };
|
||||
}
|
||||
|
||||
@@ -134,7 +131,6 @@ namespace WorkIndicator
|
||||
|
||||
if (dialogResult.HasValue && dialogResult.Value)
|
||||
{
|
||||
windowPatterns.Save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
namespace WorkIndicator
|
||||
{
|
||||
public class WindowPattern
|
||||
{
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string Pattern { get; set; } = string.Empty;
|
||||
public bool Enabled { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using WorkIndicator.Properties;
|
||||
|
||||
namespace WorkIndicator
|
||||
{
|
||||
public class WindowPatterns : ObservableCollection<WindowPattern>
|
||||
{
|
||||
public static event EventHandler Changed;
|
||||
|
||||
public static WindowPatterns Load()
|
||||
{
|
||||
var windowPatterns = Load(Settings.Default.WindowPatterns);
|
||||
|
||||
return windowPatterns;
|
||||
}
|
||||
|
||||
private static WindowPatterns Load(string serializedData)
|
||||
{
|
||||
var windowPatterns = JsonConvert.DeserializeObject<WindowPatterns>(serializedData) ?? new WindowPatterns();
|
||||
|
||||
return windowPatterns;
|
||||
}
|
||||
|
||||
public void Save()
|
||||
{
|
||||
Settings.Default.WindowPatterns = Serialize();
|
||||
|
||||
Settings.Default.Save();
|
||||
|
||||
Changed?.Invoke(this, null);
|
||||
}
|
||||
|
||||
private string Serialize()
|
||||
{
|
||||
return JsonConvert.SerializeObject(this);
|
||||
}
|
||||
|
||||
public WindowPatterns Clone()
|
||||
{
|
||||
var data = Serialize();
|
||||
|
||||
return Load(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -147,6 +147,7 @@
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</ApplicationDefinition>
|
||||
<Compile Include="AudioWatcher.cs" />
|
||||
<Compile Include="LightController.cs" />
|
||||
<Compile Include="Delcom\StoplightIndicator.cs" />
|
||||
<Compile Include="App.xaml.cs">
|
||||
@@ -165,15 +166,7 @@
|
||||
<Compile Include="Options\GeneralOptionsPanel.xaml.cs">
|
||||
<DependentUpon>GeneralOptionsPanel.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Options\WindowPatternsOptionsPanel.xaml.cs">
|
||||
<DependentUpon>WindowPatternsOptionsPanel.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Options\WindowPatternWindow.xaml.cs">
|
||||
<DependentUpon>WindowPatternWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="TrayIcon.cs" />
|
||||
<Compile Include="WindowPattern.cs" />
|
||||
<Compile Include="WindowPatterns.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Properties\AssemblyInfo.cs">
|
||||
@@ -232,18 +225,13 @@
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Options\WindowPatternsOptionsPanel.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Options\WindowPatternWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CSCore">
|
||||
<Version>1.2.1.2</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Newtonsoft.Json">
|
||||
<Version>10.0.3</Version>
|
||||
<Version>13.0.1</Version>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
2
WorkIndicator.sln.DotSettings
Normal file
2
WorkIndicator.sln.DotSettings
Normal file
@@ -0,0 +1,2 @@
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Delcom/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||
Reference in New Issue
Block a user