From 13712cf8ce76cf0aebf7e3d707b6536ea8f594a5 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Wed, 8 Feb 2023 20:07:12 +0530 Subject: [PATCH] add ML settings components --- .../MLSearchSettings/enableFaceSearch.tsx | 79 ++++++++++++ .../MLSearchSettings/enableMLSearch.tsx | 46 +++++++ .../MLSearchSettings/index.tsx | 118 ++++++++++++++++++ .../MLSearchSettings/manageMLSearch.tsx | 53 ++++++++ src/constants/urls/index.ts | 3 + src/pages/_app.tsx | 11 +- src/utils/strings/englishConstants.tsx | 55 ++++++++ 7 files changed, 364 insertions(+), 1 deletion(-) create mode 100644 src/components/MachineLearning/MLSearchSettings/enableFaceSearch.tsx create mode 100644 src/components/MachineLearning/MLSearchSettings/enableMLSearch.tsx create mode 100644 src/components/MachineLearning/MLSearchSettings/index.tsx create mode 100644 src/components/MachineLearning/MLSearchSettings/manageMLSearch.tsx diff --git a/src/components/MachineLearning/MLSearchSettings/enableFaceSearch.tsx b/src/components/MachineLearning/MLSearchSettings/enableFaceSearch.tsx new file mode 100644 index 000000000..d1d26fc67 --- /dev/null +++ b/src/components/MachineLearning/MLSearchSettings/enableFaceSearch.tsx @@ -0,0 +1,79 @@ +import { + Stack, + Box, + Button, + FormGroup, + Checkbox, + FormControlLabel, +} from '@mui/material'; +import { EnteDrawer } from 'components/EnteDrawer'; +import Titlebar from 'components/Titlebar'; +import { useState } from 'react'; +import constants from 'utils/strings/constants'; + +export default function EnableFaceSearch({ + open, + onClose, + enableFaceSearch, + onRootClose, +}) { + const [acceptTerms, setAcceptTerms] = useState(false); + return ( + + + + + + {constants.ENABLE_FACE_SEARCH_DESCRIPTION()} + + + + setAcceptTerms(e.target.checked) + } + color="accent" + /> + } + label={constants.FACE_SEARCH_CONFIRMATION} + /> + + + + + + + + + ); +} diff --git a/src/components/MachineLearning/MLSearchSettings/enableMLSearch.tsx b/src/components/MachineLearning/MLSearchSettings/enableMLSearch.tsx new file mode 100644 index 000000000..f9127f4d6 --- /dev/null +++ b/src/components/MachineLearning/MLSearchSettings/enableMLSearch.tsx @@ -0,0 +1,46 @@ +import { Stack, Box, Button } from '@mui/material'; +import { EnteDrawer } from 'components/EnteDrawer'; +import Titlebar from 'components/Titlebar'; +import { ML_BLOG_LINK } from 'constants/urls'; +import { openLink } from 'utils/common'; +import constants from 'utils/strings/constants'; + +export default function EnableMLSearch({ + open, + onClose, + enableMlSearch, + onRootClose, +}) { + return ( + + + + + {constants.ML_SEARCH_DESCRIPTION()} + + + + + + + + ); +} diff --git a/src/components/MachineLearning/MLSearchSettings/index.tsx b/src/components/MachineLearning/MLSearchSettings/index.tsx new file mode 100644 index 000000000..a240f7d52 --- /dev/null +++ b/src/components/MachineLearning/MLSearchSettings/index.tsx @@ -0,0 +1,118 @@ +import { Box } from '@mui/material'; +import { AppContext } from 'pages/_app'; +import { useContext, useState } from 'react'; +import { + getFaceSearchStatus, + updateFaceSearchStatus, +} from 'services/userService'; +import { logError } from 'utils/sentry'; +import constants from 'utils/strings/constants'; +import EnableFaceSearch from './enableFaceSearch'; +import EnableMLSearch from './enableMLSearch'; +import ManageMLSearch from './manageMLSearch'; + +const MLSearchSettings = ({ open, onClose, OnRootClose }) => { + const { + updateMlSearchEnabled, + mlSearchEnabled, + setDialogMessage, + somethingWentWrong, + } = useContext(AppContext); + + const [enableFaceSearchView, setEnableFaceSearchView] = useState(false); + + const openEnableFaceSearch = () => { + setEnableFaceSearchView(true); + }; + const closeEnableFaceSearch = () => { + setEnableFaceSearchView(false); + }; + + const enableMlSearch = async () => { + try { + const hasEnabledFaceSearch = await getFaceSearchStatus(); + if (!hasEnabledFaceSearch) { + openEnableFaceSearch(); + } else { + updateMlSearchEnabled(true); + } + } catch (e) { + logError(e, 'Enable ML search failed'); + somethingWentWrong(); + } + }; + + const enableFaceSearch = async () => { + try { + await updateFaceSearchStatus(true); + updateMlSearchEnabled(true); + closeEnableFaceSearch(); + } catch (e) { + logError(e, 'Enable face search failed'); + somethingWentWrong(); + } + }; + + const disableMlSearch = async () => { + try { + await updateMlSearchEnabled(false); + onClose(); + } catch (e) { + logError(e, 'Disable ML search failed'); + somethingWentWrong(); + } + }; + + const disableFaceSearch = async () => { + try { + await updateFaceSearchStatus(false); + await disableMlSearch(); + } catch (e) { + logError(e, 'Disable face search failed'); + somethingWentWrong(); + } + }; + + const confirmDisableFaceSearch = () => { + setDialogMessage({ + title: constants.DISABLE_FACE_SEARCH_TITLE, + content: constants.DISABLE_FACE_SEARCH_DESCRIPTION(), + close: { text: constants.CANCEL }, + proceed: { + variant: 'primary', + text: constants.DISABLE_FACE_SEARCH, + action: disableFaceSearch, + }, + }); + }; + + return ( + + {mlSearchEnabled ? ( + + ) : ( + + )} + + + + ); +}; + +export default MLSearchSettings; diff --git a/src/components/MachineLearning/MLSearchSettings/manageMLSearch.tsx b/src/components/MachineLearning/MLSearchSettings/manageMLSearch.tsx new file mode 100644 index 000000000..aef762178 --- /dev/null +++ b/src/components/MachineLearning/MLSearchSettings/manageMLSearch.tsx @@ -0,0 +1,53 @@ +import { Stack, Box, ButtonProps, TypographyVariant } from '@mui/material'; +import { EnteDrawer } from 'components/EnteDrawer'; +import SidebarButton from 'components/Sidebar/Button'; +import Titlebar from 'components/Titlebar'; +import constants from 'utils/strings/constants'; + +type Iprops = ButtonProps<'button', { typographyVariant?: TypographyVariant }>; + +const ManageOptions = (props: Iprops) => { + return ( + + ); +}; + +export default function ManageMLSearch({ + open, + onClose, + disableMlSearch, + handleDisableFaceSearch, + onRootClose, +}) { + return ( + + + + + + + {constants.DISABLE_BETA} + + + {constants.DISABLE_FACE_SEARCH} + + + + + + ); +} diff --git a/src/constants/urls/index.ts b/src/constants/urls/index.ts index 0d4dff35b..bd4c1a541 100644 --- a/src/constants/urls/index.ts +++ b/src/constants/urls/index.ts @@ -1 +1,4 @@ export const ENTE_WEBSITE_LINK = 'https://ente.io'; + +export const ML_BLOG_LINK = + 'https://on-device-ml.ente-website.pages.dev/blog/desktop-ml-beta'; diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 4796249b6..f5d0c8c8f 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -76,7 +76,7 @@ type AppContextType = { redirectURL: string; setRedirectURL: (url: string) => void; mlSearchEnabled: boolean; - updateMlSearchEnabled: (enabled: boolean) => void; + updateMlSearchEnabled: (enabled: boolean) => Promise; startLoading: () => void; finishLoading: () => void; closeMessageDialog: () => void; @@ -91,6 +91,7 @@ type AppContextType = { isMobile: boolean; theme: THEME_COLOR; setTheme: SetTheme; + somethingWentWrong: () => void; }; export enum FLASH_MESSAGE_TYPE { @@ -328,6 +329,13 @@ export default function App({ Component, err }) { const closeMessageDialog = () => setMessageDialogView(false); + const somethingWentWrong = () => + setDialogMessage({ + title: constants.ERROR, + close: { variant: 'danger' }, + content: constants.UNKNOWN_ERROR, + }); + return ( <> @@ -406,6 +414,7 @@ export default function App({ Component, err }) { setNotificationAttributes, theme, setTheme, + somethingWentWrong, }}> {loading ? ( diff --git a/src/utils/strings/englishConstants.tsx b/src/utils/strings/englishConstants.tsx index 0b9c7a7c8..b610f8117 100644 --- a/src/utils/strings/englishConstants.tsx +++ b/src/utils/strings/englishConstants.tsx @@ -920,6 +920,61 @@ const englishConstants = { ), ADD_X_PHOTOS: (x: number) => `Add ${x} ${x > 1 ? 'photos' : 'photo'}`, CHOSE_THEME: 'Choose theme', + ML_SEARCH: 'ML search (beta)', + ML_SEARCH_DESCRIPTION: () => ( + <> + + This will enable on-device machine learning and face search + which will start analyzing your uploaded photos locally. +
+
+ For the first run after login or enabling this feature, it will + download all images on local device to analyze them. So please + only enable this if you are ok with bandwidth and local + processing of all images in your photo library. +
+
+ If this is the first time you're enabling this, we'll also ask + your permission to process face data. +
+ + ), + ML_MORE_DETAILS: 'More details', + + ENABLE_FACE_SEARCH: 'Enable face search', + ENABLE_FACE_SEARCH_TITLE: 'Enable face search?', + ENABLE_FACE_SEARCH_DESCRIPTION: () => ( + <> + + If you enable face search, ente will extract face geometry from + your photos. This will happen on your device, and any generated + biometric data will be end-to-encrypted. +
+
+ + Please click here for more details about this feature in our + privacy policy + +
+ + ), + DISABLE_BETA: 'Disable beta', + DISABLE_FACE_SEARCH: 'Disable face search', + DISABLE_FACE_SEARCH_TITLE: 'Disable face search?', + DISABLE_FACE_SEARCH_DESCRIPTION: () => ( + + ente will stop processing face geometry, and will also disable ML + search (beta) +
+
+ You can reenable face search again if you wish, so this operation is + safe +
+ ), + ADVANCED: 'Advanced', + FACE_SEARCH_CONFIRMATION: + 'I understand, and wish to allow ente to process face geometry', + LABS: 'Labs', }; export default englishConstants;