display pdf files
This commit is contained in:
@@ -79,6 +79,7 @@ class ApiClient {
|
|||||||
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
this.accessToken = data.access_token;
|
this.accessToken = data.access_token;
|
||||||
|
await tokenStorage.setAccessToken(data.access_token);
|
||||||
await tokenStorage.setRefreshToken(data.refresh_token);
|
await tokenStorage.setRefreshToken(data.refresh_token);
|
||||||
return true;
|
return true;
|
||||||
} catch {
|
} catch {
|
||||||
@@ -89,6 +90,7 @@ class ApiClient {
|
|||||||
|
|
||||||
private async clearAuth() {
|
private async clearAuth() {
|
||||||
this.accessToken = null;
|
this.accessToken = null;
|
||||||
|
await tokenStorage.deleteAccessToken();
|
||||||
await tokenStorage.deleteRefreshToken();
|
await tokenStorage.deleteRefreshToken();
|
||||||
await tokenStorage.deleteUser();
|
await tokenStorage.deleteUser();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,22 @@
|
|||||||
import * as SecureStore from 'expo-secure-store';
|
import * as SecureStore from 'expo-secure-store';
|
||||||
|
|
||||||
|
const ACCESS_KEY = 'vaultdrop_access_token';
|
||||||
const REFRESH_KEY = 'vaultdrop_refresh_token';
|
const REFRESH_KEY = 'vaultdrop_refresh_token';
|
||||||
const USER_KEY = 'vaultdrop_user';
|
const USER_KEY = 'vaultdrop_user';
|
||||||
|
|
||||||
export const tokenStorage = {
|
export const tokenStorage = {
|
||||||
|
async getAccessToken(): Promise<string | null> {
|
||||||
|
return SecureStore.getItemAsync(ACCESS_KEY);
|
||||||
|
},
|
||||||
|
|
||||||
|
async setAccessToken(token: string): Promise<void> {
|
||||||
|
await SecureStore.setItemAsync(ACCESS_KEY, token);
|
||||||
|
},
|
||||||
|
|
||||||
|
async deleteAccessToken(): Promise<void> {
|
||||||
|
await SecureStore.deleteItemAsync(ACCESS_KEY);
|
||||||
|
},
|
||||||
|
|
||||||
async getRefreshToken(): Promise<string | null> {
|
async getRefreshToken(): Promise<string | null> {
|
||||||
return SecureStore.getItemAsync(REFRESH_KEY);
|
return SecureStore.getItemAsync(REFRESH_KEY);
|
||||||
},
|
},
|
||||||
|
|||||||
+37
-77
@@ -1,4 +1,4 @@
|
|||||||
import React, { useRef, useState, useEffect } from 'react';
|
import React, { useRef, useState } from 'react';
|
||||||
import {
|
import {
|
||||||
View,
|
View,
|
||||||
Text,
|
Text,
|
||||||
@@ -10,12 +10,10 @@ import {
|
|||||||
ScrollView,
|
ScrollView,
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import { RouteProp, useRoute } from '@react-navigation/native';
|
import { RouteProp, useRoute } from '@react-navigation/native';
|
||||||
import Pdf from 'react-native-pdf';
|
|
||||||
import { downloadAsync, documentDirectory, getInfoAsync } from 'expo-file-system/legacy';
|
|
||||||
import { useFile, useFileImage } from '../hooks/useFiles';
|
import { useFile, useFileImage } from '../hooks/useFiles';
|
||||||
import { apiClient } from '../api/client';
|
|
||||||
import { TagChip } from '../components/TagChip';
|
import { TagChip } from '../components/TagChip';
|
||||||
import { FileThumbnail } from '../components/FileThumbnail';
|
import { FileThumbnail } from '../components/FileThumbnail';
|
||||||
|
import type { Thumbnail } from '../types';
|
||||||
|
|
||||||
const SCREEN_WIDTH = Dimensions.get('window').width;
|
const SCREEN_WIDTH = Dimensions.get('window').width;
|
||||||
|
|
||||||
@@ -30,71 +28,42 @@ function DetailItem({ fileId }: { fileId: string }) {
|
|||||||
const { data: fileData } = useFile(fileId);
|
const { data: fileData } = useFile(fileId);
|
||||||
const uri = imageData?.data?.url;
|
const uri = imageData?.data?.url;
|
||||||
const file = fileData as any;
|
const file = fileData as any;
|
||||||
const isPdf = file?.data?.mimeType === 'application/pdf';
|
|
||||||
const [localPdfUri, setLocalPdfUri] = useState<string | null>(null);
|
|
||||||
const [pdfLoading, setPdfLoading] = useState(false);
|
|
||||||
|
|
||||||
useEffect(() => {
|
const fullThumbnails: Thumbnail[] = (file?.data?.thumbnails ?? [])
|
||||||
if (!isPdf || !uri) return;
|
.filter((t: Thumbnail) => t.resolutionLabel === 'full')
|
||||||
let cancelled = false;
|
.sort((a: Thumbnail, b: Thumbnail) => a.pageNumber - b.pageNumber);
|
||||||
|
|
||||||
async function downloadPdf() {
|
const hasPages = fullThumbnails.length > 0;
|
||||||
if (!uri) return;
|
|
||||||
setPdfLoading(true);
|
|
||||||
const localUri = `${documentDirectory}pdf_${fileId}.pdf`;
|
|
||||||
try {
|
|
||||||
const info = await getInfoAsync(localUri);
|
|
||||||
if (info.exists && info.size > 100) {
|
|
||||||
if (!cancelled) setLocalPdfUri(localUri);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const headers: Record<string, string> = {};
|
|
||||||
const token = apiClient.getAccessToken();
|
|
||||||
if (token) headers['Authorization'] = `Bearer ${token}`;
|
|
||||||
await downloadAsync(uri, localUri, { headers });
|
|
||||||
if (!cancelled) setLocalPdfUri(localUri);
|
|
||||||
} catch (e) {
|
|
||||||
console.log('PDF download error:', e);
|
|
||||||
} finally {
|
|
||||||
if (!cancelled) setPdfLoading(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
downloadPdf();
|
|
||||||
return () => { cancelled = true; };
|
|
||||||
}, [isPdf, uri, fileId]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollView style={styles.page} contentContainerStyle={styles.pageContent}>
|
<ScrollView style={styles.page} contentContainerStyle={styles.pageContent}>
|
||||||
<View style={styles.imageContainer}>
|
{hasPages ? (
|
||||||
{isPdf ? (
|
fullThumbnails.map((thumb) => (
|
||||||
pdfLoading || !localPdfUri ? (
|
<View key={thumb.id} style={styles.pageImageContainer}>
|
||||||
<ActivityIndicator size="large" color="#fff" />
|
<Image
|
||||||
) : (
|
source={{ uri: thumb.url }}
|
||||||
<Pdf
|
style={[styles.pageImage, { height: thumb.height * (SCREEN_WIDTH / thumb.width) }]}
|
||||||
source={{ uri: localPdfUri }}
|
resizeMode="contain"
|
||||||
style={styles.pdf}
|
|
||||||
onLoadComplete={(numberOfPages) => {
|
|
||||||
console.log(`PDF loaded: ${numberOfPages} pages`);
|
|
||||||
}}
|
|
||||||
onError={(error) => {
|
|
||||||
console.log('PDF error:', error);
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
)
|
</View>
|
||||||
) : uri ? (
|
))
|
||||||
<Image source={{ uri }} style={styles.image} resizeMode="contain" />
|
) : (
|
||||||
) : file ? (
|
<View style={styles.imageContainer}>
|
||||||
<FileThumbnail
|
{uri ? (
|
||||||
mimeType={file.mimeType ?? 'application/pdf'}
|
<Image source={{ uri }} style={styles.image} resizeMode="contain" />
|
||||||
fileName={file.name ?? fileId}
|
) : file ? (
|
||||||
size={SCREEN_WIDTH * 0.6}
|
<FileThumbnail
|
||||||
isLoading={imageLoading}
|
thumbnailUrl={file.data?.thumbnailUrl}
|
||||||
/>
|
mimeType={file.mimeType ?? 'application/pdf'}
|
||||||
) : (
|
fileName={file.name ?? fileId}
|
||||||
<ActivityIndicator size="large" color="#1976D2" />
|
size={SCREEN_WIDTH * 0.6}
|
||||||
)}
|
isLoading={imageLoading}
|
||||||
</View>
|
/>
|
||||||
|
) : (
|
||||||
|
<ActivityIndicator size="large" color="#1976D2" />
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
|
||||||
<View style={styles.details}>
|
<View style={styles.details}>
|
||||||
<Text style={styles.fileName}>{imageData?.data?.name ?? file?.name ?? fileId}</Text>
|
<Text style={styles.fileName}>{imageData?.data?.name ?? file?.name ?? fileId}</Text>
|
||||||
@@ -201,22 +170,13 @@ const styles = StyleSheet.create({
|
|||||||
width: SCREEN_WIDTH,
|
width: SCREEN_WIDTH,
|
||||||
height: SCREEN_WIDTH,
|
height: SCREEN_WIDTH,
|
||||||
},
|
},
|
||||||
pdf: {
|
pageImageContainer: {
|
||||||
width: SCREEN_WIDTH,
|
|
||||||
height: SCREEN_WIDTH,
|
|
||||||
backgroundColor: '#fff',
|
|
||||||
},
|
|
||||||
placeholder: {
|
|
||||||
width: SCREEN_WIDTH,
|
|
||||||
height: SCREEN_WIDTH,
|
|
||||||
justifyContent: 'center',
|
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
backgroundColor: '#1a1a2e',
|
backgroundColor: '#000',
|
||||||
|
paddingVertical: 4,
|
||||||
},
|
},
|
||||||
placeholderText: {
|
pageImage: {
|
||||||
fontSize: 48,
|
width: SCREEN_WIDTH,
|
||||||
color: '#1976D2',
|
|
||||||
fontWeight: '700',
|
|
||||||
},
|
},
|
||||||
details: {
|
details: {
|
||||||
backgroundColor: '#fff',
|
backgroundColor: '#fff',
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ function FileEditItem({ fileId, selected, onPress }: FileEditItemProps) {
|
|||||||
<Image source={{ uri }} style={styles.thumb} />
|
<Image source={{ uri }} style={styles.thumb} />
|
||||||
) : (
|
) : (
|
||||||
<FileThumbnail
|
<FileThumbnail
|
||||||
|
thumbnailUrl={file?.data?.thumbnailUrl}
|
||||||
mimeType={file?.mimeType ?? 'application/octet-stream'}
|
mimeType={file?.mimeType ?? 'application/octet-stream'}
|
||||||
fileName={file?.name ?? fileId}
|
fileName={file?.name ?? fileId}
|
||||||
size={ITEM_SIZE}
|
size={ITEM_SIZE}
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ function FolderGridItem({ file, onPress, onLongPress, selected, onFolderPress }:
|
|||||||
>
|
>
|
||||||
<FileThumbnail
|
<FileThumbnail
|
||||||
uri={data?.data?.url}
|
uri={data?.data?.url}
|
||||||
|
thumbnailUrl={file.thumbnailUrl}
|
||||||
mimeType={file.mimeType}
|
mimeType={file.mimeType}
|
||||||
fileName={file.name}
|
fileName={file.name}
|
||||||
size={ITEM_SIZE}
|
size={ITEM_SIZE}
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ function FileGridItem({ file, onPress, onLongPress, selected }: { file: FileItem
|
|||||||
>
|
>
|
||||||
<FileThumbnail
|
<FileThumbnail
|
||||||
uri={data?.data?.url}
|
uri={data?.data?.url}
|
||||||
|
thumbnailUrl={file.thumbnailUrl}
|
||||||
mimeType={file.mimeType}
|
mimeType={file.mimeType}
|
||||||
fileName={file.name}
|
fileName={file.name}
|
||||||
size={ITEM_SIZE}
|
size={ITEM_SIZE}
|
||||||
|
|||||||
@@ -30,13 +30,14 @@ function getExtension(fileName: string): string {
|
|||||||
|
|
||||||
interface FileThumbnailProps {
|
interface FileThumbnailProps {
|
||||||
uri?: string;
|
uri?: string;
|
||||||
|
thumbnailUrl?: string;
|
||||||
mimeType: string;
|
mimeType: string;
|
||||||
fileName: string;
|
fileName: string;
|
||||||
size: number;
|
size: number;
|
||||||
isLoading?: boolean;
|
isLoading?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function FileThumbnail({ uri, mimeType, fileName, size, isLoading }: FileThumbnailProps) {
|
export function FileThumbnail({ uri, thumbnailUrl, mimeType, fileName, size, isLoading }: FileThumbnailProps) {
|
||||||
const info = getFileInfo(mimeType, fileName);
|
const info = getFileInfo(mimeType, fileName);
|
||||||
const ext = getExtension(fileName);
|
const ext = getExtension(fileName);
|
||||||
|
|
||||||
@@ -48,8 +49,10 @@ export function FileThumbnail({ uri, mimeType, fileName, size, isLoading }: File
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uri && mimeType.startsWith('image/')) {
|
const imageUri = thumbnailUrl || (uri && mimeType.startsWith('image/') ? uri : undefined);
|
||||||
return <Image source={{ uri }} style={[styles.image, { width: size, height: size }]} />;
|
|
||||||
|
if (imageUri) {
|
||||||
|
return <Image source={{ uri: imageUri }} style={[styles.image, { width: size, height: size }]} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -28,6 +28,11 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
|
|||||||
if (stored) {
|
if (stored) {
|
||||||
const userData = JSON.parse(stored) as User;
|
const userData = JSON.parse(stored) as User;
|
||||||
setUser(userData);
|
setUser(userData);
|
||||||
|
|
||||||
|
const accessToken = await tokenStorage.getAccessToken();
|
||||||
|
if (accessToken) {
|
||||||
|
apiClient.setAccessToken(accessToken);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
await tokenStorage.deleteUser();
|
await tokenStorage.deleteUser();
|
||||||
@@ -43,6 +48,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
apiClient.setAccessToken(response.access_token);
|
apiClient.setAccessToken(response.access_token);
|
||||||
|
await tokenStorage.setAccessToken(response.access_token);
|
||||||
await tokenStorage.setRefreshToken(response.refresh_token);
|
await tokenStorage.setRefreshToken(response.refresh_token);
|
||||||
await tokenStorage.setUser(JSON.stringify(response.user));
|
await tokenStorage.setUser(JSON.stringify(response.user));
|
||||||
setUser(response.user);
|
setUser(response.user);
|
||||||
@@ -55,6 +61,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
apiClient.setAccessToken(response.access_token);
|
apiClient.setAccessToken(response.access_token);
|
||||||
|
await tokenStorage.setAccessToken(response.access_token);
|
||||||
await tokenStorage.setRefreshToken(response.refresh_token);
|
await tokenStorage.setRefreshToken(response.refresh_token);
|
||||||
await tokenStorage.setUser(JSON.stringify(response.user));
|
await tokenStorage.setUser(JSON.stringify(response.user));
|
||||||
setUser(response.user);
|
setUser(response.user);
|
||||||
@@ -69,6 +76,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
|
|||||||
} catch {}
|
} catch {}
|
||||||
|
|
||||||
apiClient.setAccessToken(null);
|
apiClient.setAccessToken(null);
|
||||||
|
await tokenStorage.deleteAccessToken();
|
||||||
await tokenStorage.deleteRefreshToken();
|
await tokenStorage.deleteRefreshToken();
|
||||||
await tokenStorage.deleteUser();
|
await tokenStorage.deleteUser();
|
||||||
setUser(null);
|
setUser(null);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ export function useFiles(page: number = 1, limit: number = 20) {
|
|||||||
queryKey: ['files', page, limit],
|
queryKey: ['files', page, limit],
|
||||||
queryFn: () =>
|
queryFn: () =>
|
||||||
apiClient.get<PaginatedResponse<FileItem>>(
|
apiClient.get<PaginatedResponse<FileItem>>(
|
||||||
`${ENDPOINTS.FILES}?page=${page}&limit=${limit}`
|
`${ENDPOINTS.FILES}?page=${page}&limit=${limit}&thumbnail=thumbnail`
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -16,7 +16,7 @@ export function useFiles(page: number = 1, limit: number = 20) {
|
|||||||
export function useFile(id: string) {
|
export function useFile(id: string) {
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: ['files', id],
|
queryKey: ['files', id],
|
||||||
queryFn: () => apiClient.get<FileItem>(`${ENDPOINTS.FILES}/${id}`),
|
queryFn: () => apiClient.get<FileItem>(`${ENDPOINTS.FILES}/${id}?thumbnail=thumbnail`),
|
||||||
enabled: !!id,
|
enabled: !!id,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -75,7 +75,7 @@ export function useFilesByParent(parentId: string) {
|
|||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: ['files', 'parent', parentId],
|
queryKey: ['files', 'parent', parentId],
|
||||||
queryFn: () =>
|
queryFn: () =>
|
||||||
apiClient.get<{ data: FileItem[] }>(`${ENDPOINTS.FOLDERS}/${parentId}/files`),
|
apiClient.get<{ data: FileItem[] }>(`${ENDPOINTS.FOLDERS}/${parentId}/files?thumbnail=thumbnail`),
|
||||||
enabled: !!parentId,
|
enabled: !!parentId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
-91
@@ -24,7 +24,6 @@
|
|||||||
"react-native-mmkv": "^4.3.2",
|
"react-native-mmkv": "^4.3.2",
|
||||||
"react-native-nitro-image": "^0.15.1",
|
"react-native-nitro-image": "^0.15.1",
|
||||||
"react-native-nitro-modules": "^0.36.1",
|
"react-native-nitro-modules": "^0.36.1",
|
||||||
"react-native-pdf": "^7.0.4",
|
|
||||||
"react-native-safe-area-context": "~5.7.0",
|
"react-native-safe-area-context": "~5.7.0",
|
||||||
"react-native-screens": "4.25.2",
|
"react-native-screens": "4.25.2",
|
||||||
"react-native-vision-camera": "^5.1.0"
|
"react-native-vision-camera": "^5.1.0"
|
||||||
@@ -1669,12 +1668,6 @@
|
|||||||
"node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0"
|
"node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@react-native/normalize-color": {
|
|
||||||
"version": "2.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@react-native/normalize-color/-/normalize-color-2.1.0.tgz",
|
|
||||||
"integrity": "sha512-Z1jQI2NpdFJCVgpY+8Dq/Bt3d+YUi1928Q+/CZm/oh66fzM0RUl54vvuXlPJKybH4pdCZey1eDTPaLHkMPNgWA==",
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/@react-native/normalize-colors": {
|
"node_modules/@react-native/normalize-colors": {
|
||||||
"version": "0.86.0",
|
"version": "0.86.0",
|
||||||
"resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.86.0.tgz",
|
"resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.86.0.tgz",
|
||||||
@@ -2141,13 +2134,6 @@
|
|||||||
"node": "18 || 20 || >=22"
|
"node": "18 || 20 || >=22"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/base-64": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/base-64/-/base-64-1.0.0.tgz",
|
|
||||||
"integrity": "sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==",
|
|
||||||
"license": "MIT",
|
|
||||||
"peer": true
|
|
||||||
},
|
|
||||||
"node_modules/base64-js": {
|
"node_modules/base64-js": {
|
||||||
"version": "1.5.1",
|
"version": "1.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||||
@@ -2590,12 +2576,6 @@
|
|||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/crypto-js": {
|
|
||||||
"version": "4.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
|
|
||||||
"integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==",
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/csstype": {
|
"node_modules/csstype": {
|
||||||
"version": "3.2.3",
|
"version": "3.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
|
||||||
@@ -2659,17 +2639,6 @@
|
|||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/deprecated-react-native-prop-types": {
|
|
||||||
"version": "2.3.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/deprecated-react-native-prop-types/-/deprecated-react-native-prop-types-2.3.0.tgz",
|
|
||||||
"integrity": "sha512-pWD0voFtNYxrVqvBMYf5gq3NA2GCpfodS1yNynTPc93AYA/KEMGeWDqqeUB6R2Z9ZofVhks2aeJXiuQqKNpesA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@react-native/normalize-color": "*",
|
|
||||||
"invariant": "*",
|
|
||||||
"prop-types": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/destroy": {
|
"node_modules/destroy": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
|
||||||
@@ -4829,15 +4798,6 @@
|
|||||||
"node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0"
|
"node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/object-assign": {
|
|
||||||
"version": "4.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
|
||||||
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.10.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/on-finished": {
|
"node_modules/on-finished": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
|
||||||
@@ -5201,23 +5161,6 @@
|
|||||||
"node": ">= 6"
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/prop-types": {
|
|
||||||
"version": "15.8.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
|
||||||
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"loose-envify": "^1.4.0",
|
|
||||||
"object-assign": "^4.1.1",
|
|
||||||
"react-is": "^16.13.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/prop-types/node_modules/react-is": {
|
|
||||||
"version": "16.13.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
|
||||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/query-string": {
|
"node_modules/query-string": {
|
||||||
"version": "7.1.3",
|
"version": "7.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/query-string/-/query-string-7.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/query-string/-/query-string-7.1.3.tgz",
|
||||||
@@ -5350,25 +5293,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-native-blob-util": {
|
|
||||||
"version": "0.24.10",
|
|
||||||
"resolved": "https://registry.npmjs.org/react-native-blob-util/-/react-native-blob-util-0.24.10.tgz",
|
|
||||||
"integrity": "sha512-4yazgoCstXgt2/CRURtowGP3furAzbWdfMQ4jyUPDo5xtLx7KE2F/xMz3oU3shLwfL4id0iEKsBywoxvJSHPzQ==",
|
|
||||||
"license": "MIT",
|
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
|
||||||
"base-64": "1.0.0",
|
|
||||||
"glob": "13.0.6"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"type": "github",
|
|
||||||
"url": "https://github.com/sponsors/ronradtke"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"react": "*",
|
|
||||||
"react-native": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/react-native-mmkv": {
|
"node_modules/react-native-mmkv": {
|
||||||
"version": "4.3.2",
|
"version": "4.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/react-native-mmkv/-/react-native-mmkv-4.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-native-mmkv/-/react-native-mmkv-4.3.2.tgz",
|
||||||
@@ -5404,21 +5328,6 @@
|
|||||||
"react-native": "*"
|
"react-native": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-native-pdf": {
|
|
||||||
"version": "7.0.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/react-native-pdf/-/react-native-pdf-7.0.4.tgz",
|
|
||||||
"integrity": "sha512-Uhxn5SSguMKvbwD50iIZfYPmYeKcX+9I3tc4J3HCbRExAN0uqXTAKx2pvbR2Y62umAj0JS274FcbSldQfoQfyg==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"crypto-js": "4.2.0",
|
|
||||||
"deprecated-react-native-prop-types": "^2.3.0"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"react": "*",
|
|
||||||
"react-native": "*",
|
|
||||||
"react-native-blob-util": ">=0.13.7"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/react-native-safe-area-context": {
|
"node_modules/react-native-safe-area-context": {
|
||||||
"version": "5.7.0",
|
"version": "5.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-5.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-5.7.0.tgz",
|
||||||
|
|||||||
@@ -19,7 +19,6 @@
|
|||||||
"react-native-mmkv": "^4.3.2",
|
"react-native-mmkv": "^4.3.2",
|
||||||
"react-native-nitro-image": "^0.15.1",
|
"react-native-nitro-image": "^0.15.1",
|
||||||
"react-native-nitro-modules": "^0.36.1",
|
"react-native-nitro-modules": "^0.36.1",
|
||||||
"react-native-pdf": "^7.0.4",
|
|
||||||
"react-native-safe-area-context": "~5.7.0",
|
"react-native-safe-area-context": "~5.7.0",
|
||||||
"react-native-screens": "4.25.2",
|
"react-native-screens": "4.25.2",
|
||||||
"react-native-vision-camera": "^5.1.0"
|
"react-native-vision-camera": "^5.1.0"
|
||||||
|
|||||||
@@ -1,3 +1,13 @@
|
|||||||
|
export interface Thumbnail {
|
||||||
|
id: string;
|
||||||
|
pageNumber: number;
|
||||||
|
resolutionLabel: string;
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
url: string;
|
||||||
|
mimeType: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface FileItem {
|
export interface FileItem {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
@@ -10,6 +20,8 @@ export interface FileItem {
|
|||||||
isFolder: boolean;
|
isFolder: boolean;
|
||||||
parentFileId?: string;
|
parentFileId?: string;
|
||||||
url?: string;
|
url?: string;
|
||||||
|
thumbnailUrl?: string;
|
||||||
|
thumbnails?: Thumbnail[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isFolder(file: FileItem): boolean {
|
export function isFolder(file: FileItem): boolean {
|
||||||
|
|||||||
Reference in New Issue
Block a user