/ widget-task-handler.ts
widget-task-handler.ts
1 import React from "react"; 2 import type { WidgetTaskHandlerProps } from "react-native-android-widget"; 3 import { ImageWidget } from "./components/image-widget"; 4 import { AuthStorage } from "./utils/auth-storage"; 5 import { ConvexHttpClient } from "convex/browser"; 6 import { api } from "./convex/_generated/api"; 7 import { getCachedImage, cacheImage } from "./utils/image-cache"; 8 9 async function getClerkAuthToken(): Promise<string | null> { 10 try { 11 const storedToken = await AuthStorage.getToken(); 12 if (storedToken) return storedToken; 13 console.warn("No Clerk auth token found in storage"); 14 return null; 15 } catch (error) { 16 console.error("Failed to get Clerk auth token:", error); 17 return null; 18 } 19 } 20 21 async function fetchLatestDrawing(): Promise<string | null> { 22 try { 23 console.log("Fetching latest drawing for widget update..."); 24 25 const convexUrl = process.env.EXPO_PUBLIC_CONVEX_URL; 26 if (!convexUrl) { 27 console.error("EXPO_PUBLIC_CONVEX_URL is not defined."); 28 return await getCachedImage(); 29 } 30 31 const client = new ConvexHttpClient(convexUrl); 32 33 const authToken = await getClerkAuthToken(); 34 if (!authToken) { 35 console.warn("No auth token available, trying cached image..."); 36 return await getCachedImage(); 37 } 38 client.setAuth(authToken); 39 40 const result = await client.query(api.drawings.getDrawings, { 41 pairDrawingsOnly: true, 42 limit: 1, 43 }); 44 45 if (result && result.length > 0 && result[0].imageUrl) { 46 const imageUrl = result[0].imageUrl; 47 cacheImage(imageUrl).catch((error) => { 48 console.error("Failed to cache image:", error); 49 }); 50 return imageUrl; 51 } 52 53 console.log("No drawings found, trying cached image..."); 54 return await getCachedImage(); 55 } catch (error) { 56 console.error("Failed to fetch latest drawing:", error); 57 return await getCachedImage(); 58 } 59 } 60 61 const nameToWidget = { 62 Liontin: ImageWidget, 63 }; 64 65 export async function widgetTaskHandler(props: WidgetTaskHandlerProps) { 66 const widgetInfo = props.widgetInfo; 67 const Widget = 68 nameToWidget[widgetInfo.widgetName as keyof typeof nameToWidget]; 69 70 switch (props.widgetAction) { 71 case "WIDGET_ADDED": { 72 console.log("Widget added, fetching initial data..."); 73 const imageUrl = await fetchLatestDrawing(); 74 props.renderWidget( 75 React.createElement(Widget, { 76 imageUrl, 77 width: 180, 78 }), 79 ); 80 break; 81 } 82 83 case "WIDGET_CLICK": 84 case "WIDGET_UPDATE": { 85 console.log("Widget update triggered, fetching latest drawing..."); 86 const imageUrl = await fetchLatestDrawing(); 87 props.renderWidget(React.createElement(Widget, { imageUrl, width: 180 })); 88 break; 89 } 90 91 case "WIDGET_RESIZED": { 92 console.log("Widget resized, re-rendering..."); 93 const imageUrl = await fetchLatestDrawing(); 94 props.renderWidget( 95 React.createElement(Widget, { 96 imageUrl, 97 width: 180, 98 }), 99 ); 100 break; 101 } 102 103 case "WIDGET_DELETED": 104 console.log("Widget deleted"); 105 break; 106 107 default: 108 break; 109 } 110 }