Skip to content

Commit

Permalink
Prevent mobile browsers from sleeping during transfer (#125)
Browse files Browse the repository at this point in the history
We use nosleep.js to provide sleep prevention by playing a video offscreen.
Its activation is tied with user interaction events to work around browsers that
block autoplay.
  • Loading branch information
JustusFT authored Jan 19, 2023
1 parent 39028b7 commit 9bce5dc
Show file tree
Hide file tree
Showing 10 changed files with 45 additions and 2 deletions.
11 changes: 11 additions & 0 deletions client/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"bowser": "^2.11.0",
"classnames": "^2.3.1",
"fastest-levenshtein": "^1.0.12",
"nosleep.js": "^0.12.0",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"react-dropzone": "^14.2.1",
Expand Down
3 changes: 3 additions & 0 deletions client/src/app/NoSleep.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import nosleep from "nosleep.js";

export const NoSleep = new nosleep();
6 changes: 5 additions & 1 deletion client/src/app/components/Dropzone.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import classNames from "classnames";
import React from "react";
import { FileRejection, useDropzone } from "react-dropzone";
import { Plus } from "tabler-icons-react";
import { NoSleep } from "../NoSleep";
import Link from "./Link";

const useStyles = createStyles((theme) => ({
Expand Down Expand Up @@ -96,7 +97,10 @@ export default function Dropzone(props: Props) {
const button = (
<Group position="center">
<Button
onClick={open}
onClick={() => {
NoSleep.enable();
open();
}}
className={classNames(classes.dropzoneButton)}
color="tertiary"
>
Expand Down
7 changes: 7 additions & 0 deletions client/src/app/components/providers/WormholeProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { PropsWithChildren, useEffect, useRef, useState } from "react";
import { useCodeInput } from "../../hooks/useCodeInput";
import { useError } from "../../hooks/useError";
import { useRateLimitedState } from "../../hooks/useRateLimitedState";
import { NoSleep } from "../../NoSleep";
import { PROGRESS_BAR_MS_PER_UPDATES } from "../../util/constants";
import { detectErrorType, ErrorTypes } from "../../util/errors";
import ClientWorker from "../../wormhole/client_worker";
Expand Down Expand Up @@ -181,6 +182,12 @@ export default function WormholeProvider(props: Props) {
);
}, []);

useEffect(() => {
if (!fileMeta || done) {
NoSleep.disable();
}
}, [fileMeta, done]);

async function sendFile(
file: File,
opts?: TransferOptions
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { Modal, Space, Text } from "@mantine/core";
import React from "react";
import React, { useEffect } from "react";
import { useCancelModal } from "../../../hooks/useCancelModal";
import { useCodeInput } from "../../../hooks/useCodeInput";
import { useCommonStyles } from "../../../hooks/useCommonStyles";
import { useError } from "../../../hooks/useError";
import { useWormhole } from "../../../hooks/useWormhole";
import { NoSleep } from "../../../NoSleep";
import { detectErrorType } from "../../../util/errors";
import CodeInput from "../../CodeInput";
import Content from "../../Content";
Expand Down Expand Up @@ -58,11 +59,18 @@ export default function ReceiveBeginScreen({}: Props) {
const error = useError();
const codeInput = useCodeInput();

useEffect(() => {
if (error?.error) {
NoSleep.disable();
}
}, [error]);

return (
<ReceiveBeginScreenContent
cancelModalOpen={cancelModal}
onCancelModalClose={() => setCancelModal(false)}
onSubmit={(code) => {
NoSleep.enable();
if (wormhole) {
codeInput?.setSubmitting(true);
wormhole
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { useError } from "../../../hooks/useError";
import { useNavigate } from "../../../hooks/useNavigate";
import { onTabExit, useTabExitWarning } from "../../../hooks/useTabExitWarning";
import { useWormhole } from "../../../hooks/useWormhole";
import { NoSleep } from "../../../NoSleep";
import { detectErrorType } from "../../../util/errors";
import Content from "../../Content";
import FileLabel from "../../FileLabel";
Expand Down Expand Up @@ -75,6 +76,7 @@ export default function ReceiveConsentScreen({}: Props) {
<ReceiveConsentScreenContent
submitting={submitting}
onAccept={() => {
NoSleep.enable();
setSubmitting(true);
wormhole?.fileMeta
?.accept()
Expand Down
5 changes: 5 additions & 0 deletions client/src/app/components/screens/send/SendBeginScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { FileRejection } from "react-dropzone";
import { useCancelModal } from "../../../hooks/useCancelModal";
import { useCommonStyles } from "../../../hooks/useCommonStyles";
import { useWormhole } from "../../../hooks/useWormhole";
import { NoSleep } from "../../../NoSleep";
import Content from "../../Content";
import Dropzone from "../../Dropzone";
import Link from "../../Link";
Expand Down Expand Up @@ -139,6 +140,10 @@ export default function SendBeginScreen(props: Props) {
wormhole?.sendFile(files[0]);
}}
onReject={(rejections) => {
if (rejections.length) {
NoSleep.disable();
}

if (rejections.length > 1) {
setModalState("DIRECTORIES_NOT_SUPPORTED");
} else if (rejections.length == 1) {
Expand Down
1 change: 1 addition & 0 deletions client/src/app/index.development.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import CodeInputProvider from "./components/providers/CodeInputProvider";
import ErrorProvider from "./components/providers/ErrorProvider";
import ThemeProvider from "./components/providers/ThemeProvider";
import WormholeProvider from "./components/providers/WormholeProvider";
import "./NoSleep";

Sentry.init({
dsn: process.env["SENTRY_DSN"],
Expand Down
1 change: 1 addition & 0 deletions client/src/app/index.production.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import CodeInputProvider from "./components/providers/CodeInputProvider";
import ErrorProvider from "./components/providers/ErrorProvider";
import ThemeProvider from "./components/providers/ThemeProvider";
import WormholeProvider from "./components/providers/WormholeProvider";
import "./NoSleep";

ReactDOM.render(
<CodeInputProvider>
Expand Down

0 comments on commit 9bce5dc

Please sign in to comment.