Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
![version](https://img.shields.io/badge/Version-1.8.1-white.svg)
![version](https://img.shields.io/badge/Version-1.8.2-white.svg)
![license](https://img.shields.io/badge/License-GPL%20v3-blue.svg)
![python](https://img.shields.io/badge/Python-3.13-green.svg)

Expand All @@ -24,6 +24,20 @@ To install, follow the instructions for your platform found here:

NOTE: GIL is detached for the macOS build; use Python 3.13.7t

## Building

For building, it is recommended to use Python 3.13.7 for Windows/Linux, and 3.13.7t for macOS in a virtual enviroment.

Install requirents:
`pip install -r requirements.txt`

Run build script:
`python build.py`

The resulting AppUsageGUI folder will be created in dist/

Scripts to create macOS/Windows installers are located in dev/

## How It Works

AppUsageGUI is a cross-platform desktop application built with Python and Tkinter that monitors application usage time with project-based organization. The application works by:
Expand Down
1 change: 1 addition & 0 deletions build.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ def build_executable():
f'--collect-submodules pynput '
f'--collect-submodules requests '
f'--collect-submodules PIL '
f'--collect-submodules pyperclip '
f'--exclude-module PIL.tests '
f'--exclude-module tkinter.test '
f'--icon={icon_file} '
Expand Down
2 changes: 1 addition & 1 deletion dev/macos_installer.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/bin/bash
# This script is used to create the installer for the macOS version of the application
app_version='1.8.1'
app_version='1.8.2'

mv dist/AppUsageGUI.app dist/AppUsageGUI/

Expand Down
4 changes: 2 additions & 2 deletions dev/windows_installer.iss
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!

#define MyAppName "AppUsageGUI"
#define MyAppVersion "1.8.1"
#define MyAppVersion "1.8.2"
#define MyAppPublisher "Adam Blair-Smith"
#define MyAppURL "https://github.com/Adam-Color/AppUsageGUI"
#define MyAppExeName "AppUsageGUI.exe"
#define MyInstallerName "AppUsageGUI_v1.8.1_WINDOWS_setup"
#define MyInstallerName "AppUsageGUI_v1.8.2_WINDOWS_setup"

[Setup]
; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications.
Expand Down
3 changes: 3 additions & 0 deletions docs/release_template.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# AppUsageGUI v0.0.0

>[!warning]
>Due to Apple's restrictions when it comes to open source applications such as ours, workarounds are needed to get AppUsageGUI to run on macOS. Please read the installation instructions below.

To install, follow the instructions for your platform found here:

[Windows](https://github.com/Adam-Color/AppUsageGUI/blob/Develop/docs/install_windows.md) | [macOS](https://github.com/Adam-Color/AppUsageGUI/blob/Develop/docs/install_macos.md)
Expand Down
5 changes: 1 addition & 4 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
MouseInfo==0.1.3
psutil==7.1.0
pynput==1.8.1
PyGetWindow==0.0.9
PyMsgBox==1.0.9
pyobjc-core==11.0; sys_platform == "darwin"
pyobjc-framework-Cocoa==11.0; sys_platform == "darwin"
pyobjc-framework-Quartz==11.0; sys_platform == "darwin"
pyperclip==1.9.0
PyRect==0.2.0
pyperclip==1.11.0
PyScreeze==1.0.1
pytweening==1.2.0
rubicon-objc==0.5.0
Expand Down
2 changes: 1 addition & 1 deletion src/_logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def setup_logging():
rotating_handler = RotatingFileHandler(
log_file,
maxBytes=2_000_000, # 2 MB before rotating
backupCount=5, # keep 5 old log files
backupCount=20, # keep 20 old log files
encoding='utf-8'
)

Expand Down
2 changes: 1 addition & 1 deletion src/_version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "1.8.1"
__version__ = "1.8.2"
16 changes: 13 additions & 3 deletions src/core/gui_root.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ def show_logs(self, _=None):
f"Platform: {platform.system()} ({platform.machine()})\n"
f"{'=' * 21}\n"
f"NOTE: logs window only refreshes when reopened.\n\n"
)
)

# Read logs from the log file if available
log_contents = ""
Expand Down Expand Up @@ -261,7 +261,7 @@ def show_logs(self, _=None):
btn_frame.columnconfigure(0, weight=1)
btn_frame.columnconfigure(1, weight=1)

def copy_logs():
def logs():
"""Read the log file and return its contents."""
try:
if os.path.exists(self.log_file_path):
Expand All @@ -271,6 +271,16 @@ def copy_logs():
return "(Log file not found)"
except Exception as e:
return f"(Failed to read log file: {e})"

def copy_logs():
"""Copy the current logs to the clipboard."""
import pyperclip # type: ignore
try:
log_text = header + logs()
pyperclip.copy(log_text)
messagebox.showinfo("Copy Logs", "Logs copied to clipboard.")
except Exception as e:
messagebox.showerror("Copy Logs", f"Failed to copy logs: {e}")

ttk.Button(btn_frame, text="Copy Logs", command=copy_logs).grid(row=0, column=0, sticky="w", padx=(8, 0))
ttk.Button(btn_frame, text="Close", command=win.destroy).grid(row=0, column=1, sticky="e", padx=(0, 8))
Expand All @@ -279,7 +289,7 @@ def copy_logs():
def refresh_logs():
"""Refresh the logs displayed in the logs window."""
try:
new_text = header + copy_logs() # Use copy_logs() to get log content
new_text = header + logs() # Use logs() to get log content
text_box.config(state="normal")
text_box.delete(1.0, "end") # Clear existing content
text_box.insert("end", new_text) # Insert new content
Expand Down
5 changes: 3 additions & 2 deletions src/core/logic/app_tracker.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import threading
import os
import psutil
import psutil # type: ignore
import sys

if os.name == 'nt':
from pywinauto import Desktop
from pywinauto.findwindows import ElementNotFoundError
windows = Desktop(backend="uia").windows()
elif sys.platform == 'darwin':
from AppKit import NSWorkspace
from AppKit import NSWorkspace # type: ignore

from core.utils.file_utils import read_file, write_file, apps_file, user_dir_exists, config_file

Expand Down Expand Up @@ -98,6 +98,7 @@ def stop(self):
if self.update_thread is not None:
try:
self.update_thread.join()
logging.info("App tracker stopped.")
except RuntimeError:
pass

Expand Down
4 changes: 2 additions & 2 deletions src/core/logic/user_trackers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"""

import threading
import pynput
import pynput # type: ignore

from core.utils.file_utils import read_file, config_file

Expand Down Expand Up @@ -68,9 +68,9 @@ def stop(self):
if self.update_thread is not None:
try:
self.update_thread.join()
logging.info("Mouse tracker stopped.")
except RuntimeError:
pass
logging.info("Mouse tracker stopped.")

def set_enabled(self, enabled=bool):
self.enabled = enabled
Expand Down
Loading