[web] Miscellaneous tweaks (#1363)
- Clean up environment detection code - Remove l11n unsafe direct string manipulation - Inline - Remove isCanvasBlocked checker - Remove unused stuff
This commit is contained in:
commit
873b158718
28 changed files with 103 additions and 252 deletions
|
@ -1,4 +1,3 @@
|
|||
import { FACE_SEARCH_PRIVACY_POLICY_LINK } from "@ente/shared/constants/urls";
|
||||
import {
|
||||
Button,
|
||||
Checkbox,
|
||||
|
@ -60,8 +59,8 @@ export default function EnableFaceSearch({
|
|||
components={{
|
||||
a: (
|
||||
<Link
|
||||
target={"_blank"}
|
||||
href={FACE_SEARCH_PRIVACY_POLICY_LINK}
|
||||
target="_blank"
|
||||
href="https://ente.io/privacy#8-biometric-information-privacy-policy"
|
||||
underline="always"
|
||||
sx={{
|
||||
color: "inherit",
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { ML_BLOG_LINK } from "@ente/shared/constants/urls";
|
||||
import { Box, Button, Stack, Typography } from "@mui/material";
|
||||
import Titlebar from "components/Titlebar";
|
||||
import { t } from "i18next";
|
||||
|
@ -10,6 +9,9 @@ export default function EnableMLSearch({
|
|||
enableMlSearch,
|
||||
onRootClose,
|
||||
}) {
|
||||
const showDetails = () =>
|
||||
openLink("https://ente.io/blog/desktop-ml-beta", true);
|
||||
|
||||
return (
|
||||
<Stack spacing={"4px"} py={"12px"}>
|
||||
<Titlebar
|
||||
|
@ -33,9 +35,9 @@ export default function EnableMLSearch({
|
|||
{t("ENABLE")}
|
||||
</Button>
|
||||
<Button
|
||||
color={"secondary"}
|
||||
color="secondary"
|
||||
size="large"
|
||||
onClick={() => openLink(ML_BLOG_LINK, true)}
|
||||
onClick={showDetails}
|
||||
>
|
||||
{t("ML_MORE_DETAILS")}
|
||||
</Button>
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import { haveWindow } from "@/next/env";
|
||||
import { styled } from "@mui/material";
|
||||
import { useEffect, useRef } from "react";
|
||||
import { runningInBrowser } from "utils/common";
|
||||
import { MapButton } from "./MapButton";
|
||||
|
||||
import { t } from "i18next";
|
||||
import "leaflet-defaulticon-compatibility/dist/leaflet-defaulticon-compatibility.webpack.css"; // Re-uses images from ~leaflet package
|
||||
import "leaflet/dist/leaflet.css";
|
||||
runningInBrowser() && require("leaflet-defaulticon-compatibility");
|
||||
const L = runningInBrowser()
|
||||
haveWindow() && require("leaflet-defaulticon-compatibility");
|
||||
const L = haveWindow()
|
||||
? (require("leaflet") as typeof import("leaflet"))
|
||||
: null;
|
||||
|
||||
|
|
|
@ -2,10 +2,6 @@ import { t } from "i18next";
|
|||
import { useContext } from "react";
|
||||
|
||||
import EnteSpinner from "@ente/shared/components/EnteSpinner";
|
||||
import {
|
||||
DESKTOP_ROADMAP_URL,
|
||||
WEB_ROADMAP_URL,
|
||||
} from "@ente/shared/constants/urls";
|
||||
import { Typography } from "@mui/material";
|
||||
import { EnteMenuItem } from "components/Menu/EnteMenuItem";
|
||||
import { NoStyleAnchor } from "components/pages/sharedAlbum/GoToEnte";
|
||||
|
@ -20,17 +16,12 @@ export default function HelpSection() {
|
|||
const { setDialogMessage } = useContext(AppContext);
|
||||
const { openExportModal } = useContext(GalleryContext);
|
||||
|
||||
async function openRoadmap() {
|
||||
let roadmapURL: string;
|
||||
if (isElectron()) {
|
||||
roadmapURL = DESKTOP_ROADMAP_URL;
|
||||
} else {
|
||||
roadmapURL = WEB_ROADMAP_URL;
|
||||
}
|
||||
openLink(roadmapURL, true);
|
||||
}
|
||||
const openRoadmap = () =>
|
||||
openLink("https://github.com/ente-io/ente/discussions", true);
|
||||
|
||||
function handleExportOpen() {
|
||||
const contactSupport = () => openLink("mailto:support@ente.io", true);
|
||||
|
||||
function openExport() {
|
||||
if (isElectron()) {
|
||||
openExportModal();
|
||||
} else {
|
||||
|
@ -46,7 +37,7 @@ export default function HelpSection() {
|
|||
variant="secondary"
|
||||
/>
|
||||
<EnteMenuItem
|
||||
onClick={() => openLink("mailto:support@ente.io", true)}
|
||||
onClick={contactSupport}
|
||||
labelComponent={
|
||||
<NoStyleAnchor href="mailto:support@ente.io">
|
||||
<Typography fontWeight={"bold"}>
|
||||
|
@ -57,7 +48,7 @@ export default function HelpSection() {
|
|||
variant="secondary"
|
||||
/>
|
||||
<EnteMenuItem
|
||||
onClick={handleExportOpen}
|
||||
onClick={openExport}
|
||||
label={t("EXPORT")}
|
||||
endIcon={
|
||||
exportService.isExportInProgress() && (
|
||||
|
|
|
@ -2,7 +2,6 @@ import { Dialog, DialogContent, Link } from "@mui/material";
|
|||
import { t } from "i18next";
|
||||
|
||||
import { dialogCloseHandler } from "@ente/shared/components/DialogBox/TitleWithCloseButton";
|
||||
import { APP_DOWNLOAD_URL } from "@ente/shared/constants/urls";
|
||||
import { UPLOAD_RESULT, UPLOAD_STAGES } from "constants/upload";
|
||||
import UploadProgressContext from "contexts/uploadProgress";
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
|
@ -84,7 +83,7 @@ export function UploadProgressDialog() {
|
|||
components={{
|
||||
a: (
|
||||
<Link
|
||||
href={APP_DOWNLOAD_URL}
|
||||
href="https://ente.io/download/desktop"
|
||||
target="_blank"
|
||||
/>
|
||||
),
|
||||
|
|
|
@ -1,15 +1,8 @@
|
|||
import { useContext, useEffect, useRef, useState } from "react";
|
||||
|
||||
import { t } from "i18next";
|
||||
import { Trans } from "react-i18next";
|
||||
import { getLatestCollections } from "services/collectionService";
|
||||
|
||||
import UploadProgress from "./UploadProgress";
|
||||
|
||||
import ElectronAPIs from "@ente/shared/electron";
|
||||
import { CustomError } from "@ente/shared/error";
|
||||
import { addLogLine } from "@ente/shared/logging";
|
||||
import { logError } from "@ente/shared/sentry";
|
||||
import { isPromise } from "@ente/shared/utils";
|
||||
import DiscFullIcon from "@mui/icons-material/DiscFull";
|
||||
import UserNameInputDialog from "components/UserNameInputDialog";
|
||||
import {
|
||||
|
@ -18,10 +11,13 @@ import {
|
|||
UPLOAD_STAGES,
|
||||
UPLOAD_STRATEGY,
|
||||
} from "constants/upload";
|
||||
import { t } from "i18next";
|
||||
import isElectron from "is-electron";
|
||||
import { AppContext } from "pages/_app";
|
||||
import { GalleryContext } from "pages/gallery";
|
||||
import { useContext, useEffect, useRef, useState } from "react";
|
||||
import billingService from "services/billingService";
|
||||
import { getLatestCollections } from "services/collectionService";
|
||||
import ImportService from "services/importService";
|
||||
import {
|
||||
getPublicCollectionUID,
|
||||
|
@ -52,7 +48,6 @@ import {
|
|||
UploadFileNames,
|
||||
} from "types/upload/ui";
|
||||
import { getOrCreateAlbum } from "utils/collection";
|
||||
import { downloadApp, waitAndRun } from "utils/common";
|
||||
import { PublicCollectionGalleryContext } from "utils/publicCollectionGallery";
|
||||
import {
|
||||
getDownloadAppMessage,
|
||||
|
@ -63,8 +58,8 @@ import {
|
|||
getImportSuggestion,
|
||||
groupFilesBasedOnParentFolder,
|
||||
} from "utils/upload";
|
||||
import { isCanvasBlocked } from "utils/upload/isCanvasBlocked";
|
||||
import { SetCollectionNamerAttributes } from "../Collections/CollectionNamer";
|
||||
import UploadProgress from "./UploadProgress";
|
||||
import UploadStrategyChoiceModal from "./UploadStrategyChoiceModal";
|
||||
import UploadTypeSelector from "./UploadTypeSelector";
|
||||
|
||||
|
@ -312,21 +307,6 @@ export default function Uploader(props: Props) {
|
|||
return;
|
||||
}
|
||||
}
|
||||
if (isCanvasBlocked()) {
|
||||
addLogLine("canvas blocked, blocking upload");
|
||||
appContext.setDialogMessage({
|
||||
title: t("CANVAS_BLOCKED_TITLE"),
|
||||
|
||||
content: <Trans i18nKey="CANVAS_BLOCKED_MESSAGE" />,
|
||||
close: { text: t("CLOSE") },
|
||||
proceed: {
|
||||
text: t("DOWNLOAD"),
|
||||
action: downloadApp,
|
||||
variant: "accent",
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
uploadRunning.current = true;
|
||||
props.closeUploadTypeSelector();
|
||||
props.setLoading(true);
|
||||
|
@ -844,3 +824,13 @@ export default function Uploader(props: Props) {
|
|||
</>
|
||||
);
|
||||
}
|
||||
|
||||
async function waitAndRun(
|
||||
waitPromise: Promise<void>,
|
||||
task: () => Promise<void>,
|
||||
) {
|
||||
if (waitPromise && isPromise(waitPromise)) {
|
||||
await waitPromise;
|
||||
}
|
||||
await task();
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@ import {
|
|||
planForSubscription,
|
||||
updateSubscription,
|
||||
} from "utils/billing";
|
||||
import { reverseString } from "utils/common";
|
||||
import { getLocalUserDetails } from "utils/user";
|
||||
import { getTotalFamilyUsage, isPartOfFamily } from "utils/user/family";
|
||||
import FreeSubscriptionPlanSelectorCard from "./free";
|
||||
|
@ -130,9 +129,7 @@ function PlanSelectorCard(props: Props) {
|
|||
}
|
||||
} else if (hasStripeSubscription(subscription)) {
|
||||
appContext.setDialogMessage({
|
||||
title: `${t("CONFIRM")} ${reverseString(
|
||||
t("UPDATE_SUBSCRIPTION"),
|
||||
)}`,
|
||||
title: t("update_subscription_title"),
|
||||
content: t("UPDATE_SUBSCRIPTION_MESSAGE"),
|
||||
proceed: {
|
||||
text: t("UPDATE_SUBSCRIPTION"),
|
||||
|
|
|
@ -49,7 +49,7 @@ import {
|
|||
syncMapEnabled,
|
||||
validateKey,
|
||||
} from "services/userService";
|
||||
import { mergeMaps, preloadImage } from "utils/common";
|
||||
import { preloadImage } from "utils/common";
|
||||
import {
|
||||
FILE_OPS_TYPE,
|
||||
constructFileToCollectionMap,
|
||||
|
@ -135,7 +135,6 @@ import {
|
|||
import { Search, SearchResultSummary, UpdateSearch } from "types/search";
|
||||
import { FamilyData } from "types/user";
|
||||
import ComlinkSearchWorker from "utils/comlink/ComlinkSearchWorker";
|
||||
import { checkConnectivity } from "utils/common";
|
||||
import { isArchivedFile } from "utils/magicMetadata";
|
||||
import { getSessionExpiredMessage } from "utils/ui";
|
||||
import { getLocalFamilyData } from "utils/user/family";
|
||||
|
@ -680,13 +679,13 @@ export default function Gallery() {
|
|||
};
|
||||
|
||||
const syncWithRemote = async (force = false, silent = false) => {
|
||||
if (!navigator.onLine) return;
|
||||
if (syncInProgress.current && !force) {
|
||||
resync.current = { force, silent };
|
||||
return;
|
||||
}
|
||||
syncInProgress.current = true;
|
||||
try {
|
||||
checkConnectivity();
|
||||
const token = getToken();
|
||||
if (!token) {
|
||||
return;
|
||||
|
@ -719,8 +718,6 @@ export default function Gallery() {
|
|||
clearKeys();
|
||||
router.push(PAGES.CREDENTIALS);
|
||||
break;
|
||||
case CustomError.NO_INTERNET_CONNECTION:
|
||||
break;
|
||||
default:
|
||||
logError(e, "syncWithRemote failed");
|
||||
}
|
||||
|
@ -1252,3 +1249,11 @@ function useEffectSingleThreaded(
|
|||
main(deps);
|
||||
}, deps);
|
||||
}
|
||||
|
||||
const mergeMaps = <K, V>(map1: Map<K, V>, map2: Map<K, V>) => {
|
||||
const mergedMap = new Map<K, V>(map1);
|
||||
map2.forEach((value, key) => {
|
||||
mergedMap.set(key, value);
|
||||
});
|
||||
return mergedMap;
|
||||
};
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { CITIES_URL } from "@ente/shared/constants/urls";
|
||||
import { logError } from "@ente/shared/sentry";
|
||||
import { LocationTagData } from "types/entity";
|
||||
import { Location } from "types/upload";
|
||||
|
@ -22,7 +21,9 @@ class LocationSearchService {
|
|||
if (this.citiesPromise) {
|
||||
return;
|
||||
}
|
||||
this.citiesPromise = fetch(CITIES_URL).then((response) => {
|
||||
this.citiesPromise = fetch(
|
||||
"https://static.ente.io/world_cities.json",
|
||||
).then((response) => {
|
||||
return response.json().then((data) => {
|
||||
this.cities = data["data"];
|
||||
});
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { haveWindow } from "@/next/env";
|
||||
import { getDedicatedCryptoWorker } from "@ente/shared/crypto";
|
||||
import { DedicatedCryptoWorker } from "@ente/shared/crypto/internal/crypto.worker";
|
||||
import { addLogLine } from "@ente/shared/logging";
|
||||
|
@ -24,7 +25,6 @@ import {
|
|||
SceneDetectionMethod,
|
||||
SceneDetectionService,
|
||||
} from "types/machineLearning";
|
||||
import { getConcurrency } from "utils/common/concurrency";
|
||||
import { logQueueStats } from "utils/machineLearning";
|
||||
import arcfaceAlignmentService from "./arcfaceAlignmentService";
|
||||
import arcfaceCropService from "./arcfaceCropService";
|
||||
|
@ -232,3 +232,6 @@ export class LocalMLSyncContext implements MLSyncContext {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const getConcurrency = () =>
|
||||
haveWindow() && Math.max(2, Math.ceil(navigator.hardwareConcurrency / 2));
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { haveWindow } from "@/next/env";
|
||||
import { ComlinkWorker } from "@ente/shared/worker/comlinkWorker";
|
||||
import { Remote } from "comlink";
|
||||
import { runningInBrowser } from "utils/common";
|
||||
import { DedicatedConvertWorker } from "worker/convert.worker";
|
||||
|
||||
class ComlinkConvertWorker {
|
||||
|
@ -16,7 +16,7 @@ class ComlinkConvertWorker {
|
|||
}
|
||||
|
||||
export const getDedicatedConvertWorker = () => {
|
||||
if (runningInBrowser()) {
|
||||
if (haveWindow()) {
|
||||
const cryptoComlinkWorker = new ComlinkWorker<
|
||||
typeof DedicatedConvertWorker
|
||||
>(
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { haveWindow } from "@/next/env";
|
||||
import { ComlinkWorker } from "@ente/shared/worker/comlinkWorker";
|
||||
import { runningInBrowser } from "utils/common";
|
||||
import { DedicatedMLWorker } from "worker/ml.worker";
|
||||
|
||||
export const getDedicatedMLWorker = (name: string) => {
|
||||
if (runningInBrowser()) {
|
||||
if (haveWindow()) {
|
||||
const cryptoComlinkWorker = new ComlinkWorker<typeof DedicatedMLWorker>(
|
||||
name ?? "ente-ml-worker",
|
||||
new Worker(new URL("worker/ml.worker.ts", import.meta.url)),
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { haveWindow } from "@/next/env";
|
||||
import { ComlinkWorker } from "@ente/shared/worker/comlinkWorker";
|
||||
import { Remote } from "comlink";
|
||||
import { runningInBrowser } from "utils/common";
|
||||
import { DedicatedSearchWorker } from "worker/search.worker";
|
||||
|
||||
class ComlinkSearchWorker {
|
||||
|
@ -16,7 +16,7 @@ class ComlinkSearchWorker {
|
|||
}
|
||||
|
||||
export const getDedicatedSearchWorker = () => {
|
||||
if (runningInBrowser()) {
|
||||
if (haveWindow()) {
|
||||
const cryptoComlinkWorker = new ComlinkWorker<
|
||||
typeof DedicatedSearchWorker
|
||||
>(
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
import { runningInBrowser } from ".";
|
||||
|
||||
export const getConcurrency = () =>
|
||||
runningInBrowser() &&
|
||||
Math.max(2, Math.ceil(navigator.hardwareConcurrency / 2));
|
|
@ -1,65 +1,3 @@
|
|||
import { APP_DOWNLOAD_URL } from "@ente/shared/constants/urls";
|
||||
import { CustomError } from "@ente/shared/error";
|
||||
import { isPromise } from "@ente/shared/utils";
|
||||
import isElectron from "is-electron";
|
||||
|
||||
export function checkConnectivity() {
|
||||
if (navigator.onLine) {
|
||||
return true;
|
||||
}
|
||||
throw new Error(CustomError.NO_INTERNET_CONNECTION);
|
||||
}
|
||||
|
||||
export function runningInBrowser() {
|
||||
return typeof window !== "undefined";
|
||||
}
|
||||
|
||||
export function runningInWorker() {
|
||||
return typeof importScripts === "function";
|
||||
}
|
||||
|
||||
export function runningInElectron() {
|
||||
return isElectron();
|
||||
}
|
||||
|
||||
export function runningInChrome(includeMobile: boolean) {
|
||||
try {
|
||||
const userAgentData = navigator["userAgentData"];
|
||||
const chromeBrand = userAgentData?.brands?.filter(
|
||||
(b) => b.brand === "Google Chrome" || b.brand === "Chromium",
|
||||
)?.[0];
|
||||
return chromeBrand && (includeMobile || userAgentData.mobile === false);
|
||||
} catch (error) {
|
||||
console.error("Error in runningInChrome: ", error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function offscreenCanvasSupported() {
|
||||
return !(typeof OffscreenCanvas === "undefined");
|
||||
}
|
||||
|
||||
export function webglSupported() {
|
||||
try {
|
||||
const canvas = document.createElement("canvas");
|
||||
const gl = canvas.getContext("webgl");
|
||||
return gl && gl instanceof WebGLRenderingContext;
|
||||
} catch (error) {
|
||||
console.error("Error in webglSupported: ", error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function downloadApp() {
|
||||
openLink(APP_DOWNLOAD_URL, true);
|
||||
}
|
||||
|
||||
export function reverseString(title: string) {
|
||||
return title
|
||||
?.split(" ")
|
||||
.reduce((reversedString, currWord) => `${currWord} ${reversedString}`);
|
||||
}
|
||||
|
||||
export function initiateEmail(email: string) {
|
||||
const a = document.createElement("a");
|
||||
a.href = "mailto:" + email;
|
||||
|
@ -74,6 +12,7 @@ export const preloadImage = (imgBasePath: string) => {
|
|||
}
|
||||
new Image().srcset = srcSet.join(",");
|
||||
};
|
||||
|
||||
export function openLink(href: string, newTab?: boolean) {
|
||||
const a = document.createElement("a");
|
||||
a.href = href;
|
||||
|
@ -84,16 +23,6 @@ export function openLink(href: string, newTab?: boolean) {
|
|||
a.click();
|
||||
}
|
||||
|
||||
export async function waitAndRun(
|
||||
waitPromise: Promise<void>,
|
||||
task: () => Promise<void>,
|
||||
) {
|
||||
if (waitPromise && isPromise(waitPromise)) {
|
||||
await waitPromise;
|
||||
}
|
||||
await task();
|
||||
}
|
||||
|
||||
export function isClipboardItemPresent() {
|
||||
return typeof ClipboardItem !== "undefined";
|
||||
}
|
||||
|
@ -105,11 +34,3 @@ export function batch<T>(arr: T[], batchSize: number): T[][] {
|
|||
}
|
||||
return batches;
|
||||
}
|
||||
|
||||
export const mergeMaps = <K, V>(map1: Map<K, V>, map2: Map<K, V>) => {
|
||||
const mergedMap = new Map<K, V>(map1);
|
||||
map2.forEach((value, key) => {
|
||||
mergedMap.set(key, value);
|
||||
});
|
||||
return mergedMap;
|
||||
};
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { haveWindow } from "@/next/env";
|
||||
import { addLogLine } from "@ente/shared/logging";
|
||||
import { logError } from "@ente/shared/sentry";
|
||||
import {
|
||||
|
@ -14,6 +15,7 @@ import {
|
|||
deleteDB,
|
||||
openDB,
|
||||
} from "idb";
|
||||
import isElectron from "is-electron";
|
||||
import {
|
||||
Face,
|
||||
MLLibraryData,
|
||||
|
@ -23,7 +25,6 @@ import {
|
|||
Thing,
|
||||
} from "types/machineLearning";
|
||||
import { IndexStatus } from "types/machineLearning/ui";
|
||||
import { runningInBrowser, runningInElectron } from "utils/common";
|
||||
|
||||
interface Config {}
|
||||
|
||||
|
@ -64,7 +65,7 @@ class MLIDbStorage {
|
|||
public _db: Promise<IDBPDatabase<MLDb>>;
|
||||
|
||||
constructor() {
|
||||
if (!runningInBrowser() || !runningInElectron()) {
|
||||
if (!haveWindow() || !isElectron()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
import { DialogBoxAttributes } from "@ente/shared/components/DialogBox/types";
|
||||
import AutoAwesomeOutlinedIcon from "@mui/icons-material/AutoAwesomeOutlined";
|
||||
import { t } from "i18next";
|
||||
import { downloadApp } from "utils/common";
|
||||
|
||||
import { logoutUser } from "@ente/accounts/services/user";
|
||||
import { DialogBoxAttributes } from "@ente/shared/components/DialogBox/types";
|
||||
import ElectronAPIs from "@ente/shared/electron";
|
||||
import { AppUpdateInfo } from "@ente/shared/electron/types";
|
||||
import AutoAwesomeOutlinedIcon from "@mui/icons-material/AutoAwesomeOutlined";
|
||||
import InfoOutlined from "@mui/icons-material/InfoRounded";
|
||||
import { Link } from "@mui/material";
|
||||
import { OPEN_STREET_MAP_LINK } from "components/Sidebar/EnableMap";
|
||||
import { t } from "i18next";
|
||||
import { Trans } from "react-i18next";
|
||||
import { Subscription } from "types/billing";
|
||||
import { openLink } from "utils/common";
|
||||
|
||||
export const getDownloadAppMessage = (): DialogBoxAttributes => {
|
||||
return {
|
||||
title: t("DOWNLOAD_APP"),
|
||||
|
@ -27,6 +27,8 @@ export const getDownloadAppMessage = (): DialogBoxAttributes => {
|
|||
};
|
||||
};
|
||||
|
||||
const downloadApp = () => openLink("https://ente.io/download/desktop", true);
|
||||
|
||||
export const getTrashFilesMessage = (
|
||||
deleteFileHelper,
|
||||
): DialogBoxAttributes => ({
|
||||
|
|
|
@ -1,53 +0,0 @@
|
|||
//
|
||||
// Canvas Blocker &
|
||||
// Firefox privacy.resistFingerprinting Detector.
|
||||
// (c) 2018 // JOHN OZBAY // CRYPT.EE
|
||||
// MIT License
|
||||
|
||||
// Credits: https://github.com/johnozbay/canvas-block-detector/blob/master/isCanvasBlocked.js
|
||||
|
||||
//
|
||||
export function isCanvasBlocked() {
|
||||
// create a 1px image data
|
||||
let blocked = false;
|
||||
const canvas = document.createElement("canvas");
|
||||
const ctx = canvas.getContext("2d");
|
||||
|
||||
// some blockers just return an undefined ctx. So let's check that first.
|
||||
if (ctx) {
|
||||
const imageData = ctx.createImageData(1, 1);
|
||||
const originalImageData = imageData.data;
|
||||
|
||||
// set pixels to RGB 128
|
||||
originalImageData[0] = 128;
|
||||
originalImageData[1] = 128;
|
||||
originalImageData[2] = 128;
|
||||
originalImageData[3] = 255;
|
||||
|
||||
// set this to canvas
|
||||
ctx.putImageData(imageData, 1, 1);
|
||||
|
||||
try {
|
||||
// now get the data back from canvas.
|
||||
const checkData = ctx.getImageData(1, 1, 1, 1).data;
|
||||
|
||||
// If this is firefox, and privacy.resistFingerprinting is enabled,
|
||||
// OR a browser extension blocking the canvas,
|
||||
// This will return RGB all white (255,255,255) instead of the (128,128,128) we put.
|
||||
|
||||
// so let's check the R and G to see if they're 255 or 128 (matching what we've initially set)
|
||||
if (
|
||||
originalImageData[0] !== checkData[0] &&
|
||||
originalImageData[1] !== checkData[1]
|
||||
) {
|
||||
blocked = true;
|
||||
}
|
||||
} catch (error) {
|
||||
// some extensions will return getImageData null. this is to account for that.
|
||||
blocked = true;
|
||||
}
|
||||
} else {
|
||||
blocked = true;
|
||||
}
|
||||
return blocked;
|
||||
}
|
|
@ -10,3 +10,28 @@
|
|||
* all other commands.
|
||||
*/
|
||||
export const isDevBuild = process.env.NODE_ENV === "development";
|
||||
|
||||
/**
|
||||
* `true` if we're running in the default global context (aka the main thread)
|
||||
* of a web browser.
|
||||
*
|
||||
* In particular, this is `false` when we're running in a Web Worker,
|
||||
* irrespecitve of whether the worker is running in a Node.js context or a web
|
||||
* browser context.
|
||||
*
|
||||
* > We can be running in a browser context either if the user has the page open
|
||||
* in a web browser, or if we're the renderer process of an Electron app.
|
||||
*
|
||||
* Note that this cannot be a constant, otherwise it'll get inlined during SSR
|
||||
* with the wrong value.
|
||||
*/
|
||||
export const haveWindow = () => typeof window !== "undefined";
|
||||
|
||||
/**
|
||||
* Return true if we are running in a [Web
|
||||
* Worker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API)
|
||||
*
|
||||
* Note that this cannot be a constant, otherwise it'll get inlined during SSR
|
||||
* with the wrong value.
|
||||
*/
|
||||
export const inWorker = () => typeof importScripts === "function";
|
||||
|
|
|
@ -168,6 +168,7 @@
|
|||
"UPDATE_PAYMENT_METHOD": "Update payment method",
|
||||
"MONTHLY": "Monthly",
|
||||
"YEARLY": "Yearly",
|
||||
"update_subscription_title": "Confirm plan change",
|
||||
"UPDATE_SUBSCRIPTION_MESSAGE": "Are you sure you want to change your plan?",
|
||||
"UPDATE_SUBSCRIPTION": "Change plan",
|
||||
"CANCEL_SUBSCRIPTION": "Cancel subscription",
|
||||
|
@ -421,8 +422,6 @@
|
|||
"ENTER_TWO_FACTOR_OTP": "Enter the 6-digit code from your authenticator app.",
|
||||
"CREATE_ACCOUNT": "Create account",
|
||||
"COPIED": "Copied",
|
||||
"CANVAS_BLOCKED_TITLE": "Unable to generate thumbnail",
|
||||
"CANVAS_BLOCKED_MESSAGE": "<p>It looks like your browser has disabled access to canvas, which is necessary to generate thumbnails for your photos </p> <p> Please enable access to your browser's canvas, or check out our desktop app</p>",
|
||||
"WATCH_FOLDERS": "Watch folders",
|
||||
"UPGRADE_NOW": "Upgrade now",
|
||||
"RENEW_NOW": "Renew now",
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
"get-user-locale": "^2.3",
|
||||
"i18next": "^23.10",
|
||||
"i18next-resources-to-backend": "^1.2.0",
|
||||
"is-electron": "^2.2",
|
||||
"next": "^14.1",
|
||||
"react": "^18",
|
||||
"react-dom": "^18",
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
{
|
||||
"extends": "@/build-config/tsconfig-typecheck.json",
|
||||
"compilerOptions": {
|
||||
/* Also indicate expectation of a WebWorker runtime */
|
||||
"lib": ["ESnext", "DOM", "DOM.Iterable", "WebWorker"]
|
||||
},
|
||||
/* Typecheck all files with the given extensions (here or in subfolders) */
|
||||
"include": ["**/*.ts", "**/*.tsx"]
|
||||
}
|
||||
|
|
|
@ -1,21 +1,5 @@
|
|||
export const ENTE_WEBSITE_LINK = "https://ente.io";
|
||||
|
||||
export const ML_BLOG_LINK = "https://ente.io/blog/desktop-ml-beta";
|
||||
|
||||
export const FACE_SEARCH_PRIVACY_POLICY_LINK =
|
||||
"https://ente.io/privacy#8-biometric-information-privacy-policy";
|
||||
|
||||
export const SUPPORT_EMAIL = "support@ente.io";
|
||||
|
||||
export const APP_DOWNLOAD_URL = "https://ente.io/download/desktop";
|
||||
|
||||
export const FEEDBACK_EMAIL = "feedback@ente.io";
|
||||
|
||||
export const DELETE_ACCOUNT_EMAIL = "account-deletion@ente.io";
|
||||
|
||||
export const WEB_ROADMAP_URL = "https://github.com/ente-io/ente/discussions";
|
||||
|
||||
export const DESKTOP_ROADMAP_URL =
|
||||
"https://github.com/ente-io/ente/discussions";
|
||||
|
||||
export const CITIES_URL = "https://static.ente.io/world_cities.json";
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { runningInWorker } from "@ente/shared/platform";
|
||||
import { inWorker } from "@/next/env";
|
||||
import * as Comlink from "comlink";
|
||||
import { wrap } from "comlink";
|
||||
import { ElectronAPIsType } from "./types";
|
||||
|
@ -17,7 +17,7 @@ class WorkerSafeElectronServiceImpl implements LimitedElectronAPIs {
|
|||
this.ready = this.init();
|
||||
}
|
||||
private async init() {
|
||||
if (runningInWorker()) {
|
||||
if (inWorker()) {
|
||||
const workerSafeElectronClient =
|
||||
wrap<typeof WorkerSafeElectronClient>(self);
|
||||
|
||||
|
|
|
@ -70,7 +70,6 @@ export const CustomError = {
|
|||
EXPORT_STOPPED: "export stopped",
|
||||
NO_EXPORT_FOLDER_SELECTED: "no export folder selected",
|
||||
EXPORT_FOLDER_DOES_NOT_EXIST: "export folder does not exist",
|
||||
NO_INTERNET_CONNECTION: "no internet connection",
|
||||
AUTH_KEY_NOT_FOUND: "auth key not found",
|
||||
EXIF_DATA_NOT_FOUND: "exif data not found",
|
||||
SELECT_FOLDER_ABORTED: "select folder aborted",
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
import isElectron from "is-electron";
|
||||
|
||||
export function runningInBrowser() {
|
||||
return typeof window !== "undefined";
|
||||
}
|
||||
|
||||
export function runningInWorker() {
|
||||
return typeof importScripts === "function";
|
||||
}
|
||||
|
||||
export function runningInElectron() {
|
||||
return isElectron();
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
import { runningInBrowser } from "../../platform";
|
||||
import { haveWindow } from "@/next/env";
|
||||
|
||||
import localForage from "localforage";
|
||||
|
||||
if (runningInBrowser()) {
|
||||
if (haveWindow()) {
|
||||
localForage.config({
|
||||
name: "ente-files",
|
||||
version: 1.0,
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"is-electron": "^2.2",
|
||||
"libsodium-wrappers": "0.7.9",
|
||||
"yup": "^1.4"
|
||||
},
|
||||
|
|
Loading…
Add table
Reference in a new issue