From 61e970bb8c75c6edb279447be3f7ca8a00bd607d Mon Sep 17 00:00:00 2001 From: MohamedBassem Date: Wed, 13 Mar 2024 03:36:32 +0000 Subject: mobile: Add support for loading states for bookmarks --- packages/mobile/assets/blur.jpeg | Bin 0 -> 178818 bytes .../mobile/components/bookmarks/BookmarkCard.tsx | 58 ++++++++++++++++++--- packages/mobile/components/ui/Skeleton.tsx | 38 ++++++++++++++ packages/mobile/package.json | 1 + pnpm-lock.yaml | 12 +++++ 5 files changed, 103 insertions(+), 6 deletions(-) create mode 100644 packages/mobile/assets/blur.jpeg create mode 100644 packages/mobile/components/ui/Skeleton.tsx diff --git a/packages/mobile/assets/blur.jpeg b/packages/mobile/assets/blur.jpeg new file mode 100644 index 00000000..387ce697 Binary files /dev/null and b/packages/mobile/assets/blur.jpeg differ diff --git a/packages/mobile/components/bookmarks/BookmarkCard.tsx b/packages/mobile/components/bookmarks/BookmarkCard.tsx index 607c2fc8..30c6724a 100644 --- a/packages/mobile/components/bookmarks/BookmarkCard.tsx +++ b/packages/mobile/components/bookmarks/BookmarkCard.tsx @@ -1,11 +1,33 @@ import { ZBookmark } from "@hoarder/trpc/types/bookmarks"; -import { ZBookmarkTags } from "@hoarder/trpc/types/tags"; import { Star, Archive, Trash } from "lucide-react-native"; import { View, Text, Image, ScrollView, Pressable } from "react-native"; import Markdown from "react-native-markdown-display"; +import { Skeleton } from "../ui/Skeleton"; + import { api } from "@/lib/trpc"; +const MAX_LOADING_MSEC = 30 * 1000; + +export function isBookmarkStillCrawling(bookmark: ZBookmark) { + return ( + bookmark.content.type === "link" && + !bookmark.content.crawledAt && + Date.now().valueOf() - bookmark.createdAt.valueOf() < MAX_LOADING_MSEC + ); +} + +export function isBookmarkStillTagging(bookmark: ZBookmark) { + return ( + bookmark.taggingStatus === "pending" && + Date.now().valueOf() - bookmark.createdAt.valueOf() < MAX_LOADING_MSEC + ); +} + +export function isBookmarkStillLoading(bookmark: ZBookmark) { + return isBookmarkStillTagging(bookmark) || isBookmarkStillCrawling(bookmark); +} + function ActionBar({ bookmark }: { bookmark: ZBookmark }) { const apiUtils = api.useUtils(); @@ -61,7 +83,18 @@ function ActionBar({ bookmark }: { bookmark: ZBookmark }) { ); } -function TagList({ tags }: { tags: ZBookmarkTags[] }) { +function TagList({ bookmark }: { bookmark: ZBookmark }) { + const tags = bookmark.tags; + + if (isBookmarkStillTagging(bookmark)) { + return ( + <> + + + + ); + } + return ( @@ -91,7 +124,7 @@ function LinkCard({ bookmark }: { bookmark: ZBookmark }) { className="h-56 min-h-56 w-full" /> ) : ( - + ); return ( @@ -101,7 +134,7 @@ function LinkCard({ bookmark }: { bookmark: ZBookmark }) { {bookmark.content.title || parsedUrl.host} - + {parsedUrl.host} @@ -120,7 +153,7 @@ function TextCard({ bookmark }: { bookmark: ZBookmark }) { {bookmark.content.text} - + @@ -138,7 +171,20 @@ export default function BookmarkCard({ { bookmarkId: initialData.id, }, - { initialData }, + { + initialData, + refetchInterval: (query) => { + const data = query.state.data; + if (!data) { + return false; + } + // If the link is not crawled or not tagged + if (isBookmarkStillLoading(data)) { + return 1000; + } + return false; + }, + }, ); let comp; diff --git a/packages/mobile/components/ui/Skeleton.tsx b/packages/mobile/components/ui/Skeleton.tsx new file mode 100644 index 00000000..68b22e1e --- /dev/null +++ b/packages/mobile/components/ui/Skeleton.tsx @@ -0,0 +1,38 @@ +import { useEffect, useRef } from "react"; +import { Animated, type View } from "react-native"; + +import { cn } from "@/lib/utils"; + +function Skeleton({ + className, + ...props +}: { className?: string } & React.ComponentPropsWithoutRef) { + const fadeAnim = useRef(new Animated.Value(0.5)).current; + + useEffect(() => { + Animated.loop( + Animated.sequence([ + Animated.timing(fadeAnim, { + toValue: 1, + duration: 1000, + useNativeDriver: true, + }), + Animated.timing(fadeAnim, { + toValue: 0.5, + duration: 1000, + useNativeDriver: true, + }), + ]), + ).start(); + }, [fadeAnim]); + + return ( + + ); +} + +export { Skeleton }; diff --git a/packages/mobile/package.json b/packages/mobile/package.json index 613bb3c3..2d43346b 100644 --- a/packages/mobile/package.json +++ b/packages/mobile/package.json @@ -17,6 +17,7 @@ "expo-config-plugin-ios-share-extension": "^0.0.4", "expo-constants": "~15.4.5", "expo-dev-client": "^3.3.9", + "expo-image": "^1.10.6", "expo-linking": "~6.2.2", "expo-router": "~3.4.8", "expo-secure-store": "^12.8.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b11597fa..df5602d9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -214,6 +214,9 @@ importers: expo-dev-client: specifier: ^3.3.9 version: 3.3.9(expo@50.0.11) + expo-image: + specifier: ^1.10.6 + version: 1.10.6(expo@50.0.11) expo-linking: specifier: ~6.2.2 version: 6.2.2(expo@50.0.11) @@ -9244,6 +9247,15 @@ packages: fontfaceobserver: 2.3.0 dev: false + /expo-image@1.10.6(expo@50.0.11): + resolution: {integrity: sha512-vcnAIym1eU8vQgV1re1E7rVQZStJimBa4aPDhjFfzMzbddAF7heJuagyewiUkTzbZUwYzPaZAie6VJPyWx9Ueg==} + peerDependencies: + expo: '*' + dependencies: + '@react-native/assets-registry': 0.73.1 + expo: 50.0.11(@babel/core@7.23.9)(@react-native/babel-preset@0.73.21) + dev: false + /expo-json-utils@0.12.3: resolution: {integrity: sha512-4pypQdinpNc6XY9wsZk56njvzDh+B/9mISr7FPP3CVk1QGB1nSLh883/BCDSgnsephATZkC5HG+cdE60kCAR6A==} dev: false -- cgit v1.2.3-70-g09d2