diff --git a/apps/mobile/index.tablet.js b/apps/mobile/index.tablet.js index 1144d96d3..d40576bbb 100644 --- a/apps/mobile/index.tablet.js +++ b/apps/mobile/index.tablet.js @@ -1,4 +1,4 @@ -import React, {createRef, useEffect} from 'react'; +import React, {createRef, useEffect, useState} from 'react'; import {Platform, StatusBar, View} from 'react-native'; import * as Animatable from 'react-native-animatable'; import {Menu} from './src/components/Menu'; @@ -8,6 +8,11 @@ import NavigationService, { AppContainer, } from './src/services/NavigationService'; import Editor from './src/views/Editor'; +import {eSubscribeEvent} from './src/services/eventManager'; +import { + eOpenFullscreenEditor, + eCloseFullscreenEditor, +} from './src/services/events'; const editorRef = createRef(); let outColors; diff --git a/apps/mobile/src/components/ActionSheet/index.js b/apps/mobile/src/components/ActionSheet/index.js index 388e3da07..48616dfa9 100644 --- a/apps/mobile/src/components/ActionSheet/index.js +++ b/apps/mobile/src/components/ActionSheet/index.js @@ -1,4 +1,4 @@ -import React, {Component} from 'react'; +import React, {Component, createRef} from 'react'; import { View, TouchableOpacity, @@ -8,11 +8,12 @@ import { KeyboardAvoidingView, Platform, Animated, + DeviceEventEmitter, } from 'react-native'; import PropTypes from 'prop-types'; import {styles} from './styles'; -const deviceHeight = Dimensions.get('window').height; +var deviceHeight = Dimensions.get('window').height; const getElevation = elevation => { return { @@ -31,6 +32,7 @@ const SUPPORTED_ORIENTATIONS = [ 'landscape-left', 'landscape-right', ]; + export default class ActionSheet extends Component { constructor(props) { super(props); @@ -39,19 +41,31 @@ export default class ActionSheet extends Component { scrollable: false, layoutHasCalled: false, }; - this.containerOpacity = new Animated.Value(0); this.transformValue = new Animated.Value(0); - this.opacity = new Animated.Value(0); + this.opacityValue = new Animated.Value(0); this.customComponentHeight; this.prevScroll; this.scrollAnimationEndValue; this.hasBounced; - this.scrollViewRef; + this.scrollViewRef = createRef(); this.layoutHasCalled = false; this.isClosing = false; + this.isRecoiling = false; } + waitAsync = ms => + new Promise((resolve, reject) => { + setTimeout(() => { + resolve(); + }, ms); + }); + + /** + * Open/Close the ActionSheet + */ + _setModalVisible = () => { + deviceHeight = Dimensions.get('window').height; if (!this.state.modalVisible) { this.setState({ modalVisible: true, @@ -67,14 +81,12 @@ export default class ActionSheet extends Component { if (this.isClosing) return; this.isClosing = true; - Animated.parallel([ - Animated.timing(this.transformValue, { - toValue: this.customComponentHeight * 2, - duration: animated ? closeAnimationDuration : 1, - useNativeDriver: true, - }), - ]).start(() => { - this.scrollViewRef.scrollTo({ + Animated.timing(this.transformValue, { + toValue: this.customComponentHeight * 2, + duration: animated ? closeAnimationDuration : 1, + useNativeDriver: true, + }).start(() => { + this.scrollViewRef.current?.scrollTo({ x: 0, y: 0, animated: false, @@ -92,7 +104,7 @@ export default class ActionSheet extends Component { }); }; - _showModal = event => { + _showModal = async event => { let { gestureEnabled, bounciness, @@ -102,6 +114,7 @@ export default class ActionSheet extends Component { footerHeight, footerAlwaysVisible, extraScroll, + openAnimationSpeed, } = this.props; let addFactor = deviceHeight * 0.1; @@ -110,14 +123,12 @@ export default class ActionSheet extends Component { let diff; if (height > this.customComponentHeight) { diff = height - this.customComponentHeight; - //this._scrollTo(this.prevScroll + diff + 15); + this._scrollTo(this.prevScroll + diff); this.customComponentHeight = height; } else { diff = this.customComponentHeight - height; - - // this._scrollTo(this.prevScroll - diff - 7); - + this._scrollTo(this.prevScroll - diff); this.customComponentHeight = height; } return; @@ -127,54 +138,91 @@ export default class ActionSheet extends Component { } else { this.customComponentHeight = height - footerHeight; } + + if (this.customComponentHeight > deviceHeight) { + this.customComponentHeight = + (this.customComponentHeight - + (this.customComponentHeight - deviceHeight)) * + 0.9; + } + let scrollOffset = gestureEnabled ? this.customComponentHeight * initialOffsetFromBottom + addFactor + extraScroll : this.customComponentHeight + addFactor + extraScroll; - this.scrollViewRef.scrollTo({ + await this.waitAsync(50); + this.scrollViewRef.current.scrollTo({ x: 0, y: scrollOffset, animated: false, }); - + await this.waitAsync(20); if (animated) { this.transformValue.setValue(scrollOffset); - Animated.parallel([ - Animated.spring(this.transformValue, { - toValue: 0, - bounciness: bounceOnOpen ? bounciness : 1, - useNativeDriver: true, - }).start(), - ]).start(); + this.opacityValue.setValue(1); + Animated.spring(this.transformValue, { + toValue: 0, + bounciness: bounceOnOpen ? bounciness : 1, + speed: openAnimationSpeed, + useNativeDriver: true, + }).start(); + } + + if (!gestureEnabled) { + DeviceEventEmitter.emit('hasReachedTop'); } this.layoutHasCalled = true; } }; - _onScrollBeginDrag = event => { + _onScrollBegin = event => { let verticalOffset = event.nativeEvent.contentOffset.y; this.prevScroll = verticalOffset; }; - _onScrollEndDrag = event => { + _onScrollEnd = async event => { let {springOffset, extraScroll} = this.props; let verticalOffset = event.nativeEvent.contentOffset.y; if (this.prevScroll < verticalOffset) { + if (this.isRecoiling) return; if (verticalOffset - this.prevScroll > springOffset * 0.75) { + this.isRecoiling = true; let addFactor = deviceHeight * 0.1; - this._scrollTo(this.customComponentHeight + addFactor + extraScroll); + + let scrollValue = this.customComponentHeight + addFactor + extraScroll; + + if (scrollValue > deviceHeight) { + scrollValue = (scrollValue - (scrollValue - deviceHeight)) * 1; + } + + this._scrollTo(scrollValue); + await this.waitAsync(450); + this.isRecoiling = false; + + DeviceEventEmitter.emit('hasReachedTop'); } else { this._scrollTo(this.prevScroll); } } else { if (this.prevScroll - verticalOffset > springOffset) { + if (this.isRecoiling) { + return; + } + this._hideModal(); } else { + if (this.isRecoiling) { + return; + } + this.isRecoiling = true; + await this.waitAsync(450); + this.isRecoiling = false; + this._scrollTo(this.prevScroll); } } @@ -182,7 +230,7 @@ export default class ActionSheet extends Component { _scrollTo = y => { this.scrollAnimationEndValue = y; - this.scrollViewRef.scrollTo({ + this.scrollViewRef.current?.scrollTo({ x: 0, y: this.scrollAnimationEndValue, animated: true, @@ -190,14 +238,18 @@ export default class ActionSheet extends Component { }; _onTouchMove = () => { - this._hideModal(); + if (this.props.closeOnTouchBackdrop) { + this._hideModal(); + } this.setState({ scrollable: false, }); }; _onTouchStart = () => { - this._hideModal(); + if (this.props.closeOnTouchBackdrop) { + this._hideModal(); + } this.setState({ scrollable: false, }); @@ -211,11 +263,19 @@ export default class ActionSheet extends Component { } }; + _onRequestClose = () => { + if (this.props.closeOnPressBack) this._hideModal(); + }; + + _onTouchBackdrop = () => { + if (this.props.closeOnTouchBackdrop) { + this._hideModal(); + } + }; render() { let {scrollable, modalVisible} = this.state; let { onOpen, - closeOnPressBack, overlayColor, gestureEnabled, elevation, @@ -237,30 +297,31 @@ export default class ActionSheet extends Component { animationType="fade" supportedOrientations={SUPPORTED_ORIENTATIONS} onShow={() => onOpen} - onRequestClose={() => { - if (closeOnPressBack) this._hideModal(); - }} + onRequestClose={this._onRequestClose} transparent={true}> - + + enabled={Platform.OS === 'ios'} + behavior="position"> (this.scrollViewRef = ref)} + ref={this.scrollViewRef} showsVerticalScrollIndicator={false} + onMomentumScrollBegin={this._onScrollBegin} + onMomentumScrollEnd={this._onScrollEnd} scrollEnabled={scrollable} - onScrollBeginDrag={this._onScrollBeginDrag} - onScrollEndDrag={this._onScrollEndDrag} + onScrollBeginDrag={this._onScrollBegin} + onScrollEndDrag={this._onScrollEnd} onTouchEnd={this._onTouchEnd} - overScrollMode="always" - style={[styles.scrollview]}> + //onScroll={this._onScroll} + style={styles.scrollView}> - + zIndex: 10, + }}> + + {}, onOpen: () => {}, }; @@ -370,12 +442,13 @@ ActionSheet.propTypes = { animated: PropTypes.bool, closeOnPressBack: PropTypes.bool, gestureEnabled: PropTypes.bool, + closeOnTouchBackdrop: PropTypes.bool, bounceOnOpen: PropTypes.bool, bounciness: PropTypes.number, springOffset: PropTypes.number, defaultOverlayOpacity: PropTypes.number, closeAnimationDuration: PropTypes.number, - openAnimationDuration: PropTypes.number, + openAnimationSpeed: PropTypes.number, elevation: PropTypes.number, initialOffsetFromBottom: PropTypes.number, indicatorColor: PropTypes.string, diff --git a/apps/mobile/src/components/DialogManager/templates.js b/apps/mobile/src/components/DialogManager/templates.js index 19d0e51b2..c18b35e13 100644 --- a/apps/mobile/src/components/DialogManager/templates.js +++ b/apps/mobile/src/components/DialogManager/templates.js @@ -1,4 +1,5 @@ import {dialogActions} from './dialogActions'; +import {timeConverter} from '../../utils/utils'; export const TEMPLATE_DELETE = type => { return { diff --git a/apps/mobile/src/components/Menu/index.js b/apps/mobile/src/components/Menu/index.js index 9aa6697c0..24fdfe981 100644 --- a/apps/mobile/src/components/Menu/index.js +++ b/apps/mobile/src/components/Menu/index.js @@ -608,14 +608,13 @@ export const Menu = ({ width: '100%', flexDirection: 'row', alignItems: 'center', - backgroundColor: colors.shade, - - paddingHorizontal: 12, + justifyContent: noTextMode ? 'center' : 'flex-start', + backgroundColor: noTextMode ? 'transparent' : colors.shade, + paddingHorizontal: noTextMode ? 0 : 12, }}> - - - You are not logged in - - - Login to sync notes. - - + + You are not logged in + + + Login to sync notes. + + + )} )} diff --git a/apps/mobile/src/views/Editor/index.js b/apps/mobile/src/views/Editor/index.js index f4560c8ca..532f1ea5f 100755 --- a/apps/mobile/src/views/Editor/index.js +++ b/apps/mobile/src/views/Editor/index.js @@ -47,7 +47,7 @@ var title = null; let timer = null; let saveCounter = 0; let tapCount = 0; -let canSave = false; +let canSave = true; const Editor = ({noMenu}) => { // Global State const [state, dispatch] = useTracked(); @@ -77,7 +77,7 @@ const Editor = ({noMenu}) => { }, []); const loadNote = async item => { - EditorWebView.current?.requestFocus(); + //EditorWebView.current?.requestFocus(); noMenu ? null : sideMenuRef.current?.setGestureEnabled(false); if (note && note.id) { dispatch({type: ACTIONS.NOTES}); @@ -89,6 +89,7 @@ const Editor = ({noMenu}) => { canSave = true; } else { note = item; + canSave = false; dispatch({ type: ACTIONS.CURRENT_EDITING_NOTE, id: item.id, @@ -105,6 +106,7 @@ const Editor = ({noMenu}) => { canSave = true; } else { note = item; + canSave = false; dispatch({ type: ACTIONS.CURRENT_EDITING_NOTE, id: item.id, @@ -168,6 +170,7 @@ const Editor = ({noMenu}) => { const onChange = data => { if (data !== '') { let rawData = JSON.parse(data); + if (rawData.type === 'content') { content = rawData; } else { @@ -185,6 +188,7 @@ const Editor = ({noMenu}) => { clearTimeout(timer); timer = null; onChange(evt.nativeEvent.data); + timer = setTimeout(() => { saveNote.call(this, true); }, 500); @@ -202,13 +206,15 @@ const Editor = ({noMenu}) => { const saveNote = async (lockNote = true) => { if (!canSave) return; - if (!title && !content) return; + if (!title && content && content.text.length <= 2) return; + if (!title && content && !content.text) return; if ( title && - title.trim().length === 0 && + title.trim().length <= 1 && content && - content.text.length === 0 + content.text && + content.text.length <= 2 ) return; @@ -616,6 +622,17 @@ const Editor = ({noMenu}) => { }}> {timeConverter(dateEdited)} + + + {dateEdited ? 'Saved' : ''} +