diff --git a/apps/mobile/src/assets/images/assets.js b/apps/mobile/src/assets/images/assets.js
index d104b8995..f76df1e9e 100644
--- a/apps/mobile/src/assets/images/assets.js
+++ b/apps/mobile/src/assets/images/assets.js
@@ -1124,6 +1124,8 @@ export const ACCENT_SVG = color => `
`;
-export const WELCOME_SVG = color => `
-
-`;
+export const SUPPORT_SVG = () =>
+ ``;
+
+export const WELCOME_SVG = color =>
+ ``;
diff --git a/apps/mobile/src/components/Auth/changepassword.js b/apps/mobile/src/components/Auth/changepassword.js
index f849c7182..2a86304e6 100644
--- a/apps/mobile/src/components/Auth/changepassword.js
+++ b/apps/mobile/src/components/Auth/changepassword.js
@@ -22,7 +22,7 @@ export const ChangePassword = () => {
const [loading, setLoading] = useState(false);
const changePassword = async () => {
- if (error || !oldPassword || !password) {
+ if (error || !oldPassword.current || !password.current) {
ToastEvent.show({
heading: 'All fields required',
message: 'Fill all the fields and try again.',
@@ -34,7 +34,7 @@ export const ChangePassword = () => {
eSendEvent(eCloseProgressDialog);
setLoading(true);
try {
- await db.user.changePassword(oldPassword, password);
+ await db.user.changePassword(oldPassword.current, password.current);
ToastEvent.show({
heading: `Account password updated`,
type: 'success',
diff --git a/apps/mobile/src/components/Auth/forgotpassword.js b/apps/mobile/src/components/Auth/forgotpassword.js
index d34fba9a7..f1925588b 100644
--- a/apps/mobile/src/components/Auth/forgotpassword.js
+++ b/apps/mobile/src/components/Auth/forgotpassword.js
@@ -24,7 +24,7 @@ export const ForgotPassword = () => {
const [sent, setSent] = useState(false);
const sendRecoveryEmail = async () => {
- if (!email || error) {
+ if (!email.current || error) {
ToastEvent.show({
heading: 'Account email is required.',
type: 'error',
@@ -38,7 +38,7 @@ export const ForgotPassword = () => {
if (lastRecoveryEmailTime && Date.now() - JSON.parse(lastRecoveryEmailTime) < 60000 * 3) {
throw new Error('Please wait before requesting another email');
}
- await db.user.recoverAccount(email.toLowerCase());
+ await db.user.recoverAccount(email.current.toLowerCase());
await MMKV.setItem('lastRecoveryEmailTime', JSON.stringify(Date.now()));
ToastEvent.show({
heading: `Check your email to reset password`,
diff --git a/apps/mobile/src/components/Auth/login.js b/apps/mobile/src/components/Auth/login.js
index 2d42e3a38..66013081f 100644
--- a/apps/mobile/src/components/Auth/login.js
+++ b/apps/mobile/src/components/Auth/login.js
@@ -1,5 +1,5 @@
import React, { useEffect, useRef, useState } from 'react';
-import { LayoutAnimation, Platform, View } from 'react-native';
+import { Platform, View } from 'react-native';
import { SheetManager } from 'react-native-actions-sheet';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { useTracked } from '../../provider';
@@ -31,9 +31,7 @@ export const Login = ({ changeMode }) => {
const emailInputRef = useRef();
const passwordInputRef = useRef();
const password = useRef();
-
const [focused, setFocused] = useState(false);
-
const [error, setError] = useState(false);
const [loading, setLoading] = useState(false);
const insets = useSafeAreaInsets();
diff --git a/apps/mobile/src/components/Auth/signup.js b/apps/mobile/src/components/Auth/signup.js
index dd27d92da..d2658c592 100644
--- a/apps/mobile/src/components/Auth/signup.js
+++ b/apps/mobile/src/components/Auth/signup.js
@@ -8,7 +8,8 @@ import { eSendEvent, ToastEvent } from '../../services/EventManager';
import { clearMessage, setEmailVerifyMessage } from '../../services/Message';
import PremiumService from '../../services/PremiumService';
import { db } from '../../utils/database';
-import { eCloseLoginDialog, eOpenResultDialog } from '../../utils/Events';
+import { eCloseLoginDialog } from '../../utils/Events';
+import { openLinkInBrowser } from '../../utils/functions';
import { SIZE } from '../../utils/SizeUtils';
import { sleep } from '../../utils/TimeUtils';
import umami from '../../utils/umami';
@@ -58,7 +59,7 @@ export const Signup = ({ changeMode, welcome, trial }) => {
if (!validateInfo() || error) return;
setLoading(true);
try {
- await db.user.signup(email.toLowerCase(), password);
+ await db.user.signup(email.current.toLowerCase(), password.current);
let user = await db.user.getUser();
setUser(user);
setLastSynced(await db.lastSynced());
@@ -214,7 +215,36 @@ export const Signup = ({ changeMode, welcome, trial }) => {
marginBottom={5}
/>
- By signing up, you agree to our terms of service and privacy policy.
+ By signing up, you agree to our{' '}
+ {
+ openLinkInBrowser('https://notesnook.com/tos', colors)
+ .catch(e => {})
+ .then(r => {});
+ }}
+ style={{
+ textDecorationLine: 'underline'
+ }}
+ color={colors.accent}
+ >
+ terms of service{' '}
+
+ and{' '}
+ {
+ openLinkInBrowser('https://notesnook.com/privacy', colors)
+ .catch(e => {})
+ .then(r => {});
+ }}
+ style={{
+ textDecorationLine: 'underline'
+ }}
+ color={colors.accent}
+ >
+ privacy policy.
+
{
);
};
-export const SvgToPngView = ({ width, height, src, color, img }) => {
+export const SvgToPngView = ({ width = 250, height = 250, src }) => {
const [error, setError] = useState(false);
return (
diff --git a/apps/mobile/src/components/Menu/MenuListItem.js b/apps/mobile/src/components/Menu/MenuListItem.js
index 812475d16..9f82ea375 100644
--- a/apps/mobile/src/components/Menu/MenuListItem.js
+++ b/apps/mobile/src/components/Menu/MenuListItem.js
@@ -1,16 +1,15 @@
import React, { useEffect, useState } from 'react';
-import { InteractionManager, View } from 'react-native';
+import { View } from 'react-native';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
+import ToggleSwitch from 'toggle-switch-react-native';
import { useTracked } from '../../provider';
import { eSubscribeEvent, eUnSubscribeEvent } from '../../services/EventManager';
import Navigation from '../../services/Navigation';
-import { getElevation } from '../../utils';
import { normalize, SIZE } from '../../utils/SizeUtils';
import { Button } from '../Button';
import { PressableButton } from '../PressableButton';
import Heading from '../Typography/Heading';
import Paragraph from '../Typography/Paragraph';
-import ToggleSwitch from 'toggle-switch-react-native';
export const MenuListItem = React.memo(
({ item, index, noTextMode, testID, rightBtn }) => {
diff --git a/apps/mobile/src/components/Premium/component.js b/apps/mobile/src/components/Premium/component.js
index d9acb7e86..f409727fe 100644
--- a/apps/mobile/src/components/Premium/component.js
+++ b/apps/mobile/src/components/Premium/component.js
@@ -7,8 +7,15 @@ import { DDS } from '../../services/DeviceDetection';
import { eSendEvent, presentSheet } from '../../services/EventManager';
import PremiumService from '../../services/PremiumService';
import { getElevation } from '../../utils';
-import { eOpenLoginDialog, eOpenResultDialog } from '../../utils/Events';
+import { db } from '../../utils/database';
+import {
+ eClosePremiumDialog,
+ eCloseProgressDialog,
+ eOpenLoginDialog,
+ eOpenResultDialog
+} from '../../utils/Events';
import { SIZE } from '../../utils/SizeUtils';
+import { sleep } from '../../utils/TimeUtils';
import umami from '../../utils/umami';
import { ActionIcon } from '../ActionIcon';
import { AuthMode } from '../Auth';
@@ -19,6 +26,7 @@ import Seperator from '../Seperator';
import { Toast } from '../Toast';
import Heading from '../Typography/Heading';
import Paragraph from '../Typography/Paragraph';
+import { Walkthrough } from '../Walkthrough';
import { features } from './features';
import { Group } from './group';
import { PricingPlans } from './pricing-plans';
@@ -146,8 +154,14 @@ export const Component = ({ close, promo, getRef }) => {
{userCanRequestTrial ? (
);
};
-Walkthrough.present = async (id: 'notebooks') => {
- let walkthroughState = await MMKV.getItem('walkthroughState');
- if (walkthroughState) {
- walkthroughState = JSON.parse(walkthroughState);
- } else {
+Walkthrough.present = async (
+ id: 'notebooks' | 'trialstarted' | 'emailconfirmed' | 'prouser',
+ canSkip = true,
+ nopersist?: boolean
+) => {
+ if (!nopersist) {
+ let walkthroughState = await MMKV.getItem('walkthroughState');
+ if (walkthroughState) {
+ walkthroughState = JSON.parse(walkthroughState);
+ } else {
+ //@ts-ignore
+ walkthroughState = {};
+ }
//@ts-ignore
- walkthroughState = {};
+ if (walkthroughState[id]) return;
+ //@ts-ignore
+ walkthroughState[id] = true;
+ MMKV.setItem('walkthroughState', JSON.stringify(walkthroughState));
}
- //@ts-ignore
- if (walkthroughState[id]) return;
- //@ts-ignore
- walkthroughState[id] = true;
- MMKV.setItem('walkthroughState', JSON.stringify(walkthroughState));
+
//@ts-ignore
let walkthrough = walkthroughs[id];
if (!walkthrough) return;
presentSheet({
- component: ,
+ component: ,
disableClosing: true
});
};
diff --git a/apps/mobile/src/components/Walkthrough/walkthroughs.tsx b/apps/mobile/src/components/Walkthrough/walkthroughs.tsx
index 877674789..3e2cca846 100644
--- a/apps/mobile/src/components/Walkthrough/walkthroughs.tsx
+++ b/apps/mobile/src/components/Walkthrough/walkthroughs.tsx
@@ -1,25 +1,34 @@
import React from 'react';
-import { View } from 'react-native';
+import { Linking, View } from 'react-native';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
+import { COMMUNITY_SVG, LAUNCH_ROCKET, SUPPORT_SVG, WELCOME_SVG } from '../../assets/images/assets';
import { TrackedState, useTracked } from '../../provider';
import { eSendEvent } from '../../services/EventManager';
import { getElevation } from '../../utils';
import { eOpenAddNotebookDialog } from '../../utils/Events';
import { SIZE } from '../../utils/SizeUtils';
import useRotator from '../../utils/use-rotator';
+import { AccentColorPicker } from '../../views/Settings/appearance';
+import { Button } from '../Button';
+import { SvgToPngView } from '../ListPlaceholders';
import { PinItem } from '../Menu/TagsSection';
+import Seperator from '../Seperator';
import Heading from '../Typography/Heading';
import Paragraph from '../Typography/Paragraph';
export type TStep = {
- text: string;
+ text?: string;
walkthroughItem: (colors: TrackedState['colors']) => React.ReactNode;
- title: string;
+ title?: string;
button?: {
type: 'next' | 'done';
title: string;
action?: () => void;
};
+ actionButton?: {
+ text: string;
+ action: () => void;
+ };
};
const NotebookWelcome = () => {
@@ -237,4 +246,170 @@ const notebooks: { id: string; steps: TStep[] } = {
]
};
-export default { notebooks };
+const ChooseTheme = () => {
+ const [state] = useTracked();
+ const { colors } = state;
+
+ return (
+
+
+
+ );
+};
+
+const trialstarted: { id: string; steps: TStep[] } = {
+ id: 'trialstarted',
+ steps: [
+ {
+ title: 'Your trial is activated',
+ text: 'You can use all permium features for free for the next 14 days',
+ walkthroughItem: colors => ,
+ button: {
+ type: 'next',
+ title: 'Next'
+ }
+ },
+
+ {
+ title: 'Make yourself at home',
+ text: 'Pick a theme of your choice',
+ walkthroughItem: () => ,
+ button: {
+ type: 'next',
+ title: 'Next'
+ }
+ },
+ {
+ title: 'Join the cause',
+ text: 'Meet other privacy-minded people and talk to us directly about your concerns, issues and suggestions.',
+ walkthroughItem: colors => ,
+ button: {
+ type: 'done',
+ title: 'Continue'
+ },
+ actionButton: {
+ text: 'Join Discord Community',
+ action: () => {
+ Linking.openURL('https://discord.gg/zQBK97EE22').catch(console.log);
+ }
+ }
+ }
+ ]
+};
+
+const emailconfirmed: { id: string; steps: TStep[] } = {
+ id: 'emailconfirmed',
+ steps: [
+ {
+ title: 'Email confirmed',
+ text: 'Your email was confirmed successfully. Thank you for choosing end-to-end encrypted note taking.',
+ walkthroughItem: colors => ,
+ button: {
+ type: 'done',
+ title: 'Continue'
+ }
+ }
+ ]
+};
+
+const Support = () => {
+ const [state] = useTracked();
+ const { colors } = state;
+
+ return (
+
+
+ Get Priority Support
+
+ You can reach out to us via multiple channels if you face an issue or want to just talk.
+
+
+
+ {
+ Linking.openURL('https://discord.gg/zQBK97EE22').catch(console.log);
+ }}
+ icon="discord"
+ type="grayBg"
+ title="Join our community on Discord"
+ />
+
+ {
+ Linking.openURL('https://t.me/notesnook').catch(console.log);
+ }}
+ icon="telegram"
+ type="grayBg"
+ title="Join our Telegram group"
+ />
+
+
+
+ );
+};
+
+const prouser: { id: string; steps: TStep[] } = {
+ id: 'prouser',
+ steps: [
+ {
+ title: 'Welcome to Notesnook Pro',
+ text: 'Thank you for reaffirming our idea that privacy comes first',
+ walkthroughItem: colors => ,
+ button: {
+ type: 'next',
+ title: 'Next'
+ }
+ },
+ {
+ walkthroughItem: () => ,
+ button: {
+ type: 'done',
+ title: 'Continue'
+ }
+ }
+ ]
+};
+
+export default { notebooks, trialstarted, emailconfirmed, prouser };
diff --git a/apps/mobile/src/navigation/RootView.js b/apps/mobile/src/navigation/RootView.js
index 54a6e17ee..4077e2cdf 100644
--- a/apps/mobile/src/navigation/RootView.js
+++ b/apps/mobile/src/navigation/RootView.js
@@ -23,11 +23,11 @@ import {
} from '../utils/Events';
import { editorRef, tabBarRef } from '../utils/Refs';
import { sleep } from '../utils/TimeUtils';
+import useTooltip, { hideAllTooltips } from '../utils/use-tooltip';
import { EditorWrapper } from '../views/Editor/EditorWrapper';
import { checkStatus, EditorWebView, getNote } from '../views/Editor/Functions';
import tiny from '../views/Editor/tiny/tiny';
import { NavigatorStack } from './NavigatorStack';
-import useTooltip, { hideAllTooltips } from '../utils/use-tooltip';
let layoutTimer = null;
diff --git a/apps/mobile/src/services/Message.js b/apps/mobile/src/services/Message.js
index 978060a2e..791892f2b 100644
--- a/apps/mobile/src/services/Message.js
+++ b/apps/mobile/src/services/Message.js
@@ -70,13 +70,13 @@ export function setLoginMessage() {
const emailMessage = {
visible: true,
message: 'Email not confirmed',
- actionText: 'Confirm now to get 7 more days of free trial',
+ actionText: 'Please confrim your email to sync notes.',
onPress: () => {
PremiumService.showVerifyEmailDialog();
},
data: {},
icon: 'email',
- type: 'normal'
+ type: 'error'
};
export function setEmailVerifyMessage() {
diff --git a/apps/mobile/src/utils/useAppEvents.js b/apps/mobile/src/utils/useAppEvents.js
index 81468ed0c..1ea9a2659 100644
--- a/apps/mobile/src/utils/useAppEvents.js
+++ b/apps/mobile/src/utils/useAppEvents.js
@@ -15,6 +15,7 @@ import * as RNIap from 'react-native-iap';
import { enabled } from 'react-native-privacy-snapshot';
import { doInBackground, editing } from '.';
import { ProFeatures } from '../components/ResultDialog/pro-features';
+import { Walkthrough } from '../components/Walkthrough';
import {
clearAllStores,
initialize,
@@ -202,23 +203,7 @@ export const useAppEvents = () => {
if (!user) return;
MMKV.setItem('isUserEmailConfirmed', 'yes');
await PremiumService.setPremiumStatus();
- let message = 'You have been rewarded 7 more days of free trial. Enjoy using Notesnook!';
- presentSheet({
- title: 'Email confirmed!',
- paragraph: message,
- component: (
-
-
-
- )
- });
-
+ Walkthrough.present('emailconfirmed', false, true);
if (user?.isEmailConfirmed) {
clearMessage();
}
@@ -240,15 +225,7 @@ export const useAppEvents = () => {
const onAccountStatusChange = async userStatus => {
if (!PremiumService.get() && userStatus.type === 5) {
PremiumService.subscriptions.clear();
- presentSheet({
- title: 'Notesnook Pro',
- paragraph: `Your Notesnook Pro subscription has been successfully activated.`,
- action: async () => {
- eSendEvent(eCloseProgressDialog);
- },
- icon: 'check',
- actionText: 'Continue'
- });
+ Walkthrough.present('prouser', false, true);
}
await PremiumService.setPremiumStatus();
};
diff --git a/apps/mobile/src/views/Settings/appearance.js b/apps/mobile/src/views/Settings/appearance.js
index 68f4d634b..ced8e66c9 100644
--- a/apps/mobile/src/views/Settings/appearance.js
+++ b/apps/mobile/src/views/Settings/appearance.js
@@ -1,5 +1,6 @@
import React, { useRef, useState } from 'react';
-import { Appearance, ScrollView, TouchableOpacity, View } from 'react-native';
+import { Appearance, TouchableOpacity, View } from 'react-native';
+import { ScrollView } from 'react-native-gesture-handler';
import Menu, { MenuItem } from 'react-native-reanimated-material-menu';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import ToggleSwitch from 'toggle-switch-react-native';
@@ -111,82 +112,8 @@ const SettingsAppearanceSection = () => {
Change the accent color of the app.
- {
- tabBarRef.current?.setScrollEnabled(false);
- }}
- onMomentumScrollEnd={() => {
- tabBarRef.current?.setScrollEnabled(true);
- }}
- style={{
- borderRadius: 5,
- padding: 5,
- marginTop: 10,
- marginBottom: pv + 5,
- width: '100%',
- paddingHorizontal: 12
- }}
- nestedScrollEnabled
- contentContainerStyle={{
- alignSelf: 'center',
- flexDirection: 'row',
- flexWrap: 'wrap'
- }}
- >
- {[
- '#FF5722',
- '#FFA000',
- '#1B5E20',
- '#008837',
- '#757575',
- '#0560ff',
- '#009688',
- '#2196F3',
- '#880E4F',
- '#9C27B0',
- '#FF1744',
- '#B71C1C'
- ].map(item => (
- {
- await PremiumService.verify(async () => {
- changeAccentColor(item);
- await MMKV.setStringAsync('accentColor', item);
- });
- }}
- customStyle={{
- flexDirection: 'row',
- justifyContent: 'center',
- alignItems: 'center',
- marginRight: 10,
- marginVertical: 5,
- width: DDS.isLargeTablet() ? 40 : 50,
- height: DDS.isLargeTablet() ? 40 : 50,
- borderRadius: 100
- }}
- >
- {colors.accent === item ? (
-
- ) : null}
-
- ))}
-
-
+
+
{
);
};
+export const AccentColorPicker = ({ settings = true }) => {
+ const [state, dispatch] = useTracked();
+ const { colors } = state;
+
+ function changeColorScheme(colors = COLOR_SCHEME, accent = ACCENT) {
+ let newColors = setColorScheme(colors, accent);
+ dispatch({ type: Actions.THEME, colors: newColors });
+ }
+
+ function changeAccentColor(accentColor) {
+ ACCENT.color = accentColor;
+ ACCENT.shade = accentColor + '12';
+ changeColorScheme();
+ }
+
+ return (
+ {
+ if (!settings) return;
+ tabBarRef.current?.setScrollEnabled(false);
+ }}
+ onMomentumScrollEnd={() => {
+ if (!settings) return;
+ tabBarRef.current?.setScrollEnabled(true);
+ }}
+ style={{
+ borderRadius: 5,
+ padding: 5,
+ marginTop: 10,
+ marginBottom: pv + 5,
+ width: '100%',
+ paddingHorizontal: 12,
+ maxWidth: settings ? null : '100%'
+ }}
+ scrollEnabled={true}
+ nestedScrollEnabled={true}
+ contentContainerStyle={{
+ alignSelf: 'center',
+ flexDirection: 'row',
+ flexWrap: 'wrap'
+ }}
+ >
+ {[
+ '#FF5722',
+ '#FFA000',
+ '#1B5E20',
+ '#008837',
+ '#757575',
+ '#0560ff',
+ '#009688',
+ '#2196F3',
+ '#880E4F',
+ '#9C27B0',
+ '#FF1744',
+ '#B71C1C'
+ ].map(item => (
+ {
+ await PremiumService.verify(async () => {
+ changeAccentColor(item);
+ await MMKV.setStringAsync('accentColor', item);
+ });
+ }}
+ customStyle={{
+ flexDirection: 'row',
+ justifyContent: 'center',
+ alignItems: 'center',
+ marginRight: 10,
+ marginVertical: 5,
+ width: DDS.isLargeTablet() ? 40 : 50,
+ height: DDS.isLargeTablet() ? 40 : 50,
+ borderRadius: 100
+ }}
+ >
+ {colors.accent === item ? (
+
+ ) : null}
+
+ ))}
+
+
+ );
+};
+
export default SettingsAppearanceSection;
diff --git a/apps/mobile/src/views/Settings/index.js b/apps/mobile/src/views/Settings/index.js
index e57926505..05414d2e5 100644
--- a/apps/mobile/src/views/Settings/index.js
+++ b/apps/mobile/src/views/Settings/index.js
@@ -124,11 +124,17 @@ export const Settings = ({ navigation }) => {
component:
});
},
- desc: `Facing an issue? Click here to create a bug report`
+ desc: `Faced an issue or have a suggestion? Click here to create a bug report`
+ },
+ {
+ name: 'Join our Telegram group',
+ desc: "We are on telegram, let's talk",
+ func: () => {
+ Linking.openURL('https://t.me/notesnook').catch(console.log);
+ }
},
{
name: 'Join our Discord community',
-
func: async () => {
presentSheet({
title: 'Join our Discord Community',
@@ -144,7 +150,7 @@ export const Settings = ({ navigation }) => {
icon: 'discord',
action: async () => {
try {
- await openLinkInBrowser('https://discord.gg/zQBK97EE22', colors);
+ Linking.openURL('https://discord.gg/zQBK97EE22').catch(console.log);
} catch (e) {}
},
actionText: 'Join Now'