Skip to content

Commit 72fcc86

Browse files
committed
feat: recursively find visible item to redirect stream to
1 parent 7d15819 commit 72fcc86

File tree

1 file changed

+91
-53
lines changed

1 file changed

+91
-53
lines changed

electron/renderer/pages/grid.tsx

+91-53
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,19 @@ import type {
1818
} from '../../common/game/types.js';
1919
import { GameEventType } from '../../common/game/types.js';
2020
import { GameStream } from '../components/game/game-stream.jsx';
21-
import type { GridItemMetadata } from '../components/grid/grid-item.jsx';
22-
import type { GridContentItem } from '../components/grid/grid.jsx';
2321
import { Grid } from '../components/grid/grid.jsx';
2422
import { NoSSR } from '../components/no-ssr/no-ssr.jsx';
2523
import { useLogger } from '../hooks/logger.jsx';
2624
import { useMeasure } from '../hooks/measure.js';
2725
import { useWindowSize } from '../hooks/window-size.js';
2826
import { runInBackground } from '../lib/async/run-in-background.js';
29-
import type { GameLogLine } from '../types/game.types.js';
27+
import { getGameItemInfo } from '../lib/game/game-item-info.js';
28+
import { GameItemId, type GameLogLine } from '../types/game.types.js';
29+
import type {
30+
GridItemConfig,
31+
GridItemContent,
32+
GridItemInfo,
33+
} from '../types/grid.types.js';
3034

3135
// The grid dynamically modifies the DOM, so we can't use SSR
3236
// because the server and client DOMs will be out of sync.
@@ -342,54 +346,53 @@ const GridPage: React.FC = (): ReactNode => {
342346
const [gridWidthRef, { width: gridWidth }] = useMeasure<HTMLDivElement>();
343347
const gridHeight = windowSize.height - bottomBarSize.height - 40;
344348

345-
interface GridConfigItem {
346-
itemId: string; // 'room'
347-
title: string; // 'Room'
348-
whenVisibleStreamToItemIds: Array<string>; // ['room'], always streams to itself, may also stream elsewhere
349-
whenHiddenStreamToItemIds: Array<string>; // ['main'], default streams nowhere else, may also stream elsewhere
350-
}
351-
352-
const configGridItems: Array<GridConfigItem> = [];
349+
// TODO define a default config set
350+
// TODO allow users to customize the set and add/remove items
351+
// TODO IPC handler to get/save the user's config set
352+
const configGridItems: Array<GridItemConfig> = [];
353353

354354
configGridItems.push({
355-
itemId: 'room',
356-
title: 'Room',
357-
whenVisibleStreamToItemIds: ['room'],
358-
whenHiddenStreamToItemIds: ['main'],
355+
gameItemInfo: getGameItemInfo(GameItemId.ROOM),
356+
whenVisibleStreamToItemIds: [GameItemId.ROOM],
357+
whenHiddenStreamToItemIds: [],
359358
});
360359

361360
configGridItems.push({
362-
itemId: 'experience',
363-
title: 'Experience',
364-
whenVisibleStreamToItemIds: ['experience'],
365-
whenHiddenStreamToItemIds: ['main'],
361+
gameItemInfo: getGameItemInfo(GameItemId.EXPERIENCE),
362+
whenVisibleStreamToItemIds: [GameItemId.EXPERIENCE],
363+
whenHiddenStreamToItemIds: [],
366364
});
367365

368366
configGridItems.push({
369-
itemId: 'main',
370-
title: 'Main',
371-
whenVisibleStreamToItemIds: ['main'],
372-
whenHiddenStreamToItemIds: [''],
367+
gameItemInfo: getGameItemInfo(GameItemId.MAIN),
368+
whenVisibleStreamToItemIds: [GameItemId.MAIN],
369+
whenHiddenStreamToItemIds: [],
373370
});
374371

375372
configGridItems.push({
376-
itemId: 'percWindow',
377-
title: 'Spells',
378-
whenVisibleStreamToItemIds: ['percWindow'],
373+
gameItemInfo: getGameItemInfo(GameItemId.SPELLS),
374+
whenVisibleStreamToItemIds: [GameItemId.SPELLS],
379375
whenHiddenStreamToItemIds: [],
380376
});
381377

382-
const configItemIds = configGridItems.map((configItem) => {
383-
return configItem.itemId;
378+
const configItemsMap: Record<string, GridItemConfig> = {};
379+
const configItemIds: Array<string> = [];
380+
configGridItems.forEach((configItem) => {
381+
const itemId = configItem.gameItemInfo.itemId;
382+
configItemsMap[itemId] = configItem;
383+
configItemIds.push(itemId);
384384
});
385385

386-
let layoutGridItems: Array<GridItemMetadata> = [];
386+
// TODO define a default layout
387+
// TODO IPC handler to get/save a layout
388+
// TODO allow user to assign layouts to characters
389+
let layoutGridItems = new Array<GridItemInfo>();
387390

388391
layoutGridItems.push({
389392
itemId: 'room',
390393
itemTitle: 'Room',
391394
isFocused: false,
392-
itemLayout: {
395+
layout: {
393396
x: 0,
394397
y: 0,
395398
width: 100,
@@ -401,19 +404,31 @@ const GridPage: React.FC = (): ReactNode => {
401404
itemId: 'experience',
402405
itemTitle: 'Experience',
403406
isFocused: false,
404-
itemLayout: {
407+
layout: {
405408
x: 200,
406409
y: 0,
407410
width: 100,
408411
height: 100,
409412
},
410413
});
411414

415+
layoutGridItems.push({
416+
itemId: 'spells',
417+
itemTitle: 'Spells',
418+
isFocused: false,
419+
layout: {
420+
x: 800,
421+
y: 0,
422+
width: 100,
423+
height: 100,
424+
},
425+
});
426+
412427
layoutGridItems.push({
413428
itemId: 'main',
414429
itemTitle: 'Main',
415430
isFocused: true,
416-
itemLayout: {
431+
layout: {
417432
x: 0,
418433
y: 200,
419434
width: 200,
@@ -426,44 +441,67 @@ const GridPage: React.FC = (): ReactNode => {
426441
return configItemIds.includes(layoutItem.itemId);
427442
});
428443

429-
const layoutItemIds = layoutGridItems.map((layoutItem) => {
430-
return layoutItem.itemId;
444+
const layoutItemsMap: Record<string, GridItemInfo> = {};
445+
const layoutItemIds: Array<string> = [];
446+
layoutGridItems.forEach((layoutItem) => {
447+
const itemId = layoutItem.itemId;
448+
layoutItemsMap[itemId] = layoutItem;
449+
layoutItemIds.push(itemId);
431450
});
432451

433-
const itemIdToStreamIdsMap: Record<string, Array<string>> = {};
452+
// Map of item ids to the item ids that should stream to it.
453+
// The key is the item id that should receive the stream(s).
454+
// The values are the items redirecting their stream to the key item.
455+
const itemStreamMapping: Record<string, Array<string>> = {};
434456

435457
// If layout includes the config item then stream to its visible items.
436458
// If layout does not include the config item then stream to its hidden items.
437459
configGridItems.forEach((configItem) => {
438-
const streamToItemIds = layoutItemIds.includes(configItem.itemId)
460+
const itemId = configItem.gameItemInfo.itemId;
461+
462+
const streamToItemIds = layoutItemsMap[itemId]
439463
? configItem.whenVisibleStreamToItemIds
440464
: configItem.whenHiddenStreamToItemIds;
441465

442-
streamToItemIds.forEach((streamToItemId) => {
443-
itemIdToStreamIdsMap[streamToItemId] ||= [];
444-
itemIdToStreamIdsMap[streamToItemId].push(configItem.itemId);
445-
});
466+
// TODO rename this method and move it out the for-each loop
467+
// If an item is hidden and redirects elsewhere, follow the chain
468+
// until we find an item that is visible to truly redirect to.
469+
// This is necessary because the layout may not include all items.
470+
const funcX = (streamToItemIds: Array<string>, itemId: string) => {
471+
streamToItemIds.forEach((streamToItemId) => {
472+
if (layoutItemsMap[streamToItemId]) {
473+
// We're in luck. We found a visible item to stream to.
474+
itemStreamMapping[streamToItemId] ||= [];
475+
itemStreamMapping[streamToItemId].push(itemId);
476+
} else {
477+
// Well, where the hidden item wanted to redirect to
478+
// also is hidden so we need to keep looking for a visible item.
479+
funcX(
480+
configItemsMap[streamToItemId].whenHiddenStreamToItemIds,
481+
itemId
482+
);
483+
}
484+
});
485+
};
486+
487+
funcX(streamToItemIds, itemId);
446488
});
447489

448-
const contentGridItems: Array<GridContentItem> = [];
490+
const contentGridItems: Array<GridItemContent> = [];
449491

450492
layoutGridItems.forEach((layoutItem) => {
451-
const configItem = configGridItems.find((configItem) => {
452-
return configItem.itemId === layoutItem.itemId;
453-
});
493+
const configItem = configItemsMap[layoutItem.itemId];
454494

455495
contentGridItems.push({
456-
layout: {
457-
...layoutItem,
458-
itemTitle: configItem?.title ?? layoutItem.itemTitle,
459-
},
496+
itemId: layoutItem.itemId,
497+
itemTitle: configItem.gameItemInfo.itemTitle ?? layoutItem.itemTitle,
498+
isFocused: layoutItem.isFocused,
499+
layout: layoutItem.layout,
460500
content: (
461501
<GameStream
462-
gameStreamIds={itemIdToStreamIdsMap[layoutItem.itemId].map(
463-
(streamId) => {
464-
return streamId === 'main' ? '' : streamId;
465-
}
466-
)}
502+
gameStreamIds={itemStreamMapping[layoutItem.itemId].map((itemId) => {
503+
return configItemsMap[itemId].gameItemInfo.streamId;
504+
})}
467505
stream$={gameLogLineSubject$}
468506
/>
469507
),

0 commit comments

Comments
 (0)