# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview Roster is a GNOME application written in Python using GTK 4 and libadwaita. The project follows GNOME application conventions and uses the Meson build system. - **Application ID**: `cz.vesp.roster` - **Build System**: Meson - **Runtime**: GNOME Platform (org.gnome.Platform) - **UI Framework**: GTK 4 + libadwaita (Adw) - **Language**: Python 3 - **License**: GPL-3.0-or-later ## Build Commands ### Native Build ```bash # Configure the build (from project root) meson setup builddir # Build the project meson compile -C builddir # Install locally meson install -C builddir # Run tests meson test -C builddir # Clean build directory rm -rf builddir ``` ### Running the Application The application uses **libsoup3** (from GNOME Platform) for HTTP requests - no external dependencies required. ## Development with Flatpak The project includes a Flatpak manifest (`cz.vesp.roster.json`) for building and running the application in a sandboxed environment: ```bash # Build with GNOME Builder (recommended for GNOME apps) # Or use flatpak-builder directly: flatpak-builder --user --install --force-clean build-dir cz.vesp.roster.json ``` ## Architecture ### Application Structure The application follows the standard GNOME/Adwaita application pattern: - **RosterApplication** (main.py): Singleton application class inheriting from `Adw.Application` - Manages application lifecycle and actions (quit, about, preferences) - Sets up keyboard shortcuts (e.g., Ctrl+Q for quit) - Creates and presents the main window - **RosterWindow** (window.py): Main application window inheriting from `Adw.ApplicationWindow` - Defined as a GTK template class using `@Gtk.Template` decorator - UI layout loaded from `window.ui` via GResources ### Resource Management UI files are packaged into a GResource bundle: - Defined in `src/roster.gresource.xml` - Resource base path: `/cz/vesp/roster` - UI files are preprocessed with `xml-stripblanks` ### File Organization ``` src/ __init__.py # Package marker main.py # Application class and entry point window.py # Main window class window.ui # Main window UI definition (GTK Builder XML) shortcuts-dialog.ui # Keyboard shortcuts dialog roster.in # Launcher script template (configured by Meson) roster.gresource.xml # GResource bundle definition data/ cz.vesp.roster.desktop.in # Desktop entry (i18n template) cz.vesp.roster.metainfo.xml.in # AppStream metadata (i18n template) cz.vesp.roster.gschema.xml # GSettings schema cz.vesp.roster.service.in # D-Bus service file (configured by Meson) icons/ # Application icons po/ # Translation files (gettext) ``` ### Key Patterns 1. **UI Templates**: Window classes use `@Gtk.Template` decorator with `resource_path` pointing to `.ui` files in GResources. Child widgets are accessed via `Gtk.Template.Child()`. 2. **Actions**: Application actions are created with the `create_action()` helper method, which sets up actions and optional keyboard shortcuts. 3. **Internationalization**: Uses gettext with domain "roster". Template files (`.in`) are processed through `i18n.merge_file()` during build. 4. **Configuration Data**: Meson substitutes variables in `.in` files using `configuration_data()` (e.g., paths, version). 5. **Module Installation**: Python modules are installed to `{datadir}/roster/roster/` and the launcher script is configured with the correct Python interpreter path. ## Adding New Python Modules When adding new `.py` files to `src/`: 1. Add the filename to `roster_sources` list in `src/meson.build` 2. Import in `main.py` or other modules as needed ## Adding New UI Files When adding new `.ui` files: 1. Place in `src/` directory 2. Add `` entry to `src/roster.gresource.xml` 3. Use `@Gtk.Template(resource_path='/cz/vesp/roster/filename.ui')` in the corresponding Python class ## GSettings Schema Settings are defined in `data/cz.vesp.roster.gschema.xml`. After modifying: - Schema is validated during `meson test` - Compiled automatically during installation via `gnome.post_install()`