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
25 changes: 24 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ license = "GPL-3.0-or-later"

[dependencies]
iced = { version = "0.14.0", features = ["image"] }
# The shared Colony design system: themes, fonts, labels, preferences, paths.
# Built on iced 0.14 exactly, so the two move together.
colony-ui = "0.1.6"
ureq = { version = "3.4.2", features = ["json"] }
serde = { version = "1.0.229", features = ["derive"] }
serde_json = "1.0.151"
Expand Down
42 changes: 28 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ A cross-platform game library tracker and statistics dashboard built with [Rust]
- **Multi-platform imports** - Steam, GOG, Epic Games, Xbox (via OpenXBL), and PlayStation Network
- **Achievement tracking** - view and track achievements with icons, descriptions, and unlock dates
- **Statistics dashboard** - playtime charts, status/platform distribution, most played games
- **Customizable UI** - dark/darker/midnight themes, accent colors, UI scaling, sidebar width, compact mode
- **Accessibility** - high contrast mode, large click targets, status label toggles
- **Settings** - date format, notification preferences, toast duration, start screen, default status/platform
- **Customizable UI** - the shared Colony themes and accents, two text sizes, sidebar width, compact mode
- **Accessibility** - high contrast, a dyslexia-friendly font, reduced motion, large click targets, status labels
- **Preferences** - language, date format, notifications, start screen, default status/platform
- **English and French** - the interface follows the system language, or the one picked in Preferences
- **Local-first** - all data stored in a local SQLite database, no cloud dependency

## Running the binaries
Expand Down Expand Up @@ -78,29 +79,42 @@ src/
lib.rs Module tree; public modules for tests
app.rs Application state, messages, update loop
db.rs SQLite database operations
paths.rs Where Spotter's files live, and the copy from Spotter 0.3
preferences.rs preferences.json: load, save, import from Spotter 0.3
keyring.rs Platform tokens in the OS keyring
models.rs Data structures (Game, Platform, Settings, etc.)
theme.rs Color constants and ViewTheme
models.rs Data structures (Game, Platform, Preferences, etc.)
i18n/ Interface strings: en.json, fr.json and the lookup
theme.rs Icons and style helpers on the Colony palette
steam.rs Steam import + HTML scraping
steam_auth.rs Steam browser login flow
gog.rs GOG Galaxy import
epic.rs Epic Games Launcher scanner
xbox.rs Xbox Live import via OpenXBL
playstation.rs PSN import via trophy API
images.rs Cover art + achievement icon caching
views/ UI views (library, detail, stats, settings, etc.)
views/ UI views (library, detail, stats, preferences, etc.)
tests/
unit_tests.rs Unit + integration tests
```

## Data Storage

All data is stored locally:
- **Database**: `~/.local/share/spotter/spotter.db` (Linux) or equivalent `dirs::data_dir()`
- **Covers**: `~/.local/share/spotter/covers/`
- **Achievement icons**: `~/.local/share/spotter/achievement_icons/`
- **Settings**: Stored as JSON inside the SQLite database
- **Platform credentials** (API keys, login tokens): in the operating system's keyring (Windows Credential Manager, macOS Keychain, the Secret Service on Linux). Without one, they stay unencrypted in the database and the Profile page says so.
All data is stored locally, under `Colony/Spotter/` in the platform's folders:

| | Linux | Windows | macOS |
|---|---|---|---|
| Config | `~/.config/Colony/Spotter/` | `%LOCALAPPDATA%\Colony\Spotter\` | `~/Library/Application Support/Colony/Spotter/` |
| Data | `~/.local/share/Colony/Spotter/` | `%LOCALAPPDATA%\Colony\Spotter\` | `~/Library/Application Support/Colony/Spotter/` |
| Cache | `~/.cache/Colony/Spotter/` | `%LOCALAPPDATA%\Colony\Spotter\cache\` | `~/Library/Caches/Colony/Spotter/` |

- **Preferences**: `<config>/preferences/preferences.json`
- **Library database**: `<data>/library/spotter.db` (SQLite)
- **Exports and the automatic backup**: `<data>/exports/`
- **Import log**: `<data>/logs/import.log`
- **Covers and achievement icons**: `<cache>/covers/` and `<cache>/achievement_icons/`, downloaded again when deleted
- **Platform credentials** (API keys, login tokens): in the operating system's keyring (Windows Credential Manager, macOS Keychain, the Secret Service on Linux). Without one, they are kept unencrypted in `<config>/credentials/tokens.json`, readable by your user only, and the Profile page says so.

Spotter 0.3 and earlier kept everything in the config folder (`data/`, `exports/`, `logs/`, `cache/`). The first start of a newer Spotter copies the library, the exports and the log to the folders above, imports the settings from the old database into `preferences.json`, and leaves the old files where they are.

## Code signing policy

Expand All @@ -115,7 +129,7 @@ Team roles and members:

### Privacy policy

Spotter has no telemetry, no analytics and no update check, and sends nothing to its developers. Your library stays in the local database. Your platform credentials (the API keys you enter and the login tokens Spotter receives) are kept in your operating system's keyring (Windows Credential Manager, macOS Keychain, or the Secret Service on Linux, such as GNOME Keyring or KWallet); when no keyring is available, Spotter keeps them unencrypted in the local database instead, and says so on its Profile page. Spotter only contacts the services below, for the features that need them:
Spotter has no telemetry, no analytics and no update check, and sends nothing to its developers. Your library stays in the local database. Your platform credentials (the API keys you enter and the login tokens Spotter receives) are kept in your operating system's keyring (Windows Credential Manager, macOS Keychain, or the Secret Service on Linux, such as GNOME Keyring or KWallet); when no keyring is available, Spotter keeps them unencrypted in a file of its config folder that only your user can read instead, and says so on its Profile page. Spotter only contacts the services below, for the features that need them:

- **Imports, when you start one** from the Import screen. Spotter contacts the platform you picked and sends it the credentials you entered for it, plus the ids of your games:
- Steam: `api.steampowered.com` (your Web API key and Steam ID, to list owned games), `steamcommunity.com` (your Steam ID, to read achievements from your profile) and `store.steampowered.com` (game details).
Expand All @@ -124,7 +138,7 @@ Spotter has no telemetry, no analytics and no update check, and sends nothing to
- Xbox: `xbl.io` (your OpenXBL API key).
- PlayStation: `ca.account.sony.com` (your NPSSO token, exchanged for an access token), then `m.np.playstation.com` with that token.
- **Steam login**, when you use it: Spotter opens Steam's sign-in page in your browser, receives the answer on a local port of your own computer (127.0.0.1) and asks `steamcommunity.com` to confirm it.
- **Cover art and achievement icons**, downloaded from the image addresses stored with each game, which come from those platforms (or from a JSON backup you import): covers after an import, unless you turn off automatic cover downloads in Settings; achievement icons when you open a Steam game's page.
- **Cover art and achievement icons**, downloaded from the image addresses stored with each game, which come from those platforms (or from a JSON backup you import): covers after an import, unless you turn off automatic cover downloads in Preferences; achievement icons when you open a Steam game's page.
- **At startup**, if you have connected GOG or Epic Games, Spotter renews that login automatically by sending the saved refresh token to `auth.gog.com` or `account-public-service-prod.ol.epicgames.com`.

Links such as a game's store page open in your browser; Spotter itself sends nothing for them.
Expand Down
Binary file removed assets/fonts/JetBrainsMonoNerdFont-Bold.ttf
Binary file not shown.
Binary file removed assets/fonts/JetBrainsMonoNerdFont-Regular.ttf
Binary file not shown.
21 changes: 12 additions & 9 deletions docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,17 @@ app.rs (1300+ lines) State machine: Spotter struct, Message enum, update(), v
│ ├── library.rs Game list with search, filters, sort
│ ├── detail.rs Single game: metadata, achievements, rating, notes
│ ├── stats.rs Statistics dashboard with charts
│ ├── settings.rs Three-tab preferences (General / Appearances / Accessibility)
│ ├── preferences.rs Preferences page on the shared Colony kit
│ ├── profile.rs User profile, credentials, data export/import
│ ├── import.rs Platform import cards with step-by-step flows
│ ├── sidebar.rs Navigation + quick stats
│ └── add_game.rs Manual game entry form
├── models.rs Data structures: Game, Settings, Platform, Achievement, etc.
├── models.rs Data structures: Game, Preferences, Platform, Achievement, etc.
├── i18n/ English and French strings (en.json, fr.json) and t/tf/tn
├── db.rs SQLite: schema, CRUD, playtime history, export/import
├── theme.rs Color constants, ViewTheme, style helpers
├── paths.rs File locations (colony_ui::paths) and the copy from Spotter 0.3
├── preferences.rs preferences.json: lenient load, save, import from Spotter 0.3
├── theme.rs Icons and style helpers on the Colony palette
├── error.rs SpotterError enum (migration in progress)
├── api_client.rs HTTP agents, retry logic, URL encoding, browser open
├── images.rs Cover art + achievement icon download/caching
Expand Down Expand Up @@ -67,7 +70,7 @@ All state mutations pass through the `Message` enum in `app.rs`. Async operation
│ Profile ────┼───►│ Profile (credentials, export) │
│ │ │ │
│ ── Quick ── │ │ GameDetail (from library click) │
│ Playing: X │ │ Settings (from sidebar logo) │
│ Playing: X │ │ Preferences (from the Spotter name)│
│ Completed: Y│ │ │
│ Unplayed: Z │ └────────────────────────────────────┘
│ │
Expand Down Expand Up @@ -112,15 +115,15 @@ Existing user data (ratings, notes, status) is always preserved. Only empty meta

### Theme System

Two layers:
- **Static constants** (`theme.rs`): Used in style closures where `ViewTheme` isn't available
- **ViewTheme struct**: Computed per-render from `Settings`, provides theme-mode-aware colors
Colours come from colony-ui. `StandardPreferences::apply` sets the theme, accent and high contrast at startup and on every change; widgets read the active palette wherever they are drawn, including inside style closures:

```rust
let vt = ViewTheme::from_settings(&app.settings);
// vt.bg_card, vt.text_muted, vt.border, etc.
text(label).color(Palette::TEXT_MUTED())
container(content).style(theme::card_style(Palette::BG_CARD(), Palette::BORDER_SUBTLE(), 8.0))
```

Platforms and game statuses keep one colour on every theme: a shared accent swatch picked by key (`Platform::accent_key`, `GameStatus::accent_key`).

## Dependencies

| Crate | Version | Role |
Expand Down
Loading
Loading