Skip to content

Commit 871164e

Browse files
committed
Features:
- Add billable units column to main DataGrid showing 6-minute block calculations per entry - Fix real-time update of billable units when editing time entries - Add dynamic assembly description loading in About window - Update project description to "MSP time tracking with instant billable units calculation" UI Improvements: - Add BillableUnits property to TimeEntry with proper change notifications - Right-align billable units column for better readability Configuration: - Disable automatic Git version suffix in assembly version - Add SourceRevisionId and IncludeSourceRevisionInInformationalVersion settings - Update assembly metadata (company, authors, copyright)
1 parent 9146f34 commit 871164e

5 files changed

Lines changed: 59 additions & 4 deletions

File tree

Data/TimeEntry.cs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ public TimeOnly? StartTime
6363
if (SetProperty(ref _startTime, value))
6464
{
6565
OnPropertyChanged(nameof(Duration));
66+
OnPropertyChanged(nameof(BillableUnits));
6667
OnPropertyChanged(nameof(IsValid));
6768
OnTimeEntryChanged(true);
6869
}
@@ -77,6 +78,7 @@ public TimeOnly? EndTime
7778
if (SetProperty(ref _endTime, value))
7879
{
7980
OnPropertyChanged(nameof(Duration));
81+
OnPropertyChanged(nameof(BillableUnits));
8082
OnPropertyChanged(nameof(IsValid));
8183
OnTimeEntryChanged(true);
8284
}
@@ -117,6 +119,33 @@ public TimeSpan? Duration
117119
}
118120
}
119121

122+
/// <summary>
123+
/// Calculate billable units in 6-minute blocks (0.1 hour increments).
124+
/// Rounds up to nearest 6-minute block.
125+
/// Returns formatted string like "0.1", "1.5", "2.0", etc., or empty string if duration is invalid.
126+
/// </summary>
127+
public string BillableUnits
128+
{
129+
get
130+
{
131+
var duration = Duration;
132+
if (!duration.HasValue || duration.Value < TimeSpan.Zero)
133+
return string.Empty;
134+
135+
double totalMinutes = duration.Value.TotalMinutes;
136+
137+
// If no time (0 minutes), no billable units
138+
if (totalMinutes < 0.01)
139+
return "0.0";
140+
141+
// Round up to nearest 6-minute block
142+
int blocks = (int)Math.Ceiling(totalMinutes / 6.0);
143+
double units = blocks / 10.0;
144+
145+
return units.ToString("F1");
146+
}
147+
}
148+
120149
public bool IsValid => !string.IsNullOrWhiteSpace(TicketNumber) && Duration.HasValue;
121150

122151
private readonly SynchronizationContext _synchronizationContext;

TimeTrack.csproj

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
<Product>TimeTrack v2</Product>
1313
<Company>TimeTrack Project</Company>
1414
<Authors>Jared Kinnear, Richard Moore</Authors>
15-
<Description>Time tracking application for daily work entries</Description>
15+
<Description>MSP time tracking with instant billable units calculation</Description>
1616
<Copyright>Copyright © 2020-2025</Copyright>
1717

1818
<!-- Application icon and manifest -->
@@ -24,6 +24,10 @@
2424
<AssemblyVersion>2.4.0.0</AssemblyVersion>
2525
<FileVersion>2.4.0.0</FileVersion>
2626
<InformationalVersion>2.4</InformationalVersion>
27+
28+
<!-- Disable automatic Git version suffix -->
29+
<SourceRevisionId></SourceRevisionId>
30+
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
2731
</PropertyGroup>
2832

2933
<!-- Release-specific publish packaging settings -->

Views/Dialogs/AboutWindow.xaml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,9 @@
4545
Margin="0,0,0,20"/>
4646

4747
<!-- Description -->
48-
<TextBlock Grid.Row="2"
49-
Text="A simple time tracking application for daily work entries."
48+
<TextBlock Grid.Row="2"
49+
x:Name="DescriptionText"
50+
Text="Loading..."
5051
FontSize="13"
5152
TextWrapping="Wrap"
5253
HorizontalAlignment="Center"

Views/Dialogs/AboutWindow.xaml.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,24 @@ public AboutWindow()
1313
{
1414
InitializeComponent();
1515

16-
// Set version from InformationalVersion attribute (user-friendly version)
1716
var assembly = Assembly.GetExecutingAssembly();
17+
18+
// Set version from InformationalVersion attribute (user-friendly version)
1819
var informationalVersion = assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion;
1920
string version = informationalVersion ?? assembly.GetName().Version?.ToString() ?? "Unknown";
2021
VersionText.Text = $"Version: {version}";
2122

23+
// Set description from AssemblyDescription attribute
24+
var description = assembly.GetCustomAttribute<AssemblyDescriptionAttribute>()?.Description;
25+
if (!string.IsNullOrEmpty(description))
26+
{
27+
DescriptionText.Text = description;
28+
}
29+
else
30+
{
31+
DescriptionText.Text = "Time tracking application for daily work entries";
32+
}
33+
2234
// Set database location
2335
UpdateDatabaseLocationDisplay();
2436
}

Views/MainWindow.xaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,15 @@
582582
Binding="{Binding StartTime, Converter={StaticResource TimeEntryUIConverter}}"/>
583583
<DataGridTextColumn Header="End" Width="Auto"
584584
Binding="{Binding EndTime, Converter={StaticResource TimeEntryUIConverter}}"/>
585+
<DataGridTextColumn Header="Units" Width="50"
586+
Binding="{Binding BillableUnits}">
587+
<DataGridTextColumn.ElementStyle>
588+
<Style TargetType="TextBlock">
589+
<Setter Property="HorizontalAlignment" Value="Right"/>
590+
<Setter Property="Margin" Value="0,0,8,0"/>
591+
</Style>
592+
</DataGridTextColumn.ElementStyle>
593+
</DataGridTextColumn>
585594
<DataGridTextColumn Header="Ticket Number" Width="Auto"
586595
Binding="{Binding TicketNumber}"/>
587596
<DataGridTextColumn Header="Notes" Width="*"

0 commit comments

Comments
 (0)