diff --git a/web/apps/photos/src/components/MachineLearning/MLSearchSettings/enableFaceSearch.tsx b/web/apps/photos/src/components/MachineLearning/MLSearchSettings/enableFaceSearch.tsx index 469144639..a007cb398 100644 --- a/web/apps/photos/src/components/MachineLearning/MLSearchSettings/enableFaceSearch.tsx +++ b/web/apps/photos/src/components/MachineLearning/MLSearchSettings/enableFaceSearch.tsx @@ -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: ( + openLink("https://ente.io/blog/desktop-ml-beta", true); + return ( diff --git a/web/apps/photos/src/components/PhotoViewer/FileInfo/MapBox.tsx b/web/apps/photos/src/components/PhotoViewer/FileInfo/MapBox.tsx index d7e3b9e91..c4d552fbc 100644 --- a/web/apps/photos/src/components/PhotoViewer/FileInfo/MapBox.tsx +++ b/web/apps/photos/src/components/PhotoViewer/FileInfo/MapBox.tsx @@ -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; diff --git a/web/apps/photos/src/components/Sidebar/HelpSection.tsx b/web/apps/photos/src/components/Sidebar/HelpSection.tsx index 1f7ce95cc..4cc97c414 100644 --- a/web/apps/photos/src/components/Sidebar/HelpSection.tsx +++ b/web/apps/photos/src/components/Sidebar/HelpSection.tsx @@ -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" /> openLink("mailto:support@ente.io", true)} + onClick={contactSupport} labelComponent={ @@ -57,7 +48,7 @@ export default function HelpSection() { variant="secondary" /> ), diff --git a/web/apps/photos/src/components/Upload/Uploader.tsx b/web/apps/photos/src/components/Upload/Uploader.tsx index ef91f0670..f1d6d03ff 100644 --- a/web/apps/photos/src/components/Upload/Uploader.tsx +++ b/web/apps/photos/src/components/Upload/Uploader.tsx @@ -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: , - 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, + task: () => Promise, +) { + if (waitPromise && isPromise(waitPromise)) { + await waitPromise; + } + await task(); +} diff --git a/web/apps/photos/src/components/pages/gallery/PlanSelector/card/index.tsx b/web/apps/photos/src/components/pages/gallery/PlanSelector/card/index.tsx index 7bafa0403..41e577675 100644 --- a/web/apps/photos/src/components/pages/gallery/PlanSelector/card/index.tsx +++ b/web/apps/photos/src/components/pages/gallery/PlanSelector/card/index.tsx @@ -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"), diff --git a/web/apps/photos/src/pages/gallery/index.tsx b/web/apps/photos/src/pages/gallery/index.tsx index f62376ea6..5930dd30b 100644 --- a/web/apps/photos/src/pages/gallery/index.tsx +++ b/web/apps/photos/src/pages/gallery/index.tsx @@ -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 = (map1: Map, map2: Map) => { + const mergedMap = new Map(map1); + map2.forEach((value, key) => { + mergedMap.set(key, value); + }); + return mergedMap; +}; diff --git a/web/apps/photos/src/services/locationSearchService.ts b/web/apps/photos/src/services/locationSearchService.ts index a77557dee..bfc6990da 100644 --- a/web/apps/photos/src/services/locationSearchService.ts +++ b/web/apps/photos/src/services/locationSearchService.ts @@ -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"]; }); diff --git a/web/apps/photos/src/services/machineLearning/machineLearningFactory.ts b/web/apps/photos/src/services/machineLearning/machineLearningFactory.ts index d397a60ad..b93474cb3 100644 --- a/web/apps/photos/src/services/machineLearning/machineLearningFactory.ts +++ b/web/apps/photos/src/services/machineLearning/machineLearningFactory.ts @@ -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)); diff --git a/web/apps/photos/src/utils/comlink/ComlinkConvertWorker.ts b/web/apps/photos/src/utils/comlink/ComlinkConvertWorker.ts index 3dc034160..7136fbd62 100644 --- a/web/apps/photos/src/utils/comlink/ComlinkConvertWorker.ts +++ b/web/apps/photos/src/utils/comlink/ComlinkConvertWorker.ts @@ -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 >( diff --git a/web/apps/photos/src/utils/comlink/ComlinkMLWorker.ts b/web/apps/photos/src/utils/comlink/ComlinkMLWorker.ts index f61754c6b..f75c0f866 100644 --- a/web/apps/photos/src/utils/comlink/ComlinkMLWorker.ts +++ b/web/apps/photos/src/utils/comlink/ComlinkMLWorker.ts @@ -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( name ?? "ente-ml-worker", new Worker(new URL("worker/ml.worker.ts", import.meta.url)), diff --git a/web/apps/photos/src/utils/comlink/ComlinkSearchWorker.ts b/web/apps/photos/src/utils/comlink/ComlinkSearchWorker.ts index 971f12338..b4ec05490 100644 --- a/web/apps/photos/src/utils/comlink/ComlinkSearchWorker.ts +++ b/web/apps/photos/src/utils/comlink/ComlinkSearchWorker.ts @@ -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 >( diff --git a/web/apps/photos/src/utils/common/concurrency.ts b/web/apps/photos/src/utils/common/concurrency.ts deleted file mode 100644 index bba75f009..000000000 --- a/web/apps/photos/src/utils/common/concurrency.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { runningInBrowser } from "."; - -export const getConcurrency = () => - runningInBrowser() && - Math.max(2, Math.ceil(navigator.hardwareConcurrency / 2)); diff --git a/web/apps/photos/src/utils/common/index.ts b/web/apps/photos/src/utils/common/index.ts index 4fcc07717..059dfed2b 100644 --- a/web/apps/photos/src/utils/common/index.ts +++ b/web/apps/photos/src/utils/common/index.ts @@ -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, - task: () => Promise, -) { - if (waitPromise && isPromise(waitPromise)) { - await waitPromise; - } - await task(); -} - export function isClipboardItemPresent() { return typeof ClipboardItem !== "undefined"; } @@ -105,11 +34,3 @@ export function batch(arr: T[], batchSize: number): T[][] { } return batches; } - -export const mergeMaps = (map1: Map, map2: Map) => { - const mergedMap = new Map(map1); - map2.forEach((value, key) => { - mergedMap.set(key, value); - }); - return mergedMap; -}; diff --git a/web/apps/photos/src/utils/storage/mlIDbStorage.ts b/web/apps/photos/src/utils/storage/mlIDbStorage.ts index 7ee4a5fcf..865b6cb8c 100644 --- a/web/apps/photos/src/utils/storage/mlIDbStorage.ts +++ b/web/apps/photos/src/utils/storage/mlIDbStorage.ts @@ -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>; constructor() { - if (!runningInBrowser() || !runningInElectron()) { + if (!haveWindow() || !isElectron()) { return; } diff --git a/web/apps/photos/src/utils/ui/index.tsx b/web/apps/photos/src/utils/ui/index.tsx index 1b938fb03..75b0cd23d 100644 --- a/web/apps/photos/src/utils/ui/index.tsx +++ b/web/apps/photos/src/utils/ui/index.tsx @@ -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 => ({ diff --git a/web/apps/photos/src/utils/upload/isCanvasBlocked.ts b/web/apps/photos/src/utils/upload/isCanvasBlocked.ts deleted file mode 100644 index e9f9b5abe..000000000 --- a/web/apps/photos/src/utils/upload/isCanvasBlocked.ts +++ /dev/null @@ -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; -} diff --git a/web/packages/next/env.ts b/web/packages/next/env.ts index 8e66e7fd9..ea145d892 100644 --- a/web/packages/next/env.ts +++ b/web/packages/next/env.ts @@ -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"; diff --git a/web/packages/next/locales/en-US/translation.json b/web/packages/next/locales/en-US/translation.json index 29469cd0f..5fdb380d5 100644 --- a/web/packages/next/locales/en-US/translation.json +++ b/web/packages/next/locales/en-US/translation.json @@ -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": "

It looks like your browser has disabled access to canvas, which is necessary to generate thumbnails for your photos

Please enable access to your browser's canvas, or check out our desktop app

", "WATCH_FOLDERS": "Watch folders", "UPGRADE_NOW": "Upgrade now", "RENEW_NOW": "Renew now", diff --git a/web/packages/next/package.json b/web/packages/next/package.json index f0bbe8544..f5a325f14 100644 --- a/web/packages/next/package.json +++ b/web/packages/next/package.json @@ -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", diff --git a/web/packages/next/tsconfig.json b/web/packages/next/tsconfig.json index f29c34811..10fe5229c 100644 --- a/web/packages/next/tsconfig.json +++ b/web/packages/next/tsconfig.json @@ -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"] } diff --git a/web/packages/shared/constants/urls.ts b/web/packages/shared/constants/urls.ts index 747e1fa22..89d5faa16 100644 --- a/web/packages/shared/constants/urls.ts +++ b/web/packages/shared/constants/urls.ts @@ -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"; diff --git a/web/packages/shared/electron/service.ts b/web/packages/shared/electron/service.ts index 0484b0746..f926d20b2 100644 --- a/web/packages/shared/electron/service.ts +++ b/web/packages/shared/electron/service.ts @@ -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(self); diff --git a/web/packages/shared/error/index.ts b/web/packages/shared/error/index.ts index 3d3309379..6ed4c7486 100644 --- a/web/packages/shared/error/index.ts +++ b/web/packages/shared/error/index.ts @@ -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", diff --git a/web/packages/shared/platform/index.ts b/web/packages/shared/platform/index.ts deleted file mode 100644 index a7a63dd6f..000000000 --- a/web/packages/shared/platform/index.ts +++ /dev/null @@ -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(); -} diff --git a/web/packages/shared/storage/localForage/index.ts b/web/packages/shared/storage/localForage/index.ts index 9ddf80d99..a3bb4442d 100644 --- a/web/packages/shared/storage/localForage/index.ts +++ b/web/packages/shared/storage/localForage/index.ts @@ -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, diff --git a/web/packages/utils/package.json b/web/packages/utils/package.json index bfe78b5f7..930e3aa44 100644 --- a/web/packages/utils/package.json +++ b/web/packages/utils/package.json @@ -3,7 +3,6 @@ "version": "0.0.0", "private": true, "dependencies": { - "is-electron": "^2.2", "libsodium-wrappers": "0.7.9", "yup": "^1.4" },