From 70a41211b354fc24c6be7984453f5593bfc5ef43 Mon Sep 17 00:00:00 2001 From: Mariko Kosaka Date: Tue, 14 May 2019 18:53:36 -0700 Subject: [PATCH] Vibrate the device on game lost (#454) * vibrate on lost * add preference in setting view * move to constants, slight naming change --- .../preact-canvas/components/game/index.tsx | 5 +++++ .../components/settings/index.tsx | 12 ++++++++++- src/services/preact-canvas/index.tsx | 21 ++++++++++++++++--- src/services/preact-canvas/lazy-load.ts | 8 ++++++- src/services/state/vibration-preference.ts | 21 +++++++++++++++++++ src/utils/constants.ts | 2 ++ 6 files changed, 64 insertions(+), 5 deletions(-) create mode 100644 src/services/state/vibration-preference.ts diff --git a/src/services/preact-canvas/components/game/index.tsx b/src/services/preact-canvas/components/game/index.tsx index c5ebeb00..27566a08 100644 --- a/src/services/preact-canvas/components/game/index.tsx +++ b/src/services/preact-canvas/components/game/index.tsx @@ -20,6 +20,7 @@ import { bind } from "src/utils/bind"; import { GameChangeCallback } from "../.."; import { StateChange } from "../../../../gamelogic"; import { Cell, PlayMode } from "../../../../gamelogic/types"; +import { vibrationLength } from "../../../../utils/constants"; import initFocusHandling from "../../../../utils/focus-visible"; import { isFeaturePhone } from "../../../../utils/static-display"; import Board from "../board"; @@ -47,6 +48,7 @@ export interface Props { toRevealTotal: number; useMotion: boolean; bestTime?: number; + useVibration: boolean; } interface State { @@ -186,6 +188,9 @@ export default class Game extends Component { this._tryAgainBtn ) { this._tryAgainBtn.focus(); + if (this.props.useVibration) { + navigator.vibrate(vibrationLength); + } } } diff --git a/src/services/preact-canvas/components/settings/index.tsx b/src/services/preact-canvas/components/settings/index.tsx index 82fdefe3..d6368795 100644 --- a/src/services/preact-canvas/components/settings/index.tsx +++ b/src/services/preact-canvas/components/settings/index.tsx @@ -35,6 +35,8 @@ interface Props { disableAnimationBtn: boolean; texturePromise: Promise; supportsSufficientWebGL: boolean; + useVibration: boolean; + onVibrationPrefChange: () => void; } interface State {} @@ -48,7 +50,9 @@ export default class Settings extends Component { motion, texturePromise, supportsSufficientWebGL, - disableAnimationBtn + disableAnimationBtn, + useVibration, + onVibrationPrefChange }: Props) { const closeBtn = isFeaturePhone ? ( + void; @@ -123,7 +124,8 @@ export default class Root extends Component { settingsOpen: false, motionPreference: true, gameInPlay: false, - allowIntroAnim: true + allowIntroAnim: true, + vibrationPreference: true }; private previousFocus: HTMLElement | null = null; @@ -144,7 +146,8 @@ export default class Root extends Component { lazyImport!.initOffline(); this.setState({ - motionPreference: await lazyImport!.shouldUseMotion() + motionPreference: await lazyImport!.shouldUseMotion(), + vibrationPreference: await lazyImport!.getVibrationPreference() }); }); @@ -220,7 +223,8 @@ export default class Root extends Component { motionPreference, gameInPlay, bestTime, - allowIntroAnim + allowIntroAnim, + vibrationPreference }: State ) { let mainComponent: VNode; @@ -242,6 +246,8 @@ export default class Root extends Component { } supportsSufficientWebGL={lazyImport!.supportsSufficientWebGL} texturePromise={texturePromise} + useVibration={vibrationPreference} + onVibrationPrefChange={this._onVibrationPrefChange} /> )} /> @@ -272,6 +278,7 @@ export default class Root extends Component { onDangerModeChange={this._onDangerModeChange} useMotion={motionPreference} bestTime={bestTime} + useVibration={vibrationPreference} /> )} /> @@ -348,6 +355,14 @@ export default class Root extends Component { setMotionPreference(motionPreference); } + @bind + private async _onVibrationPrefChange() { + const vibrationPreference = !this.state.vibrationPreference; + this.setState({ vibrationPreference }); + const { setVibrationPreference } = await lazyImportReady; + setVibrationPreference(vibrationPreference); + } + @bind private _onDangerModeChange(dangerMode: boolean) { this.setState({ dangerMode }); diff --git a/src/services/preact-canvas/lazy-load.ts b/src/services/preact-canvas/lazy-load.ts index 0aae0b7f..8516cf39 100644 --- a/src/services/preact-canvas/lazy-load.ts +++ b/src/services/preact-canvas/lazy-load.ts @@ -22,6 +22,10 @@ import { setMotionPreference, shouldUseMotion } from "../state/motion-preference"; +import { + getVibrationPreference, + setVibrationPreference +} from "../state/vibration-preference"; export { supportsSufficientWebGL, @@ -36,5 +40,7 @@ export { lazyGenerateTextures, setMotionPreference, getMotionPreference, - shouldUseMotion + shouldUseMotion, + getVibrationPreference, + setVibrationPreference }; diff --git a/src/services/state/vibration-preference.ts b/src/services/state/vibration-preference.ts new file mode 100644 index 00000000..6e602788 --- /dev/null +++ b/src/services/state/vibration-preference.ts @@ -0,0 +1,21 @@ +import { get, set } from "idb-keyval"; + +const DEFAULT: boolean = true; + +/** + * Set vibration preference (true means will vibrate) + * + * @param vibrate + */ +export async function setVibrationPreference(vibrate: boolean): Promise { + await set("vibrate", vibrate); +} + +export async function getVibrationPreference(): Promise { + const vibrate = await get("vibrate"); + if (typeof vibrate === "boolean") { + return vibrate; + } + // if no value is assigned to "vibrate", return default value + return DEFAULT; +} diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 4cef325f..28a397c3 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -28,3 +28,5 @@ export const forceMotionMode = : forceMotionParam === "1" ? true : undefined; + +export const vibrationLength = 300;