@tastic/shell 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -5
- package/dist/index.d.mts +29 -2
- package/dist/index.d.ts +29 -2
- package/dist/index.js +195 -133
- package/dist/index.mjs +151 -92
- package/package.json +8 -8
- package/src/components/MatchChips.tsx +72 -0
- package/src/components/OpponentPicker.tsx +112 -0
- package/src/hooks/useAtComputer.ts +13 -0
- package/src/index.ts +2 -0
- package/src/redux/opponentSlice.ts +1 -1
- package/src/screens/HomeScreen.tsx +1 -1
- package/src/screens/LoadoutScreen.tsx +86 -37
- package/src/types.ts +11 -4
- package/src/components/SeatTwoPanel.tsx +0 -144
package/dist/index.js
CHANGED
|
@@ -35,6 +35,8 @@ __export(index_exports, {
|
|
|
35
35
|
GUEST_PLAYER_ID: () => GUEST_PLAYER_ID,
|
|
36
36
|
HomeScreen: () => HomeScreen,
|
|
37
37
|
LoadoutRoute: () => LoadoutRoute,
|
|
38
|
+
MATCH_CHIPS_FADE_MS: () => MATCH_CHIPS_FADE_MS,
|
|
39
|
+
MatchChips: () => MatchChips,
|
|
38
40
|
PREVIEW_ASPECT: () => PREVIEW_ASPECT,
|
|
39
41
|
PackProvider: () => PackProvider,
|
|
40
42
|
PlayRoute: () => PlayRoute,
|
|
@@ -64,12 +66,13 @@ __export(index_exports, {
|
|
|
64
66
|
profileSelectionActions: () => profileSelectionActions,
|
|
65
67
|
profileSelectionReducer: () => profileSelectionSlice_default,
|
|
66
68
|
roundModeFor: () => roundModeFor,
|
|
67
|
-
safeBack: () =>
|
|
69
|
+
safeBack: () => import_core8.safeBack,
|
|
68
70
|
seatColorsActions: () => seatColorsActions,
|
|
69
71
|
seatPlayerKey: () => seatPlayerKey,
|
|
70
72
|
seatTwoFor: () => seatTwoFor,
|
|
71
73
|
useActiveRound: () => useActiveRound,
|
|
72
74
|
useAppSettings: () => useAppSettings,
|
|
75
|
+
useAtComputer: () => useAtComputer,
|
|
73
76
|
useGameGuide: () => useGameGuide,
|
|
74
77
|
useOpponent: () => useOpponent,
|
|
75
78
|
usePack: () => usePack,
|
|
@@ -522,7 +525,7 @@ var styles = import_react_native2.StyleSheet.create({
|
|
|
522
525
|
// src/screens/GameRoute.tsx
|
|
523
526
|
var import_expo_router5 = require("expo-router");
|
|
524
527
|
var import_react14 = require("react");
|
|
525
|
-
var
|
|
528
|
+
var import_react_native6 = require("react-native");
|
|
526
529
|
|
|
527
530
|
// src/routes.ts
|
|
528
531
|
var playHref = (game) => ({ pathname: "/play/[game]", params: { game } });
|
|
@@ -532,91 +535,66 @@ var PROFILES_HREF = "/profiles";
|
|
|
532
535
|
|
|
533
536
|
// src/screens/LoadoutScreen.tsx
|
|
534
537
|
var import_auto_paper4 = require("@rific/auto-paper");
|
|
535
|
-
var
|
|
538
|
+
var import_core10 = require("@tastic/core");
|
|
536
539
|
var import_chrome4 = require("@tastic/hud/chrome");
|
|
537
540
|
var import_lobby2 = require("@tastic/hud/lobby");
|
|
538
541
|
var import_split_screen = require("@tastic/split-screen");
|
|
539
542
|
var import_expo_router4 = require("expo-router");
|
|
540
543
|
var import_react13 = require("react");
|
|
541
|
-
var
|
|
544
|
+
var import_react_native5 = require("react-native");
|
|
542
545
|
var import_react_native_reanimated2 = __toESM(require("react-native-reanimated"));
|
|
543
546
|
var import_react_native_safe_area_context2 = require("react-native-safe-area-context");
|
|
544
547
|
var import_react_redux9 = require("react-redux");
|
|
545
548
|
|
|
546
|
-
// src/components/
|
|
549
|
+
// src/components/OpponentPicker.tsx
|
|
547
550
|
var import_lobby = require("@tastic/hud/lobby");
|
|
548
551
|
var import_profile4 = require("@tastic/profile");
|
|
549
552
|
var import_react9 = require("react");
|
|
550
553
|
var import_react_native3 = require("react-native");
|
|
551
554
|
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
552
555
|
var CPU_PREFIX = "cpu:";
|
|
553
|
-
var PROFILE_PREFIX = "profile:";
|
|
554
556
|
var NOBODY = "nobody";
|
|
555
|
-
var
|
|
556
|
-
var
|
|
557
|
+
var PERSON = "person";
|
|
558
|
+
var PERSON_ICON = "account-outline";
|
|
557
559
|
var NOBODY_ICON = "account-off-outline";
|
|
558
560
|
var CPU_ICON = "robot";
|
|
559
|
-
function
|
|
560
|
-
return `${idPrefix}-
|
|
561
|
+
function getOpponentPopoverId(idPrefix) {
|
|
562
|
+
return `${idPrefix}-opponent`;
|
|
561
563
|
}
|
|
562
|
-
function
|
|
563
|
-
const isPerson = seatTwo === "person";
|
|
564
|
+
function OpponentPicker({ idPrefix, host, choices, seatTwo, onSeatTwoChange, cpuDifficulty, color, onColorChange, swatches, takenColor, allowSwapTaken, dark, previewValue, triggerStyle, usePickerAlign }) {
|
|
564
565
|
const drawn = previewValue ? previewValue(color) : color;
|
|
565
|
-
const selectedProfile = isPerson ? profiles.find((p) => p.id === selectedProfileId) ?? null : null;
|
|
566
566
|
const cpuOptions = cpuDifficulty?.options;
|
|
567
567
|
const options = (0, import_react9.useMemo)(() => {
|
|
568
568
|
const list = [];
|
|
569
569
|
if (choices.includes("cpu")) list.push(...cpuOptions ? cpuOptions.map((o) => ({ value: `${CPU_PREFIX}${o.value}`, label: o.label, icon: o.icon })) : [{ value: CPU_PREFIX, label: "CPU", icon: CPU_ICON }]);
|
|
570
|
-
if (choices.includes("nobody")) list.push({ value: NOBODY, label: "
|
|
571
|
-
if (choices.includes("person")) {
|
|
572
|
-
list.push({ value: GUEST, label: "Player 2", icon: GUEST_ICON });
|
|
573
|
-
list.push(...[...profiles].sort((a, b) => a.name.localeCompare(b.name)).map((p) => ({ value: `${PROFILE_PREFIX}${p.id}`, label: p.name, icon: "account", color: previewValue ? previewValue(p.color) : p.color })));
|
|
574
|
-
}
|
|
570
|
+
if (choices.includes("nobody")) list.push({ value: NOBODY, label: "Solo", icon: NOBODY_ICON, dividerBefore: true });
|
|
571
|
+
if (choices.includes("person")) list.push({ value: PERSON, label: "Player", icon: PERSON_ICON, dividerBefore: true });
|
|
575
572
|
return list;
|
|
576
|
-
}, [choices, cpuOptions
|
|
577
|
-
const value = seatTwo === "cpu" ? `${CPU_PREFIX}${cpuDifficulty?.value ?? ""}` : seatTwo === "nobody" ? NOBODY :
|
|
578
|
-
const icon = seatTwo === "cpu" ? CPU_ICON : seatTwo === "nobody" ? NOBODY_ICON :
|
|
573
|
+
}, [choices, cpuOptions]);
|
|
574
|
+
const value = seatTwo === "cpu" ? `${CPU_PREFIX}${cpuDifficulty?.value ?? ""}` : seatTwo === "nobody" ? NOBODY : PERSON;
|
|
575
|
+
const icon = seatTwo === "cpu" ? CPU_ICON : seatTwo === "nobody" ? NOBODY_ICON : PERSON_ICON;
|
|
579
576
|
const handleChange = (next) => {
|
|
580
577
|
if (next.startsWith(CPU_PREFIX)) {
|
|
581
578
|
cpuDifficulty?.onChange(next.slice(CPU_PREFIX.length));
|
|
582
579
|
onSeatTwoChange("cpu");
|
|
583
|
-
} else if (next === NOBODY) {
|
|
584
|
-
onSeatTwoChange("nobody");
|
|
585
580
|
} else {
|
|
586
|
-
|
|
587
|
-
onSeatTwoChange("person");
|
|
581
|
+
onSeatTwoChange(next === NOBODY ? "nobody" : "person");
|
|
588
582
|
}
|
|
589
583
|
};
|
|
590
|
-
const colorSection = seatTwo === "
|
|
591
|
-
const pickerId =
|
|
592
|
-
const size = (0, import_profile4.getOptionPickerContentSize)(options
|
|
584
|
+
const colorSection = seatTwo === "cpu" ? { value: color, onChange: onColorChange, swatches, takenValue: takenColor, allowSwapTaken, previewValue } : void 0;
|
|
585
|
+
const pickerId = getOpponentPopoverId(idPrefix);
|
|
586
|
+
const size = (0, import_profile4.getOptionPickerContentSize)(options, colorSection);
|
|
593
587
|
const useAlign = usePickerAlign ?? import_lobby.useZoneClampedAlign;
|
|
594
588
|
const align = useAlign(host.openId === pickerId, size.width, size.height);
|
|
595
|
-
|
|
596
|
-
const pickerRowOpen = secondPickerId !== void 0 && host.openId === secondPickerId;
|
|
597
|
-
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native3.View, { style: [styles2.panel, ownPopoverOpen && styles2.panelOpen], children: [
|
|
598
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_profile4.OptionPicker, { id: pickerId, host, options, value, onChange: handleChange, color: drawn, dark, icon, colorSection, alignOverride: align, triggerStyle }),
|
|
599
|
-
isPerson && secondPicker && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native3.View, { style: [styles2.pickerRow, pickerRowOpen && styles2.pickerRowOpen], children: secondPicker }),
|
|
600
|
-
isPerson && showReadyButton && onToggleReady && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lobby.ReadyButton, { color: drawn, ready: ready ?? false, onToggleReady })
|
|
601
|
-
] });
|
|
589
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native3.View, { style: [styles2.button, host.openId === pickerId && styles2.buttonOpen], children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_profile4.OptionPicker, { id: pickerId, host, options, value, onChange: handleChange, color: drawn, dark, icon, colorSection, alignOverride: align, triggerStyle }) });
|
|
602
590
|
}
|
|
603
591
|
var styles2 = import_react_native3.StyleSheet.create({
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
},
|
|
608
|
-
// A popover escaping this panel needs the panel itself elevated to paint above a later sibling.
|
|
609
|
-
panelOpen: {
|
|
610
|
-
zIndex: 100
|
|
611
|
-
},
|
|
612
|
-
pickerRow: {
|
|
613
|
-
alignItems: "center",
|
|
614
|
-
flexDirection: "row",
|
|
615
|
-
gap: 12
|
|
592
|
+
// Its own column, so a row of seat buttons doesn't stretch the pill to the tallest of them.
|
|
593
|
+
button: {
|
|
594
|
+
alignItems: "center"
|
|
616
595
|
},
|
|
617
|
-
//
|
|
618
|
-
|
|
619
|
-
pickerRowOpen: {
|
|
596
|
+
// A popover escaping this button needs the button itself elevated to paint above a later sibling.
|
|
597
|
+
buttonOpen: {
|
|
620
598
|
zIndex: 100
|
|
621
599
|
}
|
|
622
600
|
});
|
|
@@ -668,14 +646,22 @@ function SettingsDialog({ visible, onDismiss, onShowHowToPlay, children }) {
|
|
|
668
646
|
] });
|
|
669
647
|
}
|
|
670
648
|
|
|
649
|
+
// src/hooks/useAtComputer.ts
|
|
650
|
+
var import_core6 = require("@tastic/core");
|
|
651
|
+
var import_react_native4 = require("react-native");
|
|
652
|
+
function useAtComputer() {
|
|
653
|
+
const touchPrimary = (0, import_core6.useIsTouchPrimaryDevice)();
|
|
654
|
+
return import_react_native4.Platform.OS === "web" && !touchPrimary;
|
|
655
|
+
}
|
|
656
|
+
|
|
671
657
|
// src/hooks/useOpponent.ts
|
|
672
658
|
var import_react11 = require("react");
|
|
673
659
|
var import_react_redux7 = require("react-redux");
|
|
674
660
|
|
|
675
661
|
// src/redux/opponentSlice.ts
|
|
676
|
-
var
|
|
662
|
+
var import_core7 = require("@rific/core");
|
|
677
663
|
var DEFAULT_OPPONENT = { seatTwo: "cpu" };
|
|
678
|
-
var { actions: actions4, reducer: reducer4 } = (0,
|
|
664
|
+
var { actions: actions4, reducer: reducer4 } = (0, import_core7.createSettingsSlice)("opponent", {
|
|
679
665
|
initialState: DEFAULT_OPPONENT
|
|
680
666
|
});
|
|
681
667
|
var opponentActions = actions4;
|
|
@@ -808,13 +794,13 @@ function useSeatColors(p2IsHuman) {
|
|
|
808
794
|
}
|
|
809
795
|
|
|
810
796
|
// src/navigation.ts
|
|
811
|
-
var
|
|
797
|
+
var import_core8 = require("@rific/core");
|
|
812
798
|
var import_expo_router3 = require("expo-router");
|
|
813
|
-
(0,
|
|
799
|
+
(0, import_core8.configureNavigation)({ router: import_expo_router3.router });
|
|
814
800
|
|
|
815
801
|
// src/redux/liveplaySlice.ts
|
|
816
|
-
var
|
|
817
|
-
var { actions: actions5, reducer: reducer5 } = (0,
|
|
802
|
+
var import_core9 = require("@rific/core");
|
|
803
|
+
var { actions: actions5, reducer: reducer5 } = (0, import_core9.createSettingsSlice)("liveplay", {
|
|
818
804
|
initialState: { activelyPlaying: false, activeRound: null }
|
|
819
805
|
});
|
|
820
806
|
var liveplayActions = actions5;
|
|
@@ -823,6 +809,8 @@ var liveplaySlice_default = reducer5;
|
|
|
823
809
|
// src/screens/LoadoutScreen.tsx
|
|
824
810
|
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
825
811
|
var PANEL_SWAP_FADE_MS = 180;
|
|
812
|
+
var P1_CONTROL_ID = "p1-control";
|
|
813
|
+
var P2_CONTROL_ID = "p2-control";
|
|
826
814
|
function LoadoutScreen({ game }) {
|
|
827
815
|
const pack = usePack();
|
|
828
816
|
const { seatTwo: savedSeatTwo, setSeatTwo } = useOpponent();
|
|
@@ -834,8 +822,10 @@ function LoadoutScreen({ game }) {
|
|
|
834
822
|
const loadout = game.useLoadout(mode);
|
|
835
823
|
const { openFor } = useGameGuide();
|
|
836
824
|
const { profiles, lastSelected, selectProfile } = useProfiles();
|
|
837
|
-
const { orientationMode } = (0,
|
|
838
|
-
const
|
|
825
|
+
const { orientationMode } = (0, import_core10.useOrientationState)();
|
|
826
|
+
const atComputer = useAtComputer();
|
|
827
|
+
const twoPlayerMode = game.sideBySideAtComputer && atComputer ? "sideBySide" : game.sideBySideWhenWide ? orientationMode : "faceToFace";
|
|
828
|
+
const panelMode = p2IsHuman ? twoPlayerMode : orientationMode;
|
|
839
829
|
const { panelLayout, panelFadeStyle } = (0, import_split_screen.useDualZoneLayout)(panelMode, false, true, false, PANEL_SWAP_FADE_MS);
|
|
840
830
|
const playersRowFade = panelFadeStyle;
|
|
841
831
|
const [settingsOpen, setSettingsOpen] = (0, import_react13.useState)(false);
|
|
@@ -844,7 +834,7 @@ function LoadoutScreen({ game }) {
|
|
|
844
834
|
const { p1Color, p2Color, handleP1ColorChange, handleP2ColorChange } = useSeatColors(p2IsHuman);
|
|
845
835
|
const dispatch = (0, import_react_redux9.useDispatch)();
|
|
846
836
|
const handleP1ProfileSelect = (0, import_react13.useCallback)((profile) => selectProfile(1, profile?.id ?? null), [selectProfile]);
|
|
847
|
-
const handleP2ProfileSelect = (0, import_react13.useCallback)((
|
|
837
|
+
const handleP2ProfileSelect = (0, import_react13.useCallback)((profile) => selectProfile(2, profile?.id ?? null), [selectProfile]);
|
|
848
838
|
const [ready, setReady] = (0, import_react13.useState)({ 1: false, 2: false });
|
|
849
839
|
(0, import_expo_router4.useFocusEffect)(
|
|
850
840
|
(0, import_react13.useCallback)(() => {
|
|
@@ -875,16 +865,16 @@ function LoadoutScreen({ game }) {
|
|
|
875
865
|
const p1Drawn = seatPreview ? seatPreview(p1Color) : p1Color;
|
|
876
866
|
const p2Drawn = seatPreview ? seatPreview(p2Color) : p2Color;
|
|
877
867
|
const triggerStyle = (0, import_react13.useMemo)(() => pack.Backdrop ? [styles3.pill, { backgroundColor: themeColors.surface }] : void 0, [pack.Backdrop, themeColors.surface]);
|
|
868
|
+
const readySurface = pack.Backdrop ? themeColors.surface : void 0;
|
|
878
869
|
const isPortrait = panelLayout.orientationMode === "faceToFace";
|
|
879
870
|
const showMetaInSharedBand = (0, import_split_screen.needsSharedNeutralZone)(panelLayout.orientationMode, humanSeats.length);
|
|
880
871
|
const p2ZoneStyle = p2IsHuman ? isPortrait ? styles3.p2ZoneTop : styles3.p2ZoneRight : null;
|
|
881
|
-
const showReadyButton = p2IsHuman;
|
|
882
872
|
const seatPickerAlign = p2IsHuman ? void 0 : pack.usePickerAlign;
|
|
883
873
|
const layoutKey = p2IsHuman ? "zones" : "row";
|
|
884
874
|
const controlsHost = (0, import_chrome4.usePopoverHost)();
|
|
885
|
-
const
|
|
886
|
-
const
|
|
887
|
-
const
|
|
875
|
+
const p2Host = (0, import_chrome4.usePopoverHost)();
|
|
876
|
+
const p1PickerOpen = controlsHost.openId?.startsWith("p1-") ?? false;
|
|
877
|
+
const p1ControlOpen = controlsHost.openId === P1_CONTROL_ID;
|
|
888
878
|
const optionsRow = loadout.options({
|
|
889
879
|
host: controlsHost,
|
|
890
880
|
accentColor: themeColors.tertiary,
|
|
@@ -896,36 +886,44 @@ function LoadoutScreen({ game }) {
|
|
|
896
886
|
onReset: showMetaInSharedBand ? void 0 : loadout.reset
|
|
897
887
|
});
|
|
898
888
|
const optionsPopoverOpen = controlsHost.openId !== null && loadout.optionIds.includes(controlsHost.openId);
|
|
899
|
-
const sharedControls = showMetaInSharedBand ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lobby2.SharedActionBand, { onBack:
|
|
889
|
+
const sharedControls = showMetaInSharedBand ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lobby2.SharedActionBand, { onBack: import_core8.safeBack, onSettings: () => setSettingsOpen(true), onRandomize: loadout.randomize, onReset: loadout.reset, fg, popoverOpen: optionsPopoverOpen, children: optionsRow }) : optionsRow;
|
|
900
890
|
const controlLook = { accentColor: themeColors.tertiary, mutedColor: fgMuted, dark };
|
|
901
891
|
const p1Control = loadout.seatControl(1, controlsHost, { ...controlLook, seatColor: p1Drawn });
|
|
902
|
-
const p1Panel = /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lobby2.PlayerSetupPanel, { idPrefix: "p1", host: controlsHost, color: p1Color, onColorChange: handleP1ColorChange, swatches: import_auto_paper4.defaultColors, takenColor: p2Exists ? p2Color : void 0, allowSwapTaken: mode === "vsCpu", colorCaption: pack.colorCaption, isHuman: true,
|
|
892
|
+
const p1Panel = /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lobby2.PlayerSetupPanel, { idPrefix: "p1", host: controlsHost, color: p1Color, onColorChange: handleP1ColorChange, swatches: import_auto_paper4.defaultColors, takenColor: p2Exists ? p2Color : void 0, allowSwapTaken: mode === "vsCpu", colorCaption: pack.colorCaption, isHuman: true, dark, showReadyButton: false, profiles, selectedProfileId: lastSelected[1], takenProfileId: p2IsHuman ? lastSelected[2] : null, guestLabel: pack.guestLabel ?? "P1", nullLabel: pack.nullLabel, onProfileSelect: handleP1ProfileSelect, onManageProfiles: () => import_expo_router4.router.push(PROFILES_HREF), previewValue: seatPreview, triggerStyle, useSeatPickerAlign: seatPickerAlign }, `p1-${layoutKey}`);
|
|
893
|
+
const opponentPicker = game.seatTwo && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(OpponentPicker, { idPrefix: "p1", host: controlsHost, choices: game.seatTwo, seatTwo, onSeatTwoChange: changeSeatTwo, cpuDifficulty: loadout.cpuDifficulty, color: p2Color, onColorChange: handleP2ColorChange, swatches: import_auto_paper4.defaultColors, takenColor: p1Color, allowSwapTaken: mode === "vsCpu", dark, previewValue: seatPreview, triggerStyle, usePickerAlign: seatPickerAlign }, `opponent-${layoutKey}`);
|
|
894
|
+
const toggleP1Ready = () => setReady((r) => ({ ...r, 1: !r[1] }));
|
|
895
|
+
const seatOne = /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_react_native5.View, { style: [styles3.seatOne, !p2IsHuman && styles3.seatOneAlone, p1PickerOpen && styles3.raised], children: [
|
|
896
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_react_native5.View, { style: [styles3.seatOneButtons, p1PickerOpen && styles3.raised], children: [
|
|
897
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_react_native_reanimated2.default.View, { style: [styles3.playersRow, p1PickerOpen && styles3.raised, !p2IsHuman && playersRowFade], children: [
|
|
898
|
+
p1Panel,
|
|
899
|
+
opponentPicker
|
|
900
|
+
] }),
|
|
901
|
+
p1Control && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native5.View, { style: [styles3.controlRow, p1ControlOpen && styles3.raised], children: p1Control })
|
|
902
|
+
] }),
|
|
903
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lobby2.ReadyButton, { color: p1Drawn, ready: ready[1], onToggleReady: toggleP1Ready, surfaceColor: readySurface, dark, style: !p2IsHuman && p1PickerOpen && styles3.readyButtonHidden })
|
|
904
|
+
] });
|
|
903
905
|
const p2Control = p2IsHuman ? loadout.seatControl(2, p2Host, { ...controlLook, seatColor: p2Drawn }) : void 0;
|
|
904
|
-
const p2Panel =
|
|
905
|
-
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
906
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
906
|
+
const p2Panel = p2IsHuman && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lobby2.PlayerSetupPanel, { idPrefix: "p2", host: p2Host, color: p2Color, onColorChange: handleP2ColorChange, swatches: import_auto_paper4.defaultColors, takenColor: p1Color, colorCaption: pack.colorCaption, isHuman: true, ready: ready[2], onToggleReady: () => setReady((r) => ({ ...r, 2: !r[2] })), dark, secondPicker: p2Control, secondPickerId: p2Control ? P2_CONTROL_ID : void 0, profiles, selectedProfileId: lastSelected[2], takenProfileId: lastSelected[1], guestLabel: pack.guestLabel ?? "P2", nullLabel: pack.nullLabel, onProfileSelect: handleP2ProfileSelect, previewValue: seatPreview, triggerStyle, readySurfaceColor: readySurface }, "p2-zones");
|
|
907
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_react_native5.View, { style: [styles3.container, { backgroundColor: bg }], children: [
|
|
908
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_react_native5.View, { style: styles3.frame, children: [
|
|
907
909
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_chrome4.PressAwayOverlay, { active: controlsHost.openId !== null, onPress: controlsHost.close }),
|
|
908
910
|
p2ZoneStyle && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_chrome4.PressAwayOverlay, { active: controlsHost.openId !== null || p2Host.openId !== null, onPress: p2Host.close, style: p2ZoneStyle }),
|
|
909
|
-
!showMetaInSharedBand && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_chrome4.CornerActionButtons, { onBack:
|
|
911
|
+
!showMetaInSharedBand && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_chrome4.CornerActionButtons, { onBack: import_core8.safeBack, onSettings: () => setSettingsOpen(true), fg, insets }),
|
|
910
912
|
p2IsHuman ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
911
913
|
import_split_screen.DualZoneLayout,
|
|
912
914
|
{
|
|
913
915
|
panelLayout,
|
|
914
916
|
panelFadeStyle,
|
|
915
|
-
p1:
|
|
917
|
+
p1: seatOne,
|
|
916
918
|
p2: p2Panel,
|
|
917
919
|
shared: sharedControls,
|
|
918
|
-
p1Elevated:
|
|
920
|
+
p1Elevated: p1PickerOpen,
|
|
919
921
|
p2Elevated: p2Host.openId !== null,
|
|
920
922
|
sharedElevated: optionsPopoverOpen
|
|
921
923
|
}
|
|
922
|
-
) : /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
924
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_react_native5.View, { style: styles3.stackedZone, children: [
|
|
923
925
|
sharedControls,
|
|
924
|
-
|
|
925
|
-
p1Panel,
|
|
926
|
-
p2Panel
|
|
927
|
-
] }),
|
|
928
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lobby2.ReadyButton, { color: p1Drawn, ready: ready[1], onToggleReady: () => setReady((r) => ({ ...r, 1: !r[1] })), style: anyPlayerPickerOpen && styles3.readyButtonHidden })
|
|
926
|
+
seatOne
|
|
929
927
|
] })
|
|
930
928
|
] }),
|
|
931
929
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SettingsDialog, { visible: settingsOpen, onDismiss: () => setSettingsOpen(false), onShowHowToPlay: () => openFor(game.id) })
|
|
@@ -935,10 +933,16 @@ function halfOf(color) {
|
|
|
935
933
|
const rgb = (0, import_auto_paper4.getRgb)(color);
|
|
936
934
|
return rgb ? `rgba(${rgb.r},${rgb.g},${rgb.b},0.5)` : void 0;
|
|
937
935
|
}
|
|
938
|
-
var styles3 =
|
|
936
|
+
var styles3 = import_react_native5.StyleSheet.create({
|
|
939
937
|
container: {
|
|
940
938
|
flex: 1
|
|
941
939
|
},
|
|
940
|
+
// Player 1's controls, under their row of buttons.
|
|
941
|
+
controlRow: {
|
|
942
|
+
alignItems: "center",
|
|
943
|
+
flexDirection: "row",
|
|
944
|
+
gap: 12
|
|
945
|
+
},
|
|
942
946
|
// A real full-bleed box to size the absolutely-positioned children against.
|
|
943
947
|
frame: {
|
|
944
948
|
alignItems: "center",
|
|
@@ -965,21 +969,37 @@ var styles3 = import_react_native4.StyleSheet.create({
|
|
|
965
969
|
pill: {
|
|
966
970
|
borderRadius: 999
|
|
967
971
|
},
|
|
968
|
-
//
|
|
969
|
-
//
|
|
972
|
+
// Seat 1's button and the opponent button read as one evenly spaced row of buttons, at
|
|
973
|
+
// PlayerSetupPanel's own pickerRow gap (12).
|
|
970
974
|
playersRow: {
|
|
971
975
|
flexDirection: "row",
|
|
972
976
|
gap: 12
|
|
973
977
|
},
|
|
974
|
-
|
|
978
|
+
// Lifts whichever piece of player 1's has a menu open above its later siblings (each View is its
|
|
979
|
+
// own stacking context on the web).
|
|
980
|
+
raised: {
|
|
975
981
|
zIndex: 100
|
|
976
982
|
},
|
|
977
|
-
// See
|
|
983
|
+
// See p1PickerOpen: opacity 0 (not display:'none') keeps the button's layout space, and
|
|
978
984
|
// pointerEvents:'none' keeps the sliver an open menu doesn't cover from being a hidden tap target.
|
|
979
985
|
readyButtonHidden: {
|
|
980
986
|
opacity: 0,
|
|
981
987
|
pointerEvents: "none"
|
|
982
988
|
},
|
|
989
|
+
// Player 1's column: their row of buttons and controls, then Ready, at PlayerSetupPanel's own
|
|
990
|
+
// rhythm in their half of 2 Player.
|
|
991
|
+
seatOne: {
|
|
992
|
+
alignItems: "center",
|
|
993
|
+
gap: 12
|
|
994
|
+
},
|
|
995
|
+
// With one person, Ready sits as far under the buttons as the match options sit above them.
|
|
996
|
+
seatOneAlone: {
|
|
997
|
+
gap: 28
|
|
998
|
+
},
|
|
999
|
+
seatOneButtons: {
|
|
1000
|
+
alignItems: "center",
|
|
1001
|
+
gap: 12
|
|
1002
|
+
},
|
|
983
1003
|
stackedZone: {
|
|
984
1004
|
alignItems: "center",
|
|
985
1005
|
gap: 28
|
|
@@ -1012,7 +1032,7 @@ function useResumePoint(gameId) {
|
|
|
1012
1032
|
if (!gameId) return;
|
|
1013
1033
|
setLastActiveGame(gameId);
|
|
1014
1034
|
return () => {
|
|
1015
|
-
if (
|
|
1035
|
+
if (import_react_native6.AppState.currentState === "active") clearLastActiveGame();
|
|
1016
1036
|
};
|
|
1017
1037
|
}, [gameId, setLastActiveGame, clearLastActiveGame]);
|
|
1018
1038
|
}
|
|
@@ -1024,7 +1044,7 @@ var import_chrome5 = require("@tastic/hud/chrome");
|
|
|
1024
1044
|
var import_profile7 = require("@tastic/profile");
|
|
1025
1045
|
var import_expo_router6 = require("expo-router");
|
|
1026
1046
|
var import_react16 = require("react");
|
|
1027
|
-
var
|
|
1047
|
+
var import_react_native8 = require("react-native");
|
|
1028
1048
|
var import_react_native_paper = require("react-native-paper");
|
|
1029
1049
|
|
|
1030
1050
|
// src/hooks/useFrozenWhileHidden.ts
|
|
@@ -1044,8 +1064,8 @@ function useFrozenWhileHidden(value, hidden) {
|
|
|
1044
1064
|
}
|
|
1045
1065
|
|
|
1046
1066
|
// src/screens/homeLayout.ts
|
|
1047
|
-
var
|
|
1048
|
-
var
|
|
1067
|
+
var import_core11 = require("@tastic/core");
|
|
1068
|
+
var import_react_native7 = require("react-native");
|
|
1049
1069
|
var import_react_native_safe_area_context3 = require("react-native-safe-area-context");
|
|
1050
1070
|
var PREVIEW_ASPECT = 360 / 200;
|
|
1051
1071
|
var ROW_PREVIEW_WIDTH = 92;
|
|
@@ -1074,9 +1094,9 @@ function computeHomeLayout(windowWidth, windowHeight, insets) {
|
|
|
1074
1094
|
const inner = Math.max(0, usable - HOME_WIDE_EDGE_PADDING - HOME_WIDE_RIGHT_GUTTER);
|
|
1075
1095
|
const content = Math.min(inner, HOME_WIDE_MAX_CONTENT_WIDTH);
|
|
1076
1096
|
const slack = (inner - content) / 2;
|
|
1077
|
-
const leftPaneWidth = Math.min((0,
|
|
1097
|
+
const leftPaneWidth = Math.min((0, import_core11.clamp)(Math.round(HOME_LEFT_PANE_FRACTION * content), HOME_LEFT_PANE_MIN, HOME_LEFT_PANE_MAX), Math.max(0, content - HOME_WIDE_PANE_GAP - HOME_MIN_TILE_WIDTH));
|
|
1078
1098
|
const rightPaneWidth = Math.max(0, content - HOME_WIDE_PANE_GAP - leftPaneWidth);
|
|
1079
|
-
const columns = (0,
|
|
1099
|
+
const columns = (0, import_core11.clamp)(Math.floor((rightPaneWidth + HOME_GRID_GAP) / (HOME_MIN_TILE_WIDTH + HOME_GRID_GAP)), 1, HOME_MAX_COLUMNS);
|
|
1080
1100
|
const tileWidth = Math.max(0, Math.floor((rightPaneWidth - (columns - 1) * HOME_GRID_GAP) / columns));
|
|
1081
1101
|
const previewWidth = Math.max(0, tileWidth - 2 * HOME_TILE_PADDING);
|
|
1082
1102
|
const heroFit = {
|
|
@@ -1099,7 +1119,7 @@ function computeHomeLayout(windowWidth, windowHeight, insets) {
|
|
|
1099
1119
|
};
|
|
1100
1120
|
}
|
|
1101
1121
|
function useHomeLayout() {
|
|
1102
|
-
const { width, height } = (0,
|
|
1122
|
+
const { width, height } = (0, import_react_native7.useWindowDimensions)();
|
|
1103
1123
|
const insets = (0, import_react_native_safe_area_context3.useSafeAreaInsets)();
|
|
1104
1124
|
return computeHomeLayout(width, height, insets);
|
|
1105
1125
|
}
|
|
@@ -1129,9 +1149,9 @@ function HomeMenu() {
|
|
|
1129
1149
|
const [settingsOpen, setSettingsOpen] = (0, import_react16.useState)(false);
|
|
1130
1150
|
const [rulesGame, setRulesGame] = (0, import_react16.useState)(null);
|
|
1131
1151
|
const isFocused = (0, import_expo_router6.useIsFocused)();
|
|
1132
|
-
const [appState, setAppState] = (0, import_react16.useState)(
|
|
1152
|
+
const [appState, setAppState] = (0, import_react16.useState)(import_react_native8.AppState.currentState);
|
|
1133
1153
|
(0, import_react16.useEffect)(() => {
|
|
1134
|
-
const subscription =
|
|
1154
|
+
const subscription = import_react_native8.AppState.addEventListener("change", setAppState);
|
|
1135
1155
|
return () => subscription.remove();
|
|
1136
1156
|
}, []);
|
|
1137
1157
|
const heroActive = isFocused && appState === "active";
|
|
@@ -1173,24 +1193,24 @@ function HomeMenu() {
|
|
|
1173
1193
|
const picker = /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_profile7.ProfilePicker, { idPrefix: SEAT_ONE_PICKER, host: pickerHost, profiles, selectedId: lastSelected[1], color: p1Drawn, dark, guestLabel: pack.guestLabel ?? "P1", nullLabel: pack.nullLabel, onSelect: (profile) => selectProfile(1, profile?.id ?? null), onManage: () => import_expo_router6.router.push(PROFILES_HREF), colorSection, alignOverride: pickerAlign, triggerStyle });
|
|
1174
1194
|
const pressAway = /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_chrome5.PressAwayOverlay, { active: pickerHost.openId !== null, onPress: pickerHost.close, style: styles4.pressAway });
|
|
1175
1195
|
const RulesSheet = rulesGame?.Rules;
|
|
1176
|
-
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
1177
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1196
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_react_native8.View, { style: [styles4.container, { backgroundColor: bg }], children: [
|
|
1197
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native8.View, { style: styles4.frame, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(RulesHost, { enabled: pack.games.some((game) => game.Rules), children: [
|
|
1178
1198
|
isWide ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
|
|
1179
1199
|
pressAway,
|
|
1180
1200
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_auto_paper5.FadingScrollView, { ...tab && gridClamp, style: [styles4.wideRightPane, { left: layout.paddingLeft + layout.leftPaneWidth + HOME_WIDE_PANE_GAP }], contentContainerStyle: { paddingTop: 16 + insets.top, paddingBottom: 16 + insets.bottom, paddingRight: layout.paddingRight }, children: [
|
|
1181
|
-
tabBar && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1182
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1201
|
+
tabBar && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native8.View, { style: [styles4.wideTabs, { width: layout.rightPaneWidth }], children: tabBar }),
|
|
1202
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native8.View, { style: [styles4.grid, { width: layout.rightPaneWidth }], children: pack.games.map((game) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(GameTile, { game, hidden: isHidden(tab, game), width: layout.tileWidth, previewWidth: layout.previewWidth, previewRevealed: previewsRevealed, dark, p1Color, p2Color, onPress: () => openGame(game), onRules: hasRules(game) ? () => openRules(game) : void 0 }, game.id)) })
|
|
1183
1203
|
] }),
|
|
1184
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
1204
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_react_native8.View, { style: [styles4.wideLeftPane, { left: layout.paddingLeft, width: layout.leftPaneWidth, paddingTop: HOME_TOP_BAND + insets.top, paddingBottom: 16 + insets.bottom }, pickerHost.openId !== null && styles4.pickerOpen], children: [
|
|
1185
1205
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(pack.HeroTitle, { words: pack.wordmark, color: fg, p1Color, p2Color, active: heroActive, fit: layout.heroFit }),
|
|
1186
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1206
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native8.View, { style: styles4.widePicker, children: picker })
|
|
1187
1207
|
] })
|
|
1188
1208
|
] }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_auto_paper5.FadingScrollView, { ...tab && columnClamp, style: styles4.scroll, contentContainerStyle: [styles4.content, { paddingTop: 56 + insets.top, paddingBottom: 24 + insets.bottom, paddingLeft: 16 + insets.left, paddingRight: 16 + insets.right }], children: [
|
|
1189
1209
|
pressAway,
|
|
1190
1210
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(pack.HeroTitle, { words: pack.wordmark, color: fg, p1Color, p2Color, active: heroActive }),
|
|
1191
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1192
|
-
tabBar && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1193
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1211
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native8.View, { style: [styles4.picker, pickerHost.openId !== null && styles4.pickerOpen], children: picker }),
|
|
1212
|
+
tabBar && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native8.View, { style: styles4.listWidth, children: tabBar }),
|
|
1213
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native8.View, { style: styles4.list, children: pack.games.map((game) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(GameRow, { game, hidden: isHidden(tab, game), dark, p1Color, p2Color, previewRevealed: previewsRevealed, onPress: () => openGame(game), onRules: hasRules(game) ? () => openRules(game) : void 0 }, game.id)) })
|
|
1194
1214
|
] }),
|
|
1195
1215
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_feedback_press3.IconButton, { icon: "trophy", iconColor: fg, size: 24, style: [styles4.corner, { top: 8 + insets.top, left: 8 + insets.left }], onPress: () => import_expo_router6.router.push(STATS_HREF), accessibilityLabel: "Stats & Achievements" }),
|
|
1196
1216
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_feedback_press3.IconButton, { icon: "cog", iconColor: fg, size: 24, style: [styles4.corner, { top: 8 + insets.top, right: 8 + insets.right }], onPress: () => setSettingsOpen(true), accessibilityLabel: "Settings" }),
|
|
@@ -1241,10 +1261,10 @@ function GameRow({ game, hidden, dark, p1Color, p2Color, previewRevealed, onPres
|
|
|
1241
1261
|
return (
|
|
1242
1262
|
// The rules button sits beside the row's own button, laid over its end, not inside it: a button
|
|
1243
1263
|
// inside a button is invalid on the web.
|
|
1244
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
1264
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_react_native8.View, { style: hidden ? styles4.hidden : void 0, children: [
|
|
1245
1265
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_feedback_press3.Pressable, { onPress, style: [styles4.row, { backgroundColor: well.bg }], accessibilityRole: "button", accessibilityLabel: game.title, children: [
|
|
1246
|
-
game.Preview ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(PreviewBox, { game, width: ROW_PREVIEW_WIDTH, revealed: previewRevealed, dark, p1Color, p2Color }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1247
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
1266
|
+
game.Preview ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(PreviewBox, { game, width: ROW_PREVIEW_WIDTH, revealed: previewRevealed, dark, p1Color, p2Color }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native8.View, { style: [styles4.rowIcon, { backgroundColor: dark ? ICON_DARK_BG : ICON_LIGHT_BG }], children: GameIcon && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(GameIcon, { size: ROW_ICON_SIZE, p1Color, p2Color, dark }) }),
|
|
1267
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_react_native8.View, { style: styles4.rowText, children: [
|
|
1248
1268
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native_paper.Text, { variant: "titleLarge", style: [styles4.rowTitle, { color: well.fg }], numberOfLines: 1, children: game.title }),
|
|
1249
1269
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native_paper.Text, { variant: "bodyMedium", style: { color: well.fgMuted }, numberOfLines: 2, children: game.blurb })
|
|
1250
1270
|
] })
|
|
@@ -1255,7 +1275,7 @@ function GameRow({ game, hidden, dark, p1Color, p2Color, previewRevealed, onPres
|
|
|
1255
1275
|
}
|
|
1256
1276
|
function GameTile({ game, hidden, width, previewWidth, dark, p1Color, p2Color, previewRevealed, onPress, onRules }) {
|
|
1257
1277
|
const well = (0, import_chrome5.useWellColors)();
|
|
1258
|
-
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
1278
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_react_native8.View, { style: [{ width }, hidden && styles4.hidden], children: [
|
|
1259
1279
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_feedback_press3.Pressable, { onPress, style: [styles4.tile, { backgroundColor: well.bg }], accessibilityRole: "button", accessibilityLabel: game.title, children: [
|
|
1260
1280
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(PreviewBox, { game, width: previewWidth, revealed: previewRevealed, dark, p1Color, p2Color }),
|
|
1261
1281
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native_paper.Text, { variant: "titleMedium", style: [styles4.rowTitle, { color: well.fg }], numberOfLines: 1, children: game.title }),
|
|
@@ -1268,13 +1288,13 @@ function PreviewBox({ game, width, revealed, dark, p1Color, p2Color }) {
|
|
|
1268
1288
|
const height = Math.round(width / PREVIEW_ASPECT);
|
|
1269
1289
|
const { Preview, icon: GameIcon } = game;
|
|
1270
1290
|
const iconSize = Math.min(height, ROW_ICON_SIZE);
|
|
1271
|
-
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1291
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native8.View, { style: [styles4.preview, { width, height, backgroundColor: dark ? ICON_DARK_BG : ICON_LIGHT_BG }], children: Preview ? revealed && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Preview, { width, height, p1Color, p2Color, dark }) : GameIcon && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native8.View, { style: [styles4.previewIcon, { width: iconSize, height: iconSize, borderRadius: iconSize * 0.22 }], children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(GameIcon, { size: iconSize, p1Color, p2Color, dark }) }) });
|
|
1272
1292
|
}
|
|
1273
1293
|
var ROW_ICON_SIZE = 56;
|
|
1274
1294
|
var ICON_LIGHT_BG = "#FAFAFA";
|
|
1275
1295
|
var ICON_DARK_BG = "#050505";
|
|
1276
1296
|
var RULES_BUTTON_SPACE = 44;
|
|
1277
|
-
var styles4 =
|
|
1297
|
+
var styles4 = import_react_native8.StyleSheet.create({
|
|
1278
1298
|
container: {
|
|
1279
1299
|
flex: 1
|
|
1280
1300
|
},
|
|
@@ -1430,7 +1450,7 @@ function useRosterAlign(open, contentWidth, contentHeight) {
|
|
|
1430
1450
|
function ProfilesRoute() {
|
|
1431
1451
|
const { profiles, createProfile, updateProfile, deleteProfile } = useProfiles();
|
|
1432
1452
|
const { Backdrop, foreground, newProfileColor, usePickerAlign } = usePack();
|
|
1433
|
-
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_chrome6.RotatedFrame, { rotatedSafeArea: true, portalHost: true, maxContentWidth: ROSTER_MAX_WIDTH, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_profile8.ProfilesScreen, { profiles, defaultColor: newProfileColor ?? import_auto_paper6.defaultColors[0].value, onCreate: (patch) => createProfile(patch), onSave: (id, patch) => updateProfile(id, patch), onDelete: deleteProfile, onBack:
|
|
1453
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_chrome6.RotatedFrame, { rotatedSafeArea: true, portalHost: true, maxContentWidth: ROSTER_MAX_WIDTH, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_profile8.ProfilesScreen, { profiles, defaultColor: newProfileColor ?? import_auto_paper6.defaultColors[0].value, onCreate: (patch) => createProfile(patch), onSave: (id, patch) => updateProfile(id, patch), onDelete: deleteProfile, onBack: import_core8.safeBack, fg: foreground, bg: Backdrop ? "transparent" : void 0, useColorPickerAlign: usePickerAlign ? useRosterAlign : void 0 }) });
|
|
1434
1454
|
}
|
|
1435
1455
|
|
|
1436
1456
|
// src/screens/StatsScreen.tsx
|
|
@@ -1438,7 +1458,7 @@ var import_auto_paper7 = require("@rific/auto-paper");
|
|
|
1438
1458
|
var import_chrome7 = require("@tastic/hud/chrome");
|
|
1439
1459
|
var import_profile9 = require("@tastic/profile");
|
|
1440
1460
|
var import_react17 = require("react");
|
|
1441
|
-
var
|
|
1461
|
+
var import_react_native9 = require("react-native");
|
|
1442
1462
|
var import_react_native_paper2 = require("react-native-paper");
|
|
1443
1463
|
var import_react_native_safe_area_context4 = require("react-native-safe-area-context");
|
|
1444
1464
|
var import_react_redux10 = require("react-redux");
|
|
@@ -1461,7 +1481,7 @@ function StatsScreen() {
|
|
|
1461
1481
|
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(StatsPressAway, { host: pickerHost, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_chrome7.RotatedFrame, { rotatedSafeArea: true, portalHost: true, maxContentWidth: STATS_MAX_WIDTH, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(StatsContent, { pickerHost }) }) });
|
|
1462
1482
|
}
|
|
1463
1483
|
function StatsPressAway({ host, children }) {
|
|
1464
|
-
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
1484
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react_native9.View, { testID: "stats-press-away", style: styles5.screen, onStartShouldSetResponder: () => host.openId !== null, onResponderRelease: host.close, children });
|
|
1465
1485
|
}
|
|
1466
1486
|
var useNoPackReset = () => null;
|
|
1467
1487
|
var noPickerAlign2 = () => void 0;
|
|
@@ -1495,10 +1515,10 @@ function StatsContent({ pickerHost }) {
|
|
|
1495
1515
|
const surface = pack.Backdrop ? { backgroundColor: colors.surface } : void 0;
|
|
1496
1516
|
const triggerStyle = pack.Backdrop ? [styles5.pill, surface] : void 0;
|
|
1497
1517
|
const PackTabContent = packTab?.Content;
|
|
1498
|
-
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_chrome7.BaseStatsScreen, { title, onBack:
|
|
1518
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_chrome7.BaseStatsScreen, { title, onBack: import_core8.safeBack, insets, onReset: reset.onReset, resetLabel: reset.label, resetConfirmTitle: reset.title, resetConfirmBody: reset.body, fg: pack.foreground, bg: pack.Backdrop ? "transparent" : void 0, rotation: 0, children: [
|
|
1499
1519
|
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_chrome7.PressAwayOverlay, { active: pickerHost.openId !== null, onPress: pickerHost.close, style: styles5.pressAway }),
|
|
1500
1520
|
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react_native_paper2.SegmentedButtons, { value: tab, onValueChange: setTab, buttons: tabButtons, style: [styles5.tabs, surface] }),
|
|
1501
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
1521
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_react_native9.View, { style: [styles5.filters, pickerHost.openId !== null && styles5.filtersOpen], onStartShouldSetResponder: () => pickerHost.openId !== null, children: [
|
|
1502
1522
|
profiles.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_profile9.OptionPicker, { id: PLAYER_PICKER_ID, host: pickerHost, options: playerOptions, value: profileId ?? EVERYONE, onChange: (value) => setSelectedProfileId(value === EVERYONE ? null : value), color: colors.primary, dark, icon: profileId ? "account" : "account-group", alignOverride: playerAlign, triggerStyle }),
|
|
1503
1523
|
showGamePicker && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_profile9.OptionPicker, { id: GAME_PICKER_ID, host: pickerHost, options: gameOptions, value: gameId, onChange: setGameId, color: colors.primary, dark, icon: "view-grid-outline", alignOverride: gameAlign, triggerStyle })
|
|
1504
1524
|
] }),
|
|
@@ -1519,12 +1539,12 @@ function GameStats({ game, tab, profileId, showTitle, titleColor }) {
|
|
|
1519
1539
|
const { StatsSections, AchievementList } = game;
|
|
1520
1540
|
const Sections = tab === STATS ? StatsSections : AchievementList;
|
|
1521
1541
|
if (!Sections) return null;
|
|
1522
|
-
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
1542
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_react_native9.View, { style: styles5.game, children: [
|
|
1523
1543
|
showTitle && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react_native_paper2.Text, { variant: "titleLarge", style: [styles5.gameTitle, { color: titleColor }], children: game.title }),
|
|
1524
1544
|
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Sections, { profileId })
|
|
1525
1545
|
] });
|
|
1526
1546
|
}
|
|
1527
|
-
var styles5 =
|
|
1547
|
+
var styles5 = import_react_native9.StyleSheet.create({
|
|
1528
1548
|
filters: {
|
|
1529
1549
|
flexDirection: "row",
|
|
1530
1550
|
flexWrap: "wrap",
|
|
@@ -1558,14 +1578,53 @@ var styles5 = import_react_native8.StyleSheet.create({
|
|
|
1558
1578
|
});
|
|
1559
1579
|
|
|
1560
1580
|
// src/components/imageGameIcon.tsx
|
|
1561
|
-
var
|
|
1581
|
+
var import_react_native10 = require("react-native");
|
|
1562
1582
|
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
1563
1583
|
function imageGameIcon(images) {
|
|
1564
1584
|
return function ImageGameIcon({ size, dark }) {
|
|
1565
|
-
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
1585
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react_native10.Image, { source: dark ? images.dark : images.light, style: { height: size, width: size }, accessibilityIgnoresInvertColors: true });
|
|
1566
1586
|
};
|
|
1567
1587
|
}
|
|
1568
1588
|
|
|
1589
|
+
// src/components/MatchChips.tsx
|
|
1590
|
+
var import_auto_paper8 = require("@rific/auto-paper");
|
|
1591
|
+
var import_feedback_press4 = require("@rific/feedback-press");
|
|
1592
|
+
var import_react18 = require("react");
|
|
1593
|
+
var import_react_native11 = require("react-native");
|
|
1594
|
+
var import_react_native_reanimated3 = __toESM(require("react-native-reanimated"));
|
|
1595
|
+
var import_react_native_safe_area_context5 = require("react-native-safe-area-context");
|
|
1596
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
1597
|
+
var MATCH_CHIPS_FADE_MS = 150;
|
|
1598
|
+
var CHIP_SIZE = 48;
|
|
1599
|
+
var EDGE_PAD = 8;
|
|
1600
|
+
function MatchChips({ playing, faceToFace, centerLineY, onBack, onSettings }) {
|
|
1601
|
+
const { height } = (0, import_react_native11.useWindowDimensions)();
|
|
1602
|
+
const insets = (0, import_react_native_safe_area_context5.useSafeAreaInsets)();
|
|
1603
|
+
const { dark } = (0, import_auto_paper8.useAutoPaperTheme)();
|
|
1604
|
+
const atComputer = useAtComputer();
|
|
1605
|
+
const visible = atComputer || !playing;
|
|
1606
|
+
const opacity = (0, import_react_native_reanimated3.useSharedValue)(visible ? 1 : 0);
|
|
1607
|
+
(0, import_react18.useEffect)(() => {
|
|
1608
|
+
opacity.value = (0, import_react_native_reanimated3.withTiming)(visible ? 1 : 0, { duration: MATCH_CHIPS_FADE_MS });
|
|
1609
|
+
}, [visible]);
|
|
1610
|
+
const fadeStyle = (0, import_react_native_reanimated3.useAnimatedStyle)(() => ({ opacity: opacity.value }));
|
|
1611
|
+
const iconColor = dark ? "#FFFFFF" : "#000000";
|
|
1612
|
+
const containerColor = dark ? "rgba(0,0,0,0.55)" : "rgba(255,255,255,0.55)";
|
|
1613
|
+
const between = faceToFace && !atComputer;
|
|
1614
|
+
const top = between ? (centerLineY ?? height / 2) - CHIP_SIZE / 2 : EDGE_PAD + insets.top;
|
|
1615
|
+
const backSlot = { top, left: EDGE_PAD + insets.left };
|
|
1616
|
+
const settingsSlot = { top, right: EDGE_PAD + insets.right };
|
|
1617
|
+
const pointerEvents = visible ? "box-none" : "none";
|
|
1618
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
|
|
1619
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native_reanimated3.default.View, { pointerEvents, style: [styles6.slot, backSlot, fadeStyle], testID: "match-chips-back", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_feedback_press4.IconButton, { icon: "arrow-left", iconColor, containerColor, style: styles6.chip, size: 24, onPress: onBack, accessibilityLabel: "Back" }) }),
|
|
1620
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native_reanimated3.default.View, { pointerEvents, style: [styles6.slot, settingsSlot, fadeStyle], testID: "match-chips-settings", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_feedback_press4.IconButton, { icon: "cog", iconColor, containerColor, style: styles6.chip, size: 24, onPress: onSettings, accessibilityLabel: "Settings" }) })
|
|
1621
|
+
] });
|
|
1622
|
+
}
|
|
1623
|
+
var styles6 = import_react_native11.StyleSheet.create({
|
|
1624
|
+
chip: { margin: 0 },
|
|
1625
|
+
slot: { position: "absolute" }
|
|
1626
|
+
});
|
|
1627
|
+
|
|
1569
1628
|
// src/hooks/useActiveRound.ts
|
|
1570
1629
|
var import_react_redux11 = require("react-redux");
|
|
1571
1630
|
function useActiveRound(game, defaults) {
|
|
@@ -1581,12 +1640,12 @@ var import_toolkit = require("@reduxjs/toolkit");
|
|
|
1581
1640
|
var import_redux_persist = require("redux-persist");
|
|
1582
1641
|
|
|
1583
1642
|
// src/redux/shellState.ts
|
|
1584
|
-
var
|
|
1585
|
-
var
|
|
1586
|
-
var
|
|
1643
|
+
var import_auto_paper9 = require("@rific/auto-paper");
|
|
1644
|
+
var import_core12 = require("@rific/core");
|
|
1645
|
+
var import_feedback_press5 = require("@rific/feedback-press");
|
|
1587
1646
|
var import_profile10 = require("@tastic/profile");
|
|
1588
|
-
var initialSoundSettings = { ...
|
|
1589
|
-
var appSoundReducer = (state = initialSoundSettings, action) => (0,
|
|
1647
|
+
var initialSoundSettings = { ...import_feedback_press5.defaultSoundSettings, enabled: !__DEV__ };
|
|
1648
|
+
var appSoundReducer = (state = initialSoundSettings, action) => (0, import_feedback_press5.soundReducer)(state, action);
|
|
1590
1649
|
function createShellReducers({ seatColors, appearance = "system", seatTheme }) {
|
|
1591
1650
|
return {
|
|
1592
1651
|
// Explicit primary/secondary triad (rather than a single seed expanded via harmony) so the pack's
|
|
@@ -1598,12 +1657,12 @@ function createShellReducers({ seatColors, appearance = "system", seatTheme }) {
|
|
|
1598
1657
|
// createThemeReducer's own default, when it sets none).
|
|
1599
1658
|
// A pack with its own seatTheme starts from what seat 1's default color makes of it instead (dark
|
|
1600
1659
|
// only when the pack's appearance is; hooks/useSeatColors.ts re-applies it with the live mode).
|
|
1601
|
-
theme: (0,
|
|
1602
|
-
haptic:
|
|
1660
|
+
theme: (0, import_auto_paper9.createThemeReducer)(seatTheme ? { appearance, ...seatTheme(seatColors, appearance === "dark") } : { appearance, color: { primary: seatColors[1], secondary: seatColors[2], tertiary: (0, import_auto_paper9.getThirdColor)(seatColors[1], seatColors[2]) } }),
|
|
1661
|
+
haptic: import_feedback_press5.hapticReducer,
|
|
1603
1662
|
sound: appSoundReducer,
|
|
1604
1663
|
// @rific/core's Keep Awake setting (see Providers.tsx's KeepAwakeBridge), under the namespace its
|
|
1605
1664
|
// REHYDRATE handling expects.
|
|
1606
|
-
keepAwake:
|
|
1665
|
+
keepAwake: import_core12.keepAwakeReducer,
|
|
1607
1666
|
// The shared App Group roster (see @tastic/profile's resolveInitialProfiles/
|
|
1608
1667
|
// useSharedProfilesSync, wired in hooks/useProfiles.tsx) is layered on top of this as a separate
|
|
1609
1668
|
// sync target - this slice persisting normally via redux-persist is what gives it local-fallback
|
|
@@ -1709,8 +1768,8 @@ function forgetProfileAchievements(dropStats) {
|
|
|
1709
1768
|
|
|
1710
1769
|
// src/gameStats.tsx
|
|
1711
1770
|
var import_achievements2 = require("@tastic/achievements");
|
|
1712
|
-
var
|
|
1713
|
-
var
|
|
1771
|
+
var import_react19 = require("react");
|
|
1772
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
1714
1773
|
var SEATS = [1, 2];
|
|
1715
1774
|
function createGameStats({ key, defaultStats, isValidStats, catalog, getProfileStatsView }) {
|
|
1716
1775
|
const { actions: actions6, reducer: sliceReducer } = (0, import_achievements2.createAchievementsSlice)({
|
|
@@ -1727,7 +1786,7 @@ function createGameStats({ key, defaultStats, isValidStats, catalog, getProfileS
|
|
|
1727
1786
|
};
|
|
1728
1787
|
const reducer6 = onProfileRemoved(sliceReducer, forgetProfileAchievements(dropProfileStats));
|
|
1729
1788
|
const profileViews = (stats) => Object.fromEntries(Object.entries(stats.profiles).map(([profileId, bucket]) => [profileId, getProfileStatsView(bucket)]));
|
|
1730
|
-
const Context = (0,
|
|
1789
|
+
const Context = (0, import_react19.createContext)(null);
|
|
1731
1790
|
function Provider({ children }) {
|
|
1732
1791
|
const { stats, unlockedAchievements, recordOutcome, resetAll } = (0, import_achievements2.useAchievements)({
|
|
1733
1792
|
catalog,
|
|
@@ -1735,18 +1794,18 @@ function createGameStats({ key, defaultStats, isValidStats, catalog, getProfileS
|
|
|
1735
1794
|
actions: actions6,
|
|
1736
1795
|
profileViews
|
|
1737
1796
|
});
|
|
1738
|
-
const record = (0,
|
|
1797
|
+
const record = (0, import_react19.useCallback)(
|
|
1739
1798
|
(update, profileIds) => {
|
|
1740
1799
|
const result = recordOutcome(update);
|
|
1741
1800
|
return { device: result.device, profiles: (0, import_achievements2.mapUnlocksBySeat)(SEATS, profileIds, result.profiles) };
|
|
1742
1801
|
},
|
|
1743
1802
|
[recordOutcome]
|
|
1744
1803
|
);
|
|
1745
|
-
const value = (0,
|
|
1746
|
-
return /* @__PURE__ */ (0,
|
|
1804
|
+
const value = (0, import_react19.useMemo)(() => ({ stats, unlockedAchievements, record, resetAll }), [stats, unlockedAchievements, record, resetAll]);
|
|
1805
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Context.Provider, { value, children });
|
|
1747
1806
|
}
|
|
1748
1807
|
function useStats() {
|
|
1749
|
-
const ctx = (0,
|
|
1808
|
+
const ctx = (0, import_react19.useContext)(Context);
|
|
1750
1809
|
if (!ctx) throw new Error(`The ${key} stats are read within their game's Provider`);
|
|
1751
1810
|
return ctx;
|
|
1752
1811
|
}
|
|
@@ -1754,7 +1813,7 @@ function createGameStats({ key, defaultStats, isValidStats, catalog, getProfileS
|
|
|
1754
1813
|
}
|
|
1755
1814
|
|
|
1756
1815
|
// src/playerSettings.ts
|
|
1757
|
-
var
|
|
1816
|
+
var import_react20 = require("react");
|
|
1758
1817
|
var import_react_redux12 = require("react-redux");
|
|
1759
1818
|
var SEATS2 = [1, 2];
|
|
1760
1819
|
function seatPlayerKey(selection, seat) {
|
|
@@ -1798,8 +1857,8 @@ function createPlayerSettings({ id, defaults, distinctControls }) {
|
|
|
1798
1857
|
const saved = (0, import_react_redux12.useSelector)((state) => state[settingsKey]);
|
|
1799
1858
|
const controls = (0, import_react_redux12.useSelector)((state) => state[controlsKey]);
|
|
1800
1859
|
const dispatch = (0, import_react_redux12.useDispatch)();
|
|
1801
|
-
const settings = (0,
|
|
1802
|
-
const setSettings = (0,
|
|
1860
|
+
const settings = (0, import_react20.useMemo)(() => compose(saved, controls, selection, seatTwoIsPerson), [saved, controls, selection, seatTwoIsPerson]);
|
|
1861
|
+
const setSettings = (0, import_react20.useCallback)(
|
|
1803
1862
|
(next) => {
|
|
1804
1863
|
const { controlScheme, ...changes } = next;
|
|
1805
1864
|
if (Object.keys(changes).length > 0) dispatch(patch(seatPlayerKey(selection, 1), changes));
|
|
@@ -1822,6 +1881,8 @@ function createPlayerSettings({ id, defaults, distinctControls }) {
|
|
|
1822
1881
|
GUEST_PLAYER_ID,
|
|
1823
1882
|
HomeScreen,
|
|
1824
1883
|
LoadoutRoute,
|
|
1884
|
+
MATCH_CHIPS_FADE_MS,
|
|
1885
|
+
MatchChips,
|
|
1825
1886
|
PREVIEW_ASPECT,
|
|
1826
1887
|
PackProvider,
|
|
1827
1888
|
PlayRoute,
|
|
@@ -1857,6 +1918,7 @@ function createPlayerSettings({ id, defaults, distinctControls }) {
|
|
|
1857
1918
|
seatTwoFor,
|
|
1858
1919
|
useActiveRound,
|
|
1859
1920
|
useAppSettings,
|
|
1921
|
+
useAtComputer,
|
|
1860
1922
|
useGameGuide,
|
|
1861
1923
|
useOpponent,
|
|
1862
1924
|
usePack,
|