Merge branch 'main' into quickOptions-Refactor
This commit is contained in:
commit
848caedde5
38
.github/workflows/cla.yaml
vendored
Normal file
38
.github/workflows/cla.yaml
vendored
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
name: "CLA Assistant"
|
||||||
|
on:
|
||||||
|
issue_comment:
|
||||||
|
types: [created]
|
||||||
|
pull_request_target:
|
||||||
|
types: [opened, closed, synchronize]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
CLAAssistant:
|
||||||
|
# This job only runs for pull request comments
|
||||||
|
if: ${{ github.event.issue.pull_request }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: "CLA Assistant"
|
||||||
|
if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target'
|
||||||
|
# Beta Release
|
||||||
|
uses: contributor-assistant/github-action@v2.2.1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
# the below token should have repo scope and must be manually added by you in the repository's secret
|
||||||
|
PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
|
||||||
|
with:
|
||||||
|
path-to-signatures: "signatures/version1/cla.json"
|
||||||
|
path-to-document: "https://github.com/ente-io/cla/blob/main/CLA.md" # e.g. a CLA or a DCO document
|
||||||
|
# branch should not be protected
|
||||||
|
branch: "main"
|
||||||
|
allowlist: enteio
|
||||||
|
|
||||||
|
# the followings are the optional inputs - If the optional inputs are not given, then default values will be taken
|
||||||
|
#remote-organization-name: enter the remote organization name where the signatures should be stored (Default is storing the signatures in the same repository)
|
||||||
|
remote-repository-name: cla
|
||||||
|
#create-file-commit-message: 'For example: Creating file for storing CLA Signatures'
|
||||||
|
#signed-commit-message: 'For example: $contributorName has signed the CLA in #$pullRequestNo'
|
||||||
|
#custom-notsigned-prcomment: 'pull request comment with Introductory message to ask new contributors to sign'
|
||||||
|
#custom-pr-sign-comment: 'The signature to be committed in order to sign the CLA'
|
||||||
|
#custom-allsigned-prcomment: 'pull request comment when all contributors has signed, defaults to **CLA Assistant Lite bot** All Contributors have signed the CLA.'
|
||||||
|
#lock-pullrequest-aftermerge: false - if you don't want this bot to automatically lock the pull request after merging (default - true)
|
||||||
|
#use-dco-flag: true - If you are using DCO instead of CLA
|
98
CLA.md
Normal file
98
CLA.md
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
## Contributor License Agreement
|
||||||
|
|
||||||
|
Thank you for your contribution to ente projects.
|
||||||
|
|
||||||
|
This contributor license agreement documents the rights granted by contributors
|
||||||
|
to Ente Technologies, Inc ("ente"). This license is for your protection as a
|
||||||
|
Contributor as well as the protection of ente, its users, and its licensees; you
|
||||||
|
may still license your own Contributions under other terms.
|
||||||
|
|
||||||
|
In exchange for the ability to participate in the ente community and for other
|
||||||
|
good consideration, the receipt of which is hereby acknowledged, you accept and
|
||||||
|
agree to the following terms and conditions for Your present and future
|
||||||
|
Contributions submitted to ente. Except for the license granted herein to ente
|
||||||
|
and recipients of software distributed by ente, You reserve all right, title,
|
||||||
|
and interest in and to Your Contributions.
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean the copyright owner or legal entity authorized
|
||||||
|
by the copyright owner that is making this Agreement with ente. For legal
|
||||||
|
entities, the entity making a Contribution and all other entities that
|
||||||
|
control, are controlled by, or are under common control with that entity are
|
||||||
|
considered to be a single Contributor. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the direction or
|
||||||
|
management of such entity, whether by contract or otherwise, or (ii)
|
||||||
|
ownership of fifty percent (50%) or more of the outstanding shares, or (iii)
|
||||||
|
beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"Contribution" shall mean any original work of authorship or invention,
|
||||||
|
including any modifications or additions to an existing work, that is
|
||||||
|
intentionally submitted by You to ente for inclusion in, or documentation of,
|
||||||
|
any of the products owned or managed by ente (the "Work"). For the purposes
|
||||||
|
of this definition, "submitted" means any form of electronic, verbal, or
|
||||||
|
written communication sent to ente or its representatives, including but not
|
||||||
|
limited to communication on electronic mailing lists, source code control
|
||||||
|
systems, and issue tracking systems that are managed by, or on behalf of,
|
||||||
|
ente for the purpose of discussing and improving the Work, but excluding
|
||||||
|
communication that is conspicuously marked or otherwise designated in writing
|
||||||
|
by You as "Not a Contribution."
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of this
|
||||||
|
Agreement, You hereby grant to ente and to recipients of software distributed
|
||||||
|
by ente a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
||||||
|
irrevocable copyright license to reproduce, prepare derivative works of,
|
||||||
|
publicly display, publicly perform, and distribute Your Contributions and
|
||||||
|
such derivative works.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of this
|
||||||
|
Agreement, You hereby grant to ente and to recipients of software distributed
|
||||||
|
by ente a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
||||||
|
irrevocable (except as stated in this section) patent license to make, have
|
||||||
|
made, use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable by You that
|
||||||
|
are necessarily infringed by Your Contribution(s) alone or by combination of
|
||||||
|
Your Contribution(s) with the Work to which such Contribution(s) was
|
||||||
|
submitted. If any entity institutes patent litigation against You or any
|
||||||
|
other entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
||||||
|
that your Contribution, or the Work to which you have contributed,
|
||||||
|
constitutes direct or contributory patent infringement, then any patent
|
||||||
|
licenses granted to that entity under this Agreement for that Contribution or
|
||||||
|
Work shall terminate as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. You represent that you are legally entitled to grant the above license. If
|
||||||
|
your employer(s) has rights to intellectual property that you create that
|
||||||
|
includes your Contributions, you represent that you have received permission
|
||||||
|
to make Contributions on behalf of that employer, that your employer has
|
||||||
|
waived such rights for your contributions to ente, or that your employer has
|
||||||
|
executed with ente a separate contributor license agreement substantially
|
||||||
|
similar to this Agreement. If You are a current employee or contractor of
|
||||||
|
ente, then the terms of your existing Employment Agreement or Consulting
|
||||||
|
Services Agreement shall supersede this CLA, and remain in full effect.
|
||||||
|
|
||||||
|
5. You represent that each of Your Contributions is Your original creation (see
|
||||||
|
section 7 for submissions on behalf of others). You represent that Your
|
||||||
|
Contribution submissions include complete details of any third-party license
|
||||||
|
or other restriction (including, but not limited to, related patents and
|
||||||
|
trademarks) of which you are personally aware and which are associated with
|
||||||
|
any part of Your Contributions.
|
||||||
|
|
||||||
|
6. You are not expected to provide support for Your Contributions, except to the
|
||||||
|
extent You desire to provide support. You may provide support for free, for
|
||||||
|
a fee, or not at all. Unless required by applicable law or agreed to in
|
||||||
|
writing, You provide Your Contributions on an "AS IS" BASIS, WITHOUT
|
||||||
|
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including,
|
||||||
|
without limitation, any warranties or conditions of title, non-infringement,
|
||||||
|
merchantability, or fitness for a particular purpose.
|
||||||
|
|
||||||
|
7. Should You wish to submit work that is not Your original creation, You may
|
||||||
|
submit it to ente separately from any Contribution, identifying the complete
|
||||||
|
details of its source and of any license or other restriction (including, but
|
||||||
|
not limited to, related patents, trademarks, and license agreements) of which
|
||||||
|
you are personally aware, and conspicuously marking the work as "Not a
|
||||||
|
Contribution". Third-party materials licensed pursuant to: [license name(s)
|
||||||
|
here]" (substituting the bracketed text with the appropriate license
|
||||||
|
name(s)).
|
||||||
|
|
||||||
|
8. You agree to notify ente of any facts or circumstances of which you become
|
||||||
|
aware that would make these representations inaccurate in any respect.
|
11
README.md
11
README.md
|
@ -62,8 +62,15 @@ We maintain a public roadmap, that's driven by our community @ [roadmap.ente.io]
|
||||||
|
|
||||||
If you like this project, please consider upgrading to a paid subscription.
|
If you like this project, please consider upgrading to a paid subscription.
|
||||||
|
|
||||||
If you would like to motivate us to keep building, you can do so by
|
And [star this repo](https://github.com/ente-io/photos-web/stargazers)!
|
||||||
[starring](https://github.com/ente-io/photos-web/stargazers) this project.
|
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
## 🌍 Translate
|
||||||
|
|
||||||
|
Create a copy of
|
||||||
|
[src/utils/strings/englishConstants.tsx](src/utils/strings/englishConstants.tsx)
|
||||||
|
and open a PR.
|
||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
|
|
|
@ -203,6 +203,7 @@ const PhotoFrame = ({
|
||||||
h: window.innerHeight,
|
h: window.innerHeight,
|
||||||
title: item.pubMagicMetadata?.data.caption,
|
title: item.pubMagicMetadata?.data.caption,
|
||||||
};
|
};
|
||||||
|
try {
|
||||||
if (galleryContext.thumbs.has(item.id)) {
|
if (galleryContext.thumbs.has(item.id)) {
|
||||||
updateFileMsrcProps(
|
updateFileMsrcProps(
|
||||||
filteredItem,
|
filteredItem,
|
||||||
|
@ -215,6 +216,9 @@ const PhotoFrame = ({
|
||||||
galleryContext.files.get(item.id)
|
galleryContext.files.get(item.id)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
} catch (e) {
|
||||||
|
logError(e, 'PhotoFrame url prefill failed');
|
||||||
|
}
|
||||||
return filteredItem;
|
return filteredItem;
|
||||||
});
|
});
|
||||||
setFilteredData(filteredData);
|
setFilteredData(filteredData);
|
||||||
|
@ -459,12 +463,12 @@ const PhotoFrame = ({
|
||||||
) {
|
) {
|
||||||
handleSelect(
|
handleSelect(
|
||||||
filteredData[i].id,
|
filteredData[i].id,
|
||||||
filteredData[i].ownerID === user.id
|
filteredData[i].ownerID === user?.id
|
||||||
)(!checked);
|
)(!checked);
|
||||||
}
|
}
|
||||||
handleSelect(
|
handleSelect(
|
||||||
filteredData[index].id,
|
filteredData[index].id,
|
||||||
filteredData[index].ownerID === user.id,
|
filteredData[index].ownerID === user?.id,
|
||||||
index
|
index
|
||||||
)(!checked);
|
)(!checked);
|
||||||
}
|
}
|
||||||
|
@ -479,7 +483,10 @@ const PhotoFrame = ({
|
||||||
file={item}
|
file={item}
|
||||||
updateURL={updateURL(index)}
|
updateURL={updateURL(index)}
|
||||||
onClick={onThumbnailClick(index)}
|
onClick={onThumbnailClick(index)}
|
||||||
onSelect={handleSelect(item.id, item.ownerID === user.id, index)}
|
selectable={
|
||||||
|
!publicCollectionGalleryContext?.accessedThroughSharedURL
|
||||||
|
}
|
||||||
|
onSelect={handleSelect(item.id, item.ownerID === user?.id, index)}
|
||||||
selected={
|
selected={
|
||||||
selected.collectionID === activeCollection && selected[item.id]
|
selected.collectionID === activeCollection && selected[item.id]
|
||||||
}
|
}
|
||||||
|
|
|
@ -663,7 +663,11 @@ export function PhotoList({
|
||||||
let sum = 0;
|
let sum = 0;
|
||||||
for (let i = 0; i < listItem.groups.length - 1; i++) {
|
for (let i = 0; i < listItem.groups.length - 1; i++) {
|
||||||
sum = sum + listItem.groups[i];
|
sum = sum + listItem.groups[i];
|
||||||
ret.splice(sum, 0, <div />);
|
ret.splice(
|
||||||
|
sum,
|
||||||
|
0,
|
||||||
|
<div key={`${listItem.items[0].id}-gap-${i}`} />
|
||||||
|
);
|
||||||
sum += 1;
|
sum += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -687,7 +691,7 @@ export function PhotoList({
|
||||||
width={width}
|
width={width}
|
||||||
itemCount={timeStampList.length}
|
itemCount={timeStampList.length}
|
||||||
itemKey={generateKey}
|
itemKey={generateKey}
|
||||||
overscanCount={0}
|
overscanCount={3}
|
||||||
useIsScrolling>
|
useIsScrolling>
|
||||||
{({ index, style, isScrolling }) => (
|
{({ index, style, isScrolling }) => (
|
||||||
<ListItem style={style}>
|
<ListItem style={style}>
|
||||||
|
|
|
@ -20,6 +20,7 @@ interface IProps {
|
||||||
file: EnteFile;
|
file: EnteFile;
|
||||||
updateURL: (id: number, url: string) => void;
|
updateURL: (id: number, url: string) => void;
|
||||||
onClick: () => void;
|
onClick: () => void;
|
||||||
|
selectable: boolean;
|
||||||
selected: boolean;
|
selected: boolean;
|
||||||
onSelect: (checked: boolean) => void;
|
onSelect: (checked: boolean) => void;
|
||||||
onHover: () => void;
|
onHover: () => void;
|
||||||
|
@ -202,6 +203,7 @@ export default function PreviewCard(props: IProps) {
|
||||||
file,
|
file,
|
||||||
onClick,
|
onClick,
|
||||||
updateURL,
|
updateURL,
|
||||||
|
selectable,
|
||||||
selected,
|
selected,
|
||||||
onSelect,
|
onSelect,
|
||||||
selectOnClick,
|
selectOnClick,
|
||||||
|
@ -220,6 +222,12 @@ export default function PreviewCard(props: IProps) {
|
||||||
|
|
||||||
const isMounted = useRef(true);
|
const isMounted = useRef(true);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
return () => {
|
||||||
|
isMounted.current = false;
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!file.msrc && !props.showPlaceholder) {
|
if (!file.msrc && !props.showPlaceholder) {
|
||||||
const main = async () => {
|
const main = async () => {
|
||||||
|
@ -253,11 +261,8 @@ export default function PreviewCard(props: IProps) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
main();
|
main();
|
||||||
return () => {
|
|
||||||
isMounted.current = false;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}, []);
|
}, [props.showPlaceholder]);
|
||||||
|
|
||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
if (selectOnClick) {
|
if (selectOnClick) {
|
||||||
|
@ -290,11 +295,12 @@ export default function PreviewCard(props: IProps) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Cont
|
<Cont
|
||||||
id={`thumb-${file.id}-${props.showPlaceholder}`}
|
key={`thumb-${file.id}-${props.showPlaceholder}`}
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
onMouseEnter={handleHover}
|
onMouseEnter={handleHover}
|
||||||
disabled={!file?.msrc && !imgSrc}
|
disabled={!file?.msrc && !imgSrc}
|
||||||
{...useLongPress(longPressCallback, 500)}>
|
{...(selectable ? useLongPress(longPressCallback, 500) : {})}>
|
||||||
|
{selectable && (
|
||||||
<Check
|
<Check
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={selected}
|
checked={selected}
|
||||||
|
@ -302,7 +308,7 @@ export default function PreviewCard(props: IProps) {
|
||||||
$active={isRangeSelectActive && isInsSelectRange}
|
$active={isRangeSelectActive && isInsSelectRange}
|
||||||
onClick={(e) => e.stopPropagation()}
|
onClick={(e) => e.stopPropagation()}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
{(file?.msrc || imgSrc) && <img src={file?.msrc || imgSrc} />}
|
{(file?.msrc || imgSrc) && <img src={file?.msrc || imgSrc} />}
|
||||||
{file?.metadata.fileType === 1 && <PlayCircleOutlineOutlinedIcon />}
|
{file?.metadata.fileType === 1 && <PlayCircleOutlineOutlinedIcon />}
|
||||||
<SelectedOverlay selected={selected} />
|
<SelectedOverlay selected={selected} />
|
||||||
|
|
|
@ -59,7 +59,7 @@ export const syncFiles = async (
|
||||||
let files = await removeDeletedCollectionFiles(collections, localFiles);
|
let files = await removeDeletedCollectionFiles(collections, localFiles);
|
||||||
if (files.length !== localFiles.length) {
|
if (files.length !== localFiles.length) {
|
||||||
await setLocalFiles(files);
|
await setLocalFiles(files);
|
||||||
setFiles(files);
|
setFiles(sortFiles(mergeMetadata(files)));
|
||||||
}
|
}
|
||||||
for (const collection of collections) {
|
for (const collection of collections) {
|
||||||
if (!getToken()) {
|
if (!getToken()) {
|
||||||
|
|
|
@ -166,18 +166,13 @@ export function getSelectedFiles(
|
||||||
}
|
}
|
||||||
|
|
||||||
export function sortFiles(files: EnteFile[]) {
|
export function sortFiles(files: EnteFile[]) {
|
||||||
// sort according to modification time first
|
// sort based on the time of creation time of the file,
|
||||||
// then sort according to creation time, maintaining ordering according to modification time for files with creation time
|
// for files with same creation time, sort based on the time of last modification
|
||||||
return files
|
return files.sort((a, b) => {
|
||||||
.sort(
|
if (a.metadata.creationTime === b.metadata.creationTime) {
|
||||||
(a, b) => b.metadata.modificationTime - a.metadata.modificationTime
|
return b.metadata.modificationTime - a.metadata.modificationTime;
|
||||||
)
|
|
||||||
.sort((a, b) => {
|
|
||||||
if (a.metadata.modificationTime !== b.metadata.modificationTime) {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
return b.metadata.creationTime - a.metadata.creationTime;
|
|
||||||
}
|
}
|
||||||
|
return b.metadata.creationTime - a.metadata.creationTime;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { FILE_TYPE } from 'constants/file';
|
import { FILE_TYPE } from 'constants/file';
|
||||||
import { EnteFile } from 'types/file';
|
import { EnteFile } from 'types/file';
|
||||||
import { MergedSourceURL } from 'types/gallery';
|
import { MergedSourceURL } from 'types/gallery';
|
||||||
|
import { logError } from 'utils/sentry';
|
||||||
import constants from 'utils/strings/constants';
|
import constants from 'utils/strings/constants';
|
||||||
|
|
||||||
const WAIT_FOR_VIDEO_PLAYBACK = 1 * 1000;
|
const WAIT_FOR_VIDEO_PLAYBACK = 1 * 1000;
|
||||||
|
@ -61,7 +62,11 @@ export function updateFileMsrcProps(file: EnteFile, url: string) {
|
||||||
} else if (file.metadata.fileType === FILE_TYPE.IMAGE) {
|
} else if (file.metadata.fileType === FILE_TYPE.IMAGE) {
|
||||||
file.src = url;
|
file.src = url;
|
||||||
} else {
|
} else {
|
||||||
throw Error('Invalid file type');
|
logError(
|
||||||
|
Error(`unknown file type - ${file.metadata.fileType}`),
|
||||||
|
'Unknown file type'
|
||||||
|
);
|
||||||
|
file.src = url;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,15 +82,18 @@ export async function updateFileSrcProps(
|
||||||
let originalVideoURL;
|
let originalVideoURL;
|
||||||
let convertedImageURL;
|
let convertedImageURL;
|
||||||
let convertedVideoURL;
|
let convertedVideoURL;
|
||||||
|
let originalURL;
|
||||||
if (file.metadata.fileType === FILE_TYPE.LIVE_PHOTO) {
|
if (file.metadata.fileType === FILE_TYPE.LIVE_PHOTO) {
|
||||||
[originalImageURL, originalVideoURL] = urls.original;
|
[originalImageURL, originalVideoURL] = urls.original;
|
||||||
[convertedImageURL, convertedVideoURL] = urls.converted;
|
[convertedImageURL, convertedVideoURL] = urls.converted;
|
||||||
} else if (file.metadata.fileType === FILE_TYPE.VIDEO) {
|
} else if (file.metadata.fileType === FILE_TYPE.VIDEO) {
|
||||||
[originalVideoURL] = urls.original;
|
[originalVideoURL] = urls.original;
|
||||||
[convertedVideoURL] = urls.converted;
|
[convertedVideoURL] = urls.converted;
|
||||||
} else {
|
} else if (file.metadata.fileType === FILE_TYPE.IMAGE) {
|
||||||
[originalImageURL] = urls.original;
|
[originalImageURL] = urls.original;
|
||||||
[convertedImageURL] = urls.converted;
|
[convertedImageURL] = urls.converted;
|
||||||
|
} else {
|
||||||
|
[originalURL] = urls.original;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isPlayable =
|
const isPlayable =
|
||||||
|
@ -141,6 +149,10 @@ export async function updateFileSrcProps(
|
||||||
} else if (file.metadata.fileType === FILE_TYPE.IMAGE) {
|
} else if (file.metadata.fileType === FILE_TYPE.IMAGE) {
|
||||||
file.src = convertedImageURL;
|
file.src = convertedImageURL;
|
||||||
} else {
|
} else {
|
||||||
throw Error('Invalid file type');
|
logError(
|
||||||
|
Error(`unknown file type - ${file.metadata.fileType}`),
|
||||||
|
'Unknown file type'
|
||||||
|
);
|
||||||
|
file.src = originalURL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue