Loading apps/demo/components/log-view.tsxdeleted 100644 → 0 +0 −171 Original line number Diff line number Diff line import { IconButton, IListProps, List, mergeStyles, mergeStyleSets, Stack } from '@fluentui/react'; import { AdbCommand, AdbPacketCore, decodeUtf8 } from '@yume-chan/adb'; import { observer } from "mobx-react-lite"; import { PropsWithChildren, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react'; import { globalState } from "../state"; import { Icons, withDisplayName } from '../utils'; import { CommandBar } from './command-bar'; const classNames = mergeStyleSets({ 'logger-container': { width: 300, }, grow: { flexGrow: 1, height: 0, padding: '0 8px', overflowX: 'hidden', overflowY: 'auto', fontFamily: 'monospace', whiteSpace: 'pre-wrap', wordWrap: 'break-word', }, }); const ADB_COMMAND_NAME = { [AdbCommand.Auth]: 'AUTH', [AdbCommand.Close]: 'CLSE', [AdbCommand.Connect]: 'CNXN', [AdbCommand.OK]: 'OKAY', [AdbCommand.Open]: 'OPEN', [AdbCommand.Write]: 'WRTE', }; function serializePacket(packet: AdbPacketCore) { const command = ADB_COMMAND_NAME[packet.command as AdbCommand] ?? decodeUtf8(new Uint32Array([packet.command])); const parts = [ command, packet.arg0.toString(16).padStart(8, '0'), packet.arg1.toString(16).padStart(8, '0'), ]; if (packet.payload) { parts.push( Array.from( packet.payload, byte => byte.toString(16).padStart(2, '0') ).join(' ') ); } return parts.join(' '); } const LogLine = withDisplayName('LoggerLine')(({ packet }: { packet: [string, AdbPacketCore]; }) => { const string = useMemo(() => serializePacket(packet[1]), [packet]); return ( <> {packet[0]}{' '}{string} </> ); }); export const ToggleLogView = observer(() => { return ( <IconButton checked={globalState.logVisible} iconProps={{ iconName: Icons.TextGrammarError }} title="Toggle Log" onClick={globalState.toggleLog} /> ); }); export interface LoggerProps { className?: string; } function shouldVirtualize(props: IListProps<[string, AdbPacketCore]>) { return !!props.items && props.items.length > 100; } function renderCell(item?: [string, AdbPacketCore]) { if (!item) { return null; } return ( <LogLine packet={item} /> ); } export const LogView = observer(({ className, }: LoggerProps) => { const scrollerRef = useRef<HTMLDivElement | null>(null); useLayoutEffect(() => { const scroller = scrollerRef.current; if (scroller) { scroller.scrollTop = scroller.scrollHeight; } }); const commandBarItems = useMemo(() => [ { key: 'Copy', text: 'Copy', iconProps: { iconName: Icons.Copy }, onClick: () => { window.navigator.clipboard.writeText( globalState.logs .map( ([direction, packet]) => `${direction}${serializePacket((packet))}` ) .join('\n')); }, }, { key: 'Clear', text: 'Clear', iconProps: { iconName: Icons.Delete }, onClick: () => { globalState.clearLog(); }, }, ], []); const mergedClassName = useMemo(() => mergeStyles( className, classNames['logger-container'], ), [className]); if (!globalState.logVisible) { return null; } return ( <Stack className={mergedClassName} verticalFill > <CommandBar items={commandBarItems} /> <div ref={scrollerRef} className={classNames.grow}> <List items={globalState.logs} onShouldVirtualize={shouldVirtualize} onRenderCell={renderCell} /> </div> </Stack> ); }); export function NoSsr({ children }: PropsWithChildren<{}>) { const [showChild, setShowChild] = useState(false); // Wait until after client-side hydration to show useEffect(() => { setShowChild(true); }, []); if (!showChild) { return null; } return <>{children}</>; } apps/demo/package.json +3 −1 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ "next": "12.1.3", "react": "^17.0.2", "react-dom": "^17.0.2", "react-window": "1.8.6", "streamsaver": "^2.0.5", "xterm": "^4.17.0", "xterm-addon-fit": "^0.5.0", Loading @@ -41,8 +42,9 @@ "@mdx-js/loader": "^1.6.22", "@next/mdx": "^11.1.2", "@types/react": "17.0.27", "@types/react-window": "^1.8.5", "eslint": "8.8.0", "eslint-config-next": "12.1.3", "typescript": "next" "typescript": "4.7.0-beta" } } apps/demo/components/command-bar.tsx→apps/demo/src/components/command-bar.tsx +0 −0 File moved. View file apps/demo/components/connect.tsx→apps/demo/src/components/connect.tsx +2 −2 Original line number Diff line number Diff line Loading @@ -150,13 +150,13 @@ function _Connect(): JSX.Element | null { const readable = streams.readable .pipeThrough( new InspectStream(packet => { globalState.appendLog('Incoming', packet); globalState.appendLog('in', packet); }) ); const writable = pipeFrom( streams.writable, new InspectStream(packet => { globalState.appendLog('Outgoing', packet); globalState.appendLog('out', packet); }) ); device = await Adb.authenticate({ readable, writable }, CredentialStore, undefined); Loading apps/demo/components/demo-mode-panel.tsx→apps/demo/src/components/demo-mode-panel.tsx +0 −0 File moved. View file Loading
apps/demo/components/log-view.tsxdeleted 100644 → 0 +0 −171 Original line number Diff line number Diff line import { IconButton, IListProps, List, mergeStyles, mergeStyleSets, Stack } from '@fluentui/react'; import { AdbCommand, AdbPacketCore, decodeUtf8 } from '@yume-chan/adb'; import { observer } from "mobx-react-lite"; import { PropsWithChildren, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react'; import { globalState } from "../state"; import { Icons, withDisplayName } from '../utils'; import { CommandBar } from './command-bar'; const classNames = mergeStyleSets({ 'logger-container': { width: 300, }, grow: { flexGrow: 1, height: 0, padding: '0 8px', overflowX: 'hidden', overflowY: 'auto', fontFamily: 'monospace', whiteSpace: 'pre-wrap', wordWrap: 'break-word', }, }); const ADB_COMMAND_NAME = { [AdbCommand.Auth]: 'AUTH', [AdbCommand.Close]: 'CLSE', [AdbCommand.Connect]: 'CNXN', [AdbCommand.OK]: 'OKAY', [AdbCommand.Open]: 'OPEN', [AdbCommand.Write]: 'WRTE', }; function serializePacket(packet: AdbPacketCore) { const command = ADB_COMMAND_NAME[packet.command as AdbCommand] ?? decodeUtf8(new Uint32Array([packet.command])); const parts = [ command, packet.arg0.toString(16).padStart(8, '0'), packet.arg1.toString(16).padStart(8, '0'), ]; if (packet.payload) { parts.push( Array.from( packet.payload, byte => byte.toString(16).padStart(2, '0') ).join(' ') ); } return parts.join(' '); } const LogLine = withDisplayName('LoggerLine')(({ packet }: { packet: [string, AdbPacketCore]; }) => { const string = useMemo(() => serializePacket(packet[1]), [packet]); return ( <> {packet[0]}{' '}{string} </> ); }); export const ToggleLogView = observer(() => { return ( <IconButton checked={globalState.logVisible} iconProps={{ iconName: Icons.TextGrammarError }} title="Toggle Log" onClick={globalState.toggleLog} /> ); }); export interface LoggerProps { className?: string; } function shouldVirtualize(props: IListProps<[string, AdbPacketCore]>) { return !!props.items && props.items.length > 100; } function renderCell(item?: [string, AdbPacketCore]) { if (!item) { return null; } return ( <LogLine packet={item} /> ); } export const LogView = observer(({ className, }: LoggerProps) => { const scrollerRef = useRef<HTMLDivElement | null>(null); useLayoutEffect(() => { const scroller = scrollerRef.current; if (scroller) { scroller.scrollTop = scroller.scrollHeight; } }); const commandBarItems = useMemo(() => [ { key: 'Copy', text: 'Copy', iconProps: { iconName: Icons.Copy }, onClick: () => { window.navigator.clipboard.writeText( globalState.logs .map( ([direction, packet]) => `${direction}${serializePacket((packet))}` ) .join('\n')); }, }, { key: 'Clear', text: 'Clear', iconProps: { iconName: Icons.Delete }, onClick: () => { globalState.clearLog(); }, }, ], []); const mergedClassName = useMemo(() => mergeStyles( className, classNames['logger-container'], ), [className]); if (!globalState.logVisible) { return null; } return ( <Stack className={mergedClassName} verticalFill > <CommandBar items={commandBarItems} /> <div ref={scrollerRef} className={classNames.grow}> <List items={globalState.logs} onShouldVirtualize={shouldVirtualize} onRenderCell={renderCell} /> </div> </Stack> ); }); export function NoSsr({ children }: PropsWithChildren<{}>) { const [showChild, setShowChild] = useState(false); // Wait until after client-side hydration to show useEffect(() => { setShowChild(true); }, []); if (!showChild) { return null; } return <>{children}</>; }
apps/demo/package.json +3 −1 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ "next": "12.1.3", "react": "^17.0.2", "react-dom": "^17.0.2", "react-window": "1.8.6", "streamsaver": "^2.0.5", "xterm": "^4.17.0", "xterm-addon-fit": "^0.5.0", Loading @@ -41,8 +42,9 @@ "@mdx-js/loader": "^1.6.22", "@next/mdx": "^11.1.2", "@types/react": "17.0.27", "@types/react-window": "^1.8.5", "eslint": "8.8.0", "eslint-config-next": "12.1.3", "typescript": "next" "typescript": "4.7.0-beta" } }
apps/demo/components/command-bar.tsx→apps/demo/src/components/command-bar.tsx +0 −0 File moved. View file
apps/demo/components/connect.tsx→apps/demo/src/components/connect.tsx +2 −2 Original line number Diff line number Diff line Loading @@ -150,13 +150,13 @@ function _Connect(): JSX.Element | null { const readable = streams.readable .pipeThrough( new InspectStream(packet => { globalState.appendLog('Incoming', packet); globalState.appendLog('in', packet); }) ); const writable = pipeFrom( streams.writable, new InspectStream(packet => { globalState.appendLog('Outgoing', packet); globalState.appendLog('out', packet); }) ); device = await Adb.authenticate({ readable, writable }, CredentialStore, undefined); Loading
apps/demo/components/demo-mode-panel.tsx→apps/demo/src/components/demo-mode-panel.tsx +0 −0 File moved. View file