add volume setting

This commit is contained in:
Justin Quan
2024-12-15 23:22:44 -08:00
parent 09934e20f7
commit 1adc36a292
8 changed files with 78 additions and 17 deletions

6
package-lock.json generated
View File

@@ -38,6 +38,7 @@
"puppeteer-chromium-resolver": "^23.0.0", "puppeteer-chromium-resolver": "^23.0.0",
"puppeteer-core": "^23.4.0", "puppeteer-core": "^23.4.0",
"serialize-error": "^11.0.3", "serialize-error": "^11.0.3",
"sound-play": "^1.1.0",
"strip-ansi": "^7.1.0", "strip-ansi": "^7.1.0",
"tree-sitter-wasms": "^0.1.11", "tree-sitter-wasms": "^0.1.11",
"turndown": "^7.2.0", "turndown": "^7.2.0",
@@ -14001,6 +14002,11 @@
"node": ">= 14" "node": ">= 14"
} }
}, },
"node_modules/sound-play": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/sound-play/-/sound-play-1.1.0.tgz",
"integrity": "sha512-Bd/L0AoCwITFeOnpNLMsfPXrV5GG5NhrC/T6odveahYbhPZkdTnrFXRia9FCC5WBWdUTw1d+yvLBvi4wnD1xOA=="
},
"node_modules/source-map": { "node_modules/source-map": {
"version": "0.6.1", "version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",

View File

@@ -220,6 +220,7 @@
"puppeteer-chromium-resolver": "^23.0.0", "puppeteer-chromium-resolver": "^23.0.0",
"puppeteer-core": "^23.4.0", "puppeteer-core": "^23.4.0",
"serialize-error": "^11.0.3", "serialize-error": "^11.0.3",
"sound-play": "^1.1.0",
"strip-ansi": "^7.1.0", "strip-ansi": "^7.1.0",
"tree-sitter-wasms": "^0.1.11", "tree-sitter-wasms": "^0.1.11",
"turndown": "^7.2.0", "turndown": "^7.2.0",

View File

@@ -22,7 +22,7 @@ import { Cline } from "../Cline"
import { openMention } from "../mentions" import { openMention } from "../mentions"
import { getNonce } from "./getNonce" import { getNonce } from "./getNonce"
import { getUri } from "./getUri" import { getUri } from "./getUri"
import { playSound, setSoundEnabled } from "../../utils/sound" import { playSound, setSoundEnabled, setSoundVolume } from "../../utils/sound"
/* /*
https://github.com/microsoft/vscode-webview-ui-toolkit-samples/blob/main/default/weather-webview/src/providers/WeatherViewProvider.ts https://github.com/microsoft/vscode-webview-ui-toolkit-samples/blob/main/default/weather-webview/src/providers/WeatherViewProvider.ts
@@ -66,6 +66,7 @@ type GlobalStateKey =
| "openRouterUseMiddleOutTransform" | "openRouterUseMiddleOutTransform"
| "allowedCommands" | "allowedCommands"
| "soundEnabled" | "soundEnabled"
| "soundVolume"
| "diffEnabled" | "diffEnabled"
| "alwaysAllowMcp" | "alwaysAllowMcp"
@@ -597,6 +598,12 @@ export class ClineProvider implements vscode.WebviewViewProvider {
setSoundEnabled(soundEnabled) // Add this line to update the sound utility setSoundEnabled(soundEnabled) // Add this line to update the sound utility
await this.postStateToWebview() await this.postStateToWebview()
break break
case "soundVolume":
const soundVolume = message.value ?? 0.5
await this.updateGlobalState("soundVolume", soundVolume)
setSoundVolume(soundVolume)
await this.postStateToWebview()
break
case "diffEnabled": case "diffEnabled":
const diffEnabled = message.bool ?? true const diffEnabled = message.bool ?? true
await this.updateGlobalState("diffEnabled", diffEnabled) await this.updateGlobalState("diffEnabled", diffEnabled)
@@ -929,6 +936,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
soundEnabled, soundEnabled,
diffEnabled, diffEnabled,
taskHistory, taskHistory,
soundVolume,
} = await this.getState() } = await this.getState()
const allowedCommands = vscode.workspace const allowedCommands = vscode.workspace
@@ -953,6 +961,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
diffEnabled: diffEnabled ?? false, diffEnabled: diffEnabled ?? false,
shouldShowAnnouncement: lastShownAnnouncementId !== this.latestAnnouncementId, shouldShowAnnouncement: lastShownAnnouncementId !== this.latestAnnouncementId,
allowedCommands, allowedCommands,
soundVolume: soundVolume ?? 0.5,
} }
} }
@@ -1045,6 +1054,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
allowedCommands, allowedCommands,
soundEnabled, soundEnabled,
diffEnabled, diffEnabled,
soundVolume,
] = await Promise.all([ ] = await Promise.all([
this.getGlobalState("apiProvider") as Promise<ApiProvider | undefined>, this.getGlobalState("apiProvider") as Promise<ApiProvider | undefined>,
this.getGlobalState("apiModelId") as Promise<string | undefined>, this.getGlobalState("apiModelId") as Promise<string | undefined>,
@@ -1082,6 +1092,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
this.getGlobalState("allowedCommands") as Promise<string[] | undefined>, this.getGlobalState("allowedCommands") as Promise<string[] | undefined>,
this.getGlobalState("soundEnabled") as Promise<boolean | undefined>, this.getGlobalState("soundEnabled") as Promise<boolean | undefined>,
this.getGlobalState("diffEnabled") as Promise<boolean | undefined>, this.getGlobalState("diffEnabled") as Promise<boolean | undefined>,
this.getGlobalState("soundVolume") as Promise<number | undefined>,
]) ])
let apiProvider: ApiProvider let apiProvider: ApiProvider
@@ -1137,6 +1148,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
allowedCommands, allowedCommands,
soundEnabled, soundEnabled,
diffEnabled, diffEnabled,
soundVolume,
} }
} }

View File

@@ -51,6 +51,7 @@ export interface ExtensionState {
uriScheme?: string uriScheme?: string
allowedCommands?: string[] allowedCommands?: string[]
soundEnabled?: boolean soundEnabled?: boolean
soundVolume?: number
diffEnabled?: boolean diffEnabled?: boolean
} }

View File

@@ -32,6 +32,7 @@ export interface WebviewMessage {
| "alwaysAllowMcp" | "alwaysAllowMcp"
| "playSound" | "playSound"
| "soundEnabled" | "soundEnabled"
| "soundVolume"
| "diffEnabled" | "diffEnabled"
| "openMcpSettings" | "openMcpSettings"
| "restartMcpServer" | "restartMcpServer"
@@ -43,6 +44,7 @@ export interface WebviewMessage {
apiConfiguration?: ApiConfiguration apiConfiguration?: ApiConfiguration
images?: string[] images?: string[]
bool?: boolean bool?: boolean
value?: number
commands?: string[] commands?: string[]
audioType?: AudioType audioType?: AudioType
// For toggleToolAutoApprove // For toggleToolAutoApprove

View File

@@ -21,6 +21,7 @@ export const isWAV = (filepath: string): boolean => {
} }
let isSoundEnabled = false let isSoundEnabled = false
let volume = .5
/** /**
* Set sound configuration * Set sound configuration
@@ -30,6 +31,14 @@ export const setSoundEnabled = (enabled: boolean): void => {
isSoundEnabled = enabled isSoundEnabled = enabled
} }
/**
* Set sound volume
* @param volume number
*/
export const setSoundVolume = (newVolume: number): void => {
volume = newVolume
}
/** /**
* Play a sound file * Play a sound file
* @param filepath string * @param filepath string
@@ -54,11 +63,9 @@ export const playSound = (filepath: string): void => {
return // Skip playback within minimum interval to prevent continuous playback return // Skip playback within minimum interval to prevent continuous playback
} }
const player = require("play-sound")() const sound = require("sound-play")
player.play(filepath, function (err: any) { sound.play(filepath, volume).catch(() => {
if (err) {
throw new Error("Failed to play sound effect") throw new Error("Failed to play sound effect")
}
}) })
lastPlayedTime = currentTime lastPlayedTime = currentTime

View File

@@ -29,6 +29,8 @@ const SettingsView = ({ onDone }: SettingsViewProps) => {
setAlwaysAllowMcp, setAlwaysAllowMcp,
soundEnabled, soundEnabled,
setSoundEnabled, setSoundEnabled,
soundVolume,
setSoundVolume,
diffEnabled, diffEnabled,
setDiffEnabled, setDiffEnabled,
openRouterModels, openRouterModels,
@@ -55,6 +57,7 @@ const SettingsView = ({ onDone }: SettingsViewProps) => {
vscode.postMessage({ type: "alwaysAllowMcp", bool: alwaysAllowMcp }) vscode.postMessage({ type: "alwaysAllowMcp", bool: alwaysAllowMcp })
vscode.postMessage({ type: "allowedCommands", commands: allowedCommands ?? [] }) vscode.postMessage({ type: "allowedCommands", commands: allowedCommands ?? [] })
vscode.postMessage({ type: "soundEnabled", bool: soundEnabled }) vscode.postMessage({ type: "soundEnabled", bool: soundEnabled })
vscode.postMessage({ type: "soundVolume", value: soundVolume })
vscode.postMessage({ type: "diffEnabled", bool: diffEnabled }) vscode.postMessage({ type: "diffEnabled", bool: diffEnabled })
onDone() onDone()
} }
@@ -306,6 +309,7 @@ const SettingsView = ({ onDone }: SettingsViewProps) => {
<h4 style={{ fontWeight: 500, marginBottom: 10 }}>Experimental Features</h4> <h4 style={{ fontWeight: 500, marginBottom: 10 }}>Experimental Features</h4>
<div style={{ marginBottom: 5 }}> <div style={{ marginBottom: 5 }}>
<div style={{ marginBottom: 10 }}>
<VSCodeCheckbox checked={soundEnabled} onChange={(e: any) => setSoundEnabled(e.target.checked)}> <VSCodeCheckbox checked={soundEnabled} onChange={(e: any) => setSoundEnabled(e.target.checked)}>
<span style={{ fontWeight: "500" }}>Enable sound effects</span> <span style={{ fontWeight: "500" }}>Enable sound effects</span>
</VSCodeCheckbox> </VSCodeCheckbox>
@@ -318,6 +322,30 @@ const SettingsView = ({ onDone }: SettingsViewProps) => {
When enabled, Cline will play sound effects for notifications and events. When enabled, Cline will play sound effects for notifications and events.
</p> </p>
</div> </div>
{soundEnabled && (
<div style={{ marginLeft: 0 }}>
<div style={{ display: 'flex', alignItems: 'center', gap: '5px' }}>
<span style={{ fontWeight: "500", minWidth: '50px' }}>Volume</span>
<input
type="range"
min="0"
max="1"
step="0.01"
value={soundVolume ?? 0.5}
onChange={(e) => setSoundVolume(parseFloat(e.target.value))}
style={{
flexGrow: 1,
accentColor: 'var(--vscode-button-background)',
height: '2px'
}}
/>
<span style={{ minWidth: '35px', textAlign: 'left' }}>
{Math.round((soundVolume ?? 0.5) * 100)}%
</span>
</div>
</div>
)}
</div>
</div> </div>
{IS_DEV && ( {IS_DEV && (

View File

@@ -29,6 +29,7 @@ export interface ExtensionStateContextType extends ExtensionState {
setShowAnnouncement: (value: boolean) => void setShowAnnouncement: (value: boolean) => void
setAllowedCommands: (value: string[]) => void setAllowedCommands: (value: string[]) => void
setSoundEnabled: (value: boolean) => void setSoundEnabled: (value: boolean) => void
setSoundVolume: (value: number) => void
setDiffEnabled: (value: boolean) => void setDiffEnabled: (value: boolean) => void
} }
@@ -42,6 +43,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
shouldShowAnnouncement: false, shouldShowAnnouncement: false,
allowedCommands: [], allowedCommands: [],
soundEnabled: false, soundEnabled: false,
soundVolume: 0.5,
diffEnabled: false, diffEnabled: false,
}) })
const [didHydrateState, setDidHydrateState] = useState(false) const [didHydrateState, setDidHydrateState] = useState(false)
@@ -129,6 +131,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
openRouterModels, openRouterModels,
mcpServers, mcpServers,
filePaths, filePaths,
soundVolume: state.soundVolume,
setApiConfiguration: (value) => setState((prevState) => ({ ...prevState, apiConfiguration: value })), setApiConfiguration: (value) => setState((prevState) => ({ ...prevState, apiConfiguration: value })),
setCustomInstructions: (value) => setState((prevState) => ({ ...prevState, customInstructions: value })), setCustomInstructions: (value) => setState((prevState) => ({ ...prevState, customInstructions: value })),
setAlwaysAllowReadOnly: (value) => setState((prevState) => ({ ...prevState, alwaysAllowReadOnly: value })), setAlwaysAllowReadOnly: (value) => setState((prevState) => ({ ...prevState, alwaysAllowReadOnly: value })),
@@ -139,6 +142,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
setShowAnnouncement: (value) => setState((prevState) => ({ ...prevState, shouldShowAnnouncement: value })), setShowAnnouncement: (value) => setState((prevState) => ({ ...prevState, shouldShowAnnouncement: value })),
setAllowedCommands: (value) => setState((prevState) => ({ ...prevState, allowedCommands: value })), setAllowedCommands: (value) => setState((prevState) => ({ ...prevState, allowedCommands: value })),
setSoundEnabled: (value) => setState((prevState) => ({ ...prevState, soundEnabled: value })), setSoundEnabled: (value) => setState((prevState) => ({ ...prevState, soundEnabled: value })),
setSoundVolume: (value) => setState((prevState) => ({ ...prevState, soundVolume: value })),
setDiffEnabled: (value) => setState((prevState) => ({ ...prevState, diffEnabled: value })), setDiffEnabled: (value) => setState((prevState) => ({ ...prevState, diffEnabled: value })),
} }