9 changed files with 550 additions and 627 deletions
File diff suppressed because it is too large
@ -0,0 +1,134 @@ |
|||||
|
import type React from "react"; |
||||
|
import { useEffect, useState } from "react"; |
||||
|
|
||||
|
import { fromByteArray, toByteArray } from "base64-js"; |
||||
|
import { toast } from "react-hot-toast"; |
||||
|
import { QRCode } from "react-qrcode-logo"; |
||||
|
|
||||
|
import { Checkbox } from "@components/form/Checkbox.js"; |
||||
|
import { Input } from "@components/form/Input.js"; |
||||
|
import { Dialog } from "@components/generic/Dialog.js"; |
||||
|
import { ClipboardIcon } from "@heroicons/react/24/outline"; |
||||
|
import { Protobuf } from "@meshtastic/meshtasticjs"; |
||||
|
import { Select } from "../form/Select.js"; |
||||
|
import { renderOptions } from "@app/core/utils/selectEnumOptions.js"; |
||||
|
import { Toggle } from "../form/Toggle.js"; |
||||
|
import { Button } from "../form/Button.js"; |
||||
|
import { useDevice } from "@app/core/providers/useDevice.js"; |
||||
|
|
||||
|
export interface ImportDialogProps { |
||||
|
isOpen: boolean; |
||||
|
close: () => void; |
||||
|
loraConfig?: Protobuf.Config_LoRaConfig; |
||||
|
channels: Protobuf.Channel[]; |
||||
|
} |
||||
|
|
||||
|
export const ImportDialog = ({ |
||||
|
isOpen, |
||||
|
close, |
||||
|
}: ImportDialogProps): JSX.Element => { |
||||
|
const [QRCodeURL, setQRCodeURL] = useState<string>(""); |
||||
|
const [channelSet, setChannelSet] = useState<Protobuf.ChannelSet>(); |
||||
|
const [validURL, setValidURL] = useState<boolean>(false); |
||||
|
|
||||
|
const {connection} = useDevice() |
||||
|
|
||||
|
useEffect(() => { |
||||
|
const base64String = QRCodeURL.split("e/#")[1] |
||||
|
?.replace(/-/g, "+") |
||||
|
.replace(/_/g, "/") |
||||
|
.padEnd(QRCodeURL.length + ((4 - (QRCodeURL.length % 4)) % 4), "="); |
||||
|
try { |
||||
|
setChannelSet(Protobuf.ChannelSet.fromBinary(toByteArray(base64String))); |
||||
|
setValidURL(true); |
||||
|
} catch (error) { |
||||
|
setValidURL(false); |
||||
|
setChannelSet(undefined); |
||||
|
} |
||||
|
}, [QRCodeURL]); |
||||
|
|
||||
|
const apply = () => { |
||||
|
|
||||
|
channelSet?.settings.map(((ch, index) => { |
||||
|
connection?.setChannel({ |
||||
|
channel: { |
||||
|
index, |
||||
|
role: index === 0 ? Protobuf.Channel_Role.PRIMARY: Protobuf.Channel_Role.SECONDARY, |
||||
|
settings: ch |
||||
|
} |
||||
|
}) |
||||
|
})) |
||||
|
|
||||
|
if (channelSet?.loraConfig) { |
||||
|
connection?.setConfig({ |
||||
|
config: { |
||||
|
payloadVariant: { |
||||
|
oneofKind: 'lora', |
||||
|
lora: channelSet.loraConfig |
||||
|
} |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
return ( |
||||
|
<Dialog |
||||
|
title={"Import Channel Set"} |
||||
|
description={"The current LoRa configuration will be overridden."} |
||||
|
isOpen={isOpen} |
||||
|
close={close} |
||||
|
> |
||||
|
<div className="flex flex-col gap-3"> |
||||
|
<Input |
||||
|
label="Channel Set/QR Code URL" |
||||
|
value={QRCodeURL} |
||||
|
suffix={validURL ? "✅" : "❌"} |
||||
|
onChange={(e) => { |
||||
|
setQRCodeURL(e.target.value); |
||||
|
}} |
||||
|
/>{validURL && ( |
||||
|
<div className="flex flex-col gap-3"> |
||||
|
|
||||
|
<div className="flex w-full gap-2"> |
||||
|
<div className="w-36"> |
||||
|
<Toggle |
||||
|
className="flex-col gap-2" |
||||
|
label="Use Preset?" |
||||
|
disabled |
||||
|
checked={channelSet?.loraConfig?.usePreset ?? true} |
||||
|
/> |
||||
|
</div> |
||||
|
<Select |
||||
|
label="Modem Preset" |
||||
|
disabled |
||||
|
value={channelSet?.loraConfig?.modemPreset} |
||||
|
> |
||||
|
{renderOptions(Protobuf.Config_LoRaConfig_ModemPreset)} |
||||
|
</Select> |
||||
|
</div> |
||||
|
<Select |
||||
|
label="Region" |
||||
|
disabled |
||||
|
value={channelSet?.loraConfig?.region} |
||||
|
> |
||||
|
{renderOptions(Protobuf.Config_LoRaConfig_RegionCode)} |
||||
|
</Select> |
||||
|
|
||||
|
|
||||
|
<span className="block text-md font-medium text-gray-700">Channels:</span> |
||||
|
<div className="flex w-40 flex-col gap-1"> |
||||
|
{channelSet?.settings.map((channel, index) => ( |
||||
|
<Checkbox |
||||
|
key={index} |
||||
|
label={ |
||||
|
channel.name.length ? channel.name : `Channel: ${channel.id}` |
||||
|
} |
||||
|
/> |
||||
|
))} |
||||
|
</div> |
||||
|
</div>)} |
||||
|
<Button onClick={() => apply()} disabled={!validURL}>Apply</Button></div> |
||||
|
</Dialog> |
||||
|
); |
||||
|
}; |
||||
Loading…
Reference in new issue