Desktop: per-store ignore (hide only the App Store or Google Play side), N ignored show toggle in sidebar and portfolio, Unignore in the app controls; ignore flags sync with the shared app list

This commit is contained in:
CRTkafa 2026-10-23 01:35:27 +08:00
parent 13b91dd423
commit 9610c9477e
14 changed files with 347 additions and 17 deletions

View file

@ -207,3 +207,40 @@ fn a_folder_that_pins_another_storebound_says_so() {
assert!(!pin_differs(spec, "0.8.0"), "{spec}");
}
}
#[test]
fn ignored_flags_travel_between_the_registry_and_the_apps_ignore_keys() {
let dir = tempfile::tempdir().unwrap();
let file = dir.path().join("projects.json");
// as `storebound apps ignore` wrote it: one folder fully, one store side of another, one store-only app
let (one, two) = (dir.path().join("one").to_string_lossy().to_string(), dir.path().join("two").to_string_lossy().to_string());
let doc = json!({ "version": 1, "projects": [
{ "id": "aaaaaaaaaaaaaaaa", "path": one, "name": "One", "added": "t", "ignored": ["apple", "play"] },
{ "id": "bbbbbbbbbbbbbbbb", "path": two, "name": "Two", "added": "t", "ignored": ["play"] }],
"storeApps": [{ "store": "apple", "appId": "6400000999", "account": "teamA", "name": "Demo", "ignored": ["apple"] }] });
std::fs::write(&file, doc.to_string()).unwrap();
let mut st = State { projects: vec![project("aaaaaaaaaaaaaaaa", &one, None), project("bbbbbbbbbbbbbbbb", &two, None)], ..State::default() };
st.accounts = vec![account("acct1", "Team A", AccountKind::Apple, Some("teamA"))];
st.overrides.ignored = vec!["account:zzz".into(), "app:ios:other:6400000999".into()];
assert!(registry::pull_ignored(&mut st, &file));
assert!(st.overrides.ignored.contains(&"account:zzz".to_string()));
assert!(st.overrides.ignored.contains(&"project:aaaaaaaaaaaaaaaa".to_string()));
assert!(st.overrides.ignored.contains(&"project:bbbbbbbbbbbbbbbb:android".to_string()));
assert!(st.overrides.ignored.contains(&"app:ios:acct1:6400000999".to_string()));
assert!(!st.overrides.ignored.contains(&"app:ios:other:6400000999".to_string()));
assert!(!registry::pull_ignored(&mut st, &file), "second pull changes nothing");
// the owner restores one folder's play side and ignores the other's apple side in the app
st.overrides.ignored.retain(|k| k != "project:bbbbbbbbbbbbbbbb:android" && k != "app:ios:acct1:6400000999");
st.overrides.ignored.push("project:bbbbbbbbbbbbbbbb:ios".into());
assert!(registry::push_ignored(&st, &file).unwrap());
let doc: serde_json::Value = serde_json::from_str(&std::fs::read_to_string(&file).unwrap()).unwrap();
assert_eq!(doc["projects"][0]["ignored"], json!(["apple", "play"]));
assert_eq!(doc["projects"][1]["ignored"], json!(["apple"]));
assert!(doc["storeApps"][0].get("ignored").is_none());
assert!(!registry::push_ignored(&st, &file).unwrap());
// writing the folder list keeps the flags of the folders that stay
let list = registry::read(&file).unwrap();
registry::write(&file, &list).unwrap();
let doc: serde_json::Value = serde_json::from_str(&std::fs::read_to_string(&file).unwrap()).unwrap();
assert_eq!(doc["projects"][1]["ignored"], json!(["apple"]));
}