diff --git a/.gitea/workflows/android-release.yml b/.gitea/workflows/android-release.yml
index ac1ba40..45f9b3b 100644
--- a/.gitea/workflows/android-release.yml
+++ b/.gitea/workflows/android-release.yml
@@ -10,9 +10,9 @@ env:
NDK_VERSION: 30.0.14904198
BUILD_TOOLS_VERSION: "36.1.0"
PLATFORM: android-34
- APK_OUT: target/release/apk/solitaire-quest.apk
+ APK_OUT: target/release/apk/ferrous-solitaire.apk
GITEA_URL: https://git.aleshym.co
- REPO: funman300/Rusty_Solitare
+ REPO: funman300/Ferrous-Solitaire
jobs:
build-apk:
@@ -106,7 +106,7 @@ jobs:
-d "{
\"tag_name\": \"$TAG\",
\"name\": \"$TAG\",
- \"body\": \"## Android release $TAG\n\n**Install / update with Obtainium** — add this source URL:\n\`\`\`\nhttps://git.aleshym.co/funman300/Rusty_Solitare\n\`\`\`\n\nOr download \`solitaire-quest.apk\` below and sideload it directly.\",
+ \"body\": \"## Android release $TAG\n\n**Install / update with Obtainium** — add this source URL:\n\`\`\`\nhttps://git.aleshym.co/funman300/Ferrous-Solitaire\n\`\`\`\n\nOr download \`ferrous-solitaire.apk\` below and sideload it directly.\",
\"draft\": false,
\"prerelease\": false
}" \
diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md
index 1e1d91c..8f8b3b5 100644
--- a/ARCHITECTURE.md
+++ b/ARCHITECTURE.md
@@ -58,7 +58,7 @@ Pure-core, no-panics-in-game-logic, and UI-first-interaction constraints are enf
## 2. Workspace Structure
```
-solitaire_quest/
+ferrous_solitaire/
│
├── Cargo.toml # Workspace manifest
├── .env.example # Server environment variable template
@@ -366,12 +366,12 @@ Minimum window: 800×600. At this size cards are small but usable.
### Local Storage
-All files stored under `dirs::data_dir() / "solitaire_quest"/`:
+All files stored under `dirs::data_dir() / "ferrous_solitaire"/`:
```
-~/.local/share/solitaire_quest/ (Linux)
-~/Library/Application Support/solitaire_quest/ (macOS)
-%APPDATA%\solitaire_quest\ (Windows)
+~/.local/share/ferrous_solitaire/ (Linux)
+~/Library/Application Support/ferrous_solitaire/ (macOS)
+%APPDATA%\ferrous_solitaire\ (Windows)
│
├── stats.json # StatsSnapshot
├── progress.json # PlayerProgress (XP, level, unlocks, daily challenge)
@@ -426,7 +426,7 @@ pub enum SyncBackend {
url: String,
username: String,
// JWT access + refresh tokens stored in OS keychain
- // key: "solitaire_quest_server_{username}"
+ // key: "ferrous_solitaire_server_{username}"
},
}
```
@@ -980,8 +980,8 @@ Add `--features bevy/dynamic_linking` during development to dramatically reduce
### Docker Compose (Recommended)
```bash
-git clone https://github.com/yourname/solitaire_quest
-cd solitaire_quest
+git clone https://github.com/yourname/ferrous_solitaire
+cd ferrous_solitaire
cp .env.example .env
# Edit .env — set JWT_SECRET and SERVER_PORT
docker compose up -d
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8141cf1..5ae186e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1431,7 +1431,7 @@ candidate — the app-icon round — stays open.
- **Android build target — first working APK** (`fb8b2ac`).
`cargo apk build -p solitaire_app --target x86_64-linux-android`
now produces a 54 MB debug-signed APK at
- `target/debug/apk/solitaire-quest.apk`. Five gating points
+ `target/debug/apk/ferrous-solitaire.apk`. Five gating points
resolved end-to-end:
- **`solitaire_app` split into bin + lib.** cargo-apk needs a
`cdylib` to bundle as `libmain.so`; pure-bin crates panic
@@ -1548,7 +1548,7 @@ candidate — the app-icon round — stays open.
achievements, replays, game-state, time-attack sessions, user
themes). New `solitaire_data::platform::data_dir()` shim falls
through to `dirs::data_dir()` on desktop and returns the per-app
- sandbox at `/data/data/com.solitairequest.app/files` on Android
+ sandbox at `/data/data/com.ferrousapp.solitaire/files` on Android
— no JNI needed, since the package id is pinned in
`[package.metadata.android]`. Six call sites across
`solitaire_data` plus `solitaire_engine/assets/user_dir.rs`
@@ -1690,7 +1690,7 @@ fully reverted and is not part of this release.
The test's single-frame `app.update()` was sensitive to
first-frame `Time::delta_secs()` variance under heavy parallel
cargo-test load, and to production-disk
- `~/.local/share/solitaire_quest/game_state.json` state leaking
+ `~/.local/share/ferrous_solitaire/game_state.json` state leaking
into the test world via `GamePlugin::build`'s load path.
`test_app` now resets `PendingRestoredGame(None)` after plugin
build (preventing the dev machine's saved-game state from
@@ -2386,7 +2386,7 @@ the binary shipped with bundled artwork.
patterns.
- **Ambient audio loop** wired through the kira mixer.
- **Arch Linux PKGBUILDs** for the game client and sync server (under
- the separate `solitaire-quest-pkgbuild` directory).
+ the separate `ferrous-solitaire-pkgbuild` directory).
- **Workspace README, CI workflow, migration guide.**
### Changed
diff --git a/CLAUDE.md b/CLAUDE.md
index 233cade..ceba491 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -447,7 +447,7 @@ raw `z_index` values — they drift and cause ordering bugs.
```bash
cargo apk build --package solitaire_app --lib
-adb install -r target/debug/apk/solitaire-quest.apk
+adb install -r target/debug/apk/ferrous-solitaire.apk
```
## 15.2 Coordinate system reminder
diff --git a/README.md b/README.md
index 74e42a3..592d796 100644
--- a/README.md
+++ b/README.md
@@ -38,16 +38,16 @@ optional self-hosted sync so your stats follow you across machines.
1. Install [Obtainium](https://github.com/ImranR98/Obtainium/releases) on your device
2. Tap the badge below (on your Android device) or add the URL manually:
- [
](https://apps.obtainium.imranr.dev/redirect?r=obtainium://add/https://git.aleshym.co/funman300/Rusty_Solitare)
+ [
](https://apps.obtainium.imranr.dev/redirect?r=obtainium://add/https://git.aleshym.co/funman300/Ferrous-Solitaire)
- Manual URL: `https://git.aleshym.co/funman300/Rusty_Solitare`
+ Manual URL: `https://git.aleshym.co/funman300/Ferrous-Solitaire`
3. Tap **Install** to download the current release — Obtainium will notify you when updates are available.
### Direct APK
-Download the latest `solitaire-quest.apk` from the
-[Releases](https://git.aleshym.co/funman300/Rusty_Solitare/releases) page,
+Download the latest `ferrous-solitaire.apk` from the
+[Releases](https://git.aleshym.co/funman300/Ferrous-Solitaire/releases) page,
enable **Install from unknown sources** in your device settings, and open the file.
## Building
diff --git a/argocd/application.yaml b/argocd/application.yaml
index d62d673..b0a279f 100644
--- a/argocd/application.yaml
+++ b/argocd/application.yaml
@@ -6,7 +6,7 @@ metadata:
spec:
project: default
source:
- repoURL: https://git.aleshym.co/funman300/Rusty_Solitare.git
+ repoURL: https://git.aleshym.co/funman300/Ferrous-Solitaire.git
targetRevision: master
path: deploy
destination:
diff --git a/docs/ANDROID.md b/docs/ANDROID.md
index 55ff451..91f0fb6 100644
--- a/docs/ANDROID.md
+++ b/docs/ANDROID.md
@@ -6,7 +6,7 @@ later sections document what's known to compile, what's stubbed, and
the next milestones.
> **Status (2026-05-07):** First working APK at `fb8b2ac`. 54 MB
-> debug-signed `solitaire-quest.apk` for `x86_64-linux-android`. Has
+> debug-signed `ferrous-solitaire.apk` for `x86_64-linux-android`. Has
> NOT yet been verified to launch on a device or emulator — that's
> the next milestone.
@@ -121,7 +121,7 @@ cargo apk build -p solitaire_app --target x86_64-linux-android
Output:
```
-target/debug/apk/solitaire-quest.apk
+target/debug/apk/ferrous-solitaire.apk
```
Targets shipped via `[package.metadata.android].build_targets` in
@@ -164,8 +164,8 @@ Physical device:
```bash
adb devices # confirm connection
-adb install target/debug/apk/solitaire-quest.apk
-adb shell am start -n com.solitairequest.app/android.app.NativeActivity
+adb install target/debug/apk/ferrous-solitaire.apk
+adb shell am start -n com.ferrousapp.solitaire/android.app.NativeActivity
adb logcat | grep -iE "RustStdoutStderr|solitaire|panic"
```
@@ -174,7 +174,7 @@ Emulator:
```bash
emulator -avd bevy_test -no-window -gpu swiftshader_indirect &
adb wait-for-device
-adb install target/debug/apk/solitaire-quest.apk
+adb install target/debug/apk/ferrous-solitaire.apk
# ... same start + logcat steps as above.
```
@@ -203,7 +203,7 @@ What's NOT yet ported / not yet measured:
- `dirs::data_dir()` returns `None` on Android. Callers in
`solitaire_data/src/storage.rs`, `progress.rs`, `replay.rs`,
`achievements.rs`, `settings.rs` all need an Android-aware
- helper (likely `/data/data/com.solitairequest.app/files`).
+ helper (likely `/data/data/com.ferrousapp.solitaire/files`).
- Touch UX pass — hit-target sizes, modal scaling on small screens,
app lifecycle (suspend / resume), font scaling.
- Android Keystore via JNI for `auth_tokens`.
@@ -221,8 +221,8 @@ cargo build -p solitaire_app # desktop sanity
cargo clippy --workspace --all-targets -- -D warnings # gate
cargo test --workspace # gate
cargo apk build -p solitaire_app --target x86_64-linux-android --lib
-adb install -r target/debug/apk/solitaire-quest.apk # `-r` reinstalls
-adb logcat -c && adb shell am start -n com.solitairequest.app/android.app.NativeActivity
+adb install -r target/debug/apk/ferrous-solitaire.apk # `-r` reinstalls
+adb logcat -c && adb shell am start -n com.ferrousapp.solitaire/android.app.NativeActivity
adb logcat | grep -iE "RustStdoutStderr|solitaire"
```
diff --git a/docs/sync_test_runbook.md b/docs/sync_test_runbook.md
index d828568..3e31ba7 100644
--- a/docs/sync_test_runbook.md
+++ b/docs/sync_test_runbook.md
@@ -39,13 +39,13 @@ Before starting, delete any existing local save files to ensure a clean state:
```
# Linux
-rm -rf ~/.local/share/solitaire_quest/
+rm -rf ~/.local/share/ferrous_solitaire/
# macOS
-rm -rf ~/Library/Application\ Support/solitaire_quest/
+rm -rf ~/Library/Application\ Support/ferrous_solitaire/
# Windows
-rmdir /s %APPDATA%\solitaire_quest\
+rmdir /s %APPDATA%\ferrous_solitaire\
```
---
@@ -130,10 +130,10 @@ On the machine where you want to test (Linux example):
```bash
# List keychain entries (uses secret-tool on GNOME)
-secret-tool search service solitaire_quest_server
+secret-tool search service ferrous_solitaire_server
# Overwrite alice's access token with a deliberately invalid value
-secret-tool store --label="alice_access" service solitaire_quest_server account alice_access <<< "invalid.token.value"
+secret-tool store --label="alice_access" service ferrous_solitaire_server account alice_access <<< "invalid.token.value"
```
### Step 2 — Trigger a sync with the expired/invalid token
@@ -148,7 +148,7 @@ secret-tool store --label="alice_access" service solitaire_quest_server account
```bash
# Extract the new token from the keychain
-secret-tool lookup service solitaire_quest_server account alice_access | head -c 50
+secret-tool lookup service ferrous_solitaire_server account alice_access | head -c 50
# Should look like a valid JWT (three base64 segments separated by dots)
```
@@ -157,8 +157,8 @@ secret-tool lookup service solitaire_quest_server account alice_access | head -c
1. Corrupt both the access token and the refresh token in the keychain:
```bash
- secret-tool store --label="alice_access" service solitaire_quest_server account alice_access <<< "bad"
- secret-tool store --label="alice_refresh" service solitaire_quest_server account alice_refresh <<< "bad"
+ secret-tool store --label="alice_access" service ferrous_solitaire_server account alice_access <<< "bad"
+ secret-tool store --label="alice_refresh" service ferrous_solitaire_server account alice_refresh <<< "bad"
```
2. Launch the game and trigger a sync.
diff --git a/pkg/solitaire-quest-server/PKGBUILD b/pkg/ferrous-solitaire-server/PKGBUILD
similarity index 72%
rename from pkg/solitaire-quest-server/PKGBUILD
rename to pkg/ferrous-solitaire-server/PKGBUILD
index 145876f..2c40491 100644
--- a/pkg/solitaire-quest-server/PKGBUILD
+++ b/pkg/ferrous-solitaire-server/PKGBUILD
@@ -1,10 +1,10 @@
# Maintainer: funman300
-pkgname=solitaire-quest-server
+pkgname=ferrous-solitaire-server
pkgver=0.1.0
pkgrel=1
-pkgdesc='Self-hosted sync server for Solitaire Quest (stats, achievements, leaderboards)'
-url='https://github.com/funman300/solitaire-quest'
+pkgdesc='Self-hosted sync server for Ferrous Solitaire (stats, achievements, leaderboards)'
+url='https://github.com/funman300/ferrous-solitaire'
license=('MIT')
arch=('x86_64')
makedepends=('cargo' 'rust')
@@ -12,12 +12,12 @@ depends=(
'gcc-libs'
'glibc'
)
-backup=('etc/solitaire-quest-server/server.env')
+backup=('etc/ferrous-solitaire-server/server.env')
# Build from the local workspace (two levels above this PKGBUILD).
_srcdir="$startdir/../.."
source=(
- 'solitaire-quest-server.service'
+ 'ferrous-solitaire-server.service'
'server.env'
)
b2sums=('SKIP'
@@ -49,12 +49,12 @@ package() {
install -Dm0755 -t "$pkgdir/usr/bin/" "target/release/solitaire_server"
# systemd service
- install -Dm0644 "$srcdir/solitaire-quest-server.service" \
- "$pkgdir/usr/lib/systemd/system/solitaire-quest-server.service"
+ install -Dm0644 "$srcdir/ferrous-solitaire-server.service" \
+ "$pkgdir/usr/lib/systemd/system/ferrous-solitaire-server.service"
# Environment file (contains JWT_SECRET, DATABASE_URL, SERVER_PORT)
install -Dm0640 "$srcdir/server.env" \
- "$pkgdir/etc/solitaire-quest-server/server.env"
+ "$pkgdir/etc/ferrous-solitaire-server/server.env"
# License and docs
install -Dm0644 LICENSE "$pkgdir/usr/share/licenses/$pkgname/LICENSE"
diff --git a/pkg/ferrous-solitaire-server/ferrous-solitaire-server.service b/pkg/ferrous-solitaire-server/ferrous-solitaire-server.service
new file mode 100644
index 0000000..30a8577
--- /dev/null
+++ b/pkg/ferrous-solitaire-server/ferrous-solitaire-server.service
@@ -0,0 +1,23 @@
+[Unit]
+Description=Ferrous Solitaire Sync Server
+Documentation=https://github.com/funman300/ferrous-solitaire/blob/main/README_SERVER.md
+After=network.target
+
+[Service]
+Type=simple
+User=ferrous-solitaire
+Group=ferrous-solitaire
+EnvironmentFile=/etc/ferrous-solitaire-server/server.env
+ExecStart=/usr/bin/solitaire_server
+Restart=on-failure
+RestartSec=5s
+
+# Harden the service
+NoNewPrivileges=true
+PrivateTmp=true
+ProtectSystem=strict
+ProtectHome=true
+ReadWritePaths=/var/lib/ferrous-solitaire-server
+
+[Install]
+WantedBy=multi-user.target
diff --git a/pkg/solitaire-quest-server/server.env b/pkg/ferrous-solitaire-server/server.env
similarity index 54%
rename from pkg/solitaire-quest-server/server.env
rename to pkg/ferrous-solitaire-server/server.env
index 2b0afbe..f2fb3fa 100644
--- a/pkg/solitaire-quest-server/server.env
+++ b/pkg/ferrous-solitaire-server/server.env
@@ -1,10 +1,10 @@
-# Solitaire Quest Server — environment configuration
-# This file is installed to /etc/solitaire-quest-server/server.env (mode 0640).
+# Ferrous Solitaire Server — environment configuration
+# This file is installed to /etc/ferrous-solitaire-server/server.env (mode 0640).
# Edit these values before starting the service.
# Path to the SQLite database file.
-# The directory must be writable by the solitaire-quest service user.
-DATABASE_URL=sqlite:///var/lib/solitaire-quest-server/solitaire.db
+# The directory must be writable by the ferrous-solitaire service user.
+DATABASE_URL=sqlite:///var/lib/ferrous-solitaire-server/solitaire.db
# HS256 signing secret for JWT tokens.
# Generate a strong secret with: openssl rand -hex 32
diff --git a/pkg/solitaire-quest/PKGBUILD b/pkg/ferrous-solitaire/PKGBUILD
similarity index 93%
rename from pkg/solitaire-quest/PKGBUILD
rename to pkg/ferrous-solitaire/PKGBUILD
index 43b3229..8cc34cb 100644
--- a/pkg/solitaire-quest/PKGBUILD
+++ b/pkg/ferrous-solitaire/PKGBUILD
@@ -1,10 +1,10 @@
# Maintainer: funman300
-pkgname=solitaire-quest
+pkgname=ferrous-solitaire
pkgver=0.1.0
pkgrel=1
pkgdesc='Cross-platform Klondike Solitaire with progression, achievements, and optional sync'
-url='https://github.com/funman300/solitaire-quest'
+url='https://github.com/funman300/ferrous-solitaire'
license=('MIT')
arch=('x86_64')
makedepends=('cargo' 'rust')
diff --git a/pkg/solitaire-quest-server/solitaire-quest-server.service b/pkg/solitaire-quest-server/solitaire-quest-server.service
deleted file mode 100644
index 8f1c7c7..0000000
--- a/pkg/solitaire-quest-server/solitaire-quest-server.service
+++ /dev/null
@@ -1,23 +0,0 @@
-[Unit]
-Description=Solitaire Quest Sync Server
-Documentation=https://github.com/funman300/solitaire-quest/blob/main/README_SERVER.md
-After=network.target
-
-[Service]
-Type=simple
-User=solitaire-quest
-Group=solitaire-quest
-EnvironmentFile=/etc/solitaire-quest-server/server.env
-ExecStart=/usr/bin/solitaire_server
-Restart=on-failure
-RestartSec=5s
-
-# Harden the service
-NoNewPrivileges=true
-PrivateTmp=true
-ProtectSystem=strict
-ProtectHome=true
-ReadWritePaths=/var/lib/solitaire-quest-server
-
-[Install]
-WantedBy=multi-user.target
diff --git a/scripts/build_android_apk.sh b/scripts/build_android_apk.sh
index e375e50..f11ad78 100755
--- a/scripts/build_android_apk.sh
+++ b/scripts/build_android_apk.sh
@@ -18,7 +18,7 @@
# "arm64-v8a armeabi-v7a x86_64"). Reduce in CI to
# fit the runner's disk budget — a full three-ABI
# debug build can exceed 25 GB of target/ output.
-# APK_OUT Output APK path (default: target/$PROFILE/apk/solitaire-quest.apk)
+# APK_OUT Output APK path (default: target/$PROFILE/apk/ferrous-solitaire.apk)
# KEYSTORE Path to keystore for signing (default: generates a debug keystore)
# KEYSTORE_PASS Keystore password (default: "android" for the generated debug keystore)
# KEY_ALIAS Key alias (default: "androiddebugkey")
@@ -35,7 +35,7 @@ set -euo pipefail
PROFILE="${PROFILE:-debug}"
ABIS="${ABIS:-arm64-v8a armeabi-v7a x86_64}"
-APK_OUT="${APK_OUT:-target/${PROFILE}/apk/solitaire-quest.apk}"
+APK_OUT="${APK_OUT:-target/${PROFILE}/apk/ferrous-solitaire.apk}"
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$REPO_ROOT"
diff --git a/solitaire_app/Cargo.toml b/solitaire_app/Cargo.toml
index ed6e2bd..2556920 100644
--- a/solitaire_app/Cargo.toml
+++ b/solitaire_app/Cargo.toml
@@ -56,8 +56,8 @@ tiny-skia = { workspace = true }
# already uses ships into the APK without copy-tree gymnastics.
# `apk_name` keeps the output filename predictable across machines.
[package.metadata.android]
-package = "com.solitairequest.app"
-apk_name = "solitaire-quest"
+package = "com.ferrousapp.solitaire"
+apk_name = "ferrous-solitaire"
build_targets = ["aarch64-linux-android", "armv7-linux-androideabi", "x86_64-linux-android"]
assets = "../assets"
# Density-bucketed launcher icons. `aapt` processes `res/mipmap-*/` and
diff --git a/solitaire_app/android/AndroidManifest.xml b/solitaire_app/android/AndroidManifest.xml
index ceb25bc..f814f93 100644
--- a/solitaire_app/android/AndroidManifest.xml
+++ b/solitaire_app/android/AndroidManifest.xml
@@ -13,7 +13,7 @@
shared object name without the `lib` prefix or `.so` suffix.
-->
diff --git a/solitaire_app/src/lib.rs b/solitaire_app/src/lib.rs
index 46d7178..16512a5 100644
--- a/solitaire_app/src/lib.rs
+++ b/solitaire_app/src/lib.rs
@@ -109,7 +109,7 @@ pub fn run() {
title: "Ferrous Solitaire".into(),
// X11/Wayland WM_CLASS so taskbar managers group
// multiple windows of this app correctly.
- name: Some("solitaire-quest".into()),
+ name: Some("ferrous-solitaire".into()),
resolution: window_resolution,
position: window_position,
// AutoNoVsync prefers Mailbox (triple-buffered) and
diff --git a/solitaire_data/src/achievements.rs b/solitaire_data/src/achievements.rs
index b6aca92..40cdaa7 100644
--- a/solitaire_data/src/achievements.rs
+++ b/solitaire_data/src/achievements.rs
@@ -10,7 +10,7 @@ use std::path::{Path, PathBuf};
pub use solitaire_sync::AchievementRecord;
-const APP_DIR_NAME: &str = "solitaire_quest";
+const APP_DIR_NAME: &str = "ferrous_solitaire";
const FILE_NAME: &str = "achievements.json";
/// Platform-specific default path for `achievements.json`.
diff --git a/solitaire_data/src/android_keystore.rs b/solitaire_data/src/android_keystore.rs
index 457ac40..46995dd 100644
--- a/solitaire_data/src/android_keystore.rs
+++ b/solitaire_data/src/android_keystore.rs
@@ -19,7 +19,7 @@ use std::path::PathBuf;
use crate::auth_tokens::TokenError;
-const KEY_ALIAS: &str = "solitaire_quest_token_key";
+const KEY_ALIAS: &str = "ferrous_solitaire_token_key";
#[derive(Serialize, Deserialize)]
struct TokenBlob {
diff --git a/solitaire_data/src/auth_tokens.rs b/solitaire_data/src/auth_tokens.rs
index d638e29..b9ff173 100644
--- a/solitaire_data/src/auth_tokens.rs
+++ b/solitaire_data/src/auth_tokens.rs
@@ -1,6 +1,6 @@
//! Secure storage for JWT access and refresh tokens using the OS keychain.
//!
-//! Tokens are stored under service name `"solitaire_quest_server"` with entry
+//! Tokens are stored under service name `"ferrous_solitaire_server"` with entry
//! keys `"{username}_access"` and `"{username}_refresh"`.
//!
//! On Linux this requires a running secret service (GNOME Keyring / KWallet).
@@ -46,7 +46,7 @@ pub enum TokenError {
/// Service name used to namespace all keychain entries for this application.
#[cfg(not(target_os = "android"))]
-const SERVICE: &str = "solitaire_quest_server";
+const SERVICE: &str = "ferrous_solitaire_server";
/// Map a `keyring_core::Error` to the appropriate `TokenError`.
#[cfg(not(target_os = "android"))]
diff --git a/solitaire_data/src/platform.rs b/solitaire_data/src/platform.rs
index a8bd36c..47777ef 100644
--- a/solitaire_data/src/platform.rs
+++ b/solitaire_data/src/platform.rs
@@ -3,7 +3,7 @@
//! The rest of `solitaire_data` (settings, stats, achievements,
//! replays, progress, game state) and the engine's user-themes
//! discovery all need a base path under which to nest
-//! `solitaire_quest/`. On desktop the right answer is
+//! `ferrous_solitaire/`. On desktop the right answer is
//! `dirs::data_dir()` (which resolves to platform-appropriate
//! locations: `~/.local/share` on Linux, `~/Library/Application
//! Support` on macOS, `%APPDATA%` on Windows). On Android the
@@ -12,9 +12,9 @@
//!
//! [`data_dir`] is a thin shim that returns the right base path
//! per target. Callers continue to append
-//! `solitaire_quest/` themselves, so the on-disk layout is
+//! `ferrous_solitaire/` themselves, so the on-disk layout is
//! identical across platforms (the per-app Android sandbox makes
-//! the extra `solitaire_quest/` segment harmless, and a `tar`
+//! the extra `ferrous_solitaire/` segment harmless, and a `tar`
//! export from one platform deserialises cleanly on another).
//!
//! # Why hardcode on Android?
@@ -24,7 +24,7 @@
//! `AndroidApp` context through Bevy's startup hooks and a
//! per-call JNI bridge — meaningfully more code than the
//! sandbox-guaranteed `/data/data//files` path. The
-//! package name `com.solitairequest.app` is fixed at compile
+//! package name `com.ferrousapp.solitaire` is fixed at compile
//! time in `solitaire_app/Cargo.toml`'s
//! `[package.metadata.android]` block, so a hardcoded path is
//! safe until that ever changes (at which point this constant
@@ -40,14 +40,14 @@ use std::path::PathBuf;
/// constant and the Cargo metadata together if the package id
/// ever changes.
#[cfg(target_os = "android")]
-const ANDROID_APP_FILES_DIR: &str = "/data/data/com.solitairequest.app/files";
+const ANDROID_APP_FILES_DIR: &str = "/data/data/com.ferrousapp.solitaire/files";
/// Returns the per-user data directory for the current target,
/// or `None` if the platform doesn't expose one (rare; usually
/// indicates a broken `$HOME` or `$XDG_*` configuration on a
/// minimal Linux container).
///
-/// Callers append `solitaire_quest/` themselves. See the
+/// Callers append `ferrous_solitaire/` themselves. See the
/// module-level doc comment for the per-platform behaviour and
/// why Android uses a hardcoded path.
pub fn data_dir() -> Option {
@@ -87,6 +87,6 @@ mod tests {
#[test]
fn data_dir_returns_sandbox_path_on_android() {
let dir = data_dir().expect("android must report a data dir");
- assert_eq!(dir, PathBuf::from("/data/data/com.solitairequest.app/files"));
+ assert_eq!(dir, PathBuf::from("/data/data/com.ferrousapp.solitaire/files"));
}
}
diff --git a/solitaire_data/src/progress.rs b/solitaire_data/src/progress.rs
index a3cc95b..9dccdf3 100644
--- a/solitaire_data/src/progress.rs
+++ b/solitaire_data/src/progress.rs
@@ -14,7 +14,7 @@ use chrono::{Datelike, NaiveDate};
pub use solitaire_sync::progress::level_for_xp;
pub use solitaire_sync::PlayerProgress;
-const APP_DIR_NAME: &str = "solitaire_quest";
+const APP_DIR_NAME: &str = "ferrous_solitaire";
const FILE_NAME: &str = "progress.json";
/// Deterministic seed derived from a date, identical for all players globally.
diff --git a/solitaire_data/src/replay.rs b/solitaire_data/src/replay.rs
index 3b4e3bd..82d97a3 100644
--- a/solitaire_data/src/replay.rs
+++ b/solitaire_data/src/replay.rs
@@ -1,7 +1,7 @@
//! Win-game replay recording + storage.
//!
//! When a player wins, the engine freezes the in-memory recording into a
-//! [`Replay`] and persists it to `/solitaire_quest/latest_replay.json`
+//! [`Replay`] and persists it to `/ferrous_solitaire/latest_replay.json`
//! via [`save_latest_replay_to`]. The Stats screen offers a "Watch replay"
//! action that loads it via [`load_latest_replay_from`] so the player can
//! revisit (or, in a future build, watch the engine re-execute) the path
@@ -29,7 +29,7 @@ use serde::{Deserialize, Serialize};
use solitaire_core::game_state::{DrawMode, GameMode};
use solitaire_core::pile::PileType;
-const APP_DIR_NAME: &str = "solitaire_quest";
+const APP_DIR_NAME: &str = "ferrous_solitaire";
const LATEST_REPLAY_FILE_NAME: &str = "latest_replay.json";
const REPLAY_HISTORY_FILE_NAME: &str = "replays.json";
@@ -221,7 +221,7 @@ impl Replay {
/// Rolling history of the player's most recent winning replays.
///
/// Stored as a single JSON file at
-/// `/solitaire_quest/replays.json` (see
+/// `/ferrous_solitaire/replays.json` (see
/// [`replay_history_path`]). Capped at [`REPLAY_HISTORY_CAP`] entries —
/// when [`append_replay_to_history`] pushes past the cap, the oldest
/// entry is dropped so the file never grows unbounded.
diff --git a/solitaire_data/src/settings.rs b/solitaire_data/src/settings.rs
index c4beaa9..ab27a9b 100644
--- a/solitaire_data/src/settings.rs
+++ b/solitaire_data/src/settings.rs
@@ -11,7 +11,7 @@ use std::path::{Path, PathBuf};
use serde::{Deserialize, Serialize};
use solitaire_core::game_state::{DifficultyLevel, DrawMode};
-const APP_DIR_NAME: &str = "solitaire_quest";
+const APP_DIR_NAME: &str = "ferrous_solitaire";
const SETTINGS_FILE_NAME: &str = "settings.json";
/// Animation playback speed for card transitions.
diff --git a/solitaire_data/src/storage.rs b/solitaire_data/src/storage.rs
index 0da45f8..e2d7a14 100644
--- a/solitaire_data/src/storage.rs
+++ b/solitaire_data/src/storage.rs
@@ -13,7 +13,7 @@ use solitaire_core::game_state::{GameState, GAME_STATE_SCHEMA_VERSION};
use crate::stats::StatsSnapshot;
-const APP_DIR_NAME: &str = "solitaire_quest";
+const APP_DIR_NAME: &str = "ferrous_solitaire";
const STATS_FILE_NAME: &str = "stats.json";
const GAME_STATE_FILE_NAME: &str = "game_state.json";
const TIME_ATTACK_SESSION_FILE_NAME: &str = "time_attack_session.json";
diff --git a/solitaire_engine/src/assets/user_dir.rs b/solitaire_engine/src/assets/user_dir.rs
index d31dcaa..22e1a8f 100644
--- a/solitaire_engine/src/assets/user_dir.rs
+++ b/solitaire_engine/src/assets/user_dir.rs
@@ -29,7 +29,7 @@ static USER_THEME_DIR_OVERRIDE: OnceLock = OnceLock::new();
/// Sub-folder under `dirs::data_dir()` where the project keeps every
/// per-user file. Matches the existing convention used by
/// `solitaire_data` for `settings.json`, `stats.json`, etc.
-const APP_DIR_NAME: &str = "solitaire_quest";
+const APP_DIR_NAME: &str = "ferrous_solitaire";
/// Sub-folder under [`APP_DIR_NAME`] dedicated to user themes.
const THEME_DIR_NAME: &str = "themes";
@@ -97,19 +97,19 @@ mod tests {
use super::*;
#[test]
- fn user_theme_dir_for_appends_solitaire_quest_themes() {
+ fn user_theme_dir_for_appends_ferrous_solitaire_themes() {
let dir = user_theme_dir_for(PathBuf::from("/tmp/data"));
assert_eq!(
dir,
- PathBuf::from("/tmp/data/solitaire_quest/themes"),
- "user dir must nest under solitaire_quest/themes"
+ PathBuf::from("/tmp/data/ferrous_solitaire/themes"),
+ "user dir must nest under ferrous_solitaire/themes"
);
}
#[test]
fn user_theme_dir_for_handles_empty_root() {
let dir = user_theme_dir_for(PathBuf::new());
- assert_eq!(dir, PathBuf::from("solitaire_quest/themes"));
+ assert_eq!(dir, PathBuf::from("ferrous_solitaire/themes"));
}
#[test]
diff --git a/solitaire_engine/src/game_plugin.rs b/solitaire_engine/src/game_plugin.rs
index 3295aff..77ebb2a 100644
--- a/solitaire_engine/src/game_plugin.rs
+++ b/solitaire_engine/src/game_plugin.rs
@@ -1302,7 +1302,7 @@ mod tests {
/// Build a minimal headless `App` with just `GamePlugin` installed.
/// Disables persistence and overrides the seed so tests are deterministic
- /// and don't touch `~/.local/share/solitaire_quest/game_state.json`.
+ /// and don't touch `~/.local/share/ferrous_solitaire/game_state.json`.
fn test_app(seed: u64) -> App {
let mut app = App::new();
app.add_plugins(MinimalPlugins).add_plugins(GamePlugin);
@@ -1316,7 +1316,7 @@ mod tests {
// can't leak into per-test world state and trip the
// `pending.0.is_some()` guard in `auto_save_game_state` /
// `save_game_state_on_exit`. Without this clear, an
- // unrelated `~/.local/share/solitaire_quest/game_state.json`
+ // unrelated `~/.local/share/ferrous_solitaire/game_state.json`
// would silently disable the auto-save path under test.
app.insert_resource(PendingRestoredGame(None));
// Override the system-time seed with a known value.
diff --git a/solitaire_engine/src/replay_playback.rs b/solitaire_engine/src/replay_playback.rs
index 8ae4064..97924c5 100644
--- a/solitaire_engine/src/replay_playback.rs
+++ b/solitaire_engine/src/replay_playback.rs
@@ -552,7 +552,7 @@ mod tests {
.add_plugins(GamePlugin::headless())
.add_plugins(ReplayPlaybackPlugin);
// Disable game-state persistence so tests don't touch the
- // real ~/.local/share/solitaire_quest/game_state.json.
+ // real ~/.local/share/ferrous_solitaire/game_state.json.
app.insert_resource(crate::game_plugin::GameStatePath(None));
app.insert_resource(crate::game_plugin::ReplayPath(None));
// Tick once so any startup systems flush before the first
diff --git a/solitaire_engine/src/stats_plugin.rs b/solitaire_engine/src/stats_plugin.rs
index 2fc524f..f968624 100644
--- a/solitaire_engine/src/stats_plugin.rs
+++ b/solitaire_engine/src/stats_plugin.rs
@@ -64,7 +64,7 @@ pub struct StatsCell;
/// Resource holding the rolling [`ReplayHistory`] of recent winning
/// replays.
///
-/// Populated from `/solitaire_quest/replays.json` at startup
+/// Populated from `/ferrous_solitaire/replays.json` at startup
/// and refreshed in-place whenever the engine writes a new winning
/// replay so the Stats overlay's selector always reflects the current
/// on-disk history.
@@ -166,7 +166,7 @@ impl Default for StatsPlugin {
impl StatsPlugin {
/// Plugin configured with no persistence. Use in tests and headless apps
- /// where touching `~/.local/share/solitaire_quest/stats.json` would be
+ /// where touching `~/.local/share/ferrous_solitaire/stats.json` would be
/// incorrect.
pub fn headless() -> Self {
Self { storage_path: None }
diff --git a/solitaire_engine/src/time_attack_plugin.rs b/solitaire_engine/src/time_attack_plugin.rs
index ce3fbea..829fd5d 100644
--- a/solitaire_engine/src/time_attack_plugin.rs
+++ b/solitaire_engine/src/time_attack_plugin.rs
@@ -307,7 +307,7 @@ mod tests {
.add_plugins(TimeAttackPlugin);
app.init_resource::>();
// Disable session persistence — tests must not touch the real
- // ~/.local/share/solitaire_quest/time_attack_session.json.
+ // ~/.local/share/ferrous_solitaire/time_attack_session.json.
app.insert_resource(TimeAttackSessionPath(None));
// The plugin's startup-load hook may have populated TimeAttackResource
// from a real on-disk session. Reset it so each test starts inactive.
diff --git a/solitaire_server/docker-compose.yml b/solitaire_server/docker-compose.yml
index 5779110..757a91c 100644
--- a/solitaire_server/docker-compose.yml
+++ b/solitaire_server/docker-compose.yml
@@ -3,7 +3,7 @@ services:
build:
context: ..
dockerfile: solitaire_server/Dockerfile
- image: solitaire-quest-server:latest
+ image: ferrous-solitaire-server:latest
restart: unless-stopped
ports:
- "${SERVER_PORT:-8080}:8080"