Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Unverified Commit bb5e292a authored by Simon Chan's avatar Simon Chan
Browse files

feat(demo): wip: add new packet log

ref #397
parent 4cec3ec5
Loading
Loading
Loading
Loading

apps/demo/components/log-view.tsx

deleted100644 → 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}</>;
}
+3 −1
Original line number Diff line number Diff line
@@ -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",
@@ -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"
    }
}
+2 −2
Original line number Diff line number Diff line
@@ -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