@tastic/shell 0.2.0 → 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/dist/index.js +26 -23
- package/dist/index.mjs +7 -4
- package/package.json +1 -1
- package/src/screens/GameRoute.tsx +11 -4
package/dist/index.js
CHANGED
|
@@ -557,6 +557,7 @@ var styles = import_react_native2.StyleSheet.create({
|
|
|
557
557
|
// src/screens/GameRoute.tsx
|
|
558
558
|
var import_expo_router5 = require("expo-router");
|
|
559
559
|
var import_react14 = require("react");
|
|
560
|
+
var import_react_native5 = require("react-native");
|
|
560
561
|
|
|
561
562
|
// src/routes.ts
|
|
562
563
|
var playHref = (game) => ({ pathname: "/play/[game]", params: { game } });
|
|
@@ -1006,7 +1007,9 @@ function useResumePoint(gameId) {
|
|
|
1006
1007
|
(0, import_react14.useEffect)(() => {
|
|
1007
1008
|
if (!gameId) return;
|
|
1008
1009
|
setLastActiveGame(gameId);
|
|
1009
|
-
return
|
|
1010
|
+
return () => {
|
|
1011
|
+
if (import_react_native5.AppState.currentState === "active") clearLastActiveGame();
|
|
1012
|
+
};
|
|
1010
1013
|
}, [gameId, setLastActiveGame, clearLastActiveGame]);
|
|
1011
1014
|
}
|
|
1012
1015
|
|
|
@@ -1018,7 +1021,7 @@ var import_chrome5 = require("@tastic/hud/chrome");
|
|
|
1018
1021
|
var import_profile7 = require("@tastic/profile");
|
|
1019
1022
|
var import_expo_router6 = require("expo-router");
|
|
1020
1023
|
var import_react16 = require("react");
|
|
1021
|
-
var
|
|
1024
|
+
var import_react_native6 = require("react-native");
|
|
1022
1025
|
var import_react_native_paper = require("react-native-paper");
|
|
1023
1026
|
|
|
1024
1027
|
// src/hooks/useFrozenWhileHidden.ts
|
|
@@ -1124,9 +1127,9 @@ function HomeMenu() {
|
|
|
1124
1127
|
const [settingsOpen, setSettingsOpen] = (0, import_react16.useState)(false);
|
|
1125
1128
|
const [rulesGame, setRulesGame] = (0, import_react16.useState)(null);
|
|
1126
1129
|
const isFocused = (0, import_expo_router6.useIsFocused)();
|
|
1127
|
-
const [appState, setAppState] = (0, import_react16.useState)(
|
|
1130
|
+
const [appState, setAppState] = (0, import_react16.useState)(import_react_native6.AppState.currentState);
|
|
1128
1131
|
(0, import_react16.useEffect)(() => {
|
|
1129
|
-
const subscription =
|
|
1132
|
+
const subscription = import_react_native6.AppState.addEventListener("change", setAppState);
|
|
1130
1133
|
return () => subscription.remove();
|
|
1131
1134
|
}, []);
|
|
1132
1135
|
const heroActive = isFocused && appState === "active";
|
|
@@ -1161,20 +1164,20 @@ function HomeMenu() {
|
|
|
1161
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 });
|
|
1162
1165
|
const pressAway = /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_chrome5.PressAwayOverlay, { active: pickerHost.openId !== null, onPress: pickerHost.close, style: styles4.pressAway });
|
|
1163
1166
|
const RulesSheet = rulesGame?.Rules;
|
|
1164
|
-
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
1167
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_react_native6.View, { style: [styles4.container, { backgroundColor: bg }], children: [
|
|
1165
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: [
|
|
1166
1169
|
isWide ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
|
|
1167
1170
|
pressAway,
|
|
1168
|
-
/* @__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)(
|
|
1169
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
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: [
|
|
1170
1173
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(pack.HeroTitle, { words: pack.wordmark, color: fg, p1Color, p2Color, active: heroActive, fit: layout.heroFit }),
|
|
1171
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1174
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native6.View, { style: styles4.widePicker, children: picker })
|
|
1172
1175
|
] })
|
|
1173
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: [
|
|
1174
1177
|
pressAway,
|
|
1175
1178
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(pack.HeroTitle, { words: pack.wordmark, color: fg, p1Color, p2Color, active: heroActive }),
|
|
1176
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1177
|
-
/* @__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)) })
|
|
1178
1181
|
] }),
|
|
1179
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" }),
|
|
1180
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" }),
|
|
@@ -1197,10 +1200,10 @@ function GameRow({ game, dark, p1Color, p2Color, previewRevealed, onPress, onRul
|
|
|
1197
1200
|
return (
|
|
1198
1201
|
// The rules button sits beside the row's own button, laid over its end, not inside it: a button
|
|
1199
1202
|
// inside a button is invalid on the web.
|
|
1200
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
1203
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_react_native6.View, { children: [
|
|
1201
1204
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_feedback_press3.Pressable, { onPress, style: [styles4.row, { backgroundColor: well.bg }], accessibilityRole: "button", accessibilityLabel: game.title, children: [
|
|
1202
|
-
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)(
|
|
1203
|
-
/* @__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: [
|
|
1204
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 }),
|
|
1205
1208
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native_paper.Text, { variant: "bodyMedium", style: { color: well.fgMuted }, numberOfLines: 2, children: game.blurb })
|
|
1206
1209
|
] })
|
|
@@ -1211,7 +1214,7 @@ function GameRow({ game, dark, p1Color, p2Color, previewRevealed, onPress, onRul
|
|
|
1211
1214
|
}
|
|
1212
1215
|
function GameTile({ game, width, previewWidth, dark, p1Color, p2Color, previewRevealed, onPress, onRules }) {
|
|
1213
1216
|
const well = (0, import_chrome5.useWellColors)();
|
|
1214
|
-
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
1217
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_react_native6.View, { style: { width }, children: [
|
|
1215
1218
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_feedback_press3.Pressable, { onPress, style: [styles4.tile, { backgroundColor: well.bg }], accessibilityRole: "button", accessibilityLabel: game.title, children: [
|
|
1216
1219
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(PreviewBox, { game, width: previewWidth, revealed: previewRevealed, dark, p1Color, p2Color }),
|
|
1217
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 }),
|
|
@@ -1224,13 +1227,13 @@ function PreviewBox({ game, width, revealed, dark, p1Color, p2Color }) {
|
|
|
1224
1227
|
const height = Math.round(width / PREVIEW_ASPECT);
|
|
1225
1228
|
const { Preview, icon: GameIcon } = game;
|
|
1226
1229
|
const iconSize = Math.min(height, ROW_ICON_SIZE);
|
|
1227
|
-
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 }) }) });
|
|
1228
1231
|
}
|
|
1229
1232
|
var ROW_ICON_SIZE = 56;
|
|
1230
1233
|
var ICON_LIGHT_BG = "#FAFAFA";
|
|
1231
1234
|
var ICON_DARK_BG = "#050505";
|
|
1232
1235
|
var RULES_BUTTON_SPACE = 44;
|
|
1233
|
-
var styles4 =
|
|
1236
|
+
var styles4 = import_react_native6.StyleSheet.create({
|
|
1234
1237
|
container: {
|
|
1235
1238
|
flex: 1
|
|
1236
1239
|
},
|
|
@@ -1377,7 +1380,7 @@ var import_auto_paper7 = require("@rific/auto-paper");
|
|
|
1377
1380
|
var import_chrome7 = require("@tastic/hud/chrome");
|
|
1378
1381
|
var import_profile9 = require("@tastic/profile");
|
|
1379
1382
|
var import_react17 = require("react");
|
|
1380
|
-
var
|
|
1383
|
+
var import_react_native7 = require("react-native");
|
|
1381
1384
|
var import_react_native_paper2 = require("react-native-paper");
|
|
1382
1385
|
var import_react_native_safe_area_context4 = require("react-native-safe-area-context");
|
|
1383
1386
|
var import_react_redux10 = require("react-redux");
|
|
@@ -1400,7 +1403,7 @@ function StatsScreen() {
|
|
|
1400
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 }) }) });
|
|
1401
1404
|
}
|
|
1402
1405
|
function StatsPressAway({ host, children }) {
|
|
1403
|
-
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
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 });
|
|
1404
1407
|
}
|
|
1405
1408
|
var useNoPackReset = () => null;
|
|
1406
1409
|
var noPickerAlign2 = () => void 0;
|
|
@@ -1437,7 +1440,7 @@ function StatsContent({ pickerHost }) {
|
|
|
1437
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: [
|
|
1438
1441
|
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_chrome7.PressAwayOverlay, { active: pickerHost.openId !== null, onPress: pickerHost.close, style: styles5.pressAway }),
|
|
1439
1442
|
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react_native_paper2.SegmentedButtons, { value: tab, onValueChange: setTab, buttons: tabButtons, style: [styles5.tabs, surface] }),
|
|
1440
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
1443
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_react_native7.View, { style: [styles5.filters, pickerHost.openId !== null && styles5.filtersOpen], onStartShouldSetResponder: () => pickerHost.openId !== null, children: [
|
|
1441
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 }),
|
|
1442
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 })
|
|
1443
1446
|
] }),
|
|
@@ -1458,12 +1461,12 @@ function GameStats({ game, tab, profileId, showTitle, titleColor }) {
|
|
|
1458
1461
|
const { StatsSections, AchievementList } = game;
|
|
1459
1462
|
const Sections = tab === STATS ? StatsSections : AchievementList;
|
|
1460
1463
|
if (!Sections) return null;
|
|
1461
|
-
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
1464
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_react_native7.View, { style: styles5.game, children: [
|
|
1462
1465
|
showTitle && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react_native_paper2.Text, { variant: "titleLarge", style: [styles5.gameTitle, { color: titleColor }], children: game.title }),
|
|
1463
1466
|
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Sections, { profileId })
|
|
1464
1467
|
] });
|
|
1465
1468
|
}
|
|
1466
|
-
var styles5 =
|
|
1469
|
+
var styles5 = import_react_native7.StyleSheet.create({
|
|
1467
1470
|
filters: {
|
|
1468
1471
|
flexDirection: "row",
|
|
1469
1472
|
flexWrap: "wrap",
|
|
@@ -1497,11 +1500,11 @@ var styles5 = import_react_native6.StyleSheet.create({
|
|
|
1497
1500
|
});
|
|
1498
1501
|
|
|
1499
1502
|
// src/components/imageGameIcon.tsx
|
|
1500
|
-
var
|
|
1503
|
+
var import_react_native8 = require("react-native");
|
|
1501
1504
|
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
1502
1505
|
function imageGameIcon(images) {
|
|
1503
1506
|
return function ImageGameIcon({ size, dark }) {
|
|
1504
|
-
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 });
|
|
1505
1508
|
};
|
|
1506
1509
|
}
|
|
1507
1510
|
|
package/dist/index.mjs
CHANGED
|
@@ -483,6 +483,7 @@ var styles = StyleSheet.create({
|
|
|
483
483
|
// src/screens/GameRoute.tsx
|
|
484
484
|
import { Redirect, useLocalSearchParams } from "expo-router";
|
|
485
485
|
import { useEffect as useEffect5 } from "react";
|
|
486
|
+
import { AppState } from "react-native";
|
|
486
487
|
|
|
487
488
|
// src/routes.ts
|
|
488
489
|
var playHref = (game) => ({ pathname: "/play/[game]", params: { game } });
|
|
@@ -932,7 +933,9 @@ function useResumePoint(gameId) {
|
|
|
932
933
|
useEffect5(() => {
|
|
933
934
|
if (!gameId) return;
|
|
934
935
|
setLastActiveGame(gameId);
|
|
935
|
-
return
|
|
936
|
+
return () => {
|
|
937
|
+
if (AppState.currentState === "active") clearLastActiveGame();
|
|
938
|
+
};
|
|
936
939
|
}, [gameId, setLastActiveGame, clearLastActiveGame]);
|
|
937
940
|
}
|
|
938
941
|
|
|
@@ -944,7 +947,7 @@ import { PressAwayOverlay as PressAwayOverlay2, usePopoverHost as usePopoverHost
|
|
|
944
947
|
import { getProfilePickerContentSize, ProfilePicker } from "@tastic/profile";
|
|
945
948
|
import { Redirect as Redirect2, router as router3, useIsFocused } from "expo-router";
|
|
946
949
|
import { useCallback as useCallback10, useEffect as useEffect6, useMemo as useMemo6, useState as useState6 } from "react";
|
|
947
|
-
import { AppState, StyleSheet as StyleSheet4, View as View4 } from "react-native";
|
|
950
|
+
import { AppState as AppState2, StyleSheet as StyleSheet4, View as View4 } from "react-native";
|
|
948
951
|
import { Icon, Portal, Text } from "react-native-paper";
|
|
949
952
|
|
|
950
953
|
// src/hooks/useFrozenWhileHidden.ts
|
|
@@ -1050,9 +1053,9 @@ function HomeMenu() {
|
|
|
1050
1053
|
const [settingsOpen, setSettingsOpen] = useState6(false);
|
|
1051
1054
|
const [rulesGame, setRulesGame] = useState6(null);
|
|
1052
1055
|
const isFocused = useIsFocused();
|
|
1053
|
-
const [appState, setAppState] = useState6(
|
|
1056
|
+
const [appState, setAppState] = useState6(AppState2.currentState);
|
|
1054
1057
|
useEffect6(() => {
|
|
1055
|
-
const subscription =
|
|
1058
|
+
const subscription = AppState2.addEventListener("change", setAppState);
|
|
1056
1059
|
return () => subscription.remove();
|
|
1057
1060
|
}, []);
|
|
1058
1061
|
const heroActive = isFocused && appState === "active";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tastic/shell",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "The app around a pack of React Native games, two-seat or for one player: Home, the loadout, the stats screen, Profiles and Settings, the pack's Redux store and its root providers, driven by one PackDefinition",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react-native",
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Redirect, useLocalSearchParams } from 'expo-router'
|
|
2
2
|
import { useEffect } from 'react'
|
|
3
|
+
import { AppState } from 'react-native'
|
|
3
4
|
|
|
4
5
|
import { useLastActiveGame } from '../hooks/useLastActiveGame'
|
|
5
6
|
import { usePackGame } from '../PackContext'
|
|
@@ -36,14 +37,20 @@ export function PlayRoute() {
|
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
// A resumable game's play screen (GameDefinition.resumable) is where a cold launch comes back to:
|
|
39
|
-
// remembered as it mounts, and forgotten when
|
|
40
|
-
//
|
|
41
|
-
// so it stays remembered.
|
|
40
|
+
// remembered as it mounts, and forgotten when the player backs out of it (its own back, hardware back
|
|
41
|
+
// or a browser back), which unmounts it while the app is in use. Backgrounding the app leaves the
|
|
42
|
+
// screen mounted, so it stays remembered. An unmount with the app NOT active keeps it too: when iOS
|
|
43
|
+
// terminates an app it hasn't suspended yet (swiped away from the app switcher soon after leaving
|
|
44
|
+
// it), React Native's renderer stops every surface (RCTSurfacePresenter's will-terminate handler),
|
|
45
|
+
// which unmounts the whole tree, and clearing then sent every such relaunch to Home. Runs once per
|
|
46
|
+
// play screen: the context's functions never change.
|
|
42
47
|
function useResumePoint(gameId: string | null) {
|
|
43
48
|
const { setLastActiveGame, clearLastActiveGame } = useLastActiveGame()
|
|
44
49
|
useEffect(() => {
|
|
45
50
|
if (!gameId) return
|
|
46
51
|
setLastActiveGame(gameId)
|
|
47
|
-
return
|
|
52
|
+
return () => {
|
|
53
|
+
if (AppState.currentState === 'active') clearLastActiveGame()
|
|
54
|
+
}
|
|
48
55
|
}, [gameId, setLastActiveGame, clearLastActiveGame])
|
|
49
56
|
}
|