aboutsummaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/mobile/components/bookmarks/BookmarkCard.tsx81
-rw-r--r--apps/mobile/package.json4
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",