refactor: 收口推荐 runtime 自动启动

This commit is contained in:
2026-06-04 04:44:22 +08:00
parent 4e23995347
commit 05713e1d3b
7 changed files with 209 additions and 36 deletions

View File

@@ -553,9 +553,9 @@ import {
buildPlatformPublicGalleryFeeds,
getPlatformPublicGalleryEntryKey,
getPlatformRecommendRuntimeKind,
isPlatformRecommendRuntimeReadyForEntry,
isSamePlatformPublicGalleryEntry,
type RecommendRuntimeKind,
resolvePlatformRecommendRuntimeAutoStartDecision,
resolvePlatformRecommendRuntimeStartIntent,
} from './platformPublicGalleryFlow';
import {
@@ -12309,31 +12309,15 @@ export function PlatformEntryFlowShellImpl({
]);
useEffect(() => {
if (
isDesktopLayout ||
selectionStage !== 'platform' ||
platformBootstrap.platformTab !== 'home' ||
platformBootstrap.isLoadingPlatform
) {
return;
}
if (recommendRuntimeEntries.length === 0) {
setActiveRecommendEntryKey(null);
setActiveRecommendRuntimeKind(null);
setActiveRecommendRuntimeError(null);
return;
}
const activeRecommendEntry = activeRecommendEntryKey
? (recommendRuntimeEntries.find(
(entry) =>
getPlatformPublicGalleryEntryKey(entry) === activeRecommendEntryKey,
) ?? null)
: null;
const isActiveRecommendRuntimeReady =
activeRecommendEntry !== null &&
isPlatformRecommendRuntimeReadyForEntry(activeRecommendEntry, {
const decision = resolvePlatformRecommendRuntimeAutoStartDecision({
isDesktopLayout,
selectionStage,
platformTab: platformBootstrap.platformTab,
isLoadingPlatform: platformBootstrap.isLoadingPlatform,
entries: recommendRuntimeEntries,
activeEntryKey: activeRecommendEntryKey,
isStarting: isStartingRecommendEntry,
readyState: {
activeKind: activeRecommendRuntimeKind,
hasBabyObjectMatchDraft: Boolean(babyObjectMatchDraft),
hasBigFishRun: Boolean(bigFishRun),
@@ -12345,19 +12329,21 @@ export function PlatformEntryFlowShellImpl({
puzzleRunEntryProfileId: puzzleRun?.entryProfileId ?? null,
puzzleRunCurrentLevelProfileId:
puzzleRun?.currentLevel?.profileId ?? null,
});
if (
(activeRecommendEntry !== null && isActiveRecommendRuntimeReady) ||
isStartingRecommendEntry
) {
},
});
if (decision.type === 'noop') {
return;
}
const nextRecommendEntry =
activeRecommendEntry ?? recommendRuntimeEntries[0];
if (nextRecommendEntry) {
void selectRecommendRuntimeEntry(nextRecommendEntry);
if (decision.type === 'clear') {
setActiveRecommendEntryKey(null);
setActiveRecommendRuntimeKind(null);
setActiveRecommendRuntimeError(null);
return;
}
void selectRecommendRuntimeEntry(decision.entry);
}, [
activeRecommendEntryKey,
activeRecommendRuntimeKind,

View File

@@ -22,6 +22,7 @@ import {
mergePlatformPublicGalleryEntries,
type PlatformRecommendRuntimeStartIntentDeps,
type RecommendRuntimeKind,
resolvePlatformRecommendRuntimeAutoStartDecision,
resolvePlatformRecommendRuntimeStartIntent,
} from './platformPublicGalleryFlow';
import {
@@ -611,6 +612,92 @@ test('platform public gallery flow resolves puzzle and edutainment readiness det
).toBe(false);
});
test('platform public gallery flow resolves recommend runtime auto-start gates', () => {
const entry = buildTypedEntry('big-fish');
const baseInput: Parameters<
typeof resolvePlatformRecommendRuntimeAutoStartDecision
>[0] = {
isDesktopLayout: false,
selectionStage: 'platform',
platformTab: 'home',
isLoadingPlatform: false,
entries: [entry],
activeEntryKey: null,
isStarting: false,
readyState: { activeKind: null },
};
expect(
resolvePlatformRecommendRuntimeAutoStartDecision({
...baseInput,
isDesktopLayout: true,
}),
).toEqual({ type: 'noop' });
expect(
resolvePlatformRecommendRuntimeAutoStartDecision({
...baseInput,
platformTab: 'discover',
}),
).toEqual({ type: 'noop' });
expect(
resolvePlatformRecommendRuntimeAutoStartDecision({
...baseInput,
entries: [],
}),
).toEqual({ type: 'clear' });
expect(
resolvePlatformRecommendRuntimeAutoStartDecision({
...baseInput,
isStarting: true,
}),
).toEqual({ type: 'noop' });
});
test('platform public gallery flow resolves recommend runtime auto-start target', () => {
const firstEntry = buildTypedEntry('big-fish', {
profileId: 'big-fish-first',
});
const activeEntry = buildTypedEntry('puzzle', {
profileId: 'puzzle-active',
});
const activeEntryKey = getPlatformPublicGalleryEntryKey(activeEntry);
const baseInput: Parameters<
typeof resolvePlatformRecommendRuntimeAutoStartDecision
>[0] = {
isDesktopLayout: false,
selectionStage: 'platform',
platformTab: 'home',
isLoadingPlatform: false,
entries: [firstEntry, activeEntry],
activeEntryKey,
isStarting: false,
readyState: { activeKind: 'puzzle' },
};
expect(
resolvePlatformRecommendRuntimeAutoStartDecision({
...baseInput,
readyState: {
activeKind: 'puzzle',
puzzleRunEntryProfileId: 'puzzle-active',
},
}),
).toEqual({ type: 'noop' });
expect(resolvePlatformRecommendRuntimeAutoStartDecision(baseInput)).toEqual({
type: 'start',
entry: activeEntry,
});
expect(
resolvePlatformRecommendRuntimeAutoStartDecision({
...baseInput,
activeEntryKey: 'missing-entry',
}),
).toEqual({
type: 'start',
entry: firstEntry,
});
});
test('platform public gallery flow merges duplicate identities and sorts newest first', () => {
const staleRpgEntry = buildRpgEntry({
profileId: 'shared-rpg',

View File

@@ -140,6 +140,22 @@ export type PlatformRecommendRuntimeReadyState = {
puzzleRunCurrentLevelProfileId?: string | null;
};
export type PlatformRecommendRuntimeAutoStartDecision =
| { type: 'noop' }
| { type: 'clear' }
| { type: 'start'; entry: PlatformPublicGalleryCard };
export type PlatformRecommendRuntimeAutoStartInput = {
isDesktopLayout: boolean;
selectionStage: string;
platformTab: string;
isLoadingPlatform: boolean;
entries: readonly PlatformPublicGalleryCard[];
activeEntryKey: string | null;
isStarting: boolean;
readyState: PlatformRecommendRuntimeReadyState;
};
export type PlatformPublicGalleryFeedsInput = {
rpgEntries: readonly CustomWorldGalleryCard[];
bigFishEntries: readonly BigFishWorkSummary[];
@@ -423,6 +439,40 @@ export function isPlatformRecommendRuntimeReadyForEntry(
return true;
}
export function resolvePlatformRecommendRuntimeAutoStartDecision(
input: PlatformRecommendRuntimeAutoStartInput,
): PlatformRecommendRuntimeAutoStartDecision {
if (
input.isDesktopLayout ||
input.selectionStage !== 'platform' ||
input.platformTab !== 'home' ||
input.isLoadingPlatform
) {
return { type: 'noop' };
}
if (input.entries.length === 0) {
return { type: 'clear' };
}
const activeEntry = input.activeEntryKey
? (input.entries.find(
(entry) =>
getPlatformPublicGalleryEntryKey(entry) === input.activeEntryKey,
) ?? null)
: null;
const isActiveRuntimeReady =
activeEntry !== null &&
isPlatformRecommendRuntimeReadyForEntry(activeEntry, input.readyState);
if ((activeEntry !== null && isActiveRuntimeReady) || input.isStarting) {
return { type: 'noop' };
}
const nextEntry = activeEntry ?? input.entries[0];
return nextEntry ? { type: 'start', entry: nextEntry } : { type: 'clear' };
}
export function isSamePlatformPublicGalleryEntry(
left: PlatformPublicGalleryCard,
right: PlatformPublicGalleryCard,