diff options
Diffstat (limited to 'apps/mobile')
| -rw-r--r-- | apps/mobile/components/bookmarks/BookmarkCard.tsx | 81 | ||||
| -rw-r--r-- | apps/mobile/package.json | 4 |
2 files changed, 83 insertions, 2 deletions
diff --git a/apps/mobile/components/bookmarks/BookmarkCard.tsx b/apps/mobile/components/bookmarks/BookmarkCard.tsx index 52d39c5c..7329aa46 100644 --- a/apps/mobile/components/bookmarks/BookmarkCard.tsx +++ b/apps/mobile/components/bookmarks/BookmarkCard.tsx @@ -6,15 +6,19 @@ import { Platform, Pressable, ScrollView, + Share, Text, View, } from "react-native"; +import * as Clipboard from "expo-clipboard"; +import * as FileSystem from "expo-file-system"; import * as Haptics from "expo-haptics"; import { router, useRouter } from "expo-router"; +import * as Sharing from "expo-sharing"; import useAppSettings from "@/lib/settings"; import { api } from "@/lib/trpc"; import { MenuView } from "@react-native-menu/menu"; -import { Ellipsis, Star } from "lucide-react-native"; +import { Ellipsis, Share2, Star } from "lucide-react-native"; import type { ZBookmark } from "@karakeep/shared/types/bookmarks"; import { @@ -37,6 +41,7 @@ import TagPill from "./TagPill"; function ActionBar({ bookmark }: { bookmark: ZBookmark }) { const { toast } = useToast(); + const { settings } = useAppSettings(); const onError = () => { toast({ @@ -86,6 +91,71 @@ function ActionBar({ bookmark }: { bookmark: ZBookmark }) { ], ); + const handleShare = async () => { + try { + switch (bookmark.content.type) { + case BookmarkTypes.LINK: + await Share.share({ + url: bookmark.content.url, + message: bookmark.content.url, + }); + break; + + case BookmarkTypes.TEXT: + await Clipboard.setStringAsync(bookmark.content.text); + toast({ + message: "Text copied to clipboard", + showProgress: false, + }); + break; + + case BookmarkTypes.ASSET: + if (bookmark.content.assetType === "image") { + if (await Sharing.isAvailableAsync()) { + const assetUrl = `${settings.address}/api/assets/${bookmark.content.assetId}`; + const fileUri = `${FileSystem.documentDirectory}temp_image.jpg`; + + const downloadResult = await FileSystem.downloadAsync( + assetUrl, + fileUri, + { + headers: { + Authorization: `Bearer ${settings.apiKey}`, + }, + }, + ); + + if (downloadResult.status === 200) { + await Sharing.shareAsync(downloadResult.uri); + // Clean up the temporary file + await FileSystem.deleteAsync(downloadResult.uri, { + idempotent: true, + }); + } else { + throw new Error("Failed to download image"); + } + } + } else { + // For PDFs, share the URL + const assetUrl = `${settings.address}/api/assets/${bookmark.content.assetId}`; + await Share.share({ + url: assetUrl, + message: + bookmark.title || bookmark.content.fileName || "PDF Document", + }); + } + break; + } + } catch (error) { + console.error("Share error:", error); + toast({ + message: "Failed to share", + variant: "destructive", + showProgress: false, + }); + } + }; + return ( <View className="flex flex-row gap-4"> {(isArchivePending || isDeletionPending) && <ActivityIndicator />} @@ -105,6 +175,15 @@ function ActionBar({ bookmark }: { bookmark: ZBookmark }) { )} </Pressable> + <Pressable + onPress={() => { + Haptics.selectionAsync(); + handleShare(); + }} + > + <Share2 color="gray" /> + </Pressable> + <MenuView onPressAction={({ nativeEvent }) => { Haptics.selectionAsync(); diff --git a/apps/mobile/package.json b/apps/mobile/package.json index d5c2262f..00010ba6 100644 --- a/apps/mobile/package.json +++ b/apps/mobile/package.json @@ -29,6 +29,7 @@ "expo-clipboard": "^7.0.1", "expo-constants": "~17.0.8", "expo-dev-client": "^5.0.20", + "expo-file-system": "~18.0.12", "expo-haptics": "^14.0.1", "expo-image": "^2.0.7", "expo-image-picker": "^16.0.6", @@ -36,7 +37,8 @@ "expo-navigation-bar": "^4.0.9", "expo-router": "~4.0.21", "expo-secure-store": "^14.0.1", - "expo-share-intent": "3.0.0", + "expo-share-intent": "3.2.3", + "expo-sharing": "~13.0.1", "expo-status-bar": "~2.0.1", "expo-system-ui": "^4.0.9", "expo-web-browser": "^14.0.2", |
