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:
parent
13b91dd423
commit
9610c9477e
14 changed files with 347 additions and 17 deletions
|
|
@ -46,7 +46,12 @@ export interface UnifiedApp<P extends IdProject = IdProject> {
|
|||
pairing: Pairing;
|
||||
/** The keys an "ignore" puts on the list ("project:<id>" or "app:<store key>"). */
|
||||
ignoreKeys: string[];
|
||||
/** Ignored entirely (every store side it has). */
|
||||
ignored: boolean;
|
||||
/** Store sides left out while the other side stays (a half-ignored app): their ref is dropped from ios / android. */
|
||||
ignoredStores: ('ios' | 'android')[];
|
||||
/** The ignore key of each side (null: no such side), for the per-store toggles. */
|
||||
sideKeys: { ios: string | null; android: string | null };
|
||||
/** Store icon (data URL) when the folder has none. */
|
||||
storeIcon: string | null;
|
||||
}
|
||||
|
|
@ -115,9 +120,17 @@ export function buildApps<P extends IdProject>(i: BuildInput<P>): UnifiedApp<P>[
|
|||
const studio = studioOverride.get(`project:${p.id}`)
|
||||
?? (p.appleAccount && accountStudio.get(p.appleAccount)) ?? (p.playAccount && accountStudio.get(p.playAccount))
|
||||
?? (ios && accountStudio.get(ios.account)) ?? (android && accountStudio.get(android.account)) ?? null;
|
||||
// ignored: the whole folder, or every store side it has; one side alone hides just that store (project:<id>:ios | :android)
|
||||
const whole = ignored.has(`project:${p.id}`);
|
||||
const sideOff = { ios: whole || ignored.has(`project:${p.id}:ios`), android: whole || ignored.has(`project:${p.id}:android`) };
|
||||
const has = { ios: !!ios || !!s?.apple || !!p.appleAccount, android: !!android || !!s?.play || !!p.playAccount };
|
||||
const present = (['ios', 'android'] as const).filter(k => has[k]);
|
||||
const allOff = whole || (present.length > 0 && present.every(k => sideOff[k]));
|
||||
const hidden = allOff ? [] : present.filter(k => sideOff[k]);
|
||||
out.push({
|
||||
key: p.id, target: p.id, name: p.name, project: p, ios, android, studio, pairing: 'folder',
|
||||
ignoreKeys: [`project:${p.id}`], ignored: ignored.has(`project:${p.id}`), storeIcon: ios?.app.icon ?? android?.app.icon ?? null,
|
||||
key: p.id, target: p.id, name: p.name, project: p, ios: hidden.includes('ios') ? null : ios, android: hidden.includes('android') ? null : android, studio, pairing: 'folder',
|
||||
ignoreKeys: [`project:${p.id}`, `project:${p.id}:ios`, `project:${p.id}:android`], ignored: allOff, ignoredStores: hidden, sideKeys: { ios: `project:${p.id}:ios`, android: `project:${p.id}:android` },
|
||||
storeIcon: ios?.app.icon ?? android?.app.icon ?? null,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -147,9 +160,14 @@ export function buildApps<P extends IdProject>(i: BuildInput<P>): UnifiedApp<P>[
|
|||
const keys = [ios, android].filter((r): r is StoreRef => !!r).map(r => r.key);
|
||||
const studio = keys.map(k => studioOverride.get(k)).find(Boolean)
|
||||
?? (ios && accountStudio.get(ios.account)) ?? (android && accountStudio.get(android.account)) ?? null;
|
||||
// a paired app is ignored when every side is; one ignored side alone hides just that store
|
||||
const off = (r: StoreRef | null) => !!r && ignored.has(`app:${r.key}`);
|
||||
const allOff = [ios, android].filter(Boolean).length > 0 && [ios, android].every(r => !r || off(r));
|
||||
const hidden = allOff ? [] : (['ios', 'android'] as const).filter(k => off(k === 'ios' ? ios : android));
|
||||
out.push({
|
||||
key: target, target, name: ios?.app.name ?? android?.app.name ?? '?', project: null, ios, android, studio, pairing,
|
||||
ignoreKeys: keys.map(k => `app:${k}`), ignored: keys.some(k => ignored.has(`app:${k}`)), storeIcon: ios?.app.icon ?? android?.app.icon ?? null,
|
||||
key: target, target, name: ios?.app.name ?? android?.app.name ?? '?', project: null, ios: hidden.includes('ios') ? null : ios, android: hidden.includes('android') ? null : android, studio, pairing,
|
||||
ignoreKeys: keys.map(k => `app:${k}`), ignored: allOff, ignoredStores: hidden, sideKeys: { ios: ios ? `app:${ios.key}` : null, android: android ? `app:${android.key}` : null },
|
||||
storeIcon: ios?.app.icon ?? android?.app.icon ?? null,
|
||||
});
|
||||
};
|
||||
for (const [a, b, how] of pairs) storeOnly(a, b, how);
|
||||
|
|
@ -180,6 +198,21 @@ export function withUnpair(o: Overrides, ios: string, android: string): Override
|
|||
return { ...o, pairs: o.pairs.filter(p => !samePair(p, ios, android)), unpairs: [...o.unpairs.filter(p => !samePair(p, ios, android)), { ios, android }] };
|
||||
}
|
||||
|
||||
/** Overrides after ignoring (or restoring) ONE store side of an app. A whole-folder key is split into its sides first. */
|
||||
export function withSideIgnored(o: Overrides, app: UnifiedApp, side: 'ios' | 'android', on: boolean): Overrides {
|
||||
const key = app.sideKeys[side];
|
||||
if (!key) return o;
|
||||
const set = new Set(o.ignored);
|
||||
if (app.project) {
|
||||
const whole = `project:${app.project.id}`;
|
||||
if (set.delete(whole)) { set.add(app.sideKeys.ios!); set.add(app.sideKeys.android!); }
|
||||
// both sides ignored is the same as the whole folder
|
||||
if (on) set.add(key); else set.delete(key);
|
||||
if (set.has(app.sideKeys.ios!) && set.has(app.sideKeys.android!)) { set.delete(app.sideKeys.ios!); set.delete(app.sideKeys.android!); set.add(whole); }
|
||||
} else if (on) set.add(key); else set.delete(key);
|
||||
return { ...o, ignored: [...set] };
|
||||
}
|
||||
|
||||
export function withIgnored(o: Overrides, keys: string[], on: boolean): Overrides {
|
||||
const set = new Set(o.ignored);
|
||||
for (const k of keys) { if (on) set.add(k); else set.delete(k); }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue