Skip to content

Commit ced1239

Browse files
authored
Merge pull request #7 from Adam-Color/Develop
v1.0.4
2 parents 0dfb43f + 0e3ef84 commit ced1239

File tree

12 files changed

+79
-32
lines changed

12 files changed

+79
-32
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# App Usage GUI
1+
# AppUsageGUI
22
### Application Runtime Tracker
33

44
This program tracks the runtime of a specified application, logging the duration the application is running over multiple instances, with unique sessions created by the user.

build.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22
import sys
33
import shutil
44
import subprocess
5+
from src._version import __version__
56

67
# Project details
7-
PROJECT_NAME = "AppUsageGUI"
8+
PROJECT_NAME = f"AppUsageGUI-v{__version__}"
89
ENTRY_POINT = "src/main.py"
910
BUILD_DIR = "build"
1011
DIST_DIR = "dist"
@@ -25,7 +26,7 @@ def build_executable():
2526
icon_file = "src/core/resources/icon.ico" if os.name == 'nt' else "src/core/resources/icon.icns"
2627
print("Building the application...")
2728
run_command(
28-
f'{python_executable} -m PyInstaller --onefile --name {PROJECT_NAME} '
29+
f'{python_executable} -m PyInstaller --onefile --clean --name {PROJECT_NAME} '
2930
f'--windowed --clean '
3031
f'--add-data "src/core:core" '
3132
f'--add-data "{icon_file}:." '

installer/windows_installer.iss

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[Setup]
2-
AppName=App Usage GUI
2+
AppName=AppUsageGUI
33
AppVersion={#MyAppVersion}
44
DefaultDirName={autopf}\AppUsageGUI
55
DefaultGroupName=AppUsageGUI
@@ -12,5 +12,5 @@ SolidCompression=yes
1212
Source: "dist\App-${#MyAppVersion}.exe"; DestDir: "{app}"
1313

1414
[Icons]
15-
Name: "{group}\App Usage GUI"; Filename: "{app}\App-${#MyAppVersion}.exe"
16-
Name: "{commondesktop}\App Usage GUI"; Filename: "{app}\App-${#MyAppVersion}.exe"
15+
Name: "{group}\AppUsageGUI"; Filename: "{app}\App-${#MyAppVersion}.exe"
16+
Name: "{commondesktop}\AppUsageGUI"; Filename: "{app}\App-${#MyAppVersion}.exe"

src/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "1.0.0"
1+
__version__ = "1.0.4"

src/core/gui_root.py

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -46,25 +46,45 @@ def show_frame(self, page_name):
4646
frame = self.frames[page_name]
4747
frame.tkraise()
4848

49+
#FIXME: thread duplication in update_total_time
4950
def reset_frames(self):
50-
"""Reset the GUI frames."""
51-
# Stop the AppTracker thread
52-
if self.logic_controller.app_tracker:
53-
self.logic_controller.app_tracker.reset()
51+
print("Resetting frames...") #! Debugging prints
52+
53+
try:
54+
# Stop trackers
55+
if self.logic_controller.app_tracker:
56+
print("Stopping AppTracker...")
57+
self.logic_controller.app_tracker.reset()
58+
59+
if self.logic_controller.time_tracker:
60+
print("Stopping TimeTracker...")
61+
self.logic_controller.time_tracker.reset()
62+
63+
if self.logic_controller.mouse_tracker:
64+
print("Stopping MouseTracker...")
65+
self.logic_controller.mouse_tracker.stop()
66+
67+
# Stop GUI threads
68+
for frame_name, frame in self.frames.items():
69+
if hasattr(frame, "stop_threads"):
70+
print(f"Stopping threads for {frame_name}...")
71+
frame.stop_threads()
72+
73+
# Destroy frames
74+
for frame_name, frame in self.frames.items():
75+
print(f"Destroying frame {frame_name}...")
76+
frame.destroy()
77+
78+
self.frames = {}
79+
80+
# Reinitialize screens
81+
print("Reinitializing screens...")
82+
self.init_screens()
83+
84+
except Exception as e:
85+
print(f"Crash in reset_frames(): {e}")
86+
5487

55-
# stop the TimeTracker thread
56-
if self.logic_controller.time_tracker:
57-
self.logic_controller.time_tracker.reset()
58-
59-
# stop the MouseTracker thread
60-
if self.logic_controller.mouse_tracker:
61-
self.logic_controller.mouse_tracker.stop()
62-
63-
# Reset the frames and initialize them again
64-
for frame in self.frames.values():
65-
frame.destroy()
66-
self.frames = {}
67-
self.init_screens()
6888

6989
def on_close(self):
7090
"""Handle cleanup and close the application."""

src/core/logic/app_tracker.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def _fetch_app_names(self):
2222
seen_names = set()
2323
for process in psutil.process_iter(['name']):
2424
try:
25-
app_name = process.info['name'].split(" ")[0]
25+
app_name = process.info['name']
2626
app_name = app_name.split(".")[0] # Use the base name of the process
2727
if app_name not in seen_names and len(app_name) > 0:
2828
apps.append(app_name)

src/core/screens/create_session_window.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ def __init__(self, parent, controller, logic_controller):
1818
confirm_button = tk.Button(self, text="Confirm", command=self.on_confirm)
1919
confirm_button.pack(side="top", fill="x", pady=5)
2020

21+
back_button = tk.Button(self, text="Main Menu", command=lambda: (self.controller.reset_frames(), self.controller.show_frame("MainWindow")))
22+
back_button.pack(pady=5, side='bottom')
23+
2124
def on_confirm(self):
2225
"""Resets trackers upon confirmation"""
2326
session_name = self.session_name_input.get()

src/core/screens/save_window.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ def __init__(self, parent, controller, logic_controller):
1717
button_no = tk.Button(self, text="No", command=self.dont_save)
1818
button_no.pack(pady=5)
1919

20+
back_button = tk.Button(self, text="Main Menu", command=lambda: (self.controller.reset_frames(), self.controller.show_frame("MainWindow")))
21+
back_button.pack(pady=5, side='bottom')
22+
2023
def save(self):
2124
if self.logic_controller.file_handler.get_continuing_session():
2225
session_time = self.logic_controller.time_tracker.get_total_time()

src/core/screens/select_app_window.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ def refresh_apps(self):
8383
else:
8484
for app in self.all_apps:
8585
self.app_listbox.insert(tk.END, app)
86+
self.update_search()
8687

8788
@threaded
8889
def update_search(self, *args):

src/core/screens/session_total_window.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ def __init__(self, parent, controller, logic_controller):
1313

1414
self.update_queue = queue.Queue()
1515

16+
self.stop_event = threading.Event()
17+
1618
self.time_readout = "loading..."
1719

1820
# Display the page label
@@ -43,10 +45,10 @@ def update_total_time(self):
4345
pass
4446

4547
# Call this method again after 1000 ms (1 second) to keep updating the label
46-
self.after(1000, self.update_total_time)
48+
self.update_total_time_id = self.after(1000, self.update_total_time)
4749

4850
def total_time_thread(self):
49-
while True:
51+
while not self.stop_event.is_set():
5052
try:
5153
if self.logic_controller.time_tracker.get_time() > 0 and self.logic_controller.time_tracker.is_running():
5254
# Get the total session time from the logic controller
@@ -57,5 +59,16 @@ def total_time_thread(self):
5759
except TypeError:
5860
pass
5961

60-
# Sleep for 3 seconds before the next update
62+
# Sleep for 1 second before the next update
6163
time.sleep(1)
64+
65+
def stop_threads(self):
66+
self.stop_event.set()
67+
68+
# Cancel scheduled update_total_time calls
69+
try:
70+
self.after_cancel(self.update_total_time_id)
71+
except AttributeError:
72+
pass # If no updates were scheduled yet, ignore error
73+
except ValueError:
74+
pass # If already cancelled, ignore error

src/core/screens/tracker_window.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ def __init__(self, parent, controller, logic_controller):
1414
self.app = ""
1515
self.track_time_disp = "Looking for app..."
1616
self.rec_time = 0
17+
self.stop_event = threading.Event()
1718

1819
# Display the note label
1920
self.note_label = tk.Label(self, text="Tracking stops automatically when tracked app is fully closed")
@@ -44,7 +45,7 @@ def __init__(self, parent, controller, logic_controller):
4445

4546
def update_time_label(self):
4647
secs = 0
47-
while True:
48+
while not self.stop_event.is_set():
4849
self.app = self.logic_controller.app_tracker.get_selected_app()
4950

5051
app_names = self.logic_controller.app_tracker.get_app_names()
@@ -96,7 +97,8 @@ def update_time_label(self):
9697
self.update_queue.put(("time", "Looking for application..."))
9798

9899
time.sleep(0.1)
99-
self.controller.show_frame("SaveWindow")
100+
if not self.stop_event.is_set():
101+
self.controller.show_frame("SaveWindow")
100102

101103

102104
def periodic_update(self):
@@ -111,3 +113,6 @@ def periodic_update(self):
111113
except queue.Empty:
112114
pass
113115
self.after(500, self.periodic_update)
116+
117+
def stop_threads(self):
118+
self.stop_event.set()

src/main.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""
22
Application runtime tracker.
3-
Copyright (C) 2025 Adam Blair-Smith
3+
4+
Copyright (C) 2025 Adam Blair-Smith
45
56
This program is free software: you can redistribute it and/or modify
67
it under the terms of the GNU General Public License as published by
@@ -59,7 +60,7 @@ def main():
5960
icon_path = resource_path(icon_name)
6061

6162
root.iconbitmap(icon_path)
62-
root.title(f"App Usage GUI - v{__version__}")
63+
root.title(f"AppUsageGUI - v{__version__}")
6364

6465
win = GUIRoot(root)
6566
win.pack(side="top", fill="both", expand=True)

0 commit comments

Comments
 (0)