diff --git a/apps/mobile/app/components/image-preview/index.tsx b/apps/mobile/app/components/image-preview/index.tsx index 886ef04b6..f2d070f51 100644 --- a/apps/mobile/app/components/image-preview/index.tsx +++ b/apps/mobile/app/components/image-preview/index.tsx @@ -52,7 +52,7 @@ const ImagePreview = () => { setLoading(true); setTimeout(async () => { let hash = image.hash; - if (!hash && dataurl.toObject(image.src)) { + if (!hash && image.src && dataurl.toObject(image.src)) { const data = dataurl.toObject(image.src); if (!data) return; hash = await Sodium.hashFile({ diff --git a/apps/mobile/app/components/side-menu/user-status.js b/apps/mobile/app/components/side-menu/user-status.js index 6fe7c5d9f..b93aca914 100644 --- a/apps/mobile/app/components/side-menu/user-status.js +++ b/apps/mobile/app/components/side-menu/user-status.js @@ -46,6 +46,8 @@ export const UserStatus = () => { const { isInternetReachable } = useNetInfo(); const isOffline = !isInternetReachable; const { progress } = useSyncProgress(); + const userProfile = useUserStore((state) => state.profile); + return ( { alignItems: "center" }} > - {user ? ( + {userProfile?.profilePicture ? ( @@ -117,7 +118,9 @@ export const UserStatus = () => { ? `Syncing your notes${ progress ? ` (${progress.current})` : "" }` - : "Ammar Ahmed"} + : !userProfile?.fullName + ? "Tap to sync" + : userProfile.fullName} { const isUserEmailConfirmed = SettingsService.get().userEmailConfirmed; setUser(user); + + useUserStore.setState({ + profile: await db.user.getProfile() + }); + if (SettingsService.get().sessionExpired) { syncedOnLaunch.current = true; return; diff --git a/apps/mobile/app/screens/settings/settings-data.tsx b/apps/mobile/app/screens/settings/settings-data.tsx index c1652822e..141ebc7f9 100644 --- a/apps/mobile/app/screens/settings/settings-data.tsx +++ b/apps/mobile/app/screens/settings/settings-data.tsx @@ -70,7 +70,6 @@ import { useDragState } from "./editor/state"; import { verifyUser, verifyUserWithApplock } from "./functions"; import { SettingSection } from "./types"; import { getTimeLeft } from "./user-section"; -import ImagePicker from "react-native-image-crop-picker"; type User = any; @@ -135,49 +134,53 @@ export const settingsGroups: SettingSection[] = [ description: "Manage account", sections: [ { - id: "change-profile-picture", - name: "Change profile picture", - description: "Change your profile picture", - icon: "account-outline", + id: "remove-profile-picture", + name: "Remove profile picture", + description: "Remove your picture from profile", + useHook: () => + useUserStore((state) => state.profile?.profilePicture), + hidden: () => !useUserStore.getState().profile?.profilePicture, modifer: () => { - const theme = - useThemeStore.getState().colorScheme === "dark" - ? useThemeStore.getState().darkTheme - : useThemeStore.getState().lightTheme; - ImagePicker.openPicker({ - compressImageMaxWidth: 512, - compressImageMaxHeight: 512, - compressImageQuality: 0.8, - avoidEmptySpaceAroundImage: true, - cropping: true, - cropperCircleOverlay: true, - mediaType: "photo", - forceJpg: true, - includeBase64: true, - writeTempFile: false, - cropperToolbarColor: theme.scopes.base.primary.background, - cropperToolbarTitle: "Edit profile picture", - cropperActiveWidgetColor: theme.scopes.base.primary.accent, - cropperToolbarWidgetColor: theme.scopes.base.primary.icon - }).then((image) => { - console.log(image); + presentDialog({ + title: "Remove profile picture", + paragraph: + "Are you sure you want to remove your profile picture?", + positiveText: "Remove", + positivePress: async () => { + db.user + .setProfile({ + profilePicture: undefined + }) + .then(async () => { + useUserStore.setState({ + profile: await db.user.getProfile() + }); + }); + } }); } }, { - id: "change-name", - name: "Change name", - description: "Change your name", + id: "remove-name", + name: "Remove full name", + description: "Remove your name from profile", + useHook: () => useUserStore((state) => state.profile?.fullName), + hidden: () => !useUserStore.getState().profile?.fullName, modifer: () => { presentDialog({ - title: "Change name", - paragraph: "Change your name", - positiveText: "Save", - input: true, - inputPlaceholder: "Enter new name", - defaultValue: "Ammar Ahmed", - positivePress(value) { - console.log(value); + title: "Remove name", + paragraph: "Are you sure you want to remove your name?", + positiveText: "Remove", + positivePress: async () => { + db.user + .setProfile({ + fullName: undefined + }) + .then(async () => { + useUserStore.setState({ + profile: await db.user.getProfile() + }); + }); } }); } diff --git a/apps/mobile/app/screens/settings/user-section.js b/apps/mobile/app/screens/settings/user-section.js index 3d90958ce..afcea6661 100644 --- a/apps/mobile/app/screens/settings/user-section.js +++ b/apps/mobile/app/screens/settings/user-section.js @@ -17,22 +17,24 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ +import { useThemeColors } from "@notesnook/theme"; +import { useNetInfo } from "@react-native-community/netinfo"; import dayjs from "dayjs"; import React from "react"; -import { Image, View } from "react-native"; +import { Image, TouchableOpacity, View } from "react-native"; +import ImagePicker from "react-native-image-crop-picker"; import Icon from "react-native-vector-icons/MaterialCommunityIcons"; +import { db } from "../../common/database"; +import { presentDialog } from "../../components/dialog/functions"; +import AppIcon from "../../components/ui/AppIcon"; import { TimeSince } from "../../components/ui/time-since"; import Heading from "../../components/ui/typography/heading"; import Paragraph from "../../components/ui/typography/paragraph"; -import { useThemeColors } from "@notesnook/theme"; +import { useThemeStore } from "../../stores/use-theme-store"; import { SyncStatus, useUserStore } from "../../stores/use-user-store"; import { SUBSCRIPTION_STATUS_STRINGS } from "../../utils/constants"; import { SIZE } from "../../utils/size"; import { SectionItem } from "./section-item"; -import { useNetInfo } from "@react-native-community/netinfo"; -import { IconButton } from "../../components/ui/icon-button"; - -const PROFILE_PIC_URL = `https://picsum.photos/id/177/367/267`; export const getTimeLeft = (t2) => { let daysRemaining = dayjs(t2).diff(dayjs(), "days"); @@ -45,28 +47,56 @@ export const getTimeLeft = (t2) => { const ProfilePicPlaceholder = () => { const { colors } = useThemeColors(); return ( - { + const theme = + useThemeStore.getState().colorScheme === "dark" + ? useThemeStore.getState().darkTheme + : useThemeStore.getState().lightTheme; + + ImagePicker.openPicker({ + compressImageMaxWidth: 256, + compressImageMaxHeight: 256, + compressImageQuality: 0.8, + avoidEmptySpaceAroundImage: true, + cropping: true, + cropperCircleOverlay: true, + mediaType: "photo", + forceJpg: true, + includeBase64: true, + writeTempFile: false, + cropperToolbarColor: theme.scopes.base.primary.background, + cropperToolbarTitle: "Edit profile picture", + cropperActiveWidgetColor: theme.scopes.base.primary.accent, + cropperToolbarWidgetColor: theme.scopes.base.primary.icon + }).then(async (image) => { + if (!image.data) return; + await db.user.setProfile({ + profilePicture: "data:image/jpeg;base64," + image.data + }); + useUserStore.setState({ + profile: await db.user.getProfile() + }); + }); + }} > - + - + ); }; @@ -77,6 +107,7 @@ const SettingsUserSection = ({ item }) => { const lastSyncStatus = useUserStore((state) => state.lastSyncStatus); const { isInternetReachable } = useNetInfo(); const isOffline = !isInternetReachable; + const userProfile = useUserStore((state) => state.profile); return ( <> @@ -98,8 +129,6 @@ const SettingsUserSection = ({ item }) => { width: "100%" }} > - {/* */} - { borderColor: colors.primary.accent }} > - + {userProfile?.profilePicture ? ( + + ) : ( + + )} { ]?.toUpperCase() || "Basic"} - - Ammar Ahmed + { + presentDialog({ + title: "Set name", + paragraph: "Set your full name", + positiveText: "Save", + input: true, + inputPlaceholder: "Enter your full name", + defaultValue: userProfile?.fullName, + positivePress: async (value) => { + db.user + .setProfile({ + fullName: value + }) + .then(async () => { + useUserStore.setState({ + profile: await db.user.getProfile() + }); + }); + } + }); + }} + color={colors.primary.heading} + size={SIZE.lg} + > + {userProfile?.fullName + ? userProfile.fullName + " " + : "Set your name "} + @@ -149,7 +208,8 @@ const SettingsUserSection = ({ item }) => { { - - diff --git a/apps/mobile/app/stores/use-user-store.ts b/apps/mobile/app/stores/use-user-store.ts index bfd1bae85..250fa9213 100644 --- a/apps/mobile/app/stores/use-user-store.ts +++ b/apps/mobile/app/stores/use-user-store.ts @@ -17,7 +17,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -import { User } from "@notesnook/core/dist/api/user-manager"; +import { Profile } from "@notesnook/core"; +import { User } from "@notesnook/core"; import create, { State } from "zustand"; export enum SyncStatus { @@ -40,6 +41,7 @@ export interface UserStore extends State { lockApp: (verified: boolean) => void; disableAppLockRequests: boolean; setDisableAppLockRequests: (shouldBlockVerifyUser: boolean) => void; + profile?: Partial; } export const useUserStore = create((set) => ({ @@ -62,5 +64,6 @@ export const useUserStore = create((set) => ({ setTimeout(() => { set({ disableAppLockRequests: false }); }, 1000); - } + }, + profile: undefined }));