From 99b04740fef7fd2d3e2288af582c00ef060fe135 Mon Sep 17 00:00:00 2001 From: SimonStnn Date: Fri, 1 Nov 2024 17:16:33 +0100 Subject: [PATCH 01/16] Add global option to graph component #326 --- src/popup/components/graph.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/popup/components/graph.tsx b/src/popup/components/graph.tsx index c84267b..baf5170 100644 --- a/src/popup/components/graph.tsx +++ b/src/popup/components/graph.tsx @@ -9,7 +9,7 @@ import { import { BalloonName, HistoryNode } from '@/const'; import remote from '@/remote'; -export default (props: { startDate: Date; endDate: Date }) => { +export default (props: { startDate: Date; endDate: Date; global: boolean }) => { const [data, setData] = useState({} as (HistoryNode & { total: number })[]); const [poppedBalloonTypes, setPoppedBalloonTypes] = useState( [] @@ -20,7 +20,8 @@ export default (props: { startDate: Date; endDate: Date }) => { const fetchData = async () => { const response = await remote.getPopHistory( props.startDate, - props.endDate + props.endDate, + props.global ); const allBalloonNames = [ From a280a78dd614e7475648e8411eaba148a53994df Mon Sep 17 00:00:00 2001 From: SimonStnn Date: Fri, 1 Nov 2024 17:40:22 +0100 Subject: [PATCH 02/16] Add shadcn Toggle component --- package-lock.json | 114 +++++++++++++++++++++++++++++ package.json | 1 + src/popup/components/ui/toggle.tsx | 42 +++++++++++ 3 files changed, 157 insertions(+) create mode 100644 src/popup/components/ui/toggle.tsx diff --git a/package-lock.json b/package-lock.json index f6ac171..fe35b86 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,7 @@ "@radix-ui/react-separator": "^1.0.3", "@radix-ui/react-slider": "^1.1.2", "@radix-ui/react-slot": "^1.0.2", + "@radix-ui/react-toggle": "^1.1.0", "@radix-ui/react-tooltip": "^1.0.7", "class-variance-authority": "^0.7.0", "clsx": "^2.1.0", @@ -3068,6 +3069,119 @@ } } }, + "node_modules/@radix-ui/react-toggle": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-1.1.0.tgz", + "integrity": "sha512-gwoxaKZ0oJ4vIgzsfESBuSgJNdc0rv12VhHgcqN0TEJmmZixXG/2XpsLK8kzNWYcnaoRIEEQc0bEi3dIvdUpjw==", + "dependencies": { + "@radix-ui/primitive": "1.1.0", + "@radix-ui/react-primitive": "2.0.0", + "@radix-ui/react-use-controllable-state": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle/node_modules/@radix-ui/primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.0.tgz", + "integrity": "sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==" + }, + "node_modules/@radix-ui/react-toggle/node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz", + "integrity": "sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle/node_modules/@radix-ui/react-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.0.tgz", + "integrity": "sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==", + "dependencies": { + "@radix-ui/react-slot": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle/node_modules/@radix-ui/react-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz", + "integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle/node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz", + "integrity": "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-toggle/node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.1.0.tgz", + "integrity": "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-tooltip": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.0.7.tgz", diff --git a/package.json b/package.json index fb8bb13..b0ac89e 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "@radix-ui/react-separator": "^1.0.3", "@radix-ui/react-slider": "^1.1.2", "@radix-ui/react-slot": "^1.0.2", + "@radix-ui/react-toggle": "^1.1.0", "@radix-ui/react-tooltip": "^1.0.7", "class-variance-authority": "^0.7.0", "clsx": "^2.1.0", diff --git a/src/popup/components/ui/toggle.tsx b/src/popup/components/ui/toggle.tsx new file mode 100644 index 0000000..dae1a8b --- /dev/null +++ b/src/popup/components/ui/toggle.tsx @@ -0,0 +1,42 @@ +import * as TogglePrimitive from '@radix-ui/react-toggle'; +import { cva, type VariantProps } from 'class-variance-authority'; +import * as React from 'react'; +import { cn } from '@/utils'; + +const toggleVariants = cva( + 'inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground', + { + variants: { + variant: { + default: 'bg-transparent', + outline: + 'border border-input bg-transparent hover:bg-accent hover:text-accent-foreground', + }, + size: { + default: 'h-10 px-3', + sm: 'h-9 px-2.5', + lg: 'h-11 px-5', + }, + }, + defaultVariants: { + variant: 'default', + size: 'default', + }, + } +); + +const Toggle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & + VariantProps +>(({ className, variant, size, ...props }, ref) => ( + +)); + +Toggle.displayName = TogglePrimitive.Root.displayName; + +export { Toggle, toggleVariants }; From f24dfd38af73b99eb32747e74f0d5c5133d3dfdf Mon Sep 17 00:00:00 2001 From: SimonStnn Date: Fri, 1 Nov 2024 17:41:22 +0100 Subject: [PATCH 03/16] Add a toggle to toggle global stats in history graph --- src/popup/pages/Statistics.tsx | 117 ++++++++++++++++++--------------- 1 file changed, 64 insertions(+), 53 deletions(-) diff --git a/src/popup/pages/Statistics.tsx b/src/popup/pages/Statistics.tsx index 6752270..48f6306 100644 --- a/src/popup/pages/Statistics.tsx +++ b/src/popup/pages/Statistics.tsx @@ -1,5 +1,5 @@ import { format, subDays } from 'date-fns'; -import { Calendar as CalendarIcon } from 'lucide-react'; +import { Calendar as CalendarIcon, Globe } from 'lucide-react'; import React from 'react'; import { DateRange } from 'react-day-picker'; import Main from '@/components/Main'; @@ -19,6 +19,7 @@ import { SelectValue, } from '@/components/ui/select'; import { Skeleton } from '@/components/ui/skeleton'; +import { Toggle } from '@/components/ui/toggle'; import storage from '@/managers/storage'; import { cn } from '@/utils'; @@ -27,6 +28,7 @@ export default () => { from: subDays(new Date(), 7), to: new Date(), }); + const [global, setGlobal] = React.useState(true); const handleDatePresetChange = async (value: string) => { const minDate = new Date('2024-07-01'); @@ -67,61 +69,70 @@ export default () => { return (
- - - - - Pick a date + )} + + + + + + + + setGlobal(!global)} > - - - - + + + {date?.from && date?.to ? ( - + ) : ( )} From 9579fcfa2b436b8469ad64419b6b3e55662578b2 Mon Sep 17 00:00:00 2001 From: SimonStnn Date: Fri, 1 Nov 2024 17:46:21 +0100 Subject: [PATCH 04/16] Update data fetching dependencies to include global prop #326 --- src/popup/components/graph.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/popup/components/graph.tsx b/src/popup/components/graph.tsx index baf5170..c4be065 100644 --- a/src/popup/components/graph.tsx +++ b/src/popup/components/graph.tsx @@ -63,7 +63,7 @@ export default (props: { startDate: Date; endDate: Date; global: boolean }) => { }; fetchData(); - }, [props.startDate, props.endDate]); + }, [props.startDate, props.endDate, props.global]); return ( <> From 71d38d64564f86ba35fa2312d3b00d9a0d888356 Mon Sep 17 00:00:00 2001 From: benz Date: Fri, 1 Nov 2024 18:19:31 +0100 Subject: [PATCH 05/16] Set button size to icon close #239 --- src/popup/components/Leaderboard.tsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/popup/components/Leaderboard.tsx b/src/popup/components/Leaderboard.tsx index fe75d09..af579ec 100644 --- a/src/popup/components/Leaderboard.tsx +++ b/src/popup/components/Leaderboard.tsx @@ -1,7 +1,9 @@ -import React, { useState, useEffect } from 'react'; -import { Link } from 'react-router-dom'; import { type ClassValue } from 'clsx'; import { Medal, ChevronLeft, ChevronRight } from 'lucide-react'; +import React, { useState, useEffect } from 'react'; +import { Link } from 'react-router-dom'; +import { Button } from '@/components/ui/button'; +import { Skeleton } from '@/components/ui/skeleton'; import { Table, TableBody, @@ -11,17 +13,15 @@ import { TableHeader, TableRow, } from '@/components/ui/table'; -import { Skeleton } from '@/components/ui/skeleton'; -import remote from '@/remote'; -import { RemoteResponse } from '@/const'; -import { cn } from '@/utils'; -import { Button } from '@/components/ui/button'; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from '@/components/ui/tooltip'; +import { RemoteResponse } from '@/const'; +import remote from '@/remote'; +import { cn } from '@/utils'; const limit = 10; const maxPages = 10; @@ -88,7 +88,7 @@ export default () => { - - - - - )} - /> - )} + ); }; + +export default ConfigForm; From b200d1e407b8a9a768cff1bcdf2363df8dbe324b Mon Sep 17 00:00:00 2001 From: benz Date: Thu, 7 Nov 2024 19:26:48 +0100 Subject: [PATCH 12/16] the snooze button has been made --- src/background/background.ts | 33 ++----- src/const.ts | 3 +- src/popup/components/forms/LocalSettings.tsx | 95 +++++++++++--------- src/utils.ts | 13 ++- tests/__mocks__/webextension-polyfill.ts | 1 + 5 files changed, 70 insertions(+), 75 deletions(-) diff --git a/src/background/background.ts b/src/background/background.ts index 4a069a7..69c766a 100644 --- a/src/background/background.ts +++ b/src/background/background.ts @@ -9,6 +9,7 @@ import { random, getBrowser, isRunningInBackground, + isInSnooze, sendMessage, } from '@/utils'; @@ -33,28 +34,6 @@ const updateBadgeColors = () => { })(); }; -// Snooze state variable to track if the spawn is snoozed -let isSnoozed = false; -let snoozeTimer: NodeJS.Timeout | null = null; - -// Function to handle starting the snooze -const startSnooze = async (duration: number) => { - // Activate snooze - isSnoozed = true; - - // Clear existing timer if present - if (snoozeTimer) clearTimeout(snoozeTimer); - - // If snooze is not indefinite (-1), set up a timeout to end snooze - if (duration !== -1) { - snoozeTimer = setTimeout(() => { - isSnoozed = false; - snoozeTimer = null; - log.info('Snooze ended, resuming balloon spawns'); - }, duration); - } -}; - (() => { // Check if the background script is running in the background if (!isRunningInBackground()) return; @@ -78,6 +57,7 @@ const startSnooze = async (duration: number) => { log.getLevel(), ')' ); + log.debug(''); // Clear all alarms await browser.alarms.clearAll(); @@ -124,12 +104,6 @@ const startSnooze = async (duration: number) => { }; const spawnBalloon = async () => { - // Prevent spawn if snooze is active - if (isSnoozed) { - log.info('Balloon spawn snoozed'); - return; - } - log.groupCollapsed( 'debug', `(${new Date().toLocaleTimeString()}) Spawning Balloon...` @@ -157,6 +131,9 @@ const startSnooze = async (duration: number) => { } log.debug(' - Last spawn was not too recent'); + if (await isInSnooze()) return skipSpawnMessage('In snooze'); + log.debug(' - Not in snooze'); + // Check if the browser is idle const state = await browser.idle.queryState(5 * 60); if (state !== 'active') return skipSpawnMessage('Browser is idle'); diff --git a/src/const.ts b/src/const.ts index 218937c..d035931 100644 --- a/src/const.ts +++ b/src/const.ts @@ -110,6 +110,7 @@ export type SyncStorageStructure = { config: Config; token: string; user: User; + snooze: number | null; }; export type SyncStorageKey = keyof SyncStorageStructure; @@ -142,7 +143,7 @@ type SetLogLevelMessage = { }; type StartSnoozeMessage = { - action: 'startSnooze'; + action: 'setSnooze'; duration: number; }; diff --git a/src/popup/components/forms/LocalSettings.tsx b/src/popup/components/forms/LocalSettings.tsx index 6b451a1..d31a2dd 100644 --- a/src/popup/components/forms/LocalSettings.tsx +++ b/src/popup/components/forms/LocalSettings.tsx @@ -27,7 +27,7 @@ import { Slider } from '@/components/ui/slider'; import { initalConfig } from '@/const'; import log from '@/managers/log'; import storage from '@/managers/storage'; -import { askOriginPermissions } from '@/utils'; +import { askOriginPermissions, isInSnooze } from '@/utils'; const MIN_POP_VOLUME = 0; const VOLUME_STEP = 20; @@ -40,14 +40,15 @@ const formSchema = z.object({ popVolume: z.number().int().min(MIN_POP_VOLUME).max(MAX_POP_VOLUME), spawnRate: z.number().int().min(MIN_SPAWN_RATE).max(MAX_SPAWN_RATE), fullScreenVideoSpawn: z.boolean(), - snooze: z.number().int().min(0), + snooze: z.number().int().min(-1).nullable(), permissions: z.object({ origins: z.array(z.string()), permissions: z.array(z.string()), }), }); -const SNOOZE_OPTIONS = [ +const SNOOZE_OPTIONS: { label: string; value: number | null }[] = [ + { label: 'Off', value: null }, { label: '15 minutes', value: 15 * 60 * 1000 }, { label: '1 hour', value: 1 * 60 * 60 * 1000 }, { label: '3 hours', value: 3 * 60 * 60 * 1000 }, @@ -56,7 +57,7 @@ const SNOOZE_OPTIONS = [ { label: 'Until I turn it back on', value: -1 }, ]; -const ConfigForm = () => { +export default () => { const [popVolume, setPopVolume] = useState(initalConfig.popVolume); const [spawnRate, setSpawnRate] = useState(initalConfig.spawnRate); const [fullScreenVideoSpawn, setFullScreenVideoSpawn] = useState( @@ -65,8 +66,6 @@ const ConfigForm = () => { const [permissions, setPermissions] = useState( {} ); - const [isSnoozed, setIsSnoozed] = useState(false); - const [snoozeTimer, setSnoozeTimer] = useState(null); const form = useForm>({ resolver: zodResolver(formSchema), @@ -105,32 +104,20 @@ const ConfigForm = () => { setPermissions(await browser.permissions.getAll()); }; - const startSnooze = (duration: number) => { - setIsSnoozed(true); - setSpawnRate(0); - - if (duration === -1) { - return; - } - - const timer = setTimeout(() => { - setSpawnRate(initalConfig.spawnRate); - setIsSnoozed(false); - form.setValue('snooze', 0); - }, duration); - - setSnoozeTimer(timer); - }; - - const handleSnoozeChange = (selectedDuration: string) => { - const duration = Number(selectedDuration); + const handleSnoozeChange = async (selectedDuration: string) => { + const duration = + selectedDuration === 'null' ? null : Number(selectedDuration); form.setValue('snooze', duration); - startSnooze(duration); + + const snoozeEnd = + duration === null ? null : duration > 0 ? Date.now() + duration : -1; + await storage.sync.set('snooze', snoozeEnd); }; useEffect(() => { const loadConfig = async () => { const config = await storage.sync.get('config'); + setPopVolume(config.popVolume); setSpawnRate(config.spawnRate); setFullScreenVideoSpawn(config.fullScreenVideoSpawn); @@ -138,13 +125,7 @@ const ConfigForm = () => { }; loadConfig(); - - return () => { - if (snoozeTimer) { - clearTimeout(snoozeTimer); - } - }; - }, [snoozeTimer]); + }, []); return (
@@ -265,14 +246,14 @@ const ConfigForm = () => { control={form.control} name="fullScreenVideoSpawn" render={({ field: { onChange } }) => ( - + Full-Screen Video Spawn { - onFullScreenVideoSpawnChange(checked); - onChange(checked); + onCheckedChange={(val) => { + onFullScreenVideoSpawnChange(!!val); + onChange(!!val); }} /> @@ -280,12 +261,42 @@ const ConfigForm = () => { )} /> - + {/* If the user hasn't granted the host permissions; show the grant permission button */} + {!(permissions.origins?.length !== 0) && ( + ( + + + Host Permission + +

+ Host Permission{' '} + *recommended +

+

+ Pop-a-loon requires host permissions to function properly. +

+
+
+ + + + + + +
+ )} + /> + )} ); }; - -export default ConfigForm; diff --git a/src/utils.ts b/src/utils.ts index 4d2a370..6dbfbd2 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -159,7 +159,7 @@ export async function askOriginPermissions() { log.debug('Permissions granted for', permissions); } -export const isFullScreenVideoPlaying = () => { +export function isFullScreenVideoPlaying() { const fullscreenElement = document.fullscreenElement; if (fullscreenElement) { if (fullscreenElement.tagName.toLowerCase() === 'video') { @@ -174,9 +174,14 @@ export const isFullScreenVideoPlaying = () => { } } return false; -}; +} + +export async function isInSnooze(): Promise { + const snooze = await storage.sync.get('snooze'); + return snooze !== null && (snooze === -1 || Date.now() < snooze); +} -export const joinPaths = (...paths: string[]): string => { +export function joinPaths(...paths: string[]): string { return paths .map((part, index) => { if (index === 0) { @@ -187,4 +192,4 @@ export const joinPaths = (...paths: string[]): string => { }) .filter((part) => part.length) .join('/'); -}; +} diff --git a/tests/__mocks__/webextension-polyfill.ts b/tests/__mocks__/webextension-polyfill.ts index fe58c74..4b829ba 100644 --- a/tests/__mocks__/webextension-polyfill.ts +++ b/tests/__mocks__/webextension-polyfill.ts @@ -11,6 +11,7 @@ const defaultStorage: SyncStorageStructure = { updatedAt: '', createdAt: '', }, + snooze: null, }; let mockStorage: SyncStorageStructure = defaultStorage; From a215cb5266b7db7784170141e8c854f7022b8dc1 Mon Sep 17 00:00:00 2001 From: SimonStnn Date: Fri, 8 Nov 2024 23:41:06 +0100 Subject: [PATCH 13/16] Fix snooze functionallity in LocalSettings form #346 --- src/popup/components/forms/LocalSettings.tsx | 202 +++++++++++++------ 1 file changed, 138 insertions(+), 64 deletions(-) diff --git a/src/popup/components/forms/LocalSettings.tsx b/src/popup/components/forms/LocalSettings.tsx index d31a2dd..dc0ade8 100644 --- a/src/popup/components/forms/LocalSettings.tsx +++ b/src/popup/components/forms/LocalSettings.tsx @@ -21,13 +21,13 @@ import { SelectValue, SelectContent, SelectItem, - SelectLabel, } from '@/components/ui/select'; +import { Skeleton } from '@/components/ui/skeleton'; import { Slider } from '@/components/ui/slider'; import { initalConfig } from '@/const'; import log from '@/managers/log'; import storage from '@/managers/storage'; -import { askOriginPermissions, isInSnooze } from '@/utils'; +import { askOriginPermissions } from '@/utils'; const MIN_POP_VOLUME = 0; const VOLUME_STEP = 20; @@ -35,29 +35,29 @@ const MAX_POP_VOLUME = 100; const MIN_SPAWN_RATE = 0.1; const MAX_SPAWN_RATE = 1; const SPAWN_RATE_STEP = 0.1; +const SNOOZE_OPTIONS: { label: string; value: number | null }[] = [ + { label: 'Off', value: null }, + { label: '15 minutes', value: 15 * 60 * 1000 }, + { label: '1 hour', value: 1 * 60 * 60 * 1000 }, + { label: '3 hours', value: 3 * 60 * 60 * 1000 }, + { label: '8 hours', value: 8 * 60 * 60 * 1000 }, + { label: '24 hours', value: 24 * 60 * 60 * 1000 }, + { label: 'Until I turn it back on', value: -1 }, +]; const formSchema = z.object({ popVolume: z.number().int().min(MIN_POP_VOLUME).max(MAX_POP_VOLUME), spawnRate: z.number().int().min(MIN_SPAWN_RATE).max(MAX_SPAWN_RATE), fullScreenVideoSpawn: z.boolean(), - snooze: z.number().int().min(-1).nullable(), + snooze: z.number().int().min(-1).nullable().optional(), permissions: z.object({ origins: z.array(z.string()), permissions: z.array(z.string()), }), }); -const SNOOZE_OPTIONS: { label: string; value: number | null }[] = [ - { label: 'Off', value: null }, - { label: '15 minutes', value: 15 * 60 * 1000 }, - { label: '1 hour', value: 1 * 60 * 60 * 1000 }, - { label: '3 hours', value: 3 * 60 * 60 * 1000 }, - { label: '8 hours', value: 8 * 60 * 60 * 1000 }, - { label: '24 hours', value: 24 * 60 * 60 * 1000 }, - { label: 'Until I turn it back on', value: -1 }, -]; - export default () => { + const [isConfigLoaded, setIsConfigLoaded] = useState(false); const [popVolume, setPopVolume] = useState(initalConfig.popVolume); const [spawnRate, setSpawnRate] = useState(initalConfig.spawnRate); const [fullScreenVideoSpawn, setFullScreenVideoSpawn] = useState( @@ -66,6 +66,7 @@ export default () => { const [permissions, setPermissions] = useState( {} ); + const [snooze, setSnooze] = useState(null); const form = useForm>({ resolver: zodResolver(formSchema), @@ -104,14 +105,45 @@ export default () => { setPermissions(await browser.permissions.getAll()); }; + const updateSnooze = async ( + snoozeEnd: number | null, + saveToStorage: boolean = true + ) => { + setSnooze(snoozeEnd); + if (saveToStorage) await storage.sync.set('snooze', snoozeEnd); + console.debug('Snooze changed to', snoozeEnd); + + const snoozeOption = SNOOZE_OPTIONS.find( + // Can only detect off or until I turn it back on + (option) => option.value === snoozeEnd + ); + console.debug('Snooze option is', snoozeOption); + form.setValue('snooze', snoozeOption?.value); + }; + const handleSnoozeChange = async (selectedDuration: string) => { const duration = selectedDuration === 'null' ? null : Number(selectedDuration); - form.setValue('snooze', duration); - const snoozeEnd = duration === null ? null : duration > 0 ? Date.now() + duration : -1; - await storage.sync.set('snooze', snoozeEnd); + await updateSnooze(snoozeEnd); + }; + + const renderSnoozeStatus = () => { + if (snooze !== null && snooze > 0) { + return ( + <> + Snoozed until{' '} + {new Date(snooze).toLocaleTimeString('en-US', { + hour: 'numeric', + minute: 'numeric', + })} + + ); + } else if (snooze === -1) { + return <>Snoozed until you turn it back off; + } + return <>Snooze is off; }; useEffect(() => { @@ -122,6 +154,8 @@ export default () => { setSpawnRate(config.spawnRate); setFullScreenVideoSpawn(config.fullScreenVideoSpawn); setPermissions(await browser.permissions.getAll()); + await updateSnooze(await storage.sync.get('snooze'), false); + setIsConfigLoaded(true); // Set loading status to true after config is loaded }; loadConfig(); @@ -130,47 +164,69 @@ export default () => { return (
- ( - - - Snooze Balloon Spawn - -

- Snooze Baloon Spawn -

-

- Set how long to pause the balloon appearances. During this - snooze period, no new balloons will spawn on your screen. -

-
-
- - - - -
- )} - /> + {!isConfigLoaded ? ( + + ) : ( + ( + + + Snooze Balloon Spawn + +

+ Snooze Baloon Spawn +

+

+ Set how long to pause the balloon appearances. During this + snooze period, no new balloons will spawn on your screen. +

+

+ {renderSnoozeStatus()} +

+
+
+ + + + +
+ )} + /> + )} { Full-Screen Video Spawn - { - onFullScreenVideoSpawnChange(!!val); - onChange(!!val); - }} - /> + + { + onFullScreenVideoSpawnChange(!!val); + onChange(!!val); + }} + /> + +

+ Fullscreen video spawn +

+

+ Weither or not to spawn balloons in fullscreen video + players, like youtube. +

+

+ {fullScreenVideoSpawn ? ( + <>Balloons can spawn! + ) : ( + <>Balloons will not spawn. + )} +

+
+
From 1fb073c4c56999c0ac8db19b65ca2dcb9fc09e49 Mon Sep 17 00:00:00 2001 From: SimonStnn Date: Sat, 9 Nov 2024 00:01:52 +0100 Subject: [PATCH 14/16] Return unwated deleted code --- src/popup/components/forms/LocalSettings.tsx | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/popup/components/forms/LocalSettings.tsx b/src/popup/components/forms/LocalSettings.tsx index dc0ade8..9daeeef 100644 --- a/src/popup/components/forms/LocalSettings.tsx +++ b/src/popup/components/forms/LocalSettings.tsx @@ -78,8 +78,12 @@ export default () => { const config = await storage.sync.get('config'); await storage.sync.set('config', { ...config, popVolume }); setPopVolume(popVolume); - log.debug('Pop volume changed to', popVolume); + log.debug( + 'Pop volume changed to', + (await storage.sync.get('config')).popVolume + ); + // Play the pop sound popSound.volume = popVolume / 100; popSound.play(); }; @@ -88,7 +92,10 @@ export default () => { const config = await storage.sync.get('config'); await storage.sync.set('config', { ...config, spawnRate }); setSpawnRate(spawnRate); - log.debug('Spawn rate changed to', spawnRate); + log.debug( + 'Spawn rate changed to', + (await storage.sync.get('config')).spawnRate + ); }; const onFullScreenVideoSpawnChange = async ( @@ -97,7 +104,10 @@ export default () => { const config = await storage.sync.get('config'); await storage.sync.set('config', { ...config, fullScreenVideoSpawn }); setFullScreenVideoSpawn(fullScreenVideoSpawn); - log.debug('Spawning in full screen video players:', fullScreenVideoSpawn); + log.debug( + 'Spawning in full screen video players:', + (await storage.sync.get('config')).fullScreenVideoSpawn + ); }; const onGrantOriginPermissionClick = async () => { From 822cb39c1b9ee2a4c02c4d3ef7a7bfba700bf541 Mon Sep 17 00:00:00 2001 From: SimonStnn Date: Sat, 9 Nov 2024 00:02:02 +0100 Subject: [PATCH 15/16] Remove unused message type --- src/const.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/const.ts b/src/const.ts index d035931..28397d3 100644 --- a/src/const.ts +++ b/src/const.ts @@ -142,17 +142,11 @@ type SetLogLevelMessage = { level: LogLevelNumbers; }; -type StartSnoozeMessage = { - action: 'setSnooze'; - duration: number; -}; - export type Message = | UpdateCounterMessage | IncrementCount | SpawnBalloonMessage - | SetLogLevelMessage - | StartSnoozeMessage; + | SetLogLevelMessage; // // * Alarms From 619c9e8c612c1f25717d2161da536bad3916cf5c Mon Sep 17 00:00:00 2001 From: SimonStnn Date: Sat, 9 Nov 2024 13:37:00 +0100 Subject: [PATCH 16/16] Bump package version to 1.18.0 --- package-lock.json | 118 +--------------------------------------------- package.json | 3 +- 2 files changed, 3 insertions(+), 118 deletions(-) diff --git a/package-lock.json b/package-lock.json index fe35b86..067de18 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "pop-a-loon", - "version": "1.17.1", + "version": "1.18.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "pop-a-loon", - "version": "1.17.1", + "version": "1.18.0", "license": "Apache-2.0", "dependencies": { "@hookform/resolvers": "^3.3.4", @@ -21,7 +21,6 @@ "@radix-ui/react-separator": "^1.0.3", "@radix-ui/react-slider": "^1.1.2", "@radix-ui/react-slot": "^1.0.2", - "@radix-ui/react-toggle": "^1.1.0", "@radix-ui/react-tooltip": "^1.0.7", "class-variance-authority": "^0.7.0", "clsx": "^2.1.0", @@ -3069,119 +3068,6 @@ } } }, - "node_modules/@radix-ui/react-toggle": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-1.1.0.tgz", - "integrity": "sha512-gwoxaKZ0oJ4vIgzsfESBuSgJNdc0rv12VhHgcqN0TEJmmZixXG/2XpsLK8kzNWYcnaoRIEEQc0bEi3dIvdUpjw==", - "dependencies": { - "@radix-ui/primitive": "1.1.0", - "@radix-ui/react-primitive": "2.0.0", - "@radix-ui/react-use-controllable-state": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-toggle/node_modules/@radix-ui/primitive": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.0.tgz", - "integrity": "sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==" - }, - "node_modules/@radix-ui/react-toggle/node_modules/@radix-ui/react-compose-refs": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz", - "integrity": "sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-toggle/node_modules/@radix-ui/react-primitive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.0.tgz", - "integrity": "sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==", - "dependencies": { - "@radix-ui/react-slot": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-toggle/node_modules/@radix-ui/react-slot": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz", - "integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-toggle/node_modules/@radix-ui/react-use-callback-ref": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz", - "integrity": "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-toggle/node_modules/@radix-ui/react-use-controllable-state": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.1.0.tgz", - "integrity": "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==", - "dependencies": { - "@radix-ui/react-use-callback-ref": "1.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, "node_modules/@radix-ui/react-tooltip": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.0.7.tgz", diff --git a/package.json b/package.json index b0ac89e..9573ef1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pop-a-loon", - "version": "1.17.1", + "version": "1.18.0", "description": "The new rising trend (literally) that changes the browser game completely.", "private": true, "scripts": { @@ -45,7 +45,6 @@ "@radix-ui/react-separator": "^1.0.3", "@radix-ui/react-slider": "^1.1.2", "@radix-ui/react-slot": "^1.0.2", - "@radix-ui/react-toggle": "^1.1.0", "@radix-ui/react-tooltip": "^1.0.7", "class-variance-authority": "^0.7.0", "clsx": "^2.1.0",