mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-16 19:57:52 +01:00
add walkthroughs for pro/trial users
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -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',
|
||||
|
||||
@@ -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`,
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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}
|
||||
/>
|
||||
<Paragraph size={SIZE.xs} color={colors.icon}>
|
||||
By signing up, you agree to our terms of service and privacy policy.
|
||||
By signing up, you agree to our{' '}
|
||||
<Paragraph
|
||||
size={SIZE.xs}
|
||||
onPress={() => {
|
||||
openLinkInBrowser('https://notesnook.com/tos', colors)
|
||||
.catch(e => {})
|
||||
.then(r => {});
|
||||
}}
|
||||
style={{
|
||||
textDecorationLine: 'underline'
|
||||
}}
|
||||
color={colors.accent}
|
||||
>
|
||||
terms of service{' '}
|
||||
</Paragraph>
|
||||
and{' '}
|
||||
<Paragraph
|
||||
size={SIZE.xs}
|
||||
onPress={() => {
|
||||
openLinkInBrowser('https://notesnook.com/privacy', colors)
|
||||
.catch(e => {})
|
||||
.then(r => {});
|
||||
}}
|
||||
style={{
|
||||
textDecorationLine: 'underline'
|
||||
}}
|
||||
color={colors.accent}
|
||||
>
|
||||
privacy policy.
|
||||
</Paragraph>
|
||||
</Paragraph>
|
||||
|
||||
<View
|
||||
|
||||
@@ -53,7 +53,7 @@ export const Placeholder = ({ type, w, h, color }) => {
|
||||
);
|
||||
};
|
||||
|
||||
export const SvgToPngView = ({ width, height, src, color, img }) => {
|
||||
export const SvgToPngView = ({ width = 250, height = 250, src }) => {
|
||||
const [error, setError] = useState(false);
|
||||
|
||||
return (
|
||||
|
||||
@@ -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 }) => {
|
||||
|
||||
@@ -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 ? (
|
||||
<Button
|
||||
key="calltoaction"
|
||||
onPress={() => {
|
||||
eSendEvent(eOpenResultDialog);
|
||||
onPress={async () => {
|
||||
try {
|
||||
await db.user.activateTrial();
|
||||
eSendEvent(eClosePremiumDialog);
|
||||
eSendEvent(eCloseProgressDialog);
|
||||
await sleep(300);
|
||||
Walkthrough.present('trialstarted', false, true);
|
||||
} catch (e) {}
|
||||
}}
|
||||
title="Try free for 14 days"
|
||||
type="accent"
|
||||
|
||||
@@ -22,6 +22,7 @@ import BaseDialog from '../Dialog/base-dialog';
|
||||
import { presentDialog } from '../Dialog/functions';
|
||||
import Heading from '../Typography/Heading';
|
||||
import Paragraph from '../Typography/Paragraph';
|
||||
import { Walkthrough } from '../Walkthrough';
|
||||
import { PricingItem } from './pricing-item';
|
||||
|
||||
const promoCyclesMonthly = {
|
||||
@@ -195,12 +196,14 @@ export const PricingPlans = ({
|
||||
/>
|
||||
|
||||
<Button
|
||||
onPress={() => {
|
||||
eSendEvent(eClosePremiumDialog);
|
||||
eSendEvent(eCloseProgressDialog);
|
||||
setTimeout(() => {
|
||||
eSendEvent(eOpenLoginDialog, 1);
|
||||
}, 400);
|
||||
onPress={async () => {
|
||||
try {
|
||||
await db.user.activateTrial();
|
||||
eSendEvent(eClosePremiumDialog);
|
||||
eSendEvent(eCloseProgressDialog);
|
||||
await sleep(300);
|
||||
Walkthrough.present('trialstarted', false, true);
|
||||
} catch (e) {}
|
||||
}}
|
||||
title={`Try free for 14 days`}
|
||||
type="grayAccent"
|
||||
|
||||
@@ -11,7 +11,7 @@ import Heading from '../Typography/Heading';
|
||||
import Paragraph from '../Typography/Paragraph';
|
||||
import walkthroughs, { TStep } from './walkthroughs';
|
||||
|
||||
export const Walkthrough = ({ steps }: { steps: TStep[] }) => {
|
||||
export const Walkthrough = ({ steps, canSkip = true }: { steps: TStep[]; canSkip: boolean }) => {
|
||||
const [state] = useTracked();
|
||||
const colors = state.colors;
|
||||
const [step, setStep] = useState<TStep>(steps && steps[0]);
|
||||
@@ -33,17 +33,36 @@ export const Walkthrough = ({ steps }: { steps: TStep[] }) => {
|
||||
>
|
||||
{step.walkthroughItem(colors)}
|
||||
|
||||
<Heading>{step.title}</Heading>
|
||||
<Paragraph
|
||||
style={{
|
||||
textAlign: 'center',
|
||||
alignSelf: 'center',
|
||||
maxWidth: '80%'
|
||||
}}
|
||||
size={SIZE.md}
|
||||
>
|
||||
{step.text}
|
||||
</Paragraph>
|
||||
{step.title ? <Heading>{step.title}</Heading> : null}
|
||||
{step.text ? (
|
||||
<Paragraph
|
||||
style={{
|
||||
textAlign: 'center',
|
||||
alignSelf: 'center',
|
||||
maxWidth: '80%'
|
||||
}}
|
||||
size={SIZE.md}
|
||||
>
|
||||
{step.text}
|
||||
</Paragraph>
|
||||
) : null}
|
||||
{step.actionButton && (
|
||||
<Button
|
||||
//@ts-ignore
|
||||
style={{
|
||||
height: 30,
|
||||
marginTop: 10
|
||||
}}
|
||||
textStyle={{
|
||||
textDecorationLine: 'underline'
|
||||
}}
|
||||
onPress={async () => {
|
||||
step.actionButton?.action();
|
||||
}}
|
||||
type="transparent"
|
||||
title={step.actionButton.text}
|
||||
/>
|
||||
)}
|
||||
|
||||
<Button
|
||||
//@ts-ignore
|
||||
@@ -69,43 +88,52 @@ export const Walkthrough = ({ steps }: { steps: TStep[] }) => {
|
||||
type="accent"
|
||||
/>
|
||||
|
||||
<Button
|
||||
//@ts-ignore
|
||||
style={{
|
||||
height: 30,
|
||||
marginTop: 10
|
||||
}}
|
||||
textStyle={{
|
||||
textDecorationLine: 'underline'
|
||||
}}
|
||||
onPress={async () => {
|
||||
eSendEvent(eCloseProgressDialog);
|
||||
}}
|
||||
type="gray"
|
||||
title="Skip introduction"
|
||||
/>
|
||||
{canSkip ? (
|
||||
<Button
|
||||
//@ts-ignore
|
||||
style={{
|
||||
height: 30,
|
||||
marginTop: 10
|
||||
}}
|
||||
textStyle={{
|
||||
textDecorationLine: 'underline'
|
||||
}}
|
||||
onPress={async () => {
|
||||
eSendEvent(eCloseProgressDialog);
|
||||
}}
|
||||
type="gray"
|
||||
title="Skip introduction"
|
||||
/>
|
||||
) : null}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
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: <Walkthrough steps={walkthrough.steps} />,
|
||||
component: <Walkthrough canSkip={canSkip} steps={walkthrough.steps} />,
|
||||
disableClosing: true
|
||||
});
|
||||
};
|
||||
|
||||
@@ -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 (
|
||||
<View
|
||||
style={{
|
||||
height: 100
|
||||
}}
|
||||
>
|
||||
<AccentColorPicker settings={false} />
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
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 => <SvgToPngView src={LAUNCH_ROCKET(colors.pri)} />,
|
||||
button: {
|
||||
type: 'next',
|
||||
title: 'Next'
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
title: 'Make yourself at home',
|
||||
text: 'Pick a theme of your choice',
|
||||
walkthroughItem: () => <ChooseTheme />,
|
||||
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 => <SvgToPngView src={COMMUNITY_SVG(colors.pri)} />,
|
||||
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 => <SvgToPngView src={WELCOME_SVG(colors.pri)} />,
|
||||
button: {
|
||||
type: 'done',
|
||||
title: 'Continue'
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const Support = () => {
|
||||
const [state] = useTracked();
|
||||
const { colors } = state;
|
||||
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
width: '100%',
|
||||
alignItems: 'center'
|
||||
}}
|
||||
>
|
||||
<SvgToPngView src={SUPPORT_SVG()} />
|
||||
<Heading>Get Priority Support</Heading>
|
||||
<Paragraph
|
||||
style={{
|
||||
textAlign: 'center'
|
||||
}}
|
||||
size={SIZE.md}
|
||||
>
|
||||
You can reach out to us via multiple channels if you face an issue or want to just talk.
|
||||
</Paragraph>
|
||||
<Seperator />
|
||||
|
||||
<Button
|
||||
style={{
|
||||
justifyContent: 'flex-start',
|
||||
marginBottom: 10,
|
||||
width: '90%'
|
||||
}}
|
||||
onPress={() => {
|
||||
Linking.openURL('https://discord.gg/zQBK97EE22').catch(console.log);
|
||||
}}
|
||||
icon="discord"
|
||||
type="grayBg"
|
||||
title="Join our community on Discord"
|
||||
/>
|
||||
|
||||
<Button
|
||||
style={{
|
||||
justifyContent: 'flex-start',
|
||||
marginBottom: 10,
|
||||
width: '90%'
|
||||
}}
|
||||
onPress={() => {
|
||||
Linking.openURL('https://t.me/notesnook').catch(console.log);
|
||||
}}
|
||||
icon="telegram"
|
||||
type="grayBg"
|
||||
title="Join our Telegram group"
|
||||
/>
|
||||
<Button
|
||||
style={{
|
||||
justifyContent: 'flex-start',
|
||||
marginBottom: 10,
|
||||
width: '90%'
|
||||
}}
|
||||
icon="bug"
|
||||
type="grayBg"
|
||||
title="Submit an issue from Settings"
|
||||
/>
|
||||
<Button
|
||||
style={{
|
||||
justifyContent: 'flex-start',
|
||||
marginBottom: 10,
|
||||
width: '90%'
|
||||
}}
|
||||
icon="mail"
|
||||
type="grayBg"
|
||||
title="Email us at support@streetwriters.co"
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
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 => <SvgToPngView src={LAUNCH_ROCKET(colors.pri)} />,
|
||||
button: {
|
||||
type: 'next',
|
||||
title: 'Next'
|
||||
}
|
||||
},
|
||||
{
|
||||
walkthroughItem: () => <Support />,
|
||||
button: {
|
||||
type: 'done',
|
||||
title: 'Continue'
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export default { notebooks, trialstarted, emailconfirmed, prouser };
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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: (
|
||||
<View
|
||||
style={{
|
||||
paddingHorizontal: 12,
|
||||
paddingBottom: 15,
|
||||
alignItems: 'center'
|
||||
}}
|
||||
>
|
||||
<ProFeatures />
|
||||
</View>
|
||||
)
|
||||
});
|
||||
|
||||
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();
|
||||
};
|
||||
|
||||
@@ -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.
|
||||
</Paragraph>
|
||||
</View>
|
||||
<ScrollView
|
||||
horizontal={true}
|
||||
showsHorizontalScrollIndicator={false}
|
||||
onMoveShouldSetResponderCapture={() => {
|
||||
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 => (
|
||||
<PressableButton
|
||||
key={item}
|
||||
customColor={
|
||||
colors.accent === item
|
||||
? RGB_Linear_Shade(!colors.night ? -0.2 : 0.2, hexToRGBA(item, 1))
|
||||
: item
|
||||
}
|
||||
customSelectedColor={item}
|
||||
alpha={!colors.night ? -0.1 : 0.1}
|
||||
opacity={1}
|
||||
onPress={async () => {
|
||||
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 ? (
|
||||
<Icon
|
||||
size={DDS.isLargeTablet() ? SIZE.lg : SIZE.xxl}
|
||||
color="white"
|
||||
name="check"
|
||||
/>
|
||||
) : null}
|
||||
</PressableButton>
|
||||
))}
|
||||
<View style={{ width: 50 }} />
|
||||
</ScrollView>
|
||||
|
||||
<AccentColorPicker />
|
||||
|
||||
<CustomButton
|
||||
title="Use system theme"
|
||||
@@ -337,4 +264,99 @@ const SettingsAppearanceSection = () => {
|
||||
);
|
||||
};
|
||||
|
||||
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 (
|
||||
<ScrollView
|
||||
horizontal={true}
|
||||
showsHorizontalScrollIndicator={false}
|
||||
onMoveShouldSetResponderCapture={() => {
|
||||
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 => (
|
||||
<PressableButton
|
||||
key={item}
|
||||
customColor={
|
||||
colors.accent === item
|
||||
? RGB_Linear_Shade(!colors.night ? -0.2 : 0.2, hexToRGBA(item, 1))
|
||||
: item
|
||||
}
|
||||
customSelectedColor={item}
|
||||
alpha={!colors.night ? -0.1 : 0.1}
|
||||
opacity={1}
|
||||
onPress={async () => {
|
||||
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 ? (
|
||||
<Icon size={DDS.isLargeTablet() ? SIZE.lg : SIZE.xxl} color="white" name="check" />
|
||||
) : null}
|
||||
</PressableButton>
|
||||
))}
|
||||
<View style={{ width: 50 }} />
|
||||
</ScrollView>
|
||||
);
|
||||
};
|
||||
|
||||
export default SettingsAppearanceSection;
|
||||
|
||||
@@ -124,11 +124,17 @@ export const Settings = ({ navigation }) => {
|
||||
component: <Issue />
|
||||
});
|
||||
},
|
||||
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'
|
||||
|
||||
Reference in New Issue
Block a user