@tastic/shell 0.1.1 → 0.2.1
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 +71 -12
- package/dist/index.d.mts +86 -14
- package/dist/index.d.ts +86 -14
- package/dist/index.js +337 -165
- package/dist/index.mjs +327 -156
- package/package.json +9 -9
- package/src/PackContext.tsx +2 -2
- package/src/RootLayout.tsx +110 -28
- package/src/components/GuideHost.tsx +62 -23
- package/src/components/Providers.tsx +17 -7
- package/src/components/SeatTwoPanel.tsx +2 -1
- package/src/components/SettingsDialog.tsx +6 -4
- package/src/components/UpdateDialog.tsx +1 -1
- package/src/hooks/useSeatColors.ts +54 -27
- package/src/index.ts +1 -1
- package/src/redux/createPackStore.ts +16 -6
- package/src/redux/shellState.ts +4 -2
- package/src/routes.ts +10 -0
- package/src/screens/GameRoute.tsx +15 -7
- package/src/screens/HomeScreen.tsx +145 -76
- package/src/screens/LoadoutScreen.tsx +13 -7
- package/src/screens/ProfilesRoute.tsx +26 -1
- package/src/screens/StatsScreen.tsx +138 -56
- package/src/types.ts +143 -10
package/dist/index.js
CHANGED
|
@@ -32,6 +32,7 @@ var index_exports = {};
|
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
DEFAULT_APP_SETTINGS: () => DEFAULT_APP_SETTINGS,
|
|
34
34
|
DEFAULT_OPPONENT: () => DEFAULT_OPPONENT,
|
|
35
|
+
GUEST_PLAYER_ID: () => GUEST_PLAYER_ID,
|
|
35
36
|
HomeScreen: () => HomeScreen,
|
|
36
37
|
LoadoutRoute: () => LoadoutRoute,
|
|
37
38
|
PREVIEW_ASPECT: () => PREVIEW_ASPECT,
|
|
@@ -99,7 +100,8 @@ var import_auto_paper2 = require("@rific/auto-paper");
|
|
|
99
100
|
var import_feedback_press2 = require("@rific/feedback-press");
|
|
100
101
|
var import_toaster2 = require("@rific/toaster");
|
|
101
102
|
var import_core6 = require("@tastic/core");
|
|
102
|
-
var
|
|
103
|
+
var import_chrome2 = require("@tastic/hud/chrome");
|
|
104
|
+
var import_profile3 = require("@tastic/profile");
|
|
103
105
|
var Haptics = __toESM(require("expo-haptics"));
|
|
104
106
|
var import_expo_router = require("expo-router");
|
|
105
107
|
var import_expo_sensors = require("expo-sensors");
|
|
@@ -148,24 +150,35 @@ function seatTwoFor(saved, choices) {
|
|
|
148
150
|
function humanSeatsFor(mode) {
|
|
149
151
|
return mode === "twoPlayer" ? [1, 2] : [1];
|
|
150
152
|
}
|
|
153
|
+
var GUEST_PLAYER_ID = "guest";
|
|
151
154
|
|
|
152
155
|
// src/components/GuideHost.tsx
|
|
153
156
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
157
|
+
var PACK_GUIDE = "__pack__";
|
|
158
|
+
var NO_INPUT = {};
|
|
154
159
|
var GameGuideContext = (0, import_react2.createContext)(null);
|
|
155
160
|
function GuideHost({ children }) {
|
|
156
161
|
const pack = usePack();
|
|
157
|
-
const [
|
|
158
|
-
const
|
|
162
|
+
const [subject, setSubject] = (0, import_react2.useState)(() => pack.guide ? PACK_GUIDE : pack.games.find((g) => g.guide)?.id ?? null);
|
|
163
|
+
const packGuide = subject === PACK_GUIDE ? pack.guide : void 0;
|
|
164
|
+
const game = subject === PACK_GUIDE ? void 0 : pack.games.find((g) => g.id === subject);
|
|
165
|
+
const gameGuide = game?.guide;
|
|
159
166
|
const rotation = (0, import_core.useRotation)();
|
|
160
167
|
const touch = (0, import_core.useIsTouchPrimaryDevice)();
|
|
161
168
|
const seatTwo = (0, import_react_redux.useSelector)((state) => state.opponent.seatTwo);
|
|
162
|
-
const input = (0, import_react_redux.useSelector)((state) =>
|
|
163
|
-
const seenVersion = (0, import_react_redux.useSelector)((state) =>
|
|
169
|
+
const input = (0, import_react_redux.useSelector)((state) => gameGuide ? gameGuide.selectInput(state) : NO_INPUT, import_react_redux.shallowEqual);
|
|
170
|
+
const seenVersion = (0, import_react_redux.useSelector)((state) => (packGuide ?? gameGuide)?.selectVersionSeen(state) ?? 0);
|
|
164
171
|
const dispatch = (0, import_react_redux.useDispatch)();
|
|
165
|
-
const mode = roundModeFor(seatTwoFor(seatTwo, game
|
|
166
|
-
const steps = (0, import_react2.useMemo)(() =>
|
|
167
|
-
const onSeen = (0, import_react2.useCallback)(
|
|
168
|
-
|
|
172
|
+
const mode = roundModeFor(seatTwoFor(seatTwo, game?.seatTwo));
|
|
173
|
+
const steps = (0, import_react2.useMemo)(() => packGuide ? packGuide.getSteps({ touch }) : gameGuide ? gameGuide.getSteps(input, { touch, mode }) : [], [packGuide, gameGuide, input, touch, mode]);
|
|
174
|
+
const onSeen = (0, import_react2.useCallback)(
|
|
175
|
+
(version) => {
|
|
176
|
+
const guide = packGuide ?? gameGuide;
|
|
177
|
+
if (guide) dispatch(guide.markSeen(version));
|
|
178
|
+
},
|
|
179
|
+
[dispatch, packGuide, gameGuide]
|
|
180
|
+
);
|
|
181
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_guide.GuideProvider, { steps, currentVersion: (packGuide ?? gameGuide)?.version ?? 0, seenVersion, onSeen, rotation, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(GameGuideBridge, { onPick: setSubject, children }) });
|
|
169
182
|
}
|
|
170
183
|
function GameGuideBridge({ onPick, children }) {
|
|
171
184
|
const pack = usePack();
|
|
@@ -173,6 +186,7 @@ function GameGuideBridge({ onPick, children }) {
|
|
|
173
186
|
const { isOpen, open } = (0, import_guide.useGuide)();
|
|
174
187
|
const pendingNext = (0, import_react2.useRef)(null);
|
|
175
188
|
const wasOpen = (0, import_react2.useRef)(false);
|
|
189
|
+
const packAutoShown = (0, import_react2.useRef)(false);
|
|
176
190
|
(0, import_react2.useEffect)(() => {
|
|
177
191
|
if (wasOpen.current && !isOpen && pendingNext.current) {
|
|
178
192
|
const next = pendingNext.current;
|
|
@@ -183,15 +197,16 @@ function GameGuideBridge({ onPick, children }) {
|
|
|
183
197
|
}, [isOpen]);
|
|
184
198
|
const openFor = (0, import_react2.useCallback)(
|
|
185
199
|
(gameId) => {
|
|
200
|
+
if (!pack.games.find((g) => g.id === gameId)?.guide) return;
|
|
186
201
|
onPick(gameId);
|
|
187
202
|
open();
|
|
188
203
|
},
|
|
189
|
-
[onPick, open]
|
|
204
|
+
[pack, onPick, open]
|
|
190
205
|
);
|
|
191
206
|
const openFirstTime = (0, import_react2.useCallback)(
|
|
192
207
|
(gameId, next) => {
|
|
193
|
-
const
|
|
194
|
-
if (!
|
|
208
|
+
const guide = pack.games.find((g) => g.id === gameId)?.guide;
|
|
209
|
+
if (!guide || guide.selectVersionSeen(store.getState()) >= guide.version) {
|
|
195
210
|
next();
|
|
196
211
|
return;
|
|
197
212
|
}
|
|
@@ -200,7 +215,18 @@ function GameGuideBridge({ onPick, children }) {
|
|
|
200
215
|
},
|
|
201
216
|
[pack, store, openFor]
|
|
202
217
|
);
|
|
203
|
-
const
|
|
218
|
+
const openPack = (0, import_react2.useCallback)(() => {
|
|
219
|
+
if (!pack.guide) return;
|
|
220
|
+
onPick(PACK_GUIDE);
|
|
221
|
+
open();
|
|
222
|
+
}, [pack, onPick, open]);
|
|
223
|
+
const autoShowPack = (0, import_react2.useCallback)(() => {
|
|
224
|
+
const guide = pack.guide;
|
|
225
|
+
if (!guide || packAutoShown.current || guide.selectVersionSeen(store.getState()) >= guide.version) return;
|
|
226
|
+
packAutoShown.current = true;
|
|
227
|
+
openPack();
|
|
228
|
+
}, [pack, store, openPack]);
|
|
229
|
+
const value = (0, import_react2.useMemo)(() => ({ openFirstTime, openFor, openPack, autoShowPack }), [openFirstTime, openFor, openPack, autoShowPack]);
|
|
204
230
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(GameGuideContext.Provider, { value, children });
|
|
205
231
|
}
|
|
206
232
|
function useGameGuide() {
|
|
@@ -220,15 +246,20 @@ var RNPaper = __toESM(require("react-native-paper"));
|
|
|
220
246
|
var import_react_redux2 = require("react-redux");
|
|
221
247
|
var import_react4 = require("redux-persist/integration/react");
|
|
222
248
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
249
|
+
function useShellFeedbackSounds() {
|
|
250
|
+
const selection = (0, import_audio.useAudioPool)(require("./select-MLBNNA4N.wav"));
|
|
251
|
+
const notification = (0, import_audio.useAudioPool)(require("./notification-CGGFPYK7.wav"));
|
|
252
|
+
return { selection, notification };
|
|
253
|
+
}
|
|
223
254
|
var FeedbackBridge = ({ children }) => {
|
|
224
255
|
const haptic = (0, import_react_redux2.useSelector)((state) => state.haptic);
|
|
225
256
|
const sound = (0, import_react_redux2.useSelector)((state) => state.sound);
|
|
226
257
|
const dispatch = (0, import_react_redux2.useDispatch)();
|
|
227
258
|
const onChange = (0, import_react3.useCallback)((next) => dispatch(import_feedback_press.hapticActions.initialize(next)), [dispatch]);
|
|
228
259
|
const onSoundChange = (0, import_react3.useCallback)((next) => dispatch(import_feedback_press.soundActions.initialize(next)), [dispatch]);
|
|
229
|
-
const
|
|
230
|
-
const
|
|
231
|
-
const bridgeProps = (0, import_feedback_press.useFeedbackBridgeProps)({ initialValue: haptic, onChange, soundInitialValue: sound, onSoundChange, sound:
|
|
260
|
+
const { useFeedbackSounds = useShellFeedbackSounds } = usePack();
|
|
261
|
+
const sounds = useFeedbackSounds();
|
|
262
|
+
const bridgeProps = (0, import_feedback_press.useFeedbackBridgeProps)({ initialValue: haptic, onChange, soundInitialValue: sound, onSoundChange, sound: sounds });
|
|
232
263
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_feedback_press.FeedbackPressProvider, { ...bridgeProps, paper: RNPaper, children });
|
|
233
264
|
};
|
|
234
265
|
var EdgeGuardBridge = ({ children }) => {
|
|
@@ -271,12 +302,12 @@ function Theme({ children }) {
|
|
|
271
302
|
// src/components/UpdateDialog.tsx
|
|
272
303
|
var import_toaster = require("@rific/toaster");
|
|
273
304
|
var import_core3 = require("@tastic/core");
|
|
274
|
-
var
|
|
305
|
+
var import_chrome = require("@tastic/hud/chrome");
|
|
275
306
|
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
276
307
|
function UpdateDialog() {
|
|
277
308
|
const onError = (0, import_toaster.useUpdateErrorToast)();
|
|
278
309
|
const rotation = (0, import_core3.useRotation)();
|
|
279
|
-
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
310
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_chrome.UpdateDialog, { onError, rotation });
|
|
280
311
|
}
|
|
281
312
|
|
|
282
313
|
// src/hooks/useAppSettings.ts
|
|
@@ -446,18 +477,39 @@ function useProfiles() {
|
|
|
446
477
|
// src/RootLayout.tsx
|
|
447
478
|
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
448
479
|
var PLAY_OPTIONS = { statusBarHidden: true };
|
|
480
|
+
var KEEP_STATUS_BAR_OPTIONS = {};
|
|
481
|
+
var TRANSPARENT_CONTENT = { backgroundColor: "transparent" };
|
|
482
|
+
var noScreenOptions = () => ({});
|
|
449
483
|
function AppStack() {
|
|
484
|
+
const pack = usePack();
|
|
485
|
+
const { Backdrop } = pack;
|
|
450
486
|
const { dark } = (0, import_auto_paper2.useAutoPaperTheme)();
|
|
451
|
-
const rootBackground = (0, import_core6.useThemedRootBackground)(dark, false);
|
|
487
|
+
const rootBackground = (0, import_core6.useThemedRootBackground)(Backdrop ? true : dark, false);
|
|
452
488
|
const statusBar = (0, import_core6.useRotationAwareStatusBar)();
|
|
453
|
-
|
|
489
|
+
const packOptions = (pack.useScreenOptions ?? noScreenOptions)();
|
|
490
|
+
const backdropOptions = Backdrop ? { contentStyle: TRANSPARENT_CONTENT, animation: import_react_native2.Platform.select({ android: "fade" }) } : void 0;
|
|
491
|
+
const playOptions = (0, import_react9.useCallback)(
|
|
492
|
+
({ route }) => {
|
|
493
|
+
const id = route.params?.game;
|
|
494
|
+
return pack.games.some((g) => g.id === id && g.keepStatusBar) ? KEEP_STATUS_BAR_OPTIONS : PLAY_OPTIONS;
|
|
495
|
+
},
|
|
496
|
+
[pack.games]
|
|
497
|
+
);
|
|
498
|
+
const navigationTheme = (0, import_react9.useMemo)(() => Backdrop ? { ...import_expo_router.DarkTheme, colors: { ...import_expo_router.DarkTheme.colors, background: "transparent" } } : null, [Backdrop]);
|
|
499
|
+
const stack = /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_expo_router.Stack, { screenOptions: { ...rootBackground, ...statusBar, ...backdropOptions, ...packOptions }, children: [
|
|
454
500
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_expo_router.Stack.Screen, { name: "index" }),
|
|
455
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_expo_router.Stack.Screen, { name: "play/[game]", options:
|
|
501
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_expo_router.Stack.Screen, { name: "play/[game]", options: playOptions })
|
|
502
|
+
] });
|
|
503
|
+
if (!Backdrop || !navigationTheme) return stack;
|
|
504
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native2.View, { style: styles.root, children: [
|
|
505
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Backdrop, {}),
|
|
506
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_expo_router.ThemeProvider, { value: navigationTheme, children: stack })
|
|
456
507
|
] });
|
|
457
508
|
}
|
|
458
509
|
function OrientationBridge({ children }) {
|
|
459
510
|
const { settings, setSettings } = useAppSettings();
|
|
460
|
-
|
|
511
|
+
const { portraitWhileKeyboard } = usePack();
|
|
512
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_core6.OrientationProvider, { deviceMotion: import_expo_sensors.DeviceMotion, freezeWhileLocked: true, lockInitialValue: { locked: settings.lockOrientation, rotation: settings.lockedRotation }, onLockChange: (next) => setSettings({ lockOrientation: next.locked, lockedRotation: next.rotation }), portraitWhileKeyboard, children });
|
|
461
513
|
}
|
|
462
514
|
function GatedApp({ children }) {
|
|
463
515
|
const { loaded } = useProfiles();
|
|
@@ -465,24 +517,38 @@ function GatedApp({ children }) {
|
|
|
465
517
|
}
|
|
466
518
|
function HapticGatedToastProvider({ children }) {
|
|
467
519
|
const { settings } = (0, import_feedback_press2.useHapticSettings)();
|
|
468
|
-
|
|
520
|
+
const { Toaster: PackToasterComponent } = usePack();
|
|
521
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_toaster2.ToastProvider, { haptics: settings.vibrate ? Haptics : void 0, paper: PackToasterComponent ? void 0 : RNPaper2, children });
|
|
469
522
|
}
|
|
470
523
|
function RotatingToaster() {
|
|
471
524
|
const renderFrame = (0, import_react9.useCallback)(
|
|
472
|
-
(toasts) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
525
|
+
(toasts) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_chrome2.RotatedFrame, { rotatedSafeArea: true, passThrough: true, children: toasts }),
|
|
473
526
|
[]
|
|
474
527
|
);
|
|
475
528
|
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_toaster2.Toaster, { historyButton: null, clearButton: null, limit: 3, renderFrame });
|
|
476
529
|
}
|
|
530
|
+
function PackToaster({ Toaster: PackToasterComponent }) {
|
|
531
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native2.View, { style: import_react_native2.StyleSheet.absoluteFill, pointerEvents: "box-none", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_chrome2.RotatedFrame, { rotatedSafeArea: true, passThrough: true, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(PackToasterComponent, {}) }) });
|
|
532
|
+
}
|
|
477
533
|
function GameProviders({ games, children }) {
|
|
478
|
-
return games.reduceRight((inner, game) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(game.Provider, { children: inner }, game.id), children);
|
|
534
|
+
return games.reduceRight((inner, game) => game.Provider ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(game.Provider, { children: inner }, game.id) : inner, children);
|
|
535
|
+
}
|
|
536
|
+
function PreviewColors({ previewColor, children }) {
|
|
537
|
+
const { dark } = (0, import_auto_paper2.useAutoPaperTheme)();
|
|
538
|
+
const preview = (0, import_react9.useCallback)((hex) => previewColor(hex, dark), [previewColor, dark]);
|
|
539
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_profile3.ProfileColorProvider, { preview, children });
|
|
540
|
+
}
|
|
541
|
+
function PackRoot({ pack, children }) {
|
|
542
|
+
const { Provider, previewColor } = pack;
|
|
543
|
+
const inner = Provider ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Provider, { children }) : children;
|
|
544
|
+
return previewColor ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(PreviewColors, { previewColor, children: inner }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_jsx_runtime9.Fragment, { children: inner });
|
|
479
545
|
}
|
|
480
546
|
function RootLayout({ pack, store, persistor }) {
|
|
481
|
-
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_gesture_handler.GestureHandlerRootView, { style: styles.root, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_safe_area_context.SafeAreaProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(PackProvider, { pack, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Fonts, { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Providers, { store, persistor, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Theme, { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ProfilesProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(LastActiveGameProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(GameProviders, { games: pack.games, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(GatedApp, { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(OrientationBridge, { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(HapticGatedToastProvider, { children: [
|
|
547
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_gesture_handler.GestureHandlerRootView, { style: styles.root, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_safe_area_context.SafeAreaProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(PackProvider, { pack, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Fonts, { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Providers, { store, persistor, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Theme, { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ProfilesProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(LastActiveGameProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(GameProviders, { games: pack.games, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(PackRoot, { pack, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(GatedApp, { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(OrientationBridge, { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(HapticGatedToastProvider, { children: [
|
|
482
548
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(GuideHost, { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(AppStack, {}) }),
|
|
483
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(RotatingToaster, {}),
|
|
549
|
+
pack.Toaster ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(PackToaster, { Toaster: pack.Toaster }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(RotatingToaster, {}),
|
|
484
550
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(UpdateDialog, {})
|
|
485
|
-
] }) }) }) }) }) }) }) }) }) }) }) });
|
|
551
|
+
] }) }) }) }) }) }) }) }) }) }) }) }) });
|
|
486
552
|
}
|
|
487
553
|
var styles = import_react_native2.StyleSheet.create({
|
|
488
554
|
root: { flex: 1 }
|
|
@@ -491,11 +557,19 @@ var styles = import_react_native2.StyleSheet.create({
|
|
|
491
557
|
// src/screens/GameRoute.tsx
|
|
492
558
|
var import_expo_router5 = require("expo-router");
|
|
493
559
|
var import_react14 = require("react");
|
|
560
|
+
var import_react_native5 = require("react-native");
|
|
561
|
+
|
|
562
|
+
// src/routes.ts
|
|
563
|
+
var playHref = (game) => ({ pathname: "/play/[game]", params: { game } });
|
|
564
|
+
var loadoutHref = (game) => ({ pathname: "/loadout/[game]", params: { game } });
|
|
565
|
+
var STATS_HREF = "/stats";
|
|
566
|
+
var PROFILES_HREF = "/profiles";
|
|
494
567
|
|
|
495
568
|
// src/screens/LoadoutScreen.tsx
|
|
496
569
|
var import_auto_paper4 = require("@rific/auto-paper");
|
|
497
570
|
var import_core10 = require("@tastic/core");
|
|
498
|
-
var
|
|
571
|
+
var import_chrome4 = require("@tastic/hud/chrome");
|
|
572
|
+
var import_lobby2 = require("@tastic/hud/lobby");
|
|
499
573
|
var import_split_screen = require("@tastic/split-screen");
|
|
500
574
|
var import_expo_router4 = require("expo-router");
|
|
501
575
|
var import_react13 = require("react");
|
|
@@ -505,8 +579,8 @@ var import_react_native_safe_area_context2 = require("react-native-safe-area-con
|
|
|
505
579
|
var import_react_redux9 = require("react-redux");
|
|
506
580
|
|
|
507
581
|
// src/components/SeatTwoPanel.tsx
|
|
508
|
-
var
|
|
509
|
-
var
|
|
582
|
+
var import_lobby = require("@tastic/hud/lobby");
|
|
583
|
+
var import_profile4 = require("@tastic/profile");
|
|
510
584
|
var import_react10 = require("react");
|
|
511
585
|
var import_react_native3 = require("react-native");
|
|
512
586
|
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
@@ -549,14 +623,14 @@ function SeatTwoPanel({ idPrefix, host, choices, seatTwo, onSeatTwoChange, cpuDi
|
|
|
549
623
|
};
|
|
550
624
|
const colorSection = seatTwo === "nobody" ? void 0 : { value: color, onChange: onColorChange, swatches, takenValue: takenColor, allowSwapTaken, caption: selectedProfile ? colorCaption : void 0 };
|
|
551
625
|
const pickerId = getSeatTwoPopoverId(idPrefix);
|
|
552
|
-
const size = (0,
|
|
553
|
-
const align = (0,
|
|
626
|
+
const size = (0, import_profile4.getOptionPickerContentSize)(options.length, colorSection);
|
|
627
|
+
const align = (0, import_lobby.useZoneClampedAlign)(host.openId === pickerId, size.width, size.height);
|
|
554
628
|
const ownPopoverOpen = host.openId?.startsWith(`${idPrefix}-`) ?? false;
|
|
555
629
|
const pickerRowOpen = secondPickerId !== void 0 && host.openId === secondPickerId;
|
|
556
630
|
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native3.View, { style: [styles2.panel, ownPopoverOpen && styles2.panelOpen], children: [
|
|
557
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
631
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_profile4.OptionPicker, { id: pickerId, host, options, value, onChange: handleChange, color, dark, icon, colorSection, alignOverride: align }),
|
|
558
632
|
isPerson && secondPicker && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native3.View, { style: [styles2.pickerRow, pickerRowOpen && styles2.pickerRowOpen], children: secondPicker }),
|
|
559
|
-
isPerson && showReadyButton && onToggleReady && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
633
|
+
isPerson && showReadyButton && onToggleReady && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lobby.ReadyButton, { color, ready: ready ?? false, onToggleReady })
|
|
560
634
|
] });
|
|
561
635
|
}
|
|
562
636
|
var styles2 = import_react_native3.StyleSheet.create({
|
|
@@ -582,13 +656,14 @@ var styles2 = import_react_native3.StyleSheet.create({
|
|
|
582
656
|
|
|
583
657
|
// src/components/SettingsDialog.tsx
|
|
584
658
|
var import_toaster3 = require("@rific/toaster");
|
|
585
|
-
var
|
|
659
|
+
var import_chrome3 = require("@tastic/hud/chrome");
|
|
586
660
|
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
587
661
|
function SettingsDialog({ visible, onDismiss, rotation = 0, onShowHowToPlay, children }) {
|
|
588
662
|
const onUpdateError = (0, import_toaster3.useUpdateErrorToast)();
|
|
589
663
|
const { settings, setSettings } = useAppSettings();
|
|
590
|
-
const { otaVersion, SettingsSections } = usePack();
|
|
591
|
-
|
|
664
|
+
const { otaVersion, SettingsSections, edgeGuard = true } = usePack();
|
|
665
|
+
const edgeGuardProps = edgeGuard ? { deferBottomEdgeGestures: settings.deferBottomEdgeGestures, onDeferBottomEdgeGestures: (value) => setSettings({ deferBottomEdgeGestures: value }) } : {};
|
|
666
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_chrome3.BaseSettingsDialog, { visible, onDismiss, rotation, version: otaVersion, lockOrientation: settings.lockOrientation, onLockOrientationChange: (value) => setSettings({ lockOrientation: value }), ...edgeGuardProps, onUpdateError, onShowHowToPlay, children: [
|
|
592
667
|
children,
|
|
593
668
|
SettingsSections && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SettingsSections, {})
|
|
594
669
|
] });
|
|
@@ -617,29 +692,33 @@ function useOpponent() {
|
|
|
617
692
|
|
|
618
693
|
// src/hooks/useSeatColors.ts
|
|
619
694
|
var import_auto_paper3 = require("@rific/auto-paper");
|
|
620
|
-
var
|
|
695
|
+
var import_profile6 = require("@tastic/profile");
|
|
621
696
|
var import_expo_router2 = require("expo-router");
|
|
622
697
|
var import_react12 = require("react");
|
|
623
698
|
var import_react_redux8 = require("react-redux");
|
|
624
699
|
|
|
625
700
|
// src/redux/seatColorsSlice.ts
|
|
626
|
-
var
|
|
701
|
+
var import_profile5 = require("@tastic/profile");
|
|
627
702
|
function defaultSeatColorsState(seatColors) {
|
|
628
703
|
return { lastGuestColor: { 1: seatColors[1], 2: seatColors[2] }, lastCpuColor: seatColors[2], profileColors: {} };
|
|
629
704
|
}
|
|
630
705
|
function createSeatColorsReducer(seatColors) {
|
|
631
|
-
return (0,
|
|
706
|
+
return (0, import_profile5.createSeatColorsSlice)("pack", defaultSeatColorsState(seatColors)).reducer;
|
|
632
707
|
}
|
|
633
|
-
var seatColorsActions = (0,
|
|
708
|
+
var seatColorsActions = (0, import_profile5.createSeatColorsSlice)("pack", defaultSeatColorsState({ 1: "", 2: "" })).actions;
|
|
634
709
|
|
|
635
710
|
// src/hooks/useSeatColors.ts
|
|
711
|
+
function sameTheme(current, next) {
|
|
712
|
+
const a = current.color;
|
|
713
|
+
const b = next.color;
|
|
714
|
+
const sameColor = typeof a === "string" || typeof b === "string" ? typeof a === typeof b && String(a).toLowerCase() === String(b).toLowerCase() : !!a && !!b && a.primary.toLowerCase() === b.primary.toLowerCase() && a.secondary.toLowerCase() === b.secondary.toLowerCase();
|
|
715
|
+
return sameColor && (next.harmony === void 0 || next.harmony === current.harmony);
|
|
716
|
+
}
|
|
636
717
|
function useSeatColors(p2IsHuman) {
|
|
637
|
-
const { colors: themeColors } = (0, import_auto_paper3.useAutoPaperTheme)();
|
|
638
|
-
const { set: setThemeColor } = (0, import_auto_paper3.useThemeSettings)();
|
|
639
|
-
const p1Color = themeColors.primary;
|
|
640
|
-
const p2Color = themeColors.secondary;
|
|
718
|
+
const { dark, colors: themeColors } = (0, import_auto_paper3.useAutoPaperTheme)();
|
|
719
|
+
const { settings: themeSettings, set: setThemeColor } = (0, import_auto_paper3.useThemeSettings)();
|
|
641
720
|
const { profiles, lastSelected } = useProfiles();
|
|
642
|
-
const { seatColors } = usePack();
|
|
721
|
+
const { seatColors, seatTheme } = usePack();
|
|
643
722
|
const seatDefaultColors = [seatColors[1], seatColors[2]];
|
|
644
723
|
const dispatch = (0, import_react_redux8.useDispatch)();
|
|
645
724
|
const guestColors = (0, import_react_redux8.useSelector)((state) => state.seatColors.lastGuestColor);
|
|
@@ -647,11 +726,21 @@ function useSeatColors(p2IsHuman) {
|
|
|
647
726
|
const profileColors = (0, import_react_redux8.useSelector)((state) => state.seatColors.profileColors);
|
|
648
727
|
const p1Profile = profiles.find((p) => p.id === lastSelected[1]) ?? null;
|
|
649
728
|
const p2Profile = p2IsHuman ? profiles.find((p) => p.id === lastSelected[2]) ?? null : null;
|
|
729
|
+
const rememberedColors = (p1Prof, p2Prof, picks, guest, cpu) => {
|
|
730
|
+
const p1 = p1Prof ? (0, import_profile6.profileSeatColor)(p1Prof, picks) : guest[1];
|
|
731
|
+
const p2 = (0, import_profile6.avoidSeatColorClash)(p1, p2Prof ? (0, import_profile6.profileSeatColor)(p2Prof, picks) : p2IsHuman ? guest[2] : cpu, seatDefaultColors);
|
|
732
|
+
return { p1, p2 };
|
|
733
|
+
};
|
|
734
|
+
const remembered = rememberedColors(p1Profile, p2Profile, profileColors, guestColors, cpuColor);
|
|
735
|
+
const p1Color = seatTheme ? remembered.p1 : themeColors.primary;
|
|
736
|
+
const p2Color = seatTheme ? remembered.p2 : themeColors.secondary;
|
|
737
|
+
const themeFor = (0, import_react12.useCallback)((p1, p2) => seatTheme ? seatTheme({ 1: p1, 2: p2 }, dark) : { color: { primary: p1, secondary: p2, tertiary: (0, import_auto_paper3.getThirdColor)(p1, p2) } }, [seatTheme, dark]);
|
|
650
738
|
const p1ProfileRef = (0, import_react12.useRef)(p1Profile);
|
|
651
739
|
const p2ProfileRef = (0, import_react12.useRef)(p2Profile);
|
|
652
740
|
const guestColorsRef = (0, import_react12.useRef)(guestColors);
|
|
653
741
|
const cpuColorRef = (0, import_react12.useRef)(cpuColor);
|
|
654
742
|
const profileColorsRef = (0, import_react12.useRef)(profileColors);
|
|
743
|
+
const themeForRef = (0, import_react12.useRef)(themeFor);
|
|
655
744
|
(0, import_react12.useEffect)(() => {
|
|
656
745
|
p1ProfileRef.current = p1Profile;
|
|
657
746
|
}, [p1Profile]);
|
|
@@ -668,21 +757,17 @@ function useSeatColors(p2IsHuman) {
|
|
|
668
757
|
profileColorsRef.current = profileColors;
|
|
669
758
|
}, [profileColors]);
|
|
670
759
|
(0, import_react12.useEffect)(() => {
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
760
|
+
themeForRef.current = themeFor;
|
|
761
|
+
}, [themeFor]);
|
|
762
|
+
(0, import_react12.useEffect)(() => {
|
|
763
|
+
const next = themeFor(remembered.p1, remembered.p2);
|
|
764
|
+
if (sameTheme(themeSettings, next)) return;
|
|
765
|
+
setThemeColor(next);
|
|
766
|
+
}, [lastSelected[1], lastSelected[2], p2IsHuman, guestColors, cpuColor, profileColors, profiles.length, dark]);
|
|
676
767
|
(0, import_expo_router2.useFocusEffect)(
|
|
677
768
|
(0, import_react12.useCallback)(() => {
|
|
678
|
-
const
|
|
679
|
-
|
|
680
|
-
const p1Prof = p1ProfileRef.current;
|
|
681
|
-
const p2Prof = p2ProfileRef.current;
|
|
682
|
-
const picks = profileColorsRef.current;
|
|
683
|
-
const nextP1 = p1Prof ? (0, import_profile5.profileSeatColor)(p1Prof, picks) : guest[1];
|
|
684
|
-
const nextP2 = (0, import_profile5.avoidSeatColorClash)(nextP1, p2Prof ? (0, import_profile5.profileSeatColor)(p2Prof, picks) : p2IsHuman ? guest[2] : cpu, seatDefaultColors);
|
|
685
|
-
setThemeColor({ color: { primary: nextP1, secondary: nextP2, tertiary: (0, import_auto_paper3.getThirdColor)(nextP1, nextP2) } });
|
|
769
|
+
const next = rememberedColors(p1ProfileRef.current, p2ProfileRef.current, profileColorsRef.current, guestColorsRef.current, cpuColorRef.current);
|
|
770
|
+
setThemeColor(themeForRef.current(next.p1, next.p2));
|
|
686
771
|
}, [lastSelected[1], lastSelected[2], p2IsHuman, setThemeColor])
|
|
687
772
|
);
|
|
688
773
|
const persistSeatColor = (0, import_react12.useCallback)(
|
|
@@ -704,21 +789,21 @@ function useSeatColors(p2IsHuman) {
|
|
|
704
789
|
(hex) => {
|
|
705
790
|
const swapped = hex.toLowerCase() === p2Color.toLowerCase();
|
|
706
791
|
const nextP2 = swapped ? p1Color : p2Color;
|
|
707
|
-
setThemeColor(
|
|
792
|
+
setThemeColor(themeFor(hex, nextP2));
|
|
708
793
|
persistSeatColor(1, hex);
|
|
709
794
|
if (swapped) persistSeatColor(2, nextP2);
|
|
710
795
|
},
|
|
711
|
-
[setThemeColor, p1Color, p2Color, persistSeatColor]
|
|
796
|
+
[setThemeColor, themeFor, p1Color, p2Color, persistSeatColor]
|
|
712
797
|
);
|
|
713
798
|
const handleP2ColorChange = (0, import_react12.useCallback)(
|
|
714
799
|
(hex) => {
|
|
715
800
|
const swapped = hex.toLowerCase() === p1Color.toLowerCase();
|
|
716
801
|
const nextP1 = swapped ? p2Color : p1Color;
|
|
717
|
-
setThemeColor(
|
|
802
|
+
setThemeColor(themeFor(nextP1, hex));
|
|
718
803
|
persistSeatColor(2, hex);
|
|
719
804
|
if (swapped) persistSeatColor(1, nextP1);
|
|
720
805
|
},
|
|
721
|
-
[setThemeColor, p1Color, p2Color, persistSeatColor]
|
|
806
|
+
[setThemeColor, themeFor, p1Color, p2Color, persistSeatColor]
|
|
722
807
|
);
|
|
723
808
|
return { p1Color, p2Color, handleP1ColorChange, handleP2ColorChange };
|
|
724
809
|
}
|
|
@@ -754,6 +839,7 @@ function LoadoutScreen({ game }) {
|
|
|
754
839
|
const fixedSeats = p2IsHuman && (!!game.twoPlayerSeats?.faceToFaceOnWeb || import_react_native4.Platform.OS !== "web");
|
|
755
840
|
const fixedUpsideDown = !!game.twoPlayerSeats?.followUpsideDown && orientationMode === "faceToFace" && upsideDown;
|
|
756
841
|
const { panelLayout, panelFadeStyle } = (0, import_split_screen.useDualZoneLayout)(fixedSeats ? "faceToFace" : orientationMode, fixedSeats ? true : p1OnRight, fixedSeats || p1OnRightResolved, fixedSeats ? fixedUpsideDown : upsideDown, PANEL_SWAP_FADE_MS);
|
|
842
|
+
const playersRowFade = panelFadeStyle;
|
|
757
843
|
const [settingsOpen, setSettingsOpen] = (0, import_react13.useState)(false);
|
|
758
844
|
const rotation = (0, import_core10.getViewRotation)(panelLayout.orientationMode, panelLayout.p1OnRight, panelLayout.upsideDown);
|
|
759
845
|
const insets = (0, import_core10.rotateInsets)((0, import_react_native_safe_area_context2.useSafeAreaInsets)(), rotation);
|
|
@@ -782,7 +868,7 @@ function LoadoutScreen({ game }) {
|
|
|
782
868
|
(0, import_react13.useEffect)(() => {
|
|
783
869
|
if (!humanSeats.every((s) => ready[s])) return;
|
|
784
870
|
dispatch(liveplayActions.setActiveRound({ game: game.id, mode, settings: roundSettingsRef.current }));
|
|
785
|
-
import_expo_router4.router.push(
|
|
871
|
+
import_expo_router4.router.push(playHref(game.id));
|
|
786
872
|
}, [ready, humanSeats, game.id, mode, dispatch]);
|
|
787
873
|
const bg = dark ? "#000000" : "#FFFFFF";
|
|
788
874
|
const fg = dark ? "#FFFFFF" : "#000000";
|
|
@@ -791,8 +877,8 @@ function LoadoutScreen({ game }) {
|
|
|
791
877
|
const showMetaInSharedBand = (0, import_split_screen.needsSharedNeutralZone)(panelLayout.orientationMode, humanSeats.length);
|
|
792
878
|
const p2ZoneStyle = p2IsHuman ? isPortrait ? styles3.p2ZoneTop : panelLayout.p1OnRight ? styles3.p2ZoneLeft : styles3.p2ZoneRight : null;
|
|
793
879
|
const showReadyButton = p2IsHuman;
|
|
794
|
-
const controlsHost = (0,
|
|
795
|
-
const p2PanelHost = (0,
|
|
880
|
+
const controlsHost = (0, import_chrome4.usePopoverHost)();
|
|
881
|
+
const p2PanelHost = (0, import_chrome4.usePopoverHost)();
|
|
796
882
|
const p2Host = p2IsHuman ? p2PanelHost : controlsHost;
|
|
797
883
|
const anyPlayerPickerOpen = !!(controlsHost.openId?.startsWith("p1-") || controlsHost.openId?.startsWith("p2-"));
|
|
798
884
|
const optionsRow = loadout.options({
|
|
@@ -807,17 +893,17 @@ function LoadoutScreen({ game }) {
|
|
|
807
893
|
onReset: showMetaInSharedBand ? void 0 : loadout.reset
|
|
808
894
|
});
|
|
809
895
|
const optionsPopoverOpen = controlsHost.openId !== null && loadout.optionIds.includes(controlsHost.openId);
|
|
810
|
-
const sharedControls = showMetaInSharedBand ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
896
|
+
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;
|
|
811
897
|
const controlLook = { accentColor: themeColors.tertiary, mutedColor: fgMuted, dark, rotation };
|
|
812
898
|
const p1Control = loadout.seatControl(1, controlsHost, { ...controlLook, seatColor: p1Color });
|
|
813
|
-
const p1Panel = /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
899
|
+
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, ready: ready[1], onToggleReady: () => setReady((r) => ({ ...r, 1: !r[1] })), dark, showReadyButton, secondPicker: p1Control, secondPickerId: p1Control ? "p1-control" : void 0, profiles, selectedProfileId: lastSelected[1], takenProfileId: p2IsHuman ? lastSelected[2] : null, guestLabel: "P1", onProfileSelect: handleP1ProfileSelect, onManageProfiles: () => import_expo_router4.router.push(PROFILES_HREF) });
|
|
814
900
|
const p2Control = p2IsHuman ? loadout.seatControl(2, p2Host, { ...controlLook, seatColor: p2Color }) : void 0;
|
|
815
901
|
const p2Panel = game.seatTwo && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SeatTwoPanel, { idPrefix: "p2", host: p2Host, choices: game.seatTwo, seatTwo, onSeatTwoChange: changeSeatTwo, cpuDifficulty: loadout.cpuDifficulty, profiles, selectedProfileId: lastSelected[2], onProfileSelect: handleP2ProfileSelect, color: p2Color, onColorChange: handleP2ColorChange, swatches: import_auto_paper4.defaultColors, takenColor: p1Color, allowSwapTaken: mode === "vsCpu", colorCaption: pack.colorCaption, dark, secondPicker: p2Control, secondPickerId: p2Control ? "p2-control" : void 0, ready: ready[2], onToggleReady: () => setReady((r) => ({ ...r, 2: !r[2] })), showReadyButton });
|
|
816
902
|
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_react_native4.View, { style: [styles3.container, { backgroundColor: bg }], children: [
|
|
817
903
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_core10.FakeLandscapeView, { orientationMode: panelLayout.orientationMode, p1OnRight: panelLayout.p1OnRight, upsideDown: panelLayout.upsideDown, style: styles3.rotatable, children: [
|
|
818
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
819
|
-
p2ZoneStyle && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
820
|
-
!showMetaInSharedBand && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
904
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_chrome4.PressAwayOverlay, { active: controlsHost.openId !== null, onPress: controlsHost.close }),
|
|
905
|
+
p2ZoneStyle && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_chrome4.PressAwayOverlay, { active: controlsHost.openId !== null || p2Host.openId !== null, onPress: p2Host.close, style: p2ZoneStyle }),
|
|
906
|
+
!showMetaInSharedBand && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_chrome4.CornerActionButtons, { onBack: import_core8.safeBack, onSettings: () => setSettingsOpen(true), fg, insets }),
|
|
821
907
|
p2IsHuman ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
822
908
|
import_split_screen.DualZoneLayout,
|
|
823
909
|
{
|
|
@@ -832,11 +918,11 @@ function LoadoutScreen({ game }) {
|
|
|
832
918
|
}
|
|
833
919
|
) : /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_react_native4.View, { style: styles3.stackedZone, children: [
|
|
834
920
|
sharedControls,
|
|
835
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_react_native_reanimated2.default.View, { style: [styles3.playersRow, anyPlayerPickerOpen && styles3.playersRowOpen,
|
|
921
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_react_native_reanimated2.default.View, { style: [styles3.playersRow, anyPlayerPickerOpen && styles3.playersRowOpen, playersRowFade], children: [
|
|
836
922
|
!isPortrait && panelLayout.p1OnRight ? p2Panel : p1Panel,
|
|
837
923
|
!isPortrait && panelLayout.p1OnRight ? p1Panel : p2Panel
|
|
838
924
|
] }),
|
|
839
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
925
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lobby2.ReadyButton, { color: p1Color, ready: ready[1], onToggleReady: () => setReady((r) => ({ ...r, 1: !r[1] })), style: anyPlayerPickerOpen && styles3.readyButtonHidden })
|
|
840
926
|
] })
|
|
841
927
|
] }),
|
|
842
928
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SettingsDialog, { visible: settingsOpen, onDismiss: () => setSettingsOpen(false), rotation, onShowHowToPlay: () => openFor(game.id) })
|
|
@@ -902,7 +988,7 @@ function LoadoutRoute() {
|
|
|
902
988
|
const { game: id } = (0, import_expo_router5.useLocalSearchParams)();
|
|
903
989
|
const game = usePackGame(id);
|
|
904
990
|
if (!game) return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_expo_router5.Redirect, { href: "/" });
|
|
905
|
-
if (!hasLoadout(game)) return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_expo_router5.Redirect, { href:
|
|
991
|
+
if (!hasLoadout(game)) return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_expo_router5.Redirect, { href: playHref(game.id) });
|
|
906
992
|
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(LoadoutScreen, { game }, game.id);
|
|
907
993
|
}
|
|
908
994
|
function hasLoadout(game) {
|
|
@@ -921,7 +1007,9 @@ function useResumePoint(gameId) {
|
|
|
921
1007
|
(0, import_react14.useEffect)(() => {
|
|
922
1008
|
if (!gameId) return;
|
|
923
1009
|
setLastActiveGame(gameId);
|
|
924
|
-
return
|
|
1010
|
+
return () => {
|
|
1011
|
+
if (import_react_native5.AppState.currentState === "active") clearLastActiveGame();
|
|
1012
|
+
};
|
|
925
1013
|
}, [gameId, setLastActiveGame, clearLastActiveGame]);
|
|
926
1014
|
}
|
|
927
1015
|
|
|
@@ -929,11 +1017,11 @@ function useResumePoint(gameId) {
|
|
|
929
1017
|
var import_auto_paper5 = require("@rific/auto-paper");
|
|
930
1018
|
var import_feedback_press3 = require("@rific/feedback-press");
|
|
931
1019
|
var import_core12 = require("@tastic/core");
|
|
932
|
-
var
|
|
933
|
-
var
|
|
1020
|
+
var import_chrome5 = require("@tastic/hud/chrome");
|
|
1021
|
+
var import_profile7 = require("@tastic/profile");
|
|
934
1022
|
var import_expo_router6 = require("expo-router");
|
|
935
1023
|
var import_react16 = require("react");
|
|
936
|
-
var
|
|
1024
|
+
var import_react_native6 = require("react-native");
|
|
937
1025
|
var import_react_native_paper = require("react-native-paper");
|
|
938
1026
|
|
|
939
1027
|
// src/hooks/useFrozenWhileHidden.ts
|
|
@@ -1018,11 +1106,15 @@ var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
|
1018
1106
|
function HomeScreen() {
|
|
1019
1107
|
const pack = usePack();
|
|
1020
1108
|
const { consumeResumeGame } = useLastActiveGame();
|
|
1109
|
+
const { autoShowPack } = useGameGuide();
|
|
1021
1110
|
const [resumeGame] = (0, import_react16.useState)(() => {
|
|
1022
1111
|
const id = consumeResumeGame();
|
|
1023
1112
|
return pack.games.find((g) => g.id === id && g.resumable) ?? null;
|
|
1024
1113
|
});
|
|
1025
|
-
|
|
1114
|
+
(0, import_react16.useEffect)(() => {
|
|
1115
|
+
if (!resumeGame) autoShowPack();
|
|
1116
|
+
}, [resumeGame, autoShowPack]);
|
|
1117
|
+
if (resumeGame) return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_expo_router6.Redirect, { href: playHref(resumeGame.id) });
|
|
1026
1118
|
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(HomeMenu, {});
|
|
1027
1119
|
}
|
|
1028
1120
|
function HomeMenu() {
|
|
@@ -1030,20 +1122,21 @@ function HomeMenu() {
|
|
|
1030
1122
|
const rotation = (0, import_core12.useRotation)();
|
|
1031
1123
|
const layout = useHomeLayout();
|
|
1032
1124
|
const { insets } = layout;
|
|
1033
|
-
const { dark } = (0, import_auto_paper5.useAutoPaperTheme)();
|
|
1034
|
-
const { openFirstTime, openFor } = useGameGuide();
|
|
1125
|
+
const { dark, colors } = (0, import_auto_paper5.useAutoPaperTheme)();
|
|
1126
|
+
const { openFirstTime, openFor, openPack } = useGameGuide();
|
|
1035
1127
|
const [settingsOpen, setSettingsOpen] = (0, import_react16.useState)(false);
|
|
1128
|
+
const [rulesGame, setRulesGame] = (0, import_react16.useState)(null);
|
|
1036
1129
|
const isFocused = (0, import_expo_router6.useIsFocused)();
|
|
1037
|
-
const [appState, setAppState] = (0, import_react16.useState)(
|
|
1130
|
+
const [appState, setAppState] = (0, import_react16.useState)(import_react_native6.AppState.currentState);
|
|
1038
1131
|
(0, import_react16.useEffect)(() => {
|
|
1039
|
-
const subscription =
|
|
1132
|
+
const subscription = import_react_native6.AppState.addEventListener("change", setAppState);
|
|
1040
1133
|
return () => subscription.remove();
|
|
1041
1134
|
}, []);
|
|
1042
1135
|
const heroActive = isFocused && appState === "active";
|
|
1043
1136
|
const { profiles, lastSelected, selectProfile } = useProfiles();
|
|
1044
1137
|
const { seatTwo } = useOpponent();
|
|
1045
1138
|
const { p1Color, p2Color, handleP1ColorChange } = useSeatColors(seatTwo === "person");
|
|
1046
|
-
const pickerHost = (0,
|
|
1139
|
+
const pickerHost = (0, import_chrome5.usePopoverHost)();
|
|
1047
1140
|
const selectedProfile = profiles.find((p) => p.id === lastSelected[1]) ?? null;
|
|
1048
1141
|
const tiled = pack.games.some((game) => game.Preview);
|
|
1049
1142
|
const isWide = useFrozenWhileHidden(tiled && layout.isWide, !isFocused);
|
|
@@ -1056,71 +1149,91 @@ function HomeMenu() {
|
|
|
1056
1149
|
const closePicker = pickerHost.close;
|
|
1057
1150
|
(0, import_react16.useEffect)(() => {
|
|
1058
1151
|
closePicker();
|
|
1059
|
-
}, [isWide, closePicker]);
|
|
1060
|
-
const bg = dark ? "#000000" : "#FFFFFF";
|
|
1061
|
-
const fg = dark ? "#FFFFFF" : "#000000";
|
|
1062
|
-
const
|
|
1063
|
-
const
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1152
|
+
}, [isWide, rotation, layout.windowWidth, layout.windowHeight, closePicker]);
|
|
1153
|
+
const bg = pack.Backdrop ? "transparent" : dark ? "#000000" : "#FFFFFF";
|
|
1154
|
+
const fg = pack.foreground ?? (dark ? "#FFFFFF" : "#000000");
|
|
1155
|
+
const { previewColor } = pack;
|
|
1156
|
+
const p1Drawn = previewColor ? previewColor(p1Color, dark) : p1Color;
|
|
1157
|
+
const triggerStyle = (0, import_react16.useMemo)(() => pack.Backdrop ? [styles4.pill, { backgroundColor: colors.surface }] : void 0, [pack.Backdrop, colors.surface]);
|
|
1158
|
+
const openGame = (0, import_react16.useCallback)((game) => openFirstTime(game.id, () => import_expo_router6.router.push(game.useLoadout ? loadoutHref(game.id) : playHref(game.id))), [openFirstTime]);
|
|
1159
|
+
const openRules = (0, import_react16.useCallback)((game) => game.Rules ? setRulesGame(game) : openFor(game.id), [openFor]);
|
|
1160
|
+
const colorSection = { value: p1Color, onChange: handleP1ColorChange, swatches: import_auto_paper5.defaultColors, caption: selectedProfile ? pack.colorCaption : void 0, previewValue: previewColor ? (hex) => previewColor(hex, dark) : void 0 };
|
|
1161
|
+
const usePickerAlign = pack.usePickerAlign ?? noPickerAlign;
|
|
1162
|
+
const pickerSize = (0, import_profile7.getProfilePickerContentSize)(profiles.length, true, colorSection);
|
|
1163
|
+
const pickerAlign = usePickerAlign(pickerHost.openId === `${SEAT_ONE_PICKER}-profile`, pickerSize.width, pickerSize.height);
|
|
1164
|
+
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 });
|
|
1165
|
+
const pressAway = /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_chrome5.PressAwayOverlay, { active: pickerHost.openId !== null, onPress: pickerHost.close, style: styles4.pressAway });
|
|
1166
|
+
const RulesSheet = rulesGame?.Rules;
|
|
1167
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_react_native6.View, { style: [styles4.container, { backgroundColor: bg }], children: [
|
|
1168
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_core12.FakeLandscapeView, { style: styles4.rotatable, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(RulesHost, { enabled: pack.games.some((game) => game.Rules), children: [
|
|
1067
1169
|
isWide ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
|
|
1068
|
-
|
|
1069
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.
|
|
1170
|
+
pressAway,
|
|
1171
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_auto_paper5.FadingScrollView, { 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: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native6.View, { style: [styles4.grid, { width: layout.rightPaneWidth }], children: pack.games.map((game) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(GameTile, { game, width: layout.tileWidth, previewWidth: layout.previewWidth, previewRevealed: previewsRevealed, dark, p1Color, p2Color, onPress: () => openGame(game), onRules: hasRules(game) ? () => openRules(game) : void 0 }, game.id)) }) }),
|
|
1172
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_react_native6.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: [
|
|
1070
1173
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(pack.HeroTitle, { words: pack.wordmark, color: fg, p1Color, p2Color, active: heroActive, fit: layout.heroFit }),
|
|
1071
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1174
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native6.View, { style: styles4.widePicker, children: picker })
|
|
1072
1175
|
] })
|
|
1073
|
-
] }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
1176
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_auto_paper5.FadingScrollView, { style: styles4.scroll, contentContainerStyle: [styles4.content, { paddingTop: 56 + insets.top, paddingBottom: 24 + insets.bottom, paddingLeft: 16 + insets.left, paddingRight: 16 + insets.right }], children: [
|
|
1177
|
+
pressAway,
|
|
1074
1178
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(pack.HeroTitle, { words: pack.wordmark, color: fg, p1Color, p2Color, active: heroActive }),
|
|
1075
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1076
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1179
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native6.View, { style: [styles4.picker, pickerHost.openId !== null && styles4.pickerOpen], children: picker }),
|
|
1180
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native6.View, { style: styles4.list, children: pack.games.map((game) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(GameRow, { game, dark, p1Color, p2Color, previewRevealed: previewsRevealed, onPress: () => openGame(game), onRules: hasRules(game) ? () => openRules(game) : void 0 }, game.id)) })
|
|
1077
1181
|
] }),
|
|
1078
|
-
/* @__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(
|
|
1079
|
-
/* @__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" })
|
|
1080
|
-
|
|
1081
|
-
|
|
1182
|
+
/* @__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" }),
|
|
1183
|
+
/* @__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" }),
|
|
1184
|
+
RulesSheet && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(RulesSheet, { visible: true, onDismiss: () => setRulesGame(null) })
|
|
1185
|
+
] }) }),
|
|
1186
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(SettingsDialog, { visible: settingsOpen, onDismiss: () => setSettingsOpen(false), rotation, onShowHowToPlay: pack.guide ? openPack : void 0 })
|
|
1082
1187
|
] });
|
|
1083
1188
|
}
|
|
1189
|
+
var SEAT_ONE_PICKER = "home-p1";
|
|
1190
|
+
var noPickerAlign = () => void 0;
|
|
1191
|
+
function hasRules(game) {
|
|
1192
|
+
return !!(game.Rules || game.guide);
|
|
1193
|
+
}
|
|
1194
|
+
function RulesHost({ enabled, children }) {
|
|
1195
|
+
return enabled ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native_paper.Portal.Host, { children }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_jsx_runtime14.Fragment, { children });
|
|
1196
|
+
}
|
|
1084
1197
|
function GameRow({ game, dark, p1Color, p2Color, previewRevealed, onPress, onRules }) {
|
|
1085
|
-
const well = (0,
|
|
1198
|
+
const well = (0, import_chrome5.useWellColors)();
|
|
1086
1199
|
const GameIcon = game.icon;
|
|
1087
1200
|
return (
|
|
1088
1201
|
// The rules button sits beside the row's own button, laid over its end, not inside it: a button
|
|
1089
1202
|
// inside a button is invalid on the web.
|
|
1090
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
1203
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_react_native6.View, { children: [
|
|
1091
1204
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_feedback_press3.Pressable, { onPress, style: [styles4.row, { backgroundColor: well.bg }], accessibilityRole: "button", accessibilityLabel: game.title, children: [
|
|
1092
|
-
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)(
|
|
1093
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
1205
|
+
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_native6.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 }) }),
|
|
1206
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_react_native6.View, { style: styles4.rowText, children: [
|
|
1094
1207
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native_paper.Text, { variant: "titleLarge", style: [styles4.rowTitle, { color: well.fg }], numberOfLines: 1, children: game.title }),
|
|
1095
1208
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native_paper.Text, { variant: "bodyMedium", style: { color: well.fgMuted }, numberOfLines: 2, children: game.blurb })
|
|
1096
1209
|
] })
|
|
1097
1210
|
] }),
|
|
1098
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_feedback_press3.Pressable, { onPress: onRules, style: styles4.rulesButton, hitSlop: 12, accessibilityRole: "button", accessibilityLabel: `${game.title} rules`, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native_paper.Icon, { source: "information-outline", size: 22, color: well.fgMuted }) })
|
|
1211
|
+
onRules && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_feedback_press3.Pressable, { onPress: onRules, style: styles4.rulesButton, hitSlop: 12, accessibilityRole: "button", accessibilityLabel: `${game.title} rules`, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native_paper.Icon, { source: "information-outline", size: 22, color: well.fgMuted }) })
|
|
1099
1212
|
] })
|
|
1100
1213
|
);
|
|
1101
1214
|
}
|
|
1102
1215
|
function GameTile({ game, width, previewWidth, dark, p1Color, p2Color, previewRevealed, onPress, onRules }) {
|
|
1103
|
-
const well = (0,
|
|
1104
|
-
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
1216
|
+
const well = (0, import_chrome5.useWellColors)();
|
|
1217
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_react_native6.View, { style: { width }, children: [
|
|
1105
1218
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_feedback_press3.Pressable, { onPress, style: [styles4.tile, { backgroundColor: well.bg }], accessibilityRole: "button", accessibilityLabel: game.title, children: [
|
|
1106
1219
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(PreviewBox, { game, width: previewWidth, revealed: previewRevealed, dark, p1Color, p2Color }),
|
|
1107
1220
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native_paper.Text, { variant: "titleMedium", style: [styles4.rowTitle, { color: well.fg }], numberOfLines: 1, children: game.title }),
|
|
1108
1221
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native_paper.Text, { variant: "bodySmall", style: { color: well.fgMuted }, numberOfLines: 3, children: game.blurb })
|
|
1109
1222
|
] }),
|
|
1110
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_feedback_press3.Pressable, { onPress: onRules, style: styles4.tileRulesButton, hitSlop: 12, accessibilityRole: "button", accessibilityLabel: `${game.title} rules`, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native_paper.Icon, { source: "information-outline", size: 20, color: "#FFFFFF" }) })
|
|
1223
|
+
onRules && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_feedback_press3.Pressable, { onPress: onRules, style: styles4.tileRulesButton, hitSlop: 12, accessibilityRole: "button", accessibilityLabel: `${game.title} rules`, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native_paper.Icon, { source: "information-outline", size: 20, color: "#FFFFFF" }) })
|
|
1111
1224
|
] });
|
|
1112
1225
|
}
|
|
1113
1226
|
function PreviewBox({ game, width, revealed, dark, p1Color, p2Color }) {
|
|
1114
1227
|
const height = Math.round(width / PREVIEW_ASPECT);
|
|
1115
1228
|
const { Preview, icon: GameIcon } = game;
|
|
1116
1229
|
const iconSize = Math.min(height, ROW_ICON_SIZE);
|
|
1117
|
-
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1230
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native6.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_native6.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 }) }) });
|
|
1118
1231
|
}
|
|
1119
1232
|
var ROW_ICON_SIZE = 56;
|
|
1120
1233
|
var ICON_LIGHT_BG = "#FAFAFA";
|
|
1121
1234
|
var ICON_DARK_BG = "#050505";
|
|
1122
1235
|
var RULES_BUTTON_SPACE = 44;
|
|
1123
|
-
var styles4 =
|
|
1236
|
+
var styles4 = import_react_native6.StyleSheet.create({
|
|
1124
1237
|
container: {
|
|
1125
1238
|
flex: 1
|
|
1126
1239
|
},
|
|
@@ -1149,6 +1262,15 @@ var styles4 = import_react_native5.StyleSheet.create({
|
|
|
1149
1262
|
pickerOpen: {
|
|
1150
1263
|
zIndex: 100
|
|
1151
1264
|
},
|
|
1265
|
+
// Seat 1's button on the theme's surface (over a backdrop), the same pill as the tiles' wells.
|
|
1266
|
+
pill: {
|
|
1267
|
+
borderRadius: 999
|
|
1268
|
+
},
|
|
1269
|
+
// Over the rows (and, wide, the grid), whose own stacking is unset, so a press on them reaches it on
|
|
1270
|
+
// the web too, and under the raised button and left pane, so the menu's rows stay pressable.
|
|
1271
|
+
pressAway: {
|
|
1272
|
+
zIndex: 5
|
|
1273
|
+
},
|
|
1152
1274
|
// The preview's own rounding, clipping whatever it draws to the box.
|
|
1153
1275
|
preview: {
|
|
1154
1276
|
alignItems: "center",
|
|
@@ -1167,7 +1289,7 @@ var styles4 = import_react_native5.StyleSheet.create({
|
|
|
1167
1289
|
row: {
|
|
1168
1290
|
alignItems: "center",
|
|
1169
1291
|
borderRadius: 12,
|
|
1170
|
-
boxShadow:
|
|
1292
|
+
boxShadow: import_chrome5.WELL_SHADOW,
|
|
1171
1293
|
flexDirection: "row",
|
|
1172
1294
|
gap: 14,
|
|
1173
1295
|
padding: 14,
|
|
@@ -1199,7 +1321,7 @@ var styles4 = import_react_native5.StyleSheet.create({
|
|
|
1199
1321
|
// The same well as a row, turned on its side.
|
|
1200
1322
|
tile: {
|
|
1201
1323
|
borderRadius: 12,
|
|
1202
|
-
boxShadow:
|
|
1324
|
+
boxShadow: import_chrome5.WELL_SHADOW,
|
|
1203
1325
|
gap: 6,
|
|
1204
1326
|
padding: HOME_TILE_PADDING
|
|
1205
1327
|
},
|
|
@@ -1239,69 +1361,112 @@ var styles4 = import_react_native5.StyleSheet.create({
|
|
|
1239
1361
|
|
|
1240
1362
|
// src/screens/ProfilesRoute.tsx
|
|
1241
1363
|
var import_auto_paper6 = require("@rific/auto-paper");
|
|
1242
|
-
var
|
|
1364
|
+
var import_chrome6 = require("@tastic/hud/chrome");
|
|
1365
|
+
var import_profile8 = require("@tastic/profile");
|
|
1243
1366
|
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
1367
|
+
var ROSTER_MAX_WIDTH = 640;
|
|
1368
|
+
function useRosterAlign(open, contentWidth, contentHeight) {
|
|
1369
|
+
const { usePickerAlign } = usePack();
|
|
1370
|
+
return usePickerAlign(open, contentWidth, contentHeight, { maxContentWidth: ROSTER_MAX_WIDTH });
|
|
1371
|
+
}
|
|
1244
1372
|
function ProfilesRoute() {
|
|
1245
1373
|
const { profiles, createProfile, updateProfile, deleteProfile } = useProfiles();
|
|
1246
|
-
|
|
1374
|
+
const { Backdrop, foreground, newProfileColor, usePickerAlign } = usePack();
|
|
1375
|
+
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 }) });
|
|
1247
1376
|
}
|
|
1248
1377
|
|
|
1249
1378
|
// src/screens/StatsScreen.tsx
|
|
1250
1379
|
var import_auto_paper7 = require("@rific/auto-paper");
|
|
1251
|
-
var
|
|
1252
|
-
var
|
|
1253
|
-
var import_profile8 = require("@tastic/profile");
|
|
1380
|
+
var import_chrome7 = require("@tastic/hud/chrome");
|
|
1381
|
+
var import_profile9 = require("@tastic/profile");
|
|
1254
1382
|
var import_react17 = require("react");
|
|
1255
|
-
var
|
|
1383
|
+
var import_react_native7 = require("react-native");
|
|
1256
1384
|
var import_react_native_paper2 = require("react-native-paper");
|
|
1257
1385
|
var import_react_native_safe_area_context4 = require("react-native-safe-area-context");
|
|
1258
1386
|
var import_react_redux10 = require("react-redux");
|
|
1259
1387
|
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
1388
|
+
var STATS = "stats";
|
|
1389
|
+
var ACHIEVEMENTS = "achievements";
|
|
1260
1390
|
var TABS = [
|
|
1261
|
-
{ value:
|
|
1262
|
-
{ value:
|
|
1391
|
+
{ value: STATS, label: "Stats", icon: "chart-box-outline" },
|
|
1392
|
+
{ value: ACHIEVEMENTS, label: "Achievements", icon: "trophy-outline" }
|
|
1263
1393
|
];
|
|
1394
|
+
var LABEL_WIDE_TAB = { flexBasis: "auto", flexGrow: 1, flexShrink: 1 };
|
|
1395
|
+
var NO_PACK_TABS = [];
|
|
1264
1396
|
var EVERYONE = "__everyone__";
|
|
1265
1397
|
var ALL_GAMES = "__all__";
|
|
1266
1398
|
var PLAYER_PICKER_ID = "stats-player";
|
|
1267
1399
|
var GAME_PICKER_ID = "stats-game";
|
|
1400
|
+
var STATS_MAX_WIDTH = 640;
|
|
1268
1401
|
function StatsScreen() {
|
|
1402
|
+
const pickerHost = (0, import_chrome7.usePopoverHost)();
|
|
1403
|
+
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 }) }) });
|
|
1404
|
+
}
|
|
1405
|
+
function StatsPressAway({ host, children }) {
|
|
1406
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react_native7.View, { testID: "stats-press-away", style: styles5.screen, onStartShouldSetResponder: () => host.openId !== null, onResponderRelease: host.close, children });
|
|
1407
|
+
}
|
|
1408
|
+
var useNoPackReset = () => null;
|
|
1409
|
+
var noPickerAlign2 = () => void 0;
|
|
1410
|
+
function StatsContent({ pickerHost }) {
|
|
1269
1411
|
const pack = usePack();
|
|
1270
1412
|
const { dark, colors } = (0, import_auto_paper7.useAutoPaperTheme)();
|
|
1271
|
-
const
|
|
1272
|
-
const
|
|
1273
|
-
const { profiles } = useProfiles();
|
|
1413
|
+
const insets = (0, import_react_native_safe_area_context4.useSafeAreaInsets)();
|
|
1414
|
+
const { profiles, lastSelected } = useProfiles();
|
|
1274
1415
|
const dispatch = (0, import_react_redux10.useDispatch)();
|
|
1275
|
-
const
|
|
1276
|
-
const [tab, setTab] = (0, import_react17.useState)(
|
|
1416
|
+
const fg = pack.foreground ?? colors.onBackground;
|
|
1417
|
+
const [tab, setTab] = (0, import_react17.useState)(STATS);
|
|
1277
1418
|
const [gameId, setGameId] = (0, import_react17.useState)(ALL_GAMES);
|
|
1278
|
-
const [selectedProfileId, setSelectedProfileId] = (0, import_react17.useState)(null);
|
|
1279
|
-
const profileId = selectedProfileId && profiles.some((p) => p.id === selectedProfileId) ? selectedProfileId : null;
|
|
1419
|
+
const [selectedProfileId, setSelectedProfileId] = (0, import_react17.useState)(() => pack.guestStats ? lastSelected[1] ?? GUEST_PLAYER_ID : null);
|
|
1420
|
+
const profileId = selectedProfileId && profiles.length > 0 && (pack.guestStats && selectedProfileId === GUEST_PLAYER_ID || profiles.some((p) => p.id === selectedProfileId)) ? selectedProfileId : null;
|
|
1280
1421
|
const games = gameId === ALL_GAMES ? pack.games : pack.games.filter((g) => g.id === gameId);
|
|
1281
|
-
const
|
|
1422
|
+
const packTabs = pack.statsTabs ?? NO_PACK_TABS;
|
|
1423
|
+
const packTab = packTabs.find((t) => t.value === tab);
|
|
1424
|
+
const showGamePicker = !(tab === ACHIEVEMENTS && pack.AchievementList);
|
|
1425
|
+
const playerOptions = (0, import_react17.useMemo)(() => [{ value: EVERYONE, label: "Everyone", icon: "account-group" }, ...pack.guestStats ? [{ value: GUEST_PLAYER_ID, label: "Guest", icon: "account-outline" }] : [], ...profiles.map((p) => ({ value: p.id, label: p.name, icon: "account", color: pack.previewColor ? pack.previewColor(p.color, dark) : p.color }))], [profiles, pack, dark]);
|
|
1282
1426
|
const gameOptions = (0, import_react17.useMemo)(() => [{ value: ALL_GAMES, label: "All Games", icon: "view-grid-outline" }, ...pack.games.map((g) => ({ value: g.id, label: g.title }))], [pack.games]);
|
|
1283
|
-
const
|
|
1284
|
-
const
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1427
|
+
const tabButtons = (0, import_react17.useMemo)(() => packTabs.length > 0 ? [{ value: STATS, label: "Stats" }, ...packTabs.map(({ value, label }) => ({ value, label })), { value: ACHIEVEMENTS, label: "Achievements" }].map((button) => ({ ...button, style: LABEL_WIDE_TAB })) : TABS, [packTabs]);
|
|
1428
|
+
const title = tab === STATS ? "Stats" : tab === ACHIEVEMENTS ? "Achievements" : packTab?.label ?? "";
|
|
1429
|
+
const usePackReset = pack.resetStats?.useReset ?? useNoPackReset;
|
|
1430
|
+
const packReset = usePackReset();
|
|
1431
|
+
const reset = resetFor(pack, packReset, profileId, profiles, games, () => games.forEach((g) => g.resetStats && dispatch(g.resetStats())));
|
|
1432
|
+
const usePickerAlign = pack.usePickerAlign ?? noPickerAlign2;
|
|
1433
|
+
const playerSize = (0, import_profile9.getOptionPickerContentSize)(playerOptions.length);
|
|
1434
|
+
const gameSize = (0, import_profile9.getOptionPickerContentSize)(gameOptions.length);
|
|
1435
|
+
const playerAlign = usePickerAlign(pickerHost.openId === PLAYER_PICKER_ID, playerSize.width, playerSize.height);
|
|
1436
|
+
const gameAlign = usePickerAlign(pickerHost.openId === GAME_PICKER_ID, gameSize.width, gameSize.height);
|
|
1437
|
+
const surface = pack.Backdrop ? { backgroundColor: colors.surface } : void 0;
|
|
1438
|
+
const triggerStyle = pack.Backdrop ? [styles5.pill, surface] : void 0;
|
|
1439
|
+
const PackTabContent = packTab?.Content;
|
|
1440
|
+
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: [
|
|
1441
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_chrome7.PressAwayOverlay, { active: pickerHost.openId !== null, onPress: pickerHost.close, style: styles5.pressAway }),
|
|
1442
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react_native_paper2.SegmentedButtons, { value: tab, onValueChange: setTab, buttons: tabButtons, style: [styles5.tabs, surface] }),
|
|
1443
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_react_native7.View, { style: [styles5.filters, pickerHost.openId !== null && styles5.filtersOpen], onStartShouldSetResponder: () => pickerHost.openId !== null, children: [
|
|
1444
|
+
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 }),
|
|
1445
|
+
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 })
|
|
1291
1446
|
] }),
|
|
1292
|
-
tab ===
|
|
1293
|
-
|
|
1294
|
-
|
|
1447
|
+
tab === STATS && pack.StatsSections && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(pack.StatsSections, { profileId, gameId: gameId === ALL_GAMES ? null : gameId }),
|
|
1448
|
+
PackTabContent && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(PackTabContent, { profileId, gameId: gameId === ALL_GAMES ? null : gameId }),
|
|
1449
|
+
tab === ACHIEVEMENTS && pack.AchievementList ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(pack.AchievementList, { profileId }) : (tab === STATS || tab === ACHIEVEMENTS) && games.map((game) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(GameStats, { game, tab, profileId, showTitle: games.length > 1 && pack.statsGameTitles !== false, titleColor: fg }, game.id))
|
|
1450
|
+
] });
|
|
1451
|
+
}
|
|
1452
|
+
function resetFor(pack, packReset, profileId, profiles, games, resetGames) {
|
|
1453
|
+
if (pack.resetStats && packReset) {
|
|
1454
|
+
const name = profileId === GUEST_PLAYER_ID ? "Guest" : profileId ? profiles.find((p) => p.id === profileId)?.name ?? null : null;
|
|
1455
|
+
return { onReset: () => packReset(profileId), ...pack.resetStats.labels(name) };
|
|
1456
|
+
}
|
|
1457
|
+
const scope = games.length === 1 ? games[0].title : "every game";
|
|
1458
|
+
return { onReset: resetGames, label: games.length === 1 ? `Reset ${scope} Stats` : "Reset All Stats", title: "Reset Stats?", body: `Erases every player's stats and achievements in ${scope}. This cannot be undone.` };
|
|
1295
1459
|
}
|
|
1296
|
-
function GameStats({ game, tab, profileId, showTitle }) {
|
|
1297
|
-
const { colors } = (0, import_auto_paper7.useAutoPaperTheme)();
|
|
1460
|
+
function GameStats({ game, tab, profileId, showTitle, titleColor }) {
|
|
1298
1461
|
const { StatsSections, AchievementList } = game;
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1462
|
+
const Sections = tab === STATS ? StatsSections : AchievementList;
|
|
1463
|
+
if (!Sections) return null;
|
|
1464
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_react_native7.View, { style: styles5.game, children: [
|
|
1465
|
+
showTitle && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react_native_paper2.Text, { variant: "titleLarge", style: [styles5.gameTitle, { color: titleColor }], children: game.title }),
|
|
1466
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Sections, { profileId })
|
|
1302
1467
|
] });
|
|
1303
1468
|
}
|
|
1304
|
-
var styles5 =
|
|
1469
|
+
var styles5 = import_react_native7.StyleSheet.create({
|
|
1305
1470
|
filters: {
|
|
1306
1471
|
flexDirection: "row",
|
|
1307
1472
|
flexWrap: "wrap",
|
|
@@ -1318,25 +1483,28 @@ var styles5 = import_react_native6.StyleSheet.create({
|
|
|
1318
1483
|
fontWeight: "bold",
|
|
1319
1484
|
marginTop: 8
|
|
1320
1485
|
},
|
|
1486
|
+
// A picker's button on the theme's surface (over a backdrop), the same pill as Home's.
|
|
1487
|
+
pill: {
|
|
1488
|
+
borderRadius: 999
|
|
1489
|
+
},
|
|
1321
1490
|
pressAway: {
|
|
1322
1491
|
zIndex: 50
|
|
1323
1492
|
},
|
|
1324
|
-
|
|
1325
|
-
rotatable: {
|
|
1493
|
+
screen: {
|
|
1326
1494
|
flex: 1
|
|
1327
1495
|
},
|
|
1328
|
-
// SegmentedButtons' own rounding.
|
|
1496
|
+
// SegmentedButtons' own rounding, so a surface behind it is the same pill.
|
|
1329
1497
|
tabs: {
|
|
1330
1498
|
borderRadius: 20
|
|
1331
1499
|
}
|
|
1332
1500
|
});
|
|
1333
1501
|
|
|
1334
1502
|
// src/components/imageGameIcon.tsx
|
|
1335
|
-
var
|
|
1503
|
+
var import_react_native8 = require("react-native");
|
|
1336
1504
|
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
1337
1505
|
function imageGameIcon(images) {
|
|
1338
1506
|
return function ImageGameIcon({ size, dark }) {
|
|
1339
|
-
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
1507
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react_native8.Image, { source: dark ? images.dark : images.light, style: { height: size, width: size }, accessibilityIgnoresInvertColors: true });
|
|
1340
1508
|
};
|
|
1341
1509
|
}
|
|
1342
1510
|
|
|
@@ -1356,12 +1524,12 @@ var import_redux_persist = require("redux-persist");
|
|
|
1356
1524
|
|
|
1357
1525
|
// src/redux/shellState.ts
|
|
1358
1526
|
var import_auto_paper8 = require("@rific/auto-paper");
|
|
1359
|
-
var
|
|
1527
|
+
var import_core13 = require("@rific/core");
|
|
1360
1528
|
var import_feedback_press4 = require("@rific/feedback-press");
|
|
1361
|
-
var
|
|
1529
|
+
var import_profile10 = require("@tastic/profile");
|
|
1362
1530
|
var initialSoundSettings = { ...import_feedback_press4.defaultSoundSettings, enabled: !__DEV__ };
|
|
1363
1531
|
var appSoundReducer = (state = initialSoundSettings, action) => (0, import_feedback_press4.soundReducer)(state, action);
|
|
1364
|
-
function createShellReducers({ seatColors, appearance = "system" }) {
|
|
1532
|
+
function createShellReducers({ seatColors, appearance = "system", seatTheme }) {
|
|
1365
1533
|
return {
|
|
1366
1534
|
// Explicit primary/secondary triad (rather than a single seed expanded via harmony) so the pack's
|
|
1367
1535
|
// identity is pinned exactly instead of drifting with whatever hue math a harmony offset would
|
|
@@ -1370,17 +1538,19 @@ function createShellReducers({ seatColors, appearance = "system" }) {
|
|
|
1370
1538
|
// derived, not picked, via getThirdColor: the hue maximally distant from both (see
|
|
1371
1539
|
// @rific/auto-paper's README "Explicit triad" section). The appearance is the pack's ('system',
|
|
1372
1540
|
// createThemeReducer's own default, when it sets none).
|
|
1373
|
-
|
|
1541
|
+
// A pack with its own seatTheme starts from what seat 1's default color makes of it instead (dark
|
|
1542
|
+
// only when the pack's appearance is; hooks/useSeatColors.ts re-applies it with the live mode).
|
|
1543
|
+
theme: (0, import_auto_paper8.createThemeReducer)(seatTheme ? { appearance, ...seatTheme(seatColors, appearance === "dark") } : { appearance, color: { primary: seatColors[1], secondary: seatColors[2], tertiary: (0, import_auto_paper8.getThirdColor)(seatColors[1], seatColors[2]) } }),
|
|
1374
1544
|
haptic: import_feedback_press4.hapticReducer,
|
|
1375
1545
|
sound: appSoundReducer,
|
|
1376
1546
|
// @rific/core's Keep Awake setting (see Providers.tsx's KeepAwakeBridge), under the namespace its
|
|
1377
1547
|
// REHYDRATE handling expects.
|
|
1378
|
-
keepAwake:
|
|
1548
|
+
keepAwake: import_core13.keepAwakeReducer,
|
|
1379
1549
|
// The shared App Group roster (see @tastic/profile's resolveInitialProfiles/
|
|
1380
1550
|
// useSharedProfilesSync, wired in hooks/useProfiles.tsx) is layered on top of this as a separate
|
|
1381
1551
|
// sync target - this slice persisting normally via redux-persist is what gives it local-fallback
|
|
1382
1552
|
// behavior where the shared store isn't available, with no separate AsyncStorage path.
|
|
1383
|
-
profiles:
|
|
1553
|
+
profiles: import_profile10.profilesReducer,
|
|
1384
1554
|
profileSelection: profileSelectionSlice_default,
|
|
1385
1555
|
// The loadout's "remember this color for next time" memory (guest, CPU, and each profile's pick
|
|
1386
1556
|
// in this pack) - separate from `theme` above, which always reflects whatever's live right now.
|
|
@@ -1398,7 +1568,7 @@ var errorMiddleware = () => (next) => (action) => {
|
|
|
1398
1568
|
if (!hasError(action)) return next(action);
|
|
1399
1569
|
return action;
|
|
1400
1570
|
};
|
|
1401
|
-
function createPackStore(pack, { keyPrefix, migrate }) {
|
|
1571
|
+
function createPackStore(pack, { keyPrefix, migrate, blacklist = [], serializableIgnoredPaths = [], middleware = [] }) {
|
|
1402
1572
|
const gameReducers = Object.assign({}, ...pack.games.map((game) => game.reducers));
|
|
1403
1573
|
const resumeReducers = pack.games.some((game) => game.resumable) ? { lastActiveGame: lastActiveGameSlice_default } : {};
|
|
1404
1574
|
const rootReducer = (0, import_toolkit.combineReducers)({ ...createShellReducers(pack), ...resumeReducers, ...pack.reducers, ...gameReducers });
|
|
@@ -1416,7 +1586,7 @@ function createPackStore(pack, { keyPrefix, migrate }) {
|
|
|
1416
1586
|
// failing to ever resolve at all isn't a failure mode worth a 5s failsafe for.
|
|
1417
1587
|
timeout: 0,
|
|
1418
1588
|
// liveplay is per-round state that must never survive a relaunch (see liveplaySlice.ts).
|
|
1419
|
-
blacklist: ["liveplay"],
|
|
1589
|
+
blacklist: ["liveplay", ...blacklist],
|
|
1420
1590
|
migrate
|
|
1421
1591
|
},
|
|
1422
1592
|
rootReducer
|
|
@@ -1426,10 +1596,11 @@ function createPackStore(pack, { keyPrefix, migrate }) {
|
|
|
1426
1596
|
const defaultMiddleware = getDefaultMiddleware({
|
|
1427
1597
|
immutableCheck: false,
|
|
1428
1598
|
serializableCheck: {
|
|
1429
|
-
ignoredActions: [import_redux_persist.FLUSH, import_redux_persist.REHYDRATE, import_redux_persist.PAUSE, import_redux_persist.PERSIST, import_redux_persist.PURGE, import_redux_persist.REGISTER]
|
|
1599
|
+
ignoredActions: [import_redux_persist.FLUSH, import_redux_persist.REHYDRATE, import_redux_persist.PAUSE, import_redux_persist.PERSIST, import_redux_persist.PURGE, import_redux_persist.REGISTER],
|
|
1600
|
+
ignoredPaths: [...serializableIgnoredPaths]
|
|
1430
1601
|
}
|
|
1431
1602
|
});
|
|
1432
|
-
return defaultMiddleware.concat(errorMiddleware);
|
|
1603
|
+
return defaultMiddleware.concat(errorMiddleware, ...middleware);
|
|
1433
1604
|
},
|
|
1434
1605
|
reducer: persistedReducer
|
|
1435
1606
|
});
|
|
@@ -1463,11 +1634,11 @@ function createGameGuideSlice(mountKey) {
|
|
|
1463
1634
|
|
|
1464
1635
|
// src/redux/onProfileRemoved.ts
|
|
1465
1636
|
var import_achievements = require("@tastic/achievements");
|
|
1466
|
-
var
|
|
1637
|
+
var import_profile11 = require("@tastic/profile");
|
|
1467
1638
|
function onProfileRemoved(reducer6, forget) {
|
|
1468
1639
|
return (state, action) => {
|
|
1469
1640
|
const next = reducer6(state, action);
|
|
1470
|
-
return
|
|
1641
|
+
return import_profile11.profilesActions.remove.match(action) ? forget(next, action.payload) : next;
|
|
1471
1642
|
};
|
|
1472
1643
|
}
|
|
1473
1644
|
function forgetProfileAchievements(dropStats) {
|
|
@@ -1590,6 +1761,7 @@ function createPlayerSettings({ id, defaults, distinctControls }) {
|
|
|
1590
1761
|
0 && (module.exports = {
|
|
1591
1762
|
DEFAULT_APP_SETTINGS,
|
|
1592
1763
|
DEFAULT_OPPONENT,
|
|
1764
|
+
GUEST_PLAYER_ID,
|
|
1593
1765
|
HomeScreen,
|
|
1594
1766
|
LoadoutRoute,
|
|
1595
1767
|
PREVIEW_ASPECT,
|