Update Electron

This commit is contained in:
Kenta420 2024-03-15 14:10:24 +07:00
parent cae6d582ac
commit c84ee948f5
22 changed files with 763 additions and 152 deletions

View file

@ -10,7 +10,7 @@ import {
DialogTrigger
} from './ui/dialog'
import { Button } from './ui/button'
import { CaretSortIcon, CheckIcon, PlusCircledIcon } from '@radix-ui/react-icons'
import { CaretSortIcon, PlusCircledIcon } from '@radix-ui/react-icons'
import {
Command,
CommandEmpty,
@ -27,9 +27,11 @@ import useAdb from '@/hooks/useAdb'
import { useShallow } from 'zustand/react/shallow'
import type { AdbDaemonWebUsbConnection } from '@yume-chan/adb-daemon-webusb'
import { ADB_DEFAULT_DEVICE_FILTER, AdbDaemonWebUsbDevice } from '@yume-chan/adb-daemon-webusb'
import { Adb, AdbDaemonTransport } from '@yume-chan/adb'
import { Adb, type AdbDaemonDevice, AdbDaemonTransport } from '@yume-chan/adb'
import { toast } from './ui/use-toast'
import AdbWebCredentialStore from '@yume-chan/adb-credential-web'
import { Input } from './ui/input'
import { IpcTcpTransport } from '@/lib/adb-tcp'
type PopoverTriggerProps = React.ComponentPropsWithoutRef<typeof PopoverTrigger>
@ -38,7 +40,8 @@ interface TeamSwitcherProps extends PopoverTriggerProps {}
const DeviceSwitcher = ({ className }: TeamSwitcherProps) => {
const [open, setOpen] = useState(false)
const [showNewDeviceDialog, setShowNewDeviceDialog] = useState(false)
const [connectedDevices, setConnectedDevices] = useState<AdbDaemonWebUsbDevice[]>([])
const [connectedUsbDevices, setConnectedUsbDevices] = useState<AdbDaemonDevice[]>([])
const [connectedTcpDevices, setConnectedTcpDevices] = useState<{ name: string; serial: string }[]>([])
const [newConnectionState, setNewConnectionState] = useState<'connection' | 'connecting'>('connection')
const [selectedConnectionType, setSelectedConnectionType] = useState<string | undefined>()
@ -56,9 +59,11 @@ const DeviceSwitcher = ({ className }: TeamSwitcherProps) => {
useEffect(() => {
if (open) {
const getDevices = async () => {
const devices = await manager?.getDevices()
console.log(devices)
setConnectedDevices(devices || [])
const usbDevices = await manager?.getDevices()
const tcpDevices = await window.adbNativeTcpSocket.getDevices()
setConnectedUsbDevices(usbDevices || [])
setConnectedTcpDevices(tcpDevices || [])
}
getDevices()
}
@ -94,7 +99,7 @@ const DeviceSwitcher = ({ className }: TeamSwitcherProps) => {
}
async function createNewUsbConnection() {
let selectedDevice: AdbDaemonWebUsbDevice | undefined = undefined
let selectedDevice: AdbDaemonDevice | undefined = undefined
if (!device) {
console.log('no device')
@ -149,6 +154,24 @@ const DeviceSwitcher = ({ className }: TeamSwitcherProps) => {
}
}
async function createNewTCPConnection() {
const device = await window.adbNativeTcpSocket.connect('192.168.11.196', 5555)
const transport = new IpcTcpTransport(device.serial, { product: device.name, model: device.name })
const adb = new Adb(transport)
setAdb(adb)
}
function connectDeviceAdbTcp(device: { name: string; serial: string }) {
const transport = new IpcTcpTransport(device.serial, { product: device.name, model: device.name })
const adb = new Adb(transport)
setAdb(adb)
}
// async function connectAdbDaemon() {
// if (!window.electronRuntime) {
// toast({
@ -168,7 +191,9 @@ const DeviceSwitcher = ({ className }: TeamSwitcherProps) => {
// }
function onDisconnect() {
device?.raw.forget()
if (device instanceof AdbDaemonWebUsbDevice) {
device?.raw.forget()
}
setDevice(undefined)
adb?.close()
@ -195,6 +220,12 @@ const DeviceSwitcher = ({ className }: TeamSwitcherProps) => {
<span className="font-medium">USB</span> -{' '}
<span className="text-muted-foreground">Connect device via USB</span>
</SelectItem>
{window.electronRuntime && import.meta.env.DEV && (
<SelectItem value="tcp">
<span className="font-medium">TCP</span> -{' '}
<span className="text-muted-foreground">Connect device via TCP</span>
</SelectItem>
)}
</SelectContent>
</Select>
</div>
@ -220,23 +251,27 @@ const DeviceSwitcher = ({ className }: TeamSwitcherProps) => {
<DialogDescription>Connect a new device to manage your recipes or control your devices. </DialogDescription>
</DialogHeader>
<div>
<div className="space-y-4 py-2 pb-4">
<div className="space-y-2">
{/* <Label htmlFor="plan">Connection type</Label>
<Select onValueChange={setSelectedConnectionType}>
<SelectTrigger>
<SelectValue placeholder="Select connection type" />
</SelectTrigger>
<SelectContent>
<SelectItem value="usb">
<span className="font-medium">USB</span> -{' '}
<span className="text-muted-foreground">Connect device via USB</span>
</SelectItem>
</SelectContent>
</Select> */}
<span className="text-sm">Please connect your device via USB</span>
{selectedConnectionType === 'usb' ? (
<div className="space-y-4 py-2 pb-4">
<div className="space-y-2">
<span className="text-sm">Please plug in your device and click Connect.</span>
</div>
</div>
</div>
) : selectedConnectionType === 'tcp' ? (
<div className="space-y-4 py-2 pb-4">
<div className="space-y-2">
<Label htmlFor="plan">TCP Connection</Label>
<div className="flex gap-3">
<Input type="text" placeholder="IP Address" className="flex-1" />
<Input type="text" placeholder="Port" className="flex-[0.5]" />
</div>
</div>
</div>
) : (
<div>
<span className="text-sm">Unknown connection type.</span>
</div>
)}
</div>
<DialogFooter>
<Button variant="outline" onClick={() => setNewConnectionState('connection')}>
@ -245,7 +280,7 @@ const DeviceSwitcher = ({ className }: TeamSwitcherProps) => {
<Button
type="submit"
onClick={() => {
createNewUsbConnection()
selectedConnectionType === 'usb' ? createNewUsbConnection() : createNewTCPConnection()
}}
>
Connect
@ -267,7 +302,7 @@ const DeviceSwitcher = ({ className }: TeamSwitcherProps) => {
aria-label="Select a Device"
className={cn('w-[400px] justify-between', className)}
>
{device ? device.name : 'Select a Device'}
{device ? device.name + ' [' + device.serial + ']' : 'Select a Device'}
<CaretSortIcon className="ml-auto h-4 w-4 shrink-0 opacity-50" />
</Button>
</PopoverTrigger>
@ -276,30 +311,50 @@ const DeviceSwitcher = ({ className }: TeamSwitcherProps) => {
<CommandList>
<CommandInput placeholder="Search device..." />
<CommandEmpty>No device found.</CommandEmpty>
<CommandGroup heading={'Devices'}>
{connectedDevices.length > 0 ? (
connectedDevices.map(device => (
<CommandGroup heading={'Devices [USB]'}>
{connectedUsbDevices.length > 0 ? (
connectedUsbDevices.map(device => (
<CommandItem
key={device.serial}
onSelect={() => {
connectDeviceAdbUsb(device)
connectDeviceAdbUsb(device as AdbDaemonWebUsbDevice)
setOpen(false)
}}
className="text-sm"
>
{device.name}
<CheckIcon
className={cn(
'ml-auto h-4 w-4',
device?.serial === device.serial ? 'opacity-100' : 'opacity-0'
)}
/>
</CommandItem>
))
) : (
<span className="text-sm ml-2">Not found device connected.</span>
)}
</CommandGroup>
{window.electronRuntime && import.meta.env.DEV && (
<CommandGroup heading={'Devices [TCP]'}>
{connectedTcpDevices.length > 0 ? (
connectedTcpDevices.map(device => (
<CommandItem
key={device.serial}
onSelect={() => {
connectDeviceAdbTcp(device)
setOpen(false)
}}
className="text-sm"
>
{device.name}
{/* <CheckIcon
className={cn(
'ml-auto h-4 w-4',
device?.serial === device.serial ? 'opacity-100' : 'opacity-0'
)}
/> */}
</CommandItem>
))
) : (
<span className="text-sm ml-2">Not found device connected.</span>
)}
</CommandGroup>
)}
</CommandList>
<CommandSeparator />
<CommandList>

View file

@ -0,0 +1,55 @@
import * as React from "react"
import * as AccordionPrimitive from "@radix-ui/react-accordion"
import { ChevronDownIcon } from "@radix-ui/react-icons"
import { cn } from "@/lib/utils"
const Accordion = AccordionPrimitive.Root
const AccordionItem = React.forwardRef<
React.ElementRef<typeof AccordionPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>
>(({ className, ...props }, ref) => (
<AccordionPrimitive.Item
ref={ref}
className={cn("border-b", className)}
{...props}
/>
))
AccordionItem.displayName = "AccordionItem"
const AccordionTrigger = React.forwardRef<
React.ElementRef<typeof AccordionPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>
>(({ className, children, ...props }, ref) => (
<AccordionPrimitive.Header className="flex">
<AccordionPrimitive.Trigger
ref={ref}
className={cn(
"flex flex-1 items-center justify-between py-4 text-sm font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180",
className
)}
{...props}
>
{children}
<ChevronDownIcon className="h-4 w-4 shrink-0 text-muted-foreground transition-transform duration-200" />
</AccordionPrimitive.Trigger>
</AccordionPrimitive.Header>
))
AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName
const AccordionContent = React.forwardRef<
React.ElementRef<typeof AccordionPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>
>(({ className, children, ...props }, ref) => (
<AccordionPrimitive.Content
ref={ref}
className="overflow-hidden text-sm data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
{...props}
>
<div className={cn("pb-4 pt-0", className)}>{children}</div>
</AccordionPrimitive.Content>
))
AccordionContent.displayName = AccordionPrimitive.Content.displayName
export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }