From a784fbd060ca20f22382931f17526f237b2b37df Mon Sep 17 00:00:00 2001 From: Kendall Garner <17521368+kgarner7@users.noreply.github.com> Date: Sat, 4 Nov 2023 20:27:24 -0700 Subject: [PATCH] [feat]: Remote Improvements - Make the interface a bit more responsive (menu, button changes) - Enable disabling screen lock (needs better icon) - Improve updated rating --- package-lock.json | 45 +++- package.json | 1 + src/remote/app.tsx | 6 + .../components/buttons/image-button.tsx | 3 - .../components/buttons/reconnect-button.tsx | 3 - .../components/buttons/remote-button.tsx | 34 +-- .../components/buttons/sleep-button.tsx | 18 ++ .../components/buttons/theme-button.tsx | 10 - src/remote/components/menu.tsx | 49 +++++ src/remote/components/remote-container.tsx | 198 ++++++++++-------- src/remote/components/shell.tsx | 135 +++++++----- src/remote/context/nosleep-context.tsx | 15 ++ src/remote/hooks/use-toggle-no-sleep.tsx | 28 +++ 13 files changed, 376 insertions(+), 169 deletions(-) create mode 100644 src/remote/components/buttons/sleep-button.tsx create mode 100644 src/remote/components/menu.tsx create mode 100644 src/remote/context/nosleep-context.tsx create mode 100644 src/remote/hooks/use-toggle-no-sleep.tsx diff --git a/package-lock.json b/package-lock.json index 088114b46..d6317cddd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,7 +5,6 @@ "requires": true, "packages": { "": { - "name": "feishin", "version": "0.5.1", "hasInstallScript": true, "license": "GPL-3.0", @@ -52,6 +51,7 @@ "nanoid": "^3.3.3", "net": "^1.0.2", "node-mpv": "github:jeffvli/Node-MPV", + "nosleep.js": "^0.12.0", "overlayscrollbars": "^2.2.1", "overlayscrollbars-react": "^0.5.1", "react": "^18.2.0", @@ -219,6 +219,8 @@ "integrity": "sha512-prtg5f6zCERIaECeTZzd2fMtVjlfjhUcO+fBLQ6DXXdq5FljN+excVitJ2nogsusdf31LeqkjAfXZ7Xq+HmN8g==", "dependencies": { "@jridgewell/trace-mapping": "^0.3.17", + "@nicolo-ribaudo/chokidar-2": "2.1.8-no-fsevents.3", + "chokidar": "^3.4.0", "commander": "^4.0.1", "convert-source-map": "^1.1.0", "fs-readdir-recursive": "^1.1.0", @@ -2384,6 +2386,7 @@ "debug": "^4.1.1", "env-paths": "^2.2.0", "fs-extra": "^8.1.0", + "global-agent": "^3.0.0", "got": "^11.8.5", "progress": "^2.0.3", "semver": "^6.2.0", @@ -2439,6 +2442,7 @@ "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, "dependencies": { + "graceful-fs": "^4.1.6", "universalify": "^2.0.0" }, "optionalDependencies": { @@ -2507,6 +2511,7 @@ "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, "dependencies": { + "graceful-fs": "^4.1.6", "universalify": "^2.0.0" }, "optionalDependencies": { @@ -2698,6 +2703,7 @@ "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, "dependencies": { + "graceful-fs": "^4.1.6", "universalify": "^2.0.0" }, "optionalDependencies": { @@ -2758,6 +2764,7 @@ "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", "dev": true, "dependencies": { + "encoding": "^0.1.13", "minipass": "^3.1.6", "minipass-sized": "^1.0.3", "minizlib": "^2.1.2" @@ -2945,6 +2952,7 @@ "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, "dependencies": { + "graceful-fs": "^4.1.6", "universalify": "^2.0.0" }, "optionalDependencies": { @@ -3729,6 +3737,7 @@ "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, "dependencies": { + "graceful-fs": "^4.1.6", "universalify": "^2.0.0" }, "optionalDependencies": { @@ -4504,6 +4513,7 @@ "dependencies": { "camelcase": "^5.3.1", "loader-utils": "^1.4.2", + "prettier": "*", "schema-utils": "^2.0.1" }, "optionalDependencies": { @@ -6031,6 +6041,7 @@ "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, "dependencies": { + "graceful-fs": "^4.1.6", "universalify": "^2.0.0" }, "optionalDependencies": { @@ -6943,6 +6954,7 @@ "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, "dependencies": { + "graceful-fs": "^4.1.6", "universalify": "^2.0.0" }, "optionalDependencies": { @@ -7199,6 +7211,7 @@ "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", + "fsevents": "~2.3.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", @@ -8637,6 +8650,7 @@ "app-builder-lib": "24.6.3", "builder-util": "24.5.0", "builder-util-runtime": "9.2.1", + "dmg-license": "^1.0.11", "fs-extra": "^10.1.0", "iconv-lite": "^0.6.2", "js-yaml": "^4.1.0" @@ -8678,6 +8692,7 @@ "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, "dependencies": { + "graceful-fs": "^4.1.6", "universalify": "^2.0.0" }, "optionalDependencies": { @@ -9010,6 +9025,7 @@ "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, "dependencies": { + "graceful-fs": "^4.1.6", "universalify": "^2.0.0" }, "optionalDependencies": { @@ -9137,6 +9153,7 @@ "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, "dependencies": { + "graceful-fs": "^4.1.6", "universalify": "^2.0.0" }, "optionalDependencies": { @@ -9200,6 +9217,7 @@ "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, "dependencies": { + "graceful-fs": "^4.1.6", "universalify": "^2.0.0" }, "optionalDependencies": { @@ -9276,6 +9294,7 @@ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dependencies": { + "graceful-fs": "^4.1.6", "universalify": "^2.0.0" }, "optionalDependencies": { @@ -9581,7 +9600,8 @@ "esprima": "^4.0.1", "estraverse": "^5.2.0", "esutils": "^2.0.2", - "optionator": "^0.8.1" + "optionator": "^0.8.1", + "source-map": "~0.6.1" }, "bin": { "escodegen": "bin/escodegen.js", @@ -10752,6 +10772,7 @@ "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", "dev": true, "dependencies": { + "@types/yauzl": "^2.9.1", "debug": "^4.1.1", "get-stream": "^5.1.0", "yauzl": "^2.10.0" @@ -11106,6 +11127,7 @@ "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-10.13.0.tgz", "integrity": "sha512-xKhw9VCizmwEHbopOfluaoVunGHSZyMztGbTvsgOYqCjaKu6qtlwWY1J+6GhL41NY1P157JgEikjDm67XCFnvQ==", "dependencies": { + "@emotion/is-prop-valid": "^0.8.2", "tslib": "^2.4.0" }, "optionalDependencies": { @@ -12247,6 +12269,7 @@ "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, "dependencies": { + "graceful-fs": "^4.1.6", "universalify": "^2.0.0" }, "optionalDependencies": { @@ -13396,6 +13419,7 @@ "@types/node": "*", "anymatch": "^3.0.3", "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", "graceful-fs": "^4.2.9", "jest-regex-util": "^27.5.1", "jest-serializer": "^27.5.1", @@ -13942,6 +13966,9 @@ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", "dev": true, + "dependencies": { + "graceful-fs": "^4.1.6" + }, "optionalDependencies": { "graceful-fs": "^4.1.6" } @@ -15229,6 +15256,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/nosleep.js": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/nosleep.js/-/nosleep.js-0.12.0.tgz", + "integrity": "sha512-9d1HbpKLh3sdWlhXMhU6MMH+wQzKkrgfRkYV0EBdvt99YJfj0ilCJrWRDYG2130Tm4GXbEoTCx5b34JSaP+HhA==" + }, "node_modules/now-and-later": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.1.tgz", @@ -18875,6 +18907,9 @@ "resolved": "https://registry.npmjs.org/stylelint-config-css-modules/-/stylelint-config-css-modules-4.3.0.tgz", "integrity": "sha512-KvIvhzzjpcjHKkGSPkQCueoZJHrb6sZ6GCtrQb/J45HQTBVwJAeNYXaSZZK6ZQOC7NxJ4v5kLxpQLDiCK6zzgw==", "dev": true, + "dependencies": { + "stylelint-scss": "^5.0.0 || ^6.0.0" + }, "optionalDependencies": { "stylelint-scss": "^5.0.0 || ^6.0.0" }, @@ -19432,6 +19467,7 @@ "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, "dependencies": { + "graceful-fs": "^4.1.6", "universalify": "^2.0.0" }, "optionalDependencies": { @@ -32716,6 +32752,11 @@ "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", "dev": true }, + "nosleep.js": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/nosleep.js/-/nosleep.js-0.12.0.tgz", + "integrity": "sha512-9d1HbpKLh3sdWlhXMhU6MMH+wQzKkrgfRkYV0EBdvt99YJfj0ilCJrWRDYG2130Tm4GXbEoTCx5b34JSaP+HhA==" + }, "now-and-later": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.1.tgz", diff --git a/package.json b/package.json index 3e5df6d52..cf2ce29c8 100644 --- a/package.json +++ b/package.json @@ -331,6 +331,7 @@ "nanoid": "^3.3.3", "net": "^1.0.2", "node-mpv": "github:jeffvli/Node-MPV", + "nosleep.js": "^0.12.0", "overlayscrollbars": "^2.2.1", "overlayscrollbars-react": "^0.5.1", "react": "^18.2.0", diff --git a/src/remote/app.tsx b/src/remote/app.tsx index d55814308..a1de2a57f 100644 --- a/src/remote/app.tsx +++ b/src/remote/app.tsx @@ -3,6 +3,7 @@ import { MantineProvider } from '@mantine/core'; import './styles/global.scss'; import { useIsDark, useReconnect } from '/@/remote/store'; import { Shell } from '/@/remote/components/shell'; +import { AppTheme } from '/@/renderer/themes/types'; export const App = () => { const isDark = useIsDark(); @@ -12,6 +13,11 @@ export const App = () => { reconnect(); }, [reconnect]); + useEffect(() => { + const targetTheme: AppTheme = isDark ? AppTheme.DEFAULT_DARK : AppTheme.DEFAULT_LIGHT; + document.body.setAttribute('data-theme', targetTheme); + }, [isDark]); + return ( { return ( toggleImage()} > {showImage ? : } diff --git a/src/remote/components/buttons/reconnect-button.tsx b/src/remote/components/buttons/reconnect-button.tsx index 41b5ed202..bf83d835e 100644 --- a/src/remote/components/buttons/reconnect-button.tsx +++ b/src/remote/components/buttons/reconnect-button.tsx @@ -9,10 +9,7 @@ export const ReconnectButton = () => { return ( reconnect()} > diff --git a/src/remote/components/buttons/remote-button.tsx b/src/remote/components/buttons/remote-button.tsx index 7e8b52423..226819d2f 100644 --- a/src/remote/components/buttons/remote-button.tsx +++ b/src/remote/components/buttons/remote-button.tsx @@ -12,7 +12,7 @@ interface StyledButtonProps extends MantineButtonProps { } export interface ButtonProps extends StyledButtonProps { - tooltip: string; + tooltip?: string; } const StyledButton = styled(Button)` @@ -37,19 +37,29 @@ const StyledButton = styled(Button)` export const RemoteButton = forwardRef( ({ children, tooltip, ...props }: ButtonProps, ref) => { - return ( - - - {children} - - + {children} + ); + if (tooltip) { + return ( + + {button} + + ); + } + return button; }, ); diff --git a/src/remote/components/buttons/sleep-button.tsx b/src/remote/components/buttons/sleep-button.tsx new file mode 100644 index 000000000..81ae8403a --- /dev/null +++ b/src/remote/components/buttons/sleep-button.tsx @@ -0,0 +1,18 @@ +import { RemoteButton } from '/@/remote/components/buttons/remote-button'; +import { LuMonitor, LuMonitorOff } from 'react-icons/lu'; +import { useNoSleepContext } from '/@/remote/context/nosleep-context'; +import { useToggleNoSleep } from '/@/remote/hooks/use-toggle-no-sleep'; + +export const SleepButton = () => { + const { enabled } = useNoSleepContext(); + const toggleNoSleep = useToggleNoSleep(); + + return ( + + {enabled ? : } + + ); +}; diff --git a/src/remote/components/buttons/theme-button.tsx b/src/remote/components/buttons/theme-button.tsx index 4e6bfc241..65db3a32d 100644 --- a/src/remote/components/buttons/theme-button.tsx +++ b/src/remote/components/buttons/theme-button.tsx @@ -1,24 +1,14 @@ import { useIsDark, useToggleDark } from '/@/remote/store'; import { RiMoonLine, RiSunLine } from 'react-icons/ri'; import { RemoteButton } from '/@/remote/components/buttons/remote-button'; -import { AppTheme } from '/@/renderer/themes/types'; -import { useEffect } from 'react'; export const ThemeButton = () => { const isDark = useIsDark(); const toggleDark = useToggleDark(); - useEffect(() => { - const targetTheme: AppTheme = isDark ? AppTheme.DEFAULT_DARK : AppTheme.DEFAULT_LIGHT; - document.body.setAttribute('data-theme', targetTheme); - }, [isDark]); - return ( toggleDark()} > {isDark ? : } diff --git a/src/remote/components/menu.tsx b/src/remote/components/menu.tsx new file mode 100644 index 000000000..b4900af25 --- /dev/null +++ b/src/remote/components/menu.tsx @@ -0,0 +1,49 @@ +import { CiImageOff, CiImageOn } from 'react-icons/ci'; +import { LuMonitor, LuMonitorOff } from 'react-icons/lu'; +import { RiMenuFill, RiMoonLine, RiSunLine } from 'react-icons/ri'; +import { RemoteButton } from '/@/remote/components/buttons/remote-button'; +import { DropdownMenu } from '/@/renderer/components/dropdown-menu'; +import { useIsDark, useShowImage, useToggleDark, useToggleShowImage } from '/@/remote/store'; +import { useNoSleepContext } from '/@/remote/context/nosleep-context'; +import { useToggleNoSleep } from '/@/remote/hooks/use-toggle-no-sleep'; + +export const ResponsiveMenu = () => { + const showImage = useShowImage(); + const toggleImage = useToggleShowImage(); + const isDark = useIsDark(); + const toggleDark = useToggleDark(); + + const { enabled } = useNoSleepContext(); + const toggleNoSleep = useToggleNoSleep(); + + return ( + + + + + + + + + : } + onClick={toggleImage} + > + {showImage ? 'Hide Image' : 'Show Image'} + + : } + onClick={toggleDark} + > + Toggle Theme + + : } + onClick={toggleNoSleep} + > + {enabled ? 'Enable screen lock' : 'Disable screen lock'} + + + + ); +}; diff --git a/src/remote/components/remote-container.tsx b/src/remote/components/remote-container.tsx index 2213fcbb3..e129cf7ef 100644 --- a/src/remote/components/remote-container.tsx +++ b/src/remote/components/remote-container.tsx @@ -1,9 +1,8 @@ import { useCallback } from 'react'; -import { Group, Image, Text, Title } from '@mantine/core'; +import { Center, Grid, Group, Image, MediaQuery, Text, Title } from '@mantine/core'; import { useInfo, useSend, useShowImage } from '/@/remote/store'; import { RemoteButton } from '/@/remote/components/buttons/remote-button'; import formatDuration from 'format-duration'; -import debounce from 'lodash/debounce'; import { RiHeartLine, RiPauseFill, @@ -17,7 +16,6 @@ import { } from 'react-icons/ri'; import { PlayerRepeat, PlayerStatus } from '/@/renderer/types'; import { WrapperSlider } from '/@/remote/components/wrapped-slider'; -import { Tooltip } from '/@/renderer/components/tooltip'; import { Rating } from '/@/renderer/components'; export const RemoteContainer = () => { @@ -34,8 +32,6 @@ export const RemoteContainer = () => { [send, id], ); - const debouncedSetRating = debounce(setRating, 400); - return ( <> {song && ( @@ -56,101 +52,125 @@ export const RemoteContainer = () => { )} - - send({ event: 'previous' })} - > - - - { - if (status === PlayerStatus.PLAYING) { - send({ event: 'pause' }); - } else if (status === PlayerStatus.PAUSED) { - send({ event: 'play' }); - } - }} - > - {status === PlayerStatus.PLAYING ? ( - - ) : ( - - )} - - send({ event: 'next' })} - > - - - - + send({ event: 'previous' })} + > + + + + + { + if (status === PlayerStatus.PLAYING) { + send({ event: 'pause' }); + } else if (status === PlayerStatus.PAUSED) { + send({ event: 'play' }); + } + }} + > + {status === PlayerStatus.PLAYING ? ( + + ) : ( + + )} + + + + + send({ event: 'next' })} + > + + + + + - send({ event: 'shuffle' })} + - - - send({ event: 'repeat' })} + send({ event: 'shuffle' })} + > + + + + - {repeat === undefined || repeat === PlayerRepeat.ONE ? ( - - ) : ( - - )} - - { - if (!id) return; + send({ event: 'repeat' })} + > + {repeat === undefined || repeat === PlayerRepeat.ONE ? ( + + ) : ( + + )} + + - send({ event: 'favorite', favorite: !song.userFavorite, id }); - }} + - - + { + if (!id) return; + + send({ event: 'favorite', favorite: !song.userFavorite, id }); + }} + > + + + + {(song?.serverType === 'navidrome' || song?.serverType === 'subsonic') && ( -
- + - debouncedSetRating(0)} - /> - -
+
+ +
+ + )} -
+ } max={100} diff --git a/src/remote/components/shell.tsx b/src/remote/components/shell.tsx index 1244f6c9c..b5782fa7c 100644 --- a/src/remote/components/shell.tsx +++ b/src/remote/components/shell.tsx @@ -14,62 +14,97 @@ import { ImageButton } from '/@/remote/components/buttons/image-button'; import { RemoteContainer } from '/@/remote/components/remote-container'; import { ReconnectButton } from '/@/remote/components/buttons/reconnect-button'; import { useConnected } from '/@/remote/store'; +import { NoSleepContext } from '/@/remote/context/nosleep-context'; +import NoSleep from 'nosleep.js'; +import { useMemo, useState } from 'react'; +import { SleepButton } from '/@/remote/components/buttons/sleep-button'; +import { ResponsiveMenu } from '/@/remote/components/menu'; export const Shell = () => { const connected = useConnected(); + const noSleep = useMemo(() => { + return new NoSleep(); + }, []); + + const [blockSleep, setBlockSleep] = useState(false); + + const noSleepValue = useMemo(() => { + return { enabled: blockSleep, noSleep, setEnabled: setBlockSleep }; + }, [blockSleep, noSleep]); return ( - - - -
- -
-
- - - Feishin Remote + + + + +
+ +
-
- - - + + Feishin Remote + + + + + + + + + + + - - - - - -
- - } - padding="md" - > - - {connected ? ( - - ) : ( - - )} - -
+ + + + + + + + + + + + } + padding="md" + > + + {connected ? ( + + ) : ( + + )} + + + ); }; diff --git a/src/remote/context/nosleep-context.tsx b/src/remote/context/nosleep-context.tsx new file mode 100644 index 000000000..d1f03aedb --- /dev/null +++ b/src/remote/context/nosleep-context.tsx @@ -0,0 +1,15 @@ +import { createContext, useContext } from 'react'; +import NoSleep from 'nosleep.js'; + +export const NoSleepContext = createContext<{ + enabled: boolean; + noSleep?: NoSleep; + setEnabled?: (val: boolean) => void; +}>({ + enabled: false, +}); + +export const useNoSleepContext = () => { + const ctxValue = useContext(NoSleepContext); + return ctxValue; +}; diff --git a/src/remote/hooks/use-toggle-no-sleep.tsx b/src/remote/hooks/use-toggle-no-sleep.tsx new file mode 100644 index 000000000..9f46838a7 --- /dev/null +++ b/src/remote/hooks/use-toggle-no-sleep.tsx @@ -0,0 +1,28 @@ +import { useCallback } from 'react'; +import { useNoSleepContext } from '/@/remote/context/nosleep-context'; +import { toast } from '/@/renderer/components'; + +export const useToggleNoSleep = () => { + const { noSleep, enabled, setEnabled } = useNoSleepContext(); + + const toggle = useCallback(async () => { + if (!noSleep) return; + + if (enabled) { + noSleep.disable(); + setEnabled!(false); + } else { + try { + await noSleep.enable(); + setEnabled!(true); + } catch (error) { + toast.error({ + message: (error as Error).message, + title: 'Failed to disable screen lock', + }); + } + } + }, [enabled, noSleep, setEnabled]); + + return toggle; +};