diff --git a/.gitignore b/.gitignore index 808b830..54dcf66 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ #build files build/ - +core #VS Code config files. # .vscode/ Sort this out later. .gitignore-ing an already tracked file doesn't actually work. #settings diff --git a/CMakeLists.txt b/CMakeLists.txt index f33874e..564358c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,10 +1,10 @@ cmake_minimum_required(VERSION 3.16.0) project(pipedal - VERSION 1.3.53 + VERSION 1.3.54 DESCRIPTION "PiPedal Guitar Effect Pedal For Raspberry Pi" HOMEPAGE_URL "https://rerdavies.github.io/pipedal" ) -set (DISPLAY_VERSION "PiPedal v1.3.53-Release") +set (DISPLAY_VERSION "PiPedal v1.3.54-Release") set (PACKAGE_ARCHITECTURE "arm64") set (CMAKE_INSTALL_PREFIX "/usr/") diff --git a/PiPedalCommon/src/WifiConfigSettings.cpp b/PiPedalCommon/src/WifiConfigSettings.cpp index 1cc1da6..ddeb005 100644 --- a/PiPedalCommon/src/WifiConfigSettings.cpp +++ b/PiPedalCommon/src/WifiConfigSettings.cpp @@ -168,7 +168,7 @@ void WifiConfigSettings::Save() { ofstream_synced f; openWithPerms(f,CONFIG_PATH); - json_writer writer(f); + json_writer writer(f,false); writer.write(&newSettings); } catch (const std::exception &e) @@ -300,6 +300,18 @@ namespace pipedal::priv connection["ipv4"]["method"] = sdbus::Variant(std::string("shared")); connection["ipv6"]["method"] = sdbus::Variant(std::string("ignore")); + + connection["ipv4"]["address-data"] = sdbus::Variant(std::vector>{{ + {"address", sdbus::Variant("192.168.4.1")}, + {"prefix", sdbus::Variant(uint32_t(24))} + }}); + connection["ipv4"]["dhcp-send-hostname"] = sdbus::Variant(true); + connection["ipv4"]["dhcp-hostname"] = sdbus::Variant("raspberrypi"); + connection["ipv4"]["dhcp-options"] = sdbus::Variant(std::vector{ + "option:classless-static-route,192.168.4.0/24,0.0.0.0,0.0.0.0/0,192.168.4.1" + //"option:classless-static-route,192.168.4.0/24,192.168.4.1" + }); + auto connection_path = AddConnection(connection); return connection_path; } diff --git a/README.md b/README.md index 50d728b..a476f6b 100644 --- a/README.md +++ b/README.md @@ -6,13 +6,13 @@ -Download: v1.3.53 +Download: v1.3.54 Website: [https://rerdavies.github.io/pipedal](https://rerdavies.github.io/pipedal). Documentation: [https://rerdavies.github.io/pipedal/Documentation.html](https://rerdavies.github.io/pipedal/Documentation.html).   -#### NEW version 1.3.53 Release, providing [snapshots](https://rerdavies.github.io/pipedal/Snaphots.html), and a new Performance View. See the [release notes](https://rerdavies.github.io/pipedal/ReleaseNotes) for details. +#### NEW version 1.3.54 Release, providing [snapshots](https://rerdavies.github.io/pipedal/Snaphots.html), and a new Performance View. See the [release notes](https://rerdavies.github.io/pipedal/ReleaseNotes) for details.   diff --git a/docs/Installing.md b/docs/Installing.md index 248bf6c..083e737 100644 --- a/docs/Installing.md +++ b/docs/Installing.md @@ -13,17 +13,17 @@ page_icon: img/Install4.jpg Download the most recent Debian (.deb) package for your platform: -- [Raspberry Pi OS bookworm (64-bit) v1.3.53](https://github.com/rerdavies/pipedal/releases/download/) +- [Raspberry Pi OS bookworm (64-bit) v1.3.54](https://github.com/rerdavies/pipedal/releases/download/) - [Ubuntu/Raspberry Pi OS bullseyeye (64-bit) v1.2.31](https://github.com/rerdavies/pipedal/releases/download/v1.1.31/pipedal_1.1.31_arm64.deb) -Version 1.3.53 has not yet been tested on Ubuntu or Raspberry Pi OS bullseye. On these platforms, we recommend that you use version 1.1.31. +Version 1.3.54 has not yet been tested on Ubuntu or Raspberry Pi OS bullseye. On these platforms, we recommend that you use version 1.1.31. Install the package by running ``` sudo apt update cd ~/Downloads - sudo apt-get install pipedal_1.3.53_arm64.deb + sudo apt-get install pipedal_1.3.54_arm64.deb ``` Adjust accordingly if you have downloaded v1.1.31. diff --git a/docs/ReleaseNotes.md b/docs/ReleaseNotes.md index dc4e4cf..a9a898b 100644 --- a/docs/ReleaseNotes.md +++ b/docs/ReleaseNotes.md @@ -1,4 +1,38 @@ # Release Notes +## PiPedal 1.3.54 Release + +Improvements to and fixes for hotspot functionality. Fixes for problems with snapshots. + +Minor features; +- Enter key supported in most dialogs. + +Bug fixes. +- Various crashes related to snapshots. + +- Applying changes to wi-fi hostpot configuration would not change the configuration until PiPedal was rebooted (a regression). + The configuration of the Wi-Fi hotspot now changes as soon as you apply it. + +- The state of bypass switches was not getting captured in snapshots. + +- Crashes when scrolling through presets rapidly in the Snapshot view. + +- Web server redirects link-local IPv6 connections to non-link local address. (Improves client connectivity). + +- Force DHCP routing on hotspot connections. (Improves android client cnnectivity) + +- Missing MIDI device causes audio to stop. + +- The file model for snapshots was confusing and didn't entirely work as expected. Changes to snapshots now + only get saved when the preset to which they belong gets saved (explicit-save file model, instead of + Android file model). + +- Layout improvement to a number of dialogs when displayed on wide screens. + + + +Bug fixes: + + ## PiPedal 1.3.53 Release Major features: diff --git a/docs/download.md b/docs/download.md index 681c170..b1ebd8b 100644 --- a/docs/download.md +++ b/docs/download.md @@ -4,7 +4,7 @@ Download the most recent Debian (.deb) package for your platform: -- Raspberry Pi OS Bookworm (64-bit) v1.3.53 +- Raspberry Pi OS Bookworm (64-bit) v1.3.54 Install the package by running @@ -12,7 +12,7 @@ Install the package by running ``` sudo apt update cd ~/Downloads - sudo apt-get install ./pipedal_1.3.53_arm64.deb + sudo apt-get install ./pipedal_1.3.54_arm64.deb ``` Follow the instructions in [_Configuring PiPedal After Installation_](https://rerdavies.github.io/pipedal/Configuring.html) to complete the installation. diff --git a/docs/index.md b/docs/index.md index 66099d0..5e19088 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,7 +1,7 @@ -v1.3.53 +v1.3.54   @@ -9,7 +9,7 @@ To download PiPedal, click [here](download.md). To view PiPedal documentation, click [here](Documentation.md). -#### NEW version 1.3.53 Release. See the [release notes](https://rerdavies.github.io/pipedal/ReleaseNotes) for details. +#### NEW version 1.3.54 Release. See the [release notes](https://rerdavies.github.io/pipedal/ReleaseNotes) for details.   diff --git a/react/CMakeLists.txt b/react/CMakeLists.txt index d69c08b..2c84502 100644 --- a/react/CMakeLists.txt +++ b/react/CMakeLists.txt @@ -33,6 +33,8 @@ add_custom_command( src/AlsaMidiDeviceInfo.tsx src/WifiDirectConfigSettings.tsx src/WifiConfigSettings.tsx + src/SnapshotButton.tsx + src/WindowScale.tsx src/JsonAtom.tsx src/PiPedalSocket.tsx src/TemporaryDrawer.tsx @@ -43,6 +45,7 @@ add_custom_command( src/SettingsDialog.tsx src/PedalboardView.tsx src/reportWebVitals.ts + src/OptionsDialog.tsx src/SelectChannelsDialog.tsx src/PluginPresetSelector.tsx src/VuMeter.tsx @@ -122,6 +125,7 @@ add_custom_command( src/svg/fx_utility.svg src/Updater.tsx src/UploadPresetDialog.tsx + src/RadioSelectDialog.tsx src/setupTests.ts src/ToobCabSimView.tsx src/RenameDialog.tsx @@ -140,6 +144,7 @@ add_custom_command( src/Draggable.tsx src/PluginIcon.tsx src/react-app-env.d.ts + src/TextFieldEx.tsx src/FilePropertyDialog.tsx src/FilePropertyDirectoryTree.tsx src/StringBuilder.tsx @@ -150,7 +155,6 @@ add_custom_command( src/ToobSpectrumResponseView.tsx src/PerformanceView.tsx src/JackServerSettingsDialog.tsx - src/ListSelectDialog.tsx src/Utility.tsx src/JackStatusView.tsx src/ToobSpectrumAnalyzerView.tsx @@ -160,6 +164,7 @@ add_custom_command( src/WifiChannel.tsx src/AboutDialog.tsx src/GxTunerControl.tsx + src/VirtualKeyboardHandler.tsx src/PluginControl.tsx src/LoadPluginDialog.tsx src/ZoomedUiControl.tsx @@ -175,8 +180,10 @@ add_custom_command( src/SnapshotPanel.tsx src/ToobMLView.tsx src/WifiConfigDialog.tsx + src/Rectangle.tsx src/SnapshotColors.tsx src/PiPedalModel.tsx + src/ObservableEvent.tsx src/JackHostStatus.tsx src/index.tsx src/FilePropertyControl.tsx @@ -192,7 +199,7 @@ add_custom_command( src/SnapshotPropertiesDialog.tsx src/SearchControl.tsx src/Units.tsx - + ) add_custom_target ( diff --git a/react/src/AboutDialog.tsx b/react/src/AboutDialog.tsx index 8a65e02..eb95eef 100644 --- a/react/src/AboutDialog.tsx +++ b/react/src/AboutDialog.tsx @@ -199,6 +199,7 @@ const AboutDialog = withStyles(styles, { withTheme: true })( return ( { this.props.onClose() }} TransitionComponent={Transition} + onEnterKey={() => { this.props.onClose() }} style={{ userSelect: "none" }} > diff --git a/react/src/AppThemed.tsx b/react/src/AppThemed.tsx index 73615d5..4845347 100644 --- a/react/src/AppThemed.tsx +++ b/react/src/AppThemed.tsx @@ -1020,6 +1020,7 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent< diff --git a/react/src/BankDialog.tsx b/react/src/BankDialog.tsx index 2b0940f..e22fd4c 100644 --- a/react/src/BankDialog.tsx +++ b/react/src/BankDialog.tsx @@ -409,6 +409,7 @@ const BankDialog = withStyles(styles, { withTheme: true })( return ( { this.handleDialogClose() }} TransitionComponent={Transition} + onEnterKey={()=>{}} style={{ userSelect: "none" }} >
@@ -544,7 +545,9 @@ const BankDialog = withStyles(styles, { withTheme: true })( /> this.handleDeletePromptClose()} - style={{ userSelect: "none" }}> + style={{ userSelect: "none" }} + onEnterKey={()=>{ this.handleDeletePromptOk() }} + > Are you sure you want to delete bank '{this.getSelectedBankName()}'? diff --git a/react/src/DialogEx.tsx b/react/src/DialogEx.tsx index 4879613..0fb78d9 100644 --- a/react/src/DialogEx.tsx +++ b/react/src/DialogEx.tsx @@ -25,6 +25,7 @@ import Dialog, {DialogProps} from '@mui/material/Dialog'; interface DialogExProps extends DialogProps { tag: string; fullwidth?: boolean; + onEnterKey: () => void; } interface DialogExState { @@ -186,7 +187,10 @@ class DialogEx extends React.Component implements I } onEnterKey() { - + if (this.props.onEnterKey) + { + this.props.onEnterKey(); + } } onKeyDown(evt: React.KeyboardEvent) { diff --git a/react/src/FilePropertyDialog.tsx b/react/src/FilePropertyDialog.tsx index 7a15512..7fdeecc 100644 --- a/react/src/FilePropertyDialog.tsx +++ b/react/src/FilePropertyDialog.tsx @@ -484,9 +484,12 @@ export default withStyles(styles, { withTheme: true })( fullScreen={this.state.fullScreen} onClose={() => { this.props.onCancel(); - }} + }} + onEnterKey={()=> { + this.openSelectedFile(); + }} open={this.props.open} tag="fileProperty" - fullWidth maxWidth="xl" + fullWidth maxWidth="md" PaperProps={ this.state.fullScreen ? {} diff --git a/react/src/FilePropertyDirectorySelectDialog.tsx b/react/src/FilePropertyDirectorySelectDialog.tsx index ec468c3..a9b341f 100644 --- a/react/src/FilePropertyDirectorySelectDialog.tsx +++ b/react/src/FilePropertyDirectorySelectDialog.tsx @@ -319,6 +319,7 @@ export default class FilePropertyDirectorySelectDialog extends ResizeResponsiveC { this.onClose(); }} aria-labelledby="Rename-dialog-title" fullScreen={this.state.fullScreen} style={{ userSelect: "none" }} + onEnterKey={()=>{ this.onOK(); }} PaperProps={{ style: { minHeight: "80%", maxHeight: "80%", minWidth: "75%", maxWidth: "75%", overflowY: "visible" } }} > diff --git a/react/src/FullScreenIME.tsx b/react/src/FullScreenIME.tsx index dcc9a08..f3ec69a 100644 --- a/react/src/FullScreenIME.tsx +++ b/react/src/FullScreenIME.tsx @@ -166,15 +166,19 @@ const FullScreenIME = } } + onOk() { + if (this.inputChanged) { + this.inputChanged = false; + this.validateInput(true); + } + else { + this.props.onClose(); + } + } + onInputKeyPress(e: any): void { if (e.charCode === 13) { - if (this.inputChanged) { - this.inputChanged = false; - this.validateInput(true); - } - else { - this.props.onClose(); - } + this.onOk(); } } @@ -196,7 +200,9 @@ const FullScreenIME = let value = this.props.value; return ( - this.handleClose(e, r)} > + this.handleClose(e, r)} + onEnterKey={()=>{ /*nothing*/}} + >
+ { + this.handleApply(); + }} + + >
diff --git a/react/src/LoadPluginDialog.tsx b/react/src/LoadPluginDialog.tsx index 6cfaec5..2a9eeba 100644 --- a/react/src/LoadPluginDialog.tsx +++ b/react/src/LoadPluginDialog.tsx @@ -375,8 +375,22 @@ export const LoadPluginDialog = e.preventDefault(); this.cancel(); } - handleOk(e: SyntheticEvent): void { - e.preventDefault(); + handleOk(e?: SyntheticEvent): void { + if (e) { + e.preventDefault(); + } + + let selectedPlugin: UiPlugin | undefined = undefined; + if (this.state.selected_uri) { + let t = this.model.getUiPlugin(this.state.selected_uri); + if (t) selectedPlugin = t; + } + if (!selectedPlugin) + { + return; + } + + if (this.state.selected_uri) { this.props.onOk(this.state.selected_uri); } @@ -688,7 +702,9 @@ export const LoadPluginDialog = return ( { this.handleOk(); }} onKeyPress={(e) => { this.handleKeyPress(e); }} + fullScreen={true} TransitionComponent={undefined} maxWidth={false} diff --git a/react/src/MidiBindingsDialog.tsx b/react/src/MidiBindingsDialog.tsx index bd4c6f1..1fe9991 100644 --- a/react/src/MidiBindingsDialog.tsx +++ b/react/src/MidiBindingsDialog.tsx @@ -326,6 +326,8 @@ export const MidiBindingDialog = {}} + >
diff --git a/react/src/ObservableEvent.tsx b/react/src/ObservableEvent.tsx new file mode 100644 index 0000000..a9e3be9 --- /dev/null +++ b/react/src/ObservableEvent.tsx @@ -0,0 +1,54 @@ +// Copyright (c) 2022 Robin Davies +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO `EVENT` SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + + +export type ObservableEventHandler = (newValue: VALUE_TYPE) => void; + + +export default class ObservableEvent { + + private _on_event_handlers: ObservableEventHandler[] = []; + + + addEventHandler(handler: ObservableEventHandler ) : void + { + this._on_event_handlers.push(handler); + } + removeEventHandler(handler: ObservableEventHandler ) : void + { + let newArray: ObservableEventHandler[] = []; + + for (let myHandler of this._on_event_handlers) + { + if (myHandler !== handler) + { + newArray.push(myHandler); + } + } + this._on_event_handlers = newArray; + } + fire(value: VALUE_TYPE) + { + for (let handler of this._on_event_handlers) + { + handler(value); + } + } +}; \ No newline at end of file diff --git a/react/src/ObservableProperty.tsx b/react/src/ObservableProperty.tsx index 31bb745..3808bd6 100644 --- a/react/src/ObservableProperty.tsx +++ b/react/src/ObservableProperty.tsx @@ -12,7 +12,7 @@ // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO `EVENT` SHALL THE AUTHORS OR // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/react/src/OkCancelDialog.tsx b/react/src/OkCancelDialog.tsx index 726ac3b..c46384e 100644 --- a/react/src/OkCancelDialog.tsx +++ b/react/src/OkCancelDialog.tsx @@ -63,6 +63,7 @@ export default class OkCancelDialog extends React.Component diff --git a/react/src/OptionsDialog.tsx b/react/src/OptionsDialog.tsx index bdae319..890df65 100644 --- a/react/src/OptionsDialog.tsx +++ b/react/src/OptionsDialog.tsx @@ -70,7 +70,7 @@ function OptionsDialog(props: OptionsDialogProps) { onClose(); }; return ( - + {}} > {title && ( diff --git a/react/src/Pedalboard.tsx b/react/src/Pedalboard.tsx index 5a8d010..414d060 100644 --- a/react/src/Pedalboard.tsx +++ b/react/src/Pedalboard.tsx @@ -226,12 +226,14 @@ export class SnapshotValue { { let result = new SnapshotValue(); result.instanceId = item.instanceId; + result.isEnabled = item.isEnabled; result.controlValues = ControlValue.deserializeArray(item.controlValues); result.lv2State = item.lv2State; // we can do this, because lv2State is immutable. result.pathProperties = {...item.pathProperties}; // clone the dictionary. return result; } instanceId: number = -1; + isEnabled: boolean = true; controlValues: ControlValue[] = ControlValue.EmptyArray; lv2State: [boolean,any] = [false,{}]; pathProperties: {[Name: string]: string} = {}; @@ -239,6 +241,7 @@ export class SnapshotValue { export class Snapshot { deserialize(input: any): Snapshot { this.values = SnapshotValue.deserializeArray(input.values); + this.isModified = input.isModified; this.name = input.name; this.color = input.color; return this; @@ -273,6 +276,7 @@ export class Snapshot { return result; } name: string = ""; + isModified: boolean = false; color: string = ""; values: SnapshotValue[] = []; }; diff --git a/react/src/PerformanceView.tsx b/react/src/PerformanceView.tsx index 8ca17aa..e89d776 100644 --- a/react/src/PerformanceView.tsx +++ b/react/src/PerformanceView.tsx @@ -19,6 +19,7 @@ import { Theme } from '@mui/material/styles'; +import SaveIconOutline from '@mui/icons-material/Save'; import { WithStyles } from '@mui/styles'; import createStyles from '@mui/styles/createStyles'; import withStyles from '@mui/styles/withStyles'; @@ -78,6 +79,7 @@ interface PerformanceViewState { banks: BankIndex; showSnapshotEditor: boolean; snapshotEditorIndex: number; + presetModified: boolean; } @@ -97,11 +99,13 @@ export const PerformanceView = banks: this.model.banks.get(), wrapSelects: false, showSnapshotEditor: false, - snapshotEditorIndex: 0 + snapshotEditorIndex: 0, + presetModified: this.model.presetChanged.get() }; this.onPresetsChanged = this.onPresetsChanged.bind(this); this.onBanksChanged = this.onBanksChanged.bind(this); this.handlePopState = this.handlePopState.bind(this); + this.onPresetChangedChanged = this.onPresetChangedChanged.bind(this); } @@ -181,6 +185,9 @@ export const PerformanceView = onBanksChanged(newValue: BankIndex) { this.setState({ banks: this.model.banks.get() }) } + onPresetChangedChanged(newValue: boolean) { + this.setState({ presetModified:newValue}); + } private mounted: boolean = false; componentDidMount(): void { @@ -188,9 +195,12 @@ export const PerformanceView = this.mounted = true; this.model.presets.addOnChangedHandler(this.onPresetsChanged); this.model.banks.addOnChangedHandler(this.onBanksChanged); + this.model.presetChanged.addOnChangedHandler(this.onPresetChangedChanged) this.setState({ presets: this.model.presets.get(), - banks: this.model.banks.get() + banks: this.model.banks.get(), + presetModified: this.model.presetChanged.get() + }); this.updateHooks(); @@ -200,7 +210,7 @@ export const PerformanceView = componentWillUnmount(): void { - + this.model.presetChanged.removeOnChangedHandler(this.onPresetChangedChanged) this.model.presets.removeOnChangedHandler(this.onPresetsChanged); this.model.banks.removeOnChangedHandler(this.onBanksChanged); @@ -332,13 +342,27 @@ export const PerformanceView = { this.handleNextBank(); }} - size="large" color="inherit" style={{ borderTopLeftRadius: "3px", borderBottomLeftRadius: "3px", marginLeft: 4 }} > + + {/** spacer */} + { this.handleNextBank(); }} + size="medium" + color="inherit" + style={{visibility: "hidden"}} + > + + + + + +
{/********* PRESETS *******************/}
@@ -367,9 +391,14 @@ export const PerformanceView = > { presets.presets.map((preset) => { + let name = preset.name; + if (this.state.presets.selectedInstanceId === preset.instanceId && this.state.presetModified) + { + name += "*"; + } return ( - {preset.name} + {name} ); }) @@ -385,6 +414,16 @@ export const PerformanceView = + { this.model.saveCurrentPreset(); }} + size="medium" + color="inherit" + style={{flexShrink: 0,visibility: this.state.presetModified? "visible": "hidden"}} + > + + +
diff --git a/react/src/PiPedalModel.tsx b/react/src/PiPedalModel.tsx index 6a7ad4a..d54a494 100644 --- a/react/src/PiPedalModel.tsx +++ b/react/src/PiPedalModel.tsx @@ -21,6 +21,7 @@ import { UiPlugin, UiControl, PluginType, UiFileProperty } from './Lv2Plugin'; import { PiPedalArgumentError, PiPedalStateError } from './PiPedalError'; import { UpdateStatus, UpdatePolicyT } from './Updater'; +import ObservableEvent from './ObservableEvent'; import { ObservableProperty } from './ObservableProperty'; import { Pedalboard, PedalboardItem, ControlValue, Snapshot } from './Pedalboard' import PluginClass from './PluginClass'; @@ -362,6 +363,11 @@ export interface FavoritesList { [url: string]: boolean; }; +export interface SnapshotModifiedEvent { + snapshotIndex: number; + modified: boolean; +}; + export class PiPedalModel //implements PiPedalModel { @@ -376,6 +382,9 @@ export class PiPedalModel //implements PiPedalModel webSocket?: PiPedalSocket; + + onSnapshotModified: ObservableEvent = new ObservableEvent(); + ui_plugins: ObservableProperty = new ObservableProperty([]); state: ObservableProperty = new ObservableProperty(State.Loading); @@ -503,6 +512,7 @@ export class PiPedalModel //implements PiPedalModel private setModelPedalboard(pedalboard: Pedalboard) { this.pedalboard.set(pedalboard); this.selectedSnapshot.set(pedalboard.selectedSnapshot); + } onSocketMessage(header: PiPedalMessageHeader, body?: any) { if (this.visibilityState.get() === VisibilityState.Hidden) return; @@ -564,6 +574,21 @@ export class PiPedalModel //implements PiPedalModel let channelSelectionBody = body as ChannelSelectionChangedBody; let channelSelection = new JackChannelSelection().deserialize(channelSelectionBody.jackChannelSelection); this.jackSettings.set(channelSelection); + } else if (message === "onSnapshotModified") { + let {snapshotIndex,modified} = (body as {snapshotIndex: number, modified: boolean}); + let snapshots = this.pedalboard.get().snapshots; + if (snapshotIndex >= 0 && snapshotIndex < snapshots.length) + { + let snapshot = snapshots[snapshotIndex] + if (snapshot) + { + if (snapshot.isModified !== modified) + { + snapshot.isModified = modified; + this.onSnapshotModified.fire({snapshotIndex: snapshotIndex,modified: modified}); + } + } + } } else if (message === "onSelectedSnapshotChanged") { let selectedSnapshot = body as number; this.pedalboard.get().selectedSnapshot = selectedSnapshot; @@ -581,6 +606,7 @@ export class PiPedalModel //implements PiPedalModel let presetsChangedBody = body as PresetsChangedBody; let presets = new PresetIndex().deserialize(presetsChangedBody.presets); this.presets.set(presets); + this.presetChanged.set(presets.presetChanged); } else if (message === "onPluginPresetsChanged") { let pluginUri = body as string; this.handlePluginPresetsChanged(pluginUri); @@ -1286,7 +1312,6 @@ export class PiPedalModel //implements PiPedalModel changed = item.setControlValue(controlValue.key, controlValue.value) || changed; } if (changed) { - newPedalboard.selectedSnapshot = -1; this.setModelPedalboard(newPedalboard); } } @@ -1428,7 +1453,6 @@ export class PiPedalModel //implements PiPedalModel if (pedalboard.input_volume_db !== volume_db) { let newPedalboard = pedalboard.clone(); newPedalboard.input_volume_db = volume_db; - newPedalboard.selectedSnapshot = -1; this.setModelPedalboard(newPedalboard); changed = true; } @@ -1457,7 +1481,6 @@ export class PiPedalModel //implements PiPedalModel if (pedalboard.output_volume_db !== volume_db) { let newPedalboard = pedalboard.clone(); newPedalboard.output_volume_db = volume_db; - newPedalboard.selectedSnapshot = -1; this.setModelPedalboard(newPedalboard); changed = true; } @@ -1494,7 +1517,6 @@ export class PiPedalModel //implements PiPedalModel if (notifyServer) { this._setServerControl("setControl", instanceId, key, value); } - newPedalboard.selectedSnapshot = -1; this.setModelPedalboard(newPedalboard); for (let i = 0; i < this._controlValueChangeItems.length; ++i) { let item = this._controlValueChangeItems[i]; @@ -1547,7 +1569,6 @@ export class PiPedalModel //implements PiPedalModel let changed = value !== item.isEnabled; if (changed) { item.isEnabled = value; - newPedalboard.selectedSnapshot = -1; this.setModelPedalboard(newPedalboard); if (notifyServer) { let body: PedalboardItemEnableBody = { @@ -1605,7 +1626,6 @@ export class PiPedalModel //implements PiPedalModel // null -> we've never seen a value. item.pathProperties[fileProperty.patchProperty] = "null"; } - newPedalboard.selectedSnapshot = -1; this.setModelPedalboard(newPedalboard); this.updateServerPedalboard() return item.instanceId; @@ -1646,7 +1666,6 @@ export class PiPedalModel //implements PiPedalModel let result = newPedalboard.deleteItem(instanceId); if (result !== null) { - newPedalboard.selectedSnapshot = -1; this.setModelPedalboard(newPedalboard); this.updateServerPedalboard(); } @@ -1669,7 +1688,6 @@ export class PiPedalModel //implements PiPedalModel newPedalboard.deleteItem(fromInstanceId); newPedalboard.addBefore(fromItem, toInstanceId); - newPedalboard.selectedSnapshot = -1; this.setModelPedalboard(newPedalboard); this.updateServerPedalboard(); @@ -1690,7 +1708,6 @@ export class PiPedalModel //implements PiPedalModel newPedalboard.addAfter(fromItem, toInstanceId); - newPedalboard.selectedSnapshot = -1; this.setModelPedalboard(newPedalboard); this.updateServerPedalboard(); } @@ -1712,7 +1729,6 @@ export class PiPedalModel //implements PiPedalModel newPedalboard.addToStart(fromItem); - newPedalboard.selectedSnapshot = -1; this.setModelPedalboard(newPedalboard); this.updateServerPedalboard(); } @@ -1732,7 +1748,6 @@ export class PiPedalModel //implements PiPedalModel newPedalboard.addToEnd(fromItem); - newPedalboard.selectedSnapshot = -1; this.setModelPedalboard(newPedalboard); this.updateServerPedalboard(); @@ -1761,7 +1776,6 @@ export class PiPedalModel //implements PiPedalModel newPedalboard.replaceItem(fromInstanceId, emptyItem); newPedalboard.replaceItem(toInstanceId, fromItem); - newPedalboard.selectedSnapshot = -1; this.setModelPedalboard(newPedalboard); this.updateServerPedalboard(); @@ -1785,7 +1799,6 @@ export class PiPedalModel //implements PiPedalModel } let newItem = newPedalboard.createEmptyItem(); newPedalboard.addItem(newItem, instanceId, append); - newPedalboard.selectedSnapshot = -1; this.setModelPedalboard(newPedalboard); this.updateServerPedalboard(); return newItem.instanceId; @@ -1811,7 +1824,6 @@ export class PiPedalModel //implements PiPedalModel } let newItem = newPedalboard.createEmptySplit(); newPedalboard.addItem(newItem, instanceId, append); - newPedalboard.selectedSnapshot = -1; this.setModelPedalboard(newPedalboard); this.updateServerPedalboard(); return newItem.instanceId; @@ -1829,7 +1841,6 @@ export class PiPedalModel //implements PiPedalModel } newPedalboard.setItemEmpty(item); - newPedalboard.selectedSnapshot = -1; this.setModelPedalboard(newPedalboard); this.updateServerPedalboard(); return item.instanceId; @@ -2332,7 +2343,6 @@ export class PiPedalModel //implements PiPedalModel let newPedalboard = pedalboard.clone(); this.updateVst3State(newPedalboard); if (newPedalboard.setMidiBinding(instanceId, midiBinding)) { - newPedalboard.selectedSnapshot = -1; this.setModelPedalboard(newPedalboard); diff --git a/react/src/PluginInfoDialog.tsx b/react/src/PluginInfoDialog.tsx index 2e9bfca..6d9e887 100644 --- a/react/src/PluginInfoDialog.tsx +++ b/react/src/PluginInfoDialog.tsx @@ -235,7 +235,9 @@ const PluginInfoDialog = withStyles(styles)((props: PluginInfoProps) => { {open && ( - +
diff --git a/react/src/PluginPresetsDialog.tsx b/react/src/PluginPresetsDialog.tsx index 35bd05a..9e012c9 100644 --- a/react/src/PluginPresetsDialog.tsx +++ b/react/src/PluginPresetsDialog.tsx @@ -361,7 +361,9 @@ const PluginPresetsDialog = withStyles(styles, { withTheme: true })( return ( { this.handleDialogClose() }} TransitionComponent={Transition} - style={{userSelect: "none"}}> + style={{userSelect: "none"}} + onEnterKey={()=>{}} + >
diff --git a/react/src/PresetDialog.tsx b/react/src/PresetDialog.tsx index 6f7d159..5d5f9c6 100644 --- a/react/src/PresetDialog.tsx +++ b/react/src/PresetDialog.tsx @@ -340,7 +340,9 @@ const PresetDialog = withStyles(styles, { withTheme: true })( return ( { this.handleDialogClose() }} TransitionComponent={Transition} - style={{userSelect: "none"}}> + style={{userSelect: "none"}} + onEnterKey={()=>{}} + >
diff --git a/react/src/ListSelectDialog.tsx b/react/src/RadioSelectDialog.tsx similarity index 85% rename from react/src/ListSelectDialog.tsx rename to react/src/RadioSelectDialog.tsx index 03f145d..6856fb0 100644 --- a/react/src/ListSelectDialog.tsx +++ b/react/src/RadioSelectDialog.tsx @@ -18,7 +18,6 @@ // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. import React from 'react'; -import Button from '@mui/material/Button'; import Radio from '@mui/material/Radio'; @@ -29,11 +28,10 @@ import ListItemIcon from '@mui/material/ListItemIcon'; import ListItemText from '@mui/material/ListItemText'; import DialogEx from './DialogEx'; -import DialogActions from '@mui/material/DialogActions'; import ResizeResponsiveComponent from './ResizeResponsiveComponent'; -export interface ListSelectDialogProps { +export interface RadioSelectDialogProps { open: boolean, title: string, width: number, @@ -43,15 +41,15 @@ export interface ListSelectDialogProps { onClose: () => void }; -export interface ListSelectDialogState { +export interface RadioSelectDialogState { fullScreen: boolean; }; -export default class ListSelectDialog extends ResizeResponsiveComponent { +export default class RadioSelectDialog extends ResizeResponsiveComponent { refText: React.RefObject; - constructor(props: ListSelectDialogProps) { + constructor(props: RadioSelectDialogProps) { super(props); this.state = { fullScreen: false @@ -82,7 +80,9 @@ export default class ListSelectDialog extends ResizeResponsiveComponentthis.props.onClose()} open={this.props.open}> + this.props.onClose()} open={this.props.open} + onEnterKey={()=>{ }} + > { this.props.items.map( @@ -105,11 +105,6 @@ export default class ListSelectDialog extends ResizeResponsiveComponent - - - ); } diff --git a/react/src/RenameDialog.tsx b/react/src/RenameDialog.tsx index 583dadb..cafe277 100644 --- a/react/src/RenameDialog.tsx +++ b/react/src/RenameDialog.tsx @@ -117,6 +117,7 @@ export default class RenameDialog extends ResizeResponsiveComponent{}} > + Select Channels {availableChannels.map((channel) => ( @@ -154,7 +156,9 @@ function SelectChannelsDialog(props: SelectChannelsDialogProps) { } return ( - + {}} + > handleListItemClick("Stereo")} key={"Stereo"} selected={selectionKey === "Stereo"} > diff --git a/react/src/SelectMidiChannelsDialog.tsx b/react/src/SelectMidiChannelsDialog.tsx index df621bc..23b74a5 100644 --- a/react/src/SelectMidiChannelsDialog.tsx +++ b/react/src/SelectMidiChannelsDialog.tsx @@ -93,7 +93,9 @@ function SelectMidiChannelsDialog(props: SelectMidiChannelsDialogProps) { return ( - + Select MIDI Device {availableChannels.map((channel) => ( diff --git a/react/src/SelectThemeDialog.tsx b/react/src/SelectThemeDialog.tsx index c4db808..f829045 100644 --- a/react/src/SelectThemeDialog.tsx +++ b/react/src/SelectThemeDialog.tsx @@ -64,7 +64,9 @@ function SelectThemesDialog(props: SelectThemesDialogProps) { return ( - + Theme diff --git a/react/src/SettingsDialog.tsx b/react/src/SettingsDialog.tsx index f70b42a..5e0389e 100644 --- a/react/src/SettingsDialog.tsx +++ b/react/src/SettingsDialog.tsx @@ -20,7 +20,7 @@ import React, { SyntheticEvent, Component } from 'react'; import Switch from "@mui/material/Switch"; import OkCancelDialog from './OkCancelDialog'; -import ListSelectDialog from './ListSelectDialog'; +import RadioSelectDialog from './RadioSelectDialog'; import IconButton from '@mui/material/IconButton'; import Typography from '@mui/material/Typography'; import { PiPedalModel, PiPedalModelFactory, State } from './PiPedalModel'; @@ -542,6 +542,7 @@ const SettingsDialog = withStyles(styles, { withTheme: true })( { this.props.onClose() }} TransitionComponent={Transition} style={{ userSelect: "none" }} + onEnterKey={()=>{}} >
@@ -882,7 +883,7 @@ const SettingsDialog = withStyles(styles, { withTheme: true })( { (this.state.showGovernorSettingsDialog) && ( - - + ) } { diff --git a/react/src/SnapshotButton.tsx b/react/src/SnapshotButton.tsx new file mode 100644 index 0000000..1feafb4 --- /dev/null +++ b/react/src/SnapshotButton.tsx @@ -0,0 +1,212 @@ +/* +* MIT License +* +* Copyright (c) 2024 Robin E. R. Davies +* +* Permission is hereby granted, free of charge, to any person obtaining a copy of +* this software and associated documentation files (the "Software"), to deal in +* the Software without restriction, including without limitation the rights to +* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +* of the Software, and to permit persons to whom the Software is furnished to do +* so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +import React from 'react'; +import Typography from '@mui/material/Typography'; +import IconButton from '@mui/material/IconButton'; +import ButtonBase from '@mui/material/ButtonBase'; +import ResizeResponsiveComponent from './ResizeResponsiveComponent'; +import SaveIconOutline from '@mui/icons-material/Save'; +import Button from "@mui/material/Button"; +import EditIconOutline from '@mui/icons-material/Edit'; +import { Snapshot } from './Pedalboard'; + +import { colorKeys, getBackgroundColor, getBorderColor } from './MaterialColors'; +import { PiPedalModel, PiPedalModelFactory, SnapshotModifiedEvent } from './PiPedalModel'; + +export interface SnapshotButtonProps { + snapshot: Snapshot | null; + snapshotIndex: number; + selected: boolean; + largeText: boolean; + collapseButtons: boolean; + + onEditSnapshot: (index: number) => void; + onSaveSnapshot: (index: number) => void; + onSelectSnapshot: (index: number) => void; +}; + +export interface SnapshotButtonState { + modified: boolean; +}; + +export default class SnapshotButton extends ResizeResponsiveComponent { + private model: PiPedalModel; + + constructor(props: SnapshotButtonProps) { + super(props); + this.state = { + modified: this.props.snapshot?.isModified ?? false, + }; + this.model = PiPedalModelFactory.getInstance(); + this.onSnapshotModified = this.onSnapshotModified.bind(this); + + } + + onWindowSizeChanged(width: number, height: number): void { + + } + + onSnapshotModified(event: SnapshotModifiedEvent) { + if (event.snapshotIndex === this.props.snapshotIndex) { + this.setState({ modified: event.modified }); + } + } + componentDidMount(): void { + super.componentDidMount?.(); + this.model.onSnapshotModified.addEventHandler(this.onSnapshotModified); + } + componentWillUnmount(): void { + this.model.onSnapshotModified.removeEventHandler(this.onSnapshotModified); + super.componentWillUnmount(); + } + componentDidUpdate( + prevProps: Readonly, + prevState: Readonly): void { + super.componentDidUpdate?.(prevProps, prevState); + + if (this.props.snapshot !== prevProps.snapshot) { + this.setState({ + modified: this.props.snapshot?.isModified ?? false + }) + } + } + + render() { + let { snapshot, snapshotIndex, selected } = this.props; + let { modified } = this.state; + + // (snapshot: Snapshot | null, index: number) { + //let state = this.state; + let color: string; + let bordercolor: string; + if (snapshot) { + if (colorKeys.indexOf(snapshot.color) === -1) { + bordercolor = color = snapshot.color; + } else { + color = getBackgroundColor(snapshot.color); + bordercolor = getBorderColor(snapshot.color); + } + } else { + bordercolor = color = getBackgroundColor("grey"); + } + let title = snapshot ? snapshot.name : ""; + if (modified) { + title = title + "*"; + } + let disabled = snapshot === null; + return ( +
+ + { + if (!selected) ev.stopPropagation(); + }} + + onClick={() => { if (snapshot) this.props.onSelectSnapshot(snapshotIndex); }} + > +
{ + if (disabled) ev.stopPropagation(); + }} + > +
+
+ + {title} +
+ + {(snapshotIndex + 1).toString()} + +
+ {/* placeholder where we will float the buttons, which can't be witin another button (tons of DOM validation warning messages in chrome) */} +
+ +
+
+
+ +
+ {!this.props.collapseButtons ? ( +
+ + +
+ + ) : ( +
+
 
+ { ev.stopPropagation(); /*don't prop to card*/ }} + onClick={() => { this.props.onSaveSnapshot(snapshotIndex); }} + > + + + { ev.stopPropagation(); /*don't prop to card*/ }} + onClick={() => { this.props.onEditSnapshot(snapshotIndex); }} + + > + + +
+ )} +
+
+ ); + } +} + diff --git a/react/src/SnapshotDialog.tsx b/react/src/SnapshotDialog.tsx index 4b0cc13..3076795 100644 --- a/react/src/SnapshotDialog.tsx +++ b/react/src/SnapshotDialog.tsx @@ -108,6 +108,7 @@ export default class SnapshotDialog extends ResizeResponsiveComponent{} } >
diff --git a/react/src/SnapshotEditor.tsx b/react/src/SnapshotEditor.tsx index c386c12..d078ff7 100644 --- a/react/src/SnapshotEditor.tsx +++ b/react/src/SnapshotEditor.tsx @@ -216,8 +216,23 @@ const SnapshotEditor = withStyles(appStyles)(class extends ResizeResponsiveCompo } handleOk() { - let selectedSnapshot = this.props.snapshotIndex; let currentPedalboard = this.model_.pedalboard.get(); + let selectedSnapshot = this.props.snapshotIndex; + let currentSnapshot: Snapshot | null = currentPedalboard.snapshots[selectedSnapshot]; + if (!currentSnapshot) + { + this.props.onClose(); + return; + } + + let changed = this.state.name !== currentSnapshot.name + || this.state.color !== currentSnapshot.color + || currentSnapshot.isModified; + if (!changed) + { + this.props.onClose(); + return; + } let newSnapshots = Snapshot.cloneSnapshots(currentPedalboard.snapshots); let newSnapshot = this.model_.pedalboard.get().makeSnapshot(); newSnapshot.name = this.state.name; diff --git a/react/src/SnapshotPanel.tsx b/react/src/SnapshotPanel.tsx index 205d99b..f1316f4 100644 --- a/react/src/SnapshotPanel.tsx +++ b/react/src/SnapshotPanel.tsx @@ -22,18 +22,12 @@ * SOFTWARE. */ -import Typography from '@mui/material/Typography'; -import IconButton from '@mui/material/IconButton'; -import ButtonBase from '@mui/material/ButtonBase'; +import SnapshotButton from './SnapshotButton'; import { Pedalboard, Snapshot } from './Pedalboard'; import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel'; import ResizeResponsiveComponent from './ResizeResponsiveComponent'; -import SaveIconOutline from '@mui/icons-material/Save'; -import Button from "@mui/material/Button"; -import EditIconOutline from '@mui/icons-material/Edit'; import SnapshotPropertiesDialog from './SnapshotPropertiesDialog'; -import { colorKeys, getBackgroundColor, getBorderColor } from './MaterialColors'; @@ -100,7 +94,7 @@ export default class SnapshotPanel extends ResizeResponsiveComponent"; - let disabled = snapshot === null; - let selected = this.state.selectedSnapshot === index; return ( -
- - { - if (!selected) ev.stopPropagation(); - }} - - onClick={() => { if (snapshot) this.selectSnapshot(index); }} - > -
{ - if (disabled) ev.stopPropagation(); - }} - > -
-
- - {title} -
-
- {/* placeholder where we will float the buttons, which can't be witin another button (tons of DOM validation warning messages in chrome) */} -
- -
-
-
-
- {(index+1).toString()} -
- -
- {!this.state.collapseButtons ? ( -
-
 
- - -
- - ) : ( -
-
 
- { ev.stopPropagation(); /*don't prop to card*/ }} - onClick={() => { this.onSaveSnapshot(index); }} - > - - - { ev.stopPropagation(); /*don't prop to card*/ }} - onClick={() => { this.onEditSnapshot(index); }} - - > - - -
- - )} - -
-
+ {this.onEditSnapshot(index)}} + onSaveSnapshot={(index)=>{ this.onSaveSnapshot(index); }} + onSelectSnapshot={(index)=>{this.model.selectSnapshot(index);}} + /> ); } diff --git a/react/src/SnapshotPropertiesDialog.tsx b/react/src/SnapshotPropertiesDialog.tsx index 8f3d33a..f828742 100644 --- a/react/src/SnapshotPropertiesDialog.tsx +++ b/react/src/SnapshotPropertiesDialog.tsx @@ -113,6 +113,7 @@ export default class SnapshotPropertiesDialog extends ResizeResponsiveComponent< return ( { this.handleOk(); }} >
diff --git a/react/src/SystemMidiBindingsDialog.tsx b/react/src/SystemMidiBindingsDialog.tsx index 4c398d4..52ad0e0 100644 --- a/react/src/SystemMidiBindingsDialog.tsx +++ b/react/src/SystemMidiBindingsDialog.tsx @@ -328,6 +328,7 @@ export const SystemMidiBindingDialog = {}} >
diff --git a/react/src/UpdateDialog.tsx b/react/src/UpdateDialog.tsx index 3ece574..2347948 100644 --- a/react/src/UpdateDialog.tsx +++ b/react/src/UpdateDialog.tsx @@ -166,6 +166,7 @@ export default class UpdateDialog extends ResizeResponsiveComponent { this.handleClose(); }} style={{ userSelect: "none" }} + onEnterKey={()=>{ this.handleOK();}} >
@@ -288,6 +289,7 @@ export default class UpdateDialog extends ResizeResponsiveComponent { this.handleCloseAlert(); }} aria-describedby="Alert Dialog" + onEnterKey={()=>{ this.handleCloseAlert(); }} > diff --git a/react/src/UploadFileDialog.tsx b/react/src/UploadFileDialog.tsx index 368432d..689ff5d 100644 --- a/react/src/UploadFileDialog.tsx +++ b/react/src/UploadFileDialog.tsx @@ -311,9 +311,13 @@ export default class UploadFileDialog extends ResizeResponsiveComponent this.handleClose()} - fullScreen={this.state.fullScreen} - style={{ userSelect: "none" }} + this.handleClose()} + fullScreen={false} + fullWidth={true} + maxWidth={"sm"} + style={{ userSelect: "none",}} + onEnterKey={()=>{ this.handleClose(); }} + >
@@ -326,7 +330,7 @@ export default class UploadFileDialog extends ResizeResponsiveComponent
this.handleClose()} + this.handleClose()} fullScreen={this.state.fullScreen} style={{userSelect: "none"}} + onEnterKey={()=>{}} > {this.props.title} diff --git a/react/src/WifiConfigDialog.tsx b/react/src/WifiConfigDialog.tsx index 1affb61..886af57 100644 --- a/react/src/WifiConfigDialog.tsx +++ b/react/src/WifiConfigDialog.tsx @@ -223,6 +223,10 @@ const WifiConfigDialog = withStyles(styles, { withTheme: true })( this.state.newPassword; } + onEnterKey() { + this.handleOk(false); + } + handleOk(wifiWarningGiven: boolean) { let hasError = false; if (this.state.autoStartMode !== 0) { @@ -324,6 +328,13 @@ const WifiConfigDialog = withStyles(styles, { withTheme: true })( } return result; } + handleWarningDialogOk() + { + this.setState({ showWifiWarningDialog: false }); + this.handleOk(true); + } + + render() { let props = this.props; let classes = this.props.classes; @@ -334,8 +345,11 @@ const WifiConfigDialog = withStyles(styles, { withTheme: true })( }; let enabled = this.state.autoStartMode !== 0; return ( - { this.handleOk(false); }} + > {(this.state.fullScreen || !this.state.compactHeight) && ( Wi-fi Auto-Hotspot @@ -353,8 +367,8 @@ const WifiConfigDialog = withStyles(styles, { withTheme: true })( }} > - - Auto-start hotspot when + + Auto-start hotspot when...