This Python desktop application provides a calendar interface to create and manage events, with a specific feature to log time spent on Zoho Projects. It also syncs with your Google Calendar to display your events.
- Features
- Technologies Used
- Project Structure
- Key Logic Implemented
- Installation and Startup
- Initial Configuration
- Automated Build and Release
- Possible Future Improvements
- Calendar View: Displays a weekly grid from Monday to Friday, with configurable time slots.
- Complete CRUD for Events: You can Create, Read, Modify, and Delete events.
- Local Persistence: All events are saved in a local SQLite database (
events.db), ensuring that data is not lost between sessions. - Integration with Zoho Projects: For completed events, you can log time directly to Zoho Projects through a dedicated form.
- Google Calendar Sync: Automatically fetches and displays events from your primary Google Calendar.
- Immutability of Logged Events: Once an event is logged to Zoho, it is locked and can no longer be modified or deleted.
- Settings Panel: A dedicated window to securely enter and save Zoho and Google API credentials.
- Secure Credential Management: API keys are not stored in plain text but are entrusted to the operating system's credential manager.
- Python 3: Main programming language.
- CustomTkinter: Library chosen for the GUI. It offers modern widgets and a more pleasing appearance than standard Tkinter.
- SQLite 3: Database engine. SQLite was chosen because it is integrated into Python and is perfect for single-user desktop applications.
- Requests: De-facto standard library for making HTTP calls, used for all communications with the Zoho APIs.
- Keyring: A fundamental library for security. It interfaces with the native credential manager of the operating system (e.g., Windows Credential Manager, macOS Keychain) to save and retrieve sensitive data.
- Google API Client Library for Python: Used to interact with the Google Calendar API.
- PyInstaller: To create the application executable.
The code is organized in a package structure to improve maintainability and clarity.
main.py: (Root) The application's entry point.calendar_logger/: (Package) Contains all the application's source code.__init__.py: Makes the folder a Python package.app.py: The heart of the application, manages the GUI and main logic.database.py: Manages data persistence on SQLite.settings_manager.py: Manages the secure saving and loading of credentials.zoho_api.py: Contains all the logic for communicating with the Zoho APIs.google_calendar.py: Handles integration with the Google Calendar API.
scripts/: Contains accessory scripts.build.py: Script to create the application executable via PyInstaller.
.github/workflows/: Contains the CI/CD pipeline.release.yml: A GitHub Actions workflow that automatically builds and releases executables for Linux, macOS, and Windows when a new tag is pushed.
requirements.txt: Lists the Python dependencies..gitignore: Specifies the files to be ignored in version control.
The display of events is handled in the refresh_events() method in app.py. The logic is as follows:
- Cleanup: All previously drawn event widgets are destroyed to avoid duplicates.
- Fetch: All events are retrieved from the local database and Google Calendar.
- Iteration and Drawing: For each event, its position in the grid (row and column) is calculated based on date and time.
The logic resides in zoho_api.py and follows the OAuth 2.0 flow with Refresh Token.
- Token Refresh: The
refresh_access_token()function is responsible for requesting a newaccess_tokenfrom Zoho. - API Call with Automatic Retry: The
log_time_to_zoho()function is robust: it automatically retries the API call with a new token if the current one is expired.
The google_calendar.py module handles the connection to the Google Calendar API.
- OAuth 2.0 Authentication: On the first run, it guides the user through an authentication process to grant the application read-only access to their calendar.
- Token Storage: The obtained credentials are securely stored in a
token.jsonfile for subsequent sessions. - Event Fetching: The
get_events_for_weekfunction retrieves all events for the displayed week.
In settings_manager.py, the keyring library is used to never expose credentials in the code or in text files.
- Make sure you have Python 3 installed.
- It is advisable to create a virtual environment:
python -m venv venvand activate it. - Install the dependencies:
pip install -r requirements.txt. - Start the application from the project root folder:
python main.py.
To create a standalone .exe file, run the build script from the root folder:
python scripts/build.pyThe compiled application will be in dist/CalendarLogger.
To make the integrations work, follow these steps:
- Get Zoho credentials: Go to the Zoho API console (
https://api-console.zoho.eu/) and create a new Self-Client type client. This will provide you with aClient ID, aClient Secret, and aRefresh Token. - Get Google Calendar credentials:
- Go to the Google Cloud Console.
- Create a new project.
- Enable the "Google Calendar API".
- Create credentials for a "Desktop app" OAuth client.
- Download the
credentials.jsonfile and place it in thecalendar_loggerfolder.
- Start the app and click the "Settings" button.
- Enter the credentials obtained in the respective fields.
- Click "Save Settings".
This project uses GitHub Actions to automate the creation of executables for Windows, macOS, and Linux. The workflow, defined in .github/workflows/release.yml, is triggered every time a new tag (e.g., v1.0.1) is pushed to the repository.
The workflow automatically builds the executables and attaches them as assets to a new GitHub Release.
- UI for Errors: Show error messages in dialog windows instead of on the console.
- Datepicker Widget: Replace manual date entry with a calendar widget to improve usability.
- Fetch of Projects/Tasks: Instead of manually entering project and task IDs, implement API calls that retrieve the list of existing projects and tasks and show them in a dropdown menu.
- Drag and Drop: Implement moving and resizing events with the mouse.