refactor: 收口推荐 runtime 自动启动
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user