Skip to content

Commit 3bc7033

Browse files
authored
feat: implement confirmation before download (#88)
1 parent c6ef903 commit 3bc7033

File tree

12 files changed

+211
-66
lines changed

12 files changed

+211
-66
lines changed

background/index.ts

Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ import path from "path"
66
import { getPort } from "@plasmohq/messaging/background"
77
import { Storage } from "@plasmohq/storage"
88

9-
import {
10-
requestServerSelection
11-
} from "~background/messages/api/select-server"
9+
import { requestServerSelection } from "~background/messages/api/select-server"
1210
import { skip as pressToSkip } from "~background/messages/api/skip"
1311
import { STORAGE_SETTINGS } from "~constants"
1412
import { getFullUrl } from "~options/components/RemoteSettings"
1513
import { defaultSettings, type Settings } from "~options/types"
14+
import type { Server } from "~types"
15+
import { getMergedSettings } from "~util/settings"
1616

1717
export { }
1818

@@ -78,8 +78,8 @@ const storage = new Storage()
7878
let settingsCache = defaultSettings
7979
let isRunningCache = false
8080
async function refreshSettings(): Promise<Settings> {
81-
const settings =
82-
(await storage.get<Settings>(STORAGE_SETTINGS)) || defaultSettings
81+
const storedSettings = await storage.get<Settings>(STORAGE_SETTINGS)
82+
const settings = getMergedSettings(storedSettings)
8383
settingsCache = settings
8484
return settings
8585
}
@@ -292,7 +292,10 @@ function handleRemoteDownload(
292292
settings: Settings
293293
): Function | undefined {
294294
// If only one server, no servers, or manual selection is disabled, use existing logic
295-
if (settings.remote.servers.length <= 1 || !settings.remote.requireManualSelection) {
295+
if (
296+
settings.remote.servers.length <= 1 ||
297+
!settings.remote.requireManualSelection
298+
) {
296299
const server = settings.remote.servers.find(
297300
(server) => getFullUrl(server) === settings.remote.selectedServer
298301
)
@@ -306,7 +309,10 @@ function handleRemoteDownload(
306309
return async () => {
307310
try {
308311
// Show server selector overlay
309-
const tabs = await chrome.tabs.query({ active: true, currentWindow: true })
312+
const tabs = await chrome.tabs.query({
313+
active: true,
314+
currentWindow: true
315+
})
310316
if (tabs.length === 0) {
311317
// Fallback to default server if no active tab
312318
const defaultServer = settings.remote.servers.find(
@@ -355,8 +361,12 @@ function handleRemoteDownload(
355361

356362
if (selectedServer) {
357363
// Execute download task and get result
358-
const downloadSuccess = await executeDownloadTask(info, selectedServer, settings)
359-
364+
const downloadSuccess = await executeDownloadTask(
365+
info,
366+
selectedServer,
367+
settings
368+
)
369+
360370
// Send result back to content script to handle popup closure
361371
await chrome.tabs.sendMessage(tabId, {
362372
name: "download-result",
@@ -392,7 +402,7 @@ async function executeDownloadTask(
392402
let notificationTitle: string
393403
let notificationMessage: string
394404
let success = false
395-
405+
396406
try {
397407
await client.createTask({
398408
req: await toCreateRequest(info)
@@ -411,16 +421,17 @@ async function executeDownloadTask(
411421
)
412422
success = false
413423
}
414-
415-
if (settings.remote.notification) {
424+
425+
// Show notification based on confirmBeforeDownload setting
426+
if (settings.confirmBeforeDownload || !success) {
416427
const port = getPort("notify")
417428
port.postMessage({
418429
type: notificationType,
419430
title: notificationTitle,
420431
message: notificationMessage
421432
})
422433
}
423-
434+
424435
return success
425436
}
426437

@@ -456,7 +467,9 @@ function createDownloadTask(
456467
)
457468
success = false
458469
}
459-
if (settings.remote.notification) {
470+
471+
// Show notification based on confirmBeforeDownload setting or if there's an error
472+
if (settings.confirmBeforeDownload || !success) {
460473
const port = getPort("notify")
461474
port.postMessage({
462475
type: notificationType,
@@ -470,6 +483,7 @@ function createDownloadTask(
470483

471484
interface HostRequest<T> {
472485
method: string
486+
meta?: Record<string, any>
473487
params?: T
474488
}
475489

@@ -496,14 +510,34 @@ function handleNativeDownload(
496510
try {
497511
await connectNativeAndPost<string>({
498512
method: "create",
513+
meta: {
514+
silent: !settings.confirmBeforeDownload
515+
},
499516
params: btoa(
500517
JSON.stringify({
501518
req
502519
})
503520
)
504521
})
522+
523+
if (!settings.confirmBeforeDownload) {
524+
const port = getPort("notify")
525+
port.postMessage({
526+
type: "success",
527+
title: chrome.i18n.getMessage("notification_create_success"),
528+
message: chrome.i18n.getMessage("notification_native_success_message")
529+
})
530+
}
505531
} catch (e) {
506532
console.error(e)
533+
if (!settings.confirmBeforeDownload) {
534+
const port = getPort("notify")
535+
port.postMessage({
536+
type: "error",
537+
title: chrome.i18n.getMessage("notification_create_error"),
538+
message: chrome.i18n.getMessage("notification_native_error_message")
539+
})
540+
}
507541
}
508542
}
509543
}

components/theme.tsx

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,11 @@ import { createTheme, CssBaseline, ThemeProvider } from "@mui/material"
22
import type { PropsWithChildren } from "react"
33
import { useMemo } from "react"
44

5-
import { useStorage } from "@plasmohq/storage/hook"
6-
7-
import { STORAGE_SETTINGS } from "~constants"
8-
import { defaultSettings, type Settings } from "~options/types"
5+
import { useSettings } from "~hooks/useSettings"
96

107
const Theme = ({ children }: PropsWithChildren) => {
11-
const [settings] = useStorage<Settings>(STORAGE_SETTINGS, defaultSettings)
12-
8+
const [settings] = useSettings()
9+
1310
const theme = useMemo(() => {
1411
const prefersDarkMode =
1512
settings.theme === "system"

hooks/useSettings.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { useStorage } from "@plasmohq/storage/hook"
2+
3+
import { STORAGE_SETTINGS } from "~constants"
4+
import { defaultSettings, type Settings } from "~options/types"
5+
import { getMergedSettings } from "~util/settings"
6+
7+
/**
8+
* Custom hook for managing settings with automatic merging of default values
9+
* @returns [mergedSettings, setStoredSettings] tuple
10+
*/
11+
export function useSettings() {
12+
const [storedSettings, setStoredSettings] = useStorage<Settings>(
13+
STORAGE_SETTINGS,
14+
defaultSettings
15+
)
16+
17+
// Use merged settings to ensure new fields have default values
18+
const settings = getMergedSettings(storedSettings)
19+
20+
return [settings, setStoredSettings] as const
21+
}

locales/en/messages.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,18 @@
164164
"ctrl_disable_capture_desc": {
165165
"message": "Hold %key% key to temporarily disable download capture"
166166
},
167+
"confirm_before_download": {
168+
"message": "Confirm Before Download"
169+
},
170+
"confirm_before_download_desc": {
171+
"message": "Show confirmation dialog before starting download"
172+
},
173+
"notification_native_success_message": {
174+
"message": "Task successfully added to downloader"
175+
},
176+
"notification_native_error_message": {
177+
"message": "Task creation failed, please check if downloader is working properly"
178+
},
167179
"select_server": {
168180
"message": "Select Server"
169181
},

locales/zh/messages.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,12 @@
152152
"notification_create_error_message": {
153153
"message": "任务添加失败,请检查下载服务器是否正常"
154154
},
155+
"notification_native_success_message": {
156+
"message": "任务已成功添加到下载器"
157+
},
158+
"notification_native_error_message": {
159+
"message": "任务添加失败,请检查下载器是否正常"
160+
},
155161
"no_servers_tip": {
156162
"message": "暂无服务器,点击上方按钮添加"
157163
},
@@ -164,6 +170,12 @@
164170
"ctrl_disable_capture_desc": {
165171
"message": "按住 %key% 键时临时禁用下载捕获"
166172
},
173+
"confirm_before_download": {
174+
"message": "下载前确认"
175+
},
176+
"confirm_before_download_desc": {
177+
"message": "在开始下载前显示确认对话框"
178+
},
167179
"select_server": {
168180
"message": "选择服务器"
169181
},

options/components/BasicSettings.tsx

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,19 @@ import {
1010
Typography
1111
} from "@mui/material"
1212

13-
import { useStorage } from "@plasmohq/storage/hook"
1413

15-
import { STORAGE_SETTINGS } from "~constants"
14+
import { useSettings } from "~hooks/useSettings"
1615
import { getContrlKey } from "~util"
1716

18-
import { defaultSettings, type Settings } from "../types"
1917
import SavedTip, { useTip } from "./SavedTip"
2018

2119
const BasicSettings = () => {
22-
const [settings, setSettings] = useStorage<Settings>(
23-
STORAGE_SETTINGS,
24-
defaultSettings
25-
)
20+
const [settings, setStoredSettings] = useSettings()
21+
2622
const { showTip, message, setMessage } = useTip()
2723

2824
const handleChange = (field: string, value: any) => {
29-
setSettings((prev) => ({ ...prev, [field]: value }))
25+
setStoredSettings((prev) => ({ ...prev, [field]: value }))
3026
showTip()
3127
}
3228

@@ -66,7 +62,20 @@ const BasicSettings = () => {
6662
onChange={(e) => handleChange("enabled", e.target.checked)}
6763
/>
6864
</Box>
69-
65+
66+
<Box sx={{ display: "flex", alignItems: "flex-start", px: 1 }}>
67+
{renderLabel(
68+
chrome.i18n.getMessage("confirm_before_download"),
69+
chrome.i18n.getMessage("confirm_before_download_desc")
70+
)}
71+
<Switch
72+
checked={settings.confirmBeforeDownload}
73+
onChange={(e) =>
74+
handleChange("confirmBeforeDownload", e.target.checked)
75+
}
76+
/>
77+
</Box>
78+
7079
<Box sx={{ display: "flex", alignItems: "flex-start", px: 1 }}>
7180
{renderLabel(
7281
chrome.i18n.getMessage("auto_wakeup"),

options/components/RemoteSettings.tsx

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,11 @@ import {
2727
import { useState } from "react"
2828

2929
import { sendToBackground } from "@plasmohq/messaging"
30-
import { useStorage } from "@plasmohq/storage/hook"
3130

3231
import type { CheckResult } from "~background/messages/api/check"
33-
import { STORAGE_SETTINGS } from "~constants"
32+
import { useSettings } from "~hooks/useSettings"
33+
import type { Server } from "~types"
3434

35-
import { defaultSettings, type Settings } from "../types"
3635
import SavedTip, { useTip } from "./SavedTip"
3736

3837
interface ServerFormData extends Server {
@@ -44,10 +43,8 @@ export const getFullUrl = (server: Server) =>
4443
`${server.protocol}://${server.url}`
4544

4645
export default function RemoteSettings() {
47-
const [settings, setSettings] = useStorage<Settings>(
48-
STORAGE_SETTINGS,
49-
defaultSettings
50-
)
46+
const [settings, setStoredSettings] = useSettings()
47+
5148
const { showTip, message, setMessage } = useTip()
5249
const [open, setOpen] = useState(false)
5350
const [editingServerUrl, setEditingServerUrl] = useState<string | null>(null)
@@ -63,15 +60,15 @@ export default function RemoteSettings() {
6360
showTip("no_server_error", "error")
6461
return
6562
}
66-
setSettings({
63+
setStoredSettings({
6764
...settings,
6865
remote: { ...settings.remote, enabled: checked }
6966
})
7067
showTip()
7168
}
7269

7370
const handleServerSelect = (fullUrl: string) => {
74-
setSettings({
71+
setStoredSettings({
7572
...settings,
7673
remote: { ...settings.remote, selectedServer: fullUrl }
7774
})
@@ -107,7 +104,7 @@ export default function RemoteSettings() {
107104

108105
// When deleting the last server, clear selection and disable remote download
109106
const isLastServer = newServers.length === 0
110-
setSettings({
107+
setStoredSettings({
111108
...settings,
112109
remote: {
113110
...settings.remote,
@@ -154,7 +151,7 @@ export default function RemoteSettings() {
154151

155152
// When adding the first server, automatically select it but don't enable remote download
156153
const isFirstServer = settings.remote.servers.length === 0
157-
setSettings({
154+
setStoredSettings({
158155
...settings,
159156
remote: {
160157
...settings.remote,
@@ -232,7 +229,7 @@ export default function RemoteSettings() {
232229
<Switch
233230
checked={settings.remote.notification}
234231
onChange={(e) => {
235-
setSettings({
232+
setStoredSettings({
236233
...settings,
237234
remote: { ...settings.remote, notification: e.target.checked }
238235
})
@@ -250,7 +247,7 @@ export default function RemoteSettings() {
250247
<Switch
251248
checked={settings.remote.requireManualSelection}
252249
onChange={(e) => {
253-
setSettings({
250+
setStoredSettings({
254251
...settings,
255252
remote: { ...settings.remote, requireManualSelection: e.target.checked }
256253
})

0 commit comments

Comments
 (0)