mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-21 22:19:41 +01:00
bug fixes in new state management and navigation
This commit is contained in:
@@ -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) {}
|
||||
}
|
||||
|
||||
28
apps/mobile/android/.project
Normal file
28
apps/mobile/android/.project
Normal 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>
|
||||
@@ -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
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,6 +72,7 @@ const ActionSheetWrapper = ({
|
||||
<ActionSheet
|
||||
ref={fwdRef}
|
||||
hideUnderlay={true}
|
||||
|
||||
containerStyle={style}
|
||||
gestureEnabled={gestureEnabled}
|
||||
extraScroll={largeTablet ? 50 : 0}
|
||||
|
||||
@@ -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';
|
||||
|
||||
201
apps/mobile/src/components/CustomTabs/index.js
Normal file
201
apps/mobile/src/components/CustomTabs/index.js
Normal 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:() => {}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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 ? (
|
||||
<>
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
@@ -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 />;
|
||||
};
|
||||
@@ -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} />
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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) => ({
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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',
|
||||
|
||||
Reference in New Issue
Block a user