/* eslint-disable react-native/no-inline-styles */ import React, { useEffect, useState } from 'react'; import { ActivityIndicator, FlatList, Image, Platform, StyleSheet, Text, TouchableNativeFeedback, View, } from 'react-native'; import { AndroidWidget } from '../AndroidWidget'; import { buildWidgetTree } from './build-widget-tree'; import type { ClickableArea, CollectionArea, OnClick, WidgetPreviewData, } from './private.types'; export interface WidgetPreviewProps { /** * Callback function that will be called by `WidgetPreview` to generate the widget UI. */ renderWidget: (props: { width: number; height: number }) => React.JSX.Element; /** * Callback function that will be called when clicked on a clickable area of the widget. */ onClick?: (props: OnClick) => void; /** * The height of the widget */ height: number; /** * The width of the widget */ width: number; /** * Whether to show a border around the widget. Usefull for widgets that do not use the whole space. */ showBorder?: boolean; /** * Whether to add a highlight to the clickable areas */ highlightClickableAreas?: boolean; } export function WidgetPreview({ renderWidget, onClick = () => {}, width, height, showBorder, highlightClickableAreas, }: WidgetPreviewProps) { const isAndroid = Platform.OS === 'android'; const [preview, setPreview] = useState(); const [error, setError] = useState(null); useEffect(() => { async function init() { try { const data = await AndroidWidget.createPreview( buildWidgetTree(renderWidget({ width, height })), width, height ); setPreview(data); setError(null); } catch (e: any) { console.error(e); setError(e?.message ?? 'Error rendering widget'); } } if (isAndroid) { init(); } return () => setPreview(null); }, [isAndroid, renderWidget, width, height]); function onPress(props: OnClick): void { switch (props.clickAction) { case 'OPEN_APP': console.log('This click will open the app'); break; case 'OPEN_URI': console.log(`This click will open ${props.clickActionData?.uri}`); break; default: onClick({ clickAction: props.clickAction, clickActionData: props.clickActionData, }); break; } } if (!isAndroid) { return ( ); } if (error) { return ; } return ( {preview ? ( ) : ( )} ); } function PreviewContainer({ showBorder, height, width, children, }: Pick & { children: React.ReactNode; }) { return ( {children} ); } function Preview({ height, width, preview, onClick, highlightClickableAreas, }: Pick & { preview: WidgetPreviewData; onClick: (props: OnClick) => void; }) { return ( {preview.clickableAreas.map((area, index) => ( ))} {preview.collectionAreas.map((area, index) => ( ))} ); } function Icon({ color, height, width, }: Pick & { color: string }) { const size = Math.floor(Math.min(height, width) / 3); return ( ! ); } function ErrorState({ showBorder, height, width, }: Pick) { return ( Error rendering widget, see logs ); } function PlatformNotAndroid({ showBorder, height, width, }: Pick) { return ( WidgetPreview works only on Android ); } interface ClickableAreaButtonProps { area: ClickableArea; onClick: (props: OnClick) => void; highlightClickableAreas: boolean | undefined; } function ClickableAreaButton({ area, onClick, highlightClickableAreas, }: ClickableAreaButtonProps) { return ( onClick(area)}> {highlightClickableAreas ? : null} ); } function ClickableAreaBorder() { return ( <> ); } interface CollectionAreaListProps { area: CollectionArea; onClick: (props: OnClick) => void; highlightClickableAreas: boolean | undefined; } function CollectionAreaList({ area, onClick, highlightClickableAreas, }: CollectionAreaListProps) { return ( ( onClick(item)}> {highlightClickableAreas ? : null} {item.clickableAreas.map((cA, index) => ( ))} )} /> ); } const styles = StyleSheet.create({ clickableHighlightTopLeft: { borderTopWidth: 1, borderLeftWidth: 1, borderColor: 'blue', height: 8, width: 8, position: 'absolute', left: -1, top: -1, }, clickableHighlightTopRight: { borderTopWidth: 1, borderRightWidth: 1, borderColor: 'blue', height: 8, width: 8, position: 'absolute', right: -1, top: -1, }, clickableHighlightBottomLeft: { borderBottomWidth: 1, borderLeftWidth: 1, borderColor: 'blue', height: 8, width: 8, position: 'absolute', left: -1, bottom: -1, }, clickableHighlightBottomRight: { borderBottomWidth: 1, borderRightWidth: 1, borderColor: 'blue', height: 8, width: 8, position: 'absolute', right: -1, bottom: -1, }, });