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 { enabled } from 'react-native-privacy-snapshot';
import SplashScreen from 'react-native-splash-screen';
import { updateEvent } from './src/components/DialogManager/recievers';
import { useTracked } from './src/provider';
import { Actions } from './src/provider/Actions';
import { clearAllStores, initialize, useNoteStore, useUserStore } from './src/provider/stores';
import {
clearAllStores,
initialize,
useNoteStore,
useUserStore
} from './src/provider/stores';
import Backup from './src/services/Backup';
import BiometricService from './src/services/BiometricService';
import {
@@ -103,17 +105,15 @@ async function reconnectSSE(connection) {
let prevState = null;
let showingDialog = false;
let removeInternetStateListener;
export const AppRootEvents = React.memo(
() => {
const [state, dispatch] = useTracked();
const loading = useNoteStore(state => state.loading);
const setLastSynced = useUserStore(state => state.setLastSynced);
const setUser = useUserStore(state => state.setUser);
const setSyncing = useUserStore(state => state.setSyncing);
useEffect(() => {
Appearance.addChangeListener(SettingsService.setTheme);
Linking.addEventListener('url', onUrlRecieved);
@@ -148,9 +148,6 @@ export const AppRootEvents = React.memo(
};
}, []);
const onSessionExpired = async () => {
await Storage.write('loginSessionHasExpired', 'expired');
eSendEvent(eOpenLoginDialog, 4);
@@ -203,7 +200,7 @@ export const AppRootEvents = React.memo(
const onSyncComplete = async () => {
initialize();
setLastSynced(await db.lastSynced())
setLastSynced(await db.lastSynced());
};
const onUrlRecieved = async res => {
@@ -233,7 +230,7 @@ export const AppRootEvents = React.memo(
});
if (user?.isEmailConfirmed) {
clearMessage(dispatch);
clearMessage();
}
};
@@ -281,13 +278,13 @@ export const AppRootEvents = React.memo(
}
});
if (res !== true) throw new Error(res);
setLastSynced(await db.lastSynced())
setLastSynced(await db.lastSynced());
} catch (e) {
setSyncing(false);
ToastEvent.show({
heading: 'Sync failed',
message: e.message,
context: "global",
context: 'global',
});
} finally {
setSyncing(false);
@@ -479,7 +476,7 @@ export const AppRootEvents = React.memo(
try {
let user = await db.user.fetchUser();
if (user.isEmailConfirmed) {
onEmailVerified(dispatch);
onEmailVerified();
}
} 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,12 +1,13 @@
import {
activateKeepAwake,
deactivateKeepAwake
deactivateKeepAwake,
} from '@sayem314/react-native-keep-awake';
import React, { Component, createRef, useEffect, useRef, useState } from 'react';
import { Dimensions, FlatList, TextInput, View } from 'react-native';
import React, {useEffect, useRef, useState} from 'react';
import {Dimensions, View} from 'react-native';
import Animated, {useValue} from 'react-native-reanimated';
import {notesnook} from './e2e/test.ids';
import ContextMenu from './src/components/ContextMenu';
import CustomTabs from './src/components/CustomTabs';
import {DialogManager} from './src/components/DialogManager';
import {DummyText} from './src/components/DummyText';
import {Menu} from './src/components/Menu';
@@ -18,7 +19,7 @@ import { DDS } from './src/services/DeviceDetection';
import {
eSendEvent,
eSubscribeEvent,
eUnSubscribeEvent
eUnSubscribeEvent,
} from './src/services/EventManager';
import {editing, setWidthHeight} from './src/utils';
import {updateStatusBarColor} from './src/utils/Colors';
@@ -28,7 +29,7 @@ import {
eCloseSideMenu,
eOnLoadNote,
eOpenFullscreenEditor,
eOpenSideMenu
eOpenSideMenu,
} from './src/utils/Events';
import {editorRef, tabBarRef} from './src/utils/Refs';
import {sleep} from './src/utils/TimeUtils';
@@ -53,7 +54,6 @@ const onChangeTab = async obj => {
!editing.isRestoringState &&
(!editing.currentlyEditing || !getNote())
) {
console.log('new note');
eSendEvent(eOnLoadNote, {type: 'new'});
editing.currentlyEditing = true;
}
@@ -82,7 +82,7 @@ export const RootView = React.memo(
() => {
return (
<>
<AppStack />
<NativeStack />
<Toast />
<ContextMenu />
<DummyText />
@@ -93,58 +93,9 @@ export const RootView = React.memo(
() => true,
);
let updatedDimensions = {
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 NativeStack = React.memo(
() => {
const [state, dispatch] = useTracked();
const [state] = useTracked();
const {colors} = state;
const deviceMode = useSettingStore(state => state.deviceMode);
@@ -202,7 +153,7 @@ const AppStack = React.memo(
if (!size || (size.width === dimensions.width && deviceMode !== null)) {
DDS.setSize(size);
//console.log(deviceMode, 'MODE__');
setDeviceModeState(deviceMode)
setDeviceModeState(deviceMode);
return;
}
@@ -223,16 +174,25 @@ const AppStack = React.memo(
if (DDS.isLargeTablet()) {
//console.log('setting large tab');
setDeviceMode('tablet', size);
tabBarRef.current?.goToIndex(0)
tabBarRef.current?.goToIndex(0);
sleep(300).then(r => eSendEvent(eOpenSideMenu));
} else if (DDS.isSmallTab) {
//console.log('setting small tab');
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));
} else {
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));
}
}
@@ -250,9 +210,6 @@ const AppStack = React.memo(
paddingHorizontal: 0,
},
});
if (!editing.movedAway && current !== 'tablet') {
tabBarRef.current?.goToPage(1);
}
}
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 (
<View
onLayout={_onLayout}
@@ -293,24 +268,14 @@ const AppStack = React.memo(
{deviceMode && (
<CustomTabs
ref={tabBarRef}
dimensions={dimensions}
style={{
zIndex: 1,
}}
onDrawerStateChange={state => {
//console.log(state);
}}
initialIndex={deviceMode === 'smallTablet' ? 0 : 1}
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,
}}
initialIndex={
deviceMode === 'smallTablet' || deviceMode === 'tablet' ? 0 : 1
}
offsets={offsets[deviceMode]}
items={[
<View
style={{
@@ -318,7 +283,9 @@ const AppStack = React.memo(
width:
deviceMode === 'smallTablet'
? dimensions.width * 0.35
: 300,
: deviceMode === 'smallTablet'
? dimensions.width * 0.15
: dimensions.width * 0.75,
}}>
<Menu />
</View>,
@@ -328,6 +295,8 @@ const AppStack = React.memo(
width:
deviceMode === 'mobile'
? dimensions.width
: deviceMode === 'tablet'
? dimensions.width * 0.3
: dimensions.width * 0.65,
}}>
{deviceMode === 'mobile' && (
@@ -342,7 +311,7 @@ const AppStack = React.memo(
ref={overlayRef}>
<Animated.View
onTouchEnd={() => {
tabBarRef.current?.goToIndex(1)
tabBarRef.current?.goToIndex(1);
}}
style={{
backgroundColor: 'rgba(0,0,0,0.2)',
@@ -362,279 +331,8 @@ const AppStack = React.memo(
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>
);
},
() => 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
ref={fwdRef}
hideUnderlay={true}
containerStyle={style}
gestureEnabled={gestureEnabled}
extraScroll={largeTablet ? 50 : 0}

View File

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

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

@@ -46,7 +46,9 @@ const DialogHeader = ({icon, title, paragraph, button,paragraphColor}) => {
</View>
{paragraph ? (
<Paragraph color={paragraphColor || colors.icon}>{paragraph}</Paragraph>
<Paragraph color={paragraphColor || colors.icon}>
{paragraph}
</Paragraph>
) : null}
</View>
</View>

View File

@@ -36,7 +36,10 @@ const JumpToDialog = ({scrollRef}) => {
ind = ind + 1;
ind = ind - (index + 1);
offset = offset + ind * 100 + 200;
scrollRef.current?.scrollToOffset(0, index === 0 ? 0 : offset, true);
scrollRef.current?.scrollToOffset({
offset: offset,
animated: true,
});
close();
};

View File

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

View File

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

View File

@@ -1,18 +1,11 @@
import React, { useEffect, useRef, useState } from 'react';
import {FlatList} from 'react-native';
import {RefreshControl, useWindowDimensions} from 'react-native';
import {DataProvider, LayoutProvider, RecyclerListView} from 'recyclerlistview';
import { FlatList, RefreshControl } from 'react-native';
import { useTracked } from '../../provider';
import {useMessageStore, useSettingStore} from '../../provider/stores';
import {DDS} from '../../services/DeviceDetection';
import {
eSendEvent,
eSubscribeEvent,
eUnSubscribeEvent,
eSendEvent
} from '../../services/EventManager';
import SettingsService from '../../services/SettingsService';
import Sync from '../../services/Sync';
import {dHeight, dWidth} from '../../utils';
import { COLORS_NOTE } from '../../utils/Colors';
import { eScrollEvent } from '../../utils/Events';
import useAnnouncement from '../../utils/useAnnouncement';
@@ -47,6 +40,7 @@ const TrashI = ({item, index}) => {
let renderItems = {
notes: NoteWrapper,
notebooks: NotebookWrapper,
topics:NotebookWrapper,
tags: TagItem,
section: SectionHeader,
trash: TrashI,

View File

@@ -1,5 +1,6 @@
import React from 'react';
import {
TouchableOpacity,
useWindowDimensions,
View
} from 'react-native';
@@ -41,12 +42,15 @@ export const SectionHeader = ({
: colors.nav,
marginTop: index === 0 ? 0 : 5 * fontScale,
}}>
<TouchableWithoutFeedback
<TouchableOpacity
onPress={() => {
console.log('called')
if (jumpToDialog) {
console.log('sending event')
eSendEvent(eOpenJumpToDialog);
}
}}
activeOpacity={0.9}
hitSlop={{top: 10, left: 10, right: 30, bottom: 15}}
style={{
height: '100%',
@@ -62,7 +66,7 @@ export const SectionHeader = ({
}}>
{!item.title || item.title === '' ? 'Pinned' : item.title}
</Heading>
</TouchableWithoutFeedback>
</TouchableOpacity>
{index === 0 && sortMenuButton ? <HeaderMenu /> : null}
</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,15 +1,12 @@
import { NavigationContainer } from '@react-navigation/native';
import * as React from 'react';
import {Animated} from 'react-native';
import { createNativeStackNavigator } from 'react-native-screens/native-stack';
import Container from '../components/Container';
import {useTracked} from '../provider';
import {Actions} from '../provider/Actions';
import { useSelectionStore } from '../provider/stores';
import {
eSendEvent,
eSubscribeEvent,
eUnSubscribeEvent,
eUnSubscribeEvent
} from '../services/EventManager';
import Navigation from '../services/Navigation';
import SettingsService from '../services/SettingsService';
@@ -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 = {
animationEnabled: true,
cardStyleInterpolator: forFade,
@@ -80,7 +39,6 @@ const screenOptionsForAnimation = {
export const NavigatorStack = React.memo(
() => {
const [, dispatch] = useTracked();
const [render, setRender] = React.useState(true);
const clearSelection = useSelectionStore(state => state.clearSelection);
const onStateChange = React.useCallback(() => {
@@ -124,9 +82,8 @@ export const NavigatorStack = React.memo(
initialRouteName={SettingsService.get().homepage}
screenOptions={{
headerShown: false,
animationEnabled: false,
gestureEnabled: false,
stackAnimation: 'none',
stackAnimation: 'fade',
}}>
<Stack.Screen name="Notes" component={Home} />
<Stack.Screen name="Notebooks" component={Folders} />

View File

@@ -73,13 +73,20 @@ export type Settings = {
appLockMode?: string,
}
type Dimensions = {
width:number,
height:number
}
export interface SettingStore extends State {
settings: Settings,
fullscreen: boolean,
deviceMode: string | null,
dimensions:Dimensions
setSettings: (settings: Settings) => 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 {eSendEvent} from '../services/EventManager';
import {history, SORT, sortSettings} from '../utils';
@@ -143,6 +144,8 @@ export const useUserStore = create<UserStore>((set, get) => ({
setLastSynced: lastSynced => set({lastSynced: lastSynced}),
}));
let {width, height} = Dimensions.get('window');
export const useSettingStore = create<SettingStore>((set, get) => ({
settings: {
showToolbarOnTop: false,
@@ -161,9 +164,11 @@ export const useSettingStore = create<SettingStore>((set, get) => ({
},
fullscreen: false,
deviceMode: null,
dimensions:{width,height},
setSettings: settings => set({settings}),
setFullscreen: fullscreen => set({fullscreen}),
setDeviceMode: mode => set({deviceMode: mode}),
setDimensions: dimensions => set({dimensions:dimensions})
}));
export const useMenuStore = create<MenuStore>((set, get) => ({

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,5 +1,11 @@
import dayjs from 'dayjs';
import React, {createRef, useCallback, useEffect, useState} from 'react';
import React, {
createRef,
useCallback,
useEffect,
useRef,
useState,
} from 'react';
import {
Appearance,
Linking,
@@ -28,7 +34,11 @@ import Heading from '../../components/Typography/Heading';
import Paragraph from '../../components/Typography/Paragraph';
import {useTracked} from '../../provider';
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 BiometricService from '../../services/BiometricService';
import {DDS} from '../../services/DeviceDetection';
@@ -72,6 +82,7 @@ import {
} from '../../utils/Events';
import {openLinkInBrowser} from '../../utils/functions';
import {MMKV} from '../../utils/mmkv';
import {tabBarRef} from '../../utils/Refs';
import {pv, SIZE} from '../../utils/SizeUtils';
import Storage from '../../utils/storage';
import {sleep, timeConverter} from '../../utils/TimeUtils';
@@ -579,23 +590,53 @@ const getTimeLeft = t2 => {
};
};
let passwordVerifyValue = null;
const SettingsUserSection = () => {
const [state] = useTracked();
const {colors} = state;
const user = useUserStore(state => state.user);
const messageBoardState = useMessageStore(state => state.message);
const [verifyUser, setVerifyUser] = useState(false);
const subscriptionDaysLeft =
user && getTimeLeft(parseInt(user.subscription?.expiry));
const isExpired = user && subscriptionDaysLeft.time < 0;
const expiryDate = dayjs(user?.subscription?.expiry).format(
'MMMM D, YYYY',
);
const startDate = dayjs(user?.subscription?.start).format(
'MMMM D, YYYY',
)
console.log(user?.subscription)
const expiryDate = dayjs(user?.subscription?.expiry).format('MMMM D, YYYY');
const startDate = dayjs(user?.subscription?.start).format('MMMM D, YYYY');
const input = useRef();
const tryVerification = async () => {
if (!passwordVerifyValue) {
ToastEvent.show({
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 (
<>
@@ -757,11 +798,9 @@ const SettingsUserSection = () => {
</Paragraph>
<Paragraph color={colors.pri}>
{user.subscription.type === 2
? 'You signed up on ' +
startDate
? 'You signed up on ' + startDate
: user.subscription.type === 1
? 'Your trial period started on ' +
startDate
? 'Your trial period started on ' + startDate
: user.subscription.type === 6
? subscriptionDaysLeft.time < -3
? 'Your subscription has ended'
@@ -786,7 +825,7 @@ const SettingsUserSection = () => {
}}
width="100%"
style={{
paddingHorizontal:0
paddingHorizontal: 0,
}}
fontSize={SIZE.md}
title={
@@ -847,21 +886,71 @@ const SettingsUserSection = () => {
) : null}
</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',
func: async () => {
if (BiometricService.isBiometryAvailable() === false) {
eSendEvent(eOpenRecoveryKeyDialog);
return;
}
let result = await BiometricService.validateUser(
"Verify it's you",
'',
);
if (result) {
eSendEvent(eOpenRecoveryKeyDialog);
}
setVerifyUser(true);
},
desc:
'Recover your data using the recovery key if your password is lost.',
@@ -876,11 +965,10 @@ const SettingsUserSection = () => {
{
name: 'Having problems with syncing?',
func: async () => {
await Sync.run("global",true);
await Sync.run('global', true);
},
desc: 'Try force sync to resolve issues with syncing.',
},
].map(item => (
<CustomButton
key={item.name}
@@ -958,6 +1046,12 @@ const SettingsAppearanceSection = () => {
<ScrollView
horizontal={true}
showsHorizontalScrollIndicator={false}
onMoveShouldSetResponderCapture={() => {
tabBarRef.current?.setScrollEnabled(false);
}}
onMomentumScrollEnd={() => {
tabBarRef.current?.setScrollEnabled(true);
}}
style={{
borderRadius: 5,
padding: 5,
@@ -966,6 +1060,7 @@ const SettingsAppearanceSection = () => {
width: '100%',
paddingHorizontal: 12,
}}
nestedScrollEnabled
contentContainerStyle={{
alignSelf: 'center',
flexDirection: 'row',