Add AI Team branding and configurable break counting

This commit is contained in:
2026-06-17 18:45:17 +02:00
parent 27b6e7c947
commit c9e081b46b
8 changed files with 1611 additions and 1218 deletions

View File

@@ -35,6 +35,7 @@ Sub Process_Globals
Private StatsFileName As String
Private StateFileName As String
Private AutoConfigFileName As String
Private SettingsFileName As String
Private MaxStoredDays As Int
End Sub
@@ -52,8 +53,10 @@ Sub Globals
Private BtnClearToday As Button
Private BtnHelpOpen As Button
Private BtnHelpClose As Button
Private chkIncludePauses As CheckBox
Private BtnBackground As Label
Private lblAppName As Label
Private lblBrandInfo As Label
Private lblElapsedTime As Label
Private lblAutoStatus As Label
Private pnlClock As Panel
@@ -84,6 +87,7 @@ Sub Globals
Private AutoEndMinutes As Int
Private AutoState As String
Private LastActiveStateSaveAt As Long
Private IncludePauseInTotal As Boolean
End Sub
Sub Activity_Create(FirstTime As Boolean)
@@ -101,7 +105,9 @@ Sub Activity_Create(FirstTime As Boolean)
StatsFileName = "work_segments.txt"
StateFileName = "active_state.txt"
AutoConfigFileName = "auto_config.txt"
SettingsFileName = "app_settings.txt"
MaxStoredDays = 62
IncludePauseInTotal = True
myClock.Initialize(pnlClock, 96)
myClock.SetBaseDuration(12 * DateTime.TicksPerHour)
@@ -111,6 +117,7 @@ Sub Activity_Create(FirstTime As Boolean)
StatsRows.Initialize
LoadStatsRows
LoadSettings
HideLegacyButtons
CreateStatsButton
CreateStatsPage
@@ -119,6 +126,7 @@ Sub Activity_Create(FirstTime As Boolean)
CreateHelpPage
CreateBackgroundButton
CreateAppNameLabel
CreateBrandInfoLabel
CreateAutoStatusLabel
LayoutMainButtons
LoadAutoConfig
@@ -219,6 +227,15 @@ Private Sub CreateAppNameLabel
Activity.AddView(lblAppName, 0, 0, 10dip, 10dip)
End Sub
Private Sub CreateBrandInfoLabel
lblBrandInfo.Initialize("")
lblBrandInfo.Text = "AI Team | aiteam.ai"
lblBrandInfo.TextColor = Colors.RGB(90, 90, 90)
lblBrandInfo.TextSize = 11
lblBrandInfo.Gravity = Gravity.CENTER
Activity.AddView(lblBrandInfo, 0, 0, 10dip, 10dip)
End Sub
Private Sub LayoutMainButtons
Dim margin As Int = 8dip
Dim gap As Int = 8dip
@@ -248,7 +265,9 @@ Private Sub LayoutMainButtons
If lblAppName.IsInitialized Then
Dim titleTop As Int = pnlClock.Top + pnlClock.Height + 4dip
Dim titleHeight As Int = Max(28dip, row1Top - titleTop - 4dip)
lblAppName.SetLayout(0, titleTop, Activity.Width, titleHeight)
Dim appNameHeight As Int = Max(24dip, titleHeight * 0.58)
lblAppName.SetLayout(0, titleTop, Activity.Width, appNameHeight)
If lblBrandInfo.IsInitialized Then lblBrandInfo.SetLayout(0, titleTop + appNameHeight - 2dip, Activity.Width, Max(18dip, titleHeight - appNameHeight + 2dip))
End If
If lblElapsedTime.IsInitialized Then lblElapsedTime.SetLayout(0, labelTop, Activity.Width * 0.58, 28dip)
If lblAutoStatus.IsInitialized Then lblAutoStatus.SetLayout(Activity.Width * 0.58, labelTop, Activity.Width * 0.42, 28dip)
@@ -296,22 +315,29 @@ Private Sub CreateConfigPage
txtCfgPauseEnd = AddConfigField(Localization.T("pause_end"), "13:00", y)
y = y + 58dip
txtCfgEnd = AddConfigField(Localization.T("work_end"), "17:00", y)
y = y + 58dip
chkIncludePauses.Initialize("chkIncludePauses")
chkIncludePauses.Text = Localization.T("include_pause_total")
chkIncludePauses.TextSize = 15
chkIncludePauses.Checked = IncludePauseInTotal
pnlConfig.AddView(chkIncludePauses, 12dip, y, Activity.Width - 24dip, 48dip)
BtnConfigSave.Initialize("BtnConfigSave")
BtnConfigSave.Text = Localization.T("set_config")
pnlConfig.AddView(BtnConfigSave, 12dip, y + 70dip, (Activity.Width - 32dip) / 2, 48dip)
pnlConfig.AddView(BtnConfigSave, 12dip, y + 56dip, (Activity.Width - 32dip) / 2, 48dip)
BtnConfigReset.Initialize("BtnConfigReset")
BtnConfigReset.Text = Localization.T("reset_config")
pnlConfig.AddView(BtnConfigReset, 20dip + ((Activity.Width - 32dip) / 2), y + 70dip, (Activity.Width - 32dip) / 2, 48dip)
pnlConfig.AddView(BtnConfigReset, 20dip + ((Activity.Width - 32dip) / 2), y + 56dip, (Activity.Width - 32dip) / 2, 48dip)
BtnClearToday.Initialize("BtnClearToday")
BtnClearToday.Text = Localization.T("clear_today")
pnlConfig.AddView(BtnClearToday, 12dip, y + 126dip, Activity.Width - 24dip, 48dip)
pnlConfig.AddView(BtnClearToday, 12dip, y + 112dip, Activity.Width - 24dip, 48dip)
BtnHelpOpen.Initialize("BtnHelpOpen")
BtnHelpOpen.Text = "Help"
pnlConfig.AddView(BtnHelpOpen, 12dip, y + 182dip, Activity.Width - 24dip, 48dip)
BtnHelpOpen.Text = Localization.T("help")
pnlConfig.AddView(BtnHelpOpen, 12dip, y + 168dip, Activity.Width - 24dip, 48dip)
End Sub
Private Sub CreateHelpPage
@@ -322,14 +348,14 @@ Private Sub CreateHelpPage
Dim title As Label
title.Initialize("")
title.Text = "Help"
title.Text = Localization.T("help")
title.TextSize = 22
title.TextColor = Colors.Black
title.Gravity = Gravity.CENTER_VERTICAL
pnlHelp.AddView(title, 12dip, 8dip, Activity.Width - 110dip, 46dip)
BtnHelpClose.Initialize("BtnHelpClose")
BtnHelpClose.Text = "Close"
BtnHelpClose.Text = Localization.T("close")
pnlHelp.AddView(BtnHelpClose, Activity.Width - 94dip, 8dip, 84dip, 46dip)
svHelp.Initialize(0)
@@ -450,6 +476,12 @@ Sub BtnConfigReset_Click
ResetAutomaticConfig
End Sub
Sub chkIncludePauses_CheckedChange(Checked As Boolean)
IncludePauseInTotal = Checked
SaveSettings
ApplyPauseCountingMode
End Sub
Sub BtnClearToday_Click
ClearDisplayedDay
End Sub
@@ -572,6 +604,7 @@ Private Sub CloseCurrentSegment(FinalTime As Long)
If duration <= 0 Then Return
If PauseActive Then
RecordSegment(CurrentSegmentStart, duration, Colors.Yellow, True)
If IncludePauseInTotal Then ProductiveElapsedMs = ProductiveElapsedMs + duration
Else
RecordSegment(CurrentSegmentStart, duration, GetCurrentWorkColor, False)
ProductiveElapsedMs = ProductiveElapsedMs + duration
@@ -599,6 +632,20 @@ Private Sub AddStatsSegment(DayStart As Long, DayKey As Long, SegmentStart As Lo
End Sub
Private Sub ProcessActivePauseSegment(now As Long)
If IncludePauseInTotal Then
Dim remainingToLimit As Long = MaxProductiveMs - ProductiveElapsedMs
If remainingToLimit <= 0 Then
EndSession(CurrentSegmentStart, True)
Log("Workday stopped automatically during pause: 9-hour limit reached.")
Return
End If
Dim limitTime As Long = CurrentSegmentStart + remainingToLimit
If limitTime <= GetNextMidnight(CurrentSegmentStart) And now >= limitTime Then
EndSession(limitTime, True)
Log("Workday stopped automatically during pause: 9-hour limit reached.")
Return
End If
End If
Dim midnight As Long = GetNextMidnight(CurrentSegmentStart)
If now >= midnight Then
EndSession(midnight, True)
@@ -675,6 +722,7 @@ End Sub
Private Sub GetDisplayedProductiveElapsed(now As Long) As Long
Dim total As Long = ProductiveElapsedMs
If SessionActive And PauseActive And IncludePauseInTotal Then total = total + Max(0, now - CurrentSegmentStart)
If SessionActive And PauseActive = False Then total = total + Max(0, now - CurrentSegmentStart)
Return total
End Sub
@@ -685,6 +733,7 @@ Private Sub GetProductiveTotalForWorkDay(DayKey As Long) As Long
If row.Get("dayKey") = DayKey Then
Dim category As String = row.Get("category")
If category = "lavoro" Or category = "straordinario" Then total = total + row.Get("duration")
If IncludePauseInTotal And category = "pausa" Then total = total + row.Get("duration")
End If
Next
Return total
@@ -698,6 +747,7 @@ Private Sub LoadWorkDaySegmentsIntoClock(DayKey As Long)
Dim duration As Long = row.Get("duration")
If category = "pausa" Then
myClock.AddSegment(duration, Colors.Yellow, True)
If IncludePauseInTotal Then productiveCursor = productiveCursor + duration
Else
AddDisplayProductiveSegment(duration, productiveCursor)
productiveCursor = productiveCursor + duration
@@ -839,8 +889,7 @@ Private Sub RestoreActiveState
CurrentWorkDayStart = lines.Get(0)
CurrentWorkDayKey = CurrentWorkDayStart
CurrentSegmentStart = lines.Get(1)
ProductiveElapsedMs = lines.Get(2)
ProductiveElapsedMs = Max(ProductiveElapsedMs, GetProductiveTotalForWorkDay(CurrentWorkDayKey))
ProductiveElapsedMs = GetProductiveTotalForWorkDay(CurrentWorkDayKey)
PauseActive = lines.Get(3)
CurrentSegmentColor = lines.Get(4)
@@ -1023,7 +1072,9 @@ Private Sub SetAutomaticConfig
Return
End If
Dim workMinutes As Int = (pauseStartMinutes - startMinutes) + (endMinutes - pauseEndMinutes)
If workMinutes > 480 Then
Dim countedMinutes As Int = workMinutes
If IncludePauseInTotal Then countedMinutes = endMinutes - startMinutes
If countedMinutes > 480 Then
ToastMessageShow(Localization.T("work_exceed"), False)
Return
End If
@@ -1059,6 +1110,13 @@ Private Sub SaveAutoConfig
File.WriteList(File.DirInternal, AutoConfigFileName, lines)
End Sub
Private Sub SaveSettings
Dim lines As List
lines.Initialize
lines.Add(IncludePauseInTotal)
File.WriteList(File.DirInternal, SettingsFileName, lines)
End Sub
Private Sub LoadAutoConfig
AutoModeEnabled = False
AutoState = "stopped"
@@ -1076,6 +1134,14 @@ Private Sub LoadAutoConfig
txtCfgEnd.Text = MinutesToTime(AutoEndMinutes)
End Sub
Private Sub LoadSettings
IncludePauseInTotal = True
If File.Exists(File.DirInternal, SettingsFileName) = False Then Return
Dim lines As List = File.ReadList(File.DirInternal, SettingsFileName)
If lines.Size = 0 Then Return
IncludePauseInTotal = ParseBooleanValue(lines.Get(0), True)
End Sub
Private Sub ParseTimeToMinutes(Value As String) As Int
Dim parts() As String = Regex.Split(":", Value.Trim)
If parts.Length <> 2 Then Return -1
@@ -1192,6 +1258,57 @@ Private Sub ClearDisplayedDay
ToastMessageShow(Localization.T("today_cleared"), False)
End Sub
Private Sub ApplyPauseCountingMode
If chkIncludePauses.IsInitialized And chkIncludePauses.Checked <> IncludePauseInTotal Then chkIncludePauses.Checked = IncludePauseInTotal
Dim now As Long = DateTime.Now
If SessionActive Then
ProductiveElapsedMs = GetProductiveTotalForWorkDay(CurrentWorkDayKey)
If PauseActive Then
ProcessActivePauseSegment(now)
If SessionActive = False Then
UpdateElapsedLabel
Return
End If
CurrentSegmentColor = Colors.Yellow
myClock.ClearSegments
LoadWorkDaySegmentsIntoClock(CurrentWorkDayKey)
myClock.SetActiveSegment(Max(0, now - CurrentSegmentStart), Colors.Yellow, True)
Else
ProcessActiveWorkSegment(now)
If SessionActive = False Then
UpdateElapsedLabel
Return
End If
CurrentSegmentColor = GetCurrentWorkColor
myClock.ClearSegments
LoadWorkDaySegmentsIntoClock(CurrentWorkDayKey)
myClock.SetActiveSegment(Max(0, now - CurrentSegmentStart), CurrentSegmentColor, False)
End If
SaveActiveState
Else
If CurrentWorkDayKey > 0 Then
ProductiveElapsedMs = GetProductiveTotalForWorkDay(CurrentWorkDayKey)
CurrentSegmentColor = GetCurrentWorkColor
myClock.ClearSegments
LoadWorkDaySegmentsIntoClock(CurrentWorkDayKey)
myClock.ClearActiveSegment
Else
RestoreLastClosedDayState
End If
End If
UpdateElapsedLabel
UpdateMainControlState
End Sub
Private Sub ParseBooleanValue(Value As Object, DefaultValue As Boolean) As Boolean
If Value = Null Then Return DefaultValue
Dim s As String = Value
s = s.Trim.ToLowerCase
If s = "true" Then Return True
If s = "false" Then Return False
Return DefaultValue
End Sub
Private Sub AddStatsRow(y As Int, DateText As String, WorkText As String, PauseText As String, OvertimeText As String, Header As Boolean)
Dim rowHeight As Int = 30dip
Dim col1 As Int = 104dip
@@ -1220,6 +1337,10 @@ End Sub
Private Sub BuildHelpText As String
Return $"Overtime Guard
By AI Team
aiteam.ai
AI agents and software systems
Purpose
Overtime Guard is a minimal workday timer. It helps you track work time, breaks, and overtime without projects, tasks, or extra screens.
@@ -1239,7 +1360,8 @@ Clock colors
- Red: overtime after 8 productive hours.
How timing works
- Breaks do not count toward the 8 working hours.
- Breaks always stay visible in yellow.
- In Config you can choose whether break time is included in the total 8-hour count.
- Overtime starts only after 8 productive work hours.
- Red overtime can continue for up to 1 extra hour.
- At 9 total productive hours, recording stops automatically.
@@ -1258,6 +1380,7 @@ Statistics
Automatic mode
- In Config you can set work start, pause start, pause end, and work end.
- The Include breaks in total option also affects automatic mode.
- Set config enables automatic mode.
- In automatic mode, Start and End on the main screen are disabled.
- Reset config disables automatic mode and returns control to manual mode.