import { Dimensions, Platform } from 'react-native'; import getTexts from '../click/texts'; import { findTouchableNode } from '../click/touchableComponent'; import getXPath from '../click/xpath'; import type { ReactElementFiber, ReactHostInstance } from '../element/types'; import { devtoolsInjects, pageInfoAsync } from '../global'; const window = Dimensions.get('window'); let scale = 1; if (Platform.OS === 'android') { scale = window.scale; } export interface UIPage { pageKey: string; frame: UIDataFrame; is_html: number; dom: UIData[]; } export interface UIData { texts: string[]; element_path: string; frame: UIDataFrame; is_html: number; children: UIData[]; } export interface UIDataFrame { x: number; y: number; width: number; height: number; } function parseTouchableNode( windowFrame: UIDataFrame, inst: ReactHostInstance, rootUIData: UIData ): Promise { if (!inst) { return Promise.resolve(); } const node = devtoolsInjects.findFiberByHostInstance(inst._nativeTag); if (!node) { return Promise.resolve(); } const touchableNode = findTouchableNode(node); if (!touchableNode) { const childrenPromise = inst._children.map((child) => parseTouchableNode(windowFrame, child, rootUIData) ); return Promise.all(childrenPromise); } const promise = new Promise((resolve) => { inst.measureInWindow( (x: number, y: number, width: number, height: number) => { const uidata: UIData = { element_path: getXPath(touchableNode), texts: getTexts(node), is_html: 0, frame: { x: Math.floor((x || 0) * scale + windowFrame.x), y: Math.floor((y || 0) * scale + windowFrame.y), width: Math.floor((width || 0) * scale), height: Math.floor((height || 0) * scale), }, children: [], }; rootUIData.children.push(uidata); resolve(undefined); } ); }); return promise; } export function parseUIData( app: ReactElementFiber, windowFrame: UIDataFrame ): Promise { const inst = devtoolsInjects.findHostInstanceByFiber(app); if (!inst) { return Promise.reject('Page HostInstance should not be null'); } const rootTag = app.memoizedProps.rootTag; const promise = new Promise((resolve, reject) => { let isTimeout = false; const timeoutID = setTimeout(() => { isTimeout = true; reject('pageview timeout'); }, 300); pageInfoAsync.appendCurrentPage(rootTag).then((info) => { if (isTimeout) { return; } // console.info(windowFrame, scale); // console.info(window.width, window.height); clearTimeout(timeoutID); const uidata: UIPage = { pageKey: info.page_key, is_html: 0, frame: { x: 0, y: 0, width: Math.round((window.width || 0) * scale), height: Math.round((window.height || 0) * scale), }, dom: [], }; const rootData: UIData = { texts: [], element_path: '', frame: uidata.frame, is_html: 0, children: [], }; parseTouchableNode(windowFrame, inst, rootData).then(() => { uidata.dom = rootData.children; resolve(uidata); }); }); }); return promise; }