Initial gallary chagnes.

This commit is contained in:
Pushkar Anand 2020-09-20 20:48:35 +05:30
parent 8e76f6b5bd
commit f9ee680c8f
10 changed files with 158 additions and 30 deletions

View file

@ -18,6 +18,7 @@
"react": "16.13.1",
"react-bootstrap": "^1.3.0",
"react-dom": "16.13.1",
"react-photoswipe": "^1.3.0",
"scrypt-js": "^3.0.1",
"styled-components": "^5.2.0",
"yup": "^0.29.3"

1
public/image.svg Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="white" width="48px" height="48px"><path d="M0 0h24v24H0z" fill="none"/><path d="M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z"/></svg>

After

Width:  |  Height:  |  Size: 275 B

View file

@ -2,7 +2,6 @@ import React, { useEffect, useState } from 'react';
import styled, {createGlobalStyle } from 'styled-components';
import Navbar from 'components/Navbar';
import constants from 'utils/strings/constants';
import 'bootstrap/dist/css/bootstrap.min.css';
import Button from 'react-bootstrap/Button';
import Spinner from 'react-bootstrap/Spinner';
import { clearKeys } from 'utils/storage/sessionStorage';
@ -11,6 +10,8 @@ import { useRouter } from 'next/router';
import Container from 'components/Container';
import PowerSettings from 'components/power_settings';
import Head from 'next/head';
import 'bootstrap/dist/css/bootstrap.min.css';
import 'react-photoswipe/lib/photoswipe.css';
const GlobalStyles = createGlobalStyle`
html, body {

View file

@ -1,18 +1,46 @@
import React from 'react';
import Card from 'react-bootstrap/Card';
import { fileData } from 'services/fileService';
import React, { useEffect, useState } from 'react';
import { fileData, getPreview } from 'services/fileService';
import { getActualKey } from 'utils/common/key';
import { getData, LS_KEYS } from 'utils/storage/localStorage';
import styled from 'styled-components';
interface IProps {
data: fileData,
}
const Cont = styled.div`
background: #555 url(/image.svg) no-repeat center;
margin: 0 4px;
display: inline-block;
width: 200px;
height: 200px;
overflow: hidden;
& > img {
object-fit: cover;
max-width: 100%;
min-height: 100%;
}
`;
export default function PreviewCard(props: IProps) {
const [imgSrc, setImgSrc] = useState<string>();
const { data } = props;
return (<Card>
<Card.Body>
<div>ID: {data?.id}</div>
<div>MetaData: {JSON.stringify(data?.metadata)}</div>
</Card.Body>
</Card>);
useEffect(() => {
if (data) {
const main = async () => {
const token = getData(LS_KEYS.USER).token;
const key = await getActualKey();
const url = await getPreview(token, data, key);
setImgSrc(url);
data.src = url;
}
main();
}
}, [data]);
return <Cont>
<img src={imgSrc}/>
</Cont>;
}

View file

@ -1,4 +1,4 @@
import React, { useLayoutEffect, useState } from 'react';
import React, { useEffect, useState } from 'react';
import { useRouter } from 'next/router';
import Spinner from 'react-bootstrap/Spinner';
import { getKey, SESSION_KEYS } from 'utils/storage/sessionStorage';
@ -6,13 +6,27 @@ import { fileData, getFiles } from 'services/fileService';
import { getData, LS_KEYS } from 'utils/storage/localStorage';
import PreviewCard from './components/PreviewCard';
import { getActualKey } from 'utils/common/key';
import styled from 'styled-components';
import { PhotoSwipeGallery } from 'react-photoswipe';
const Container = styled.div`
max-width: 1260px;
display: flex;
flex-wrap: wrap;
margin: 0 auto;
.pswp-thumbnail {
display: inline-block;
cursor: pointer;
}
`;
export default function Gallery() {
const router = useRouter();
const [loading, setLoading] = useState(false);
const [data, setData] = useState<fileData[]>();
useLayoutEffect(() => {
useEffect(() => {
const key = getKey(SESSION_KEYS.ENCRYPTION_KEY);
const token = getData(LS_KEYS.USER).token;
if (!key) {
@ -21,7 +35,7 @@ export default function Gallery() {
const main = async () => {
setLoading(true);
const encryptionKey = await getActualKey();
const resp = await getFiles("0", token, "100", encryptionKey);
const resp = await getFiles("0", token, "24", encryptionKey);
setLoading(false);
setData(resp);
};
@ -29,8 +43,24 @@ export default function Gallery() {
}, []);
if (!data || loading) {
return <Spinner animation="border" variant="primary"/>;
return <div className="text-center">
<Spinner animation="border" variant="primary"/>;
</div>
}
return (data || []).map(item => <PreviewCard key={item.id} data={item} />);
const getThumbnail = (item) => (
<PreviewCard data={item}/>
)
return (<Container>
<PhotoSwipeGallery
items={data.map(item => ({
...item,
src: '/image.svg',
w: 512,
h: 512,
}))}
thumbnailContent={getThumbnail}
/>
</Container>);
}

View file

@ -1,4 +1,7 @@
import aescrypt from "utils/aescrypt";
import { getEndpoint } from "utils/common/apiUtil";
import { decrypt } from "utils/crypto/aes";
import { strToUint8 } from "utils/crypto/common";
import HTTPService from "./HTTPService";
const ENDPOINT = getEndpoint();
@ -6,28 +9,56 @@ const ENDPOINT = getEndpoint();
export interface fileData {
id: number;
metadata: {
currentTimestamp: number,
},
currentTime: number;
modificationTime: number;
latitude: number;
longitude: number;
title: string;
deviceFolder: string;
};
encryptedPassword: string;
encryptedPasswordIV: string;
file?: string;
};
const getFileDataUsingWorker = (data: any, key: string) => {
return new Promise((resolve) => {
const worker = new Worker('worker/decrypt.worker.js', { type: 'module' });
const worker = new Worker('worker/decryptMetadata.worker.js', { type: 'module' });
const onWorkerMessage = (event) => resolve(event.data);
worker.addEventListener('message', onWorkerMessage);
worker.postMessage({ data, key });
});
}
export const getFiles = async (sinceTimestamp: string, token: string, limit: string, key: string) => {
const getFileUsingWorker = (data: any, key: string) => {
return new Promise((resolve) => {
const worker = new Worker('worker/decryptFile.worker.js', { type: 'module' });
const onWorkerMessage = (event) => resolve(event.data);
worker.addEventListener('message', onWorkerMessage);
worker.postMessage({ data, key });
});
}
export const getFiles = async (sinceTime: string, token: string, limit: string, key: string) => {
const resp = await HTTPService.get(`${ENDPOINT}/encrypted-files/diff`, {
sinceTimestamp, token, limit,
sinceTime, token, limit,
});
const promises: Promise<fileData>[] = resp.data.diff.map((data) => getFileDataUsingWorker(data, key));
console.time('Metadata Parsing');
const decrypted = await Promise.all(promises);
console.timeEnd('Metadata Parsing');
return decrypted;
}
export const getPreview = async (token: string, data: fileData, key: string) => {
const resp = await HTTPService.get(
`${ENDPOINT}/encrypted-files/preview/${data.id}`,
{ token }, null, { responseType: 'arraybuffer' },
);
const decrypted = await getFileUsingWorker({
...data,
file: resp.data,
}, key);
const url = URL.createObjectURL(new Blob([decrypted.file]));
return url;
}

View file

@ -1,4 +1,3 @@
import { resolve } from 'path';
import { aescrypt } from './aescrypt';
const decrypt = (file: Uint8Array, password: String, binaryResponse: Boolean = false) => {
@ -6,6 +5,7 @@ const decrypt = (file: Uint8Array, password: String, binaryResponse: Boolean = f
try {
aescrypt.decrypt(file, password, !binaryResponse, ({ data, error}) => {
if (error) {
console.log(error);
reject(error);
}
resolve(data);

View file

@ -0,0 +1,19 @@
import { decrypt } from "utils/crypto/aes";
import { strToUint8 } from "utils/crypto/common";
import aescrypt from 'utils/aescrypt';
function decryptFile(event) {
const main = async () => {
const data = event.data.data;
const key = event.data.key;
const password = await decrypt(data.encryptedPassword, key, data.encryptedPasswordIV);
const file = await aescrypt.decrypt(data.file, atob(password), true);
self.postMessage({
id: data.id,
file: file,
});
}
main();
}
self.addEventListener('message', decryptFile);

View file

@ -9,11 +9,8 @@ function decryptFile(event) {
const password = await decrypt(data.encryptedPassword, key, data.encryptedPasswordIV);
const metadata = await aescrypt.decrypt(base64ToUint8(data.encryptedMetadata), atob(password));
self.postMessage({
id: data.id,
ownerId: data.ownerId,
updationTime: data.updationTime,
password,
metadata: JSON.parse(metadata),
...data,
metadata: JSON.parse(metadata)
});
}
main();

View file

@ -2020,7 +2020,7 @@ class-utils@^0.3.5:
isobject "^3.0.0"
static-extend "^0.1.1"
classnames@2.2.6, classnames@^2.2.6:
classnames@2.2.6, classnames@^2.2.3, classnames@^2.2.6:
version "2.2.6"
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce"
integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==
@ -3502,6 +3502,11 @@ lodash-es@^4.17.11, lodash-es@^4.17.14, lodash-es@^4.17.15:
resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.15.tgz#21bd96839354412f23d7a10340e5eac6ee455d78"
integrity sha512-rlrc3yU3+JNOpZ9zj5pQtxnx2THmvRykwL4Xlxoa8I9lHBlVbbyPhgyPMioxVZ4NqyxaVVtaJnzsyOidQIhyyQ==
lodash.pick@^4.2.1:
version "4.4.0"
resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3"
integrity sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM=
lodash.sortby@^4.7.0:
version "4.7.0"
resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
@ -4232,6 +4237,11 @@ pbkdf2@^3.0.3:
safe-buffer "^5.0.1"
sha.js "^2.4.8"
photoswipe@^4.1.0:
version "4.1.3"
resolved "https://registry.yarnpkg.com/photoswipe/-/photoswipe-4.1.3.tgz#59f49494eeb9ddab5888d03392926a19bc197550"
integrity sha512-89Z43IRUyw7ycTolo+AaiDn3W1EEIfox54hERmm9bI12IB9cvRfHSHez3XhAyU8XW2EAFrC+2sKMhh7SJwn0bA==
picomatch@^2.0.4, picomatch@^2.0.5, picomatch@^2.2.1:
version "2.2.2"
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad"
@ -4368,7 +4378,7 @@ prop-types-extra@^1.1.0:
react-is "^16.3.2"
warning "^4.0.0"
prop-types@15.7.2, prop-types@^15.6.2, prop-types@^15.7.2:
prop-types@15.7.2, prop-types@^15.5.10, prop-types@^15.6.2, prop-types@^15.7.2:
version "15.7.2"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
@ -4537,6 +4547,16 @@ react-overlays@^4.1.0:
uncontrollable "^7.0.0"
warning "^4.0.3"
react-photoswipe@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/react-photoswipe/-/react-photoswipe-1.3.0.tgz#016dd978450a8406776db97511eaf96f2ffb9cfb"
integrity sha512-1ok6vXFAj/rd60KIzF0YwCdq1Tcl+8yKqWJHbPo43lJBuwUi+LBosmBdJmswpiOzMn2496ekU0k/r6aHWQk7PQ==
dependencies:
classnames "^2.2.3"
lodash.pick "^4.2.1"
photoswipe "^4.1.0"
prop-types "^15.5.10"
react-refresh@0.8.3:
version "0.8.3"
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.8.3.tgz#721d4657672d400c5e3c75d063c4a85fb2d5d68f"