فهرست منبع

Merge pull request #9 from ente-io/file-loading-single-update

File loading single update
Pushkar Anand 4 سال پیش
والد
کامیت
36c84807f1
4فایلهای تغییر یافته به همراه115 افزوده شده و 58 حذف شده
  1. 1 0
      package.json
  2. 34 10
      src/pages/gallery/index.tsx
  3. 23 5
      src/services/collectionService.ts
  4. 57 43
      src/services/fileService.ts

+ 1 - 0
package.json

@@ -24,6 +24,7 @@
     "react-dom": "16.13.1",
     "react-dropzone": "^11.2.4",
     "react-photoswipe": "^1.3.0",
+    "react-top-loading-bar": "^2.0.1",
     "react-virtualized-auto-sizer": "^1.0.2",
     "react-window": "^1.8.6",
     "react-window-infinite-loader": "^1.0.5",

+ 34 - 10
src/pages/gallery/index.tsx

@@ -7,19 +7,27 @@ import {
     getFile,
     getPreview,
     fetchData,
+    localFiles,
 } from 'services/fileService';
 import { getData, LS_KEYS } from 'utils/storage/localStorage';
 import PreviewCard from './components/PreviewCard';
-import { getActualKey } from 'utils/common/key';
+import { getActualKey, getToken } from 'utils/common/key';
 import styled from 'styled-components';
 import PhotoSwipe from 'components/PhotoSwipe/PhotoSwipe';
 import { Options } from 'photoswipe';
 import AutoSizer from 'react-virtualized-auto-sizer';
 import { VariableSizeList as List } from 'react-window';
+import LoadingBar from 'react-top-loading-bar'
 import Collections from './components/Collections';
-import SadFace from 'components/SadFace';
 import Upload from './components/Upload';
-import { collection, fetchCollections, collectionLatestFile, getCollectionLatestFile, getFavItemIds } from 'services/collectionService';
+import {
+    collection,
+    fetchUpdatedCollections,
+    collectionLatestFile,
+    getCollectionLatestFile,
+    getFavItemIds,
+    getLocalCollections
+} from 'services/collectionService';
 import constants from 'utils/strings/constants';
 
 enum ITEM_TYPE {
@@ -106,7 +114,7 @@ export default function Gallery(props) {
     });
     const fetching: { [k: number]: boolean } = {};
 
-
+    const [progress, setProgress] = useState(0)
 
     useEffect(() => {
         const key = getKey(SESSION_KEYS.ENCRYPTION_KEY);
@@ -115,24 +123,35 @@ export default function Gallery(props) {
         }
         const main = async () => {
             setLoading(true);
-            await syncWithRemote();
+            const data = await localFiles();
+            const collections = await getLocalCollections();
+            setData(data);
+            setCollections(collections);
             setLoading(false);
+            setProgress(80);
+            await syncWithRemote();
+            setProgress(100);
         };
         main();
         props.setUploadButtonView(true);
     }, []);
 
     const syncWithRemote = async () => {
-        const token = getData(LS_KEYS.USER).token;
+        const token = getToken();
         const encryptionKey = await getActualKey();
-        const collections = await fetchCollections(token, encryptionKey);
-        const data = await fetchData(token, collections);
+        const updatedCollections = await fetchUpdatedCollections(token, encryptionKey);
+        const data = await fetchData(token, updatedCollections);
+        const collections = await getLocalCollections();
         const collectionLatestFile = await getCollectionLatestFile(collections, data);
         const favItemIds = await getFavItemIds(data);
-        setCollections(collections);
-        setData(data);
+        if (updatedCollections.length > 0) {
+            setCollections(collections);
+            setData(data);
+        }
         setCollectionLatestFile(collectionLatestFile);
         setFavItemIds(favItemIds);
+
+        props.setUploadButtonView(true);
     }
     if (!data || loading) {
         return (
@@ -288,6 +307,11 @@ export default function Gallery(props) {
 
     return (
         <>
+            <LoadingBar
+                color='#f11946'
+                progress={progress}
+                onLoaderFinished={() => setProgress(0)}
+            />
             <Collections
                 collections={collections}
                 selected={router.query.collection?.toString()}

+ 23 - 5
src/services/collectionService.ts

@@ -97,15 +97,33 @@ const getCollections = async (
         return await Promise.all(promises);
     }
     catch (e) {
-        console.log("getCollections falied- " + e);
+        console.log("getCollections failed- " + e);
     }
 };
 
-export const fetchCollections = async (token: string, key: string) => {
-    const collections = await getCollections(token, '0', key);
-    const favCollection = collections.filter(collection => collection.type === CollectionType.favorites);
-    await localForage.setItem('fav-collection', favCollection);
+export const getLocalCollections = async (): Promise<collection[]> => {
+    const collections = await localForage.getItem('collections') as collection[] ?? [];
     return collections;
+}
+export const fetchUpdatedCollections = async (token: string, key: string) => {
+    const collectionUpdateTime = await localForage.getItem('collection-update-time') as string;
+    const updatedCollections = await getCollections(token, collectionUpdateTime ?? '0', key) || [];
+    const favCollection = await localForage.getItem('fav-collection') as collection[] ?? updatedCollections.filter(collection => collection.type === CollectionType.favorites);
+    const localCollections = await getLocalCollections();
+    const allCollectionsInstances = [...localCollections, ...updatedCollections];
+    var latestCollectionsInstances = new Map<string, collection>();
+    allCollectionsInstances.forEach((collection) => {
+        if (!latestCollectionsInstances.has(collection.id) || latestCollectionsInstances.get(collection.id).updationTime < collection.updationTime) {
+            latestCollectionsInstances.set(collection.id, collection);
+        }
+    });
+    let collections = [];
+    for (const [_, collection] of latestCollectionsInstances) {
+        collections.push(collection);
+    }
+    await localForage.setItem('fav-collection', favCollection);
+    await localForage.setItem('collections', collections);
+    return updatedCollections;
 };
 
 export const getCollectionLatestFile = (

+ 57 - 43
src/services/fileService.ts

@@ -66,13 +66,23 @@ export const fetchData = async (token, collections) => {
     );
 }
 
+export const localFiles = async () => {
+    let files: Array<file> = (await localForage.getItem<file[]>('files')) || [];
+    return files;
+}
+
 export const fetchFiles = async (
     token: string,
     collections: collection[]
 ) => {
-    let files: Array<file> = (await localForage.getItem<file[]>('files')) || [];
-    const fetchedFiles = await getFiles(collections, null, "100", token);
-
+    let files = await localFiles();
+    const collectionUpdationTime = new Map<string, string>();
+    let fetchedFiles = [];
+    for (let collection of collections) {
+        const files = await getFiles(collection, null, 100, token);
+        fetchedFiles.push(...files);
+        collectionUpdationTime.set(collection.id, files.length > 0 ? files.slice(-1)[0].updationTime.toString() : "0");
+    }
     files.push(...fetchedFiles);
     var latestFiles = new Map<string, file>();
     files.forEach((file) => {
@@ -82,7 +92,7 @@ export const fetchFiles = async (
         }
     });
     files = [];
-    for (const [_, file] of latestFiles.entries()) {
+    for (const [_, file] of latestFiles) {
         if (!file.isDeleted)
             files.push(file);
     }
@@ -90,53 +100,57 @@ export const fetchFiles = async (
         (a, b) => b.metadata.creationTime - a.metadata.creationTime
     );
     await localForage.setItem('files', files);
+    for (let [collectionID, updationTime] of collectionUpdationTime) {
+        await localForage.setItem(`${collectionID}-time`, updationTime);
+    }
+    let updationTime = await localForage.getItem('collection-update-time') as number;
+    for (let collection of collections) {
+        updationTime = Math.max(updationTime, collection.updationTime);
+    }
+    await localForage.setItem('collection-update-time', updationTime);
     return files;
 };
 
-export const getFiles = async (collections: collection[], sinceTime: string, limit: string, token: string): Promise<file[]> => {
+export const getFiles = async (collection: collection, sinceTime: string, limit: number, token: string): Promise<file[]> => {
     try {
         const worker = await new CryptoWorker();
         let promises: Promise<file>[] = [];
-        for (const index in collections) {
-            const collection = collections[index];
-            if (collection.isDeleted) {
-                // TODO: Remove files in this collection from localForage and cache
-                continue;
-            }
-            let time =
-                sinceTime || (await localForage.getItem<string>(`${collection.id}-time`)) || "0";
-            let resp;
-            do {
-                resp = await HTTPService.get(`${ENDPOINT}/collections/diff`, {
-                    collectionID: collection.id,
-                    sinceTime: time,
-                    limit,
-                },
-                    {
-                        'X-Auth-Token': token
-                    });
-                promises.push(...resp.data.diff.map(
-                    async (file: file) => {
-                        if (!file.isDeleted) {
-
-                            file.key = await worker.decryptB64(
-                                file.encryptedKey,
-                                file.keyDecryptionNonce,
-                                collection.key
-                            );
-                            file.metadata = await worker.decryptMetadata(file);
-                        }
-                        return file;
+        if (collection.isDeleted) {
+            // TODO: Remove files in this collection from localForage and cache
+            return;
+        }
+        let time =
+            sinceTime || (await localForage.getItem<string>(`${collection.id}-time`)) || "0";
+        let resp;
+        do {
+            resp = await HTTPService.get(`${ENDPOINT}/collections/diff`, {
+                collectionID: collection.id,
+                sinceTime: time,
+                limit: limit.toString(),
+            },
+                {
+                    'X-Auth-Token': token
+                });
+            promises.push(...resp.data.diff.map(
+                async (file: file) => {
+                    if (!file.isDeleted) {
+
+                        file.key = await worker.decryptB64(
+                            file.encryptedKey,
+                            file.keyDecryptionNonce,
+                            collection.key
+                        );
+                        file.metadata = await worker.decryptMetadata(file);
                     }
-                ));
-
-                if (resp.data.diff.length) {
-                    time = resp.data.diff.slice(-1)[0].updationTime.toString();
+                    return file;
                 }
-            } while (resp.data.diff.length);
-            await localForage.setItem(`${collection.id}-time`, time);
-        }
-        return Promise.all(promises);
+            ));
+
+            if (resp.data.diff.length) {
+                time = resp.data.diff.slice(-1)[0].updationTime.toString();
+            }
+        } while (resp.data.diff.length === limit);
+        return await Promise.all(promises);
     } catch (e) {
         console.log("Get files failed" + e);
     }