Skip to content

Commit 1e475f7

Browse files
committed
Release v1.1.0
2 parents b5a5ddd + 9398279 commit 1e475f7

File tree

16 files changed

+264
-59
lines changed

16 files changed

+264
-59
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
/*.suo
2+
/.vs/
23
/TestResults/

Hourglass.Bundle/Bundle.wxs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
33
xmlns:bal="http://schemas.microsoft.com/wix/BalExtension">
4-
<Bundle Name="Hourglass" Version="1.0.0.0" Manufacturer="Chris Dziemborowicz" UpgradeCode="f1d002c9-cfc9-40fb-84af-96e7aec26e0b" IconSourceFile="$(var.Hourglass.ProjectDir)Resources\AppIcon.ico">
4+
<Bundle Name="Hourglass" Version="1.1.0.0" Manufacturer="Chris Dziemborowicz" UpgradeCode="f1d002c9-cfc9-40fb-84af-96e7aec26e0b" IconSourceFile="$(var.Hourglass.ProjectDir)Resources\AppIcon.ico">
55
<BootstrapperApplicationRef Id="WixStandardBootstrapperApplication.RtfLicense">
66
<bal:WixStandardBootstrapperApplication LicenseFile="MIT.rtf" LogoFile="Logo.png"/>
77
</BootstrapperApplicationRef>

Hourglass.Setup/Product.wxs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
33
xmlns:netfx="http://schemas.microsoft.com/wix/NetFxExtension">
4-
<Product Id="*" Name="Hourglass" Language="1033" Version="1.0.0.0" Manufacturer="Chris Dziemborowicz" UpgradeCode="172d3713-8820-4374-8195-3e2374e7724f">
4+
<Product Id="*" Name="Hourglass" Language="1033" Version="1.1.0.0" Manufacturer="Chris Dziemborowicz" UpgradeCode="172d3713-8820-4374-8195-3e2374e7724f">
55
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine"/>
66

77
<Icon Id="AppIcon.exe" SourceFile="$(var.Hourglass.ProjectDir)Resources\AppIcon.ico"/>
+10-25
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,21 @@
1-
using System.Reflection;
2-
using System.Runtime.CompilerServices;
1+
// --------------------------------------------------------------------------------------------------------------------
2+
// <copyright file="AssemblyInfo.cs" company="Chris Dziemborowicz">
3+
// Copyright (c) Chris Dziemborowicz. All rights reserved.
4+
// </copyright>
5+
// --------------------------------------------------------------------------------------------------------------------
6+
7+
using System.Reflection;
38
using System.Runtime.InteropServices;
49

5-
// General Information about an assembly is controlled through the following
6-
// set of attributes. Change these attribute values to modify the information
7-
// associated with an assembly.
810
[assembly: AssemblyTitle("Hourglass.Test")]
911
[assembly: AssemblyDescription("")]
1012
[assembly: AssemblyConfiguration("")]
1113
[assembly: AssemblyCompany("")]
1214
[assembly: AssemblyProduct("Hourglass.Test")]
13-
[assembly: AssemblyCopyright("Copyright © 2013")]
15+
[assembly: AssemblyCopyright("Copyright © 2015 Chris Dziemborowicz")]
1416
[assembly: AssemblyTrademark("")]
1517
[assembly: AssemblyCulture("")]
16-
17-
// Setting ComVisible to false makes the types in this assembly not visible
18-
// to COM components. If you need to access a type in this assembly from
19-
// COM, set the ComVisible attribute to true on that type.
2018
[assembly: ComVisible(false)]
21-
22-
// The following GUID is for the ID of the typelib if this project is exposed to COM
2319
[assembly: Guid("002a4be7-7323-4bf9-ab08-5fc8978d9eb0")]
24-
25-
// Version information for an assembly consists of the following four values:
26-
//
27-
// Major Version
28-
// Minor Version
29-
// Build Number
30-
// Revision
31-
//
32-
// You can specify all the values or you can default the Build and Revision Numbers
33-
// by using the '*' as shown below:
34-
// [assembly: AssemblyVersion("1.0.*")]
35-
[assembly: AssemblyVersion("1.0.0.0")]
36-
[assembly: AssemblyFileVersion("1.0.0.0")]
20+
[assembly: AssemblyVersion("1.1.0.0")]
21+
[assembly: AssemblyFileVersion("1.1.0.0")]

Hourglass/Hourglass.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@
143143
<Compile Include="Windows\InterfaceScaler.cs" />
144144
<Compile Include="Windows\MultiplierConverter.cs" />
145145
<Compile Include="Windows\NotificationAreaIcon.cs" />
146+
<Compile Include="Windows\RegexMatchConverter.cs" />
146147
<Compile Include="Windows\SizeToFitTextBox.cs" />
147148
<Compile Include="Windows\SoundPlayer.cs" />
148149
<Compile Include="Windows\TimerWindow.xaml.cs">

Hourglass/Properties/App.manifest

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<asmv1:assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
3-
<assemblyIdentity version="1.0.0.0" name="Hourglass"/>
3+
<assemblyIdentity version="1.1.0.0" name="Hourglass"/>
44
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
55
<security>
66
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">

Hourglass/Properties/AssemblyInfo.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@
1717
[assembly: AssemblyCopyright("Copyright © 2015 Chris Dziemborowicz")]
1818
[assembly: AssemblyTrademark("")]
1919
[assembly: AssemblyCulture("")]
20-
[assembly: AssemblyVersion("1.0.0.0")]
21-
[assembly: AssemblyFileVersion("1.0.0.0")]
20+
[assembly: AssemblyVersion("1.1.0.0")]
21+
[assembly: AssemblyFileVersion("1.1.0.0")]
2222
[assembly: NeutralResourcesLanguageAttribute("en-US")]
23-
[assembly: GuidAttribute("83DBAA61-6193-4288-BBB7-BEAEC33FE321")]
23+
[assembly: Guid("83DBAA61-6193-4288-BBB7-BEAEC33FE321")]
2424
[assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)]
2525
[assembly: ComVisible(false)]

Hourglass/Properties/Resources.Designer.cs

+19-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Hourglass/Properties/Resources.resx

+8
Original file line numberDiff line numberDiff line change
@@ -1077,4 +1077,12 @@ $</value>
10771077
<data name="TrayIcon" type="System.Resources.ResXFileRef, System.Windows.Forms">
10781078
<value>..\Resources\TrayIcon.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
10791079
</data>
1080+
<data name="TimerTimerNotExpired" xml:space="preserve">
1081+
<value>Timer not expired</value>
1082+
<comment>The string representation of the time since the timer expired for a timer that is not expired</comment>
1083+
</data>
1084+
<data name="TimerTimeExpiredFormatString" xml:space="preserve">
1085+
<value>{0} ago</value>
1086+
<comment>A format string for the string representation of the time since the timer expired</comment>
1087+
</data>
10801088
</root>

Hourglass/Serialization/TimerInfo.cs

+21
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,27 @@ public long? TimeLeftTicks
7777
set { this.TimeLeft = value.HasValue ? new TimeSpan(value.Value) : (TimeSpan?)null; }
7878
}
7979

80+
/// <summary>
81+
/// Gets or sets a <see cref="TimeSpan"/> representing the time since this timer has expired if the <see
82+
/// cref="State"/> is <see cref="TimerState.Expired"/>, <see cref="TimeSpan.Zero"/> if the <see cref="State"/>
83+
/// is <see cref="TimerState.Running"/> or <see cref="TimerState.Paused"/>, or <c>null</c> otherwise.
84+
/// </summary>
85+
[XmlIgnore]
86+
public TimeSpan? TimeExpired { get; set; }
87+
88+
/// <summary>
89+
/// Gets or sets the <see cref="TimeSpan.Ticks"/> property of <see cref="TimeExpired"/>.
90+
/// </summary>
91+
/// <remarks>
92+
/// This property is exposed because <see cref="TimeSpan"/> does not serialize to XML.
93+
/// </remarks>
94+
[XmlElement("TimeExpired")]
95+
public long? TimeExpiredTicks
96+
{
97+
get { return this.TimeExpired.HasValue ? this.TimeExpired.Value.Ticks : (long?)null; }
98+
set { this.TimeExpired = value.HasValue ? new TimeSpan(value.Value) : (TimeSpan?)null; }
99+
}
100+
80101
/// <summary>
81102
/// Gets or sets a <see cref="TimeSpan"/> representing the total time that this timer will run for or has run
82103
/// for if the <see cref="State"/> is <see cref="TimerState.Running"/> or <see cref="TimerState.Expired"/>, or

Hourglass/Timing/Timer.cs

+33-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ namespace Hourglass.Timing
88
{
99
using System;
1010
using System.Globalization;
11+
using System.Resources;
1112

1213
using Hourglass.Extensions;
1314
using Hourglass.Properties;
@@ -61,6 +62,11 @@ public class Timer : TimerBase
6162
/// </remarks>
6263
private string timeElapsedAsString;
6364

65+
/// <summary>
66+
/// The string representation of the time since the timer expired.
67+
/// </summary>
68+
private string timeExpiredAsString;
69+
6470
#endregion
6571

6672
#region Constructors
@@ -167,6 +173,14 @@ public string TimeElapsedAsString
167173
get { return this.timeElapsedAsString; }
168174
}
169175

176+
/// <summary>
177+
/// Gets the string representation of the time since the timer expired.
178+
/// </summary>
179+
public string TimeExpiredAsString
180+
{
181+
get { return this.timeExpiredAsString; }
182+
}
183+
170184
/// <summary>
171185
/// Gets a value indicating whether the timer supports pause.
172186
/// </summary>
@@ -385,8 +399,9 @@ private void UpdateHourglassTimer()
385399
this.timeElapsedAsPercentage = this.GetTimeElapsedAsPercentage();
386400
this.timeLeftAsString = this.GetTimeLeftAsString();
387401
this.timeElapsedAsString = this.GetTimeElapsedAsString();
402+
this.timeExpiredAsString = this.GetTimeExpiredAsString();
388403

389-
this.OnPropertyChanged("TimerStart", "TimeLeftAsPercentage", "TimeElapsedAsPercentage", "TimeLeftAsString", "TimeElapsedAsString");
404+
this.OnPropertyChanged("TimerStart", "TimeLeftAsPercentage", "TimeElapsedAsPercentage", "TimeLeftAsString", "TimeElapsedAsString", "TimeExpiredAsString");
390405
}
391406

392407
/// <summary>
@@ -486,6 +501,23 @@ private string GetTimeElapsedAsString()
486501
return this.TimeElapsed.ToNaturalString();
487502
}
488503

504+
/// <summary>
505+
/// Returns the string representation of the time since the timer expired.
506+
/// </summary>
507+
/// <returns>The string representation of the time since the timer expired.</returns>
508+
private string GetTimeExpiredAsString()
509+
{
510+
if (this.State != TimerState.Expired)
511+
{
512+
return Resources.TimerTimerNotExpired;
513+
}
514+
515+
return string.Format(
516+
Resources.ResourceManager.GetEffectiveProvider(),
517+
Resources.TimerTimeExpiredFormatString,
518+
this.TimeExpired.ToNaturalString());
519+
}
520+
489521
#endregion
490522
}
491523
}

Hourglass/Timing/TimerBase.cs

+33-11
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,13 @@ public abstract class TimerBase : IDisposable, INotifyPropertyChanged
8686
/// </summary>
8787
private TimeSpan? timeLeft;
8888

89+
/// <summary>
90+
/// A <see cref="TimeSpan"/> representing the time since this timer has expired if the <see cref="State"/> is
91+
/// <see cref="TimerState.Expired"/>, <see cref="TimeSpan.Zero"/> if the <see cref="State"/> is <see
92+
/// cref="TimerState.Running"/> or <see cref="TimerState.Paused"/>, or <c>null</c> otherwise.
93+
/// </summary>
94+
private TimeSpan? timeExpired;
95+
8996
/// <summary>
9097
/// A <see cref="TimeSpan"/> representing the total time that this timer will run for or has run for if the
9198
/// <see cref="State"/> is <see cref="TimerState.Running"/> or <see cref="TimerState.Expired"/>, or <c>null</c>
@@ -129,6 +136,7 @@ protected TimerBase(TimerInfo timerInfo)
129136
this.endTime = timerInfo.EndTime;
130137
this.timeElapsed = timerInfo.TimeElapsed;
131138
this.timeLeft = timerInfo.TimeLeft;
139+
this.timeExpired = timerInfo.TimeExpired;
132140
this.totalTime = timerInfo.TotalTime;
133141

134142
if (this.state == TimerState.Running)
@@ -227,6 +235,16 @@ public TimeSpan? TimeLeft
227235
get { return this.timeLeft; }
228236
}
229237

238+
/// <summary>
239+
/// Gets a <see cref="TimeSpan"/> representing the time since this timer has expired if the <see cref="State"/>
240+
/// is <see cref="TimerState.Expired"/>, <see cref="TimeSpan.Zero"/> if the <see cref="State"/> is <see
241+
/// cref="TimerState.Running"/> or <see cref="TimerState.Paused"/>, or <c>null</c> otherwise.
242+
/// </summary>
243+
public TimeSpan? TimeExpired
244+
{
245+
get { return this.timeExpired; }
246+
}
247+
230248
/// <summary>
231249
/// Gets a <see cref="TimeSpan"/> representing the total time that this timer will run for or has run for if
232250
/// the <see cref="State"/> is <see cref="TimerState.Running"/> or <see cref="TimerState.Expired"/>, or
@@ -287,9 +305,10 @@ public virtual void Start(DateTime start, DateTime end)
287305
this.endTime = end;
288306
this.timeElapsed = TimeSpan.Zero;
289307
this.timeLeft = this.endTime - this.startTime;
308+
this.timeExpired = TimeSpan.Zero;
290309
this.totalTime = this.timeLeft;
291310

292-
this.OnPropertyChanged("State", "StartTime", "EndTime", "TimeElapsed", "TimeLeft", "TotalTime");
311+
this.OnPropertyChanged("State", "StartTime", "EndTime", "TimeElapsed", "TimeLeft", "TimeExpired", "TotalTime");
293312
this.OnStarted();
294313

295314
this.Update();
@@ -316,12 +335,13 @@ public virtual void Pause()
316335
this.state = TimerState.Paused;
317336
this.timeElapsed = MathExtensions.Min(now - (this.startTime ?? now), this.totalTime ?? TimeSpan.Zero);
318337
this.timeLeft = MathExtensions.Max((this.endTime ?? now) - now, TimeSpan.Zero);
338+
this.timeExpired = TimeSpan.Zero;
319339
this.startTime = null;
320340
this.endTime = null;
321341

322342
this.dispatcherTimer.Stop();
323343

324-
this.OnPropertyChanged("State", "StartTime", "EndTime", "TimeElapsed", "TimeLeft");
344+
this.OnPropertyChanged("State", "StartTime", "EndTime", "TimeElapsed", "TimeExpired", "TimeLeft");
325345
this.OnPaused();
326346
}
327347

@@ -373,11 +393,12 @@ public virtual void Stop()
373393
this.endTime = null;
374394
this.timeElapsed = null;
375395
this.timeLeft = null;
396+
this.timeExpired = null;
376397
this.totalTime = null;
377398

378399
this.dispatcherTimer.Stop();
379400

380-
this.OnPropertyChanged("State", "StartTime", "EndTime", "TimeLeft", "TotalTime");
401+
this.OnPropertyChanged("State", "StartTime", "EndTime", "TimeLeft", "TimeExpired", "TotalTime");
381402
this.OnStopped();
382403
}
383404

@@ -391,7 +412,7 @@ public virtual void Update()
391412
{
392413
this.ThrowIfDisposed();
393414

394-
if (this.state != TimerState.Running)
415+
if (this.state != TimerState.Running && this.state != TimerState.Expired)
395416
{
396417
return;
397418
}
@@ -400,20 +421,20 @@ public virtual void Update()
400421
DateTime now = DateTime.Now;
401422
this.timeElapsed = MathExtensions.Min(now - (this.startTime ?? now), this.totalTime ?? TimeSpan.Zero);
402423
this.timeLeft = MathExtensions.Max((this.endTime ?? now) - now, TimeSpan.Zero);
424+
this.timeExpired = MathExtensions.Max(now - (this.endTime ?? now), TimeSpan.Zero);
403425

404-
this.OnPropertyChanged("TimeElapsed", "TimeLeft");
405-
this.OnTick();
406-
407-
// Check if the timer has expired
408-
if (this.timeLeft <= TimeSpan.Zero)
426+
// Raise an event when the timer expires
427+
if (this.timeLeft <= TimeSpan.Zero && this.state == TimerState.Running)
409428
{
410429
this.state = TimerState.Expired;
411430

412-
this.dispatcherTimer.Stop();
413-
414431
this.OnPropertyChanged("State");
415432
this.OnExpired();
416433
}
434+
435+
// Raise other events
436+
this.OnPropertyChanged("TimeElapsed", "TimeLeft", "TimeExpired");
437+
this.OnTick();
417438
}
418439

419440
/// <summary>
@@ -429,6 +450,7 @@ public virtual TimerInfo ToTimerInfo()
429450
EndTime = this.endTime,
430451
TimeElapsed = this.timeElapsed,
431452
TimeLeft = this.timeLeft,
453+
TimeExpired = this.timeExpired,
432454
TotalTime = this.totalTime
433455
};
434456
}

0 commit comments

Comments
 (0)