Wi-Fi Direct alpha
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022 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.
|
||||
*/
|
||||
|
||||
export interface AndroidHostInterface {
|
||||
isAndroidHosted(): boolean;
|
||||
getHostVersion() : string;
|
||||
chooseNewDevice() : void;
|
||||
onLostConnection(): void;
|
||||
|
||||
};
|
||||
|
||||
export class FakeAndroidHost implements AndroidHostInterface
|
||||
{
|
||||
isAndroidHosted(): boolean {
|
||||
return true;
|
||||
}
|
||||
getHostVersion(): string {
|
||||
return "Fake Android 1.0";
|
||||
}
|
||||
chooseNewDevice(): void {
|
||||
|
||||
}
|
||||
onLostConnection(): void {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -36,7 +36,7 @@ declare module '@mui/styles/defaultTheme' {
|
||||
const theme = createTheme({
|
||||
palette: {
|
||||
primary: {
|
||||
main: "#324c6c"
|
||||
main: "#6750A4"
|
||||
},
|
||||
secondary: {
|
||||
main: "#FF6060"
|
||||
|
||||
@@ -292,7 +292,7 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
|
||||
isDrawerOpen: false,
|
||||
errorMessage: this.model_.errorMessage.get(),
|
||||
displayState: this.model_.state.get(),
|
||||
canFullScreen: supportsFullScreen(),
|
||||
canFullScreen: supportsFullScreen() && !this.model_.isAndroidHosted(),
|
||||
isFullScreen: !!document.fullscreenElement,
|
||||
tinyToolBar: false,
|
||||
alertDialogOpen: false,
|
||||
@@ -537,7 +537,10 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
|
||||
setDisplayState(newState: State): void {
|
||||
this.updateOverscroll();
|
||||
|
||||
this.setState({ displayState: newState });
|
||||
this.setState({
|
||||
displayState: newState,
|
||||
canFullScreen: supportsFullScreen() && !this.model_.isAndroidHosted()
|
||||
});
|
||||
}
|
||||
|
||||
showDrawer() {
|
||||
|
||||
@@ -83,7 +83,7 @@ const styles = ({ palette }: Theme) => createStyles({
|
||||
controlContentSmall: {
|
||||
flex: "0 0 162px", width: "100%", height: 162, overflowY: "hidden",
|
||||
},
|
||||
title: { fontSize: "1.3em", fontWeight: 700, marginRight: 8 },
|
||||
title: { fontSize: "1.1em", fontWeight: 700, marginRight: 8 },
|
||||
author: { fontWeight: 500, marginRight: 8 }
|
||||
});
|
||||
|
||||
@@ -103,6 +103,7 @@ interface MainState {
|
||||
horizontalScrollLayout: boolean;
|
||||
showMidiBindingsDialog: boolean;
|
||||
screenHeight: number;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -126,7 +127,7 @@ export const MainPage =
|
||||
splitControlBar: this.windowSize.width < SPLIT_CONTROLBAR_THRESHHOLD,
|
||||
horizontalScrollLayout: this.windowSize.height < HORIZONTAL_CONTROL_SCROLL_HEIGHT_BREAK,
|
||||
showMidiBindingsDialog: false,
|
||||
screenHeight: this.windowSize.height,
|
||||
screenHeight: this.windowSize.height
|
||||
|
||||
};
|
||||
this.onSelectionChanged = this.onSelectionChanged.bind(this);
|
||||
@@ -465,6 +466,7 @@ export const MainPage =
|
||||
onClick={this.onLoadClick}
|
||||
disabled={this.state.selectedPedal === -1 || (this.getSelectedPedalBoardItem()?.isSplit() ?? true)}
|
||||
startIcon={<InputIcon />}
|
||||
style={{ borderRadius: 24, paddingLeft: 18, paddingRight: 18, textTransform: "none"}}
|
||||
>
|
||||
Load
|
||||
</Button>
|
||||
|
||||
+121
-35
@@ -33,9 +33,11 @@ import JackServerSettings from './JackServerSettings';
|
||||
import MidiBinding from './MidiBinding';
|
||||
import { PluginUiPresets } from './PluginPreset';
|
||||
import WifiConfigSettings from './WifiConfigSettings';
|
||||
import WifiDirectConfigSettings from './WifiDirectConfigSettings';
|
||||
import GovernorSettings from './GovernorSettings';
|
||||
import WifiChannel from './WifiChannel';
|
||||
import AlsaDeviceInfo from './AlsaDeviceInfo';
|
||||
import { AndroidHostInterface, FakeAndroidHost } from './AndroidHost';
|
||||
|
||||
|
||||
export enum State {
|
||||
@@ -321,6 +323,7 @@ export interface PiPedalModel {
|
||||
banks: ObservableProperty<BankIndex>;
|
||||
jackServerSettings: ObservableProperty<JackServerSettings>;
|
||||
wifiConfigSettings: ObservableProperty<WifiConfigSettings>;
|
||||
wifiDirectConfigSettings: ObservableProperty<WifiDirectConfigSettings>;
|
||||
governorSettings: ObservableProperty<GovernorSettings>;
|
||||
favorites: ObservableProperty<FavoritesList>;
|
||||
|
||||
@@ -418,6 +421,7 @@ export interface PiPedalModel {
|
||||
uploadBank(file: File, uploadAfter: number): Promise<number>;
|
||||
|
||||
setWifiConfigSettings(wifiConfigSettings: WifiConfigSettings): Promise<void>;
|
||||
setWifiDirectConfigSettings(wifiDirectConfigSettings: WifiDirectConfigSettings): Promise<void>;
|
||||
setGovernorSettings(governor: string): Promise<void>;
|
||||
|
||||
getWifiChannels(countryIso3661: string): Promise<WifiChannel[]>;
|
||||
@@ -428,6 +432,10 @@ export interface PiPedalModel {
|
||||
clearZoomedControl(): void;
|
||||
|
||||
setFavorite(pluginUrl: string, isFavorite: boolean): void;
|
||||
|
||||
isAndroidHosted(): boolean;
|
||||
getAndroidHostVersion(): string;
|
||||
chooseNewDevice(): void;
|
||||
};
|
||||
|
||||
class PiPedalModelImpl implements PiPedalModel {
|
||||
@@ -457,6 +465,7 @@ class PiPedalModelImpl implements PiPedalModel {
|
||||
= new ObservableProperty<JackServerSettings>(new JackServerSettings());
|
||||
|
||||
wifiConfigSettings: ObservableProperty<WifiConfigSettings> = new ObservableProperty<WifiConfigSettings>(new WifiConfigSettings());
|
||||
wifiDirectConfigSettings: ObservableProperty<WifiDirectConfigSettings> = new ObservableProperty<WifiDirectConfigSettings>(new WifiDirectConfigSettings());
|
||||
governorSettings: ObservableProperty<GovernorSettings> = new ObservableProperty<GovernorSettings>(new GovernorSettings());
|
||||
|
||||
favorites: ObservableProperty<FavoritesList> = new ObservableProperty<FavoritesList>({});
|
||||
@@ -484,8 +493,11 @@ class PiPedalModelImpl implements PiPedalModel {
|
||||
return null;
|
||||
}
|
||||
|
||||
androidHost?: AndroidHostInterface;
|
||||
|
||||
constructor() {
|
||||
this.androidHost = (window as any).AndroidHost as AndroidHostInterface;
|
||||
|
||||
this.onSocketError = this.onSocketError.bind(this);
|
||||
this.onSocketMessage = this.onSocketMessage.bind(this);
|
||||
this.onSocketReconnecting = this.onSocketReconnecting.bind(this);
|
||||
@@ -505,23 +517,20 @@ class PiPedalModelImpl implements PiPedalModel {
|
||||
this.onError(errorMessage);
|
||||
}
|
||||
|
||||
compareFavorites(left: FavoritesList, right: FavoritesList): boolean
|
||||
{
|
||||
for (let key of Object.keys(left))
|
||||
{
|
||||
compareFavorites(left: FavoritesList, right: FavoritesList): boolean {
|
||||
for (let key of Object.keys(left)) {
|
||||
if (!right[key]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (let key of Object.keys(right))
|
||||
{
|
||||
for (let key of Object.keys(right)) {
|
||||
if (!left[key]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
|
||||
}
|
||||
onSocketMessage(header: PiPedalMessageHeader, body?: any) {
|
||||
if (this.visibilityState.get() === VisibilityState.Hidden) return;
|
||||
@@ -539,11 +548,9 @@ class PiPedalModelImpl implements PiPedalModel {
|
||||
if (header.replyTo) {
|
||||
this.webSocket?.reply(header.replyTo, "onMonitorPortOutput", true);
|
||||
}
|
||||
} else if (message === "onFavoritesChanged")
|
||||
{
|
||||
} else if (message === "onFavoritesChanged") {
|
||||
let favorites = body as FavoritesList;
|
||||
if (!this.compareFavorites(favorites,this.favorites.get()))
|
||||
{
|
||||
if (!this.compareFavorites(favorites, this.favorites.get())) {
|
||||
this.favorites.set(favorites);
|
||||
}
|
||||
} else if (message === "onChannelSelectionChanged") {
|
||||
@@ -613,6 +620,9 @@ class PiPedalModelImpl implements PiPedalModel {
|
||||
} else if (message === "onWifiConfigSettingsChanged") {
|
||||
let wifiConfigSettings = new WifiConfigSettings().deserialize(body);
|
||||
this.wifiConfigSettings.set(wifiConfigSettings);
|
||||
} else if (message === "onWifiDirectConfigSettingsChanged") {
|
||||
let wifiDirectConfigSettings = new WifiDirectConfigSettings().deserialize(body);
|
||||
this.wifiDirectConfigSettings.set(wifiDirectConfigSettings);
|
||||
}
|
||||
else if (message === "onGovernorSettingsChanged") {
|
||||
let governor = body as string;
|
||||
@@ -704,10 +714,17 @@ class PiPedalModelImpl implements PiPedalModel {
|
||||
.then(data => {
|
||||
this.wifiConfigSettings.set(new WifiConfigSettings().deserialize(data));
|
||||
|
||||
return this.getWebSocket().request<any>("getGovernorSettings");
|
||||
})
|
||||
.then(data => {
|
||||
this.governorSettings.set(new GovernorSettings().deserialize(data));
|
||||
|
||||
return this.getWebSocket().request<any>("getWifiDirectConfigSettings");
|
||||
})
|
||||
.then(data => {
|
||||
this.wifiDirectConfigSettings.set(new WifiDirectConfigSettings().deserialize(data));
|
||||
|
||||
|
||||
return this.getWebSocket().request<any>("getGovernorSettings");
|
||||
})
|
||||
.then(data => {
|
||||
this.governorSettings.set(new GovernorSettings().deserialize(data));
|
||||
|
||||
|
||||
return this.getWebSocket().request<any>("getJackServerSettings");
|
||||
@@ -740,7 +757,7 @@ class PiPedalModelImpl implements PiPedalModel {
|
||||
|
||||
return this.getWebSocket().request<FavoritesList>("getFavorites");
|
||||
})
|
||||
.then((data)=> {
|
||||
.then((data) => {
|
||||
this.favorites.set(data);
|
||||
|
||||
this.setState(State.Ready);
|
||||
@@ -773,6 +790,9 @@ class PiPedalModelImpl implements PiPedalModel {
|
||||
if (data.max_upload_size) {
|
||||
this.maxUploadSize = data.max_upload_size;
|
||||
}
|
||||
if (data.fakeAndroid) {
|
||||
this.androidHost = new FakeAndroidHost();
|
||||
}
|
||||
this.debug = !!data.debug;
|
||||
let { socket_server_port, socket_server_address } = data;
|
||||
if ((!socket_server_address) || socket_server_address === "*") {
|
||||
@@ -843,15 +863,21 @@ class PiPedalModelImpl implements PiPedalModel {
|
||||
})
|
||||
.then((data) => {
|
||||
this.presets.set(new PresetIndex().deserialize(data));
|
||||
|
||||
return this.getWebSocket().request<any>("getWifiConfigSettings");
|
||||
})
|
||||
.then(data => {
|
||||
this.wifiConfigSettings.set(new WifiConfigSettings().deserialize(data));
|
||||
|
||||
return this.getWebSocket().request<any>("getGovernorSettings");
|
||||
})
|
||||
.then(data => {
|
||||
this.governorSettings.set(new GovernorSettings().deserialize(data));
|
||||
return this.getWebSocket().request<any>("getWifiDirectConfigSettings");
|
||||
})
|
||||
.then(data => {
|
||||
this.wifiDirectConfigSettings.set(new WifiDirectConfigSettings().deserialize(data));
|
||||
|
||||
return this.getWebSocket().request<any>("getGovernorSettings");
|
||||
})
|
||||
.then(data => {
|
||||
this.governorSettings.set(new GovernorSettings().deserialize(data));
|
||||
|
||||
|
||||
return this.getWebSocket().request<any>("getJackServerSettings");
|
||||
@@ -876,19 +902,17 @@ class PiPedalModelImpl implements PiPedalModel {
|
||||
})
|
||||
.then((data) => {
|
||||
this.banks.set(new BankIndex().deserialize(data));
|
||||
if (this.webSocket)
|
||||
{
|
||||
if (this.webSocket) {
|
||||
// MUST not allow reconnect until at least one complete load has finished.
|
||||
this.webSocket.canReconnect = true;
|
||||
}
|
||||
|
||||
return this.getWebSocket().request<FavoritesList>("getFavorites");
|
||||
})
|
||||
.then((data)=> {
|
||||
.then((data) => {
|
||||
this.favorites.set(data);
|
||||
|
||||
if (this.webSocket)
|
||||
{
|
||||
if (this.webSocket) {
|
||||
// MUST not allow reconnect until at least one complete load has finished.
|
||||
this.webSocket.canReconnect = true;
|
||||
}
|
||||
@@ -1901,6 +1925,57 @@ class PiPedalModelImpl implements PiPedalModel {
|
||||
});
|
||||
return result;
|
||||
}
|
||||
setWifiDirectConfigSettings(wifiDirectConfigSettings: WifiDirectConfigSettings): Promise<void> {
|
||||
let result = new Promise<void>((resolve, reject) => {
|
||||
let oldSettings = this.wifiDirectConfigSettings.get();
|
||||
wifiDirectConfigSettings = wifiDirectConfigSettings.clone();
|
||||
|
||||
if ((!oldSettings.enable) && (!wifiDirectConfigSettings.enable)) {
|
||||
// no effective change.
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
if (!wifiDirectConfigSettings.enable) {
|
||||
wifiDirectConfigSettings = oldSettings.clone();
|
||||
wifiDirectConfigSettings.enable = false;
|
||||
} else {
|
||||
if (wifiDirectConfigSettings.countryCode === oldSettings.countryCode
|
||||
&& wifiDirectConfigSettings.channel === oldSettings.channel
|
||||
&& wifiDirectConfigSettings.hotspotName === oldSettings.hotspotName
|
||||
&& wifiDirectConfigSettings.enable == oldSettings.enable) {
|
||||
if (wifiDirectConfigSettings.pin === oldSettings.pin) {
|
||||
// no effective change.
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// save a version for the server (potentially carrying a password)
|
||||
let serverConfigSettings = wifiDirectConfigSettings.clone();
|
||||
this.wifiDirectConfigSettings.set(wifiDirectConfigSettings);
|
||||
|
||||
|
||||
|
||||
// notify the server.
|
||||
let ws = this.webSocket;
|
||||
if (!ws) {
|
||||
reject("Not connected.");
|
||||
return;
|
||||
}
|
||||
ws.request<void>(
|
||||
"setWifiDirectConfigSettings",
|
||||
serverConfigSettings
|
||||
)
|
||||
.then(() => {
|
||||
resolve();
|
||||
})
|
||||
.catch((err) => {
|
||||
reject(err);
|
||||
});
|
||||
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
getWifiChannels(countryIso3661: string): Promise<WifiChannel[]> {
|
||||
let result = new Promise<WifiChannel[]>((resolve, reject) => {
|
||||
@@ -1939,24 +2014,20 @@ class PiPedalModelImpl implements PiPedalModel {
|
||||
this.zoomedUiControl.set(undefined);
|
||||
}
|
||||
|
||||
setFavorite(pluginUrl: string, isFavorite: boolean): void
|
||||
{
|
||||
setFavorite(pluginUrl: string, isFavorite: boolean): void {
|
||||
let favorites = this.favorites.get();
|
||||
let newFavorites: FavoritesList = {};
|
||||
Object.assign(newFavorites,favorites);
|
||||
if (isFavorite)
|
||||
{
|
||||
Object.assign(newFavorites, favorites);
|
||||
if (isFavorite) {
|
||||
newFavorites[pluginUrl] = true;
|
||||
} else {
|
||||
if (newFavorites[pluginUrl])
|
||||
{
|
||||
if (newFavorites[pluginUrl]) {
|
||||
delete newFavorites[pluginUrl];
|
||||
}
|
||||
}
|
||||
this.favorites.set(newFavorites);
|
||||
if (this.webSocket)
|
||||
{
|
||||
this.webSocket.send("setFavorites",newFavorites);
|
||||
if (this.webSocket) {
|
||||
this.webSocket.send("setFavorites", newFavorites);
|
||||
}
|
||||
// stub: update server.
|
||||
}
|
||||
@@ -1971,6 +2042,21 @@ class PiPedalModelImpl implements PiPedalModel {
|
||||
}
|
||||
}
|
||||
|
||||
isAndroidHosted(): boolean { return this.androidHost !== undefined; }
|
||||
|
||||
getAndroidHostVersion(): string {
|
||||
if (this.androidHost) {
|
||||
return this.androidHost.getHostVersion();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
chooseNewDevice(): void {
|
||||
if (this.androidHost) {
|
||||
return this.androidHost.chooseNewDevice();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
let instance: PiPedalModel | undefined = undefined;
|
||||
|
||||
+118
-23
@@ -35,13 +35,15 @@ import JackServerSettings from './JackServerSettings';
|
||||
import JackServerSettingsDialog from './JackServerSettingsDialog';
|
||||
import JackHostStatus from './JackHostStatus';
|
||||
import WifiConfigSettings from './WifiConfigSettings';
|
||||
import WifiDirectConfigSettings from './WifiDirectConfigSettings';
|
||||
import WifiConfigDialog from './WifiConfigDialog';
|
||||
import WifiDirectConfigDialog from './WifiDirectConfigDialog';
|
||||
import DialogEx from './DialogEx'
|
||||
import GovernorSettings from './GovernorSettings';
|
||||
|
||||
import Slide, {SlideProps} from '@mui/material/Slide';
|
||||
import Slide, { SlideProps } from '@mui/material/Slide';
|
||||
import { createStyles, Theme } from '@mui/material/styles';
|
||||
import { WithStyles, withStyles} from '@mui/styles';
|
||||
import { WithStyles, withStyles } from '@mui/styles';
|
||||
|
||||
|
||||
|
||||
@@ -60,8 +62,10 @@ interface SettingsDialogState {
|
||||
governorSettings: GovernorSettings;
|
||||
|
||||
wifiConfigSettings: WifiConfigSettings;
|
||||
wifiDirectConfigSettings: WifiDirectConfigSettings;
|
||||
|
||||
showWifiConfigDialog: boolean;
|
||||
showWifiDirectConfigDialog: boolean;
|
||||
showGovernorSettingsDialog: boolean;
|
||||
showInputSelectDialog: boolean;
|
||||
showOutputSelectDialog: boolean;
|
||||
@@ -69,6 +73,7 @@ interface SettingsDialogState {
|
||||
showJackServerSettingsDialog: boolean;
|
||||
shuttingDown: boolean;
|
||||
restarting: boolean;
|
||||
isAndroidHosted: boolean;
|
||||
};
|
||||
|
||||
|
||||
@@ -150,15 +155,19 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
jackStatus: undefined,
|
||||
jackSettings: this.model.jackSettings.get(),
|
||||
wifiConfigSettings: this.model.wifiConfigSettings.get(),
|
||||
governorSettings: this.model.governorSettings.get(),
|
||||
wifiDirectConfigSettings: this.model.wifiDirectConfigSettings.get(),
|
||||
governorSettings: this.model.governorSettings.get(),
|
||||
showWifiConfigDialog: false,
|
||||
showWifiDirectConfigDialog: false,
|
||||
showGovernorSettingsDialog: false,
|
||||
showInputSelectDialog: false,
|
||||
showOutputSelectDialog: false,
|
||||
showMidiSelectDialog: false,
|
||||
showJackServerSettingsDialog: false,
|
||||
shuttingDown: false,
|
||||
restarting: false
|
||||
restarting: false,
|
||||
isAndroidHosted: this.model.isAndroidHosted()
|
||||
|
||||
|
||||
|
||||
};
|
||||
@@ -166,6 +175,7 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
this.handleJackSettingsChanged = this.handleJackSettingsChanged.bind(this);
|
||||
this.handleJackServerSettingsChanged = this.handleJackServerSettingsChanged.bind(this);
|
||||
this.handleWifiConfigSettingsChanged = this.handleWifiConfigSettingsChanged.bind(this);
|
||||
this.handleWifiDirectConfigSettingsChanged = this.handleWifiDirectConfigSettingsChanged.bind(this);
|
||||
this.handleGovernorSettingsChanged = this.handleGovernorSettingsChanged.bind(this);
|
||||
this.handleConnectionStateChanged = this.handleConnectionStateChanged.bind(this);
|
||||
|
||||
@@ -173,6 +183,7 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
|
||||
handleConnectionStateChanged(): void {
|
||||
if (this.model.state.get() === State.Ready) {
|
||||
this.setState({ isAndroidHosted: this.model.isAndroidHosted() });
|
||||
if (this.state.shuttingDown || this.state.restarting) {
|
||||
this.setState({ shuttingDown: false, restarting: false });
|
||||
}
|
||||
@@ -189,6 +200,18 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
this.model.showAlert(err);
|
||||
});
|
||||
}
|
||||
|
||||
handleApplyWifiDirectConfig(wifiDirectConfigSettings: WifiDirectConfigSettings): void {
|
||||
this.setState({ showWifiDirectConfigDialog: false });
|
||||
this.model.setWifiDirectConfigSettings(wifiDirectConfigSettings)
|
||||
.then(() => {
|
||||
|
||||
})
|
||||
.catch((err) => {
|
||||
this.model.showAlert(err);
|
||||
});
|
||||
}
|
||||
|
||||
handleApplyGovernorSettings(governor: string): void {
|
||||
this.model.setGovernorSettings(governor)
|
||||
.then(() => {
|
||||
@@ -206,6 +229,14 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
}
|
||||
)
|
||||
}
|
||||
handleWifiDirectConfigSettingsChanged(): void {
|
||||
this.setState(
|
||||
{
|
||||
wifiDirectConfigSettings: this.model.wifiDirectConfigSettings.get()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
handleGovernorSettingsChanged(): void {
|
||||
this.setState(
|
||||
{
|
||||
@@ -257,6 +288,7 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
this.model.jackConfiguration.addOnChangedHandler(this.handleJackConfigurationChanged);
|
||||
this.model.jackServerSettings.addOnChangedHandler(this.handleJackServerSettingsChanged);
|
||||
this.model.wifiConfigSettings.addOnChangedHandler(this.handleWifiConfigSettingsChanged);
|
||||
this.model.wifiDirectConfigSettings.addOnChangedHandler(this.handleWifiDirectConfigSettingsChanged);
|
||||
this.model.governorSettings.addOnChangedHandler(this.handleGovernorSettingsChanged);
|
||||
this.model.getJackStatus()
|
||||
.then((jackStatus) =>
|
||||
@@ -276,6 +308,7 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
this.handleJackSettingsChanged();
|
||||
this.handleJackServerSettingsChanged();
|
||||
this.handleWifiConfigSettingsChanged();
|
||||
this.handleWifiDirectConfigSettingsChanged();
|
||||
this.timerHandle = setInterval(() => this.tick(), 1000);
|
||||
} else {
|
||||
if (this.timerHandle) {
|
||||
@@ -286,7 +319,8 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
this.model.jackSettings.removeOnChangedHandler(this.handleJackSettingsChanged);
|
||||
this.model.jackServerSettings.removeOnChangedHandler(this.handleJackServerSettingsChanged);
|
||||
this.model.wifiConfigSettings.removeOnChangedHandler(this.handleWifiConfigSettingsChanged);
|
||||
this.model.wifiConfigSettings.removeOnChangedHandler(this.handleGovernorSettingsChanged);
|
||||
this.model.wifiDirectConfigSettings.removeOnChangedHandler(this.handleWifiDirectConfigSettingsChanged);
|
||||
this.model.governorSettings.removeOnChangedHandler(this.handleGovernorSettingsChanged);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -340,7 +374,7 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
let newSelection = this.state.jackSettings.clone();
|
||||
newSelection.inputMidiPorts = channels;
|
||||
this.model.setJackSettings(newSelection);
|
||||
|
||||
|
||||
}
|
||||
this.setState({
|
||||
showMidiSelectDialog: false,
|
||||
@@ -385,6 +419,11 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
showWifiConfigDialog: true
|
||||
});
|
||||
}
|
||||
handleShowWifiDirectConfigDialog() {
|
||||
this.setState({
|
||||
showWifiDirectConfigDialog: true
|
||||
});
|
||||
}
|
||||
handleShowGovernorSettingsDialogDialog() {
|
||||
this.setState({
|
||||
showGovernorSettingsDialog: true
|
||||
@@ -461,7 +500,7 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
(
|
||||
<div style={{ paddingLeft: 48, position: "relative", top: -12 }}>
|
||||
{JackHostStatus.getDisplayView("", this.state.jackStatus)}
|
||||
{ JackHostStatus.getCpuInfo("Governor:\u00A0", this.state.jackStatus)}
|
||||
{JackHostStatus.getCpuInfo("Governor:\u00A0", this.state.jackStatus)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -534,8 +573,42 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
</div>
|
||||
<Divider />
|
||||
<div >
|
||||
<Typography className={classes.sectionHead} display="block" variant="caption" color="secondary">SYSTEM</Typography>
|
||||
<Typography className={classes.sectionHead} display="block" variant="caption" color="secondary">CONNECTION</Typography>
|
||||
|
||||
{
|
||||
this.state.isAndroidHosted &&
|
||||
(
|
||||
<ButtonBase className={classes.setting} disabled={!this.state.wifiConfigSettings.valid}
|
||||
onClick={() => this.model.chooseNewDevice() } >
|
||||
<SelectHoverBackground selected={false} showHover={true} />
|
||||
<div style={{ width: "100%" }}>
|
||||
<Typography className={classes.primaryItem} display="block" variant="body2" color="textPrimary" noWrap>
|
||||
Connect to a difference device</Typography>
|
||||
<Typography display="block" variant="caption" noWrap color="textSecondary">
|
||||
|
||||
</Typography>
|
||||
|
||||
</div>
|
||||
</ButtonBase>
|
||||
)
|
||||
}
|
||||
|
||||
<ButtonBase
|
||||
className={classes.setting} disabled={!this.state.wifiConfigSettings.valid}
|
||||
onClick={() => this.handleShowWifiDirectConfigDialog()} >
|
||||
<SelectHoverBackground selected={false} showHover={true} />
|
||||
<div style={{ width: "100%" }}>
|
||||
<Typography className={classes.primaryItem} display="block" variant="body2" color="textPrimary" noWrap>
|
||||
Configure Wi-Fi Direct hotspot</Typography>
|
||||
<Typography display="block" variant="caption" noWrap color="textSecondary">
|
||||
{this.state.wifiDirectConfigSettings.getSummaryText()}
|
||||
</Typography>
|
||||
|
||||
</div>
|
||||
</ButtonBase>
|
||||
|
||||
<ButtonBase className={classes.setting} disabled={!this.state.wifiConfigSettings.valid}
|
||||
style={{ display: "none" }}
|
||||
onClick={() => this.handleShowWifiConfigDialog()} >
|
||||
<SelectHoverBackground selected={false} showHover={true} />
|
||||
<div style={{ width: "100%" }}>
|
||||
@@ -547,8 +620,13 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
|
||||
</div>
|
||||
</ButtonBase>
|
||||
</div>
|
||||
<Divider />
|
||||
<div >
|
||||
<Typography className={classes.sectionHead} display="block" variant="caption" color="secondary">SYSTEM</Typography>
|
||||
|
||||
<ButtonBase
|
||||
style={{display: "none"}}
|
||||
style={{ display: "none" }}
|
||||
className={classes.setting} disabled={!this.state.wifiConfigSettings.valid}
|
||||
onClick={() => this.handleShowGovernorSettingsDialogDialog()} >
|
||||
<SelectHoverBackground selected={false} showHover={true} />
|
||||
@@ -556,13 +634,26 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
<Typography className={classes.primaryItem} display="block" variant="body2" color="textPrimary" noWrap>
|
||||
CPU Governor</Typography>
|
||||
<Typography display="block" variant="caption" noWrap color="textSecondary">
|
||||
{this.state.governorSettings.governor }
|
||||
{this.state.governorSettings.governor}
|
||||
</Typography>
|
||||
|
||||
</div>
|
||||
</ButtonBase>
|
||||
|
||||
|
||||
|
||||
<ButtonBase
|
||||
className={classes.setting} disabled={!this.state.wifiConfigSettings.valid}
|
||||
onClick={() => this.handleShowGovernorSettingsDialogDialog()} >
|
||||
<SelectHoverBackground selected={false} showHover={true} />
|
||||
<div style={{ width: "100%" }}>
|
||||
<Typography className={classes.primaryItem} display="block" variant="body2" color="textPrimary" noWrap>
|
||||
Show status monitor on main screen.</Typography>
|
||||
<Typography display="block" variant="caption" noWrap color="textSecondary">
|
||||
Enabled
|
||||
</Typography>
|
||||
|
||||
</div>
|
||||
</ButtonBase>
|
||||
|
||||
<ButtonBase className={classes.setting} disabled={disableShutdown}
|
||||
onClick={() => this.handleRestart()} >
|
||||
<SelectHoverBackground selected={false} showHover={true} />
|
||||
@@ -571,7 +662,7 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
this.state.restarting ? (
|
||||
<Typography className={classes.primaryItem} display="block" variant="body2" color="textSecondary" noWrap>Rebooting...</Typography>
|
||||
) : (
|
||||
<Typography className={classes.primaryItem} display="block" variant="body2" noWrap>Reboot</Typography>
|
||||
<Typography className={classes.primaryItem} display="block" variant="body2" noWrap>Reboot PiPedal</Typography>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
@@ -610,25 +701,25 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
{
|
||||
(this.state.showGovernorSettingsDialog) &&
|
||||
(
|
||||
<ListSelectDialog
|
||||
<ListSelectDialog
|
||||
width={220}
|
||||
open={this.state.showGovernorSettingsDialog}
|
||||
items={this.state.governorSettings.governors}
|
||||
selectedItem={this.state.governorSettings.governor}
|
||||
title="Governor"
|
||||
onClose={()=> this.setState({showGovernorSettingsDialog: false})}
|
||||
onClose={() => this.setState({ showGovernorSettingsDialog: false })}
|
||||
onOk={(selectedValue) => {
|
||||
this.model.setGovernorSettings(selectedValue)
|
||||
.then(()=>{
|
||||
.then(() => {
|
||||
|
||||
})
|
||||
.catch(error => {
|
||||
this.model.showAlert(error);
|
||||
});
|
||||
|
||||
this.setState({showGovernorSettingsDialog: false})
|
||||
})
|
||||
.catch(error => {
|
||||
this.model.showAlert(error);
|
||||
});
|
||||
|
||||
this.setState({ showGovernorSettingsDialog: false })
|
||||
}}
|
||||
>
|
||||
>
|
||||
</ListSelectDialog>
|
||||
)
|
||||
|
||||
@@ -648,6 +739,10 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
onClose={() => this.setState({ showWifiConfigDialog: false })}
|
||||
onOk={(wifiConfigSettings) => this.handleApplyWifiConfig(wifiConfigSettings)}
|
||||
/>
|
||||
<WifiDirectConfigDialog wifiDirectConfigSettings={this.state.wifiDirectConfigSettings} open={this.state.showWifiDirectConfigDialog}
|
||||
onClose={() => this.setState({ showWifiDirectConfigDialog: false })}
|
||||
onOk={(wifiDirectConfigSettings: WifiDirectConfigSettings) => this.handleApplyWifiDirectConfig(wifiDirectConfigSettings)}
|
||||
/>
|
||||
|
||||
</DialogEx >
|
||||
|
||||
|
||||
@@ -39,8 +39,8 @@ const drawerStyles = (theme: Theme) => {
|
||||
},
|
||||
|
||||
drawer_header: {
|
||||
color: 'white',
|
||||
background: theme.palette.primary.main,
|
||||
color: theme.palette.primary.main,
|
||||
background: 'white',
|
||||
|
||||
}
|
||||
})};
|
||||
|
||||
@@ -0,0 +1,400 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022 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 Button from '@mui/material/Button';
|
||||
import TextField from '@mui/material/TextField';
|
||||
import DialogEx from './DialogEx';
|
||||
import DialogActions from '@mui/material/DialogActions';
|
||||
import DialogContent from '@mui/material/DialogContent';
|
||||
import DialogTitle from '@mui/material/DialogTitle';
|
||||
import Switch from '@mui/material/Switch';
|
||||
import FormControlLabel from '@mui/material/FormControlLabel';
|
||||
import ResizeResponsiveComponent from './ResizeResponsiveComponent';
|
||||
import WifiDirectConfigSettings from './WifiDirectConfigSettings';
|
||||
import { Theme } from '@mui/material/styles';
|
||||
import { WithStyles } from '@mui/styles';
|
||||
import withStyles from '@mui/styles/withStyles';
|
||||
import createStyles from '@mui/styles/createStyles';
|
||||
import Select from '@mui/material/Select';
|
||||
import FormControl from '@mui/material/FormControl';
|
||||
import InputLabel from '@mui/material/InputLabel';
|
||||
import MenuItem from '@mui/material/MenuItem';
|
||||
import WifiChannel from './WifiChannel';
|
||||
import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel';
|
||||
|
||||
const styles = (theme: Theme) => createStyles({
|
||||
pgraph: {
|
||||
paddingBottom: 16
|
||||
}
|
||||
});
|
||||
|
||||
declare let crypto: any;
|
||||
|
||||
const NBSP = "\u00A0";
|
||||
|
||||
export interface WifiDirectConfigProps extends WithStyles<typeof styles> {
|
||||
open: boolean,
|
||||
wifiDirectConfigSettings: WifiDirectConfigSettings,
|
||||
onOk: (wifiDirectConfigSettings: WifiDirectConfigSettings) => void,
|
||||
onClose: () => void
|
||||
}
|
||||
|
||||
export interface WifiDirectConfigState {
|
||||
fullScreen: boolean;
|
||||
enabled: boolean;
|
||||
name: string;
|
||||
pin: string;
|
||||
nameError: boolean;
|
||||
nameErrorMessage: string;
|
||||
pinError: boolean;
|
||||
pinErrorMessage: string;
|
||||
countryCode: string;
|
||||
channel: string;
|
||||
wifiChannels: WifiChannel[];
|
||||
}
|
||||
|
||||
|
||||
|
||||
const WifiDirectConfigDialog = withStyles(styles, { withTheme: true })(
|
||||
class extends ResizeResponsiveComponent<WifiDirectConfigProps, WifiDirectConfigState> {
|
||||
|
||||
refName: React.RefObject<HTMLInputElement>;
|
||||
refPassword: React.RefObject<HTMLInputElement>;
|
||||
model: PiPedalModel;
|
||||
|
||||
constructor(props: WifiDirectConfigProps) {
|
||||
super(props);
|
||||
this.model = PiPedalModelFactory.getInstance();
|
||||
this.state = {
|
||||
fullScreen: false,
|
||||
enabled: this.props.wifiDirectConfigSettings.enable,
|
||||
name: this.props.wifiDirectConfigSettings.hotspotName,
|
||||
pin: this.props.wifiDirectConfigSettings.pin,
|
||||
nameError: false,
|
||||
nameErrorMessage: NBSP,
|
||||
pinError: false,
|
||||
pinErrorMessage: NBSP,
|
||||
countryCode: this.props.wifiDirectConfigSettings.countryCode,
|
||||
channel: this.props.wifiDirectConfigSettings.channel,
|
||||
wifiChannels: []
|
||||
};
|
||||
this.model.getWifiChannels(this.props.wifiDirectConfigSettings.countryCode)
|
||||
.then((wifiChannels_) => {
|
||||
this.setState({ wifiChannels: wifiChannels_ });
|
||||
}).catch((err) => { });
|
||||
|
||||
this.refName = React.createRef<HTMLInputElement>();
|
||||
this.refPassword = React.createRef<HTMLInputElement>();
|
||||
}
|
||||
mounted: boolean = false;
|
||||
|
||||
handleEnableChanged(e: any) {
|
||||
this.setState({ enabled: e.target.checked });
|
||||
}
|
||||
|
||||
|
||||
onWindowSizeChanged(width: number, height: number): void {
|
||||
this.setState({ fullScreen: height < 200 })
|
||||
}
|
||||
|
||||
|
||||
componentDidMount() {
|
||||
super.componentDidMount();
|
||||
this.mounted = true;
|
||||
}
|
||||
componentWillUnmount() {
|
||||
super.componentWillUnmount();
|
||||
this.mounted = false;
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps: WifiDirectConfigProps) {
|
||||
|
||||
if (this.props.open && !prevProps.open) {
|
||||
this.setState({
|
||||
enabled: this.props.wifiDirectConfigSettings.enable,
|
||||
name: this.props.wifiDirectConfigSettings.hotspotName,
|
||||
pin: this.props.wifiDirectConfigSettings.pin,
|
||||
countryCode: this.props.wifiDirectConfigSettings.countryCode,
|
||||
channel: this.props.wifiDirectConfigSettings.channel
|
||||
});
|
||||
|
||||
if (this.props.wifiDirectConfigSettings.countryCode !== this.state.countryCode) {
|
||||
this.model.getWifiChannels(this.props.wifiDirectConfigSettings.countryCode)
|
||||
.then((wifiChannels) => {
|
||||
this.setState({ wifiChannels: wifiChannels });
|
||||
})
|
||||
.catch((error) => { });
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
utf8Encode: TextEncoder = new TextEncoder();
|
||||
|
||||
validateName(name: string): void {
|
||||
if (name.length === 0) {
|
||||
throw new RangeError("Required.");
|
||||
}
|
||||
let bytes = this.utf8Encode.encode("DIRECT-XX-" + name);
|
||||
if (bytes.length > 31) {
|
||||
throw new RangeError("Too long.");
|
||||
}
|
||||
}
|
||||
validatePin(pin: string) {
|
||||
if (pin.length === 0) throw new Error("Required.");
|
||||
if (pin.length !== 8) {
|
||||
throw new RangeError("Must be exactly 8 digits.");
|
||||
}
|
||||
for (let i = 0; i < pin.length; ++i) {
|
||||
let c = pin.charCodeAt(i);
|
||||
if (c < '0'.charCodeAt(0) || c > '9'.charCodeAt(0)) {
|
||||
throw new RangeError("Must be exactly 8 digits.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handleOk() {
|
||||
let nameError = false;
|
||||
let nameErrorMessage = NBSP;
|
||||
let pinError = false;
|
||||
let pinErrorMessage = NBSP;
|
||||
if (this.state.enabled) {
|
||||
let name = this.state.name;
|
||||
try {
|
||||
this.validateName(name);
|
||||
} catch (e: any) {
|
||||
nameError = true; nameErrorMessage = "* " + e.message;
|
||||
}
|
||||
let pin = this.state.pin;
|
||||
try {
|
||||
this.validatePin(pin);
|
||||
} catch (e: any) {
|
||||
pinError = true; pinErrorMessage = "* " + e.message;
|
||||
}
|
||||
|
||||
let error = pinError || nameError || this.state.countryCode === "";
|
||||
if (error) {
|
||||
this.setState({ nameError: nameError, nameErrorMessage: nameErrorMessage, pinError: pinError, pinErrorMessage: pinErrorMessage });
|
||||
} else {
|
||||
let wifiDirectConfigSettings = new WifiDirectConfigSettings();
|
||||
wifiDirectConfigSettings.valid = true;
|
||||
|
||||
wifiDirectConfigSettings.enable = this.state.enabled;
|
||||
wifiDirectConfigSettings.hotspotName = this.state.name;
|
||||
wifiDirectConfigSettings.countryCode = this.state.countryCode;
|
||||
wifiDirectConfigSettings.channel = this.state.channel;
|
||||
wifiDirectConfigSettings.pin = this.state.pin;
|
||||
this.props.onOk(wifiDirectConfigSettings);
|
||||
}
|
||||
} else {
|
||||
let wifiDirectConfigSettings = new WifiDirectConfigSettings();
|
||||
wifiDirectConfigSettings.valid = true;
|
||||
wifiDirectConfigSettings.enable = false;
|
||||
this.props.onOk(wifiDirectConfigSettings);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
preventPasswordPrompt() {
|
||||
}
|
||||
handleChannelChange(e: any) {
|
||||
let value = e.target.value as string;
|
||||
this.setState({ channel: value });
|
||||
}
|
||||
handleCountryChanged(e: any) {
|
||||
let value = e.target.value as string;
|
||||
|
||||
this.setState({ countryCode: value });
|
||||
this.model.getWifiChannels(value)
|
||||
.then(wifiChannels => {
|
||||
this.setState({ wifiChannels: wifiChannels });
|
||||
})
|
||||
.catch((error) => { });
|
||||
}
|
||||
|
||||
generateRandomPin(): string {
|
||||
// prefer crypto if it's available.
|
||||
let zero = "0".charCodeAt(0);
|
||||
try {
|
||||
let randomValue = new Int32Array(8);
|
||||
crypto.getRandomValues(randomValue);
|
||||
|
||||
let s: string = "";
|
||||
for (let i = 0; i < 8; ++i) {
|
||||
let k = randomValue[i];
|
||||
if (k < 0) k = -k;
|
||||
k = k % 10;
|
||||
|
||||
s += String.fromCharCode(zero + k);
|
||||
}
|
||||
return s;
|
||||
|
||||
} catch (e) {
|
||||
|
||||
}
|
||||
let zero2 = "a".charCodeAt(0);
|
||||
let s2 = "";
|
||||
for (let i = 0; i < 8; ++i) {
|
||||
let k = Math.floor(Math.random() * 10);
|
||||
if (k < 0) k = -k;
|
||||
k = k % 10;
|
||||
|
||||
s2 += String.fromCharCode(zero2 + k);
|
||||
}
|
||||
return s2;
|
||||
}
|
||||
|
||||
onGenerateRandomPin() {
|
||||
let newPin = this.generateRandomPin();
|
||||
this.setState({ pin: newPin, pinError: false, pinErrorMessage: NBSP });
|
||||
if (this.refPassword.current) {
|
||||
this.refPassword.current.value = newPin;
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
let props = this.props;
|
||||
let { open, onClose } = props;
|
||||
|
||||
const handleClose = () => {
|
||||
this.preventPasswordPrompt();
|
||||
// let preventPasswordPrompt changes settle (it's HARD to prevent a password prompt)
|
||||
setTimeout(() => {
|
||||
onClose();
|
||||
}, 100);
|
||||
};
|
||||
|
||||
return (
|
||||
<DialogEx tag="WifiDirectConfigDialog" open={open} fullWidth onClose={handleClose} style={{ userSelect: "none" }}
|
||||
fullScreen={this.state.fullScreen}
|
||||
>
|
||||
{this.state.fullScreen && (
|
||||
<DialogTitle>Wi-fi Hotspot</DialogTitle>
|
||||
)}
|
||||
<DialogContent>
|
||||
|
||||
<FormControlLabel
|
||||
control={(
|
||||
<Switch
|
||||
checked={this.state.enabled}
|
||||
onChange={(e: any) => this.handleEnableChanged(e)}
|
||||
color="secondary"
|
||||
/>
|
||||
)}
|
||||
label="Enable Wi-Fi Direct Hotspot"
|
||||
/>
|
||||
<div style={{ marginTop: 16 }}>
|
||||
<TextField
|
||||
required
|
||||
autoComplete="off"
|
||||
id="name"
|
||||
spellCheck="false"
|
||||
label="SSID"
|
||||
type="text"
|
||||
fullWidth
|
||||
error={this.state.nameError}
|
||||
helperText={this.state.nameErrorMessage}
|
||||
value={this.state.name}
|
||||
onChange={(e) => this.setState({ name: e.target.value, nameError: false, nameErrorMessage: NBSP })}
|
||||
inputRef={this.refName}
|
||||
disabled={!this.state.enabled}
|
||||
variant="filled"
|
||||
/>
|
||||
</div>
|
||||
<div style={{ marginBottom: 0, verticalAlign: "baseline" }}>
|
||||
<TextField
|
||||
inputRef={this.refPassword}
|
||||
autoComplete="off"
|
||||
onChange={(e): void => { this.setState({ pin: e.target.value, pinError: false, pinErrorMessage: NBSP }); }}
|
||||
label="Pin"
|
||||
error={this.state.pinError}
|
||||
helperText={this.state.pinErrorMessage}
|
||||
defaultValue={this.state.pin}
|
||||
disabled={!this.state.enabled}
|
||||
variant="filled"
|
||||
/>
|
||||
<FormControl>
|
||||
<div style={{ marginLeft: 16, marginTop: 18 }}>
|
||||
<Button size="medium" disabled={!this.state.enabled}
|
||||
onClick={() => this.onGenerateRandomPin()}
|
||||
>Generate random pin</Button>
|
||||
</div>
|
||||
</FormControl>
|
||||
</div>
|
||||
<div style={{ marginBottom: 24 }}>
|
||||
<FormControl variant="filled" sx={{ minWidth: 330 }}>
|
||||
<InputLabel htmlFor="countryCodeSelect">Country</InputLabel>
|
||||
<Select id="countryCodeSelect" label="Country" value={this.state.countryCode} disabled={!this.state.enabled}
|
||||
onChange={(event) => this.handleCountryChanged(event)} >
|
||||
{Object.entries(this.model.countryCodes).map(([key, value]) => {
|
||||
return (
|
||||
<MenuItem value={key}>{value}</MenuItem>
|
||||
);
|
||||
})}
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
<div style={{ marginBottom: 24 }}>
|
||||
<FormControl variant="filled" sx={{ minWidth: 330 }} >
|
||||
<InputLabel htmlFor="channelSelect">Channel</InputLabel>
|
||||
<Select id="channelSelect" label="Channel" value={this.state.channel} disabled={!this.state.enabled} onChange={(e) => {
|
||||
this.handleChannelChange(e);
|
||||
}}>
|
||||
{this.state.wifiChannels.map((channel) => {
|
||||
let t = channel.channelId;
|
||||
if (t.startsWith("a")) t = t.substring(1);
|
||||
if (t.startsWith("g")) t = t.substring(1);
|
||||
let name = channel.channelName;
|
||||
if (name.startsWith("1 ") || name.startsWith("6 ") || name.startsWith("11 ")) {
|
||||
name += " *Recommended";
|
||||
}
|
||||
return (
|
||||
<MenuItem value={t}>{name}</MenuItem>
|
||||
)
|
||||
})}
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
</div>
|
||||
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={handleClose} color="primary" style={{ width: 120 }}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button onClick={() => this.handleOk()} color="secondary" style={{ width: 120 }} >
|
||||
OK
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</DialogEx>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default WifiDirectConfigDialog;
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022 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.
|
||||
*/
|
||||
|
||||
|
||||
export default class WifiDirectConfigSettings {
|
||||
deserialize(input: any) : WifiDirectConfigSettings{
|
||||
this.valid = input.valid;
|
||||
this.rebootRequired = input.rebootRequired;
|
||||
this.enable = input.enable;
|
||||
this.pinChanged = input.pinChanged;
|
||||
this.hotspotName = input.hotspotName;
|
||||
this.countryCode = input.countryCode;
|
||||
this.pin = input.pin;
|
||||
this.channel = input.channel;
|
||||
|
||||
return this;
|
||||
}
|
||||
clone() : WifiDirectConfigSettings {
|
||||
return new WifiDirectConfigSettings().deserialize(this);
|
||||
}
|
||||
valid: boolean = true;
|
||||
enable: boolean = true;
|
||||
rebootRequired = false;
|
||||
hotspotName: string = "pipedal";
|
||||
pinChanged: boolean = false;
|
||||
pin: string = "";
|
||||
countryCode: string = "US";
|
||||
channel: string = "6";
|
||||
|
||||
getSummaryText() {
|
||||
let result: string;
|
||||
if (!this.valid) {
|
||||
result = "Not available.";
|
||||
} else if (!this.enable) {
|
||||
result = "Disabled.";
|
||||
} else {
|
||||
result = this.hotspotName;
|
||||
}
|
||||
if (this.rebootRequired)
|
||||
{
|
||||
result += " (Restart required)";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user