Skip to content

Commit 35b375a

Browse files
authored
Merge pull request #4 from jonwolfdev/1.0-enhancements
1.0 enhancements
2 parents 72652b3 + 3d759da commit 35b375a

15 files changed

Lines changed: 215 additions & 118 deletions

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ A simple timer/stopwatch WPF application. It simulates google's timer (https://w
88
- Stopwatch (Start/Stop for counting time)
99

1010
## Code / build status
11-
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=jonwolfdev_SimpleWPFTimer&metric=alert_status)](https://sonarcloud.io/dashboard?id=jonwolfdev_SimpleWPFTimer) [![Build Status](https://dev.azure.com/windoaccw10/SimpleWPFTimer/_apis/build/status/jonwolfdev.SimpleWPFTimer?branchName=master)](https://dev.azure.com/windoaccw10/SimpleWPFTimer/_build/latest?definitionId=1&branchName=master) [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=jonwolfdev_SimpleWPFTimer&metric=coverage)](https://sonarcloud.io/dashboard?id=jonwolfdev_SimpleWPFTimer)
11+
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=jonwolfdev_SimpleWPFTimer&metric=alert_status)](https://sonarcloud.io/dashboard?id=jonwolfdev_SimpleWPFTimer) [![Build Status](https://dev.azure.com/jonwolfdev/SimpleWPFTimer/_apis/build/status/jonwolfdev.SimpleWPFTimer?branchName=master)](https://dev.azure.com/jonwolfdev/SimpleWPFTimer/_build/latest?definitionId=1&branchName=master) [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=jonwolfdev_SimpleWPFTimer&metric=coverage)](https://sonarcloud.io/dashboard?id=jonwolfdev_SimpleWPFTimer)
1212

1313
## Technical details
1414
It uses WPF and 3.1 .net core.
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
using System;
2+
using System.ComponentModel;
3+
using System.Windows.Input;
4+
5+
namespace SimpleTimer.ClockUserControls
6+
{
7+
public abstract class BaseViewModel : IClockViewModel
8+
{
9+
protected IConfigurationValues Config { get; private set; }
10+
protected ActionCommand TextPressEnterCommand { get; set; }
11+
protected ActionCommand TextPressEscapeCommand { get; set; }
12+
13+
string _text;
14+
string _primaryButtonText;
15+
bool _isTextEnabled;
16+
17+
string _primaryBtnBackgroundColor;
18+
string _primaryBtnForegroundColor;
19+
string _primaryBtnMouseOverColor;
20+
string _primaryBtnPressedColor;
21+
22+
protected BaseViewModel(IConfigurationValues config)
23+
{
24+
Config = config;
25+
}
26+
27+
#region DataContext
28+
public string PrimaryBtnBackgroundColor { get => _primaryBtnBackgroundColor; set { _primaryBtnBackgroundColor = value; OnPropertyChanged(nameof(PrimaryBtnBackgroundColor)); } }
29+
public string PrimaryBtnForegroundColor { get => _primaryBtnForegroundColor; set { _primaryBtnForegroundColor = value; OnPropertyChanged(nameof(PrimaryBtnForegroundColor)); } }
30+
public string PrimaryBtnMouseOverColor { get => _primaryBtnMouseOverColor; set { _primaryBtnMouseOverColor = value; OnPropertyChanged(nameof(PrimaryBtnMouseOverColor)); } }
31+
public string PrimaryBtnPressedColor { get => _primaryBtnPressedColor; set { _primaryBtnPressedColor = value; OnPropertyChanged(nameof(PrimaryBtnPressedColor)); } }
32+
public string Text { get => _text; set { _text = value; OnPropertyChanged(nameof(Text)); } }
33+
public bool IsTextEnabled { get => _isTextEnabled; set { _isTextEnabled = value; OnPropertyChanged(nameof(IsTextEnabled)); } }
34+
public string PrimaryButtonText { get => _primaryButtonText; set { _primaryButtonText = value; OnPropertyChanged(nameof(PrimaryButtonText)); } }
35+
public ICommand TextPressEnter { get => TextPressEnterCommand; }
36+
public ICommand TextPressEscape { get => TextPressEscapeCommand; }
37+
38+
public event PropertyChangedEventHandler PropertyChanged;
39+
private void OnPropertyChanged(string name)
40+
{
41+
var handler = PropertyChanged;
42+
handler?.Invoke(this, new PropertyChangedEventArgs(name));
43+
}
44+
#endregion
45+
46+
protected void ChangeButtonRed()
47+
{
48+
PrimaryBtnBackgroundColor = Config.RedColor;
49+
PrimaryBtnForegroundColor = Config.FontColorOnRed;
50+
PrimaryBtnMouseOverColor = Config.RedMouseOverColor;
51+
PrimaryBtnPressedColor = Config.RedPressedColor;
52+
}
53+
protected void ChangeButtonBlue()
54+
{
55+
PrimaryBtnBackgroundColor = Config.BlueColor;
56+
PrimaryBtnForegroundColor = Config.FontColorOnBlue;
57+
PrimaryBtnMouseOverColor = Config.BlueMouseOverColor;
58+
PrimaryBtnPressedColor = Config.BluePressedColor;
59+
}
60+
61+
#region IDisposable Support
62+
private bool disposedValue = false; // To detect redundant calls
63+
64+
protected virtual void Dispose(bool disposing)
65+
{
66+
if (!disposedValue)
67+
{
68+
if (disposing)
69+
{
70+
TextPressEnterCommand?.Dispose();
71+
TextPressEscapeCommand?.Dispose();
72+
}
73+
disposedValue = true;
74+
}
75+
}
76+
77+
~BaseViewModel()
78+
{
79+
Dispose(false);
80+
}
81+
82+
public void Dispose()
83+
{
84+
Dispose(true);
85+
GC.SuppressFinalize(this);
86+
}
87+
#endregion
88+
}
89+
}

SimpleTimer/ClockUserControls/ClockUserCtrl.xaml

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
d:DesignHeight="215" d:DesignWidth="300">
99
<UserControl.Resources>
1010
<Style x:Key="btnStyleStart" TargetType="{x:Type Button}">
11-
<Setter Property="Background" Value="#4d90fe" />
12-
<Setter Property="Foreground" Value="White" />
11+
<Setter Property="Background" Value="{Binding Path=PrimaryBtnBackgroundColor, Mode=OneWay, UpdateSourceTrigger=PropertyChanged, FallbackValue='#4d90fe'}" />
12+
<Setter Property="Foreground" Value="{Binding Path=PrimaryBtnForegroundColor, Mode=OneWay, UpdateSourceTrigger=PropertyChanged, FallbackValue='White'}" />
1313
<Setter Property="FontSize" Value="15" />
1414
<Setter Property="SnapsToDevicePixels" Value="True" />
1515

@@ -24,13 +24,11 @@
2424

2525
<ControlTemplate.Triggers>
2626
<Trigger Property="IsMouseOver" Value="True">
27-
<Setter Property="Background" Value="#2f5bb7" />
28-
<Setter Property="Foreground" Value="White" />
27+
<Setter Property="Background" Value="{Binding Path=PrimaryBtnMouseOverColor, Mode=OneWay, UpdateSourceTrigger=PropertyChanged, FallbackValue='#2f5bb7'}" />
2928
</Trigger>
3029

3130
<Trigger Property="IsPressed" Value="True">
32-
<Setter Property="Background" Value="#4d90fe" />
33-
<Setter Property="Foreground" Value="White" />
31+
<Setter Property="Background" Value="{Binding Path=PrimaryBtnPressedColor, Mode=OneWay, UpdateSourceTrigger=PropertyChanged, FallbackValue='#4d90fe'}" />
3432
</Trigger>
3533
</ControlTemplate.Triggers>
3634
</ControlTemplate>
@@ -81,14 +79,14 @@
8179
</Grid.RowDefinitions>
8280
<TextBox x:Name="TxtTime" Margin="25" Grid.Column="0" Grid.ColumnSpan="2" FontSize="36" TextAlignment="Center" Padding="0,-3,0,0" FontFamily="Consolas"
8381
MaxLength="10" MaxLines="1" GotFocus="TxtTime_GotFocus" Text="{Binding Path=Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, FallbackValue=00:00:00}"
84-
IsEnabled="{Binding Path=IsTextEnabled, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
82+
IsEnabled="{Binding Path=IsTextEnabled, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}">
8583
<TextBox.InputBindings>
8684
<KeyBinding Key="Return" Command="{Binding TextPressEnter}" />
8785
<KeyBinding Key="Esc" Command="{Binding TextPressEscape}" />
8886
</TextBox.InputBindings>
8987
</TextBox>
9088
<Button x:Name="BtnStart" Grid.Column="0" Grid.Row="1" Margin="25" Style="{StaticResource btnStyleStart}" Click="BtnStart_Click"
91-
Content="{Binding Path=PrimaryButtonText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, FallbackValue=Start}">
89+
Content="{Binding Path=PrimaryButtonText, Mode=OneWay, UpdateSourceTrigger=PropertyChanged, FallbackValue=Start}">
9290
</Button>
9391
<Button x:Name="BtnReset" Grid.Column="1" Grid.Row="1" Margin="25" Style="{StaticResource btnStyleReset}" Click="BtnReset_Click">Reset</Button>
9492
</Grid>

SimpleTimer/ClockUserControls/ClockUserCtrl.xaml.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using SimpleTimer.Clocks;
22
using System;
3+
using System.ComponentModel;
34
using System.Windows;
45
using System.Windows.Controls;
56
using System.Windows.Input;
@@ -11,6 +12,23 @@ namespace SimpleTimer.ClockUserControls
1112
/// </summary>
1213
public partial class ClockUserCtrl : UserControl, IClockUserCtrl, IUserInterface
1314
{
15+
string _windowTitle;
16+
public string WindowTitle { get => _windowTitle; set { _windowTitle = value; OnPropertyChanged(nameof(WindowTitle)); } }
17+
public static string AppVersion
18+
{
19+
get
20+
{
21+
var version = typeof(MainWindow).Assembly.GetName().Version;
22+
return $"v{version.Major}.{version.Minor}";
23+
}
24+
}
25+
public event PropertyChangedEventHandler PropertyChanged;
26+
private void OnPropertyChanged(string name)
27+
{
28+
var handler = PropertyChanged;
29+
handler?.Invoke(this, new PropertyChangedEventArgs(name));
30+
}
31+
1432
public event EventHandler<UIEventArgs> UiEventHappened;
1533
IClockViewModel _vm;
1634
public ClockUserCtrl()
@@ -31,6 +49,10 @@ private void OnUiEventHappened(UIEventArgs e)
3149
}
3250

3351
#region IUserInterface
52+
public void ChangeWindowTitle(string title)
53+
{
54+
WindowTitle = title;
55+
}
3456
public void BtnStartFocus()
3557
{
3658
BtnStart.Focus();

SimpleTimer/ClockUserControls/IClockUserCtrl.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
using System;
2+
using System.ComponentModel;
23
using System.Windows.Input;
34

45
namespace SimpleTimer.ClockUserControls
56
{
6-
public interface IClockUserCtrl : IDisposable
7+
public interface IClockUserCtrl : IDisposable, INotifyPropertyChanged
78
{
9+
string WindowTitle { get; }
10+
static string AppVersion { get; }
811
void SwitchedToAnotherTab();
912
void WindowNumberKeyDown(KeyEventArgs e);
1013
void WindowBackspaceKeyDown(KeyboardEventArgs e);

SimpleTimer/ClockUserControls/IClockViewModel.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,9 @@ public interface IClockViewModel : IDisposable, INotifyPropertyChanged
1111
bool IsTextEnabled { get; set; }
1212
ICommand TextPressEnter { get; }
1313
ICommand TextPressEscape { get; }
14+
string PrimaryBtnBackgroundColor { get; }
15+
string PrimaryBtnForegroundColor { get; }
16+
string PrimaryBtnMouseOverColor { get; }
17+
string PrimaryBtnPressedColor { get; }
1418
}
1519
}

SimpleTimer/ClockUserControls/StopwatchViewModel.cs

Lines changed: 26 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,29 @@
11
using SimpleTimer.Clocks;
2-
using System;
3-
using System.ComponentModel;
42
using System.Globalization;
5-
using System.Windows.Input;
63
using static SimpleTimer.Clocks.UiUpdatedEventArgs;
74

85
namespace SimpleTimer.ClockUserControls
96
{
10-
public class StopwatchViewModel : IClockViewModel
7+
public class StopwatchViewModel : BaseViewModel
118
{
12-
readonly IConfigurationValues _config;
139
readonly IClock _clock;
1410
readonly IUserInterface _ui;
1511
readonly ILogger _logger;
16-
string _text;
17-
string _primaryButtonText;
18-
bool _isTextEnabled;
19-
20-
#region Datacontext
21-
public string Text { get => _text; set { _text = value; OnPropertyChanged(nameof(Text)); } }
22-
public bool IsTextEnabled { get => _isTextEnabled; set { _isTextEnabled = value; OnPropertyChanged(nameof(IsTextEnabled)); } }
23-
public string PrimaryButtonText { get => _primaryButtonText; set { _primaryButtonText = value; OnPropertyChanged(nameof(PrimaryButtonText)); } }
24-
public ICommand TextPressEnter { get => null; }
25-
public ICommand TextPressEscape { get => null; }
26-
27-
public event PropertyChangedEventHandler PropertyChanged;
28-
29-
private void OnPropertyChanged(string name)
30-
{
31-
var handler = PropertyChanged;
32-
handler?.Invoke(this, new PropertyChangedEventArgs(name));
33-
}
34-
#endregion
35-
36-
public StopwatchViewModel(IUserInterface ui, IClock stopwatchclock, IConfigurationValues config, ILogger logger)
12+
13+
public StopwatchViewModel(IUserInterface ui, IClock stopwatchclock, IConfigurationValues config, ILogger logger) : base(config)
3714
{
38-
_config = config;
3915
_ui = ui;
4016
_clock = stopwatchclock;
4117
_logger = logger;
4218

4319
RegisterEvents();
4420

45-
_text = _config?.InitialText ?? "";
46-
_primaryButtonText = _config?.PrimaryButtonStart ?? "";
21+
Text = Config?.InitialText ?? "";
22+
PrimaryButtonText = Config?.PrimaryButtonStart ?? "";
4723
IsTextEnabled = false;
24+
25+
ChangeButtonBlue();
26+
_ui?.ChangeWindowTitle(Config.WindowTitle);
4827
}
4928

5029
private void RegisterEvents()
@@ -114,16 +93,26 @@ private void UpdateIU(UiUpdatedEventArgs e)
11493
return;
11594
if (e.Time.HasValue)
11695
{
117-
Text = e.Time.Value.ToString(_config.TimeFormat, CultureInfo.InvariantCulture);
96+
Text = e.Time.Value.ToString(Config.TimeFormat, CultureInfo.InvariantCulture);
11897
}
11998
if (e.PrimaryBtn.HasValue)
12099
{
121-
PrimaryButtonText = e.PrimaryBtn.Value switch
100+
switch (e.PrimaryBtn.Value)
122101
{
123-
PrimaryButtonMode.Running => _config.PrimaryButtonStop,
124-
PrimaryButtonMode.Stopped => _config.PrimaryButtonStart,
125-
_ => e.PrimaryBtn.Value.ToString(),
126-
};
102+
case PrimaryButtonMode.Running:
103+
PrimaryButtonText = Config.PrimaryButtonStop;
104+
ChangeButtonRed();
105+
_ui.ChangeWindowTitle(Config.WindowTitleRunning);
106+
break;
107+
case PrimaryButtonMode.Stopped:
108+
PrimaryButtonText = Config.PrimaryButtonStart;
109+
ChangeButtonBlue();
110+
_ui.ChangeWindowTitle(Config.WindowTitle);
111+
break;
112+
default:
113+
PrimaryButtonText = e.PrimaryBtn.Value.ToString();
114+
break;
115+
}
127116
}
128117
}
129118

@@ -132,7 +121,7 @@ private void UpdateIU(UiUpdatedEventArgs e)
132121
#region IDisposable Support
133122
private bool disposedValue = false; // To detect redundant calls
134123

135-
protected virtual void Dispose(bool disposing)
124+
protected override void Dispose(bool disposing)
136125
{
137126
if (!disposedValue)
138127
{
@@ -145,19 +134,9 @@ protected virtual void Dispose(bool disposing)
145134

146135
disposedValue = true;
147136
}
137+
base.Dispose(disposing);
148138
}
149139

150-
~StopwatchViewModel()
151-
{
152-
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
153-
Dispose(false);
154-
}
155-
156-
public void Dispose()
157-
{
158-
Dispose(true);
159-
GC.SuppressFinalize(this);
160-
}
161140
#endregion
162141
}
163142
}

0 commit comments

Comments
 (0)