bug fixes in new state management and navigation

This commit is contained in:
Ammar Ahmed
2021-06-07 08:24:38 +05:00
parent 70e37dfd5b
commit 4f9d3db63a
23 changed files with 528 additions and 599 deletions

View File

@@ -6,10 +6,12 @@ import RNExitApp from 'react-native-exit-app';
import * as RNIap from 'react-native-iap'; import * as RNIap from 'react-native-iap';
import { enabled } from 'react-native-privacy-snapshot'; import { enabled } from 'react-native-privacy-snapshot';
import SplashScreen from 'react-native-splash-screen'; import SplashScreen from 'react-native-splash-screen';
import { updateEvent } from './src/components/DialogManager/recievers'; import {
import { useTracked } from './src/provider'; clearAllStores,
import { Actions } from './src/provider/Actions'; initialize,
import { clearAllStores, initialize, useNoteStore, useUserStore } from './src/provider/stores'; useNoteStore,
useUserStore
} from './src/provider/stores';
import Backup from './src/services/Backup'; import Backup from './src/services/Backup';
import BiometricService from './src/services/BiometricService'; import BiometricService from './src/services/BiometricService';
import { import {
@@ -103,17 +105,15 @@ async function reconnectSSE(connection) {
let prevState = null; let prevState = null;
let showingDialog = false; let showingDialog = false;
let removeInternetStateListener; let removeInternetStateListener;
export const AppRootEvents = React.memo( export const AppRootEvents = React.memo(
() => { () => {
const [state, dispatch] = useTracked();
const loading = useNoteStore(state => state.loading); const loading = useNoteStore(state => state.loading);
const setLastSynced = useUserStore(state => state.setLastSynced); const setLastSynced = useUserStore(state => state.setLastSynced);
const setUser = useUserStore(state => state.setUser); const setUser = useUserStore(state => state.setUser);
const setSyncing = useUserStore(state => state.setSyncing); const setSyncing = useUserStore(state => state.setSyncing);
useEffect(() => { useEffect(() => {
Appearance.addChangeListener(SettingsService.setTheme); Appearance.addChangeListener(SettingsService.setTheme);
Linking.addEventListener('url', onUrlRecieved); Linking.addEventListener('url', onUrlRecieved);
@@ -148,9 +148,6 @@ export const AppRootEvents = React.memo(
}; };
}, []); }, []);
const onSessionExpired = async () => { const onSessionExpired = async () => {
await Storage.write('loginSessionHasExpired', 'expired'); await Storage.write('loginSessionHasExpired', 'expired');
eSendEvent(eOpenLoginDialog, 4); eSendEvent(eOpenLoginDialog, 4);
@@ -203,7 +200,7 @@ export const AppRootEvents = React.memo(
const onSyncComplete = async () => { const onSyncComplete = async () => {
initialize(); initialize();
setLastSynced(await db.lastSynced()) setLastSynced(await db.lastSynced());
}; };
const onUrlRecieved = async res => { const onUrlRecieved = async res => {
@@ -233,7 +230,7 @@ export const AppRootEvents = React.memo(
}); });
if (user?.isEmailConfirmed) { if (user?.isEmailConfirmed) {
clearMessage(dispatch); clearMessage();
} }
}; };
@@ -281,13 +278,13 @@ export const AppRootEvents = React.memo(
} }
}); });
if (res !== true) throw new Error(res); if (res !== true) throw new Error(res);
setLastSynced(await db.lastSynced()) setLastSynced(await db.lastSynced());
} catch (e) { } catch (e) {
setSyncing(false); setSyncing(false);
ToastEvent.show({ ToastEvent.show({
heading: 'Sync failed', heading: 'Sync failed',
message: e.message, message: e.message,
context: "global", context: 'global',
}); });
} finally { } finally {
setSyncing(false); setSyncing(false);
@@ -330,7 +327,7 @@ export const AppRootEvents = React.memo(
const setCurrentUser = async login => { const setCurrentUser = async login => {
try { try {
if ((await MMKV.getItem('loginSessionHasExpired')) === 'expired') if ((await MMKV.getItem('loginSessionHasExpired')) === 'expired')
return; return;
let user = await db.user.getUser(); let user = await db.user.getUser();
if (user) { if (user) {
setUser(user); setUser(user);
@@ -479,7 +476,7 @@ export const AppRootEvents = React.memo(
try { try {
let user = await db.user.fetchUser(); let user = await db.user.fetchUser();
if (user.isEmailConfirmed) { if (user.isEmailConfirmed) {
onEmailVerified(dispatch); onEmailVerified();
} }
} catch (e) {} } catch (e) {}
} }

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>android</name>
<comment>Project android created by Buildship.</comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.buildship.core.gradleprojectbuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
</natures>
<filteredResources>
<filter>
<id>1622976477541</id>
<name></name>
<type>30</type>
<matcher>
<id>org.eclipse.core.resources.regexFilterMatcher</id>
<arguments>node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__</arguments>
</matcher>
</filter>
</filteredResources>
</projectDescription>

View File

@@ -0,0 +1,13 @@
arguments=
auto.sync=false
build.scans.enabled=false
connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER)
connection.project.dir=
eclipse.preferences.version=1
gradle.user.home=
java.home=/usr/lib/jvm/java-15-openjdk
jvm.arguments=
offline.mode=false
override.workspace.settings=true
show.console.view=true
show.executions.view=true

View File

@@ -1,39 +1,40 @@
import { import {
activateKeepAwake, activateKeepAwake,
deactivateKeepAwake deactivateKeepAwake,
} from '@sayem314/react-native-keep-awake'; } from '@sayem314/react-native-keep-awake';
import React, { Component, createRef, useEffect, useRef, useState } from 'react'; import React, {useEffect, useRef, useState} from 'react';
import { Dimensions, FlatList, TextInput, View } from 'react-native'; import {Dimensions, View} from 'react-native';
import Animated, { useValue } from 'react-native-reanimated'; import Animated, {useValue} from 'react-native-reanimated';
import { notesnook } from './e2e/test.ids'; import {notesnook} from './e2e/test.ids';
import ContextMenu from './src/components/ContextMenu'; import ContextMenu from './src/components/ContextMenu';
import { DialogManager } from './src/components/DialogManager'; import CustomTabs from './src/components/CustomTabs';
import { DummyText } from './src/components/DummyText'; import {DialogManager} from './src/components/DialogManager';
import { Menu } from './src/components/Menu'; import {DummyText} from './src/components/DummyText';
import { Toast } from './src/components/Toast'; import {Menu} from './src/components/Menu';
import { NavigatorStack } from './src/navigation/NavigatorStack'; import {Toast} from './src/components/Toast';
import { useTracked } from './src/provider'; import {NavigatorStack} from './src/navigation/NavigatorStack';
import { useSettingStore } from './src/provider/stores'; import {useTracked} from './src/provider';
import { DDS } from './src/services/DeviceDetection'; import {useSettingStore} from './src/provider/stores';
import {DDS} from './src/services/DeviceDetection';
import { import {
eSendEvent, eSendEvent,
eSubscribeEvent, eSubscribeEvent,
eUnSubscribeEvent eUnSubscribeEvent,
} from './src/services/EventManager'; } from './src/services/EventManager';
import { editing, setWidthHeight } from './src/utils'; import {editing, setWidthHeight} from './src/utils';
import { updateStatusBarColor } from './src/utils/Colors'; import {updateStatusBarColor} from './src/utils/Colors';
import { import {
eClearEditor, eClearEditor,
eCloseFullscreenEditor, eCloseFullscreenEditor,
eCloseSideMenu, eCloseSideMenu,
eOnLoadNote, eOnLoadNote,
eOpenFullscreenEditor, eOpenFullscreenEditor,
eOpenSideMenu eOpenSideMenu,
} from './src/utils/Events'; } from './src/utils/Events';
import { editorRef, tabBarRef } from './src/utils/Refs'; import {editorRef, tabBarRef} from './src/utils/Refs';
import { sleep } from './src/utils/TimeUtils'; import {sleep} from './src/utils/TimeUtils';
import { EditorWrapper } from './src/views/Editor/EditorWrapper'; import {EditorWrapper} from './src/views/Editor/EditorWrapper';
import { EditorWebView, getNote } from './src/views/Editor/Functions'; import {EditorWebView, getNote} from './src/views/Editor/Functions';
import tiny from './src/views/Editor/tiny/tiny'; import tiny from './src/views/Editor/tiny/tiny';
let {width, height} = Dimensions.get('window'); let {width, height} = Dimensions.get('window');
let layoutTimer = null; let layoutTimer = null;
@@ -53,7 +54,6 @@ const onChangeTab = async obj => {
!editing.isRestoringState && !editing.isRestoringState &&
(!editing.currentlyEditing || !getNote()) (!editing.currentlyEditing || !getNote())
) { ) {
console.log('new note');
eSendEvent(eOnLoadNote, {type: 'new'}); eSendEvent(eOnLoadNote, {type: 'new'});
editing.currentlyEditing = true; editing.currentlyEditing = true;
} }
@@ -82,7 +82,7 @@ export const RootView = React.memo(
() => { () => {
return ( return (
<> <>
<AppStack /> <NativeStack />
<Toast /> <Toast />
<ContextMenu /> <ContextMenu />
<DummyText /> <DummyText />
@@ -93,64 +93,15 @@ export const RootView = React.memo(
() => true, () => true,
); );
let updatedDimensions = { const NativeStack = React.memo(
width: width,
height: height,
};
let currentScroll = 0;
let startLocation = 0;
let startLocationX = 0;
const _responder = e => {
startLocation = e.nativeEvent.pageY;
startLocationX = e.nativeEvent.pageX;
_handleTouch();
return false;
};
const _moveResponder = e => {
_handleTouch();
return false;
};
let touchEndTimer = null;
const _handleTouch = () => {
{
let heightCheck = !editing.tooltip
? updatedDimensions.height - 70
: updatedDimensions.height - 140;
if (
(currentTab === 1 && startLocation > heightCheck) ||
(currentTab === 1 && startLocationX > 50) ||
(currentTab === 0 && startLocationX < 150)
) {
if (currentScroll === 0 || currentScroll === 1) {
tabBarRef.current?.setScrollEnabled(false);
}
} else {
tabBarRef.current?.setScrollEnabled(true);
}
}
};
const _onTouchEnd = e => {
startLocation = 0;
clearTimeout(touchEndTimer);
touchEndTimer = null;
touchEndTimer = setTimeout(() => {
tabBarRef.current?.setScrollEnabled(true);
}, 200);
};
const AppStack = React.memo(
() => { () => {
const [state, dispatch] = useTracked(); const [state] = useTracked();
const {colors} = state; const {colors} = state;
const deviceMode = useSettingStore(state => state.deviceMode); const deviceMode = useSettingStore(state => state.deviceMode);
const setFullscreen = useSettingStore(state => state.setFullscreen); const setFullscreen = useSettingStore(state => state.setFullscreen);
const setDeviceModeState = useSettingStore(state => state.setDeviceMode); const setDeviceModeState = useSettingStore(state => state.setDeviceMode);
const [dimensions, setDimensions] = useState({width, height}); const [dimensions, setDimensions] = useState({width, height});
const animatedOpacity = useValue(0); const animatedOpacity = useValue(0);
const overlayRef = useRef(); const overlayRef = useRef();
@@ -202,7 +153,7 @@ const AppStack = React.memo(
if (!size || (size.width === dimensions.width && deviceMode !== null)) { if (!size || (size.width === dimensions.width && deviceMode !== null)) {
DDS.setSize(size); DDS.setSize(size);
//console.log(deviceMode, 'MODE__'); //console.log(deviceMode, 'MODE__');
setDeviceModeState(deviceMode) setDeviceModeState(deviceMode);
return; return;
} }
@@ -223,16 +174,25 @@ const AppStack = React.memo(
if (DDS.isLargeTablet()) { if (DDS.isLargeTablet()) {
//console.log('setting large tab'); //console.log('setting large tab');
setDeviceMode('tablet', size); setDeviceMode('tablet', size);
tabBarRef.current?.goToIndex(0) tabBarRef.current?.goToIndex(0);
sleep(300).then(r => eSendEvent(eOpenSideMenu)); sleep(300).then(r => eSendEvent(eOpenSideMenu));
} else if (DDS.isSmallTab) { } else if (DDS.isSmallTab) {
//console.log('setting small tab'); //console.log('setting small tab');
setDeviceMode('smallTablet', size); setDeviceMode('smallTablet', size);
tabBarRef.current?.goToIndex(0) if (!editing.movedAway) {
tabBarRef.current?.goToIndex(2);
} else {
tabBarRef.current?.goToIndex(0);
}
sleep(300).then(r => eSendEvent(eOpenSideMenu)); sleep(300).then(r => eSendEvent(eOpenSideMenu));
} else { } else {
setDeviceMode('mobile', size); setDeviceMode('mobile', size);
tabBarRef.current?.goToIndex(1) if (!editing.movedAway) {
tabBarRef.current?.goToIndex(2);
} else {
tabBarRef.current?.goToIndex(1);
}
sleep(300).then(r => eSendEvent(eOpenSideMenu)); sleep(300).then(r => eSendEvent(eOpenSideMenu));
} }
} }
@@ -250,9 +210,6 @@ const AppStack = React.memo(
paddingHorizontal: 0, paddingHorizontal: 0,
}, },
}); });
if (!editing.movedAway && current !== 'tablet') {
tabBarRef.current?.goToPage(1);
}
} }
const onScroll = scrollOffset => { const onScroll = scrollOffset => {
@@ -281,6 +238,24 @@ const AppStack = React.memo(
}); });
}; };
const offsets = {
mobile: {
a: dimensions.width * 0.75,
b: dimensions.width + dimensions.width * 0.75,
c: dimensions.width * 2 + dimensions.width * 0.75,
},
smallTablet: {
a: dimensions.width,
b: dimensions.width,
c: dimensions.width * 2,
},
tablet: {
a: dimensions.width,
b: dimensions.width,
c: dimensions.width,
},
};
return ( return (
<View <View
onLayout={_onLayout} onLayout={_onLayout}
@@ -293,24 +268,14 @@ const AppStack = React.memo(
{deviceMode && ( {deviceMode && (
<CustomTabs <CustomTabs
ref={tabBarRef} ref={tabBarRef}
dimensions={dimensions}
style={{ style={{
zIndex: 1, zIndex: 1,
}} }}
onDrawerStateChange={state => { initialIndex={
//console.log(state); deviceMode === 'smallTablet' || deviceMode === 'tablet' ? 0 : 1
}} }
initialIndex={deviceMode === 'smallTablet' ? 0 : 1} offsets={offsets[deviceMode]}
offsets={{
a: deviceMode === 'smallTablet' ? dimensions.width : 300,
b:
deviceMode === 'smallTablet'
? dimensions.width
: dimensions.width + 300,
c:
deviceMode === 'smallTablet'
? dimensions.width * 2
: dimensions.width * 2 + 300,
}}
items={[ items={[
<View <View
style={{ style={{
@@ -318,7 +283,9 @@ const AppStack = React.memo(
width: width:
deviceMode === 'smallTablet' deviceMode === 'smallTablet'
? dimensions.width * 0.35 ? dimensions.width * 0.35
: 300, : deviceMode === 'smallTablet'
? dimensions.width * 0.15
: dimensions.width * 0.75,
}}> }}>
<Menu /> <Menu />
</View>, </View>,
@@ -328,6 +295,8 @@ const AppStack = React.memo(
width: width:
deviceMode === 'mobile' deviceMode === 'mobile'
? dimensions.width ? dimensions.width
: deviceMode === 'tablet'
? dimensions.width * 0.3
: dimensions.width * 0.65, : dimensions.width * 0.65,
}}> }}>
{deviceMode === 'mobile' && ( {deviceMode === 'mobile' && (
@@ -342,7 +311,7 @@ const AppStack = React.memo(
ref={overlayRef}> ref={overlayRef}>
<Animated.View <Animated.View
onTouchEnd={() => { onTouchEnd={() => {
tabBarRef.current?.goToIndex(1) tabBarRef.current?.goToIndex(1);
}} }}
style={{ style={{
backgroundColor: 'rgba(0,0,0,0.2)', backgroundColor: 'rgba(0,0,0,0.2)',
@@ -362,279 +331,8 @@ const AppStack = React.memo(
onChangeTab={onChangeTab} onChangeTab={onChangeTab}
/> />
)} )}
{/* {deviceMode !== 'tablet' && (
<View
style={{
width: dimensions.width,
height: '100%',
borderRightColor: colors.nav,
borderRightWidth: 1,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'flex-start',
}}>
{deviceMode === 'smallTablet' && (
<View
style={{
height: '100%',
width: dimensions.width * 0.35,
}}>
<Menu />
</View>
)}
<View
style={{
height: '100%',
width:
deviceMode === 'mobile'
? dimensions.width
: dimensions.width * 0.65,
}}>
<NavigatorStack />
</View>
</View>
)}
<View
style={{
width: '100%',
height: '100%',
flexDirection: 'row',
backgroundColor: colors.bg,
}}>
{deviceMode === 'tablet' && (
<View
style={{
width: dimensions.width * 0.45,
height: '100%',
borderRightColor: colors.nav,
borderRightWidth: 1,
flexDirection: 'row',
alignItems: 'center',
}}>
<View
style={{
height: '100%',
width: dimensions.width * 0.15,
}}>
<Menu />
</View>
<View
style={{
height: '100%',
width: dimensions.width * 0.3,
}}>
<NavigatorStack />
</View>
</View>
)}
<EditorWrapper dimensions={dimensions} />
</View> */}
</View> </View>
); );
}, },
() => true, () => true,
); );
class CustomTabs extends Component {
constructor(props) {
super(props);
this.listRef = createRef();
this.scrollOffset = props.initialIndex === 0 ? 0 : 300;
this.page = 0;
this.currentDrawerState = false;
this.inputElement = createRef();
this.keyboardState = false;
this.scrollTimeout = null;
this.scrollEnabled = true;
this.responderAllowedScroll = false;
}
renderItem = ({item, index}) => this.props.items[index];
onMoveShouldSetResponder = event => {
// console.log(this.responderAllowedScroll,'allowed scrolling')
if (this.responderAllowedScroll) return;
let x = event.nativeEvent.pageX;
let y = event.nativeEvent.pageY;
this.hideKeyboardIfVisible();
let cOffset = this.scrollOffset.toFixed(0);
let pOffset = this.props.offsets.b.toFixed(0);
let heightCheck = !editing.tooltip
? updatedDimensions.height - 70
: updatedDimensions.height - 140;
if (cOffset > pOffset - 50) {
if (x > 50 || y > heightCheck) {
this.responderAllowedScroll = false;
this.setScrollEnabled(false);
return;
} else {
this.responderAllowedScroll = true;
this.setScrollEnabled(true);
return;
}
}
this.responderAllowedScroll = true;
};
openDrawer = () => {
console.log('open');
if (this.page === 0) {
this.goToIndex(0);
}
};
closeDrawer = () => {
console.log('close');
if (this.page === 0) {
this.goToIndex(1);
}
};
hideKeyboardIfVisible() {
if ((editing.keyboardState || editing.isFocused) && this.scrollOffset < this.props.offsets.b - 50) {
editing.isFocused = false;
editing.keyboardState = false;
this.inputElement.current?.focus();
this.inputElement.current?.blur();
}
}
goToIndex(index, animated = true) {
// console.log('called me', index);
this.listRef.current?.scrollToIndex({
animated: animated,
index: index,
viewOffset: 0,
viewPosition: 0,
});
}
setScrollEnabled = enabled => {
this.scrollEnabled = enabled;
this.listRef.current?.getNativeScrollRef().setNativeProps({
scrollEnabled: enabled,
});
};
onTouchEnd = () => {
//console.log('touch has ended');
this.responderAllowedScroll = false;
this.listRef.current?.getNativeScrollRef().setNativeProps({
scrollEnabled: true,
});
};
onScroll = event => {
this.scrollOffset = event.nativeEvent.contentOffset.x;
if (this.page === 1) {
this.hideKeyboardIfVisible();
}
this.props.onScroll(this.scrollOffset);
if (this.scrollTimeout) {
clearTimeout(this.scrollTimeout);
this.scrollTimeout = null;
}
this.scrollTimeout = setTimeout(() => {
if (
this.scrollOffset !== this.props.offsets.a &&
this.page === 1 &&
!this.scrollEnabled
) {
this.goToIndex(2, false);
}
}, 300);
};
goToPage = page => {
if (page === 0) {
this.scrollOffset = this.props.offsets.a;
this.hideKeyboardIfVisible();
this.goToIndex(1);
} else if (page === 1) {
this.goToIndex(2);
}
if (this.page !== page) {
this.props.onChangeTab({i: page, from: this.page});
this.page = page;
}
};
keyExtractor = (item, index) => item;
onScrollEnd = event => {
//console.log('scroll end');
this.responderAllowedScroll = false;
let page = 0;
if (this.scrollOffset > this.props.offsets.b - 50) {
page = 1;
} else {
this.hideKeyboardIfVisible();
}
let drawerState = page === 0 && this.scrollOffset < 10;
if (drawerState !== this.currentDrawerState) {
this.currentDrawerState = drawerState;
this.props.onDrawerStateChange(this.currentDrawerState);
}
if (this.page !== page) {
console.log(page);
this.props.onChangeTab({i: page, from: this.page});
this.page = page;
}
};
render() {
return (
<View
onTouchEnd={this.onTouchEnd}
onMoveShouldSetResponderCapture={this.onMoveShouldSetResponder}
onStartShouldSetResponderCapture={this.onMoveShouldSetResponder}
style={{
flex: 1,
}}>
<TextInput
ref={this.inputElement}
style={{height: 1, padding: 0, width: 1, position: 'absolute'}}
blurOnSubmit={false}
/>
<FlatList
ref={this.listRef}
horizontal
onMomentumScrollEnd={this.onScrollEnd}
onScrollAnimationEnd={this.onScrollEnd}
keyExtractor={this.keyExtractor}
onScroll={this.onScroll}
bounces={false}
bouncesZoom={false}
initialNumToRender={100}
alwaysBounceHorizontal={false}
scrollToOverflowEnabled={false}
scrollsToTop={false}
scrollEventThrottle={1}
directionalLockEnabled
maintainVisibleContentPosition={true}
overScrollMode="never"
maxToRenderPerBatch={100}
removeClippedSubviews={false}
keyboardDismissMode="none"
keyboardShouldPersistTaps="always"
showsHorizontalScrollIndicator={false}
disableIntervalMomentum={true}
snapToOffsets={[
this.props.offsets.a,
this.props.offsets.b,
this.props.offsets.c,
]}
initialScrollIndex={this.props.initialIndex}
data={['drawer', 'navigation', 'editor']}
renderItem={this.renderItem}
/>
</View>
);
}
}

View File

@@ -72,6 +72,7 @@ const ActionSheetWrapper = ({
<ActionSheet <ActionSheet
ref={fwdRef} ref={fwdRef}
hideUnderlay={true} hideUnderlay={true}
containerStyle={style} containerStyle={style}
gestureEnabled={gestureEnabled} gestureEnabled={gestureEnabled}
extraScroll={largeTablet ? 50 : 0} extraScroll={largeTablet ? 50 : 0}

View File

@@ -1,5 +1,6 @@
import React, {createRef} from 'react'; import React, {createRef} from 'react';
import { import {
ActionSheetIOS,
Keyboard, Keyboard,
KeyboardAvoidingView, KeyboardAvoidingView,
Modal, Modal,
@@ -20,6 +21,7 @@ import {db} from '../../utils/DB';
import {ph, pv, SIZE} from '../../utils/SizeUtils'; import {ph, pv, SIZE} from '../../utils/SizeUtils';
import {sleep} from '../../utils/TimeUtils'; import {sleep} from '../../utils/TimeUtils';
import {ActionIcon} from '../ActionIcon'; import {ActionIcon} from '../ActionIcon';
import ActionSheetWrapper from '../ActionSheetComponent/ActionSheetWrapper';
import BaseDialog from '../Dialog/base-dialog'; import BaseDialog from '../Dialog/base-dialog';
import DialogButtons from '../Dialog/dialog-buttons'; import DialogButtons from '../Dialog/dialog-buttons';
import DialogHeader from '../Dialog/dialog-header'; import DialogHeader from '../Dialog/dialog-header';

View File

@@ -1,6 +1,6 @@
import React, {createRef} from 'react'; import React, {createRef} from 'react';
import {Actions} from '../../provider/Actions'; import {Actions} from '../../provider/Actions';
import { useMenuStore } from '../../provider/stores'; import {useMenuStore} from '../../provider/stores';
import { import {
eSubscribeEvent, eSubscribeEvent,
eUnSubscribeEvent, eUnSubscribeEvent,

View File

@@ -0,0 +1,201 @@
import React, { Component, createRef } from 'react';
import { FlatList, TextInput, View } from 'react-native';
import { editing } from '../../utils';
export default class CustomTabs extends Component {
constructor(props) {
super(props);
this.listRef = createRef();
this.scrollOffset = props.initialIndex === 0 ? 0 : this.props.offsets.a;
this.page = 0;
this.currentDrawerState = false;
this.inputElement = createRef();
this.keyboardState = false;
this.scrollTimeout = null;
this.scrollEnabled = true;
this.responderAllowedScroll = false;
}
renderItem = ({item, index}) => this.props.items[index];
onMoveShouldSetResponder = event => {
if (this.responderAllowedScroll) return;
let x = event.nativeEvent.pageX;
let y = event.nativeEvent.pageY;
this.hideKeyboardIfVisible();
let cOffset = this.scrollOffset.toFixed(0);
let pOffset = this.props.offsets.b.toFixed(0);
let heightCheck = !editing.tooltip
? this.props.dimensions.height - 70
: this.props.dimensions.height - 140;
if (cOffset > pOffset - 50) {
if (x > 50 || y > heightCheck) {
this.responderAllowedScroll = false;
this.setScrollEnabled(false);
return;
} else {
this.responderAllowedScroll = true;
this.setScrollEnabled(true);
return;
}
}
this.responderAllowedScroll = true;
};
openDrawer = () => {
if (this.page === 0) {
this.goToIndex(0);
}
};
closeDrawer = () => {
if (this.page === 0) {
this.goToIndex(1);
}
};
hideKeyboardIfVisible() {
if ((editing.keyboardState || editing.isFocused) && this.scrollOffset < this.props.offsets.b - 50) {
editing.isFocused = false;
editing.keyboardState = false;
this.inputElement.current?.focus();
this.inputElement.current?.blur();
}
}
goToIndex(index, animated = true) {
this.listRef.current?.scrollToIndex({
animated: animated,
index: index,
viewOffset: 0,
viewPosition: 0,
});
}
setScrollEnabled = enabled => {
this.scrollEnabled = enabled;
this.listRef.current?.getNativeScrollRef().setNativeProps({
scrollEnabled: enabled,
});
};
onTouchEnd = () => {
this.responderAllowedScroll = false;
this.setScrollEnabled(true)
};
onScroll = event => {
this.scrollOffset = event.nativeEvent.contentOffset.x;
if (this.page === 1) {
this.hideKeyboardIfVisible();
}
this.props.onScroll(this.scrollOffset);
if (this.scrollTimeout) {
clearTimeout(this.scrollTimeout);
this.scrollTimeout = null;
}
this.scrollTimeout = setTimeout(() => {
if (
this.scrollOffset !== this.props.offsets.a &&
this.page === 1 &&
!this.scrollEnabled
) {
this.goToIndex(2, false);
}
}, 300);
};
goToPage = page => {
if (page === 0) {
this.scrollOffset = this.props.offsets.a;
this.hideKeyboardIfVisible();
this.goToIndex(1);
} else if (page === 1) {
this.goToIndex(2);
}
if (this.page !== page) {
this.props.onChangeTab({i: page, from: this.page});
this.page = page;
}
};
keyExtractor = (item, index) => item;
onScrollEnd = event => {
this.responderAllowedScroll = false;
let page = 0;
if (this.scrollOffset > this.props.offsets.b - 50) {
page = 1;
} else {
this.hideKeyboardIfVisible();
}
let drawerState = page === 0 && this.scrollOffset < 10;
if (drawerState !== this.currentDrawerState) {
this.currentDrawerState = drawerState;
this.props.onDrawerStateChange(this.currentDrawerState);
}
if (this.page !== page) {
this.props.onChangeTab({i: page, from: this.page});
this.page = page;
}
};
render() {
return (
<View
onTouchEnd={this.onTouchEnd}
onMoveShouldSetResponderCapture={this.onMoveShouldSetResponder}
onStartShouldSetResponderCapture={this.onMoveShouldSetResponder}
style={{
flex: 1,
}}>
<TextInput
ref={this.inputElement}
style={{height: 1, padding: 0, width: 1, position: 'absolute'}}
blurOnSubmit={false}
/>
<FlatList
ref={this.listRef}
horizontal
onMomentumScrollEnd={this.onScrollEnd}
onScrollAnimationEnd={this.onScrollEnd}
keyExtractor={this.keyExtractor}
onScroll={this.onScroll}
bounces={false}
bouncesZoom={false}
initialNumToRender={100}
alwaysBounceHorizontal={false}
scrollToOverflowEnabled={false}
scrollsToTop={false}
scrollEventThrottle={1}
directionalLockEnabled
maintainVisibleContentPosition={true}
overScrollMode="never"
maxToRenderPerBatch={100}
removeClippedSubviews={false}
keyboardDismissMode="none"
keyboardShouldPersistTaps="always"
showsHorizontalScrollIndicator={false}
disableIntervalMomentum={true}
snapToOffsets={[
this.props.offsets.a,
this.props.offsets.b,
this.props.offsets.c,
]}
initialScrollIndex={this.props.initialIndex}
data={['drawer', 'navigation', 'editor']}
renderItem={this.renderItem}
/>
</View>
);
}
}
CustomTabs.defaultProps = {
onDrawerStateChange:() => {}
}

View File

@@ -6,7 +6,7 @@ import {Button} from '../Button';
import Heading from '../Typography/Heading'; import Heading from '../Typography/Heading';
import Paragraph from '../Typography/Paragraph'; import Paragraph from '../Typography/Paragraph';
const DialogHeader = ({icon, title, paragraph, button,paragraphColor}) => { const DialogHeader = ({icon, title, paragraph, button, paragraphColor}) => {
const [state, dispatch] = useTracked(); const [state, dispatch] = useTracked();
const colors = state.colors; const colors = state.colors;
@@ -46,7 +46,9 @@ const DialogHeader = ({icon, title, paragraph, button,paragraphColor}) => {
</View> </View>
{paragraph ? ( {paragraph ? (
<Paragraph color={paragraphColor || colors.icon}>{paragraph}</Paragraph> <Paragraph color={paragraphColor || colors.icon}>
{paragraph}
</Paragraph>
) : null} ) : null}
</View> </View>
</View> </View>

View File

@@ -4,7 +4,7 @@ import BaseDialog from '../../components/Dialog/base-dialog';
import {PressableButton} from '../../components/PressableButton'; import {PressableButton} from '../../components/PressableButton';
import Seperator from '../../components/Seperator'; import Seperator from '../../components/Seperator';
import {useTracked} from '../../provider'; import {useTracked} from '../../provider';
import { useNoteStore, useSettingStore } from '../../provider/stores'; import {useNoteStore, useSettingStore} from '../../provider/stores';
import {DDS} from '../../services/DeviceDetection'; import {DDS} from '../../services/DeviceDetection';
import {eSubscribeEvent, eUnSubscribeEvent} from '../../services/EventManager'; import {eSubscribeEvent, eUnSubscribeEvent} from '../../services/EventManager';
import {getElevation} from '../../utils'; import {getElevation} from '../../utils';
@@ -21,7 +21,7 @@ let timeout = null;
const JumpToDialog = ({scrollRef}) => { const JumpToDialog = ({scrollRef}) => {
const [state] = useTracked(); const [state] = useTracked();
const {colors} = state; const {colors} = state;
const notes = useNoteStore(state => state.notes); const notes = useNoteStore(state => state.notes);
const settings = useSettingStore(state => state.settings); const settings = useSettingStore(state => state.settings);
@@ -36,7 +36,10 @@ const JumpToDialog = ({scrollRef}) => {
ind = ind + 1; ind = ind + 1;
ind = ind - (index + 1); ind = ind - (index + 1);
offset = offset + ind * 100 + 200; offset = offset + ind * 100 + 200;
scrollRef.current?.scrollToOffset(0, index === 0 ? 0 : offset, true); scrollRef.current?.scrollToOffset({
offset: offset,
animated: true,
});
close(); close();
}; };

View File

@@ -9,7 +9,7 @@ import Seperator from '../../components/Seperator';
import {Toast} from '../../components/Toast'; import {Toast} from '../../components/Toast';
import {Actions} from '../../provider/Actions'; import {Actions} from '../../provider/Actions';
import {useTracked} from '../../provider/index'; import {useTracked} from '../../provider/index';
import { useUserStore } from '../../provider/stores'; import {useUserStore} from '../../provider/stores';
import BiometricService from '../../services/BiometricService'; import BiometricService from '../../services/BiometricService';
import {DDS} from '../../services/DeviceDetection'; import {DDS} from '../../services/DeviceDetection';
import { import {
@@ -74,8 +74,8 @@ const LoginDialog = () => {
const colors = state.colors; const colors = state.colors;
const setUser = useUserStore(state => state.setUser); const setUser = useUserStore(state => state.setUser);
const setLastSynced = useUserStore(state => state.setLastSynced) const setLastSynced = useUserStore(state => state.setLastSynced);
const [visible, setVisible] = useState(false); const [visible, setVisible] = useState(false);
const [status, setStatus] = useState(null); const [status, setStatus] = useState(null);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
@@ -86,7 +86,6 @@ const LoginDialog = () => {
const [confirm, setConfirm] = useState(false); const [confirm, setConfirm] = useState(false);
const insets = useSafeAreaInsets(); const insets = useSafeAreaInsets();
const _email = useRef(); const _email = useRef();
const _pass = useRef(); const _pass = useRef();
const _username = useRef(); const _username = useRef();
@@ -251,9 +250,6 @@ const LoginDialog = () => {
context: 'local', context: 'local',
}); });
close(); close();
if (MODES.sessionExpired === mode) {
await MMKV.removeItem('loginSessionHasExpired');
}
await sleep(300); await sleep(300);
eSendEvent('userLoggedIn', true); eSendEvent('userLoggedIn', true);
eSendEvent(eOpenProgressDialog, { eSendEvent(eOpenProgressDialog, {
@@ -261,6 +257,7 @@ const LoginDialog = () => {
paragraph: 'Please wait while we sync all your data.', paragraph: 'Please wait while we sync all your data.',
noProgress: false, noProgress: false,
}); });
await MMKV.removeItem('loginSessionHasExpired');
} catch (e) { } catch (e) {
setLoading(false); setLoading(false);
setStatus(null); setStatus(null);
@@ -325,7 +322,7 @@ const LoginDialog = () => {
let user = await db.user.getUser(); let user = await db.user.getUser();
setStatus('Setting Crenditials'); setStatus('Setting Crenditials');
setUser(user); setUser(user);
setLastSynced(await db.lastSynced()) setLastSynced(await db.lastSynced());
clearMessage(); clearMessage();
setEmailVerifyMessage(); setEmailVerifyMessage();
close(); close();
@@ -554,7 +551,7 @@ const LoginDialog = () => {
paddingHorizontal: 12, paddingHorizontal: 12,
height: 50, height: 50,
}}> }}>
{DDS.isTab ? ( {DDS.isTab && MODES.sessionExpired !== mode ? (
<ActionIcon <ActionIcon
name="close" name="close"
size={SIZE.xxxl} size={SIZE.xxxl}
@@ -569,7 +566,7 @@ const LoginDialog = () => {
}} }}
color={colors.heading} color={colors.heading}
/> />
) : ( ) : MODES.sessionExpired !== mode && (
<ActionIcon <ActionIcon
name="arrow-left" name="arrow-left"
size={SIZE.xxxl} size={SIZE.xxxl}
@@ -586,6 +583,7 @@ const LoginDialog = () => {
/> />
)} )}
<View /> <View />
</View> </View>

View File

@@ -94,7 +94,7 @@ export const NotebookItem = ({item, isTopic = false, notebookID, isTrash}) => {
paddingVertical: 2, paddingVertical: 2,
marginRight: 5, marginRight: 5,
marginVertical: 2.5, marginVertical: 2.5,
maxWidth: 70, maxWidth: 100,
}}> }}>
<Paragraph <Paragraph
size={SIZE.xs} size={SIZE.xs}
@@ -117,6 +117,7 @@ export const NotebookItem = ({item, isTopic = false, notebookID, isTrash}) => {
justifyContent: 'flex-start', justifyContent: 'flex-start',
alignItems: 'center', alignItems: 'center',
marginTop: 2.5, marginTop: 2.5,
minHeight:SIZE.md + 2
}}> }}>
{isTrash ? ( {isTrash ? (
<> <>

View File

@@ -1,32 +1,25 @@
import React, {useEffect, useRef, useState} from 'react'; import React, { useEffect, useRef, useState } from 'react';
import {FlatList} from 'react-native'; import { FlatList, RefreshControl } from 'react-native';
import {RefreshControl, useWindowDimensions} from 'react-native'; import { useTracked } from '../../provider';
import {DataProvider, LayoutProvider, RecyclerListView} from 'recyclerlistview';
import {useTracked} from '../../provider';
import {useMessageStore, useSettingStore} from '../../provider/stores';
import {DDS} from '../../services/DeviceDetection';
import { import {
eSendEvent, eSendEvent
eSubscribeEvent,
eUnSubscribeEvent,
} from '../../services/EventManager'; } from '../../services/EventManager';
import SettingsService from '../../services/SettingsService'; import SettingsService from '../../services/SettingsService';
import Sync from '../../services/Sync'; import Sync from '../../services/Sync';
import {dHeight, dWidth} from '../../utils'; import { COLORS_NOTE } from '../../utils/Colors';
import {COLORS_NOTE} from '../../utils/Colors'; import { eScrollEvent } from '../../utils/Events';
import {eScrollEvent} from '../../utils/Events';
import useAnnouncement from '../../utils/useAnnouncement'; import useAnnouncement from '../../utils/useAnnouncement';
import JumpToDialog from '../JumpToDialog'; import JumpToDialog from '../JumpToDialog';
import {NotebookItem} from '../NotebookItem'; import { NotebookItem } from '../NotebookItem';
import {NotebookWrapper} from '../NotebookItem/wrapper'; import { NotebookWrapper } from '../NotebookItem/wrapper';
import NoteItem from '../NoteItem'; import NoteItem from '../NoteItem';
import {NoteWrapper} from '../NoteItem/wrapper'; import { NoteWrapper } from '../NoteItem/wrapper';
import TagItem from '../TagItem'; import TagItem from '../TagItem';
import {Announcement} from './announcement'; import { Announcement } from './announcement';
import {Empty} from './empty'; import { Empty } from './empty';
import {Footer} from './footer'; import { Footer } from './footer';
import {Header} from './header'; import { Header } from './header';
import {SectionHeader} from './section-header'; import { SectionHeader } from './section-header';
const heights = { const heights = {
note: 100, note: 100,
@@ -47,6 +40,7 @@ const TrashI = ({item, index}) => {
let renderItems = { let renderItems = {
notes: NoteWrapper, notes: NoteWrapper,
notebooks: NotebookWrapper, notebooks: NotebookWrapper,
topics:NotebookWrapper,
tags: TagItem, tags: TagItem,
section: SectionHeader, section: SectionHeader,
trash: TrashI, trash: TrashI,

View File

@@ -1,5 +1,6 @@
import React from 'react'; import React from 'react';
import { import {
TouchableOpacity,
useWindowDimensions, useWindowDimensions,
View View
} from 'react-native'; } from 'react-native';
@@ -41,12 +42,15 @@ export const SectionHeader = ({
: colors.nav, : colors.nav,
marginTop: index === 0 ? 0 : 5 * fontScale, marginTop: index === 0 ? 0 : 5 * fontScale,
}}> }}>
<TouchableWithoutFeedback <TouchableOpacity
onPress={() => { onPress={() => {
console.log('called')
if (jumpToDialog) { if (jumpToDialog) {
console.log('sending event')
eSendEvent(eOpenJumpToDialog); eSendEvent(eOpenJumpToDialog);
} }
}} }}
activeOpacity={0.9}
hitSlop={{top: 10, left: 10, right: 30, bottom: 15}} hitSlop={{top: 10, left: 10, right: 30, bottom: 15}}
style={{ style={{
height: '100%', height: '100%',
@@ -62,7 +66,7 @@ export const SectionHeader = ({
}}> }}>
{!item.title || item.title === '' ? 'Pinned' : item.title} {!item.title || item.title === '' ? 'Pinned' : item.title}
</Heading> </Heading>
</TouchableWithoutFeedback> </TouchableOpacity>
{index === 0 && sortMenuButton ? <HeaderMenu /> : null} {index === 0 && sortMenuButton ? <HeaderMenu /> : null}
</View> </View>
); );

View File

@@ -1,85 +0,0 @@
import { createDrawerNavigator } from '@react-navigation/drawer';
import { NavigationContainer } from '@react-navigation/native';
import * as React from 'react';
import { State } from 'react-native-gesture-handler';
import { Menu } from '../components/Menu';
import { useTracked } from '../provider';
import { useSettingStore } from '../provider/stores';
import { eSubscribeEvent, eUnSubscribeEvent } from '../services/EventManager';
import { eCloseSideMenu, eOpenSideMenu } from '../utils/Events';
import { sideMenuRef, tabBarRef } from '../utils/Refs';
import { NavigatorStack } from './NavigatorStack';
const Drawer = createDrawerNavigator();
const onStateChange = state => {
let s = state[0];
if (s && s !== State.ACTIVE && s !== State.BEGAN) {
let state = sideMenuRef.current.getRootState();
if (state.history.findIndex(o => o.type === 'drawer') === -1) {
tabBarRef.current?.setScrollEnabled(true);
}
}
};
const onNavigatorStateChange = e => {
if (e.history.find(i => i.type === 'drawer')) {
//changeContainerScale(ContainerScale, 0.95, 250);
//changeContainerScale(DrawerScale, 1, 250);
} else {
//changeContainerScale(DrawerScale, 0.95, 250);
//changeContainerScale(ContainerScale, 1, 250);
}
};
export const NavigationStack = ({component = NavigatorStack}) => {
const deviceMode = useSettingStore(state => state.deviceMode);
const [locked, setLocked] = React.useState(false);
const setGestureDisabled = () => {
setLocked(true);
};
const setGestureEnabled = () => {
if (locked) {
setLocked(false);
}
};
React.useEffect(() => {
eSubscribeEvent(eOpenSideMenu, setGestureEnabled);
eSubscribeEvent(eCloseSideMenu, setGestureDisabled);
return () => {
eUnSubscribeEvent(eOpenSideMenu, setGestureEnabled);
eUnSubscribeEvent(eCloseSideMenu, setGestureDisabled);
};
}, [locked]);
return (
<NavigationContainer
//onStateChange={onNavigatorStateChange}
ref={sideMenuRef}>
<Drawer.Navigator
screenOptions={{
swipeEnabled: locked || deviceMode !== 'mobile' ? false : true,
gestureEnabled: locked || deviceMode !== 'mobile' ? false : true,
}}
onStateChange={onStateChange}
drawerStyle={{
width: deviceMode !== 'mobile' ? 0 : '75%',
borderRightWidth: 0,
}}
edgeWidth={200}
drawerType="slide"
drawerContent={deviceMode !== 'mobile' ? () => <></> : DrawerComponent}
initialRouteName="Main">
<Drawer.Screen name="Main" component={component} />
</Drawer.Navigator>
</NavigationContainer>
);
};
const DrawerComponent = () => {
return <Menu />;
};

View File

@@ -1,27 +1,24 @@
import {NavigationContainer} from '@react-navigation/native'; import { NavigationContainer } from '@react-navigation/native';
import * as React from 'react'; import * as React from 'react';
import {Animated} from 'react-native'; import { createNativeStackNavigator } from 'react-native-screens/native-stack';
import {createNativeStackNavigator} from 'react-native-screens/native-stack';
import Container from '../components/Container'; import Container from '../components/Container';
import {useTracked} from '../provider';
import {Actions} from '../provider/Actions';
import { useSelectionStore } from '../provider/stores'; import { useSelectionStore } from '../provider/stores';
import { import {
eSendEvent, eSendEvent,
eSubscribeEvent, eSubscribeEvent,
eUnSubscribeEvent, eUnSubscribeEvent
} from '../services/EventManager'; } from '../services/EventManager';
import Navigation from '../services/Navigation'; import Navigation from '../services/Navigation';
import SettingsService from '../services/SettingsService'; import SettingsService from '../services/SettingsService';
import {history} from '../utils'; import { history } from '../utils';
import {eOpenSideMenu} from '../utils/Events'; import { eOpenSideMenu } from '../utils/Events';
import {rootNavigatorRef} from '../utils/Refs'; import { rootNavigatorRef } from '../utils/Refs';
import Favorites from '../views/Favorites'; import Favorites from '../views/Favorites';
import Folders from '../views/Folders'; import Folders from '../views/Folders';
import Home from '../views/Home'; import Home from '../views/Home';
import Notebook from '../views/Notebook'; import Notebook from '../views/Notebook';
import Notes from '../views/Notes'; import Notes from '../views/Notes';
import {Search} from '../views/Search'; import { Search } from '../views/Search';
import Settings from '../views/Settings'; import Settings from '../views/Settings';
import Tags from '../views/Tags'; import Tags from '../views/Tags';
import Trash from '../views/Trash'; import Trash from '../views/Trash';
@@ -34,44 +31,6 @@ const forFade = ({current}) => ({
}, },
}); });
const forSlide = ({current, next, inverted, layouts: {screen}}) => {
const progress = Animated.add(
current.progress.interpolate({
inputRange: [0, 1],
outputRange: [0, 1],
extrapolate: 'clamp',
}),
next
? next.progress.interpolate({
inputRange: [0, 1],
outputRange: [0, 1],
extrapolate: 'clamp',
})
: 0,
);
return {
cardStyle: {
transform: [
{
translateX: Animated.multiply(
progress.interpolate({
inputRange: [0, 1, 2],
outputRange: [
screen.width, // Focused, but offscreen in the beginning
0, // Fully focused
screen.width * -0.3, // Fully unfocused
],
extrapolate: 'clamp',
}),
inverted,
),
},
],
},
};
};
const screenOptionsForAnimation = { const screenOptionsForAnimation = {
animationEnabled: true, animationEnabled: true,
cardStyleInterpolator: forFade, cardStyleInterpolator: forFade,
@@ -80,7 +39,6 @@ const screenOptionsForAnimation = {
export const NavigatorStack = React.memo( export const NavigatorStack = React.memo(
() => { () => {
const [, dispatch] = useTracked();
const [render, setRender] = React.useState(true); const [render, setRender] = React.useState(true);
const clearSelection = useSelectionStore(state => state.clearSelection); const clearSelection = useSelectionStore(state => state.clearSelection);
const onStateChange = React.useCallback(() => { const onStateChange = React.useCallback(() => {
@@ -124,9 +82,8 @@ export const NavigatorStack = React.memo(
initialRouteName={SettingsService.get().homepage} initialRouteName={SettingsService.get().homepage}
screenOptions={{ screenOptions={{
headerShown: false, headerShown: false,
animationEnabled: false,
gestureEnabled: false, gestureEnabled: false,
stackAnimation: 'none', stackAnimation: 'fade',
}}> }}>
<Stack.Screen name="Notes" component={Home} /> <Stack.Screen name="Notes" component={Home} />
<Stack.Screen name="Notebooks" component={Folders} /> <Stack.Screen name="Notebooks" component={Folders} />

View File

@@ -73,13 +73,20 @@ export type Settings = {
appLockMode?: string, appLockMode?: string,
} }
type Dimensions = {
width:number,
height:number
}
export interface SettingStore extends State { export interface SettingStore extends State {
settings: Settings, settings: Settings,
fullscreen: boolean, fullscreen: boolean,
deviceMode: string | null, deviceMode: string | null,
dimensions:Dimensions
setSettings: (settings: Settings) => void, setSettings: (settings: Settings) => void,
setFullscreen: (fullscreen: boolean) => void, setFullscreen: (fullscreen: boolean) => void,
setDeviceMode: (mode: string) => void setDeviceMode: (mode: string) => void,
setDimensions: (dimensions:Dimensions) => void
} }

View File

@@ -1,3 +1,4 @@
import { Dimensions } from 'react-native';
import create, {State} from 'zustand'; import create, {State} from 'zustand';
import {eSendEvent} from '../services/EventManager'; import {eSendEvent} from '../services/EventManager';
import {history, SORT, sortSettings} from '../utils'; import {history, SORT, sortSettings} from '../utils';
@@ -143,6 +144,8 @@ export const useUserStore = create<UserStore>((set, get) => ({
setLastSynced: lastSynced => set({lastSynced: lastSynced}), setLastSynced: lastSynced => set({lastSynced: lastSynced}),
})); }));
let {width, height} = Dimensions.get('window');
export const useSettingStore = create<SettingStore>((set, get) => ({ export const useSettingStore = create<SettingStore>((set, get) => ({
settings: { settings: {
showToolbarOnTop: false, showToolbarOnTop: false,
@@ -161,9 +164,11 @@ export const useSettingStore = create<SettingStore>((set, get) => ({
}, },
fullscreen: false, fullscreen: false,
deviceMode: null, deviceMode: null,
dimensions:{width,height},
setSettings: settings => set({settings}), setSettings: settings => set({settings}),
setFullscreen: fullscreen => set({fullscreen}), setFullscreen: fullscreen => set({fullscreen}),
setDeviceMode: mode => set({deviceMode: mode}), setDeviceMode: mode => set({deviceMode: mode}),
setDimensions: dimensions => set({dimensions:dimensions})
})); }));
export const useMenuStore = create<MenuStore>((set, get) => ({ export const useMenuStore = create<MenuStore>((set, get) => ({

View File

@@ -52,6 +52,9 @@ async function clear() {
} }
async function encrypt(password, data) { async function encrypt(password, data) {
if (!password.password && !password.key) return undefined
if (password.password && password.password === "" && !password.key) return undefined
let message = { let message = {
type: 'plain', type: 'plain',
data: data, data: data,
@@ -69,6 +72,8 @@ function getAlgorithm(base64Variant) {
} }
async function decrypt(password, data) { async function decrypt(password, data) {
if (!password.password && !password.key) return undefined
if (password.password && password.password === "" && !password.key) return undefined
data.output = 'plain'; data.output = 'plain';
return await Sodium.decrypt(password, data); return await Sodium.decrypt(password, data);
} }

View File

@@ -13,6 +13,8 @@ import {
eUnSubscribeEvent, eUnSubscribeEvent,
} from '../../services/EventManager'; } from '../../services/EventManager';
import {getCurrentColors} from '../../utils/Colors'; import {getCurrentColors} from '../../utils/Colors';
import { eOpenLoginDialog } from '../../utils/Events';
import { MMKV } from '../../utils/mmkv';
import {normalize} from '../../utils/SizeUtils'; import {normalize} from '../../utils/SizeUtils';
import {sleep} from '../../utils/TimeUtils'; import {sleep} from '../../utils/TimeUtils';
import EditorHeader from './EditorHeader'; import EditorHeader from './EditorHeader';
@@ -55,6 +57,11 @@ const Editor = React.memo(
}; };
useEffect(()=>{ useEffect(()=>{
setTimeout(async () => {
if ((await MMKV.getItem('loginSessionHasExpired')) === 'expired')
eSendEvent(eOpenLoginDialog, 4);
}, 1000);
if (premiumUser) { if (premiumUser) {
tiny.call(EditorWebView,tiny.setMarkdown,true) tiny.call(EditorWebView,tiny.setMarkdown,true)
} }

View File

@@ -14,6 +14,7 @@ import SearchService from '../../services/SearchService';
import { InteractionManager, scrollRef } from '../../utils'; import { InteractionManager, scrollRef } from '../../utils';
import { db } from '../../utils/DB'; import { db } from '../../utils/DB';
import { eOnLoadNote, eScrollEvent } from '../../utils/Events'; import { eOnLoadNote, eScrollEvent } from '../../utils/Events';
import { MMKV } from '../../utils/mmkv';
import { tabBarRef } from '../../utils/Refs'; import { tabBarRef } from '../../utils/Refs';
import Storage from '../../utils/storage'; import Storage from '../../utils/storage';
@@ -83,11 +84,6 @@ export const Home = ({navigation}) => {
}; };
const _onPressBottomButton = React.useCallback(async () => { const _onPressBottomButton = React.useCallback(async () => {
let result = Storage.encrypt({
password:""
},"hello world");
console.log(result);
return;
if (!DDS.isLargeTablet()) { if (!DDS.isLargeTablet()) {
eSendEvent(eOnLoadNote, {type: 'new'}); eSendEvent(eOnLoadNote, {type: 'new'});
tabBarRef.current?.goToPage(1); tabBarRef.current?.goToPage(1);

View File

@@ -73,7 +73,7 @@ export const Notebook = ({route, navigation}) => {
ranAfterInteractions = true; ranAfterInteractions = true;
runAfterInteractions(); runAfterInteractions();
} }
Navigation.setHeaderState('Notebooks', params, { Navigation.setHeaderState('Notebook', params, {
heading: params.title, heading: params.title,
id: params.notebook.id, id: params.notebook.id,
type: 'notebook', type: 'notebook',

View File

@@ -1,5 +1,11 @@
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import React, {createRef, useCallback, useEffect, useState} from 'react'; import React, {
createRef,
useCallback,
useEffect,
useRef,
useState,
} from 'react';
import { import {
Appearance, Appearance,
Linking, Linking,
@@ -28,7 +34,11 @@ import Heading from '../../components/Typography/Heading';
import Paragraph from '../../components/Typography/Paragraph'; import Paragraph from '../../components/Typography/Paragraph';
import {useTracked} from '../../provider'; import {useTracked} from '../../provider';
import {Actions} from '../../provider/Actions'; import {Actions} from '../../provider/Actions';
import { useMessageStore, useSettingStore, useUserStore } from '../../provider/stores'; import {
useMessageStore,
useSettingStore,
useUserStore,
} from '../../provider/stores';
import Backup from '../../services/Backup'; import Backup from '../../services/Backup';
import BiometricService from '../../services/BiometricService'; import BiometricService from '../../services/BiometricService';
import {DDS} from '../../services/DeviceDetection'; import {DDS} from '../../services/DeviceDetection';
@@ -72,6 +82,7 @@ import {
} from '../../utils/Events'; } from '../../utils/Events';
import {openLinkInBrowser} from '../../utils/functions'; import {openLinkInBrowser} from '../../utils/functions';
import {MMKV} from '../../utils/mmkv'; import {MMKV} from '../../utils/mmkv';
import {tabBarRef} from '../../utils/Refs';
import {pv, SIZE} from '../../utils/SizeUtils'; import {pv, SIZE} from '../../utils/SizeUtils';
import Storage from '../../utils/storage'; import Storage from '../../utils/storage';
import {sleep, timeConverter} from '../../utils/TimeUtils'; import {sleep, timeConverter} from '../../utils/TimeUtils';
@@ -579,23 +590,53 @@ const getTimeLeft = t2 => {
}; };
}; };
let passwordVerifyValue = null;
const SettingsUserSection = () => { const SettingsUserSection = () => {
const [state] = useTracked(); const [state] = useTracked();
const {colors} = state; const {colors} = state;
const user = useUserStore(state => state.user); const user = useUserStore(state => state.user);
const messageBoardState = useMessageStore(state => state.message); const messageBoardState = useMessageStore(state => state.message);
const [verifyUser, setVerifyUser] = useState(false);
const subscriptionDaysLeft = const subscriptionDaysLeft =
user && getTimeLeft(parseInt(user.subscription?.expiry)); user && getTimeLeft(parseInt(user.subscription?.expiry));
const isExpired = user && subscriptionDaysLeft.time < 0; const isExpired = user && subscriptionDaysLeft.time < 0;
const expiryDate = dayjs(user?.subscription?.expiry).format( const expiryDate = dayjs(user?.subscription?.expiry).format('MMMM D, YYYY');
'MMMM D, YYYY', const startDate = dayjs(user?.subscription?.start).format('MMMM D, YYYY');
); const input = useRef();
const startDate = dayjs(user?.subscription?.start).format( const tryVerification = async () => {
'MMMM D, YYYY', if (!passwordVerifyValue) {
) ToastEvent.show({
console.log(user?.subscription) heading: 'Account Password is required',
type: 'error',
context: 'local',
});
return;
}
try {
let verify = await db.user.verifyPassword(passwordVerifyValue);
if (verify) {
setVerifyUser(false);
passwordVerifyValue = null;
await sleep(300);
eSendEvent(eOpenRecoveryKeyDialog);
} else {
ToastEvent.show({
heading: 'Incorrect password',
message: 'Please enter the correct password to save recovery key.',
type: 'error',
context: 'local',
});
}
} catch (e) {
ToastEvent.show({
heading: 'Incorrect password',
message: e.message,
type: 'error',
context: 'local',
});
}
};
return ( return (
<> <>
@@ -757,11 +798,9 @@ const SettingsUserSection = () => {
</Paragraph> </Paragraph>
<Paragraph color={colors.pri}> <Paragraph color={colors.pri}>
{user.subscription.type === 2 {user.subscription.type === 2
? 'You signed up on ' + ? 'You signed up on ' + startDate
startDate
: user.subscription.type === 1 : user.subscription.type === 1
? 'Your trial period started on ' + ? 'Your trial period started on ' + startDate
startDate
: user.subscription.type === 6 : user.subscription.type === 6
? subscriptionDaysLeft.time < -3 ? subscriptionDaysLeft.time < -3
? 'Your subscription has ended' ? 'Your subscription has ended'
@@ -786,7 +825,7 @@ const SettingsUserSection = () => {
}} }}
width="100%" width="100%"
style={{ style={{
paddingHorizontal:0 paddingHorizontal: 0,
}} }}
fontSize={SIZE.md} fontSize={SIZE.md}
title={ title={
@@ -847,21 +886,71 @@ const SettingsUserSection = () => {
) : null} ) : null}
</View> </View>
</View> </View>
{verifyUser && (
<BaseDialog
onRequestClose={() => {
setVerifyUser(false);
passwordVerifyValue = null;
}}
onShow={() => {
setTimeout(() => {
input.current?.focus();
}, 300);
}}
statusBarTranslucent={false}
visible={true}>
<DialogContainer>
<DialogHeader
title="Verify it's you"
paragraph="To save your account recovery key, enter your account password"
/>
<Input
fwdRef={input}
placeholder="Enter account password"
onChangeText={v => {
passwordVerifyValue = v;
}}
onSubmit={tryVerification}
secureTextEntry={true}
/>
<View
style={{
flexDirection: 'row',
alignItems: 'center',
alignSelf: 'flex-end',
}}>
<Button
onPress={() => {
setVerifyUser(false);
passwordVerifyValue = null;
}}
fontSize={SIZE.md}
type="gray"
title="Cancel"
/>
<Button
onPress={tryVerification}
fontSize={SIZE.md}
style={{
marginLeft: 10,
}}
type="transparent"
title="Verify"
/>
</View>
</DialogContainer>
<Toast context="local" />
</BaseDialog>
)}
{[ {[
{ {
name: 'Save data recovery key', name: 'Save data recovery key',
func: async () => { func: async () => {
if (BiometricService.isBiometryAvailable() === false) { setVerifyUser(true);
eSendEvent(eOpenRecoveryKeyDialog);
return;
}
let result = await BiometricService.validateUser(
"Verify it's you",
'',
);
if (result) {
eSendEvent(eOpenRecoveryKeyDialog);
}
}, },
desc: desc:
'Recover your data using the recovery key if your password is lost.', 'Recover your data using the recovery key if your password is lost.',
@@ -876,11 +965,10 @@ const SettingsUserSection = () => {
{ {
name: 'Having problems with syncing?', name: 'Having problems with syncing?',
func: async () => { func: async () => {
await Sync.run("global",true); await Sync.run('global', true);
}, },
desc: 'Try force sync to resolve issues with syncing.', desc: 'Try force sync to resolve issues with syncing.',
}, },
].map(item => ( ].map(item => (
<CustomButton <CustomButton
key={item.name} key={item.name}
@@ -958,6 +1046,12 @@ const SettingsAppearanceSection = () => {
<ScrollView <ScrollView
horizontal={true} horizontal={true}
showsHorizontalScrollIndicator={false} showsHorizontalScrollIndicator={false}
onMoveShouldSetResponderCapture={() => {
tabBarRef.current?.setScrollEnabled(false);
}}
onMomentumScrollEnd={() => {
tabBarRef.current?.setScrollEnabled(true);
}}
style={{ style={{
borderRadius: 5, borderRadius: 5,
padding: 5, padding: 5,
@@ -966,6 +1060,7 @@ const SettingsAppearanceSection = () => {
width: '100%', width: '100%',
paddingHorizontal: 12, paddingHorizontal: 12,
}} }}
nestedScrollEnabled
contentContainerStyle={{ contentContainerStyle={{
alignSelf: 'center', alignSelf: 'center',
flexDirection: 'row', flexDirection: 'row',
@@ -1365,7 +1460,7 @@ const SettingsBackupAndRestore = () => {
const {colors} = state; const {colors} = state;
const settings = useSettingStore(state => state.settings); const settings = useSettingStore(state => state.settings);
const user = useUserStore(state => state.user); const user = useUserStore(state => state.user);
const backupItemsList = [ const backupItemsList = [
{ {
name: 'Backup data', name: 'Backup data',