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
1 change: 0 additions & 1 deletion ASSETS.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ Contributors and are available, at your option, under either the MIT License or
the Apache License, Version 2.0:

- all files in `sprites/british-blue/`;
- all files in `sprites/douhua-cat/`;
- all files in `sprites/huajuan-cat/`;
- all files in `sprites/tabby-cat/`;
- the corresponding `.fpack` archives in `sprites/`;
Expand Down
17 changes: 12 additions & 5 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ members = [
resolver = "2"

[workspace.package]
version = "2.2.0"
version = "2.2.1"
edition = "2021"
rust-version = "1.88"
license = "MIT OR Apache-2.0"
Expand Down
4 changes: 2 additions & 2 deletions app/package-lock.json

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

2 changes: 1 addition & 1 deletion app/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "familiar-app-ui",
"version": "2.2.0",
"version": "2.2.1",
"private": true,
"license": "MIT OR Apache-2.0",
"type": "module",
Expand Down
2 changes: 1 addition & 1 deletion app/src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ publish.workspace = true
[dependencies]
familiar-core = { path = "../../crates/familiar-core" }
familiar-api = { path = "../../crates/familiar-api" }
tauri = { version = "2.0.0-rc", features = ["macos-private-api", "tray-icon", "image-png"] }
tauri = { version = "2.0.0-rc", features = ["protocol-asset", "macos-private-api", "tray-icon", "image-png"] }
tauri-plugin-single-instance = "2"
tokio = { workspace = true }
tokio-tungstenite = { workspace = true, features = ["native-tls"] }
Expand Down
22 changes: 20 additions & 2 deletions app/src-tauri/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1095,7 +1095,10 @@ pub fn get_sprite_packs(app_handle: tauri::AppHandle) -> Result<Vec<SpritePackIn
}

#[tauri::command]
pub async fn import_sprite_pack(path: Option<String>) -> Result<SpritePackInfo, String> {
pub async fn import_sprite_pack(
app_handle: tauri::AppHandle,
path: Option<String>,
) -> Result<SpritePackInfo, String> {
let import_path = if let Some(p) = path.filter(|s| !s.is_empty()) {
std::path::PathBuf::from(p)
} else {
Expand All @@ -1111,7 +1114,22 @@ pub async fn import_sprite_pack(path: Option<String>) -> Result<SpritePackInfo,
}
};

SpritePackManager::import_pack(&import_path).map_err(|e| e.to_string())
let imported = SpritePackManager::import_pack(&import_path).map_err(|e| e.to_string())?;
use tauri::Emitter;
let _ = app_handle.emit("sprite_pack_imported", &imported);
Ok(imported)
}

#[tauri::command]
pub fn delete_sprite_pack(
config_state: tauri::State<'_, Arc<AppConfigState>>,
id: String,
) -> Result<(), String> {
if config_state.get_config().renderer.desktop_pet.sprite == id {
return Err("Cannot delete the active sprite pack; switch packs first".to_string());
}

SpritePackManager::delete_user_pack(&id).map_err(|error| error.to_string())
}

#[tauri::command]
Expand Down
1 change: 1 addition & 0 deletions app/src-tauri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -600,6 +600,7 @@ fn main() {
commands::test_hook_point,
commands::get_sprite_packs,
commands::import_sprite_pack,
commands::delete_sprite_pack,
commands::get_active_sprite_pack,
commands::open_sprite_dir,
commands::quit_app,
Expand Down
9 changes: 9 additions & 0 deletions app/src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@
"app": {
"withGlobalTauri": true,
"macOSPrivateApi": true,
"security": {
"assetProtocol": {
"enable": true,
"scope": [
"$HOME/.config/familiar/sprites/**/*",
"$APPDATA/familiar/sprites/**/*"
]
}
},
"windows": [
{
"label": "main",
Expand Down
12 changes: 10 additions & 2 deletions app/src/i18n.js
Original file line number Diff line number Diff line change
Expand Up @@ -172,12 +172,16 @@ export const translations = {
'lbl_pack_email': '联系邮箱',
'lbl_builtin': '系统自带',
'lbl_custom': '自定义导入',
'btn_use_pack': '使用此素材包',
'btn_use_pack': '使用',
'btn_preview_pack': '预览动作',
'btn_delete_pack': '删除素材包',
'title_preview_modal': '素材动作预览',
'lbl_in_use': '已使用',
'msg_import_success': '素材包导入成功!',
'msg_import_failed': '素材包导入失败: ',
'msg_delete_pack_confirm': '再次点击删除按钮以删除“{name}”',
'msg_delete_pack_success': '素材包已删除',
'msg_delete_pack_failed': '素材包删除失败: ',
'state_idle': '待命 (idle)',
'state_working': '工作中 (working)',
'state_thinking': '思考中 (thinking)',
Expand Down Expand Up @@ -484,12 +488,16 @@ export const translations = {
'lbl_pack_email': 'Email',
'lbl_builtin': 'Built-in',
'lbl_custom': 'Custom',
'btn_use_pack': 'Use Pack',
'btn_use_pack': 'Use',
'btn_preview_pack': 'Preview',
'btn_delete_pack': 'Delete Pack',
'title_preview_modal': 'Action Preview',
'lbl_in_use': 'In Use',
'msg_import_success': 'Sprite pack imported successfully!',
'msg_import_failed': 'Failed to import sprite pack: ',
'msg_delete_pack_confirm': 'Click delete again to remove “{name}”',
'msg_delete_pack_success': 'Sprite pack deleted',
'msg_delete_pack_failed': 'Failed to delete sprite pack: ',
'state_idle': 'Idle',
'state_working': 'Working',
'state_thinking': 'Thinking',
Expand Down
25 changes: 20 additions & 5 deletions app/src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -276,12 +276,18 @@ function setupContextMenu() {
}

let currentSpriteId = null;
let currentSpriteRevision = null;

async function loadActiveSpritePack() {
async function loadActiveSpritePack(force = true) {
try {
const packInfo = await invoke("get_active_sprite_pack");
if (packInfo && packInfo.manifest) {
const samePack = currentSpriteId === packInfo.manifest.id
&& currentSpriteRevision === packInfo.asset_revision;
if (!force && samePack) return;

currentSpriteId = packInfo.manifest.id;
currentSpriteRevision = packInfo.asset_revision;
await renderer.loadSpritePack(packInfo);
renderer.playAnimation("idle");
}
Expand Down Expand Up @@ -373,8 +379,17 @@ async function init() {
});

// Listen for config changes from Rust Backend
await listen("config_changed", (event) => {
applyConfigToWindow(event.payload);
await listen("config_changed", async (event) => {
await applyConfigToWindow(event.payload);
});

await listen("sprite_pack_imported", async (event) => {
const imported = event.payload;
if (!imported || !imported.manifest || imported.manifest.id !== currentSpriteId) return;

currentSpriteRevision = imported.asset_revision;
await renderer.loadSpritePack(imported);
renderer.playAnimation("idle");
});
}

Expand Down Expand Up @@ -431,8 +446,8 @@ async function applyConfigToWindow(config) {

const petConf = config.renderer['desktop-pet'];

if (petConf.sprite && currentSpriteId && petConf.sprite !== currentSpriteId) {
loadActiveSpritePack();
if (petConf.sprite && currentSpriteId) {
await loadActiveSpritePack(false);
}

baseOpacity = petConf.opacity !== undefined ? petConf.opacity : 1;
Expand Down
13 changes: 10 additions & 3 deletions app/src/pet/PixelSpriteRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,13 +104,20 @@ export class PixelSpriteRenderer extends SpriteRenderer {
const packId = this.manifest.id || this.manifest.name || 'british-blue';
if (this.packInfo && !this.packInfo.is_builtin && this.packInfo.path) {
try {
return convertFileSrc(`${this.packInfo.path}/${fileName}`);
return this._withAssetRevision(convertFileSrc(`${this.packInfo.path}/${fileName}`));
} catch (e) {
return `/sprites/${packId}/${fileName}`;
return this._withAssetRevision(`/sprites/${packId}/${fileName}`);
}
}

return `/sprites/${packId}/${fileName}`;
return this._withAssetRevision(`/sprites/${packId}/${fileName}`);
}

_withAssetRevision(url) {
const revision = this.packInfo && this.packInfo.asset_revision;
if (!revision) return url;
const separator = url.includes('?') ? '&' : '?';
return `${url}${separator}v=${encodeURIComponent(revision)}`;
}

_resizeElement(element, width, height) {
Expand Down
5 changes: 5 additions & 0 deletions app/src/settings.css
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,11 @@ input:checked + .slider:before {
.danger-btn:hover {
background-color: rgba(255, 59, 48, 0.2);
}
.btn-delete-pack.confirming {
color: #fff;
background-color: #FF3B30;
border-color: #FF3B30;
}
/* --- Hook Agent Collapsible Cards --- */
.hook-agent-card {
background-color: var(--bg-card);
Expand Down
Loading
Loading