This commit is contained in:
alihamuh
2020-03-03 09:55:03 +05:00
26 changed files with 558 additions and 458 deletions

View File

@@ -39,6 +39,7 @@ import Animated, {Easing} from 'react-native-reanimated';
import {useForceUpdate} from './src/views/ListsEditor';
import FastStorage from 'react-native-fast-storage';
import {defaultState} from './src/provider/defaultState';
import {EditorPosition} from './src/utils/animations';
export const DDS = new DeviceDetectionService();
export const db = new Storage(StorageInterface);
@@ -176,9 +177,9 @@ const App = () => {
} else {
s = JSON.parse(s);
scale.fontScale = s.fontScale;
console.log(scale.fontScale);
updateSize();
console.log(SIZE.lg);
dispatch({type: ACTIONS.SETTINGS, settings: {...s}});
}
dispatch({type: ACTIONS.THEME, colors: newColors});
@@ -367,7 +368,27 @@ const App = () => {
/>
</SideMenu>
)}
<Animated.View
ref={ref => (editorRef = ref)}
style={{
width: '100%',
height: '100%',
position: 'absolute',
zIndex: 10,
backgroundColor: colors.bg,
elevation: 10,
transform: [
{
translateX: EditorPosition,
},
],
}}>
<Editor noMenu={false} />
</Animated.View>
<Toast />
<DialogManager colors={colors} />
</Animatable.View>
</>

View File

@@ -1,4 +1,4 @@
import React, {useEffect, useState} from 'react';
import React, {useEffect, useState, createRef} from 'react';
import {
Dimensions,
StatusBar,
@@ -32,7 +32,7 @@ import NavigationService from '../../services/NavigationService';
const w = Dimensions.get('window').width;
const h = Dimensions.get('window').height;
let tagsInputRef;
const tagsInputRef = createRef();
export const ActionSheetComponent = ({
close = () => {},
item,
@@ -42,7 +42,7 @@ export const ActionSheetComponent = ({
columnItems = [],
}) => {
const [state, dispatch] = useTracked();
const {colors, tags} = state;
const {colors, tags, currentEditingNote} = state;
const [focused, setFocused] = useState(false);
const [note, setNote] = useState(
item
@@ -78,14 +78,16 @@ export const ActionSheetComponent = ({
let backPressCount = 0;
const _onSubmit = async () => {
if (!tagToAdd || tagToAdd === '') return;
if (!tagToAdd || tagToAdd === '' || tagToAdd.trimStart().length == 0) {
ToastEvent.show('Empty Tag', 'success');
return;
}
let tag = tagToAdd;
if (tag.includes(' ')) {
tag = tag.replace(' ', '_');
}
tagsInputRef.setNativeProps({
tagsInputRef.current?.setNativeProps({
text: '',
});
@@ -116,10 +118,20 @@ export const ActionSheetComponent = ({
setNote({...db.notes.note(note.id).data});
tagsInputRef.setNativeProps({
tagsInputRef.current?.setNativeProps({
text: tagInputValue,
});
}
} else if (event.nativeEvent.key === ' ') {
_onSubmit();
tagsInputRef.current?.setNativeProps({
text: '',
});
} else if (event.nativeE.key === ',') {
_onSubmit();
tagsInputRef.current?.setNativeProps({
text: '',
});
}
};
@@ -333,9 +345,14 @@ export const ActionSheetComponent = ({
key={tag}
onPress={async () => {
let oldProps = {...note};
await db.notes.note(note.id).untag(oldProps.tags.indexOf(tag));
localRefresh(item.type);
try {
await db.notes
.note(note.id)
.untag(oldProps.tags[oldProps.tags.indexOf(tag)]);
localRefresh(oldProps.type);
} catch (e) {
localRefresh(oldProps.type);
}
}}
style={{
flexDirection: 'row',
@@ -422,7 +439,7 @@ export const ActionSheetComponent = ({
}}
name={rowItem.icon}
size={DDS.isTab ? SIZE.xl : SIZE.lg}
color={colors.accent}
color={rowItem.name === 'Delete' ? colors.errorText : colors.accent}
/>
<Text
@@ -680,11 +697,21 @@ export const ActionSheetComponent = ({
borderColor: focused ? colors.accent : colors.nav,
paddingVertical: 5,
}}>
<TouchableOpacity
onPress={() => {
tagsInputRef.current?.focus();
}}
style={{
position: 'absolute',
width: '100%',
height: '100%',
}}></TouchableOpacity>
{note && note.tags ? note.tags.map(_renderTag) : null}
<TextInput
style={{
backgroundColor: 'transparent',
minWidth: 100,
zIndex: 10,
fontFamily: WEIGHT.regular,
color: colors.pri,
paddingHorizontal: 5,
@@ -692,7 +719,7 @@ export const ActionSheetComponent = ({
margin: 1,
}}
blurOnSubmit={false}
ref={ref => (tagsInputRef = ref)}
ref={tagsInputRef}
placeholderTextColor={colors.icon}
onFocus={() => {
setFocused(true);

View File

@@ -108,33 +108,42 @@ export class AddNotebookDialog extends React.Component {
if (this.currentInputValue) {
this.onSubmit();
}
let {topics} = this.state;
let {toEdit} = this.props;
if (!this.title)
return ToastEvent.show('Title is required', 'error', 3000, () => {}, '');
let id = toEdit && toEdit.id ? toEdit.id : null;
setTimeout(async () => {
let {topics} = this.state;
let {toEdit} = this.props;
if (!this.title)
return ToastEvent.show(
'Title is required',
'error',
3000,
() => {},
'',
);
if (id) {
await db.notebooks.add({
title: this.title,
description: this.description,
id: id,
});
let id = toEdit && toEdit.id ? toEdit.id : null;
await db.notebooks.notebook(id).topics.add(...topics);
} else {
await db.notebooks.add({
title: this.title,
description: this.description,
topics,
id: id,
});
}
if (id) {
await db.notebooks.add({
title: this.title,
description: this.description,
id: id,
});
updateEvent({type: ACTIONS.NOTEBOOKS});
this.close();
ToastEvent.show('New notebook added', 'success', 3000, () => {}, '');
await db.notebooks.notebook(id).topics.add(...topics);
} else {
await db.notebooks.add({
title: this.title,
description: this.description,
topics,
id: id,
});
}
this.close();
updateEvent({type: ACTIONS.NOTEBOOKS});
ToastEvent.show('New notebook added', 'success', 3000, () => {}, '');
}, 100);
};
onSubmit = () => {
@@ -205,6 +214,9 @@ export class AddNotebookDialog extends React.Component {
transparent={true}
animated
animationType="fade"
onShow={() => {
this.titleRef.focus();
}}
onRequestClose={this.close}>
<KeyboardAvoidingView
behavior={Platform.OS === 'ios' ? 'padding' : null}

View File

@@ -1,4 +1,4 @@
import React from 'react';
import React, {createRef} from 'react';
import {Modal, Text, TouchableOpacity, View} from 'react-native';
import {TextInput} from 'react-native-gesture-handler';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
@@ -18,6 +18,7 @@ export class AddTopicDialog extends React.Component {
};
this.title;
this.titleRef = createRef();
}
addNewTopic = async () => {
@@ -52,6 +53,9 @@ export class AddTopicDialog extends React.Component {
animated
animationType="fade"
transparent={true}
onShow={() => {
this.titleRef.current?.focus();
}}
onRequestClose={() => {
refs = [];
this.close();
@@ -102,6 +106,7 @@ export class AddTopicDialog extends React.Component {
</View>
<TextInput
ref={this.titleRef}
style={{
padding: pv,
borderWidth: 1.5,

View File

@@ -11,16 +11,17 @@ import {db, DDS} from '../../../App';
import {opacity, ph, pv, SIZE, WEIGHT} from '../../common/common';
import {ACTIONS} from '../../provider/actions';
import NavigationService from '../../services/NavigationService';
import {getElevation, ToastEvent} from '../../utils/utils';
import {getElevation, ToastEvent, editing, history} from '../../utils/utils';
import {dialogActions, updateEvent} from '../DialogManager';
import {eSendEvent} from '../../services/eventManager';
import {eCloseFullscreenEditor} from '../../services/events';
import {eCloseFullscreenEditor, eOnLoadNote} from '../../services/events';
export class Dialog extends Component {
constructor(props) {
super(props);
this.state = {
visible: false,
selecteItemsLength: 0,
};
}
@@ -29,29 +30,41 @@ export class Dialog extends Component {
switch (template.action) {
case dialogActions.ACTION_DELETE: {
if (item.type === 'note') {
await db.notes.delete(item.id);
ToastEvent.show('Note moved to trash', 'error', 3000);
updateEvent({type: item.type});
} else if (item.type === 'topic') {
console.log(item);
//TODO
await db.notebooks
.notebook(item.notebookId)
.topics.delete(item.title);
updateEvent({type: 'notebook'});
ToastEvent.show('Topic deleted', 'error', 3000);
} else if (item.type === 'notebook') {
await db.notebooks.delete(item.id);
updateEvent({type: item.type});
ToastEvent.show('Notebook moved to trash', 'error', 3000);
if (item.id && history.selectedItemsList.length === 0) {
history.selectedItemsList = [];
history.selectedItemsList.push(item);
}
history.selectedItemsList.forEach(async i => {
if (i.type === 'note') {
await db.notes.delete(i.id);
ToastEvent.show('Notes moved to trash', 'error', 3000);
updateEvent({type: i.type});
} else if (i.type === 'topic') {
await db.notebooks.notebook(i.notebookId).topics.delete(i.title);
updateEvent({type: 'notebook'});
ToastEvent.show('Topics deleted', 'error', 3000);
} else if (i.type === 'notebook') {
await db.notebooks.delete(i.id);
updateEvent({type: i.type});
ToastEvent.show('Notebooks moved to trash', 'error', 3000);
}
});
updateEvent({type: ACTIONS.CLEAR_SELECTION});
updateEvent({type: ACTIONS.SELECTION_MODE, enabled: false});
this.setState({
visible: false,
});
if (editing.currentlyEditing) {
if (DDS.isTab) {
eSendEvent(eCloseFullscreenEditor);
eSendEvent(eOnLoadNote, {type: 'new'});
} else {
NavigationService.goBack();
}
}
break;
}
case dialogActions.ACTION_EXIT: {
@@ -81,7 +94,7 @@ export class Dialog extends Component {
break;
}
case dialogActions.ACTION_TRASH: {
db.trash.restore(item.id);
await db.trash.restore(i.id);
ToastEvent.show(
item.type.slice(0, 1).toUpperCase() +
item.type.slice(1) +
@@ -89,6 +102,7 @@ export class Dialog extends Component {
'success',
3000,
);
updateEvent({type: ACTIONS.TRASH});
this.hide();
break;
@@ -108,8 +122,10 @@ export class Dialog extends Component {
};
show = () => {
console.log(history.selectedItemsList.length, 'length');
this.setState({
visible: true,
selectedItemsLength: history.selectedItemsList.length,
});
};
hide = () => {
@@ -187,7 +203,11 @@ export class Dialog extends Component {
textAlign: 'center',
marginTop: 10,
}}>
{paragraph}
{this.state.selectedItemsLength > 0
? 'Delete ' +
this.state.selectedItemsLength +
' selected items?'
: paragraph}
</Text>
) : null}

View File

@@ -30,6 +30,7 @@ import {eSendEvent} from '../../services/eventManager';
import {eOpenModalMenu, eSendSideMenuOverlayRef} from '../../services/events';
import NavigationService from '../../services/NavigationService';
import {timeSince, getElevation, hexToRGBA} from '../../utils/utils';
import {inputRef} from '../SearchInput';
export const Menu = ({
close = () => {},
@@ -189,7 +190,7 @@ export const Menu = ({
)}
<ScrollView
contentContainerStyle={{minHeight: '80%'}}
contentContainerStyle={{minHeight: '50%'}}
style={{
paddingHorizontal: noTextMode ? 0 : 12,
}}
@@ -201,7 +202,12 @@ export const Menu = ({
activeOpacity={opacity / 2}
onPress={() => {
item.close === false ? null : close();
if (item.close) {
inputRef.current?.setNativeProps({
text: '',
});
dispatch({type: ACTIONS.SEARCH_RESULTS, results: []});
}
item.func();
}}
style={{

View File

@@ -12,6 +12,7 @@ import {
simpleDialogEvent,
TEMPLATE_TRASH,
} from '../DialogManager';
import {openEditorAnimation} from '../../utils/animations';
const w = Dimensions.get('window').width;
const h = Dimensions.get('window').height;
@@ -116,14 +117,15 @@ export default class NoteItem extends React.Component {
onPress={() => {
if (item.locked) {
eSendEvent(eOpenVaultDialog, {unlock: true, i: item});
return;
}
if (DDS.isTab) {
eSendEvent(eOnLoadNote, item);
} else if (isTrash) {
simpleDialogEvent(TEMPLATE_TRASH(item.type));
} else {
DDS.isTab
? eSendEvent(eOnLoadNote, item)
: isTrash
? simpleDialogEvent(TEMPLATE_TRASH(item.type))
: NavigationService.navigate('Editor', {
note: item,
});
eSendEvent(eOnLoadNote, item);
openEditorAnimation();
}
}}
style={{

View File

@@ -193,22 +193,21 @@ export const NotebookItem = ({
</Text>
</View>
)}
{isTopic && item.totalNotes > 0 ? (
<Text
style={{
color: colors.icon,
fontSize: SIZE.xxs,
textAlignVertical: 'center',
fontFamily: WEIGHT.regular,
marginTop: 5,
}}>
{item && item.totalNotes && item.totalNotes > 1
? item.totalNotes + ' notes'
: item.totalNotes === 1
? item.totalNotes + ' note'
: null}
</Text>
) : null}
<Text
style={{
color: colors.icon,
fontSize: SIZE.xxs,
textAlignVertical: 'center',
fontFamily: WEIGHT.regular,
marginTop: 5,
}}>
{item && item.totalNotes && item.totalNotes > 1
? item.totalNotes + ' notes'
: item.totalNotes === 1
? item.totalNotes + ' note'
: '0 notes'}
</Text>
</TouchableOpacity>
{hideMore ||
(item.title === 'General' && item.type === 'topic') ? null : (
@@ -243,7 +242,7 @@ export const NotebookItem = ({
onPress={async () => {
let noteIds = [];
selectedItemsList.forEach(item => noteIds.push(item.id));
console.log(noteIds);
db.notes.move(
{
topic: item.title,

View File

@@ -18,6 +18,7 @@ import {NotesPlaceHolder} from '../ListPlaceholders';
import NoteItem from '../NoteItem';
import SelectionWrapper from '../SelectionWrapper';
import {db, DDS} from '../../../App';
import {inputRef} from '../SearchInput';
export const NotesList = ({isGrouped = false}) => {
const [state, dispatch] = useTracked();
@@ -155,12 +156,12 @@ export const NotesList = ({isGrouped = false}) => {
style={{
marginTop:
Platform.OS == 'ios'
? notes[0]
? notes[0] && !selectionMode
? DDS.isTab
? 115
: 135
: 135 - 60
: notes[0]
: notes[0] && !selectionMode
? 155
: 155 - 60,
flexDirection: 'row',
@@ -178,6 +179,9 @@ export const NotesList = ({isGrouped = false}) => {
</Text>
<Text
onPress={() => {
inputRef.current?.setNativeProps({
text: '',
});
dispatch({
type: ACTIONS.SEARCH_RESULTS,
results: [],
@@ -194,7 +198,7 @@ export const NotesList = ({isGrouped = false}) => {
);
const _listKeyExtractor = (item, index) => item.id.toString();
console.log(notes);
return isGrouped && searchResults.length === 0 ? (
<SectionList
ref={ref => (sectionListRef = ref)}
@@ -269,7 +273,7 @@ const PinnedItems = () => {
return (
<>
<FlatList
data={pinned}
data={pinned.notes}
keyExtractor={(item, index) => item.id.toString()}
renderItem={({item, index}) =>
item.type === 'note' ? (
@@ -288,6 +292,7 @@ const PinnedItems = () => {
borderBottomWidth: 0,
marginHorizontal: 0,
}}
onLongPress={() => {}}
pinned={true}
item={item}
index={index}

View File

@@ -8,12 +8,14 @@ import {useTracked} from '../../provider';
const {Value, timing, block} = Animated;
export const inputRef = createRef();
export const Search = props => {
const [state, dispatch] = useTracked();
const {colors, searchResults} = state;
const [focus, setFocus] = useState(false);
const inputRef = createRef();
const _marginAnim = new Value(0);
const _opacity = new Value(1);
const _borderAnim = new Value(1.5);
@@ -98,7 +100,7 @@ export const Search = props => {
text: '',
});
}}
name={searchResults.length > 0 ? 'x' : 'magnify'}
name={searchResults.length > 0 ? 'close' : 'magnify'}
color={
focus
? props.headerColor

View File

@@ -14,8 +14,9 @@ import {useTracked} from '../../provider';
import {ACTIONS} from '../../provider/actions';
import {w, ToastEvent} from '../../utils/utils';
import {eSendEvent} from '../../services/eventManager';
import {eOpenMoveNoteDialog} from '../../services/events';
import {eOpenMoveNoteDialog, eOpenSimpleDialog} from '../../services/events';
import {db} from '../../../App';
import {TEMPLATE_DELETE} from '../DialogManager';
export const AnimatedSafeAreaView = Animatable.createAnimatableComponent(
SafeAreaView,
@@ -105,6 +106,7 @@ export const SelectionHeader = ({navigation}) => {
<TouchableOpacity
onPress={() => {
dispatch({type: ACTIONS.SELECTION_MODE, enabled: false});
dispatch({type: ACTIONS.CLEAR_SELECTION});
eSendEvent(eOpenMoveNoteDialog);
}}>
<Icon
@@ -120,14 +122,31 @@ export const SelectionHeader = ({navigation}) => {
{currentScreen === 'trash' || currentScreen === 'notebooks' ? null : (
<TouchableOpacity
onPress={async () => {
let favCount = 0;
let unFavCount = 0;
if (selectedItemsList.length > 0) {
selectedItemsList.forEach(async item => {
if (item.favorite) {
favCount += 1;
} else {
unFavCount += 1;
}
await db.notes.note(item.id).favorite();
dispatch({type: ACTIONS.NOTES});
dispatch({type: ACTIONS.FAVORITES});
});
dispatch({type: ACTIONS.SELECTION_MODE, enabled: false});
dispatch({type: ACTIONS.NOTES});
dispatch({type: ACTIONS.CLEAR_SELECTION});
ToastEvent.show('Notes added to favorites', 'success');
ToastEvent.show(
favCount +
' notes added to favorites &' +
unFavCount +
'removed',
'success',
);
}
}}>
<Icon
@@ -144,6 +163,8 @@ export const SelectionHeader = ({navigation}) => {
{currentScreen === 'trash' ? null : (
<TouchableOpacity
onPress={async () => {
eSendEvent(eOpenSimpleDialog, TEMPLATE_DELETE('item'));
return;
if (selectedItemsList.length > 0) {
let noteIds = [];
selectedItemsList.forEach(item => {

View File

@@ -65,16 +65,17 @@ export const Toast = () => {
return (
<Animatable.View
transition={['translateY', 'opacity']}
duration={500}
duration={10}
delay={toast ? 300 : 0}
useNativeDriver={true}
style={{
width: '100%',
alignItems: 'center',
height: 60,
opacity: toast ? 1 : 0,
bottom: 100,
position: 'absolute',
zIndex: 999,
elevation: 15,
transform: [
{
translateY: toast ? 0 : 300,
@@ -83,6 +84,8 @@ export const Toast = () => {
}}>
<AnimatedTouchableOpacity
activeOpacity={opacity + 0.1}
transition={['opacity']}
duration={300}
style={{
...toastStyle,
maxWidth: DDS.isTab ? normalize(350) : w - 24,
@@ -91,6 +94,7 @@ export const Toast = () => {
borderRadius: 5,
paddingHorizontal: ph,
paddingVertical: pv,
opacity: toast ? 1 : 0,
justifyContent: 'center',
elevation: 25,
flexDirection: 'row',

View File

@@ -8,6 +8,7 @@ import {getElevation} from '../../utils/utils';
import NavigationService from '../../services/NavigationService';
import {updateEvent} from '../DialogManager';
import Share from 'react-native-share';
export class VaultDialog extends Component {
constructor(props) {
@@ -24,24 +25,19 @@ export class VaultDialog extends Component {
});
};
close = (share = false, item = null) => {
this.setState(
{
visible: false,
},
if (share && item) {
let m = `${item.title}\n \n ${item.content.text}`;
Share.open({
title: 'Share note to',
failOnCancel: false,
message: m,
});
updateEvent({type: item.type});
}
() => {
if (share && note) {
let m = `${item.title}\n \n ${item.content.text}`;
Share.open({
title: 'Share note to',
failOnCancel: false,
message: m,
});
}
updateEvent({type: this.props.note.type});
},
);
this.setState({
visible: false,
});
};
onPress = async () => {

View File

@@ -8,7 +8,10 @@ export const defaultState = {
notebooks: [],
trash: [],
favorites: [],
pinned: [],
pinned: {
notes: [],
notebooks: [],
},
tags: [],
colorNotes: [],
user: {},

View File

@@ -1,5 +1,5 @@
import {db} from '../../App';
import {SideMenuEvent} from '../utils/utils';
import {SideMenuEvent, history} from '../utils/utils';
import {ACTIONS} from './actions';
export const reducer = (state, action) => {
@@ -50,10 +50,15 @@ export const reducer = (state, action) => {
};
}
case ACTIONS.PINNED: {
let pinned = db.notes.pinned;
let notes = db.notes.pinned;
let notebooks = db.notebooks.pinned;
return {
...state,
pinned: pinned,
pinned: {
notes,
notebooks,
},
};
}
case ACTIONS.CURRENT_SCREEN: {
@@ -99,13 +104,16 @@ export const reducer = (state, action) => {
} else {
selectedItems.push(action.item);
}
history.selectedItemsList = selectedItems;
return {
...state,
selectedItemsList: selectedItems,
selectionMode: selectedItems.length > 0 ? true : false,
};
}
case ACTIONS.CLEAR_SELECTION: {
history.selectedItemsList = [];
return {
...state,
selectedItemsList: [],

View File

@@ -1,26 +1,18 @@
import {ToastEvent} from '../utils/utils';
let regex = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/;
export function validateEmail(email) {
if (email && email.length > 0) {
ToastEvent.show('Please enter a valid email address');
return regex.test(email);
} else {
ToastEvent.show('Please enter email or passoword to login');
return false;
}
}
export function validatePass(password) {
if (password && password.length <= 0) {
ToastEvent.show('No password provided');
return false;
}
if (password && password.length < 8 && password.length > 0) {
ToastEvent.show('Password too short');
return false;
} else if (password && password.length > 8 && password.length > 0) {
return true;
@@ -30,10 +22,8 @@ export function validatePass(password) {
export function validateUsername(username) {
let regex = /^[a-z0-9_-]{3,16}$/gim;
if (username && username.length > 0) {
//ToastEvent.show('Please enter a valid email address');
return regex.test(username);
} else {
//ToastEvent.show('Please enter email or passoword to login');
return false;
}
}

View File

@@ -1,3 +1,28 @@
import Animated, {Easing} from 'react-native-reanimated';
import {Dimensions} from 'react-native';
const {color, Value, timing} = Animated;
export const EditorPosition = new Value(Dimensions.get('window').width * 1.5);
export function openEditorAnimation() {
let openConfigH = {
duration: 300,
toValue: 0,
easing: Easing.inOut(Easing.ease),
};
timing(EditorPosition, openConfigH).start();
}
export function exitEditorAnimation() {
let openConfigH = {
duration: 300,
toValue: Dimensions.get('window').width * 1.5,
easing: Easing.inOut(Easing.ease),
};
timing(EditorPosition, openConfigH).start();
}
export const slideRight = {
0: {
transform: [{translateX: -4}],

View File

@@ -1,5 +1,6 @@
import {NativeModules} from 'react-native';
import FastStorage from 'react-native-fast-storage';
var Aes = NativeModules.Aes;
async function read(key) {
@@ -25,12 +26,16 @@ function encrypt(password, data) {
let key;
return Aes.pbkdf2('password', 'salt', 5000, 256).then(aes => {
key = aes;
console.log(aes);
return Aes.randomKey(16).then(iv => {
return Aes.encrypt(data, key, iv).then(cipher => ({
cipher,
iv,
}));
return Aes.encrypt(data, key, iv).then(cipher => {
return Aes.hmac256(cipher, key).then(hash => {
return {
hash,
cipher,
iv,
};
});
});
});
});
}
@@ -40,8 +45,13 @@ function decrypt(password, data) {
return Aes.pbkdf2(password, 'salt', 5000, 256).then(aes => {
key = aes;
return Aes.decrypt(data.cipher, key, data.iv).then(e => {
return e;
return Aes.hmac256(data.cipher, key).then(hash => {
if (hash !== data.hash) {
throw new Error('Wrong password');
}
return Aes.decrypt(data.cipher, key, data.iv).then(e => {
return e;
});
});
});
}

View File

@@ -18,6 +18,15 @@ export const getElevation = elevation => {
};
};
export const editing = {
currentlyEditing: false,
isFullscreen: false,
};
export const history = {
selectedItemsList: [],
};
export function timeSince(date) {
var seconds = Math.floor((new Date() - date) / 1000);
@@ -49,7 +58,7 @@ export const w = Dimensions.get('window').width;
export const h = Dimensions.get('window').height;
export const ToastEvent = {
show: (message, type, duration = 1000, func = null, actionText = '') => {
show: (message, type, duration = 3000, func = null, actionText = '') => {
eSendEvent(eShowToast, {
message,
type,
@@ -58,7 +67,7 @@ export const ToastEvent = {
actionText,
});
},
hide: (message, type, duration = 1000, func = null, actionText = '') => {
hide: (message, type, duration = 3000, func = null, actionText = '') => {
eSendEvent(eHideToast, {
message,
type,

View File

@@ -1,6 +1,5 @@
import React, {useEffect, useState} from 'react';
import React, {createRef, useEffect, useState} from 'react';
import {
ActivityIndicator,
BackHandler,
KeyboardAvoidingView,
Linking,
@@ -9,16 +8,15 @@ import {
Text,
TouchableOpacity,
View,
SafeAreaView,
} from 'react-native';
import * as Animatable from 'react-native-animatable';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import WebView from 'react-native-webview';
import {db, DDS} from '../../../App';
import {SIZE, WEIGHT, normalize, opacity} from '../../common/common';
import {normalize, SIZE, WEIGHT} from '../../common/common';
import {
ActionSheetEvent,
simpleDialogEvent,
TEMPLATE_EXIT,
TEMPLATE_EXIT_FULLSCREEN,
TEMPLATE_INFO,
} from '../../components/DialogManager';
@@ -34,29 +32,39 @@ import {
eOnLoadNote,
eOpenFullscreenEditor,
} from '../../services/events';
import {SideMenuEvent, timeConverter, ToastEvent} from '../../utils/utils';
import {AnimatedSafeAreaView} from '../Home';
import NavigationService from '../../services/NavigationService';
import {exitEditorAnimation} from '../../utils/animations';
import {
editing,
SideMenuEvent,
timeConverter,
ToastEvent,
} from '../../utils/utils';
let EditorWebView;
const EditorWebView = createRef();
let note = {};
let id = null;
let dateEdited = null;
var content = null;
var title = null;
let timer = null;
let saveCounter = 0;
let tapCount = 0;
const Editor = ({navigation, noMenu}) => {
// Global State
const [state, dispatch] = useTracked();
const {colors} = state;
const [loading, setLoading] = useState(true);
const [fullscreen, setFullscreen] = useState(false);
const [dateEdited, setDateEdited] = useState(0);
// FUNCTIONS
const post = value => EditorWebView.postMessage(value);
const post = value => EditorWebView.current?.postMessage(value);
useEffect(() => {
let c = {...colors};
c.factor = normalize(1);
post(JSON.stringify(c));
}, [colors.bg]);
useEffect(() => {
eSubscribeEvent(eOnLoadNote, loadNote);
@@ -65,56 +73,44 @@ const Editor = ({navigation, noMenu}) => {
};
}, []);
useEffect(() => {
setLoading(true);
setTimeout(() => {
setLoading(false);
}, 3000);
}, [colors.bg]);
const loadNote = item => {
const loadNote = async item => {
if (note && note.id) {
saveNote(true).then(() => {
dispatch({type: ACTIONS.NOTES});
if (item && item.type === 'new') {
clearEditor();
} else {
note = item;
if (DDS.isTab) {
dispatch({
type: ACTIONS.CURRENT_EDITING_NOTE,
id: item.id,
});
}
updateEditor();
}
});
dispatch({type: ACTIONS.NOTES});
if (item && item.type === 'new') {
await clearEditor();
} else {
note = item;
dispatch({
type: ACTIONS.CURRENT_EDITING_NOTE,
id: item.id,
});
updateEditor();
}
} else {
dispatch({type: ACTIONS.NOTES});
if (item && item.type === 'new') {
clearEditor();
await clearEditor();
} else {
note = item;
if (DDS.isTab) {
dispatch({
type: ACTIONS.CURRENT_EDITING_NOTE,
id: item.id,
});
}
dispatch({
type: ACTIONS.CURRENT_EDITING_NOTE,
id: item.id,
});
updateEditor();
}
}
};
const clearEditor = () => {
id = null;
const clearEditor = async () => {
await saveNote();
title = null;
content = null;
note = {};
note = null;
id = null;
tapCount = 0;
saveCounter = 0;
EditorWebView.reload();
post('clear');
post(JSON.stringify({type: 'text', value: ''}));
post('focusTitle');
};
@@ -131,7 +127,6 @@ const Editor = ({navigation, noMenu}) => {
const _onMessage = evt => {
if (evt.nativeEvent.data === 'loaded') {
setLoading(false);
} else if (
evt.nativeEvent.data !== '' &&
evt.nativeEvent.data !== 'loaded'
@@ -165,8 +160,6 @@ const Editor = ({navigation, noMenu}) => {
};
}
console.log(content.delta, 'i am called');
let rId = await db.notes.add({
title,
content: {
@@ -189,8 +182,7 @@ const Editor = ({navigation, noMenu}) => {
}
}, 500);
}
if (DDS.isTab) {
if (id) {
dispatch({
type: ACTIONS.CURRENT_EDITING_NOTE,
id: id,
@@ -248,17 +240,10 @@ const Editor = ({navigation, noMenu}) => {
);
}
if (navigation && navigation.state.params && navigation.state.params.note) {
note = navigation.state.params.note;
updateEditor();
} else if (note && note.id) {
if (note && note.id) {
updateEditor();
} else {
post('focusTitle');
wait(500).then(() => {
setLoading(false);
});
}
let c = {...colors};
c.factor = normalize(1);
@@ -274,17 +259,14 @@ const Editor = ({navigation, noMenu}) => {
});
const updateEditor = async () => {
console.log('before', content, title, id);
title = note.title;
id = note.id;
dateEdited = note.dateEdited;
setDateEdited(note.dateEdited);
content = note.content;
if (!note.locked) {
content.delta = await db.notes.note(id).delta();
}
console.log('after', content, title, id);
saveCounter = 0;
if (title !== null || title === '') {
@@ -297,18 +279,11 @@ const Editor = ({navigation, noMenu}) => {
} else {
post('focusTitle');
post('clear');
wait(500).then(() => {
setLoading(false);
});
}
if (note.content.text === '' && note.content.delta === null) {
post('clear');
wait(500).then(() => {
setLoading(false);
});
} else if (note.content.delta) {
let delta;
console.log(note.content.delta, 'HERE');
if (typeof note.content.delta !== 'string') {
delta = note.content.delta;
} else {
@@ -318,9 +293,6 @@ const Editor = ({navigation, noMenu}) => {
post(JSON.stringify(delta));
} else {
post(JSON.stringify({type: 'text', value: note.content.text}));
wait(2000).then(() => {
setLoading(false);
});
}
};
@@ -334,8 +306,92 @@ const Editor = ({navigation, noMenu}) => {
link.click();
}`;
const _renderEditor = () => {
return (
const closeFullscreen = () => {
setFullscreen(false);
};
// EFFECTS
useEffect(() => {
eSubscribeEvent(eCloseFullscreenEditor, closeFullscreen);
return () => {
eUnSubscribeEvent(eCloseFullscreenEditor, closeFullscreen);
};
});
const _onHardwareBackPress = async () => {
if (tapCount > 0) {
exitEditorAnimation();
await clearEditor();
ToastEvent.show('Note Saved!', 'success');
return true;
} else {
tapCount = 1;
setTimeout(() => {
tapCount = 0;
}, 3000);
ToastEvent.show('Press back again to exit editor', 'success');
return true;
}
};
useEffect(() => {
editing.currentlyEditing = true;
let handleBack;
if (!noMenu && DDS.isTab) {
handleBack = BackHandler.addEventListener('hardwareBackPress', () => {
simpleDialogEvent(TEMPLATE_EXIT_FULLSCREEN());
editing.isFullscreen = false;
return true;
});
} else if (!DDS.isTab) {
handleBack = BackHandler.addEventListener(
'hardwareBackPress',
_onHardwareBackPress,
);
} else {
if (handleBack) {
handleBack.remove();
handleBack = null;
}
}
return () => {
editing.currentlyEditing = false;
if (handleBack) {
handleBack.remove();
handleBack = null;
}
title = null;
content = null;
id = null;
timer = null;
note = {};
};
}, [noMenu]);
useEffect(() => {
noMenu ? null : SideMenuEvent.disable();
return () => {
if (noMenu) return;
DDS.isTab ? SideMenuEvent.open() : null;
SideMenuEvent.enable();
};
});
return (
<SafeAreaView
style={{
flex: 1,
backgroundColor: DDS.isTab ? 'transparent' : colors.bg,
height: '100%',
width: '100%',
flexDirection: 'row',
justifyContent: 'space-between',
}}>
<KeyboardAvoidingView
behavior={Platform.OS === 'ios' ? 'padding' : null}
style={{
@@ -349,17 +405,13 @@ const Editor = ({navigation, noMenu}) => {
{noMenu ? null : (
<TouchableOpacity
onPress={() => {
onPress={async () => {
if (DDS.isTab) {
simpleDialogEvent(TEMPLATE_EXIT_FULLSCREEN());
} else {
tapCount = 0;
title = null;
content = null;
note = null;
id = null;
NavigationService.goBack();
exitEditorAnimation();
await clearEditor();
ToastEvent.show('Note Saved!', 'success');
}
}}
style={{
@@ -401,6 +453,7 @@ const Editor = ({navigation, noMenu}) => {
onPress={() => {
eSendEvent(eOpenFullscreenEditor);
setFullscreen(true);
editing.isFullscreen = true;
post(
JSON.stringify({
type: 'nomenu',
@@ -468,7 +521,7 @@ const Editor = ({navigation, noMenu}) => {
</Text>
</View>
<WebView
ref={ref => (EditorWebView = ref)}
ref={EditorWebView}
onError={error => console.log(error)}
onLoad={onWebViewLoad}
javaScriptEnabled={true}
@@ -510,133 +563,7 @@ const Editor = ({navigation, noMenu}) => {
onMessage={_onMessage}
/>
</KeyboardAvoidingView>
);
};
const closeFullscreen = () => {
setFullscreen(false);
};
// EFFECTS
useEffect(() => {
eSubscribeEvent(eCloseFullscreenEditor, closeFullscreen);
return () => {
eUnSubscribeEvent(eCloseFullscreenEditor, closeFullscreen);
};
});
useEffect(() => {
let handleBack;
if (!noMenu && DDS.isTab) {
handleBack = BackHandler.addEventListener('hardwareBackPress', () => {
simpleDialogEvent(TEMPLATE_EXIT_FULLSCREEN());
return true;
});
} else if (!DDS.isTab) {
handleBack = BackHandler.addEventListener('hardwareBackPress', () => {
console.log('tapCOunt', tapCount);
if (tapCount > 0) {
tapCount = 0;
title = null;
content = null;
note = null;
id = null;
return false;
} else {
tapCount = 1;
setTimeout(() => {
tapCount = 0;
}, 3000);
ToastEvent.show('Press back again to exit editor', 'success');
return true;
}
});
} else {
console.log(' I RUN EVERYTIME');
if (handleBack) {
handleBack.remove();
handleBack = null;
}
}
return () => {
if (handleBack) {
handleBack.remove();
handleBack = null;
}
title = null;
content = null;
id = null;
timer = null;
note = {};
};
}, [noMenu]);
useEffect(() => {
noMenu ? null : SideMenuEvent.disable();
return () => {
if (noMenu) return;
DDS.isTab ? SideMenuEvent.open() : null;
SideMenuEvent.enable();
};
});
useEffect(() => {
EditorWebView.reload();
}, [colors]);
return (
<AnimatedSafeAreaView
transition={['backgroundColor', 'width']}
duration={300}
style={{
flex: 1,
backgroundColor: DDS.isTab ? 'transparent' : colors.bg,
height: '100%',
width: '100%',
flexDirection: 'row',
justifyContent: 'space-between',
}}>
<Animatable.View
transition="opacity"
useNativeDriver={true}
duration={150}
style={{
width: '100%',
height: '100%',
justifyContent: 'center',
alignItems: 'center',
zIndex: 1,
backgroundColor: colors.bg,
opacity: loading ? 1 : 0,
position: 'absolute',
}}>
<ActivityIndicator color={colors.accent} size={SIZE.xxxl} />
<Text
style={{
color: colors.accent,
fontFamily: WEIGHT.regular,
fontSize: SIZE.md,
marginTop: 10,
}}>
Write with confidence.
</Text>
</Animatable.View>
<View
style={{
width: '100%',
height: '100%',
zIndex: 2,
opacity: loading ? 0 : 1,
}}>
{_renderEditor()}
</View>
</AnimatedSafeAreaView>
</SafeAreaView>
);
};

View File

@@ -10,19 +10,24 @@ import {useTracked} from '../../provider';
import {ACTIONS} from '../../provider/actions';
import {eSendEvent} from '../../services/eventManager';
import {eScrollEvent} from '../../services/events';
import {ToastEvent} from '../../utils/utils';
import {ToastEvent, w} from '../../utils/utils';
import {useIsFocused} from 'react-navigation-hooks';
export const Favorites = ({navigation}) => {
const [state, dispatch] = useTracked();
const {colors, selectionMode, favorites} = state;
const [refreshing, setRefreshing] = useState(false);
const isFocused = useIsFocused();
useEffect(() => {
dispatch({
type: ACTIONS.CURRENT_SCREEN,
screen: 'favorites',
});
dispatch({type: ACTIONS.FAVORITES});
}, []);
if (isFocused) {
dispatch({
type: ACTIONS.CURRENT_SCREEN,
screen: 'favorites',
});
dispatch({type: ACTIONS.FAVORITES});
}
}, [isFocused]);
const onScroll = event => {
let y = event.nativeEvent.contentOffset.y;

View File

@@ -34,45 +34,37 @@ export const Folders = ({navigation}) => {
const [refreshing, setRefreshing] = useState(false);
let isFocused = useIsFocused();
///
const handleBackPress = () => {
alert('here');
return true;
};
useEffect(() => {
if (isFocused) {
dispatch({type: ACTIONS.PINNED});
dispatch({type: ACTIONS.NOTEBOOKS});
dispatch({
type: ACTIONS.CURRENT_SCREEN,
screen: 'notebooks',
});
}
}, [isFocused]);
useEffect(() => {
eSendEvent(eScrollEvent, 0);
dispatch({type: ACTIONS.NOTEBOOKS});
if (isFocused) {
if (isFocused) {
dispatch({
type: ACTIONS.CURRENT_SCREEN,
screen: 'notebooks',
});
}
}
let backhandler;
if (isFocused) {
backhandler = BackHandler.addEventListener(
'hardwareBackPress',
handleBackPress,
);
} else {
if (backhandler) {
backhandler.remove();
backhandler = null;
}
}
backhandler = BackHandler.addEventListener(
'hardwareBackPress',
handleBackPress,
);
return () => {
if (!backhandler) return;
backhandler.remove();
backhandler = null;
};
}, [isFocused]);
}, []);
const params = navigation.state.params;
@@ -134,38 +126,36 @@ export const Folders = ({navigation}) => {
? 155
: 155 - 60,
}}>
{pinned && pinned.length > 0 ? (
{pinned && pinned.notebooks && pinned.notebooks.length > 0 ? (
<>
<FlatList
data={pinned}
data={pinned.notebooks}
keyExtractor={(item, index) => item.id.toString()}
renderItem={({item, index}) =>
item.type === 'notebook' ? (
<SelectionWrapper item={item}>
<NotebookItem
hideMore={params.hideMore}
customStyle={{
width: selectionMode ? w - 74 : '100%',
marginHorizontal: 0,
}}
isMove={params.isMove}
onLongPress={() => {
dispatch({
type: ACTIONS.SELECTION_MODE,
enabled: !selectionMode,
});
dispatch({
type: ACTIONS.SELECTED_ITEMS,
item: item,
});
}}
noteToMove={params.note}
item={item}
pinned={true}
index={index}
colors={colors}
/>
</SelectionWrapper>
<NotebookItem
hideMore={params.hideMore}
customStyle={{
backgroundColor: Platform.ios
? hexToRGBA(colors.accent + '19')
: hexToRGBA(colors.shade),
width: '100%',
paddingHorizontal: 12,
paddingTop: 20,
paddingRight: 18,
marginBottom: 10,
marginTop: 20,
borderBottomWidth: 0,
marginHorizontal: 0,
}}
isMove={params.isMove}
onLongPress={() => {}}
noteToMove={params.note}
item={item}
pinned={true}
index={index}
colors={colors}
/>
) : null
}
/>
@@ -174,31 +164,29 @@ export const Folders = ({navigation}) => {
</View>
}
ListEmptyComponent={
pinned && pinned.length > 0 ? null : (
<View
style={{
height: '80%',
width: DDS.isTab ? '70%' : '100%',
alignItems: 'center',
alignSelf: 'center',
justifyContent: 'center',
opacity: 0.8,
}}>
<NotebookPlaceHolder animation={slideRight} colors={colors} />
<NotebookPlaceHolder animation={slideLeft} colors={colors} />
<NotebookPlaceHolder animation={slideRight} colors={colors} />
<View
style={{
height: '80%',
width: DDS.isTab ? '70%' : '100%',
alignItems: 'center',
alignSelf: 'center',
justifyContent: 'center',
opacity: 0.8,
}}>
<NotebookPlaceHolder animation={slideRight} colors={colors} />
<NotebookPlaceHolder animation={slideLeft} colors={colors} />
<NotebookPlaceHolder animation={slideRight} colors={colors} />
<Text
style={{
color: colors.icon,
fontSize: SIZE.sm,
fontFamily: WEIGHT.regular,
marginTop: 30,
}}>
Notebooks you add will appear here
</Text>
</View>
)
<Text
style={{
color: colors.icon,
fontSize: SIZE.sm,
fontFamily: WEIGHT.regular,
marginTop: 30,
}}>
Notebooks you add will appear here
</Text>
</View>
}
contentContainerStyle={{
width: '100%',

View File

@@ -35,7 +35,6 @@ export const Notebook = ({navigation}) => {
allTopics = db.notebooks.notebook(navigation.state.params.notebook.id).data
.topics;
console.log(allTopics);
notebook = db.notebooks.notebook(navigation.state.params.notebook.id);
@@ -67,13 +66,15 @@ export const Notebook = ({navigation}) => {
type: ACTIONS.CURRENT_SCREEN,
screen: 'notebook',
});
onLoad();
}
}, [isFocused]);
useEffect(() => {
eSubscribeEvent(eMoveNoteDialogNavigateBack, handleBackPress);
return () => {
eUnSubscribeEvent(eMoveNoteDialogNavigateBack, handleBackPress);
};
}, [isFocused]);
}, []);
const onScroll = event => {
let y = event.nativeEvent.contentOffset.y;

View File

@@ -18,6 +18,7 @@ import {ToastEvent} from '../../utils/utils';
import {eSendEvent} from '../../services/eventManager';
import {eScrollEvent} from '../../services/events';
import {NotesPlaceHolder} from '../../components/ListPlaceholders';
import {useIsFocused} from 'react-navigation-hooks';
export const Notes = ({navigation}) => {
const [state, dispatch] = useTracked();
@@ -25,6 +26,7 @@ export const Notes = ({navigation}) => {
const allNotes = state.notes;
const [notes, setNotes] = useState([]);
const [refreshing, setRefreshing] = useState(false);
const isFocused = useIsFocused();
let params = navigation.state ? navigation.state.params : null;
useEffect(() => {
@@ -34,6 +36,15 @@ export const Notes = ({navigation}) => {
};
}
}, []);
useEffect(() => {
if (isFocused) {
init();
dispatch({
type: ACTIONS.CURRENT_SCREEN,
screen: params.type,
});
}
}, [isFocused, allNotes, colorNotes]);
const init = () => {
eSendEvent(eScrollEvent, 0);
@@ -49,18 +60,12 @@ export const Notes = ({navigation}) => {
.notebook(params.notebookId)
.topics.topic(params.title).all;
console.log(allNotes, 'here getting topics');
if (allNotes && allNotes.length > 0) {
setNotes(allNotes);
}
}
};
useEffect(() => {
init();
}, [allNotes, colorNotes]);
const _renderItem = ({item, index}) => (
<SelectionWrapper
index={index}

View File

@@ -15,6 +15,7 @@ import {useTracked} from '../../provider';
import {ACTIONS} from '../../provider/actions';
import NavigationService from '../../services/NavigationService';
import {ToastEvent} from '../../utils/utils';
import {useIsFocused} from 'react-navigation-hooks';
const w = Dimensions.get('window').width;
const h = Dimensions.get('window').height;
@@ -22,13 +23,16 @@ export const Tags = ({navigation}) => {
const [state, dispatch] = useTracked();
const {colors, tags, selectionMode} = state;
const [refreshing, setRefreshing] = useState(false);
const isFocused = useIsFocused();
useEffect(() => {
dispatch({type: ACTIONS.TAGS});
dispatch({
type: ACTIONS.CURRENT_SCREEN,
screen: 'tags',
});
}, []);
if (isFocused) {
dispatch({type: ACTIONS.TAGS});
dispatch({
type: ACTIONS.CURRENT_SCREEN,
screen: 'tags',
});
}
}, [isFocused]);
return (
<Container

View File

@@ -13,21 +13,26 @@ import {useTracked} from '../../provider';
import {ACTIONS} from '../../provider/actions';
import {w, ToastEvent} from '../../utils/utils';
import SelectionWrapper from '../../components/SelectionWrapper';
import {useIsFocused} from 'react-navigation-hooks';
export const Trash = ({navigation}) => {
const [state, dispatch] = useTracked();
const {colors, selectionMode, trash} = state;
const [refreshing, setRefreshing] = useState(false);
useEffect(() => {
dispatch({
type: ACTIONS.TRASH,
});
const isFocused = useIsFocused();
dispatch({
type: ACTIONS.CURRENT_SCREEN,
screen: 'trash',
});
}, []);
useEffect(() => {
if (isFocused) {
dispatch({
type: ACTIONS.TRASH,
});
dispatch({
type: ACTIONS.CURRENT_SCREEN,
screen: 'trash',
});
}
}, [isFocused]);
const _renderItem = ({item, index}) => (
<SelectionWrapper colors={colors} item={item}>