From 4a4ca5a4d1297261885c928a59197c075a022647 Mon Sep 17 00:00:00 2001 From: ammarahm-ed Date: Sun, 1 Mar 2020 15:27:06 +0500 Subject: [PATCH 01/27] refactor --- apps/mobile/src/views/Editor/index.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/mobile/src/views/Editor/index.js b/apps/mobile/src/views/Editor/index.js index 71af92bd3..312298636 100755 --- a/apps/mobile/src/views/Editor/index.js +++ b/apps/mobile/src/views/Editor/index.js @@ -536,7 +536,6 @@ const Editor = ({navigation, noMenu}) => { }); } else if (!DDS.isTab) { handleBack = BackHandler.addEventListener('hardwareBackPress', () => { - console.log('tapCOunt', tapCount); if (tapCount > 0) { tapCount = 0; title = null; @@ -554,7 +553,6 @@ const Editor = ({navigation, noMenu}) => { } }); } else { - console.log(' I RUN EVERYTIME'); if (handleBack) { handleBack.remove(); handleBack = null; From 3aa61ab648adcd18955b96372b672279fa50c82e Mon Sep 17 00:00:00 2001 From: ammarahm-ed Date: Mon, 2 Mar 2020 09:34:46 +0500 Subject: [PATCH 02/27] return to previous screen after deleting note. --- .../src/components/ActionSheetComponent/index.js | 2 +- apps/mobile/src/components/Dialog/index.js | 9 +++++---- apps/mobile/src/utils/utils.js | 4 ++++ apps/mobile/src/views/Editor/index.js | 13 +++++++++++-- 4 files changed, 21 insertions(+), 7 deletions(-) diff --git a/apps/mobile/src/components/ActionSheetComponent/index.js b/apps/mobile/src/components/ActionSheetComponent/index.js index b3b2b9efc..5a4d04e70 100644 --- a/apps/mobile/src/components/ActionSheetComponent/index.js +++ b/apps/mobile/src/components/ActionSheetComponent/index.js @@ -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 diff --git a/apps/mobile/src/components/Dialog/index.js b/apps/mobile/src/components/Dialog/index.js index f3823b3c9..3efd4abbb 100644 --- a/apps/mobile/src/components/Dialog/index.js +++ b/apps/mobile/src/components/Dialog/index.js @@ -11,7 +11,7 @@ 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} from '../../utils/utils'; import {dialogActions, updateEvent} from '../DialogManager'; import {eSendEvent} from '../../services/eventManager'; import {eCloseFullscreenEditor} from '../../services/events'; @@ -35,13 +35,11 @@ export class Dialog extends Component { 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); @@ -52,6 +50,9 @@ export class Dialog extends Component { this.setState({ visible: false, }); + if (editing.currentlyEditing) { + NavigationService.goBack(); + } break; } case dialogActions.ACTION_EXIT: { diff --git a/apps/mobile/src/utils/utils.js b/apps/mobile/src/utils/utils.js index b6b39f0ff..b1454f65c 100755 --- a/apps/mobile/src/utils/utils.js +++ b/apps/mobile/src/utils/utils.js @@ -18,6 +18,10 @@ export const getElevation = elevation => { }; }; +export const editing = { + currentlyEditing: false, +}; + export function timeSince(date) { var seconds = Math.floor((new Date() - date) / 1000); diff --git a/apps/mobile/src/views/Editor/index.js b/apps/mobile/src/views/Editor/index.js index 312298636..6034d8cab 100755 --- a/apps/mobile/src/views/Editor/index.js +++ b/apps/mobile/src/views/Editor/index.js @@ -34,7 +34,12 @@ import { eOnLoadNote, eOpenFullscreenEditor, } from '../../services/events'; -import {SideMenuEvent, timeConverter, ToastEvent} from '../../utils/utils'; +import { + SideMenuEvent, + timeConverter, + ToastEvent, + editing, +} from '../../utils/utils'; import {AnimatedSafeAreaView} from '../Home'; import NavigationService from '../../services/NavigationService'; @@ -47,6 +52,7 @@ var title = null; let timer = null; let saveCounter = 0; let tapCount = 0; + const Editor = ({navigation, noMenu}) => { // Global State const [state, dispatch] = useTracked(); @@ -358,7 +364,7 @@ const Editor = ({navigation, noMenu}) => { content = null; note = null; id = null; - + ToastEvent.show('Note Saved!', 'success'); NavigationService.goBack(); } }} @@ -528,6 +534,7 @@ const Editor = ({navigation, noMenu}) => { }); useEffect(() => { + editing.currentlyEditing = true; let handleBack; if (!noMenu && DDS.isTab) { handleBack = BackHandler.addEventListener('hardwareBackPress', () => { @@ -542,6 +549,7 @@ const Editor = ({navigation, noMenu}) => { content = null; note = null; id = null; + ToastEvent.show('Note Saved!', 'success'); return false; } else { tapCount = 1; @@ -560,6 +568,7 @@ const Editor = ({navigation, noMenu}) => { } return () => { + editing.currentlyEditing = false; if (handleBack) { handleBack.remove(); handleBack = null; From 9b1c2971b7180df188ac905ca6be1ee4284e5ff9 Mon Sep 17 00:00:00 2001 From: ammarahm-ed Date: Mon, 2 Mar 2020 09:39:33 +0500 Subject: [PATCH 03/27] improve delete note ux --- apps/mobile/src/components/Dialog/index.js | 9 +++++++-- apps/mobile/src/views/Editor/index.js | 3 +++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/apps/mobile/src/components/Dialog/index.js b/apps/mobile/src/components/Dialog/index.js index 3efd4abbb..bcca20ca1 100644 --- a/apps/mobile/src/components/Dialog/index.js +++ b/apps/mobile/src/components/Dialog/index.js @@ -14,7 +14,7 @@ import NavigationService from '../../services/NavigationService'; import {getElevation, ToastEvent, editing} 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) { @@ -51,7 +51,12 @@ export class Dialog extends Component { visible: false, }); if (editing.currentlyEditing) { - NavigationService.goBack(); + if (DDS.isTab) { + eSendEvent(eCloseFullscreenEditor); + eSendEvent(eOnLoadNote, {type: 'new'}); + } else { + NavigationService.goBack(); + } } break; } diff --git a/apps/mobile/src/views/Editor/index.js b/apps/mobile/src/views/Editor/index.js index 6034d8cab..d9f747824 100755 --- a/apps/mobile/src/views/Editor/index.js +++ b/apps/mobile/src/views/Editor/index.js @@ -407,6 +407,7 @@ const Editor = ({navigation, noMenu}) => { onPress={() => { eSendEvent(eOpenFullscreenEditor); setFullscreen(true); + editing.isFullscreen = true; post( JSON.stringify({ type: 'nomenu', @@ -535,10 +536,12 @@ const Editor = ({navigation, noMenu}) => { 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) { From 5864ebe6d615fba4cc2ee484ac93945baf42b146 Mon Sep 17 00:00:00 2001 From: ammarahm-ed Date: Mon, 2 Mar 2020 10:25:38 +0500 Subject: [PATCH 04/27] improve multi-select ux --- apps/mobile/src/components/Dialog/index.js | 52 ++++++++++------ .../src/components/SelectionHeader/index.js | 6 +- apps/mobile/src/utils/utils.js | 5 ++ apps/mobile/src/views/Editor/index.js | 59 +++++++++++-------- 4 files changed, 76 insertions(+), 46 deletions(-) diff --git a/apps/mobile/src/components/Dialog/index.js b/apps/mobile/src/components/Dialog/index.js index bcca20ca1..955d06465 100644 --- a/apps/mobile/src/components/Dialog/index.js +++ b/apps/mobile/src/components/Dialog/index.js @@ -11,7 +11,7 @@ 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, editing} from '../../utils/utils'; +import {getElevation, ToastEvent, editing, history} from '../../utils/utils'; import {dialogActions, updateEvent} from '../DialogManager'; import {eSendEvent} from '../../services/eventManager'; import {eCloseFullscreenEditor, eOnLoadNote} from '../../services/events'; @@ -21,6 +21,7 @@ export class Dialog extends Component { super(props); this.state = { visible: false, + selecteItemsLength: 0, }; } @@ -29,23 +30,29 @@ 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') { - 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, @@ -87,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) + @@ -95,6 +102,7 @@ export class Dialog extends Component { 'success', 3000, ); + updateEvent({type: ACTIONS.TRASH}); this.hide(); break; @@ -114,8 +122,10 @@ export class Dialog extends Component { }; show = () => { + console.log(history.selectedItemsList.length, 'length'); this.setState({ visible: true, + selectedItemsLength: history.selectedItemsList.length, }); }; hide = () => { @@ -193,7 +203,11 @@ export class Dialog extends Component { textAlign: 'center', marginTop: 10, }}> - {paragraph} + {this.state.selectedItemsLength > 0 + ? 'Delete ' + + this.state.selectedItemsLength + + ' selected items?' + : paragraph} ) : null} diff --git a/apps/mobile/src/components/SelectionHeader/index.js b/apps/mobile/src/components/SelectionHeader/index.js index 122553a4b..10dd826fc 100644 --- a/apps/mobile/src/components/SelectionHeader/index.js +++ b/apps/mobile/src/components/SelectionHeader/index.js @@ -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}) => { { dispatch({type: ACTIONS.SELECTION_MODE, enabled: false}); + dispatch({type: ACTIONS.CLEAR_SELECTION}); eSendEvent(eOpenMoveNoteDialog); }}> { {currentScreen === 'trash' ? null : ( { + eSendEvent(eOpenSimpleDialog, TEMPLATE_DELETE('item')); + return; if (selectedItemsList.length > 0) { let noteIds = []; selectedItemsList.forEach(item => { diff --git a/apps/mobile/src/utils/utils.js b/apps/mobile/src/utils/utils.js index b1454f65c..b4da56aeb 100755 --- a/apps/mobile/src/utils/utils.js +++ b/apps/mobile/src/utils/utils.js @@ -20,6 +20,11 @@ export const getElevation = elevation => { export const editing = { currentlyEditing: false, + isFullscreen: false, +}; + +export const history = { + selectedItemsList: [], }; export function timeSince(date) { diff --git a/apps/mobile/src/views/Editor/index.js b/apps/mobile/src/views/Editor/index.js index d9f747824..e81323439 100755 --- a/apps/mobile/src/views/Editor/index.js +++ b/apps/mobile/src/views/Editor/index.js @@ -355,17 +355,11 @@ const Editor = ({navigation, noMenu}) => { {noMenu ? null : ( { + onPress={async () => { if (DDS.isTab) { simpleDialogEvent(TEMPLATE_EXIT_FULLSCREEN()); } else { - tapCount = 0; - title = null; - content = null; - note = null; - id = null; - ToastEvent.show('Note Saved!', 'success'); - NavigationService.goBack(); + await closeEditor(); } }} style={{ @@ -534,6 +528,33 @@ const Editor = ({navigation, noMenu}) => { }; }); + const closeEditor = async () => { + await saveNote(); + title = null; + content = null; + note = null; + id = null; + dateEdited = null; + tapCount = 0; + NavigationService.goBack(); + ToastEvent.show('Note Saved!', 'success'); + }; + + const _onHardwareBackPress = async () => { + if (tapCount > 0) { + await closeEditor(); + + return true; + } else { + tapCount = 1; + setTimeout(() => { + tapCount = 0; + }, 3000); + ToastEvent.show('Press back again to exit editor', 'success'); + return true; + } + }; + useEffect(() => { editing.currentlyEditing = true; @@ -545,24 +566,10 @@ const Editor = ({navigation, noMenu}) => { return true; }); } else if (!DDS.isTab) { - handleBack = BackHandler.addEventListener('hardwareBackPress', () => { - if (tapCount > 0) { - tapCount = 0; - title = null; - content = null; - note = null; - id = null; - ToastEvent.show('Note Saved!', 'success'); - return false; - } else { - tapCount = 1; - setTimeout(() => { - tapCount = 0; - }, 3000); - ToastEvent.show('Press back again to exit editor', 'success'); - return true; - } - }); + handleBack = BackHandler.addEventListener( + 'hardwareBackPress', + _onHardwareBackPress, + ); } else { if (handleBack) { handleBack.remove(); From 66663385d7e18a0f7c1251e0adf648528545ac0b Mon Sep 17 00:00:00 2001 From: ammarahm-ed Date: Mon, 2 Mar 2020 10:25:52 +0500 Subject: [PATCH 05/27] refactor --- apps/mobile/src/views/Folders/index.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/apps/mobile/src/views/Folders/index.js b/apps/mobile/src/views/Folders/index.js index f51edd1b0..435fcaa58 100644 --- a/apps/mobile/src/views/Folders/index.js +++ b/apps/mobile/src/views/Folders/index.js @@ -46,12 +46,10 @@ export const Folders = ({navigation}) => { dispatch({type: ACTIONS.NOTEBOOKS}); if (isFocused) { - if (isFocused) { - dispatch({ - type: ACTIONS.CURRENT_SCREEN, - screen: 'notebooks', - }); - } + dispatch({ + type: ACTIONS.CURRENT_SCREEN, + screen: 'notebooks', + }); } let backhandler; From b4ec7136aecef1d26a0595f780b9aef57b590f05 Mon Sep 17 00:00:00 2001 From: ammarahm-ed Date: Mon, 2 Mar 2020 10:40:55 +0500 Subject: [PATCH 06/27] cleanup --- apps/mobile/src/components/NotebookItem/index.js | 2 +- apps/mobile/src/components/NotesList/index.js | 2 +- apps/mobile/src/provider/reducer.js | 5 +++-- apps/mobile/src/services/validation.js | 10 ---------- 4 files changed, 5 insertions(+), 14 deletions(-) diff --git a/apps/mobile/src/components/NotebookItem/index.js b/apps/mobile/src/components/NotebookItem/index.js index 39ad7c277..254faef7f 100644 --- a/apps/mobile/src/components/NotebookItem/index.js +++ b/apps/mobile/src/components/NotebookItem/index.js @@ -243,7 +243,7 @@ export const NotebookItem = ({ onPress={async () => { let noteIds = []; selectedItemsList.forEach(item => noteIds.push(item.id)); - console.log(noteIds); + db.notes.move( { topic: item.title, diff --git a/apps/mobile/src/components/NotesList/index.js b/apps/mobile/src/components/NotesList/index.js index 60065356f..32400deaa 100644 --- a/apps/mobile/src/components/NotesList/index.js +++ b/apps/mobile/src/components/NotesList/index.js @@ -194,7 +194,7 @@ export const NotesList = ({isGrouped = false}) => { ); const _listKeyExtractor = (item, index) => item.id.toString(); - console.log(notes); + return isGrouped && searchResults.length === 0 ? ( (sectionListRef = ref)} diff --git a/apps/mobile/src/provider/reducer.js b/apps/mobile/src/provider/reducer.js index 8d4367152..50c2c2571 100644 --- a/apps/mobile/src/provider/reducer.js +++ b/apps/mobile/src/provider/reducer.js @@ -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) => { @@ -99,13 +99,14 @@ export const reducer = (state, action) => { } else { selectedItems.push(action.item); } - + history.selectedItemsList = selectedItems; return { ...state, selectedItemsList: selectedItems, }; } case ACTIONS.CLEAR_SELECTION: { + history.selectedItemsList = []; return { ...state, selectedItemsList: [], diff --git a/apps/mobile/src/services/validation.js b/apps/mobile/src/services/validation.js index de3e5f9dc..95bf33840 100644 --- a/apps/mobile/src/services/validation.js +++ b/apps/mobile/src/services/validation.js @@ -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; } } From 75c684920e22fed1e17b5911eb7b723f9f718435 Mon Sep 17 00:00:00 2001 From: ammarahm-ed Date: Mon, 2 Mar 2020 10:42:18 +0500 Subject: [PATCH 07/27] fix crash on longpress pin item --- apps/mobile/src/components/NotesList/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/mobile/src/components/NotesList/index.js b/apps/mobile/src/components/NotesList/index.js index 32400deaa..6daad645e 100644 --- a/apps/mobile/src/components/NotesList/index.js +++ b/apps/mobile/src/components/NotesList/index.js @@ -194,7 +194,7 @@ export const NotesList = ({isGrouped = false}) => { ); const _listKeyExtractor = (item, index) => item.id.toString(); - + return isGrouped && searchResults.length === 0 ? ( (sectionListRef = ref)} @@ -288,6 +288,7 @@ const PinnedItems = () => { borderBottomWidth: 0, marginHorizontal: 0, }} + onLongPress={() => {}} pinned={true} item={item} index={index} From cf8564f654d44e54672f91dff23043110a772279 Mon Sep 17 00:00:00 2001 From: ammarahm-ed Date: Mon, 2 Mar 2020 10:54:51 +0500 Subject: [PATCH 08/27] fix crash onLongPress --- apps/mobile/src/views/Favorites/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/mobile/src/views/Favorites/index.js b/apps/mobile/src/views/Favorites/index.js index 746d4def2..e4ce492b1 100644 --- a/apps/mobile/src/views/Favorites/index.js +++ b/apps/mobile/src/views/Favorites/index.js @@ -10,7 +10,7 @@ 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'; export const Favorites = ({navigation}) => { const [state, dispatch] = useTracked(); From 6dc985bf136cfe958d9522fac8c93d9c98fe704f Mon Sep 17 00:00:00 2001 From: ammarahm-ed Date: Mon, 2 Mar 2020 11:13:40 +0500 Subject: [PATCH 09/27] fix favorite from multi-select --- apps/mobile/src/components/SelectionHeader/index.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/mobile/src/components/SelectionHeader/index.js b/apps/mobile/src/components/SelectionHeader/index.js index 10dd826fc..f0a754988 100644 --- a/apps/mobile/src/components/SelectionHeader/index.js +++ b/apps/mobile/src/components/SelectionHeader/index.js @@ -125,10 +125,14 @@ export const SelectionHeader = ({navigation}) => { if (selectedItemsList.length > 0) { selectedItemsList.forEach(async item => { 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'); } }}> From 65868d66a5aea183293d5cc3b2ad06e611d178a9 Mon Sep 17 00:00:00 2001 From: ammarahm-ed Date: Mon, 2 Mar 2020 12:07:19 +0500 Subject: [PATCH 10/27] improve multi-select ux --- .../src/components/SelectionHeader/index.js | 15 +++++++++++- apps/mobile/src/views/Folders/index.js | 24 +++++++++---------- 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/apps/mobile/src/components/SelectionHeader/index.js b/apps/mobile/src/components/SelectionHeader/index.js index f0a754988..f6b89dc05 100644 --- a/apps/mobile/src/components/SelectionHeader/index.js +++ b/apps/mobile/src/components/SelectionHeader/index.js @@ -122,8 +122,15 @@ export const SelectionHeader = ({navigation}) => { {currentScreen === 'trash' || currentScreen === 'notebooks' ? null : ( { + 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}); @@ -133,7 +140,13 @@ export const SelectionHeader = ({navigation}) => { dispatch({type: ACTIONS.CLEAR_SELECTION}); - ToastEvent.show('Notes added to favorites', 'success'); + ToastEvent.show( + favCount + + ' notes added to favorites &' + + unFavCount + + 'removed', + 'success', + ); } }}> { const [refreshing, setRefreshing] = useState(false); let isFocused = useIsFocused(); - /// - const handleBackPress = () => { alert('here'); return true; @@ -143,20 +141,20 @@ export const Folders = ({navigation}) => { { - dispatch({ - type: ACTIONS.SELECTION_MODE, - enabled: !selectionMode, - }); - dispatch({ - type: ACTIONS.SELECTED_ITEMS, - item: item, - }); - }} + onLongPress={() => {}} noteToMove={params.note} item={item} pinned={true} From 437f7ade9a986d1372237bcee96f279024390ca6 Mon Sep 17 00:00:00 2001 From: ammarahm-ed Date: Mon, 2 Mar 2020 12:10:13 +0500 Subject: [PATCH 11/27] focus title input when on notebook dialog open --- apps/mobile/src/components/AddNotebookDialog/index.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/mobile/src/components/AddNotebookDialog/index.js b/apps/mobile/src/components/AddNotebookDialog/index.js index 22033a1e3..2b9f42cf6 100644 --- a/apps/mobile/src/components/AddNotebookDialog/index.js +++ b/apps/mobile/src/components/AddNotebookDialog/index.js @@ -205,6 +205,11 @@ export class AddNotebookDialog extends React.Component { transparent={true} animated animationType="fade" + onShow={() => { + setTimeout(() => { + this.titleRef.focus(); + }, 300); + }} onRequestClose={this.close}> Date: Mon, 2 Mar 2020 12:12:23 +0500 Subject: [PATCH 12/27] fix focus on dialog open --- apps/mobile/src/components/AddNotebookDialog/index.js | 4 +--- apps/mobile/src/components/AddTopicDialog/index.js | 7 ++++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/apps/mobile/src/components/AddNotebookDialog/index.js b/apps/mobile/src/components/AddNotebookDialog/index.js index 2b9f42cf6..8f0eb627a 100644 --- a/apps/mobile/src/components/AddNotebookDialog/index.js +++ b/apps/mobile/src/components/AddNotebookDialog/index.js @@ -206,9 +206,7 @@ export class AddNotebookDialog extends React.Component { animated animationType="fade" onShow={() => { - setTimeout(() => { - this.titleRef.focus(); - }, 300); + this.titleRef.focus(); }} onRequestClose={this.close}> { @@ -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 { Date: Mon, 2 Mar 2020 13:52:09 +0500 Subject: [PATCH 13/27] fix crash on close vault dialog --- .../src/components/VaultDialog/index.js | 30 ++++++++----------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/apps/mobile/src/components/VaultDialog/index.js b/apps/mobile/src/components/VaultDialog/index.js index 3fd97cc75..6385364c9 100644 --- a/apps/mobile/src/components/VaultDialog/index.js +++ b/apps/mobile/src/components/VaultDialog/index.js @@ -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 () => { From 161061c0a8ee9a80de058d83005575f7ef7324d8 Mon Sep 17 00:00:00 2001 From: ammarahm-ed Date: Mon, 2 Mar 2020 13:54:42 +0500 Subject: [PATCH 14/27] fix navigation menu scrolling --- apps/mobile/src/components/Menu/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/mobile/src/components/Menu/index.js b/apps/mobile/src/components/Menu/index.js index a8476aead..c0d57e5ba 100644 --- a/apps/mobile/src/components/Menu/index.js +++ b/apps/mobile/src/components/Menu/index.js @@ -189,7 +189,7 @@ export const Menu = ({ )} Date: Mon, 2 Mar 2020 14:10:50 +0500 Subject: [PATCH 15/27] fix placeholder not showing in notebooks --- apps/mobile/src/components/NotesList/index.js | 2 +- apps/mobile/src/provider/defaultState.js | 5 +- apps/mobile/src/provider/reducer.js | 9 +- apps/mobile/src/views/Folders/index.js | 102 +++++++++--------- 4 files changed, 63 insertions(+), 55 deletions(-) diff --git a/apps/mobile/src/components/NotesList/index.js b/apps/mobile/src/components/NotesList/index.js index 6daad645e..41ff71649 100644 --- a/apps/mobile/src/components/NotesList/index.js +++ b/apps/mobile/src/components/NotesList/index.js @@ -269,7 +269,7 @@ const PinnedItems = () => { return ( <> item.id.toString()} renderItem={({item, index}) => item.type === 'note' ? ( diff --git a/apps/mobile/src/provider/defaultState.js b/apps/mobile/src/provider/defaultState.js index c1fda7da0..2e01c94ba 100644 --- a/apps/mobile/src/provider/defaultState.js +++ b/apps/mobile/src/provider/defaultState.js @@ -8,7 +8,10 @@ export const defaultState = { notebooks: [], trash: [], favorites: [], - pinned: [], + pinned: { + notes: [], + notebooks: [], + }, tags: [], colorNotes: [], user: {}, diff --git a/apps/mobile/src/provider/reducer.js b/apps/mobile/src/provider/reducer.js index 50c2c2571..8f0f2c858 100644 --- a/apps/mobile/src/provider/reducer.js +++ b/apps/mobile/src/provider/reducer.js @@ -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: { diff --git a/apps/mobile/src/views/Folders/index.js b/apps/mobile/src/views/Folders/index.js index f9a048947..11c28b872 100644 --- a/apps/mobile/src/views/Folders/index.js +++ b/apps/mobile/src/views/Folders/index.js @@ -39,6 +39,10 @@ export const Folders = ({navigation}) => { return true; }; + useEffect(() => { + dispatch({type: ACTIONS.PINNED}); + }, []); + useEffect(() => { eSendEvent(eScrollEvent, 0); dispatch({type: ACTIONS.NOTEBOOKS}); @@ -130,38 +134,36 @@ export const Folders = ({navigation}) => { ? 155 : 155 - 60, }}> - {pinned && pinned.length > 0 ? ( + {pinned && pinned.notebooks && pinned.notebooks.length > 0 ? ( <> item.id.toString()} renderItem={({item, index}) => item.type === 'notebook' ? ( - - {}} - noteToMove={params.note} - item={item} - pinned={true} - index={index} - colors={colors} - /> - + {}} + noteToMove={params.note} + item={item} + pinned={true} + index={index} + colors={colors} + /> ) : null } /> @@ -170,31 +172,29 @@ export const Folders = ({navigation}) => { } ListEmptyComponent={ - pinned && pinned.length > 0 ? null : ( - - - - + + + + - - Notebooks you add will appear here - - - ) + + Notebooks you add will appear here + + } contentContainerStyle={{ width: '100%', From c20e36d29268b6b9ddb693af82e4ecd5cf5cbc17 Mon Sep 17 00:00:00 2001 From: ammarahm-ed Date: Mon, 2 Mar 2020 14:28:40 +0500 Subject: [PATCH 16/27] fix views not updating --- apps/mobile/src/utils/storage.js | 24 +++++++++++++------ apps/mobile/src/views/Favorites/index.js | 17 +++++++++----- apps/mobile/src/views/Folders/index.js | 30 +++++++++--------------- apps/mobile/src/views/Notebook/index.js | 7 +++--- apps/mobile/src/views/Notes/index.js | 17 +++++++++----- apps/mobile/src/views/Tags/index.js | 16 ++++++++----- apps/mobile/src/views/Trash/index.js | 23 +++++++++++------- 7 files changed, 78 insertions(+), 56 deletions(-) diff --git a/apps/mobile/src/utils/storage.js b/apps/mobile/src/utils/storage.js index 31e4399b4..d98f34c21 100644 --- a/apps/mobile/src/utils/storage.js +++ b/apps/mobile/src/utils/storage.js @@ -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; + }); }); }); } diff --git a/apps/mobile/src/views/Favorites/index.js b/apps/mobile/src/views/Favorites/index.js index e4ce492b1..ae2b3a925 100644 --- a/apps/mobile/src/views/Favorites/index.js +++ b/apps/mobile/src/views/Favorites/index.js @@ -11,18 +11,23 @@ import {ACTIONS} from '../../provider/actions'; import {eSendEvent} from '../../services/eventManager'; import {eScrollEvent} from '../../services/events'; 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; diff --git a/apps/mobile/src/views/Folders/index.js b/apps/mobile/src/views/Folders/index.js index 11c28b872..f8251b734 100644 --- a/apps/mobile/src/views/Folders/index.js +++ b/apps/mobile/src/views/Folders/index.js @@ -40,39 +40,31 @@ export const Folders = ({navigation}) => { }; useEffect(() => { - dispatch({type: ACTIONS.PINNED}); - }, []); - - useEffect(() => { - eSendEvent(eScrollEvent, 0); - dispatch({type: ACTIONS.NOTEBOOKS}); - if (isFocused) { + dispatch({type: ACTIONS.PINNED}); + dispatch({type: ACTIONS.NOTEBOOKS}); dispatch({ type: ACTIONS.CURRENT_SCREEN, screen: 'notebooks', }); } + }, [isFocused]); + useEffect(() => { + eSendEvent(eScrollEvent, 0); 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; diff --git a/apps/mobile/src/views/Notebook/index.js b/apps/mobile/src/views/Notebook/index.js index 127794dec..b107322e8 100644 --- a/apps/mobile/src/views/Notebook/index.js +++ b/apps/mobile/src/views/Notebook/index.js @@ -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; diff --git a/apps/mobile/src/views/Notes/index.js b/apps/mobile/src/views/Notes/index.js index c00787de7..85ca828b7 100644 --- a/apps/mobile/src/views/Notes/index.js +++ b/apps/mobile/src/views/Notes/index.js @@ -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: param.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}) => ( { 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 ( { 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}) => ( From 11584ef0061e247f6b98f58c9ad4299d83bf6830 Mon Sep 17 00:00:00 2001 From: ammarahm-ed Date: Mon, 2 Mar 2020 14:30:50 +0500 Subject: [PATCH 17/27] fix crash --- apps/mobile/src/views/Notes/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/mobile/src/views/Notes/index.js b/apps/mobile/src/views/Notes/index.js index 85ca828b7..06cea7a3a 100644 --- a/apps/mobile/src/views/Notes/index.js +++ b/apps/mobile/src/views/Notes/index.js @@ -41,7 +41,7 @@ export const Notes = ({navigation}) => { init(); dispatch({ type: ACTIONS.CURRENT_SCREEN, - screen: param.type, + screen: params.type, }); } }, [isFocused, allNotes, colorNotes]); From 75d06b293e84c8953a000494b2e216d0f0d6f1ff Mon Sep 17 00:00:00 2001 From: ammarahm-ed Date: Mon, 2 Mar 2020 15:00:55 +0500 Subject: [PATCH 18/27] fix tagInput focus, prevent invalid input. --- .../components/ActionSheetComponent/index.js | 47 +++++++++++++++---- 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/apps/mobile/src/components/ActionSheetComponent/index.js b/apps/mobile/src/components/ActionSheetComponent/index.js index 5a4d04e70..56494a86d 100644 --- a/apps/mobile/src/components/ActionSheetComponent/index.js +++ b/apps/mobile/src/components/ActionSheetComponent/index.js @@ -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, @@ -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', @@ -680,11 +697,21 @@ export const ActionSheetComponent = ({ borderColor: focused ? colors.accent : colors.nav, paddingVertical: 5, }}> + { + tagsInputRef.current?.focus(); + }} + style={{ + position: 'absolute', + width: '100%', + height: '100%', + }}> {note && note.tags ? note.tags.map(_renderTag) : null} (tagsInputRef = ref)} + ref={tagsInputRef} placeholderTextColor={colors.icon} onFocus={() => { setFocused(true); From a88d53024cb85efde1fd741bed4915bea5785f03 Mon Sep 17 00:00:00 2001 From: ammarahm-ed Date: Mon, 2 Mar 2020 15:02:46 +0500 Subject: [PATCH 19/27] fix searchInput icon showing as '?'. --- apps/mobile/src/components/SearchInput/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/mobile/src/components/SearchInput/index.js b/apps/mobile/src/components/SearchInput/index.js index 40a5544dd..1755a722d 100644 --- a/apps/mobile/src/components/SearchInput/index.js +++ b/apps/mobile/src/components/SearchInput/index.js @@ -98,7 +98,7 @@ export const Search = props => { text: '', }); }} - name={searchResults.length > 0 ? 'x' : 'magnify'} + name={searchResults.length > 0 ? 'close' : 'magnify'} color={ focus ? props.headerColor From a2533bfd2eb54467342089872312f9b06dd1e3df Mon Sep 17 00:00:00 2001 From: ammarahm-ed Date: Mon, 2 Mar 2020 15:05:05 +0500 Subject: [PATCH 20/27] fix search value not clear on searchInput --- apps/mobile/src/components/NotesList/index.js | 4 ++++ apps/mobile/src/components/SearchInput/index.js | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/mobile/src/components/NotesList/index.js b/apps/mobile/src/components/NotesList/index.js index 41ff71649..69c5fe90f 100644 --- a/apps/mobile/src/components/NotesList/index.js +++ b/apps/mobile/src/components/NotesList/index.js @@ -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(); @@ -178,6 +179,9 @@ export const NotesList = ({isGrouped = false}) => { { + inputRef.current?.setNativeProps({ + text: '', + }); dispatch({ type: ACTIONS.SEARCH_RESULTS, results: [], diff --git a/apps/mobile/src/components/SearchInput/index.js b/apps/mobile/src/components/SearchInput/index.js index 1755a722d..b1a49b3f8 100644 --- a/apps/mobile/src/components/SearchInput/index.js +++ b/apps/mobile/src/components/SearchInput/index.js @@ -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); From 868bccfbff939fe4ad0200a0005e9f1fb7926bed Mon Sep 17 00:00:00 2001 From: ammarahm-ed Date: Mon, 2 Mar 2020 15:08:32 +0500 Subject: [PATCH 21/27] fix selection mode not clear when 0 items in select --- apps/mobile/src/provider/reducer.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/mobile/src/provider/reducer.js b/apps/mobile/src/provider/reducer.js index 8f0f2c858..6e8035048 100644 --- a/apps/mobile/src/provider/reducer.js +++ b/apps/mobile/src/provider/reducer.js @@ -105,9 +105,11 @@ export const reducer = (state, action) => { selectedItems.push(action.item); } history.selectedItemsList = selectedItems; + return { ...state, selectedItemsList: selectedItems, + selectionMode: selectedItems.length > 0 ? true : false, }; } case ACTIONS.CLEAR_SELECTION: { From bbc2d5ea78d00c7ce4b37b0bbffefe4651b5804c Mon Sep 17 00:00:00 2001 From: ammarahm-ed Date: Mon, 2 Mar 2020 15:10:49 +0500 Subject: [PATCH 22/27] change delet icon color to red. --- apps/mobile/src/components/ActionSheetComponent/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/mobile/src/components/ActionSheetComponent/index.js b/apps/mobile/src/components/ActionSheetComponent/index.js index 56494a86d..e6390a98a 100644 --- a/apps/mobile/src/components/ActionSheetComponent/index.js +++ b/apps/mobile/src/components/ActionSheetComponent/index.js @@ -439,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} /> Date: Mon, 2 Mar 2020 15:12:34 +0500 Subject: [PATCH 23/27] fix selectionMode space on top durin search --- apps/mobile/src/components/NotesList/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/mobile/src/components/NotesList/index.js b/apps/mobile/src/components/NotesList/index.js index 69c5fe90f..5a025e29d 100644 --- a/apps/mobile/src/components/NotesList/index.js +++ b/apps/mobile/src/components/NotesList/index.js @@ -156,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', From e85cd38988acc6303333f2f2c5a058c265e7a557 Mon Sep 17 00:00:00 2001 From: ammarahm-ed Date: Mon, 2 Mar 2020 15:16:46 +0500 Subject: [PATCH 24/27] show number of notes zero on topic --- .../src/components/NotebookItem/index.js | 33 +++++++++---------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/apps/mobile/src/components/NotebookItem/index.js b/apps/mobile/src/components/NotebookItem/index.js index 254faef7f..f1a3fa6b5 100644 --- a/apps/mobile/src/components/NotebookItem/index.js +++ b/apps/mobile/src/components/NotebookItem/index.js @@ -193,22 +193,21 @@ export const NotebookItem = ({ )} - {isTopic && item.totalNotes > 0 ? ( - - {item && item.totalNotes && item.totalNotes > 1 - ? item.totalNotes + ' notes' - : item.totalNotes === 1 - ? item.totalNotes + ' note' - : null} - - ) : null} + + + {item && item.totalNotes && item.totalNotes > 1 + ? item.totalNotes + ' notes' + : item.totalNotes === 1 + ? item.totalNotes + ' note' + : '0 notes'} + {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)); - + db.notes.move( { topic: item.title, From 2dd7d937be976170a41d302175f200d79ba086b1 Mon Sep 17 00:00:00 2001 From: ammarahm-ed Date: Mon, 2 Mar 2020 15:20:22 +0500 Subject: [PATCH 25/27] fix topic not added --- .../src/components/AddNotebookDialog/index.js | 55 +++++++++++-------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/apps/mobile/src/components/AddNotebookDialog/index.js b/apps/mobile/src/components/AddNotebookDialog/index.js index 8f0eb627a..ac57f1026 100644 --- a/apps/mobile/src/components/AddNotebookDialog/index.js +++ b/apps/mobile/src/components/AddNotebookDialog/index.js @@ -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 = () => { From 231cde44e116fe8e01b01822fcedf5cd61297fbf Mon Sep 17 00:00:00 2001 From: ammarahm-ed Date: Mon, 2 Mar 2020 15:24:14 +0500 Subject: [PATCH 26/27] fix search results not clear on navigate. --- apps/mobile/src/components/Menu/index.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/mobile/src/components/Menu/index.js b/apps/mobile/src/components/Menu/index.js index c0d57e5ba..3c742f8fd 100644 --- a/apps/mobile/src/components/Menu/index.js +++ b/apps/mobile/src/components/Menu/index.js @@ -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 = () => {}, @@ -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={{ From 55a6b11e20c7922e46c1b7c9dd24e9c40970f53b Mon Sep 17 00:00:00 2001 From: ammarahm-ed Date: Tue, 3 Mar 2020 09:49:54 +0500 Subject: [PATCH 27/27] improve editor performance --- apps/mobile/App.js | 25 +- apps/mobile/src/components/NoteItem/index.js | 16 +- apps/mobile/src/components/Toast/index.js | 8 +- apps/mobile/src/utils/animations.js | 25 ++ apps/mobile/src/utils/utils.js | 4 +- apps/mobile/src/views/Editor/index.js | 356 +++++++------------ 6 files changed, 198 insertions(+), 236 deletions(-) diff --git a/apps/mobile/App.js b/apps/mobile/App.js index 7aea56c3b..7905d4c2a 100644 --- a/apps/mobile/App.js +++ b/apps/mobile/App.js @@ -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 = () => { /> )} + + (editorRef = ref)} + style={{ + width: '100%', + height: '100%', + position: 'absolute', + zIndex: 10, + backgroundColor: colors.bg, + elevation: 10, + transform: [ + { + translateX: EditorPosition, + }, + ], + }}> + + + + diff --git a/apps/mobile/src/components/NoteItem/index.js b/apps/mobile/src/components/NoteItem/index.js index 11b55ec7c..38b0e45a6 100644 --- a/apps/mobile/src/components/NoteItem/index.js +++ b/apps/mobile/src/components/NoteItem/index.js @@ -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={{ diff --git a/apps/mobile/src/components/Toast/index.js b/apps/mobile/src/components/Toast/index.js index 5bc743650..61befb6d5 100644 --- a/apps/mobile/src/components/Toast/index.js +++ b/apps/mobile/src/components/Toast/index.js @@ -65,16 +65,17 @@ export const Toast = () => { return ( { }}> { borderRadius: 5, paddingHorizontal: ph, paddingVertical: pv, + opacity: toast ? 1 : 0, justifyContent: 'center', elevation: 25, flexDirection: 'row', diff --git a/apps/mobile/src/utils/animations.js b/apps/mobile/src/utils/animations.js index 0b2159f40..2b3ad2671 100644 --- a/apps/mobile/src/utils/animations.js +++ b/apps/mobile/src/utils/animations.js @@ -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}], diff --git a/apps/mobile/src/utils/utils.js b/apps/mobile/src/utils/utils.js index b4da56aeb..d10b6e84e 100755 --- a/apps/mobile/src/utils/utils.js +++ b/apps/mobile/src/utils/utils.js @@ -58,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, @@ -67,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, diff --git a/apps/mobile/src/views/Editor/index.js b/apps/mobile/src/views/Editor/index.js index e81323439..fec9173f2 100755 --- a/apps/mobile/src/views/Editor/index.js +++ b/apps/mobile/src/views/Editor/index.js @@ -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,19 +32,17 @@ import { eOnLoadNote, eOpenFullscreenEditor, } from '../../services/events'; +import {exitEditorAnimation} from '../../utils/animations'; import { + editing, SideMenuEvent, timeConverter, ToastEvent, - editing, } from '../../utils/utils'; -import {AnimatedSafeAreaView} from '../Home'; -import NavigationService from '../../services/NavigationService'; -let EditorWebView; +const EditorWebView = createRef(); let note = {}; let id = null; -let dateEdited = null; var content = null; var title = null; let timer = null; @@ -57,12 +53,18 @@ 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); @@ -71,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'); }; @@ -137,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' @@ -171,8 +160,6 @@ const Editor = ({navigation, noMenu}) => { }; } - console.log(content.delta, 'i am called'); - let rId = await db.notes.add({ title, content: { @@ -195,8 +182,7 @@ const Editor = ({navigation, noMenu}) => { } }, 500); } - - if (DDS.isTab) { + if (id) { dispatch({ type: ACTIONS.CURRENT_EDITING_NOTE, id: id, @@ -254,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); @@ -280,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 === '') { @@ -303,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 { @@ -324,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); - }); } }; @@ -340,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 ( + { if (DDS.isTab) { simpleDialogEvent(TEMPLATE_EXIT_FULLSCREEN()); } else { - await closeEditor(); + exitEditorAnimation(); + await clearEditor(); + ToastEvent.show('Note Saved!', 'success'); } }} style={{ @@ -469,7 +521,7 @@ const Editor = ({navigation, noMenu}) => { (EditorWebView = ref)} + ref={EditorWebView} onError={error => console.log(error)} onLoad={onWebViewLoad} javaScriptEnabled={true} @@ -511,149 +563,7 @@ const Editor = ({navigation, noMenu}) => { onMessage={_onMessage} /> - ); - }; - - const closeFullscreen = () => { - setFullscreen(false); - }; - - // EFFECTS - - useEffect(() => { - eSubscribeEvent(eCloseFullscreenEditor, closeFullscreen); - - return () => { - eUnSubscribeEvent(eCloseFullscreenEditor, closeFullscreen); - }; - }); - - const closeEditor = async () => { - await saveNote(); - title = null; - content = null; - note = null; - id = null; - dateEdited = null; - tapCount = 0; - NavigationService.goBack(); - ToastEvent.show('Note Saved!', 'success'); - }; - - const _onHardwareBackPress = async () => { - if (tapCount > 0) { - await closeEditor(); - - 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(); - }; - }); - - useEffect(() => { - EditorWebView.reload(); - }, [colors]); - - return ( - - - - - - Write with confidence. - - - - - {_renderEditor()} - - + ); };