Add Master Volume slider, status bar toggle, and toolbar customization menu
The toolbar now has a right-click menu to hide/show the status bar and a short Master Volume slider (drag or scroll) that multiplies both voice and notification volume via new Settings.effectiveOutputVolume()/ effectiveSoundVolume() helpers. Also splits MainFrame's toolbar, menu bar and status bar construction into their own MainToolbar/MainMenuBar/StatusBar classes, each talking back to MainFrame only through a Listener interface. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -95,6 +95,12 @@ public final class Settings {
|
||||
public boolean music = false;
|
||||
/** Master playback gain, 0..1 (may exceed 1 for boost up to 2). */
|
||||
public double outputVolume = 1.0;
|
||||
/**
|
||||
* Global multiplier on top of {@link #outputVolume} and {@link #soundVolume},
|
||||
* controlled from the toolbar's Master Volume slider so both can be ridden
|
||||
* with one control. 0..2, same boost headroom as the other volumes.
|
||||
*/
|
||||
public double masterVolume = 1.0;
|
||||
/** Microphone input gain multiplier applied before VAD/encode. */
|
||||
public double inputVolume = 1.0;
|
||||
/** Remove steady background noise from the microphone (spectral denoise). */
|
||||
@@ -119,6 +125,12 @@ public final class Settings {
|
||||
/** Extra folder to look for icon packs in, on top of the well-known locations. */
|
||||
public String iconPackDir = "";
|
||||
|
||||
// ---- window chrome ----
|
||||
/** Whether the status bar at the bottom of the window is shown. */
|
||||
public boolean showStatusBar = true;
|
||||
/** Whether the Master Volume slider is shown on the toolbar. */
|
||||
public boolean showMasterVolumeSlider = true;
|
||||
|
||||
/** Which actions make a sound, and which ones are important enough to survive muting. */
|
||||
public final NotificationSettings notifications = new NotificationSettings();
|
||||
|
||||
@@ -155,6 +167,16 @@ public final class Settings {
|
||||
return new File(identityFile);
|
||||
}
|
||||
|
||||
/** {@link #outputVolume} scaled by the Master Volume slider. */
|
||||
public double effectiveOutputVolume() {
|
||||
return outputVolume * masterVolume;
|
||||
}
|
||||
|
||||
/** {@link #soundVolume} scaled by the Master Volume slider. */
|
||||
public double effectiveSoundVolume() {
|
||||
return soundVolume * masterVolume;
|
||||
}
|
||||
|
||||
/** The directory holding all persistent client state (settings, identities, caches). */
|
||||
public static File configDir() {
|
||||
return DIR;
|
||||
@@ -185,6 +207,7 @@ public final class Settings {
|
||||
packetLoss = parseI(props.getProperty("packetLoss"), packetLoss);
|
||||
music = parseB(props.getProperty("music"), music);
|
||||
outputVolume = parseD(props.getProperty("outputVolume"), outputVolume);
|
||||
masterVolume = parseD(props.getProperty("masterVolume"), masterVolume);
|
||||
inputVolume = parseD(props.getProperty("inputVolume"), inputVolume);
|
||||
denoise = parseB(props.getProperty("denoise"), denoise);
|
||||
denoiserLevel = parseD(props.getProperty("denoiserLevel"), denoiserLevel);
|
||||
@@ -195,6 +218,8 @@ public final class Settings {
|
||||
soundPackDir = props.getProperty("soundPackDir", soundPackDir);
|
||||
iconPack = props.getProperty("iconPack", iconPack);
|
||||
iconPackDir = props.getProperty("iconPackDir", iconPackDir);
|
||||
showStatusBar = parseB(props.getProperty("showStatusBar"), showStatusBar);
|
||||
showMasterVolumeSlider = parseB(props.getProperty("showMasterVolumeSlider"), showMasterVolumeSlider);
|
||||
notifications.load(props);
|
||||
}
|
||||
|
||||
@@ -223,6 +248,7 @@ public final class Settings {
|
||||
props.setProperty("packetLoss", Integer.toString(packetLoss));
|
||||
props.setProperty("music", Boolean.toString(music));
|
||||
props.setProperty("outputVolume", Double.toString(outputVolume));
|
||||
props.setProperty("masterVolume", Double.toString(masterVolume));
|
||||
props.setProperty("inputVolume", Double.toString(inputVolume));
|
||||
props.setProperty("denoise", Boolean.toString(denoise));
|
||||
props.setProperty("denoiserLevel", Double.toString(denoiserLevel));
|
||||
@@ -233,6 +259,8 @@ public final class Settings {
|
||||
props.setProperty("soundPackDir", soundPackDir);
|
||||
props.setProperty("iconPack", iconPack);
|
||||
props.setProperty("iconPackDir", iconPackDir);
|
||||
props.setProperty("showStatusBar", Boolean.toString(showStatusBar));
|
||||
props.setProperty("showMasterVolumeSlider", Boolean.toString(showMasterVolumeSlider));
|
||||
notifications.store(props);
|
||||
}
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ public final class SoundNotifier {
|
||||
if (script == null) return;
|
||||
|
||||
String resolved = script.resolve(withDefaults(variables));
|
||||
double volume = Math.max(0, Math.min(1.0, settings.soundVolume));
|
||||
double volume = Math.max(0, Math.min(1.0, settings.effectiveSoundVolume()));
|
||||
if (volume <= 0) return;
|
||||
|
||||
if (script.kind() == SoundScript.Kind.SAY) {
|
||||
|
||||
Reference in New Issue
Block a user