Merge branch 'master' into refactor-metadata-extraction-v2
This commit is contained in:
commit
0ff53fad3d
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "bada-frame",
|
||||
"version": "0.4.4",
|
||||
"version": "0.5.1",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
|
|
|
@ -22,6 +22,13 @@ Sentry.init({
|
|||
attachStacktrace: true,
|
||||
autoSessionTracking: false,
|
||||
tunnel: getSentryTunnelURL(),
|
||||
beforeSend(event) {
|
||||
event.request = event.request || {};
|
||||
const currentURL = new URL(document.location.href);
|
||||
currentURL.hash = '';
|
||||
event.request.url = currentURL;
|
||||
return event;
|
||||
},
|
||||
// ...
|
||||
// Note: if you want to override the automatic release value, do not set a
|
||||
// `release` value here - use the environment variable `SENTRY_RELEASE`, so
|
||||
|
|
|
@ -50,7 +50,7 @@ export const Value = styled.div<{ width?: string }>`
|
|||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
width: ${(props) => props.width ?? '30%'};
|
||||
text-align: center;
|
||||
|
||||
color: #ddd;
|
||||
`;
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ const EmptyScreen = styled.div`
|
|||
}
|
||||
`;
|
||||
|
||||
const PHOTOSWIPE_HASH_SUFFIX = '&photoswipe-opened';
|
||||
const PHOTOSWIPE_HASH_SUFFIX = '&opened';
|
||||
|
||||
interface Props {
|
||||
files: EnteFile[];
|
||||
|
|
|
@ -11,11 +11,13 @@ import {
|
|||
SPACE_BTW_DATES,
|
||||
} from 'constants/gallery';
|
||||
import constants from 'utils/strings/constants';
|
||||
import LinkButton, { ButtonVariant } from './pages/gallery/LinkButton';
|
||||
import { PublicCollectionGalleryContext } from 'utils/publicCollectionGallery';
|
||||
import { ENTE_WEBSITE_LINK } from 'constants/urls';
|
||||
import { getVariantColor, ButtonVariant } from './pages/gallery/LinkButton';
|
||||
|
||||
const A_DAY = 24 * 60 * 60 * 1000;
|
||||
const NO_OF_PAGES = 2;
|
||||
const FOOTER_HEIGHT = 90;
|
||||
|
||||
enum ITEM_TYPE {
|
||||
TIME = 'TIME',
|
||||
|
@ -83,7 +85,14 @@ const DateContainer = styled.div<{ span: number }>`
|
|||
height: ${DATE_CONTAINER_HEIGHT}px;
|
||||
`;
|
||||
|
||||
const BannerContainer = styled.div<{ span: number }>`
|
||||
const FooterContainer = styled.div<{ span: number }>`
|
||||
font-size: 14px;
|
||||
margin-bottom: 0.75rem;
|
||||
@media (max-width: 540px) {
|
||||
font-size: 12px;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
color: #979797;
|
||||
text-align: center;
|
||||
grid-column: span ${(props) => props.span};
|
||||
|
@ -93,17 +102,7 @@ const BannerContainer = styled.div<{ span: number }>`
|
|||
& > p {
|
||||
margin: 0;
|
||||
}
|
||||
margin: 1rem 0;
|
||||
`;
|
||||
|
||||
const ReportAbuseItem = styled.div<{ span: number }>`
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
grid-column: span ${(props) => props.span};
|
||||
& > p {
|
||||
margin: 0;
|
||||
}
|
||||
margin: 2rem 0 1rem 0;
|
||||
margin-top: calc(2rem + 20px);
|
||||
`;
|
||||
|
||||
const NothingContainer = styled.div<{ span: number }>`
|
||||
|
@ -219,9 +218,9 @@ export function PhotoList({
|
|||
) {
|
||||
timeStampList.push(getVacuumItem(timeStampList));
|
||||
if (publicCollectionGalleryContext.accessedThroughSharedURL) {
|
||||
timeStampList.push(getReportAbuseItem());
|
||||
timeStampList.push(getAlbumsFooter());
|
||||
} else {
|
||||
timeStampList.push(getAppDownloadBannerItem());
|
||||
timeStampList.push(getAppDownloadFooter());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -259,7 +258,7 @@ export function PhotoList({
|
|||
const getCurrentItemSize = getItemSize(timeStampList);
|
||||
for (let i = 0; i < timeStampList.length; i++) {
|
||||
sum += getCurrentItemSize(i);
|
||||
if (height - sum <= 70) {
|
||||
if (height - sum <= FOOTER_HEIGHT) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -268,32 +267,40 @@ export function PhotoList({
|
|||
return {
|
||||
itemType: ITEM_TYPE.OTHER,
|
||||
item: <></>,
|
||||
height: Math.max(height - photoFrameHeight - 70, 0),
|
||||
height: Math.max(height - photoFrameHeight - FOOTER_HEIGHT, 0),
|
||||
};
|
||||
};
|
||||
const getAppDownloadBannerItem = () => {
|
||||
const getAppDownloadFooter = () => {
|
||||
return {
|
||||
itemType: ITEM_TYPE.OTHER,
|
||||
height: FOOTER_HEIGHT,
|
||||
item: (
|
||||
<BannerContainer span={columns}>
|
||||
<FooterContainer span={columns}>
|
||||
<p>{constants.INSTALL_MOBILE_APP()}</p>
|
||||
</BannerContainer>
|
||||
</FooterContainer>
|
||||
),
|
||||
};
|
||||
};
|
||||
|
||||
const getReportAbuseItem = () => {
|
||||
const getAlbumsFooter = () => {
|
||||
return {
|
||||
itemType: ITEM_TYPE.OTHER,
|
||||
height: FOOTER_HEIGHT,
|
||||
item: (
|
||||
<ReportAbuseItem span={columns}>
|
||||
<LinkButton
|
||||
style={{ fontSize: '14px' }}
|
||||
variant={ButtonVariant.danger}
|
||||
onClick={publicCollectionGalleryContext.openReportForm}>
|
||||
{constants.ABUSE_REPORT_BUTTON_TEXT}
|
||||
</LinkButton>
|
||||
</ReportAbuseItem>
|
||||
<FooterContainer span={columns}>
|
||||
<p>
|
||||
{constants.PRESERVED_BY}{' '}
|
||||
<a
|
||||
target="_blank"
|
||||
style={{
|
||||
color: getVariantColor(ButtonVariant.success),
|
||||
}}
|
||||
href={ENTE_WEBSITE_LINK}
|
||||
rel="noreferrer">
|
||||
{constants.ENTE_IO}
|
||||
</a>
|
||||
</p>
|
||||
</FooterContainer>
|
||||
),
|
||||
};
|
||||
};
|
||||
|
|
|
@ -148,7 +148,14 @@ function RenderCreationTime({
|
|||
<>
|
||||
<Row>
|
||||
<Label width="30%">{constants.CREATION_TIME}</Label>
|
||||
<Value width={isInEditMode ? '50%' : '60%'}>
|
||||
<Value
|
||||
width={
|
||||
!shouldDisableEdits
|
||||
? isInEditMode
|
||||
? '50%'
|
||||
: '60%'
|
||||
: '70%'
|
||||
}>
|
||||
{isInEditMode ? (
|
||||
<EnteDateTimePicker
|
||||
loading={loading}
|
||||
|
@ -160,11 +167,11 @@ function RenderCreationTime({
|
|||
formatDateTime(pickedTime)
|
||||
)}
|
||||
</Value>
|
||||
<Value
|
||||
width={isInEditMode ? '20%' : '10%'}
|
||||
style={{ cursor: 'pointer', marginLeft: '10px' }}>
|
||||
{!shouldDisableEdits &&
|
||||
(!isInEditMode ? (
|
||||
{!shouldDisableEdits && (
|
||||
<Value
|
||||
width={isInEditMode ? '20%' : '10%'}
|
||||
style={{ cursor: 'pointer', marginLeft: '10px' }}>
|
||||
{!isInEditMode ? (
|
||||
<IconButton onClick={openEditMode}>
|
||||
<EditIcon />
|
||||
</IconButton>
|
||||
|
@ -181,8 +188,9 @@ function RenderCreationTime({
|
|||
<CloseIcon />
|
||||
</IconButton>
|
||||
</>
|
||||
))}
|
||||
</Value>
|
||||
)}
|
||||
</Value>
|
||||
)}
|
||||
</Row>
|
||||
</>
|
||||
);
|
||||
|
@ -323,7 +331,7 @@ function RenderFileName({
|
|||
<Label width="30%">{constants.FILE_NAME}</Label>
|
||||
{!isInEditMode ? (
|
||||
<>
|
||||
<Value width="60%">
|
||||
<Value width={!shouldDisableEdits ? '60%' : '70%'}>
|
||||
<FreeFlowText>
|
||||
{getFileTitle(filename, extension)}
|
||||
</FreeFlowText>
|
||||
|
@ -735,11 +743,13 @@ function PhotoSwipe(props: Iprops) {
|
|||
}}
|
||||
/>
|
||||
)}
|
||||
<button
|
||||
className="pswp-custom info-btn"
|
||||
title={constants.INFO}
|
||||
onClick={handleOpenInfo}
|
||||
/>
|
||||
{!props.isSharedCollection && (
|
||||
<button
|
||||
className="pswp-custom info-btn"
|
||||
title={constants.INFO}
|
||||
onClick={handleOpenInfo}
|
||||
/>
|
||||
)}
|
||||
<div className="pswp__preloader">
|
||||
<div className="pswp__preloader__icn">
|
||||
<div className="pswp__preloader__cut">
|
||||
|
@ -765,16 +775,18 @@ function PhotoSwipe(props: Iprops) {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<InfoModal
|
||||
shouldDisableEdits={props.isSharedCollection}
|
||||
showInfo={showInfo}
|
||||
handleCloseInfo={handleCloseInfo}
|
||||
items={items}
|
||||
photoSwipe={photoSwipe}
|
||||
metadata={metadata}
|
||||
exif={exif}
|
||||
scheduleUpdate={scheduleUpdate}
|
||||
/>
|
||||
{!props.isSharedCollection && (
|
||||
<InfoModal
|
||||
shouldDisableEdits={props.isSharedCollection}
|
||||
showInfo={showInfo}
|
||||
handleCloseInfo={handleCloseInfo}
|
||||
items={items}
|
||||
photoSwipe={photoSwipe}
|
||||
metadata={metadata}
|
||||
exif={exif}
|
||||
scheduleUpdate={scheduleUpdate}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { ENTE_WEBSITE_LINK } from 'constants/urls';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Button } from 'react-bootstrap';
|
||||
import styled from 'styled-components';
|
||||
|
@ -42,17 +43,9 @@ function GoToEnte() {
|
|||
}
|
||||
};
|
||||
|
||||
const getHookLink = (os: OS) => {
|
||||
if (os === OS.ANDROID || os === OS.IOS) {
|
||||
return 'https://ente.io/app';
|
||||
} else {
|
||||
return 'https://web.ente.io';
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
<ButtonWithLink href={getHookLink(os)}>
|
||||
<ButtonWithLink href={ENTE_WEBSITE_LINK}>
|
||||
{getButtonText(os)}
|
||||
</ButtonWithLink>
|
||||
</Wrapper>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
export const getSentryDSN = () =>
|
||||
process.env.NEXT_PUBLIC_SENTRY_DSN ??
|
||||
'https://860186db60c54c7fbacfe255124958e8@errors.ente.io/4';
|
||||
'https://60abb33b597c42f6a3fb27cd82c55101@sentry.ente.io/2';
|
||||
|
||||
export const getSentryENV = () =>
|
||||
process.env.NEXT_PUBLIC_SENTRY_ENV ?? 'development';
|
||||
|
|
1
src/constants/urls/index.ts
Normal file
1
src/constants/urls/index.ts
Normal file
|
@ -0,0 +1 @@
|
|||
export const ENTE_WEBSITE_LINK = 'https://ente.io';
|
|
@ -11,6 +11,7 @@ import { EnteFile } from 'types/file';
|
|||
|
||||
import { logError } from 'utils/sentry';
|
||||
import { FILE_TYPE } from 'constants/file';
|
||||
import { CustomError } from 'utils/error';
|
||||
|
||||
class DownloadManager {
|
||||
private fileObjectURLPromise = new Map<string, Promise<string>>();
|
||||
|
@ -69,6 +70,9 @@ class DownloadManager {
|
|||
{ 'X-Auth-Token': token },
|
||||
{ responseType: 'arraybuffer' }
|
||||
);
|
||||
if (typeof resp.data === 'undefined') {
|
||||
throw Error(CustomError.REQUEST_FAILED);
|
||||
}
|
||||
const worker = await new CryptoWorker();
|
||||
const decrypted: Uint8Array = await worker.decryptThumbnail(
|
||||
new Uint8Array(resp.data),
|
||||
|
@ -127,6 +131,9 @@ class DownloadManager {
|
|||
{ 'X-Auth-Token': token },
|
||||
{ responseType: 'arraybuffer' }
|
||||
);
|
||||
if (typeof resp.data === 'undefined') {
|
||||
throw Error(CustomError.REQUEST_FAILED);
|
||||
}
|
||||
const decrypted: any = await worker.decryptFile(
|
||||
new Uint8Array(resp.data),
|
||||
await worker.fromB64(file.file.decryptionHeader),
|
||||
|
|
|
@ -13,6 +13,7 @@ import { EnteFile } from 'types/file';
|
|||
|
||||
import { logError } from 'utils/sentry';
|
||||
import { FILE_TYPE } from 'constants/file';
|
||||
import { CustomError } from 'utils/error';
|
||||
|
||||
class PublicCollectionDownloadManager {
|
||||
private fileObjectURLPromise = new Map<string, Promise<string>>();
|
||||
|
@ -37,6 +38,7 @@ class PublicCollectionDownloadManager {
|
|||
const cacheResp: Response = await thumbnailCache?.match(
|
||||
file.id.toString()
|
||||
);
|
||||
|
||||
if (cacheResp) {
|
||||
return URL.createObjectURL(await cacheResp.blob());
|
||||
}
|
||||
|
@ -70,6 +72,9 @@ class PublicCollectionDownloadManager {
|
|||
{ 'X-Auth-Access-Token': token },
|
||||
{ responseType: 'arraybuffer' }
|
||||
);
|
||||
if (typeof resp.data === 'undefined') {
|
||||
throw Error(CustomError.REQUEST_FAILED);
|
||||
}
|
||||
const worker = await new CryptoWorker();
|
||||
const decrypted: Uint8Array = await worker.decryptThumbnail(
|
||||
new Uint8Array(resp.data),
|
||||
|
@ -127,6 +132,9 @@ class PublicCollectionDownloadManager {
|
|||
{ 'X-Auth-Access-Token': token },
|
||||
{ responseType: 'arraybuffer' }
|
||||
);
|
||||
if (typeof resp.data === 'undefined') {
|
||||
throw Error(CustomError.REQUEST_FAILED);
|
||||
}
|
||||
const decrypted: any = await worker.decryptFile(
|
||||
new Uint8Array(resp.data),
|
||||
await worker.fromB64(file.file.decryptionHeader),
|
||||
|
@ -136,7 +144,7 @@ class PublicCollectionDownloadManager {
|
|||
}
|
||||
const resp = await fetch(getPublicCollectionFileURL(file.id), {
|
||||
headers: {
|
||||
'X-Auth-Token': token,
|
||||
'X-Auth-Access-Token': token,
|
||||
},
|
||||
});
|
||||
const reader = resp.body.getReader();
|
||||
|
|
|
@ -263,10 +263,7 @@ export const getPublicCollection = async (
|
|||
await savePublicCollection(collection);
|
||||
return collection;
|
||||
} catch (e) {
|
||||
logError(e, 'failed to get public collection', {
|
||||
collectionKey,
|
||||
token,
|
||||
});
|
||||
logError(e, 'failed to get public collection');
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -33,6 +33,7 @@ export enum CustomError {
|
|||
INVALID_COLLECTION_OPERATION = 'invalid collection operation',
|
||||
WAIT_TIME_EXCEEDED = 'thumbnail generation wait time exceeded',
|
||||
REQUEST_CANCELLED = 'request canceled',
|
||||
REQUEST_FAILED = 'request failed',
|
||||
TOKEN_EXPIRED = 'token expired',
|
||||
BAD_REQUEST = 'bad request',
|
||||
SUBSCRIPTION_NEEDED = 'subscription not present',
|
||||
|
|
|
@ -651,6 +651,8 @@ const englishConstants = {
|
|||
TERM_1: 'I hereby state that I have a good faith belief that the sharing of copyrighted material at the location above is not authorized by the copyright owner, its agent, or the law (e.g., as a fair use). ',
|
||||
TERM_2: 'I hereby state that the information in this Notice is accurate and, under penalty of perjury, that I am the owner, or authorized to act on behalf of, the owner, of the copyright or of an exclusive right under the copyright that is allegedly infringed. ',
|
||||
TERM_3: 'I acknowledge that any person who knowingly materially misrepresents that material or activity is infringing may be subject to liability for damages. ',
|
||||
PRESERVED_BY: 'preserved by',
|
||||
ENTE_IO: 'ente.io',
|
||||
};
|
||||
|
||||
export default englishConstants;
|
||||
|
|
Loading…
Reference in a new issue