Merge branch 'main' of https://github.com/Poomipat-Ch/taobin_recipe_manager
This commit is contained in:
commit
9b0f111f5b
2 changed files with 151 additions and 6 deletions
26
client-electron/src/hooks/adbStore.ts
Normal file
26
client-electron/src/hooks/adbStore.ts
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
import { create } from 'zustand'
|
||||||
|
import { createJSONStorage, persist } from 'zustand/middleware'
|
||||||
|
|
||||||
|
interface AdbStore {
|
||||||
|
deviceSerial: string
|
||||||
|
isAlreadyConnected: boolean
|
||||||
|
setDeviceSerial: (deviceSerial: string) => void
|
||||||
|
setIsAlreadyConnected: (isAlreadyConnected: boolean) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const useAdbStore = create(
|
||||||
|
persist<AdbStore>(
|
||||||
|
set => ({
|
||||||
|
deviceSerial: '',
|
||||||
|
isAlreadyConnected: false,
|
||||||
|
setDeviceSerial: deviceSerial => set({ deviceSerial }),
|
||||||
|
setIsAlreadyConnected: isAlreadyConnected => set({ isAlreadyConnected })
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
name: 'adb',
|
||||||
|
storage: createJSONStorage(() => sessionStorage)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
export default useAdbStore
|
||||||
|
|
@ -7,11 +7,13 @@ import type { AdbScrcpyVideoStream } from '@yume-chan/adb-scrcpy'
|
||||||
import { AdbScrcpyClient, AdbScrcpyOptions1_22 } from '@yume-chan/adb-scrcpy'
|
import { AdbScrcpyClient, AdbScrcpyOptions1_22 } from '@yume-chan/adb-scrcpy'
|
||||||
import { WebCodecsDecoder } from '@yume-chan/scrcpy-decoder-webcodecs'
|
import { WebCodecsDecoder } from '@yume-chan/scrcpy-decoder-webcodecs'
|
||||||
import {
|
import {
|
||||||
|
AndroidMotionEventAction,
|
||||||
ScrcpyLogLevel1_18,
|
ScrcpyLogLevel1_18,
|
||||||
ScrcpyOptions1_25,
|
ScrcpyOptions1_25,
|
||||||
|
ScrcpyPointerId,
|
||||||
ScrcpyVideoCodecId
|
ScrcpyVideoCodecId
|
||||||
} from '@yume-chan/scrcpy'
|
} from '@yume-chan/scrcpy'
|
||||||
import { useCallback, useRef, useState } from 'react'
|
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||||
import {
|
import {
|
||||||
ReadableStream,
|
ReadableStream,
|
||||||
WritableStream,
|
WritableStream,
|
||||||
|
|
@ -19,6 +21,7 @@ import {
|
||||||
DecodeUtf8Stream
|
DecodeUtf8Stream
|
||||||
} from '@yume-chan/stream-extra'
|
} from '@yume-chan/stream-extra'
|
||||||
import { useBeforeUnload } from 'react-router-dom'
|
import { useBeforeUnload } from 'react-router-dom'
|
||||||
|
import useAdbStore from '../hooks/adbStore'
|
||||||
|
|
||||||
const AndroidPage: React.FC = () => {
|
const AndroidPage: React.FC = () => {
|
||||||
const { adb, manager, device, setAdb, setDevice } = useAdb(
|
const { adb, manager, device, setAdb, setDevice } = useAdb(
|
||||||
|
|
@ -31,6 +34,60 @@ const AndroidPage: React.FC = () => {
|
||||||
}))
|
}))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const {
|
||||||
|
isAlreadyConnected,
|
||||||
|
deviceSerial,
|
||||||
|
setIsAlreadyConnected,
|
||||||
|
setDeviceSerial
|
||||||
|
} = useAdbStore(
|
||||||
|
useShallow(state => ({
|
||||||
|
isAlreadyConnected: state.isAlreadyConnected,
|
||||||
|
setIsAlreadyConnected: state.setIsAlreadyConnected,
|
||||||
|
deviceSerial: state.deviceSerial,
|
||||||
|
setDeviceSerial: state.setDeviceSerial
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isAlreadyConnected) {
|
||||||
|
const reconnectAdb = async () => {
|
||||||
|
const device = await manager
|
||||||
|
?.getDevices([
|
||||||
|
{
|
||||||
|
...ADB_DEFAULT_DEVICE_FILTER,
|
||||||
|
serialNumber: deviceSerial
|
||||||
|
}
|
||||||
|
])
|
||||||
|
.then(devices => devices[0])
|
||||||
|
|
||||||
|
if (!device) {
|
||||||
|
// clear state
|
||||||
|
setIsAlreadyConnected(false)
|
||||||
|
setDeviceSerial('')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const connection = await device.connect()
|
||||||
|
|
||||||
|
const credentialStore: AdbWebCredentialStore =
|
||||||
|
new AdbWebCredentialStore()
|
||||||
|
|
||||||
|
const transport = await AdbDaemonTransport.authenticate({
|
||||||
|
serial: deviceSerial,
|
||||||
|
connection: connection,
|
||||||
|
credentialStore: credentialStore
|
||||||
|
})
|
||||||
|
|
||||||
|
const adb: Adb = new Adb(transport)
|
||||||
|
|
||||||
|
setAdb(adb)
|
||||||
|
setDevice(device)
|
||||||
|
}
|
||||||
|
|
||||||
|
reconnectAdb()
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
async function createNewConnection() {
|
async function createNewConnection() {
|
||||||
device?.raw.forget()
|
device?.raw.forget()
|
||||||
setDevice(undefined)
|
setDevice(undefined)
|
||||||
|
|
@ -61,6 +118,9 @@ const AndroidPage: React.FC = () => {
|
||||||
|
|
||||||
const adb: Adb = new Adb(transport)
|
const adb: Adb = new Adb(transport)
|
||||||
setAdb(adb)
|
setAdb(adb)
|
||||||
|
|
||||||
|
setDeviceSerial(selectedDevice.serial)
|
||||||
|
setIsAlreadyConnected(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
const [client, setClient] = useState<AdbScrcpyClient | undefined>()
|
const [client, setClient] = useState<AdbScrcpyClient | undefined>()
|
||||||
|
|
@ -118,13 +178,69 @@ const AndroidPage: React.FC = () => {
|
||||||
|
|
||||||
const videoStream: AdbScrcpyVideoStream | undefined =
|
const videoStream: AdbScrcpyVideoStream | undefined =
|
||||||
await _client?.videoStream
|
await _client?.videoStream
|
||||||
const _decoder = new WebCodecsDecoder(ScrcpyVideoCodecId.H264)
|
|
||||||
|
|
||||||
_decoder.renderer.style.maxHeight = 'inherit'
|
if (videoStream) {
|
||||||
|
const _decoder = new WebCodecsDecoder(ScrcpyVideoCodecId.H264)
|
||||||
|
|
||||||
|
_decoder.renderer.style.maxHeight = 'inherit'
|
||||||
|
screenRef.current?.appendChild(_decoder.renderer)
|
||||||
|
videoStream?.stream.pipeTo(_decoder.writable)
|
||||||
|
setDecoder(_decoder)
|
||||||
|
|
||||||
|
if (_client.controlMessageWriter) {
|
||||||
|
_decoder.renderer.addEventListener('mousedown', e => {
|
||||||
|
const react = _decoder.renderer.getBoundingClientRect()
|
||||||
|
const x = e.clientX - react.left
|
||||||
|
const y = e.clientY - react.top
|
||||||
|
_client.controlMessageWriter?.injectTouch({
|
||||||
|
action: AndroidMotionEventAction.Down,
|
||||||
|
pointerId: ScrcpyPointerId.Mouse,
|
||||||
|
pointerX: x,
|
||||||
|
pointerY: y,
|
||||||
|
pressure: 1,
|
||||||
|
screenWidth: _decoder.renderer.clientWidth,
|
||||||
|
screenHeight: _decoder.renderer.clientHeight,
|
||||||
|
buttons: 0,
|
||||||
|
actionButton: 0
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
_decoder.renderer.addEventListener('mousemove', e => {
|
||||||
|
const react = _decoder.renderer.getBoundingClientRect()
|
||||||
|
const x = e.clientX - react.left
|
||||||
|
const y = e.clientY - react.top
|
||||||
|
_client.controlMessageWriter?.injectTouch({
|
||||||
|
action: AndroidMotionEventAction.Move,
|
||||||
|
pointerId: ScrcpyPointerId.Mouse,
|
||||||
|
pointerX: x,
|
||||||
|
pointerY: y,
|
||||||
|
pressure: 1,
|
||||||
|
screenWidth: _decoder.renderer.clientWidth,
|
||||||
|
screenHeight: _decoder.renderer.clientHeight,
|
||||||
|
buttons: 0,
|
||||||
|
actionButton: 0
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
_decoder.renderer.addEventListener('mouseup', e => {
|
||||||
|
const react = _decoder.renderer.getBoundingClientRect()
|
||||||
|
const x = e.clientX - react.left
|
||||||
|
const y = e.clientY - react.top
|
||||||
|
_client.controlMessageWriter?.injectTouch({
|
||||||
|
action: AndroidMotionEventAction.Up,
|
||||||
|
pointerId: ScrcpyPointerId.Mouse,
|
||||||
|
pointerX: x,
|
||||||
|
pointerY: y,
|
||||||
|
pressure: 1,
|
||||||
|
screenWidth: _decoder.renderer.clientWidth,
|
||||||
|
screenHeight: _decoder.renderer.clientHeight,
|
||||||
|
buttons: 0,
|
||||||
|
actionButton: 0
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
screenRef.current?.appendChild(_decoder.renderer)
|
|
||||||
videoStream?.stream.pipeTo(_decoder.writable)
|
|
||||||
setDecoder(_decoder)
|
|
||||||
setClient(_client)
|
setClient(_client)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -133,6 +249,9 @@ const AndroidPage: React.FC = () => {
|
||||||
adb?.close()
|
adb?.close()
|
||||||
setClient(undefined)
|
setClient(undefined)
|
||||||
setAdb(undefined)
|
setAdb(undefined)
|
||||||
|
setIsAlreadyConnected(false)
|
||||||
|
setDeviceSerial('')
|
||||||
|
device?.raw.forget()
|
||||||
}
|
}
|
||||||
|
|
||||||
function scrcpyDisconnect() {
|
function scrcpyDisconnect() {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue