Merge pull request #82 from ente-io/share-target

Share target
This commit is contained in:
Pushkar Anand 2021-06-07 03:00:53 +05:30 committed by GitHub
commit c88d26205f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 170 additions and 66 deletions

View file

@ -1,38 +1,76 @@
{
"short_name": "ente",
"name": "ente | encrypted photo storage",
"icons": [
"short_name": "ente",
"name": "ente | encrypted photo storage",
"icons": [
{
"src": "/images/ente-192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "/images/ente-256.png",
"type": "image/png",
"sizes": "256x256"
},
{
"src": "/images/ente-512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": "/",
"background_color": "#191919",
"display": "standalone",
"scope": "/",
"theme_color": "#111",
"description": "ente provides a simple way to back up your memories.",
"prefer_related_applications": true,
"related_applications": [
{
"src": "/images/ente-192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "/images/ente-256.png",
"type": "image/png",
"sizes": "256x256"
},
{
"src": "/images/ente-512.png",
"type": "image/png",
"sizes": "512x512"
"platform": "play",
"url": "https://play.google.com/store/apps/details?id=io.ente.photos",
"id": "io.ente.photos"
}, {
"platform": "itunes",
"url": "https://apps.apple.com/in/app/ente-photos/id1542026904"
}
],
"start_url": "/",
"background_color": "#191919",
"display": "standalone",
"scope": "/",
"theme_color": "#111",
"description": "ente provides a simple way to back up your memories.",
"prefer_related_applications": true,
"related_applications": [
{
"platform": "play",
"url": "https://play.google.com/store/apps/details?id=io.ente.photos",
"id": "io.ente.photos"
}, {
"platform": "itunes",
"url": "https://apps.apple.com/in/app/ente-photos/id1542026904"
}
]
],
"share_target": {
"action": "./share-target",
"method": "POST",
"enctype": "multipart/form-data",
"params": {
"files": [{
"name": "files",
"accept": ["image/*", "video/*", "application/json"]
}]
}
},
"screenshots": [
{
"src": "/pwa/slide-1.jpg",
"type": "image/jpeg",
"sizes": "417x760"
},
{
"src": "/pwa/slide-2.jpg",
"type": "image/jpeg",
"sizes": "378x690"
},
{
"src": "/pwa/slide-3.jpg",
"type": "image/jpeg",
"sizes": "378x690"
},
{
"src": "/pwa/slide-4.jpg",
"type": "image/jpeg",
"sizes": "378x690"
},
{
"src": "/pwa/slide-5.jpg",
"type": "image/jpeg",
"sizes": "378x690"
}
]
}

BIN
public/pwa/slide-1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 KiB

BIN
public/pwa/slide-2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

BIN
public/pwa/slide-3.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

BIN
public/pwa/slide-4.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

BIN
public/pwa/slide-5.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

View file

@ -7,7 +7,7 @@ import {
SetFiles,
setSearchStats,
} from 'pages/gallery';
import PreviewCard from 'pages/gallery/components/PreviewCard';
import PreviewCard from './pages/gallery/PreviewCard';
import React, { useContext, useEffect, useRef, useState } from 'react';
import { Button } from 'react-bootstrap';
import { File } from 'services/fileService';

View file

@ -21,7 +21,7 @@ import { File } from 'services/fileService';
import isElectron from 'is-electron';
import { Collection } from 'services/collectionService';
import { useRouter } from 'next/router';
import LinkButton from 'pages/gallery/components/LinkButton';
import LinkButton from './pages/gallery/LinkButton';
import { downloadApp } from 'utils/common';
import { logoutUser } from 'services/userService';
import { LogoImage } from 'pages/_app';

View file

@ -27,7 +27,7 @@ export type SetCollectionSelectorAttributes = React.Dispatch<
interface Props {
show: boolean;
onHide: () => void;
onHide: (closeBtnClick?: boolean) => void;
setLoading: (value: boolean) => void;
directlyShowNextModal: boolean;
collectionsAndTheirLatestFile: CollectionAndItsLatestFile[];
@ -82,7 +82,7 @@ function CollectionSelector({
return (
<Modal {...props} size="xl" centered>
<Modal.Header closeButton>
<Modal.Header closeButton onHide={() => props.onHide(true)}>
<Modal.Title>{attributes.title}</Modal.Title>
</Modal.Header>
<Modal.Body

View file

@ -21,7 +21,7 @@ import { reverseString } from 'utils/common';
import { SetDialogMessage } from 'components/MessageDialog';
import ArrowEast from 'components/ArrowEast';
import LinkButton from './LinkButton';
import { DeadCenter, SetLoading } from '..';
import { DeadCenter, SetLoading } from 'pages/gallery';
export const PlanIcon = styled.div<{ selected: boolean }>`
border-radius: 20px;

View file

@ -4,7 +4,7 @@ import styled from 'styled-components';
import PlayCircleOutline from 'components/PlayCircleOutline';
import DownloadManager from 'services/downloadManager';
import useLongPress from 'utils/common/useLongPress';
import { GalleryContext } from '..';
import { GalleryContext } from 'pages/gallery';
interface IProps {
file: File;

View file

@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react';
import React, { useContext, useEffect, useState } from 'react';
import UploadService, { FileWithCollection, UPLOAD_STAGES } from 'services/uploadService';
import { createAlbum } from 'services/collectionService';
import { File } from 'services/fileService';
@ -9,7 +9,8 @@ import UploadProgress from './UploadProgress';
import ChoiceModal from './ChoiceModal';
import { SetCollectionNamerAttributes } from './CollectionNamer';
import { SetCollectionSelectorAttributes } from './CollectionSelector';
import { SetLoading } from '..';
import { SetLoading } from 'pages/gallery';
import { AppContext } from 'pages/_app';
interface Props {
syncWithRemote: () => Promise<void>;
@ -22,6 +23,7 @@ interface Props {
setLoading: SetLoading;
setDialogMessage: SetDialogMessage;
setUploadInProgress: any;
showCollectionSelector: () => void;
}
export enum UPLOAD_STRATEGY {
@ -43,18 +45,26 @@ export default function Upload(props: Props) {
const [percentComplete, setPercentComplete] = useState(0);
const [choiceModalView, setChoiceModalView] = useState(false);
const [fileAnalysisResult, setFileAnalysisResult] = useState<AnalysisResult>(null);
const appContext = useContext(AppContext);
useEffect(() => {
if (props.acceptedFiles?.length > 0) {
props.setLoading(true);
const fileAnalysisResult = analyseUploadFiles();
if (!fileAnalysisResult) {
setFileAnalysisResult(fileAnalysisResult);
}
props.setCollectionSelectorAttributes({
callback: uploadFilesToExistingCollection,
showNextModal: nextModal.bind(null, fileAnalysisResult),
title: 'upload to collection',
});
if (props.acceptedFiles[0]['path']) {
// File selection by drag and drop or selection of file.
const fileAnalysisResult = analyseUploadFiles();
if (!fileAnalysisResult) {
setFileAnalysisResult(fileAnalysisResult);
}
} else {
// File selection by share target.
props.showCollectionSelector();
}
props.setLoading(false);
}
}, [props.acceptedFiles]);
@ -196,6 +206,7 @@ export default function Upload(props: Props) {
setFileProgress,
},
);
appContext.resetFiles();
props.setUploadInProgress(false);
} catch (err) {
props.setBannerMessage(err.message);

View file

@ -152,6 +152,11 @@ const GlobalStyles = createGlobalStyle`
background-size: 20px 20px;
background-position: center;
}
.share-btn{
background: url('/share_icon.png') no-repeat;
background-size: 20px 20px;
background-position: center;
}
.btn-success {
background: #2dc262;
border-color: #29a354;
@ -317,7 +322,7 @@ const FlexContainer = styled.div`
text-align: center;
`;
const OfflineContainer = styled.div`
export const MessageContainer = styled.div`
background-color: #111;
padding: 0;
font-size: 14px;
@ -334,6 +339,8 @@ sentryInit();
type AppContextType = {
showNavBar: (show: boolean) => void;
files: File[];
resetFiles: () => void;
}
export const AppContext = createContext<AppContextType>(null);
@ -345,6 +352,7 @@ export default function App({ Component, err }) {
typeof window !== 'undefined' && !window.navigator.onLine,
);
const [showNavbar, setShowNavBar] = useState(false);
const [files, setFiles] = useState<File[]>(null);
useEffect(() => {
if (
@ -357,6 +365,15 @@ export default function App({ Component, err }) {
const wb = new Workbox('sw.js', { scope: '/' });
wb.register();
if ('serviceWorker' in navigator) {
navigator.serviceWorker.onmessage = (event) => {
if (event.data.action === 'upload-files') {
const files = event.data.files;
setFiles(files);
}
};
}
// if ('serviceWorker' in navigator) {
// navigator.serviceWorker
// .getRegistrations()
@ -373,6 +390,7 @@ export default function App({ Component, err }) {
const setUserOnline = () => setOffline(false);
const setUserOffline = () => setOffline(true);
const resetFiles = () => setFiles(null);
useEffect(() => {
console.log(
@ -424,9 +442,15 @@ export default function App({ Component, err }) {
/>
</FlexContainer>
</Navbar>}
<OfflineContainer>{offline && constants.OFFLINE_MSG}</OfflineContainer>
<MessageContainer>{offline && constants.OFFLINE_MSG}</MessageContainer>
{files &&
(router.pathname === '/gallery' ?
<MessageContainer>{constants.FILES_TO_BE_UPLOADED(files.length)}</MessageContainer> :
<MessageContainer>{constants.LOGIN_TO_UPLOAD_FILES(files.length)}</MessageContainer>)}
<AppContext.Provider value={{
showNavBar,
files,
resetFiles,
}}>
{loading ? (
<Container>

View file

@ -42,18 +42,18 @@ import { addFilesToCollection } from 'utils/collection';
import { errorCodes } from 'utils/common/errorUtil';
import SearchBar, { DateValue } from 'components/SearchBar';
import { Bbox } from 'services/searchService';
import SelectedFileOptions from './components/SelectedFileOptions';
import SelectedFileOptions from 'components/pages/gallery/SelectedFileOptions';
import CollectionSelector, {
CollectionSelectorAttributes,
} from './components/CollectionSelector';
} from 'components/pages/gallery/CollectionSelector';
import CollectionNamer, {
CollectionNamerAttributes,
} from './components/CollectionNamer';
import AlertBanner from './components/AlertBanner';
import UploadButton from './components/UploadButton';
import PlanSelector from './components/PlanSelector';
import Upload from './components/Upload';
import Collections from './components/Collections';
} from 'components/pages/gallery/CollectionNamer';
import AlertBanner from 'components/pages/gallery/AlertBanner';
import UploadButton from 'components/pages/gallery/UploadButton';
import PlanSelector from 'components/pages/gallery/PlanSelector';
import Upload from 'components/pages/gallery/Upload';
import Collections from 'components/pages/gallery/Collections';
import { AppContext } from 'pages/_app';
export enum FILE_TYPE {
@ -146,7 +146,7 @@ export default function Gallery() {
const loadingBar = useRef(null);
const [searchMode, setSearchMode] = useState(false);
const [searchStats, setSearchStats] = useState(null);
const [syncInProgress, setSyncInProgress] = useState(false);
const [syncInProgress, setSyncInProgress] = useState(true);
const [resync, setResync] = useState(false);
const [deleted, setDeleted] = useState<number[]>([]);
const appContext = useContext(AppContext);
@ -180,7 +180,7 @@ export default function Gallery() {
const favItemIds = await getFavItemIds(files);
setFavItemIds(favItemIds);
await checkSubscriptionPurchase(setDialogMessage, router);
await syncWithRemote();
await syncWithRemote(true);
setIsFirstLoad(false);
setJustSignedUp(false);
setIsFirstFetch(false);
@ -200,8 +200,8 @@ export default function Gallery() {
);
useEffect(() => setCollectionNamerView(true), [collectionNamerAttributes]);
const syncWithRemote = async () => {
if (syncInProgress) {
const syncWithRemote = async (force = false) => {
if (syncInProgress && !force) {
setResync(true);
return;
}
@ -335,6 +335,24 @@ export default function Gallery() {
setSearch(search);
setSearchStats(null);
};
const getFilesToBeUploaded = () => {
if (syncInProgress) {
return [];
}
if (appContext.files) {
return appContext.files;
}
return acceptedFiles;
};
const closeCollectionSelector = (closeBtnClick?: boolean) => {
if (closeBtnClick === true) {
appContext.resetFiles();
}
setCollectionSelectorView(false);
};
return (
<GalleryContext.Provider value={defaultGalleryContext}>
<FullScreenDropZone
@ -393,7 +411,7 @@ export default function Gallery() {
/>
<CollectionSelector
show={collectionSelectorView}
onHide={setCollectionSelectorView.bind(null, false)}
onHide={closeCollectionSelector}
setLoading={setLoading}
collectionsAndTheirLatestFile={collectionsAndTheirLatestFile}
directlyShowNextModal={
@ -404,11 +422,10 @@ export default function Gallery() {
<Upload
syncWithRemote={syncWithRemote}
setBannerMessage={setBannerMessage}
acceptedFiles={acceptedFiles}
acceptedFiles={getFilesToBeUploaded()}
existingFiles={files}
setCollectionSelectorAttributes={
setCollectionSelectorAttributes
}
showCollectionSelector={setCollectionSelectorView.bind(null, true)}
setCollectionSelectorAttributes={setCollectionSelectorAttributes}
closeCollectionSelector={setCollectionSelectorView.bind(
null,
false,

View file

@ -1,5 +1,5 @@
import { precacheAndRoute } from 'workbox-precaching';
import { setDefaultHandler } from 'workbox-routing';
import { registerRoute, setDefaultHandler } from 'workbox-routing';
import { NetworkOnly } from 'workbox-strategies';
import { pageCache, offlineFallback } from 'workbox-recipes';
@ -7,6 +7,18 @@ pageCache();
precacheAndRoute(self.__WB_MANIFEST);
registerRoute('/share-target', async ({ event }) => {
event.waitUntil(async function() {
const data = await event.request.formData();
const client = await self.clients.get(event.resultingClientId || event.clientId);
const files = data.getAll('files');
setTimeout(() => {
client.postMessage({ files, action: 'upload-files' });
}, 1000);
}());
return Response.redirect('./');
}, 'POST');
// Use a stale-while-revalidate strategy for all other requests.
setDefaultHandler(new NetworkOnly());

View file

@ -394,6 +394,8 @@ const englishConstants = {
APERTURE: 'aperture',
ISO: 'iso',
SHOW_ALL: 'show all',
LOGIN_TO_UPLOAD_FILES: (count: number) => count === 1 ? `1 file received. login to upload` : `${count} files received. login to upload`,
FILES_TO_BE_UPLOADED: (count: number) => count === 1 ? `1 file received. Uploading in a jiffy` : `${count} files received. Uploading in a jiffy`,
};
export default englishConstants;