mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-16 11:47:54 +01:00
refactor intro and auth flow
This commit is contained in:
@@ -5,6 +5,10 @@
|
||||
<!-- Customize your theme here. -->
|
||||
<item name="android:windowDisablePreview">true</item>
|
||||
<item name="android:editTextBackground">@drawable/edit_text</item>
|
||||
|
||||
<item name="android:windowTranslucentStatus">true</item>
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||
</style>
|
||||
|
||||
<style name="Share.Window" parent="Theme.AppCompat">
|
||||
|
||||
93
apps/mobile/src/components/auth/authmodal.js
Normal file
93
apps/mobile/src/components/auth/authmodal.js
Normal file
@@ -0,0 +1,93 @@
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { Platform, StatusBar } from 'react-native';
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import { eSendEvent, eSubscribeEvent, eUnSubscribeEvent } from '../../services/event-manager';
|
||||
import { useThemeStore } from '../../stores/use-theme-store';
|
||||
import { eCloseLoginDialog, eOpenLoginDialog } from '../../utils/events';
|
||||
import { sleep } from '../../utils/time';
|
||||
import BaseDialog from '../dialog/base-dialog';
|
||||
import { Toast } from '../toast';
|
||||
import { IconButton } from '../ui/icon-button';
|
||||
import { initialAuthMode } from './common';
|
||||
import { Login } from './login';
|
||||
import { Signup } from './signup';
|
||||
|
||||
export const AuthMode = {
|
||||
login: 0,
|
||||
signup: 1,
|
||||
welcomeSignup: 2,
|
||||
trialSignup: 3
|
||||
};
|
||||
|
||||
const AuthModal = () => {
|
||||
const colors = useThemeStore(state => state.colors);
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [currentAuthMode, setCurrentAuthMode] = useState(AuthMode.login);
|
||||
const actionSheetRef = useRef();
|
||||
const insets = useSafeAreaInsets();
|
||||
|
||||
useEffect(() => {
|
||||
eSubscribeEvent(eOpenLoginDialog, open);
|
||||
eSubscribeEvent(eCloseLoginDialog, close);
|
||||
return () => {
|
||||
eUnSubscribeEvent(eOpenLoginDialog, open);
|
||||
eUnSubscribeEvent(eCloseLoginDialog, close);
|
||||
};
|
||||
}, []);
|
||||
|
||||
async function open(mode) {
|
||||
setCurrentAuthMode(mode ? mode : AuthMode.login);
|
||||
initialAuthMode.current = -1;
|
||||
setVisible(true);
|
||||
await sleep(10);
|
||||
actionSheetRef.current?.show();
|
||||
}
|
||||
|
||||
const close = () => {
|
||||
actionSheetRef.current?.hide();
|
||||
setCurrentAuthMode(AuthMode.login);
|
||||
setVisible(false);
|
||||
};
|
||||
|
||||
return !visible ? null : (
|
||||
<BaseDialog
|
||||
overlayOpacity={0}
|
||||
statusBarTranslucent={false}
|
||||
onRequestClose={currentAuthMode !== AuthMode.welcomeSignup && close}
|
||||
visible={true}
|
||||
onClose={close}
|
||||
useSafeArea={false}
|
||||
bounce={false}
|
||||
background={colors.bg}
|
||||
transparent={false}
|
||||
>
|
||||
{currentAuthMode !== AuthMode.login ? (
|
||||
<Signup
|
||||
changeMode={mode => setCurrentAuthMode(mode)}
|
||||
trial={AuthMode.trialSignup === currentAuthMode}
|
||||
welcome={currentAuthMode === AuthMode.welcomeSignup}
|
||||
/>
|
||||
) : (
|
||||
<Login changeMode={mode => setCurrentAuthMode(mode)} />
|
||||
)}
|
||||
|
||||
<IconButton
|
||||
name="arrow-left"
|
||||
onPress={() => {
|
||||
eSendEvent(eCloseLoginDialog);
|
||||
}}
|
||||
color={colors.pri}
|
||||
customStyle={{
|
||||
position: 'absolute',
|
||||
zIndex: 999,
|
||||
left: 12,
|
||||
top: Platform.OS === 'ios' ? 12 + insets.top : 12
|
||||
}}
|
||||
/>
|
||||
|
||||
<Toast context="local" />
|
||||
</BaseDialog>
|
||||
);
|
||||
};
|
||||
|
||||
export default AuthModal;
|
||||
33
apps/mobile/src/components/auth/common.js
Normal file
33
apps/mobile/src/components/auth/common.js
Normal file
@@ -0,0 +1,33 @@
|
||||
import { createRef } from 'react';
|
||||
import { eSendEvent } from '../../services/event-manager';
|
||||
import Navigation from '../../services/navigation';
|
||||
import SettingsService from '../../services/settings';
|
||||
import { eCloseLoginDialog } from '../../utils/events';
|
||||
import { tabBarRef } from '../../utils/global-refs';
|
||||
|
||||
export const initialAuthMode = createRef(0);
|
||||
export function hideAuth() {
|
||||
if (initialAuthMode.current === -1) {
|
||||
eSendEvent(eCloseLoginDialog);
|
||||
return;
|
||||
}
|
||||
if (initialAuthMode.current === 2) {
|
||||
Navigation.replace(
|
||||
{
|
||||
name: 'Notes'
|
||||
},
|
||||
{
|
||||
menu: true
|
||||
}
|
||||
);
|
||||
} else {
|
||||
Navigation.goBack();
|
||||
}
|
||||
|
||||
tabBarRef.current?.unlock();
|
||||
if (!SettingsService.get().introCompleted) {
|
||||
SettingsService.set({
|
||||
introCompleted: true
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,11 @@
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { Platform } from 'react-native';
|
||||
import React, { useState } from 'react';
|
||||
import { View } from 'react-native';
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import { eSendEvent, eSubscribeEvent, eUnSubscribeEvent } from '../../services/event-manager';
|
||||
import { useThemeStore } from '../../stores/use-theme-store';
|
||||
import { eCloseLoginDialog, eOpenLoginDialog } from '../../utils/events';
|
||||
import { sleep } from '../../utils/time';
|
||||
import BaseDialog from '../dialog/base-dialog';
|
||||
import { tabBarRef } from '../../utils/global-refs';
|
||||
import { useNavigationFocus } from '../../utils/hooks/use-navigation-focus';
|
||||
import { Toast } from '../toast';
|
||||
import { IconButton } from '../ui/icon-button';
|
||||
import { initialAuthMode } from './common';
|
||||
import { Login } from './login';
|
||||
import { Signup } from './signup';
|
||||
|
||||
@@ -18,75 +16,48 @@ export const AuthMode = {
|
||||
trialSignup: 3
|
||||
};
|
||||
|
||||
const Auth = () => {
|
||||
const Auth = ({ navigation, route }) => {
|
||||
const colors = useThemeStore(state => state.colors);
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [currentAuthMode, setCurrentAuthMode] = useState(AuthMode.login);
|
||||
const actionSheetRef = useRef();
|
||||
const [currentAuthMode, setCurrentAuthMode] = useState(route?.params?.mode || AuthMode.login);
|
||||
const insets = useSafeAreaInsets();
|
||||
initialAuthMode.current = route?.params.mode || AuthMode.login;
|
||||
useNavigationFocus(navigation, {
|
||||
onFocus: () => {
|
||||
tabBarRef?.current.lock();
|
||||
initialAuthMode.current = route?.params.mode || AuthMode.login;
|
||||
}
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
eSubscribeEvent(eOpenLoginDialog, open);
|
||||
eSubscribeEvent(eCloseLoginDialog, close);
|
||||
return () => {
|
||||
eUnSubscribeEvent(eOpenLoginDialog, open);
|
||||
eUnSubscribeEvent(eCloseLoginDialog, close);
|
||||
};
|
||||
}, []);
|
||||
|
||||
async function open(mode) {
|
||||
setCurrentAuthMode(mode ? mode : AuthMode.login);
|
||||
setVisible(true);
|
||||
await sleep(10);
|
||||
actionSheetRef.current?.show();
|
||||
}
|
||||
|
||||
const close = () => {
|
||||
actionSheetRef.current?.hide();
|
||||
setCurrentAuthMode(AuthMode.login);
|
||||
setVisible(false);
|
||||
};
|
||||
|
||||
return !visible ? null : (
|
||||
<BaseDialog
|
||||
overlayOpacity={0}
|
||||
statusBarTranslucent={false}
|
||||
onRequestClose={currentAuthMode !== AuthMode.welcomeSignup && close}
|
||||
visible={true}
|
||||
onClose={close}
|
||||
useSafeArea={false}
|
||||
bounce={false}
|
||||
background={colors.bg}
|
||||
transparent={false}
|
||||
>
|
||||
return (
|
||||
<View style={{ flex: 1 }}>
|
||||
{currentAuthMode !== AuthMode.login ? (
|
||||
<Signup
|
||||
changeMode={mode => setCurrentAuthMode(mode)}
|
||||
trial={AuthMode.trialSignup === currentAuthMode}
|
||||
welcome={currentAuthMode === AuthMode.welcomeSignup}
|
||||
welcome={initialAuthMode.current === AuthMode.welcomeSignup}
|
||||
/>
|
||||
) : (
|
||||
<Login changeMode={mode => setCurrentAuthMode(mode)} />
|
||||
<Login welcome={initialAuthMode.current} changeMode={mode => setCurrentAuthMode(mode)} />
|
||||
)}
|
||||
|
||||
{currentAuthMode === AuthMode.welcomeSignup ? null : (
|
||||
{/* {initialAuthMode.current === AuthMode.welcomeSignup ? null : (
|
||||
<IconButton
|
||||
name="arrow-left"
|
||||
onPress={() => {
|
||||
eSendEvent(eCloseLoginDialog);
|
||||
hideAuth();
|
||||
}}
|
||||
color={colors.pri}
|
||||
customStyle={{
|
||||
position: 'absolute',
|
||||
zIndex: 999,
|
||||
left: 12,
|
||||
top: Platform.OS === 'ios' ? 12 + insets.top : 12
|
||||
top: Platform.OS === 'ios' ? 12 + insets.top : insets.top
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
)} */}
|
||||
|
||||
<Toast context="local" />
|
||||
</BaseDialog>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -26,7 +26,10 @@ import Paragraph from '../ui/typography/paragraph';
|
||||
import { SVG } from './background';
|
||||
import { ForgotPassword } from './forgot-password';
|
||||
import TwoFactorVerification from './two-factor';
|
||||
export const Login = ({ changeMode }) => {
|
||||
import Animated, { FadeInDown, FadeOutDown, FadeOutUp } from 'react-native-reanimated';
|
||||
import Navigation from '../../services/navigation';
|
||||
import { hideAuth } from './common';
|
||||
export const Login = ({ changeMode, welcome }) => {
|
||||
const colors = useThemeStore(state => state.colors);
|
||||
const email = useRef();
|
||||
const emailInputRef = useRef();
|
||||
@@ -87,8 +90,8 @@ export const Login = ({ changeMode }) => {
|
||||
type: 'success',
|
||||
context: 'global'
|
||||
});
|
||||
eSendEvent(eCloseLoginDialog);
|
||||
await SettingsService.set({
|
||||
hideAuth();
|
||||
SettingsService.set({
|
||||
sessionExpired: false,
|
||||
userEmailConfirmed: user.isEmailConfirmed
|
||||
});
|
||||
@@ -131,10 +134,11 @@ export const Login = ({ changeMode }) => {
|
||||
return (
|
||||
<>
|
||||
<ForgotPassword />
|
||||
|
||||
<SheetProvider context="two_factor_verify" />
|
||||
{loading ? <BaseDialog transparent={true} visible={true} animation="fade" /> : null}
|
||||
<View
|
||||
<Animated.View
|
||||
entering={FadeInDown}
|
||||
exiting={FadeOutUp}
|
||||
style={{
|
||||
borderRadius: DDS.isTab ? 5 : 0,
|
||||
backgroundColor: colors.bg,
|
||||
@@ -149,9 +153,7 @@ export const Login = ({ changeMode }) => {
|
||||
overflow: 'hidden'
|
||||
}}
|
||||
>
|
||||
<BouncingView initialScale={1.05} duration={5000}>
|
||||
<SvgView src={SVG(colors.night ? colors.icon : 'black')} height={700} />
|
||||
</BouncingView>
|
||||
<SvgView src={SVG(colors.night ? colors.icon : 'black')} height={700} />
|
||||
</View>
|
||||
<View
|
||||
style={{
|
||||
@@ -250,13 +252,12 @@ export const Login = ({ changeMode }) => {
|
||||
<View
|
||||
style={{
|
||||
// position: 'absolute',
|
||||
marginTop: 50,
|
||||
marginTop: 25,
|
||||
alignSelf: 'center'
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
style={{
|
||||
marginTop: 10,
|
||||
width: 250,
|
||||
borderRadius: 100
|
||||
}}
|
||||
@@ -266,9 +267,24 @@ export const Login = ({ changeMode }) => {
|
||||
type="accent"
|
||||
title={loading ? null : 'Login to your account'}
|
||||
/>
|
||||
|
||||
{loading || !welcome ? null : (
|
||||
<Button
|
||||
style={{
|
||||
marginTop: 10,
|
||||
width: 250,
|
||||
borderRadius: 100
|
||||
}}
|
||||
onPress={() => {
|
||||
hideAuth();
|
||||
}}
|
||||
type="grayBg"
|
||||
title="Skip for now"
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</Animated.View>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import React, { useRef, useState } from 'react';
|
||||
import { Dimensions, Platform, View } from 'react-native';
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import { Dimensions, View } from 'react-native';
|
||||
import Animated, { FadeInDown, FadeOutDown, FadeOutUp } from 'react-native-reanimated';
|
||||
import { DDS } from '../../services/device-detection';
|
||||
import { eSendEvent, ToastEvent } from '../../services/event-manager';
|
||||
import { clearMessage, setEmailVerifyMessage } from '../../services/message';
|
||||
import Navigation from '../../services/navigation';
|
||||
import PremiumService from '../../services/premium';
|
||||
import { useUserStore } from '../../stores/use-user-store';
|
||||
import SettingsService from '../../services/settings';
|
||||
import { useThemeStore } from '../../stores/use-theme-store';
|
||||
import { useUserStore } from '../../stores/use-user-store';
|
||||
import umami from '../../utils/analytics';
|
||||
import { db } from '../../utils/database';
|
||||
import { eCloseLoginDialog } from '../../utils/events';
|
||||
@@ -15,13 +17,13 @@ import { SIZE } from '../../utils/size';
|
||||
import { sleep } from '../../utils/time';
|
||||
import BaseDialog from '../dialog/base-dialog';
|
||||
import { Button } from '../ui/button';
|
||||
import { IconButton } from '../ui/icon-button';
|
||||
import Input from '../ui/input';
|
||||
import { SvgView } from '../ui/svg';
|
||||
import { BouncingView } from '../ui/transitions/bouncing-view';
|
||||
import Heading from '../ui/typography/heading';
|
||||
import Paragraph from '../ui/typography/paragraph';
|
||||
import { SVG } from './background';
|
||||
import { hideAuth } from './common';
|
||||
|
||||
export const Signup = ({ changeMode, welcome, trial }) => {
|
||||
const colors = useThemeStore(state => state.colors);
|
||||
@@ -33,9 +35,6 @@ export const Signup = ({ changeMode, welcome, trial }) => {
|
||||
const confirmPassword = useRef();
|
||||
const [error, setError] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const insets = useSafeAreaInsets();
|
||||
|
||||
const setUser = useUserStore(state => state.setUser);
|
||||
const setLastSynced = useUserStore(state => state.setLastSynced);
|
||||
|
||||
@@ -64,7 +63,7 @@ export const Signup = ({ changeMode, welcome, trial }) => {
|
||||
setLastSynced(await db.lastSynced());
|
||||
clearMessage();
|
||||
setEmailVerifyMessage();
|
||||
eSendEvent(eCloseLoginDialog);
|
||||
hideAuth();
|
||||
umami.pageView('/account-created', '/welcome/signup');
|
||||
await sleep(300);
|
||||
if (trial) {
|
||||
@@ -86,7 +85,9 @@ export const Signup = ({ changeMode, welcome, trial }) => {
|
||||
return (
|
||||
<>
|
||||
{loading ? <BaseDialog transparent={true} visible={true} animation="fade" /> : null}
|
||||
<View
|
||||
<Animated.View
|
||||
entering={FadeInDown}
|
||||
exiting={FadeOutUp}
|
||||
style={{
|
||||
borderRadius: DDS.isTab ? 5 : 0,
|
||||
backgroundColor: colors.bg,
|
||||
@@ -101,9 +102,7 @@ export const Signup = ({ changeMode, welcome, trial }) => {
|
||||
overflow: 'hidden'
|
||||
}}
|
||||
>
|
||||
<BouncingView initialScale={1.05}>
|
||||
<SvgView src={SVG(colors.night ? colors.icon : 'black')} height={700} />
|
||||
</BouncingView>
|
||||
<SvgView src={SVG(colors.night ? colors.icon : 'black')} height={700} />
|
||||
</View>
|
||||
|
||||
<View
|
||||
@@ -205,48 +204,14 @@ export const Signup = ({ changeMode, welcome, trial }) => {
|
||||
marginBottom={5}
|
||||
onSubmit={signup}
|
||||
/>
|
||||
<Paragraph size={SIZE.xs} color={colors.icon}>
|
||||
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
|
||||
style={{
|
||||
marginTop: 50,
|
||||
marginTop: 25,
|
||||
alignSelf: 'center'
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
style={{
|
||||
marginTop: 10,
|
||||
width: 250,
|
||||
borderRadius: 100
|
||||
}}
|
||||
@@ -264,15 +229,54 @@ export const Signup = ({ changeMode, welcome, trial }) => {
|
||||
borderRadius: 100
|
||||
}}
|
||||
onPress={() => {
|
||||
eSendEvent(eCloseLoginDialog);
|
||||
hideAuth();
|
||||
}}
|
||||
type="grayBg"
|
||||
title="Skip for now"
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
|
||||
<Paragraph
|
||||
style={{
|
||||
textAlign: 'center',
|
||||
position: 'absolute',
|
||||
bottom: 0,
|
||||
alignSelf: 'center',
|
||||
marginBottom: 20
|
||||
}}
|
||||
size={SIZE.xs}
|
||||
color={colors.icon}
|
||||
>
|
||||
By signing up, you agree to our{' '}
|
||||
<Paragraph
|
||||
size={SIZE.xs}
|
||||
onPress={() => {
|
||||
openLinkInBrowser('https://notesnook.com/tos', colors);
|
||||
}}
|
||||
style={{
|
||||
textDecorationLine: 'underline'
|
||||
}}
|
||||
color={colors.accent}
|
||||
>
|
||||
terms of service{' '}
|
||||
</Paragraph>
|
||||
and{' '}
|
||||
<Paragraph
|
||||
size={SIZE.xs}
|
||||
onPress={() => {
|
||||
openLinkInBrowser('https://notesnook.com/privacy', colors);
|
||||
}}
|
||||
style={{
|
||||
textDecorationLine: 'underline'
|
||||
}}
|
||||
color={colors.accent}
|
||||
>
|
||||
privacy policy.
|
||||
</Paragraph>
|
||||
</Paragraph>
|
||||
</View>
|
||||
</View>
|
||||
</Animated.View>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import React from 'react';
|
||||
import { KeyboardAvoidingView, Platform, SafeAreaView } from 'react-native';
|
||||
import { useSettingStore } from '../../stores/use-setting-store';
|
||||
import useIsFloatingKeyboard from '../../utils/hooks/use-is-floating-keyboard';
|
||||
import { Header } from '../header';
|
||||
import SelectionHeader from '../selection-header';
|
||||
export const Container = ({ children }) => {
|
||||
const floating = useIsFloatingKeyboard();
|
||||
const introCompleted = useSettingStore(state => state.settings.introCompleted);
|
||||
return (
|
||||
<KeyboardAvoidingView
|
||||
behavior="padding"
|
||||
@@ -19,8 +21,13 @@ export const Container = ({ children }) => {
|
||||
overflow: 'hidden'
|
||||
}}
|
||||
>
|
||||
<SelectionHeader />
|
||||
<Header title="Header" screen="Header" />
|
||||
{!introCompleted ? null : (
|
||||
<>
|
||||
<SelectionHeader />
|
||||
<Header title="Header" screen="Header" />
|
||||
</>
|
||||
)}
|
||||
|
||||
{children}
|
||||
</SafeAreaView>
|
||||
</KeyboardAvoidingView>
|
||||
|
||||
@@ -3,6 +3,7 @@ import { useThemeStore } from '../../stores/use-theme-store';
|
||||
import { AnnouncementDialog } from '../announcements';
|
||||
import { AttachmentDialog } from '../attachments';
|
||||
import Auth from '../auth';
|
||||
import AuthModal from '../auth/auth-modal';
|
||||
import { SessionExpired } from '../auth/session-expired';
|
||||
import { Dialog } from '../dialog';
|
||||
import { AddTopicDialog } from '../dialogs/add-topic';
|
||||
@@ -32,7 +33,7 @@ const DialogProvider = React.memo(
|
||||
<AddTopicDialog colors={colors} />
|
||||
<AddNotebookSheet colors={colors} />
|
||||
<PremiumDialog colors={colors} />
|
||||
<Auth colors={colors} />
|
||||
<AuthModal colors={colors} />
|
||||
<MergeConflicts />
|
||||
<ExportNotesSheet />
|
||||
<RecoveryKeySheet colors={colors} />
|
||||
|
||||
@@ -5,6 +5,7 @@ import Navigation from '../../services/navigation';
|
||||
import useNavigationStore from '../../stores/use-navigation-store';
|
||||
import { useSettingStore } from '../../stores/use-setting-store';
|
||||
import { useThemeStore } from '../../stores/use-theme-store';
|
||||
import { tabBarRef } from '../../utils/global-refs';
|
||||
import { IconButton } from '../ui/icon-button';
|
||||
|
||||
export const LeftMenus = () => {
|
||||
@@ -19,6 +20,12 @@ export const LeftMenus = () => {
|
||||
return;
|
||||
}
|
||||
Navigation.goBack();
|
||||
if (
|
||||
useNavigationStore.getState().currentScreen.name === 'Signup' ||
|
||||
useNavigationStore.getState().currentScreen.name === 'Login'
|
||||
) {
|
||||
tabBarRef.current.unlock();
|
||||
}
|
||||
};
|
||||
|
||||
return isTablet ? null : (
|
||||
|
||||
@@ -20,7 +20,10 @@ export const RightMenus = () => {
|
||||
|
||||
return (
|
||||
<View style={styles.rightBtnContainer}>
|
||||
{!currentScreen.startsWith('Settings') ? (
|
||||
{!currentScreen.startsWith('Settings') &&
|
||||
currentScreen !== 'Auth' &&
|
||||
currentScreen !== 'Signup' &&
|
||||
currentScreen !== 'Login' ? (
|
||||
<IconButton
|
||||
onPress={async () => {
|
||||
SearchService.prepareSearch();
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -46,11 +46,7 @@ const Launcher = React.memo(
|
||||
const deviceMode = useSettingStore(state => state.deviceMode);
|
||||
const passwordInputRef = useRef();
|
||||
const password = useRef();
|
||||
const introCompleted = SettingsService.get().introCompleted;
|
||||
const [requireIntro, setRequireIntro] = useState({
|
||||
updated: introCompleted,
|
||||
value: !introCompleted
|
||||
});
|
||||
const introCompleted = false; //SettingsService.get().introCompleted;
|
||||
const dbInitCompleted = useRef(false);
|
||||
|
||||
const loadNotes = async () => {
|
||||
@@ -62,13 +58,17 @@ const Launcher = React.memo(
|
||||
db.notes.init().then(() => {
|
||||
Walkthrough.init();
|
||||
initialize();
|
||||
setImmediate(() => setLoading(false));
|
||||
setImmediate(() => {
|
||||
setLoading(false);
|
||||
setImmediate(() => doAppLoadActions());
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const init = async () => {
|
||||
if (!dbInitCompleted.current) {
|
||||
await RNBootSplash.hide();
|
||||
await db.init();
|
||||
dbInitCompleted.current = true;
|
||||
}
|
||||
@@ -78,24 +78,9 @@ const Launcher = React.memo(
|
||||
}
|
||||
};
|
||||
|
||||
const hideSplashScreen = async () => {
|
||||
if (requireIntro.value) await sleep(500);
|
||||
await RNBootSplash.hide({ fade: true });
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
console.log('hide splash', requireIntro.updated);
|
||||
if (requireIntro.updated) {
|
||||
hideSplashScreen();
|
||||
return;
|
||||
}
|
||||
let introCompleted = SettingsService.get().introCompleted;
|
||||
console.log(requireIntro);
|
||||
setRequireIntro({
|
||||
updated: true,
|
||||
value: !introCompleted
|
||||
});
|
||||
}, [requireIntro, verifyUser]);
|
||||
// useEffect(() => {
|
||||
// hideSplashScreen();
|
||||
// }, [verifyUser]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!loading) {
|
||||
@@ -129,7 +114,7 @@ const Launcher = React.memo(
|
||||
}
|
||||
}
|
||||
|
||||
if (!requireIntro?.value) {
|
||||
if (introCompleted) {
|
||||
useMessageStore.subscribe(state => {
|
||||
let dialogs = state.dialogs;
|
||||
if (dialogs.length > 0) {
|
||||
@@ -141,17 +126,17 @@ const Launcher = React.memo(
|
||||
|
||||
const checkAppUpdateAvailable = async () => {
|
||||
return;
|
||||
try {
|
||||
const version = await checkVersion();
|
||||
if (!version.needsUpdate) return false;
|
||||
presentSheet({
|
||||
component: ref => <Update version={version} fwdRef={ref} />
|
||||
});
|
||||
// try {
|
||||
// const version = await checkVersion();
|
||||
// if (!version.needsUpdate) return false;
|
||||
// presentSheet({
|
||||
// component: ref => <Update version={version} fwdRef={ref} />
|
||||
// });
|
||||
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
// return true;
|
||||
// } catch (e) {
|
||||
// return false;
|
||||
// }
|
||||
};
|
||||
|
||||
const restoreEditorState = async () => {
|
||||
@@ -354,8 +339,6 @@ const Launcher = React.memo(
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
) : requireIntro.value && !loading ? (
|
||||
<Intro />
|
||||
) : null;
|
||||
},
|
||||
() => true
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -26,6 +26,7 @@ export const SideMenu = React.memo(
|
||||
const insets = useSafeAreaInsets();
|
||||
const subscriptionType = useUserStore(state => state.user?.subscription?.type);
|
||||
const loading = useNoteStore(state => state.loading);
|
||||
const introCompleted = useSettingStore(state => state.settings.introCompleted);
|
||||
const noTextMode = false;
|
||||
|
||||
const BottomItemsList = [
|
||||
@@ -72,7 +73,7 @@ export const SideMenu = React.memo(
|
||||
[]
|
||||
);
|
||||
|
||||
return !loading ? (
|
||||
return !loading && introCompleted ? (
|
||||
<View
|
||||
style={{
|
||||
height: '100%',
|
||||
|
||||
@@ -14,6 +14,8 @@ import Paragraph from '../ui/typography/paragraph';
|
||||
import { TimeSince } from '../ui/time-since';
|
||||
import useSyncProgress from '../../utils/hooks/use-sync-progress';
|
||||
import * as Progress from 'react-native-progress';
|
||||
import Navigation from '../../services/navigation';
|
||||
import { tabBarRef } from '../../utils/global-refs';
|
||||
|
||||
export const UserStatus = () => {
|
||||
const colors = useThemeStore(state => state.colors);
|
||||
@@ -45,7 +47,16 @@ export const UserStatus = () => {
|
||||
if (user) {
|
||||
await Sync.run();
|
||||
} else {
|
||||
eSendEvent(eOpenLoginDialog);
|
||||
tabBarRef.current?.closeDrawer();
|
||||
Navigation.navigate(
|
||||
{
|
||||
name: 'Login'
|
||||
},
|
||||
{
|
||||
mode: 0,
|
||||
canGoBack: true
|
||||
}
|
||||
);
|
||||
}
|
||||
}}
|
||||
type="gray"
|
||||
|
||||
@@ -1,11 +1,23 @@
|
||||
import React from 'react';
|
||||
import DelayLayout from '../components/delay-layout';
|
||||
import DialogProvider from '../components/dialog-provider';
|
||||
import { Header } from '../components/header';
|
||||
import Intro from '../components/intro';
|
||||
import { Toast } from '../components/toast';
|
||||
import SettingsService from '../services/settings';
|
||||
import { useNoteStore } from '../stores/use-notes-store';
|
||||
import { TabsHolder } from './tabs-holder';
|
||||
|
||||
export const ApplicationHolder = React.memo(
|
||||
() => {
|
||||
return (
|
||||
const loading = useNoteStore(state => state.loading);
|
||||
const introCompleted = SettingsService.get().introCompleted;
|
||||
return loading && introCompleted ? (
|
||||
<>
|
||||
<Header />
|
||||
<DelayLayout wait={loading} />
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<TabsHolder />
|
||||
<Toast />
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
|
||||
import { NavigationContainer } from '@react-navigation/native';
|
||||
import { createNativeStackNavigator } from '@react-navigation/native-stack';
|
||||
import * as React from 'react';
|
||||
import Auth from '../components/auth';
|
||||
import { Login } from '../components/auth/login';
|
||||
import { Signup } from '../components/auth/signup';
|
||||
import Container from '../components/container';
|
||||
import Intro from '../components/intro';
|
||||
import Favorites from '../screens/favorites';
|
||||
import Home from '../screens/home';
|
||||
import Notebook from '../screens/notebook';
|
||||
@@ -13,6 +16,7 @@ import { TaggedNotes } from '../screens/notes/tagged';
|
||||
import { TopicNotes } from '../screens/notes/topic-notes';
|
||||
import { Search } from '../screens/search';
|
||||
import Settings from '../screens/settings';
|
||||
import AppLock from '../screens/settings/app-lock';
|
||||
import Tags from '../screens/tags';
|
||||
import Trash from '../screens/trash';
|
||||
import { eSendEvent } from '../services/event-manager';
|
||||
@@ -24,10 +28,50 @@ import { history } from '../utils';
|
||||
import { rootNavigatorRef } from '../utils/global-refs';
|
||||
import { hideAllTooltips } from '../utils/hooks/use-tooltip';
|
||||
const NativeStack = createNativeStackNavigator();
|
||||
const IntroStack = createNativeStackNavigator();
|
||||
|
||||
/**
|
||||
* Intro Stack:
|
||||
*
|
||||
* Welcome Page
|
||||
* Select Privacy Mode Page
|
||||
* Login/Signup Page
|
||||
*
|
||||
*/
|
||||
|
||||
const IntroStackNavigator = () => {
|
||||
const colors = useThemeStore(state => state.colors);
|
||||
const introCompleted = SettingsService.get().introCompleted;
|
||||
return (
|
||||
<IntroStack.Navigator
|
||||
screenOptions={{
|
||||
headerShown: false,
|
||||
lazy: false,
|
||||
animation: 'none',
|
||||
contentStyle: {
|
||||
backgroundColor: colors.bg
|
||||
}
|
||||
}}
|
||||
initialRouteName={'Intro'}
|
||||
>
|
||||
<NativeStack.Screen name="Intro" component={Intro} />
|
||||
<NativeStack.Screen name="AppLock" component={AppLock} />
|
||||
<NativeStack.Screen
|
||||
name="Auth"
|
||||
initialParams={{
|
||||
mode: 0
|
||||
}}
|
||||
component={Auth}
|
||||
/>
|
||||
</IntroStack.Navigator>
|
||||
);
|
||||
};
|
||||
|
||||
const Tabs = React.memo(
|
||||
() => {
|
||||
const colors = useThemeStore(state => state.colors);
|
||||
const homepage = SettingsService.get().homepage;
|
||||
const showWelcome = !SettingsService.get().introCompleted;
|
||||
React.useEffect(() => {
|
||||
setTimeout(() => {
|
||||
useNavigationStore.getState().update({ name: homepage });
|
||||
@@ -37,7 +81,7 @@ const Tabs = React.memo(
|
||||
return (
|
||||
<NativeStack.Navigator
|
||||
tabBar={() => null}
|
||||
initialRouteName={homepage}
|
||||
initialRouteName={showWelcome ? 'Welcome' : homepage}
|
||||
backBehavior="history"
|
||||
screenOptions={{
|
||||
headerShown: false,
|
||||
@@ -48,6 +92,21 @@ const Tabs = React.memo(
|
||||
}
|
||||
}}
|
||||
>
|
||||
<NativeStack.Screen
|
||||
name="Signup"
|
||||
initialParams={{
|
||||
mode: 1
|
||||
}}
|
||||
component={Auth}
|
||||
/>
|
||||
<NativeStack.Screen
|
||||
name="Login"
|
||||
initialParams={{
|
||||
mode: 0
|
||||
}}
|
||||
component={Auth}
|
||||
/>
|
||||
<NativeStack.Screen name="Welcome" component={IntroStackNavigator} />
|
||||
<NativeStack.Screen name="Notes" component={Home} />
|
||||
<NativeStack.Screen name="Notebooks" component={Notebooks} />
|
||||
<NativeStack.Screen options={{ lazy: true }} name="Favorites" component={Favorites} />
|
||||
|
||||
@@ -188,7 +188,6 @@ const pick = async options => {
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (options?.type.startsWith('image') || options?.type === 'camera') {
|
||||
if (options.type === 'image') {
|
||||
gallery(options);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useCallback, useEffect, useRef } from 'react';
|
||||
import { BackHandler, InteractionManager, NativeEventSubscription } from 'react-native';
|
||||
import { WebViewMessageEvent } from 'react-native-webview';
|
||||
import { AuthMode } from '../../../components/auth';
|
||||
import { Properties } from '../../../components/properties';
|
||||
import { DDS } from '../../../services/device-detection';
|
||||
import {
|
||||
@@ -95,21 +96,18 @@ const showActionsheet = async (editor: useEditorType) => {
|
||||
const currentNote = editor?.note?.current;
|
||||
if (currentNote?.id) {
|
||||
let note = db.notes?.note(currentNote.id)?.data as NoteType;
|
||||
if (!note) {
|
||||
ToastEvent.show({
|
||||
heading: 'Start writing to create a new note',
|
||||
type: 'success',
|
||||
context: 'global'
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (editorState().isFocused || editorState().isFocused) {
|
||||
editorState().isFocused = true;
|
||||
}
|
||||
|
||||
Properties.present(note, ['Dark Mode']);
|
||||
} else {
|
||||
ToastEvent.show({
|
||||
heading: 'Start writing to create a new note',
|
||||
type: 'success',
|
||||
context: 'global'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -222,103 +220,100 @@ export const useEditorEvents = (
|
||||
};
|
||||
}, []);
|
||||
|
||||
const onMessage = useCallback(
|
||||
(event: WebViewMessageEvent) => {
|
||||
const data = event.nativeEvent.data;
|
||||
let editorMessage = JSON.parse(data) as EditorMessage;
|
||||
const onMessage = (event: WebViewMessageEvent) => {
|
||||
const data = event.nativeEvent.data;
|
||||
let editorMessage = JSON.parse(data) as EditorMessage;
|
||||
|
||||
logger.info('editor', editorMessage.type);
|
||||
if (
|
||||
editorMessage.sessionId !== editor.sessionId &&
|
||||
editorMessage.type !== EditorEvents.status
|
||||
) {
|
||||
logger.error(
|
||||
'editor',
|
||||
'invalid session',
|
||||
editorMessage.type,
|
||||
editor.sessionId,
|
||||
editorMessage.sessionId
|
||||
);
|
||||
logger.info('editor', editorMessage.type);
|
||||
if (
|
||||
editorMessage.sessionId !== editor.sessionId &&
|
||||
editorMessage.type !== EditorEvents.status
|
||||
) {
|
||||
logger.error(
|
||||
'editor',
|
||||
'invalid session',
|
||||
editorMessage.type,
|
||||
editor.sessionId,
|
||||
editorMessage.sessionId
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
switch (editorMessage.type) {
|
||||
case EventTypes.logger:
|
||||
logger.info('[WEBVIEW LOG]', editorMessage.value);
|
||||
break;
|
||||
case EventTypes.content:
|
||||
editor.saveContent({
|
||||
type: editorMessage.type,
|
||||
content: editorMessage.value
|
||||
});
|
||||
break;
|
||||
case EventTypes.selection:
|
||||
break;
|
||||
case EventTypes.title:
|
||||
editor.saveContent({
|
||||
type: editorMessage.type,
|
||||
title: editorMessage.value
|
||||
});
|
||||
break;
|
||||
case EventTypes.newtag:
|
||||
return;
|
||||
}
|
||||
switch (editorMessage.type) {
|
||||
case EventTypes.logger:
|
||||
logger.info('[WEBVIEW LOG]', editorMessage.value);
|
||||
break;
|
||||
case EventTypes.content:
|
||||
editor.saveContent({
|
||||
type: editorMessage.type,
|
||||
content: editorMessage.value
|
||||
});
|
||||
break;
|
||||
case EventTypes.selection:
|
||||
break;
|
||||
case EventTypes.title:
|
||||
editor.saveContent({
|
||||
type: editorMessage.type,
|
||||
title: editorMessage.value
|
||||
});
|
||||
break;
|
||||
case EventTypes.newtag:
|
||||
if (!editor.note.current) return;
|
||||
eSendEvent(eOpenTagsDialog, editor.note.current);
|
||||
break;
|
||||
case EventTypes.tag:
|
||||
if (editorMessage.value) {
|
||||
if (!editor.note.current) return;
|
||||
eSendEvent(eOpenTagsDialog, editor.note.current);
|
||||
break;
|
||||
case EventTypes.tag:
|
||||
if (editorMessage.value) {
|
||||
if (!editor.note.current) return;
|
||||
db.notes
|
||||
//@ts-ignore
|
||||
?.note(editor.note.current?.id)
|
||||
.untag(editorMessage.value)
|
||||
.then(async () => {
|
||||
useTagStore.getState().setTags();
|
||||
await editor.commands.setTags(editor.note.current);
|
||||
Navigation.queueRoutesForUpdate(
|
||||
'ColoredNotes',
|
||||
'Notes',
|
||||
'TaggedNotes',
|
||||
'TopicNotes',
|
||||
'Tags'
|
||||
);
|
||||
});
|
||||
}
|
||||
break;
|
||||
case EventTypes.filepicker:
|
||||
picker.pick({ type: editorMessage.value });
|
||||
break;
|
||||
case EventTypes.download:
|
||||
console.log('download attachment request', editorMessage.value);
|
||||
filesystem.downloadAttachment(editorMessage.value?.hash, true);
|
||||
break;
|
||||
case EventTypes.pro:
|
||||
if (editor.state.current?.isFocused) {
|
||||
editor.state.current.isFocused = true;
|
||||
}
|
||||
umami.pageView('/pro-screen', '/editor');
|
||||
eSendEvent(eOpenPremiumDialog);
|
||||
break;
|
||||
case EventTypes.monograph:
|
||||
publishNote(editor);
|
||||
break;
|
||||
case EventTypes.properties:
|
||||
showActionsheet(editor);
|
||||
break;
|
||||
case EventTypes.back:
|
||||
onBackPress();
|
||||
break;
|
||||
default:
|
||||
console.log(
|
||||
'unhandled event recieved from editor: ',
|
||||
editorMessage.type,
|
||||
editorMessage.value
|
||||
);
|
||||
break;
|
||||
}
|
||||
eSendEvent(editorMessage.type, editorMessage);
|
||||
},
|
||||
[editor.sessionId, editor.saveContent]
|
||||
);
|
||||
db.notes
|
||||
//@ts-ignore
|
||||
?.note(editor.note.current?.id)
|
||||
.untag(editorMessage.value)
|
||||
.then(async () => {
|
||||
useTagStore.getState().setTags();
|
||||
await editor.commands.setTags(editor.note.current);
|
||||
Navigation.queueRoutesForUpdate(
|
||||
'ColoredNotes',
|
||||
'Notes',
|
||||
'TaggedNotes',
|
||||
'TopicNotes',
|
||||
'Tags'
|
||||
);
|
||||
});
|
||||
}
|
||||
break;
|
||||
case EventTypes.filepicker:
|
||||
picker.pick({ type: editorMessage.value });
|
||||
break;
|
||||
case EventTypes.download:
|
||||
console.log('download attachment request', editorMessage.value);
|
||||
filesystem.downloadAttachment(editorMessage.value?.hash, true);
|
||||
break;
|
||||
case EventTypes.pro:
|
||||
if (editor.state.current?.isFocused) {
|
||||
editor.state.current.isFocused = true;
|
||||
}
|
||||
umami.pageView('/pro-screen', '/editor');
|
||||
eSendEvent(eOpenPremiumDialog);
|
||||
break;
|
||||
case EventTypes.monograph:
|
||||
publishNote(editor);
|
||||
break;
|
||||
case EventTypes.properties:
|
||||
showActionsheet(editor);
|
||||
break;
|
||||
case EventTypes.back:
|
||||
onBackPress();
|
||||
break;
|
||||
default:
|
||||
console.log(
|
||||
'unhandled event recieved from editor: ',
|
||||
editorMessage.type,
|
||||
editorMessage.value
|
||||
);
|
||||
break;
|
||||
}
|
||||
eSendEvent(editorMessage.type, editorMessage);
|
||||
};
|
||||
|
||||
return onMessage;
|
||||
};
|
||||
|
||||
@@ -26,6 +26,7 @@ export const EditorWrapper = ({ width }) => {
|
||||
const loading = useNoteStore(state => state.loading);
|
||||
const insets = useSafeAreaInsets();
|
||||
const floating = useIsFloatingKeyboard();
|
||||
const introCompleted = useSettingStore(state => state.settings.introCompleted);
|
||||
|
||||
const onAppStateChanged = async state => {
|
||||
if (editorState().movedAway) return;
|
||||
@@ -54,7 +55,7 @@ export const EditorWrapper = ({ width }) => {
|
||||
borderLeftColor: DDS.isTab ? colors.nav : 'transparent'
|
||||
}}
|
||||
>
|
||||
{loading ? null : (
|
||||
{loading || !introCompleted ? null : (
|
||||
<SafeAreaView
|
||||
style={{
|
||||
flex: 1
|
||||
|
||||
@@ -103,8 +103,7 @@ export const AccentColorPicker = ({ settings = true, wrap = true }) => {
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
alignContent: 'flex-start'
|
||||
width: '100%'
|
||||
}}
|
||||
>
|
||||
{[
|
||||
|
||||
@@ -1,27 +1,29 @@
|
||||
import React, { useState } from 'react';
|
||||
import { LayoutAnimation, Platform, View } from 'react-native';
|
||||
import { Dimensions, LayoutAnimation, Platform, View } from 'react-native';
|
||||
import Animated, { FadeInDown, FadeOutUp } from 'react-native-reanimated';
|
||||
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||
import BiometricService from '../../services/biometrics';
|
||||
import { PressableButton } from '../../components/ui/pressable';
|
||||
import Seperator from '../../components/ui/seperator';
|
||||
import Heading from '../../components/ui/typography/heading';
|
||||
import Paragraph from '../../components/ui/typography/paragraph';
|
||||
import { useThemeStore } from '../../stores/use-theme-store';
|
||||
import { useSettingStore } from '../../stores/use-setting-store';
|
||||
import { presentSheet } from '../../services/event-manager';
|
||||
import SettingsService from '../../services/settings';
|
||||
import { SIZE } from '../../utils/size';
|
||||
import { db } from '../../utils/database';
|
||||
import { SVG_Z } from '../../components/intro';
|
||||
import { WelcomeNotice } from '../../components/intro/welcome';
|
||||
import { Button } from '../../components/ui/button';
|
||||
import { PressableButton } from '../../components/ui/pressable';
|
||||
import Seperator from '../../components/ui/seperator';
|
||||
import { SvgView } from '../../components/ui/svg';
|
||||
import { BouncingView } from '../../components/ui/transitions/bouncing-view';
|
||||
import Heading from '../../components/ui/typography/heading';
|
||||
import Paragraph from '../../components/ui/typography/paragraph';
|
||||
import { presentSheet } from '../../services/event-manager';
|
||||
import SettingsService from '../../services/settings';
|
||||
import { useSettingStore } from '../../stores/use-setting-store';
|
||||
import { useThemeStore } from '../../stores/use-theme-store';
|
||||
import { getElevation } from '../../utils';
|
||||
import umami from '../../utils/analytics';
|
||||
import { SIZE } from '../../utils/size';
|
||||
|
||||
const AppLock = ({ welcome, s = 0 }) => {
|
||||
const AppLock = ({ navigation, route }) => {
|
||||
const colors = useThemeStore(state => state.colors);
|
||||
const appLockMode = useSettingStore(state => state.settings.appLockMode);
|
||||
|
||||
const [step, setStep] = useState(s);
|
||||
const [step, setStep] = useState(0);
|
||||
const welcome = route?.params?.welcome;
|
||||
|
||||
const modes = [
|
||||
{
|
||||
@@ -50,117 +52,155 @@ const AppLock = ({ welcome, s = 0 }) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
{step === 0 ? (
|
||||
<>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: 'row',
|
||||
alignItems: 'flex-end',
|
||||
justifyContent: 'space-between',
|
||||
width: '95%',
|
||||
paddingVertical: 12,
|
||||
paddingHorizontal: 0,
|
||||
alignSelf: 'center',
|
||||
minHeight: 125,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: colors.nav
|
||||
}}
|
||||
>
|
||||
<Icon
|
||||
name="shield-lock"
|
||||
color={colors.border}
|
||||
size={100}
|
||||
<Animated.View
|
||||
exiting={!welcome ? undefined : FadeOutUp}
|
||||
entering={!welcome ? undefined : FadeInDown}
|
||||
style={{
|
||||
justifyContent: !welcome ? undefined : 'center',
|
||||
height: !welcome ? undefined : '100%',
|
||||
width: !welcome ? undefined : '100%'
|
||||
}}
|
||||
>
|
||||
{step === 0 ? (
|
||||
<>
|
||||
<View
|
||||
style={{
|
||||
position: 'absolute',
|
||||
right: 0,
|
||||
top: 6
|
||||
flexDirection: 'row',
|
||||
alignItems: 'flex-end',
|
||||
justifyContent: 'space-between',
|
||||
width: '95%',
|
||||
paddingVertical: 12,
|
||||
paddingHorizontal: 0,
|
||||
alignSelf: 'center',
|
||||
minHeight: 125,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: welcome ? 'transparent' : colors.nav
|
||||
}}
|
||||
/>
|
||||
|
||||
<View>
|
||||
<Heading>Protect your notes</Heading>
|
||||
<Paragraph size={SIZE.md}>
|
||||
Choose how you want to secure your notes locally.
|
||||
</Paragraph>
|
||||
</View>
|
||||
</View>
|
||||
<Seperator />
|
||||
<View
|
||||
style={{
|
||||
paddingHorizontal: 12
|
||||
}}
|
||||
>
|
||||
{modes.map(item => (
|
||||
<PressableButton
|
||||
key={item.title}
|
||||
type={appLockMode === item.value ? 'grayBg' : 'transparent'}
|
||||
onPress={() => {
|
||||
SettingsService.set({ appLockMode: item.value });
|
||||
}}
|
||||
customStyle={{
|
||||
justifyContent: 'flex-start',
|
||||
alignItems: 'flex-start',
|
||||
paddingHorizontal: 12,
|
||||
paddingVertical: 12,
|
||||
marginTop: 0,
|
||||
marginBottom: 12,
|
||||
borderWidth: 1,
|
||||
borderColor: appLockMode === item.value ? item.activeColor : colors.nav
|
||||
}}
|
||||
>
|
||||
<Icon
|
||||
name="shield-lock"
|
||||
color={colors.border}
|
||||
size={100}
|
||||
style={{
|
||||
marginBottom: 10
|
||||
position: 'absolute',
|
||||
right: 0,
|
||||
top: 6
|
||||
}}
|
||||
/>
|
||||
|
||||
<View
|
||||
style={{
|
||||
alignItems: !welcome ? undefined : 'center',
|
||||
width: '100%'
|
||||
}}
|
||||
>
|
||||
<Heading
|
||||
color={appLockMode === item.value ? item.activeColor : colors.pri}
|
||||
style={{ maxWidth: '95%' }}
|
||||
<Heading>Protect your notes</Heading>
|
||||
<Paragraph
|
||||
style={{
|
||||
textAlign: !welcome ? undefined : 'center'
|
||||
}}
|
||||
size={SIZE.md}
|
||||
>
|
||||
{item.title}
|
||||
</Heading>
|
||||
<Paragraph
|
||||
color={appLockMode === item.value ? item.activeColor : colors.icon}
|
||||
style={{ maxWidth: '95%' }}
|
||||
size={SIZE.sm}
|
||||
>
|
||||
{item.desc}
|
||||
Choose how you want to secure your notes locally.
|
||||
</Paragraph>
|
||||
</PressableButton>
|
||||
))}
|
||||
</View>
|
||||
</View>
|
||||
<Seperator />
|
||||
<View
|
||||
style={{
|
||||
paddingHorizontal: 12
|
||||
}}
|
||||
>
|
||||
{modes.map(item => (
|
||||
<PressableButton
|
||||
key={item.title}
|
||||
type={appLockMode === item.value ? 'grayBg' : 'transparent'}
|
||||
onPress={() => {
|
||||
SettingsService.set({ appLockMode: item.value });
|
||||
}}
|
||||
customStyle={{
|
||||
justifyContent: 'flex-start',
|
||||
alignItems: 'flex-start',
|
||||
paddingHorizontal: 12,
|
||||
paddingVertical: 12,
|
||||
marginTop: 0,
|
||||
marginBottom: 12,
|
||||
borderWidth: 1,
|
||||
borderColor: appLockMode === item.value ? item.activeColor : colors.nav
|
||||
}}
|
||||
style={{
|
||||
marginBottom: 10
|
||||
}}
|
||||
>
|
||||
<Heading
|
||||
color={appLockMode === item.value ? item.activeColor : colors.pri}
|
||||
style={{ maxWidth: '95%' }}
|
||||
size={SIZE.md}
|
||||
>
|
||||
{item.title}
|
||||
</Heading>
|
||||
<Paragraph
|
||||
color={appLockMode === item.value ? item.activeColor : colors.icon}
|
||||
style={{ maxWidth: '95%' }}
|
||||
size={SIZE.sm}
|
||||
>
|
||||
{item.desc}
|
||||
</Paragraph>
|
||||
</PressableButton>
|
||||
))}
|
||||
|
||||
{welcome && (
|
||||
<Button
|
||||
fontSize={SIZE.md}
|
||||
height={45}
|
||||
width={250}
|
||||
onPress={async () => {
|
||||
LayoutAnimation.configureNext({
|
||||
...LayoutAnimation.Presets.linear,
|
||||
delete: {
|
||||
duration: 50,
|
||||
property: 'opacity',
|
||||
type: 'linear'
|
||||
}
|
||||
});
|
||||
umami.pageView('/privacymode', '/welcome');
|
||||
setStep(1);
|
||||
}}
|
||||
style={{
|
||||
paddingHorizontal: 24,
|
||||
alignSelf: 'center',
|
||||
borderRadius: 100,
|
||||
...getElevation(5),
|
||||
marginTop: 30
|
||||
}}
|
||||
type="accent"
|
||||
title="Next"
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
</>
|
||||
) : (
|
||||
<WelcomeNotice />
|
||||
)}
|
||||
{welcome && (
|
||||
<Button
|
||||
fontSize={SIZE.md}
|
||||
height={45}
|
||||
width={250}
|
||||
onPress={async () => {
|
||||
LayoutAnimation.configureNext({
|
||||
...LayoutAnimation.Presets.linear,
|
||||
delete: {
|
||||
duration: 50,
|
||||
property: 'opacity',
|
||||
type: 'linear'
|
||||
}
|
||||
});
|
||||
umami.pageView('/privacymode', '/welcome');
|
||||
setStep(1);
|
||||
}}
|
||||
style={{
|
||||
paddingHorizontal: 24,
|
||||
alignSelf: 'center',
|
||||
borderRadius: 100,
|
||||
...getElevation(5),
|
||||
marginTop: 30
|
||||
}}
|
||||
type="accent"
|
||||
title="Next"
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
</>
|
||||
) : (
|
||||
<WelcomeNotice />
|
||||
)}
|
||||
|
||||
{welcome ? (
|
||||
<BouncingView
|
||||
style={{
|
||||
position: 'absolute',
|
||||
bottom: -130,
|
||||
zIndex: -1
|
||||
}}
|
||||
animated={false}
|
||||
duration={3000}
|
||||
>
|
||||
<SvgView
|
||||
width={Dimensions.get('window').width}
|
||||
height={Dimensions.get('window').width}
|
||||
src={SVG_Z}
|
||||
/>
|
||||
</BouncingView>
|
||||
) : null}
|
||||
</Animated.View>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -133,6 +133,7 @@ export const SectionItem = React.memo(
|
||||
|
||||
{item.type === 'switch' && item.property && (
|
||||
<ToggleSwitch
|
||||
//@ts-ignore
|
||||
isOn={item.getter ? item.getter(item.property || current) : settings[item.property]}
|
||||
onColor={colors.accent}
|
||||
offColor={colors.icon}
|
||||
|
||||
@@ -43,6 +43,7 @@ import { verifyUser } from './functions';
|
||||
import { SettingSection } from './types';
|
||||
import { getTimeLeft } from './user-section';
|
||||
import { ConfigureToolbar } from './editor/configure-toolbar';
|
||||
import { AuthMode } from '../../components/auth';
|
||||
const format = (ver: number) => {
|
||||
let parts = ver.toString().split('');
|
||||
return `v${parts[0]}.${parts[1]}.${parts[2]?.startsWith('0') ? '' : parts[2]}${
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { BottomTabScreenProps } from '@react-navigation/bottom-tabs';
|
||||
import { StackActions } from '@react-navigation/native';
|
||||
import { NativeStackScreenProps } from '@react-navigation/native-stack';
|
||||
import { useFavoriteStore } from '../stores/use-favorite-store';
|
||||
@@ -7,7 +6,7 @@ import { useNotebookStore } from '../stores/use-notebook-store';
|
||||
import { useNoteStore } from '../stores/use-notes-store';
|
||||
import { useTagStore } from '../stores/use-tag-store';
|
||||
import { useTrashStore } from '../stores/use-trash-store';
|
||||
import { eOnNewTopicAdded, refreshNotesPage } from '../utils/events';
|
||||
import { eOnNewTopicAdded } from '../utils/events';
|
||||
import { rootNavigatorRef, tabBarRef } from '../utils/global-refs';
|
||||
import { ColorType, NotebookType, TagType, TopicType } from '../utils/types';
|
||||
import { eSendEvent } from './event-manager';
|
||||
@@ -31,7 +30,13 @@ const routeNames = {
|
||||
TaggedNotes: 'TaggedNotes',
|
||||
ColoredNotes: 'ColoredNotes',
|
||||
TopicNotes: 'TopicNotes',
|
||||
Monographs: 'Monographs'
|
||||
Monographs: 'Monographs',
|
||||
Auth: 'Auth',
|
||||
Intro: 'Intro',
|
||||
Welcome: 'Welcome',
|
||||
AppLock: 'AppLock',
|
||||
Login: 'Login',
|
||||
Signup: 'Signup'
|
||||
};
|
||||
|
||||
type GenericRouteParam = { [name: string]: never };
|
||||
@@ -48,6 +53,14 @@ export type NotesScreenParams = {
|
||||
canGoBack: boolean;
|
||||
};
|
||||
|
||||
export type AppLockRouteParams = {
|
||||
welcome: boolean;
|
||||
};
|
||||
|
||||
export type AuthParams = {
|
||||
mode: number;
|
||||
};
|
||||
|
||||
export type RouteParams = {
|
||||
Notes: GenericRouteParam;
|
||||
Notebooks: GenericRouteParam;
|
||||
@@ -62,6 +75,8 @@ export type RouteParams = {
|
||||
ColoredNotes: NotesScreenParams;
|
||||
TopicNotes: NotesScreenParams;
|
||||
Monographs: NotesScreenParams;
|
||||
AppLock: AppLockRouteParams;
|
||||
Auth: AuthParams;
|
||||
};
|
||||
|
||||
export type NavigationProps<T extends RouteName> = NativeStackScreenProps<RouteParams, T>;
|
||||
@@ -144,10 +159,10 @@ function push(screen: CurrentScreen, params: { [name: string]: any }) {
|
||||
rootNavigatorRef.current?.dispatch(StackActions.push(name, params));
|
||||
}
|
||||
|
||||
function replace(screen: CurrentScreen, params: { [name: string]: any }) {
|
||||
useNavigationStore.getState().update(screen, !params.menu);
|
||||
function replace<T extends RouteName>(screen: CurrentScreen, params: RouteParams[T]) {
|
||||
useNavigationStore.getState().update(screen, params?.canGoBack);
|
||||
//@ts-ignore
|
||||
rootNavigatorRef.current?.dispatch(StackActions.replace(name, params));
|
||||
rootNavigatorRef.current?.dispatch(StackActions.replace(screen.name, params));
|
||||
}
|
||||
|
||||
function popToTop() {
|
||||
|
||||
@@ -4,6 +4,7 @@ import { Platform } from 'react-native';
|
||||
import Share from 'react-native-share';
|
||||
import { editing, toTXT } from '..';
|
||||
import { notesnook } from '../../../e2e/test.ids';
|
||||
import { AuthMode } from '../../components/auth';
|
||||
import { presentDialog } from '../../components/dialog/functions';
|
||||
import NoteHistory from '../../components/note-history';
|
||||
import { MoveNotes } from '../../components/sheets/move-notes/movenote';
|
||||
@@ -232,7 +233,15 @@ export const useActions = ({ close = () => {}, item }) => {
|
||||
message: 'Login to publish note',
|
||||
context: 'local',
|
||||
func: () => {
|
||||
eSendEvent(eOpenLoginDialog);
|
||||
Navigation.navigate(
|
||||
{
|
||||
name: 'Login'
|
||||
},
|
||||
{
|
||||
mode: AuthMode.login,
|
||||
canGoBack: true
|
||||
}
|
||||
);
|
||||
},
|
||||
actionText: 'Login'
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user