feat(engine): embed classic theme into binary like dark theme

Classic SVGs and manifest are now compiled in via include_bytes!(),
making the theme available on all platforms (desktop, Android) without
requiring filesystem assets. Removes the now-redundant Dockerfile COPY
of solitaire_engine/assets/themes/classic.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
funman300
2026-05-14 10:53:14 -07:00
parent 2ef25934ac
commit 3cffbc2c51
4 changed files with 188 additions and 14 deletions
+20 -10
View File
@@ -15,7 +15,7 @@ use bevy::prelude::*;
use solitaire_core::card::{Rank, Suit};
use crate::assets::{
bundled_theme_url, dark_theme_svg_bytes, rasterize_svg, user_theme_dir,
bundled_theme_url, classic_theme_svg_bytes, dark_theme_svg_bytes, rasterize_svg, user_theme_dir,
};
use crate::card_plugin::CardImageSet;
use crate::events::StateChangedEvent;
@@ -306,22 +306,18 @@ const PREVIEW_BACK_FILENAME: &str = "back.svg";
///
/// - For the embedded `dark` theme, reads from the in-binary table via
/// [`dark_theme_svg_bytes`]. No filesystem I/O.
/// - For bundled non-embedded themes (e.g. `classic`), reads from the
/// `assets/themes/<id>/` directory.
/// - For the embedded `classic` theme, reads from the in-binary table via
/// [`classic_theme_svg_bytes`]. No filesystem I/O.
/// - For user themes, reads from `<user_theme_dir>/<id>/<filename>`.
/// Returns `None` for any I/O failure.
fn read_theme_preview_svg_bytes(theme_id: &str, filename: &str) -> Option<Vec<u8>> {
if theme_id == "dark" {
return dark_theme_svg_bytes(filename).map(|b| b.to_vec());
}
// Bundled non-embedded themes live alongside the binary in assets/.
let bundled_path = std::path::Path::new("assets/themes")
.join(theme_id)
.join(filename);
if let Ok(bytes) = std::fs::read(&bundled_path) {
return Some(bytes);
if theme_id == "classic" {
return classic_theme_svg_bytes(filename).map(|b| b.to_vec());
}
// Fall back to user theme dir.
// User themes live in the user theme dir.
let path = user_theme_dir().join(theme_id).join(filename);
std::fs::read(&path).ok()
}
@@ -577,6 +573,20 @@ mod tests {
);
}
/// `read_theme_preview_svg_bytes` for the classic theme always returns
/// embedded bytes for the canonical preview pair.
#[test]
fn read_classic_theme_preview_returns_some_for_canonical_files() {
assert!(
read_theme_preview_svg_bytes("classic", PREVIEW_BACK_FILENAME).is_some(),
"classic theme back.svg must be embedded"
);
assert!(
read_theme_preview_svg_bytes("classic", PREVIEW_FACE_FILENAME).is_some(),
"classic theme spades_ace.svg must be embedded"
);
}
/// `ensure_theme_thumbnails` is idempotent: calling it twice with
/// the same registry must not regenerate or replace already-cached
/// entries. This guards against the per-frame Update tick churning