@tastic/hud 0.18.0 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -3
- package/dist/chrome/index.d.mts +3 -1
- package/dist/chrome/index.d.ts +3 -1
- package/dist/chrome/index.js +9 -1
- package/dist/chrome/index.mjs +1 -1
- package/dist/{chunk-Z2WUUYTE.mjs → chunk-HGJKNLMD.mjs} +9 -1
- package/dist/index.js +9 -1
- package/dist/index.mjs +1 -1
- package/package.json +7 -7
- package/src/BaseSettingsDialog.tsx +29 -4
package/README.md
CHANGED
|
@@ -207,9 +207,11 @@ the fleet with real Redux Toolkit state - reads `lockOrientation`/`deferBottomEd
|
|
|
207
207
|
`useSelector` and writes them back via `dispatch(gameActions.setLockOrientation(...))` directly
|
|
208
208
|
inside the adapter, with nothing threaded through props at all. `BaseSettingsDialog` doesn't care
|
|
209
209
|
which of these an app uses: sound, haptics, appearance, and update-checking are identical across
|
|
210
|
-
every app and live entirely inside this package now, so `lockOrientation`/`onLockOrientationChange
|
|
211
|
-
|
|
212
|
-
actually needs to source itself, however it does that.
|
|
210
|
+
every app and live entirely inside this package now, so `lockOrientation`/`onLockOrientationChange`,
|
|
211
|
+
`deferBottomEdgeGestures`/`onDeferBottomEdgeGestures` and `keepAwake`/`onKeepAwakeChange` are the only
|
|
212
|
+
settings an adapter actually needs to source itself, however it does that. Each pair is optional: omit
|
|
213
|
+
one and its row doesn't show. The Keep Awake row only toggles the value; the app keeps the screen awake
|
|
214
|
+
itself while it's on (for example with `expo-keep-awake` on its match screen).
|
|
213
215
|
|
|
214
216
|
Every adapter also passes `version={release.otaVersion}` (so the dialog's own update-check button
|
|
215
217
|
knows what it's currently running) and `onUpdateError`, wired to a real `useToast()` call. Wire this
|
|
@@ -234,6 +236,8 @@ export function SettingsDialog({ visible, onDismiss, rotation = 0, settings, set
|
|
|
234
236
|
onLockOrientationChange={(value) => setSettings({ lockOrientation: value })}
|
|
235
237
|
deferBottomEdgeGestures={settings.deferBottomEdgeGestures}
|
|
236
238
|
onDeferBottomEdgeGestures={(value) => setSettings({ deferBottomEdgeGestures: value })}
|
|
239
|
+
keepAwake={settings.keepAwake}
|
|
240
|
+
onKeepAwakeChange={(value) => setSettings({ keepAwake: value })}
|
|
237
241
|
onUpdateError={(message) => error('Update check failed', message)}
|
|
238
242
|
/>
|
|
239
243
|
)
|
package/dist/chrome/index.d.mts
CHANGED
|
@@ -47,6 +47,8 @@ interface BaseSettingsDialogProps {
|
|
|
47
47
|
onLockOrientationChange?: (value: boolean) => void;
|
|
48
48
|
deferBottomEdgeGestures?: boolean;
|
|
49
49
|
onDeferBottomEdgeGestures?: (value: boolean) => void;
|
|
50
|
+
keepAwake?: boolean;
|
|
51
|
+
onKeepAwakeChange?: (value: boolean) => void;
|
|
50
52
|
hideSound?: boolean;
|
|
51
53
|
hideHaptics?: boolean;
|
|
52
54
|
hideAppearance?: boolean;
|
|
@@ -55,7 +57,7 @@ interface BaseSettingsDialogProps {
|
|
|
55
57
|
onShowHowToPlay?: () => void;
|
|
56
58
|
children?: ReactNode;
|
|
57
59
|
}
|
|
58
|
-
declare function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, version, lockOrientation, onLockOrientationChange, deferBottomEdgeGestures, onDeferBottomEdgeGestures, hideSound, hideHaptics, hideAppearance, hideUpdateCheck, onUpdateError, onShowHowToPlay, children }: BaseSettingsDialogProps): react.JSX.Element | null;
|
|
60
|
+
declare function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, version, lockOrientation, onLockOrientationChange, deferBottomEdgeGestures, onDeferBottomEdgeGestures, keepAwake, onKeepAwakeChange, hideSound, hideHaptics, hideAppearance, hideUpdateCheck, onUpdateError, onShowHowToPlay, children }: BaseSettingsDialogProps): react.JSX.Element | null;
|
|
59
61
|
|
|
60
62
|
type MD3TextVariant = 'displayLarge' | 'displayMedium' | 'displaySmall' | 'headlineLarge' | 'headlineMedium' | 'headlineSmall' | 'titleLarge' | 'titleMedium' | 'titleSmall' | 'labelLarge' | 'labelMedium' | 'labelSmall' | 'bodyLarge' | 'bodyMedium' | 'bodySmall';
|
|
61
63
|
interface Props$4 {
|
package/dist/chrome/index.d.ts
CHANGED
|
@@ -47,6 +47,8 @@ interface BaseSettingsDialogProps {
|
|
|
47
47
|
onLockOrientationChange?: (value: boolean) => void;
|
|
48
48
|
deferBottomEdgeGestures?: boolean;
|
|
49
49
|
onDeferBottomEdgeGestures?: (value: boolean) => void;
|
|
50
|
+
keepAwake?: boolean;
|
|
51
|
+
onKeepAwakeChange?: (value: boolean) => void;
|
|
50
52
|
hideSound?: boolean;
|
|
51
53
|
hideHaptics?: boolean;
|
|
52
54
|
hideAppearance?: boolean;
|
|
@@ -55,7 +57,7 @@ interface BaseSettingsDialogProps {
|
|
|
55
57
|
onShowHowToPlay?: () => void;
|
|
56
58
|
children?: ReactNode;
|
|
57
59
|
}
|
|
58
|
-
declare function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, version, lockOrientation, onLockOrientationChange, deferBottomEdgeGestures, onDeferBottomEdgeGestures, hideSound, hideHaptics, hideAppearance, hideUpdateCheck, onUpdateError, onShowHowToPlay, children }: BaseSettingsDialogProps): react.JSX.Element | null;
|
|
60
|
+
declare function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, version, lockOrientation, onLockOrientationChange, deferBottomEdgeGestures, onDeferBottomEdgeGestures, keepAwake, onKeepAwakeChange, hideSound, hideHaptics, hideAppearance, hideUpdateCheck, onUpdateError, onShowHowToPlay, children }: BaseSettingsDialogProps): react.JSX.Element | null;
|
|
59
61
|
|
|
60
62
|
type MD3TextVariant = 'displayLarge' | 'displayMedium' | 'displaySmall' | 'headlineLarge' | 'headlineMedium' | 'headlineSmall' | 'titleLarge' | 'titleMedium' | 'titleSmall' | 'labelLarge' | 'labelMedium' | 'labelSmall' | 'bodyLarge' | 'bodyMedium' | 'bodySmall';
|
|
61
63
|
interface Props$4 {
|
package/dist/chrome/index.js
CHANGED
|
@@ -474,7 +474,7 @@ var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
|
474
474
|
function SettingIcon({ source, color, containerColor }) {
|
|
475
475
|
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native12.View, { style: [styles9.iconBadge, { backgroundColor: containerColor }], children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_paper8.Icon, { source, size: 18, color }) });
|
|
476
476
|
}
|
|
477
|
-
function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, version, lockOrientation, onLockOrientationChange, deferBottomEdgeGestures, onDeferBottomEdgeGestures, hideSound = false, hideHaptics = false, hideAppearance = false, hideUpdateCheck = false, onUpdateError, onShowHowToPlay, children }) {
|
|
477
|
+
function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, version, lockOrientation, onLockOrientationChange, deferBottomEdgeGestures, onDeferBottomEdgeGestures, keepAwake, onKeepAwakeChange, hideSound = false, hideHaptics = false, hideAppearance = false, hideUpdateCheck = false, onUpdateError, onShowHowToPlay, children }) {
|
|
478
478
|
const { colors } = (0, import_auto_paper8.useAutoPaperTheme)();
|
|
479
479
|
const ambientRotation = (0, import_core4.useRotation)();
|
|
480
480
|
const rotation = rotationOverride ?? ambientRotation;
|
|
@@ -504,6 +504,7 @@ function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, ve
|
|
|
504
504
|
if (visible && !opened) setOpened(true);
|
|
505
505
|
const showLockOrientation = isTouchPrimary && lockOrientation !== void 0 && onLockOrientationChange !== void 0;
|
|
506
506
|
const showEdgeGuard = import_react_native12.Platform.OS === "ios" && deferBottomEdgeGestures !== void 0 && onDeferBottomEdgeGestures !== void 0;
|
|
507
|
+
const showKeepAwake = isTouchPrimary && keepAwake !== void 0 && onKeepAwakeChange !== void 0;
|
|
507
508
|
const showHaptics = import_react_native12.Platform.OS !== "web" && !hideHaptics;
|
|
508
509
|
const showSound = !hideSound;
|
|
509
510
|
const showAppearance = !hideAppearance;
|
|
@@ -530,6 +531,13 @@ function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, ve
|
|
|
530
531
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_paper8.Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Require second swipe" })
|
|
531
532
|
] })
|
|
532
533
|
] }) }),
|
|
534
|
+
showKeepAwake && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_feedback_press2.TouchableRipple, { onPress: () => onKeepAwakeChange(!keepAwake), style: styles9.toggleButton, accessibilityLabel: `Keep awake ${keepAwake ? "on" : "off"}`, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native12.View, { style: styles9.toggleContent, children: [
|
|
535
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SettingIcon, { source: keepAwake ? "eye" : "eye-closed", color: keepAwake ? colors.tertiary : colors.onSurfaceVariant, containerColor: keepAwake ? colors.tertiaryContainer : colors.surfaceVariant }),
|
|
536
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native12.View, { style: styles9.flexShrink, children: [
|
|
537
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_paper8.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Keep Awake" }),
|
|
538
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_paper8.Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Stop auto-lock mid-match" })
|
|
539
|
+
] })
|
|
540
|
+
] }) }),
|
|
533
541
|
(showSound || showHaptics) && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native12.View, { style: styles9.toggleRow, children: [
|
|
534
542
|
showSound && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
535
543
|
import_feedback_press2.TouchableRipple,
|
package/dist/chrome/index.mjs
CHANGED
|
@@ -293,7 +293,7 @@ import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
|
293
293
|
function SettingIcon({ source, color, containerColor }) {
|
|
294
294
|
return /* @__PURE__ */ jsx8(View6, { style: [styles7.iconBadge, { backgroundColor: containerColor }], children: /* @__PURE__ */ jsx8(Icon2, { source, size: 18, color }) });
|
|
295
295
|
}
|
|
296
|
-
function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, version, lockOrientation, onLockOrientationChange, deferBottomEdgeGestures, onDeferBottomEdgeGestures, hideSound = false, hideHaptics = false, hideAppearance = false, hideUpdateCheck = false, onUpdateError, onShowHowToPlay, children }) {
|
|
296
|
+
function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, version, lockOrientation, onLockOrientationChange, deferBottomEdgeGestures, onDeferBottomEdgeGestures, keepAwake, onKeepAwakeChange, hideSound = false, hideHaptics = false, hideAppearance = false, hideUpdateCheck = false, onUpdateError, onShowHowToPlay, children }) {
|
|
297
297
|
const { colors } = useAutoPaperTheme6();
|
|
298
298
|
const ambientRotation = useRotation2();
|
|
299
299
|
const rotation = rotationOverride ?? ambientRotation;
|
|
@@ -323,6 +323,7 @@ function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, ve
|
|
|
323
323
|
if (visible && !opened) setOpened(true);
|
|
324
324
|
const showLockOrientation = isTouchPrimary && lockOrientation !== void 0 && onLockOrientationChange !== void 0;
|
|
325
325
|
const showEdgeGuard = Platform2.OS === "ios" && deferBottomEdgeGestures !== void 0 && onDeferBottomEdgeGestures !== void 0;
|
|
326
|
+
const showKeepAwake = isTouchPrimary && keepAwake !== void 0 && onKeepAwakeChange !== void 0;
|
|
326
327
|
const showHaptics = Platform2.OS !== "web" && !hideHaptics;
|
|
327
328
|
const showSound = !hideSound;
|
|
328
329
|
const showAppearance = !hideAppearance;
|
|
@@ -349,6 +350,13 @@ function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, ve
|
|
|
349
350
|
/* @__PURE__ */ jsx8(Text6, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Require second swipe" })
|
|
350
351
|
] })
|
|
351
352
|
] }) }),
|
|
353
|
+
showKeepAwake && /* @__PURE__ */ jsx8(TouchableRipple, { onPress: () => onKeepAwakeChange(!keepAwake), style: styles7.toggleButton, accessibilityLabel: `Keep awake ${keepAwake ? "on" : "off"}`, children: /* @__PURE__ */ jsxs7(View6, { style: styles7.toggleContent, children: [
|
|
354
|
+
/* @__PURE__ */ jsx8(SettingIcon, { source: keepAwake ? "eye" : "eye-closed", color: keepAwake ? colors.tertiary : colors.onSurfaceVariant, containerColor: keepAwake ? colors.tertiaryContainer : colors.surfaceVariant }),
|
|
355
|
+
/* @__PURE__ */ jsxs7(View6, { style: styles7.flexShrink, children: [
|
|
356
|
+
/* @__PURE__ */ jsx8(Text6, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Keep Awake" }),
|
|
357
|
+
/* @__PURE__ */ jsx8(Text6, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Stop auto-lock mid-match" })
|
|
358
|
+
] })
|
|
359
|
+
] }) }),
|
|
352
360
|
(showSound || showHaptics) && /* @__PURE__ */ jsxs7(View6, { style: styles7.toggleRow, children: [
|
|
353
361
|
showSound && /* @__PURE__ */ jsx8(
|
|
354
362
|
TouchableRipple,
|
package/dist/index.js
CHANGED
|
@@ -678,7 +678,7 @@ var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
|
678
678
|
function SettingIcon({ source, color, containerColor }) {
|
|
679
679
|
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native13.View, { style: [styles10.iconBadge, { backgroundColor: containerColor }], children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native_paper9.Icon, { source, size: 18, color }) });
|
|
680
680
|
}
|
|
681
|
-
function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, version, lockOrientation, onLockOrientationChange, deferBottomEdgeGestures, onDeferBottomEdgeGestures, hideSound = false, hideHaptics = false, hideAppearance = false, hideUpdateCheck = false, onUpdateError, onShowHowToPlay, children }) {
|
|
681
|
+
function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, version, lockOrientation, onLockOrientationChange, deferBottomEdgeGestures, onDeferBottomEdgeGestures, keepAwake, onKeepAwakeChange, hideSound = false, hideHaptics = false, hideAppearance = false, hideUpdateCheck = false, onUpdateError, onShowHowToPlay, children }) {
|
|
682
682
|
const { colors } = (0, import_auto_paper9.useAutoPaperTheme)();
|
|
683
683
|
const ambientRotation = (0, import_core4.useRotation)();
|
|
684
684
|
const rotation = rotationOverride ?? ambientRotation;
|
|
@@ -708,6 +708,7 @@ function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, ve
|
|
|
708
708
|
if (visible && !opened) setOpened(true);
|
|
709
709
|
const showLockOrientation = isTouchPrimary && lockOrientation !== void 0 && onLockOrientationChange !== void 0;
|
|
710
710
|
const showEdgeGuard = import_react_native13.Platform.OS === "ios" && deferBottomEdgeGestures !== void 0 && onDeferBottomEdgeGestures !== void 0;
|
|
711
|
+
const showKeepAwake = isTouchPrimary && keepAwake !== void 0 && onKeepAwakeChange !== void 0;
|
|
711
712
|
const showHaptics = import_react_native13.Platform.OS !== "web" && !hideHaptics;
|
|
712
713
|
const showSound = !hideSound;
|
|
713
714
|
const showAppearance = !hideAppearance;
|
|
@@ -734,6 +735,13 @@ function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, ve
|
|
|
734
735
|
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native_paper9.Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Require second swipe" })
|
|
735
736
|
] })
|
|
736
737
|
] }) }),
|
|
738
|
+
showKeepAwake && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_feedback_press2.TouchableRipple, { onPress: () => onKeepAwakeChange(!keepAwake), style: styles10.toggleButton, accessibilityLabel: `Keep awake ${keepAwake ? "on" : "off"}`, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native13.View, { style: styles10.toggleContent, children: [
|
|
739
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SettingIcon, { source: keepAwake ? "eye" : "eye-closed", color: keepAwake ? colors.tertiary : colors.onSurfaceVariant, containerColor: keepAwake ? colors.tertiaryContainer : colors.surfaceVariant }),
|
|
740
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native13.View, { style: styles10.flexShrink, children: [
|
|
741
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native_paper9.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Keep Awake" }),
|
|
742
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native_paper9.Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Stop auto-lock mid-match" })
|
|
743
|
+
] })
|
|
744
|
+
] }) }),
|
|
737
745
|
(showSound || showHaptics) && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native13.View, { style: styles10.toggleRow, children: [
|
|
738
746
|
showSound && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
739
747
|
import_feedback_press2.TouchableRipple,
|
package/dist/index.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tastic/hud",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.0",
|
|
4
4
|
"description": "Visual component kit for local-multiplayer React Native games: inline (non-modal) popovers, dropdowns, color pickers, gauges, ready buttons, and dialogs, built to stay scoped to one player's own zone on a shared screen",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react-native",
|
|
@@ -87,15 +87,15 @@
|
|
|
87
87
|
"@infinitetoken/eslint-config": "^0.2.0",
|
|
88
88
|
"@infinitetoken/jest-config": "^0.4.0",
|
|
89
89
|
"@infinitetoken/tsconfig": "^0.5.0",
|
|
90
|
-
"@rific/auto-paper": "^0.13.
|
|
91
|
-
"@rific/core": "^0.3.
|
|
90
|
+
"@rific/auto-paper": "^0.13.2",
|
|
91
|
+
"@rific/core": "^0.3.1",
|
|
92
92
|
"@rific/feedback-press": "^0.13.0",
|
|
93
|
-
"@rific/updater": "^0.
|
|
93
|
+
"@rific/updater": "^0.7.1",
|
|
94
94
|
"@shopify/react-native-skia": "^2.6.2",
|
|
95
|
-
"@tastic/achievements": "^0.
|
|
96
|
-
"@tastic/core": "^0.
|
|
95
|
+
"@tastic/achievements": "^0.6.0",
|
|
96
|
+
"@tastic/core": "^0.14.0",
|
|
97
97
|
"@tastic/profile": "^0.12.0",
|
|
98
|
-
"@tastic/split-screen": "^0.5.
|
|
98
|
+
"@tastic/split-screen": "^0.5.2",
|
|
99
99
|
"@testing-library/dom": "^10.4.1",
|
|
100
100
|
"@testing-library/react": "^16.3.2",
|
|
101
101
|
"@types/jest": "^30.0.0",
|
|
@@ -56,6 +56,13 @@ export interface BaseSettingsDialogProps {
|
|
|
56
56
|
// @tastic/edge-guard's own swizzle is a no-op on every other platform.
|
|
57
57
|
deferBottomEdgeGestures?: boolean
|
|
58
58
|
onDeferBottomEdgeGestures?: (value: boolean) => void
|
|
59
|
+
// Optional, and always passed as a pair - omit both for an app that doesn't keep the screen awake.
|
|
60
|
+
// This dialog only shows and reports the toggle; the app itself keeps the screen on while it's set
|
|
61
|
+
// (expo-keep-awake on its match screen), so this package needs no native dependency for it. Shown
|
|
62
|
+
// on the same devices as Lock Orientation (see isTouchPrimary below): a desktop/laptop browser
|
|
63
|
+
// stays awake on its own while someone is playing with its keyboard or mouse.
|
|
64
|
+
keepAwake?: boolean
|
|
65
|
+
onKeepAwakeChange?: (value: boolean) => void
|
|
59
66
|
// Explicit opt-outs for the rows that pull their own state straight from @rific/feedback-press,
|
|
60
67
|
// @rific/auto-paper, and @rific/updater's own shared contexts/hooks rather than from anything the
|
|
61
68
|
// caller passes in - unlike Lock Orientation/Edge Guard above, there's no "value" to omit for
|
|
@@ -83,14 +90,14 @@ export interface BaseSettingsDialogProps {
|
|
|
83
90
|
children?: ReactNode
|
|
84
91
|
}
|
|
85
92
|
|
|
86
|
-
// The settings shell every @tastic game shares - orientation lock, the optional edge-guard
|
|
87
|
-
// sound/haptics, appearance, and update checking - extracted after the same six rows were
|
|
93
|
+
// The settings shell every @tastic game shares - orientation lock, the optional edge-guard and
|
|
94
|
+
// keep-awake toggles, sound/haptics, appearance, and update checking - extracted after the same six rows were
|
|
88
95
|
// independently copied into LightCycles, AirHockey, BoxHockey, Pong, and Snake and then needed
|
|
89
96
|
// hand-editing in every one of them, twice, for what were meant to be identical fixes. `children`
|
|
90
97
|
// is the seam for whatever isn't shared: a game with its own board/difficulty settings (or a stats
|
|
91
98
|
// backup flow, or anything else genuinely specific to it) renders those below Appearance, not by
|
|
92
99
|
// forking this component.
|
|
93
|
-
export function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, version, lockOrientation, onLockOrientationChange, deferBottomEdgeGestures, onDeferBottomEdgeGestures, hideSound = false, hideHaptics = false, hideAppearance = false, hideUpdateCheck = false, onUpdateError, onShowHowToPlay, children }: BaseSettingsDialogProps) {
|
|
100
|
+
export function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, version, lockOrientation, onLockOrientationChange, deferBottomEdgeGestures, onDeferBottomEdgeGestures, keepAwake, onKeepAwakeChange, hideSound = false, hideHaptics = false, hideAppearance = false, hideUpdateCheck = false, onUpdateError, onShowHowToPlay, children }: BaseSettingsDialogProps) {
|
|
94
101
|
const { colors } = useAutoPaperTheme()
|
|
95
102
|
const ambientRotation = useRotation()
|
|
96
103
|
const rotation = rotationOverride ?? ambientRotation
|
|
@@ -106,7 +113,7 @@ export function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverr
|
|
|
106
113
|
// Dialog's own 32pt padding is simply overhung.
|
|
107
114
|
const insets = rotateInsets(useSafeAreaInsets(), rotation)
|
|
108
115
|
const sheetWidth = Math.min(overlayStyles.card.maxWidth, (turned ? window.height : window.width) - 2 * Math.max(insets.left, insets.right, SHEET_GUTTER))
|
|
109
|
-
// Also gates the Lock Orientation
|
|
116
|
+
// Also gates the Lock Orientation and Keep Awake rows below (alongside their own props) - true
|
|
110
117
|
// unconditionally on native (see the hook's own doc), so this only actually excludes a
|
|
111
118
|
// desktop/laptop browser, where a mouse-driven window has no physical orientation to lock
|
|
112
119
|
// against; a resize there would just make the setting silently stop reflowing the layout instead
|
|
@@ -153,6 +160,7 @@ export function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverr
|
|
|
153
160
|
|
|
154
161
|
const showLockOrientation = isTouchPrimary && lockOrientation !== undefined && onLockOrientationChange !== undefined
|
|
155
162
|
const showEdgeGuard = Platform.OS === 'ios' && deferBottomEdgeGestures !== undefined && onDeferBottomEdgeGestures !== undefined
|
|
163
|
+
const showKeepAwake = isTouchPrimary && keepAwake !== undefined && onKeepAwakeChange !== undefined
|
|
156
164
|
const showHaptics = Platform.OS !== 'web' && !hideHaptics
|
|
157
165
|
const showSound = !hideSound
|
|
158
166
|
const showAppearance = !hideAppearance
|
|
@@ -235,6 +243,23 @@ export function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverr
|
|
|
235
243
|
</TouchableRipple>
|
|
236
244
|
)}
|
|
237
245
|
|
|
246
|
+
{/* See the keepAwake prop's own doc: the app does the keeping awake, this only toggles it. */}
|
|
247
|
+
{showKeepAwake && (
|
|
248
|
+
<TouchableRipple onPress={() => onKeepAwakeChange!(!keepAwake)} style={styles.toggleButton} accessibilityLabel={`Keep awake ${keepAwake ? 'on' : 'off'}`}>
|
|
249
|
+
<View style={styles.toggleContent}>
|
|
250
|
+
<SettingIcon source={keepAwake ? 'eye' : 'eye-closed'} color={keepAwake ? colors.tertiary : colors.onSurfaceVariant} containerColor={keepAwake ? colors.tertiaryContainer : colors.surfaceVariant} />
|
|
251
|
+
<View style={styles.flexShrink}>
|
|
252
|
+
<Text variant='bodyLarge' style={{ color: colors.onSurface }}>
|
|
253
|
+
Keep Awake
|
|
254
|
+
</Text>
|
|
255
|
+
<Text variant='bodySmall' numberOfLines={1} style={{ color: colors.onSurfaceVariant }}>
|
|
256
|
+
Stop auto-lock mid-match
|
|
257
|
+
</Text>
|
|
258
|
+
</View>
|
|
259
|
+
</View>
|
|
260
|
+
</TouchableRipple>
|
|
261
|
+
)}
|
|
262
|
+
|
|
238
263
|
{/* Side by side, not stacked - neither needs a full row's width (single-line label,
|
|
239
264
|
no description under it the way Lock Orientation has), so sharing one row reads
|
|
240
265
|
just as clearly and takes half the vertical space. toggleRow carries the same
|