From 461767b26b9c4d3d30bfc42442daacf022ff7957 Mon Sep 17 00:00:00 2001 From: Electromuis Date: Tue, 14 May 2024 13:22:04 +0200 Subject: [PATCH 1/3] Added wifi dropdown to the wizzard --- gui/public/i18n/en/translation.ftl | 3 + gui/src-tauri/capabilities/migrated.json | 52 +++- .../components/onboarding/pages/WifiCreds.tsx | 41 ++- gui/src/hooks/wifi-form.tsx | 25 +- gui/src/hooks/wifi-scan.ts | 251 ++++++++++++++++++ 5 files changed, 368 insertions(+), 4 deletions(-) create mode 100644 gui/src/hooks/wifi-scan.ts diff --git a/gui/public/i18n/en/translation.ftl b/gui/public/i18n/en/translation.ftl index ce4026ce68..802e4e9732 100644 --- a/gui/public/i18n/en/translation.ftl +++ b/gui/public/i18n/en/translation.ftl @@ -577,6 +577,9 @@ onboarding-wifi_creds-submit = Submit! onboarding-wifi_creds-ssid = .label = Wi-Fi name .placeholder = Enter Wi-Fi name +onboarding-wifi_creds-ssidSelect = + .placeholder = Select your Wi-Fi network +onboarding-wifi_creds-ssidSelect-label = Wi-Fi network onboarding-wifi_creds-password = .label = Password .placeholder = Enter password diff --git a/gui/src-tauri/capabilities/migrated.json b/gui/src-tauri/capabilities/migrated.json index 834fa4b619..ce6c1aa163 100644 --- a/gui/src-tauri/capabilities/migrated.json +++ b/gui/src-tauri/capabilities/migrated.json @@ -28,6 +28,56 @@ "store:allow-get", "store:allow-set", "store:allow-save", - "fs:allow-write-text-file" + "fs:allow-write-text-file", + { + "identifier": "shell:allow-execute", + "allow": [ + { + "name": "netsh-list", + "cmd": "netsh", + "args": [ + "wlan", + "show", + "profile" + ], + "sidecar": false + }, + { + "name": "netsh-scan", + "cmd": "netsh", + "args": [ + "wlan", + "show", + "network", + "mode=Bssid" + ], + "sidecar": false + }, + { + "name": "netsh-details", + "cmd": "netsh", + "args": [ + "wlan", + "show", + "profile", + { + "validator": "name=\\S+" + }, + "key=clear" + ], + "sidecar": false + }, + { + "name": "netsh-connected", + "cmd": "netsh", + "args": [ + "wlan", + "show", + "interfaces" + ], + "sidecar": false + } + ] + } ] } diff --git a/gui/src/components/onboarding/pages/WifiCreds.tsx b/gui/src/components/onboarding/pages/WifiCreds.tsx index b865d0fba1..1d3de8ca02 100644 --- a/gui/src/components/onboarding/pages/WifiCreds.tsx +++ b/gui/src/components/onboarding/pages/WifiCreds.tsx @@ -1,8 +1,10 @@ +import { useMemo } from 'react'; import { Localized, useLocalization } from '@fluent/react'; import { useOnboarding } from '@/hooks/onboarding'; import { useWifiForm } from '@/hooks/wifi-form'; import { Button } from '@/components/commons/Button'; import { Input } from '@/components/commons/Input'; +import { Dropdown } from '@/components/commons/Dropdown'; import { Typography } from '@/components/commons/Typography'; import classNames from 'classnames'; import { useTrackers } from '@/hooks/tracker'; @@ -11,7 +13,7 @@ import { useBnoExists } from '@/hooks/imu-logic'; export function WifiCredsPage() { const { l10n } = useLocalization(); const { applyProgress, state } = useOnboarding(); - const { control, handleSubmit, submitWifiCreds, formState } = useWifiForm(); + const { control, handleSubmit, submitWifiCreds, formState, wifiNetworks, watch } = useWifiForm(); const { useConnectedIMUTrackers } = useTrackers(); const connectedIMUTrackers = useConnectedIMUTrackers(); @@ -19,6 +21,18 @@ export function WifiCredsPage() { const bnoExists = useBnoExists(connectedIMUTrackers); + const wifiNetworksDropdownItems = useMemo(() => { + const networksMapped = wifiNetworks.map((network) => ({ + label: network.ssid, + value: network.ssid, + })); + + return [ + ...networksMapped, + { label: 'Other', value: 'other' }, + ]; + }, [wifiNetworks]); + return (
+ + {wifiNetworks.length > 0 && <> + + {l10n.getString('onboarding-wifi_creds-ssidSelect-label')} + + + + } + + {(wifiNetworks.length === 0 || watch('ssidSelect') == 'other') && @@ -70,7 +106,8 @@ export function WifiCredsPage() { placeholder="ssid" variant="secondary" /> - + } + ({ defaultValues: {}, reValidateMode: 'onSubmit', }); + const { wifiNetworks } = useWifiNetworks(); + + const ssidSelect = watch('ssidSelect'); + useEffect(() => { + if(ssidSelect === 'other') { + setValue('ssid', ''); + setValue('password', ''); + return; + } + + const network = wifiNetworks.find((network) => network.ssid === ssidSelect); + + if(!network) + return; + + setValue('ssid', network.ssid); + setValue('password', network.password); + }, [ssidSelect]); + useEffect(() => { if (state.wifi) { reset({ @@ -38,7 +59,9 @@ export function useWifiForm() { handleSubmit, register, formState, + wifiNetworks, hasWifiCreds: !!state.wifi, control, + watch, }; } diff --git a/gui/src/hooks/wifi-scan.ts b/gui/src/hooks/wifi-scan.ts new file mode 100644 index 0000000000..1052e76832 --- /dev/null +++ b/gui/src/hooks/wifi-scan.ts @@ -0,0 +1,251 @@ +import { Command } from "@tauri-apps/plugin-shell"; +import * as os from '@tauri-apps/plugin-os'; +import { useWebsocketAPI } from '@/hooks/websocket-api'; +import { + RpcMessage, + SerialTrackerGetWifiScanRequestT, + SerialUpdateResponseT, + CloseSerialRequestT, + OpenSerialRequestT +} from 'solarxr-protocol'; +import { useEffect, useState, useMemo } from 'react'; + +export interface WifiNetwork { + ssid: string; + source: string; + password: string; + connected: boolean; + signalStrength: number|null; +}; + +async function getWifiNetworksLinux(): Promise { + // TODO + return []; +} + +async function getWifiNetworksMac(): Promise { + // TODO + return []; +} + +async function getWifiNetworksWindows(): Promise { + let ret:WifiNetwork[] = []; + + const networksResponse = await Command.create('netsh-list', [ + 'wlan', + 'show', + 'profile' + ]).execute(); + + networksResponse.stdout.split('\n').forEach(line => { + const ssidMatch = line.match(/All User Profile\s+:\s+(.+)/); + if(!ssidMatch) + return; + + const ssid = ssidMatch[1]; + ret.push({ + ssid: ssid, + source: 'windows', + password: '', + connected: false, + signalStrength: null, + }); + }); + + ret.forEach(async (network) => { + const profileResponse = await Command.create('netsh-details', [ + 'wlan', + 'show', + 'profile', + `name=${network.ssid}`, + 'key=clear' + ]).execute(); + + const passwordMatch = profileResponse.stdout.match(/Key Content\s+:\s+(.+)/); + network.password = passwordMatch ? passwordMatch[1] : ''; + }); + + const scanResponse = await Command.create('netsh-scan', [ + 'wlan', + 'show', + 'network', + "mode=Bssid" + ]).execute(); + + let lastSsid:string|null = null; + + scanResponse.stdout.split('\n').forEach(line => { + const ssidMatch = line.match(/SSID\s+:\s+(.+)/); + if(ssidMatch) { + lastSsid = ssidMatch[1]; + } + + const signalMatch = line.match(/Signal\s+:\s+(.+)/); + if(!signalMatch) + return; + + if(lastSsid) { + let network = ret.find((network) => network.ssid === lastSsid); + if(network === undefined) { + network = { + ssid: lastSsid, + source: 'windows', + password: '', + connected: false, + signalStrength: null, + }; + + ret.push(network); + } + + network.signalStrength = parseInt(signalMatch[1]) / 100; + } + }); + + const connectedResponse = await Command.create('netsh-connected', [ + 'wlan', + 'show', + 'interfaces' + ]).execute(); + + const connectedMatch = connectedResponse.stdout.match(/SSID\s+:\s+(.+)/); + if(connectedMatch) { + let connectedNetwork = ret.filter((network) => network.ssid === connectedMatch[1]); + if(connectedNetwork.length > 0) { + connectedNetwork[0].connected = true; + } + } + + return ret; +} + +function useWifiNetworksSlimes() { + const [slimeWifiNetworks, setSlimeWifiNetworks] = useState([]); + const { useRPCPacket, sendRPCPacket } = useWebsocketAPI(); + const [isSerialOpen, setSerialOpen] = useState(false); + const [scanStarted, setScanStarted] = useState(false); + + useEffect(() => { + if(isSerialOpen === false) { + setSerialOpen(null); + // sendRPCPacket(RpcMessage.CloseSerialRequest, new CloseSerialRequestT()); + const req = new OpenSerialRequestT(); + req.port = 'Auto'; + req.auto = true; + sendRPCPacket(RpcMessage.OpenSerialRequest, req); + } + + if(isSerialOpen === true) { + if(scanStarted === false) { + setScanStarted(true); + setTimeout(() => { + sendRPCPacket( + RpcMessage.SerialTrackerGetWifiScanRequest, + new SerialTrackerGetWifiScanRequestT() + ); + }, 300); + } + } + }, [isSerialOpen]); + + useRPCPacket( + RpcMessage.SerialUpdateResponse, + (data: SerialUpdateResponseT) => { + if (data.closed) { + if(isSerialOpen !== false) + setSerialOpen(false); + return; + } else { + if(isSerialOpen !== true) + setSerialOpen(true); + } + + const logString:string = data.log; + + const regex = /\d+:\s+\d+\s+(.+)\t\(-\d+\)/gm; + const match = regex.exec(logString); + if(!match) + return; + + const exists = slimeWifiNetworks.find((network) => network.ssid === match[1]); + if(!exists) { + setSlimeWifiNetworks([ + ...slimeWifiNetworks, + { + ssid: match[1], + source: 'slime', + password: '', + connected: false, + signalStrength: null, + } + ]); + } + } + ); + + return slimeWifiNetworks; +} + +function useWifiNetworksInternal() { + const [wifiNetworks, setWifiNetworks] = useState([]); + + useEffect(() => { + os.type().then((platformName) => { + switch (platformName) { + case 'windows': + getWifiNetworksWindows().then((networks) => { + setWifiNetworks(networks); + }); + break; + case 'linux': + getWifiNetworksLinux().then((networks) => { + setWifiNetworks(networks); + }); + break; + case 'macos': + getWifiNetworksMac().then((networks) => { + setWifiNetworks(networks); + }); + break; + default: + console.log("Unsupported platform: ", platformName); + } + }); + }, []); + + return wifiNetworks; +}; + +export function useWifiNetworks() { + const wifiNetworksSlimes = useWifiNetworksSlimes(); + const wifiNetworksInternal = useWifiNetworksInternal(); + + const wifiNetworks = useMemo(() => { + const networksConcat = [...wifiNetworksInternal, ...wifiNetworksSlimes]; + + const ret = networksConcat.reduce((acc, network) => { + const exists = acc.find((accNetwork) => accNetwork.ssid === network.ssid); + + if(!exists) { + acc.push({ + ...network + }); + } else { + console.log("Exists", exists, network) + if(!exists.password && network.password) { + exists.password = network.password; + } + } + + return acc; + }, [] as WifiNetwork[]); + + return ret.sort((a, b) => { + return a.ssid.localeCompare(b.ssid); + }); + }, [wifiNetworksInternal, wifiNetworksSlimes]); + + return { + wifiNetworks + }; +} From 527d0eca6d8a05727e7af42e2ee38ae4b4aab317 Mon Sep 17 00:00:00 2001 From: Electromuis Date: Tue, 28 May 2024 15:54:30 +0200 Subject: [PATCH 2/3] ES linting --- .../components/onboarding/pages/WifiCreds.tsx | 87 ++++++------ gui/src/hooks/wifi-form.tsx | 7 +- gui/src/hooks/wifi-scan.ts | 126 ++++++++---------- 3 files changed, 108 insertions(+), 112 deletions(-) diff --git a/gui/src/components/onboarding/pages/WifiCreds.tsx b/gui/src/components/onboarding/pages/WifiCreds.tsx index 1d3de8ca02..bec50a8aff 100644 --- a/gui/src/components/onboarding/pages/WifiCreds.tsx +++ b/gui/src/components/onboarding/pages/WifiCreds.tsx @@ -13,7 +13,14 @@ import { useBnoExists } from '@/hooks/imu-logic'; export function WifiCredsPage() { const { l10n } = useLocalization(); const { applyProgress, state } = useOnboarding(); - const { control, handleSubmit, submitWifiCreds, formState, wifiNetworks, watch } = useWifiForm(); + const { + control, + handleSubmit, + submitWifiCreds, + formState, + wifiNetworks, + watch, + } = useWifiForm(); const { useConnectedIMUTrackers } = useTrackers(); const connectedIMUTrackers = useConnectedIMUTrackers(); @@ -27,10 +34,7 @@ export function WifiCredsPage() { value: network.ssid, })); - return [ - ...networksMapped, - { label: 'Other', value: 'other' }, - ]; + return [...networksMapped, { label: 'Other', value: 'other' }]; }, [wifiNetworks]); return ( @@ -71,42 +75,45 @@ export function WifiCredsPage() { state.alonePage && 'bg-background-60' )} > + {wifiNetworks.length > 0 && ( + <> + + {l10n.getString('onboarding-wifi_creds-ssidSelect-label')} + + + + + + )} - {wifiNetworks.length > 0 && <> - - {l10n.getString('onboarding-wifi_creds-ssidSelect-label')} - - - - - } - - {(wifiNetworks.length === 0 || watch('ssidSelect') == 'other') && - - } + {(wifiNetworks.length === 0 || watch('ssidSelect') == 'other') && ( + + + + )} { - if(ssidSelect === 'other') { + if (ssidSelect === 'other') { setValue('ssid', ''); setValue('password', ''); return; @@ -31,8 +31,7 @@ export function useWifiForm() { const network = wifiNetworks.find((network) => network.ssid === ssidSelect); - if(!network) - return; + if (!network) return; setValue('ssid', network.ssid); setValue('password', network.password); diff --git a/gui/src/hooks/wifi-scan.ts b/gui/src/hooks/wifi-scan.ts index 1052e76832..2db79a9dda 100644 --- a/gui/src/hooks/wifi-scan.ts +++ b/gui/src/hooks/wifi-scan.ts @@ -1,12 +1,11 @@ -import { Command } from "@tauri-apps/plugin-shell"; +import { Command } from '@tauri-apps/plugin-shell'; import * as os from '@tauri-apps/plugin-os'; -import { useWebsocketAPI } from '@/hooks/websocket-api'; +import { useWebsocketAPI } from './websocket-api'; import { RpcMessage, SerialTrackerGetWifiScanRequestT, SerialUpdateResponseT, - CloseSerialRequestT, - OpenSerialRequestT + OpenSerialRequestT, } from 'solarxr-protocol'; import { useEffect, useState, useMemo } from 'react'; @@ -15,8 +14,8 @@ export interface WifiNetwork { source: string; password: string; connected: boolean; - signalStrength: number|null; -}; + signalStrength: number | null; +} async function getWifiNetworksLinux(): Promise { // TODO @@ -29,18 +28,17 @@ async function getWifiNetworksMac(): Promise { } async function getWifiNetworksWindows(): Promise { - let ret:WifiNetwork[] = []; + const ret: WifiNetwork[] = []; const networksResponse = await Command.create('netsh-list', [ 'wlan', 'show', - 'profile' + 'profile', ]).execute(); - networksResponse.stdout.split('\n').forEach(line => { + networksResponse.stdout.split('\n').forEach((line) => { const ssidMatch = line.match(/All User Profile\s+:\s+(.+)/); - if(!ssidMatch) - return; + if (!ssidMatch) return; const ssid = ssidMatch[1]; ret.push({ @@ -58,7 +56,7 @@ async function getWifiNetworksWindows(): Promise { 'show', 'profile', `name=${network.ssid}`, - 'key=clear' + 'key=clear', ]).execute(); const passwordMatch = profileResponse.stdout.match(/Key Content\s+:\s+(.+)/); @@ -69,24 +67,23 @@ async function getWifiNetworksWindows(): Promise { 'wlan', 'show', 'network', - "mode=Bssid" + 'mode=Bssid', ]).execute(); - let lastSsid:string|null = null; + let lastSsid: string | null = null; - scanResponse.stdout.split('\n').forEach(line => { + scanResponse.stdout.split('\n').forEach((line) => { const ssidMatch = line.match(/SSID\s+:\s+(.+)/); - if(ssidMatch) { + if (ssidMatch) { lastSsid = ssidMatch[1]; } const signalMatch = line.match(/Signal\s+:\s+(.+)/); - if(!signalMatch) - return; + if (!signalMatch) return; - if(lastSsid) { + if (lastSsid) { let network = ret.find((network) => network.ssid === lastSsid); - if(network === undefined) { + if (network === undefined) { network = { ssid: lastSsid, source: 'windows', @@ -105,14 +102,14 @@ async function getWifiNetworksWindows(): Promise { const connectedResponse = await Command.create('netsh-connected', [ 'wlan', 'show', - 'interfaces' + 'interfaces', ]).execute(); const connectedMatch = connectedResponse.stdout.match(/SSID\s+:\s+(.+)/); - if(connectedMatch) { - let connectedNetwork = ret.filter((network) => network.ssid === connectedMatch[1]); - if(connectedNetwork.length > 0) { - connectedNetwork[0].connected = true; + if (connectedMatch) { + const connectedNetwork = ret.find((network) => network.ssid === connectedMatch[1]); + if (connectedNetwork) { + connectedNetwork.connected = true; } } @@ -122,11 +119,11 @@ async function getWifiNetworksWindows(): Promise { function useWifiNetworksSlimes() { const [slimeWifiNetworks, setSlimeWifiNetworks] = useState([]); const { useRPCPacket, sendRPCPacket } = useWebsocketAPI(); - const [isSerialOpen, setSerialOpen] = useState(false); + const [isSerialOpen, setSerialOpen] = useState(false); const [scanStarted, setScanStarted] = useState(false); useEffect(() => { - if(isSerialOpen === false) { + if (isSerialOpen === false) { setSerialOpen(null); // sendRPCPacket(RpcMessage.CloseSerialRequest, new CloseSerialRequestT()); const req = new OpenSerialRequestT(); @@ -135,8 +132,8 @@ function useWifiNetworksSlimes() { sendRPCPacket(RpcMessage.OpenSerialRequest, req); } - if(isSerialOpen === true) { - if(scanStarted === false) { + if (isSerialOpen === true) { + if (scanStarted === false) { setScanStarted(true); setTimeout(() => { sendRPCPacket( @@ -148,40 +145,34 @@ function useWifiNetworksSlimes() { } }, [isSerialOpen]); - useRPCPacket( - RpcMessage.SerialUpdateResponse, - (data: SerialUpdateResponseT) => { - if (data.closed) { - if(isSerialOpen !== false) - setSerialOpen(false); - return; - } else { - if(isSerialOpen !== true) - setSerialOpen(true); - } + useRPCPacket(RpcMessage.SerialUpdateResponse, (data: SerialUpdateResponseT) => { + if (data.closed) { + if (isSerialOpen !== false) setSerialOpen(false); + return; + } else { + if (isSerialOpen !== true) setSerialOpen(true); + } - const logString:string = data.log; - - const regex = /\d+:\s+\d+\s+(.+)\t\(-\d+\)/gm; - const match = regex.exec(logString); - if(!match) - return; - - const exists = slimeWifiNetworks.find((network) => network.ssid === match[1]); - if(!exists) { - setSlimeWifiNetworks([ - ...slimeWifiNetworks, - { - ssid: match[1], - source: 'slime', - password: '', - connected: false, - signalStrength: null, - } - ]); - } + const logString: string = data.log; + + const regex = /\d+:\s+\d+\s+(.+)\t\(-\d+\)/gm; + const match = regex.exec(logString); + if (!match) return; + + const exists = slimeWifiNetworks.find((network) => network.ssid === match[1]); + if (!exists) { + setSlimeWifiNetworks([ + ...slimeWifiNetworks, + { + ssid: match[1], + source: 'slime', + password: '', + connected: false, + signalStrength: null, + }, + ]); } - ); + }); return slimeWifiNetworks; } @@ -208,13 +199,13 @@ function useWifiNetworksInternal() { }); break; default: - console.log("Unsupported platform: ", platformName); + console.log('Unsupported platform: ', platformName); } }); }, []); return wifiNetworks; -}; +} export function useWifiNetworks() { const wifiNetworksSlimes = useWifiNetworksSlimes(); @@ -226,13 +217,12 @@ export function useWifiNetworks() { const ret = networksConcat.reduce((acc, network) => { const exists = acc.find((accNetwork) => accNetwork.ssid === network.ssid); - if(!exists) { + if (!exists) { acc.push({ - ...network + ...network, }); } else { - console.log("Exists", exists, network) - if(!exists.password && network.password) { + if (!exists.password && network.password) { exists.password = network.password; } } @@ -246,6 +236,6 @@ export function useWifiNetworks() { }, [wifiNetworksInternal, wifiNetworksSlimes]); return { - wifiNetworks + wifiNetworks, }; } From f505cfc5685a7074bc00643cfce75096e458749d Mon Sep 17 00:00:00 2001 From: Electromuis Date: Tue, 24 Sep 2024 18:02:30 +0200 Subject: [PATCH 3/3] Improved wifi network loading --- gui/src/hooks/wifi-scan.ts | 48 +++++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/gui/src/hooks/wifi-scan.ts b/gui/src/hooks/wifi-scan.ts index 2db79a9dda..df62d789ae 100644 --- a/gui/src/hooks/wifi-scan.ts +++ b/gui/src/hooks/wifi-scan.ts @@ -27,19 +27,19 @@ async function getWifiNetworksMac(): Promise { return []; } -async function getWifiNetworksWindows(): Promise { +async function getWifiNetworksWindowsSaved(): Promise { const ret: WifiNetwork[] = []; const networksResponse = await Command.create('netsh-list', [ 'wlan', 'show', - 'profile', + 'profile' ]).execute(); - networksResponse.stdout.split('\n').forEach((line) => { + networksResponse.stdout.split('\n').forEach(line => { const ssidMatch = line.match(/All User Profile\s+:\s+(.+)/); - if (!ssidMatch) return; - + if(!ssidMatch) + return; const ssid = ssidMatch[1]; ret.push({ ssid: ssid, @@ -56,13 +56,18 @@ async function getWifiNetworksWindows(): Promise { 'show', 'profile', `name=${network.ssid}`, - 'key=clear', + 'key=clear' ]).execute(); - const passwordMatch = profileResponse.stdout.match(/Key Content\s+:\s+(.+)/); network.password = passwordMatch ? passwordMatch[1] : ''; }); + return ret; +} + +async function getWifiNetworksWindowsScan(): Promise { + const ret: WifiNetwork[] = []; + const scanResponse = await Command.create('netsh-scan', [ 'wlan', 'show', @@ -119,12 +124,13 @@ async function getWifiNetworksWindows(): Promise { function useWifiNetworksSlimes() { const [slimeWifiNetworks, setSlimeWifiNetworks] = useState([]); const { useRPCPacket, sendRPCPacket } = useWebsocketAPI(); - const [isSerialOpen, setSerialOpen] = useState(false); + const [isSerialOpen, setSerialOpen] = useState(false); + const [isSerialOpening, setSerialOpening] = useState(false); const [scanStarted, setScanStarted] = useState(false); useEffect(() => { - if (isSerialOpen === false) { - setSerialOpen(null); + if(isSerialOpening === false) { + setSerialOpening(true); // sendRPCPacket(RpcMessage.CloseSerialRequest, new CloseSerialRequestT()); const req = new OpenSerialRequestT(); req.port = 'Auto'; @@ -177,16 +183,30 @@ function useWifiNetworksSlimes() { return slimeWifiNetworks; } +function populateNetworksWindows(setWifiNetworks: (networks: WifiNetwork[]) => void) +{ + let networksSaved: WifiNetwork[] = []; + let networksScanned: WifiNetwork[] = []; + + getWifiNetworksWindowsSaved().then((networks) => { + networksSaved = networks; + setWifiNetworks([...networksSaved, ...networksScanned]); + }); + + getWifiNetworksWindowsScan().then((networks) => { + networksScanned = networks; + setWifiNetworks([...networksSaved, ...networksScanned]); + }); +} + function useWifiNetworksInternal() { const [wifiNetworks, setWifiNetworks] = useState([]); useEffect(() => { - os.type().then((platformName) => { + os.type().then(async (platformName) => { switch (platformName) { case 'windows': - getWifiNetworksWindows().then((networks) => { - setWifiNetworks(networks); - }); + populateNetworksWindows(setWifiNetworks); break; case 'linux': getWifiNetworksLinux().then((networks) => {