Python - Time Keeper Application
import tkinter as tk
from tkinter import messagebox
from pynput import keyboard, mouse
import threading
import time
import os
import webbrowser
import requests
class TimeKeeperApp:
def __init__(self, root):
self.root = root
self.root.title("Time Keeper")
self.root.geometry("400x200") # <-- Set window size here
self.root.iconphoto(True, tk.PhotoImage(file="EQPD.png"))
self.active_time_label = tk.Label(root, text="Active Time: 0.00 sec", font=("Arial", 16))
self.active_time_label.pack(pady=20)
self.paused_label = tk.Label(root, text="Paused", font=("Arial", 14), fg="red")
self.paused_label.pack()
self.paused_label.pack_forget() # Initially hidden
self.start_button = tk.Button(root, text="Start", width=15, height=2, command=self.start_timer)
self.start_button.pack(pady=5)
self.stop_button = tk.Button(root, text="Stop", width=15, height=2, command=self.stop_timer, state=tk.DISABLED)
self.stop_button.pack(pady=5)
self.timer_running = False
self.timer_paused = False
self.active_time = 0
self.last_activity_time = time.time()
self.activity_timeout = 120 # seconds of inactivity before pause
self.time_log = []
self.current_session_start = None
self.keyboard_listener = None
self.mouse_listener = None
self.monitor_thread = None
self.gui_update_job = None
def start_timer(self):
if not self.timer_running:
self.timer_running = True
self.timer_paused = False
self.active_time = 0
self.current_session_start = time.time()
self.last_activity_time = time.time()
self.time_log = []
self.start_button.config(state=tk.DISABLED)
self.stop_button.config(state=tk.NORMAL)
# Start monitoring activity
self.monitor_thread = threading.Thread(target=self.monitor_activity)
self.monitor_thread.daemon = True
self.monitor_thread.start()
# Start input listeners
self.keyboard_listener = keyboard.Listener(on_press=self.update_activity)
self.mouse_listener = mouse.Listener(on_move=self.update_activity, on_click=self.update_activity)
self.keyboard_listener.start()
self.mouse_listener.start()
# Start GUI time updater
self.update_gui_time()
def stop_timer(self):
if self.timer_running:
self.timer_running = False
# Record final session if active
if not self.timer_paused and self.current_session_start:
self.time_log.append((self.current_session_start, time.time()))
self.start_button.config(state=tk.NORMAL)
self.stop_button.config(state=tk.DISABLED)
if self.keyboard_listener:
self.keyboard_listener.stop()
if self.mouse_listener:
self.mouse_listener.stop()
if self.gui_update_job:
self.root.after_cancel(self.gui_update_job)
total_time = sum(end - start for start, end in self.time_log)
self.save_log(total_time)
def update_activity(self, *args):
self.last_activity_time = time.time()
def monitor_activity(self):
while self.timer_running:
current_time = time.time()
if self.timer_paused:
if current_time - self.last_activity_time < self.activity_timeout:
# Resume
self.timer_paused = False
self.current_session_start = time.time()
else:
if current_time - self.last_activity_time >= self.activity_timeout:
# Pause
self.timer_paused = True
if self.current_session_start:
self.time_log.append((self.current_session_start, current_time))
self.current_session_start = None
time.sleep(1)
def update_gui_time(self):
if self.timer_running:
# Recalculate active time
total = sum(end - start for start, end in self.time_log)
if not self.timer_paused and self.current_session_start:
total += time.time() - self.current_session_start
# Format as HH:MM:SS
hours, remainder = divmod(int(total), 3600)
minutes, seconds = divmod(remainder, 60)
time_str = f"{hours:02}:{minutes:02}:{seconds:02}"
self.active_time_label.config(text=f"Active Time: {time_str}")
# Show or hide pause indicator
if self.timer_paused:
self.paused_label.pack()
else:
self.paused_label.pack_forget()
self.gui_update_job = self.root.after(500, self.update_gui_time)
def save_log(self, total_time):
def format_duration(seconds):
hours, remainder = divmod(int(seconds), 3600)
minutes, seconds = divmod(remainder, 60)
return f"{hours:02}:{minutes:02}:{seconds:02}"
log_lines = [
"Time Keeper Log\n",
f"Total Active Time: {format_duration(total_time)}\n",
"\nSessions:\n"
]
sessions_payload = []
for i, (start, end) in enumerate(self.time_log, 1):
duration = end - start
log_lines.append(
f"{i}. Start: {time.ctime(start)}, End: {time.ctime(end)}, Duration: {format_duration(duration)}\n"
)
sessions_payload.append({
"start": start,
"end": end,
"duration_seconds": round(duration, 2),
"duration_formatted": format_duration(duration)
})
log_path = os.path.join(os.getcwd(), "time_keeper_log.txt")
with open(log_path, "w") as f:
f.writelines(log_lines)
messagebox.showinfo("Time Keeper", f"Timer stopped.\nTotal Active Time: {format_duration(total_time)}.")
webbrowser.open(f"file://{log_path}")
# Send to Google Apps Script Web App
try:
url = "API URL"
payload = {
"timer_start": int(time.time() * 1000),
"sessions": sessions_payload
}
response = requests.post(url, json=payload)
print("Status:", response.status_code)
print("Response:", response.text)
if response.status_code == 200:
print("Logged to Google Sheet.")
else:
print("Failed to log to Google Sheet:", response.text)
except Exception as e:
print("Error sending data to Google Apps Script:", e)
if __name__ == "__main__":
root = tk.Tk()
app = TimeKeeperApp(root)
root.mainloop()