From 6d75e3b7910a0906e718b29f768a7d3a0bcb906a Mon Sep 17 00:00:00 2001 From: benthecarman Date: Sun, 15 Oct 2023 20:04:22 -0500 Subject: [PATCH] Vibrate on successful send, receive, channel open --- android/app/capacitor.build.gradle | 1 + android/capacitor.settings.gradle | 3 +++ package.json | 1 + pnpm-lock.yaml | 11 +++++++++++ src/components/PendingNwc.tsx | 8 +++++++- src/routes/Receive.tsx | 5 ++++- src/routes/Send.tsx | 3 ++- src/routes/Swap.tsx | 4 +++- src/routes/settings/Plus.tsx | 4 +++- src/utils/index.ts | 1 + src/utils/vibrate.ts | 19 +++++++++++++++++++ vite.config.ts | 1 + 12 files changed, 56 insertions(+), 5 deletions(-) create mode 100644 src/utils/vibrate.ts diff --git a/android/app/capacitor.build.gradle b/android/app/capacitor.build.gradle index 2b52ff7..fd577e3 100644 --- a/android/app/capacitor.build.gradle +++ b/android/app/capacitor.build.gradle @@ -14,6 +14,7 @@ dependencies { implementation project(':capacitor-clipboard') implementation project(':capacitor-filesystem') implementation project(':capacitor-share') + implementation project(':capacitor-haptics') implementation project(':capacitor-toast') implementation project(':mutinywallet-barcode-scanner') diff --git a/android/capacitor.settings.gradle b/android/capacitor.settings.gradle index c946a17..e2511c2 100644 --- a/android/capacitor.settings.gradle +++ b/android/capacitor.settings.gradle @@ -17,6 +17,9 @@ project(':capacitor-filesystem').projectDir = new File('../node_modules/.pnpm/@c include ':capacitor-share' project(':capacitor-share').projectDir = new File('../node_modules/.pnpm/@capacitor+share@5.0.6_@capacitor+core@5.2.2/node_modules/@capacitor/share/android') +include ':capacitor-haptics' +project(':capacitor-haptics').projectDir = new File('../node_modules/.pnpm/@capacitor+haptics@5.0.6_@capacitor+core@5.2.2/node_modules/@capacitor/haptics/android') + include ':capacitor-toast' project(':capacitor-toast').projectDir = new File('../node_modules/.pnpm/@capacitor+toast@5.0.6_@capacitor+core@5.2.2/node_modules/@capacitor/toast/android') diff --git a/package.json b/package.json index 4cad283..3251951 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ "@capacitor/core": "^5.2.2", "@capacitor/filesystem": "^5.1.4", "@capacitor/share": "^5.0.6", + "@capacitor/haptics": "^5.0.6", "@capacitor/toast": "^5.0.6", "@kobalte/core": "^0.9.8", "@kobalte/tailwindcss": "^0.5.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ddca6a1..569fa8d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -29,6 +29,9 @@ importers: '@capacitor/share': specifier: ^5.0.6 version: 5.0.6(@capacitor/core@5.2.2) + '@capacitor/haptics': + specifier: ^5.0.6 + version: 5.0.6(@capacitor/core@5.2.2) '@capacitor/toast': specifier: ^5.0.6 version: 5.0.6(@capacitor/core@5.2.2) @@ -1611,6 +1614,14 @@ packages: '@capacitor/core': 5.2.2 dev: false + /@capacitor/haptics@5.0.6(@capacitor/core@5.2.2): + resolution: {integrity: sha512-UrMcR7p2X10ql4VLlowUuH/VckTeu0lj+RQpekxox14uxDmu5AGIFDK/iDTi8W6QZkxTJRZK6sbCjgwYgNJ7Pw==} + peerDependencies: + '@capacitor/core': ^5.0.0 + dependencies: + '@capacitor/core': 5.2.2 + dev: false + /@capacitor/toast@5.0.6(@capacitor/core@5.2.2): resolution: {integrity: sha512-djkRHVT8YtLJC1vvOnDU3EfAHfQYqAD7LYEXmSmhYuTnXRIggX93m/NkazwLnnpr95kDbs2VVPM/J6dqqYuJng==} peerDependencies: diff --git a/src/components/PendingNwc.tsx b/src/components/PendingNwc.tsx index b5e97db..326ff4b 100644 --- a/src/components/PendingNwc.tsx +++ b/src/components/PendingNwc.tsx @@ -21,7 +21,12 @@ import { } from "~/components"; import { useI18n } from "~/i18n/context"; import { useMegaStore } from "~/state/megaStore"; -import { createDeepSignal, eify, formatExpiration } from "~/utils"; +import { + createDeepSignal, + eify, + formatExpiration, + vibrateSuccess +} from "~/utils"; type PendingItem = { id: string; @@ -72,6 +77,7 @@ export function PendingNwc() { setPaying(item.id); const nodes = await state.mutiny_wallet?.list_nodes(); await state.mutiny_wallet?.approve_invoice(item.id, nodes[0]); + await vibrateSuccess(); } catch (e) { setError(eify(e)); console.error(e); diff --git a/src/routes/Receive.tsx b/src/routes/Receive.tsx index 4cd66b2..931c9e7 100644 --- a/src/routes/Receive.tsx +++ b/src/routes/Receive.tsx @@ -51,7 +51,8 @@ import { eify, mempoolTxUrl, MutinyTagItem, - objectToSearchParams + objectToSearchParams, + vibrateSuccess } from "~/utils"; type OnChainTx = { @@ -314,6 +315,7 @@ export default function Receive() { if (invoice && invoice.paid) { setReceiveState("paid"); setPaymentInvoice(invoice); + await vibrateSuccess(); return "lightning_paid"; } } @@ -325,6 +327,7 @@ export default function Receive() { if (tx) { setReceiveState("paid"); setPaymentTx(tx); + await vibrateSuccess(); return "onchain_paid"; } } catch (e) { diff --git a/src/routes/Send.tsx b/src/routes/Send.tsx index c51b0e5..4cab6c2 100644 --- a/src/routes/Send.tsx +++ b/src/routes/Send.tsx @@ -47,7 +47,7 @@ import { useI18n } from "~/i18n/context"; import { Network } from "~/logic/mutinyWalletSetup"; import { ParsedParams } from "~/logic/waila"; import { useMegaStore } from "~/state/megaStore"; -import { eify, mempoolTxUrl, MutinyTagItem } from "~/utils"; +import { eify, mempoolTxUrl, MutinyTagItem, vibrateSuccess } from "~/utils"; export type SendSource = "lightning" | "onchain"; @@ -549,6 +549,7 @@ export default function Send() { } setSentDetails(sentDetails as SentDetails); clearAll(); + await vibrateSuccess(); } catch (e) { const error = eify(e); setSentDetails({ failure_reason: error.message }); diff --git a/src/routes/Swap.tsx b/src/routes/Swap.tsx index b26d5c8..6fca822 100644 --- a/src/routes/Swap.tsx +++ b/src/routes/Swap.tsx @@ -35,7 +35,7 @@ import { useI18n } from "~/i18n/context"; import { Network } from "~/logic/mutinyWalletSetup"; import { MethodChooser, SendSource } from "~/routes/Send"; import { useMegaStore } from "~/state/megaStore"; -import { eify, mempoolTxUrl } from "~/utils"; +import { eify, mempoolTxUrl, vibrateSuccess } from "~/utils"; const CHANNEL_FEE_ESTIMATE_ADDRESS = "bc1qf7546vg73ddsjznzq57z3e8jdn6gtw6au576j07kt6d9j7nz8mzsyn6lgf"; @@ -158,6 +158,8 @@ export default function Swap() { setChannelOpenResult({ channel: new_channel }); } + + await vibrateSuccess(); } catch (e) { setChannelOpenResult({ failure_reason: eify(e) }); } finally { diff --git a/src/routes/settings/Plus.tsx b/src/routes/settings/Plus.tsx index 251f1b9..4f0e20f 100644 --- a/src/routes/settings/Plus.tsx +++ b/src/routes/settings/Plus.tsx @@ -27,7 +27,7 @@ import { } from "~/components"; import { useI18n } from "~/i18n/context"; import { useMegaStore } from "~/state/megaStore"; -import { eify, subscriptionValid } from "~/utils"; +import { eify, subscriptionValid, vibrateSuccess } from "~/utils"; function Perks(props: { alreadySubbed?: boolean }) { const i18n = useI18n(); @@ -90,6 +90,8 @@ function PlusCTA() { invoice?.bolt11 ); + await vibrateSuccess(); + // "true" flag gives this a fallback to set a timestamp in case the subscription server is down await actions.checkForSubscription(true); } catch (e) { diff --git a/src/utils/index.ts b/src/utils/index.ts index cf26dab..567df09 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -15,4 +15,5 @@ export * from "./typescript"; export * from "./useCopy"; export * from "./words"; export * from "./fetchZaps"; +export * from "./vibrate"; export * from "./openLinkProgrammatically"; diff --git a/src/utils/vibrate.ts b/src/utils/vibrate.ts new file mode 100644 index 0000000..ddbf82b --- /dev/null +++ b/src/utils/vibrate.ts @@ -0,0 +1,19 @@ +import { Capacitor } from "@capacitor/core"; +import { Haptics } from "@capacitor/haptics"; +import { NotificationType } from "@capacitor/haptics/dist/esm/definitions"; + +export const vibrate = async (millis = 250) => { + if (Capacitor.isNativePlatform()) { + await Haptics.vibrate({ duration: millis }); + } else { + window.navigator.vibrate(millis); + } +}; + +export const vibrateSuccess = async () => { + if (Capacitor.isNativePlatform()) { + await Haptics.notification({ type: NotificationType.Success }); + } else { + window.navigator.vibrate([35, 65, 21]); + } +}; diff --git a/vite.config.ts b/vite.config.ts index a4b86a5..a939b96 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -51,6 +51,7 @@ export default defineConfig({ "@capacitor/core", "@capacitor/filesystem", "@capacitor/toast", + "@capacitor/haptics", "@capacitor/app", "@capacitor/browser", ],