diff --git a/apps/mobile/android/app/src/main/assets/plaineditor.html b/apps/mobile/android/app/src/main/assets/plaineditor.html new file mode 100644 index 000000000..01e4424bd --- /dev/null +++ b/apps/mobile/android/app/src/main/assets/plaineditor.html @@ -0,0 +1,15203 @@ + + + + + + + + + + + +
+
+ + + + + + + + + \ No newline at end of file diff --git a/apps/mobile/html/Web.bundle/site/plaineditor.html b/apps/mobile/html/Web.bundle/site/plaineditor.html new file mode 100644 index 000000000..211c2834b --- /dev/null +++ b/apps/mobile/html/Web.bundle/site/plaineditor.html @@ -0,0 +1,15204 @@ + + + + + + + + + + + +
+
+ + + + + + + + + \ No newline at end of file diff --git a/apps/mobile/src/components/Dialog/index.js b/apps/mobile/src/components/Dialog/index.js index 817eb14fc..3a0dc2cad 100644 --- a/apps/mobile/src/components/Dialog/index.js +++ b/apps/mobile/src/components/Dialog/index.js @@ -8,6 +8,7 @@ import { eClearEditor, eCloseFullscreenEditor, eOnNewTopicAdded, + eApplyChanges, } from '../../services/events'; import NavigationService from '../../services/NavigationService'; import {db, DDS, getElevation, history, ToastEvent} from '../../utils/utils'; @@ -118,6 +119,11 @@ export class Dialog extends Component { this.hide(); break; } + case dialogActions.ACTION_APPLY_CHANGES: { + eSendEvent(eApplyChanges); + this.hide(); + break; + } } }; diff --git a/apps/mobile/src/components/DialogManager/dialogActions.js b/apps/mobile/src/components/DialogManager/dialogActions.js index 1e921a3e5..b02bbd054 100644 --- a/apps/mobile/src/components/DialogManager/dialogActions.js +++ b/apps/mobile/src/components/DialogManager/dialogActions.js @@ -5,4 +5,5 @@ export const dialogActions = { ACTION_EXIT_FULLSCREEN: 514, ACTION_TRASH: 515, ACTION_PERMANANT_DELETE: 516, + ACTION_APPLY_CHANGES: 517, }; diff --git a/apps/mobile/src/components/DialogManager/index.js b/apps/mobile/src/components/DialogManager/index.js index 71ee6bc5a..0ed7e1e7f 100644 --- a/apps/mobile/src/components/DialogManager/index.js +++ b/apps/mobile/src/components/DialogManager/index.js @@ -31,6 +31,7 @@ import {hexToRGBA, DDS} from '../../utils/utils'; import {Platform} from 'react-native'; import {TEMPLATE_DELETE, TEMPLATE_PERMANANT_DELETE} from './templates'; import {moveNoteEvent} from './recievers'; +import MergeEditor from '../MergeEditor'; export class DialogManager extends Component { constructor(props) { @@ -343,6 +344,8 @@ export class DialogManager extends Component { /> (this.loginDialog = ref)} /> + + ); } diff --git a/apps/mobile/src/components/DialogManager/templates.js b/apps/mobile/src/components/DialogManager/templates.js index c18b35e13..7e1f696a2 100644 --- a/apps/mobile/src/components/DialogManager/templates.js +++ b/apps/mobile/src/components/DialogManager/templates.js @@ -32,6 +32,15 @@ export const TEMPLATE_TRASH = type => { }; }; +export const TEMPLATE_APPLY_CHANGES = { + title: `Apply Changes`, + paragraph: `Apply selected changes to note?`, + positiveText: 'Apply', + negativeText: 'Cancel', + action: dialogActions.ACTION_APPLY_CHANGES, + icon: 'check', +}; + export const TEMPLATE_EXIT_FULLSCREEN = () => { return { title: `Exit fullscreen editor?`, diff --git a/apps/mobile/src/components/MergeEditor/index.js b/apps/mobile/src/components/MergeEditor/index.js new file mode 100644 index 000000000..83e71c331 --- /dev/null +++ b/apps/mobile/src/components/MergeEditor/index.js @@ -0,0 +1,592 @@ +import React, {useState, createRef, useEffect} from 'react'; +import {Modal, View, TouchableOpacity, Text} from 'react-native'; +import WebView from 'react-native-webview'; +import {h, getElevation} from '../../utils/utils'; +import {useTracked} from '../../provider'; +import {SIZE, WEIGHT, normalize} from '../../common/common'; +import Icon from 'react-native-vector-icons/MaterialCommunityIcons'; +import Animated, {Easing} from 'react-native-reanimated'; +import { + eSubscribeEvent, + eUnSubscribeEvent, + eSendEvent, +} from '../../services/eventManager'; +import {eApplyChanges, eOpenSimpleDialog} from '../../services/events'; +import {TEMPLATE_APPLY_CHANGES} from '../DialogManager/templates'; +import {simpleDialogEvent} from '../DialogManager/recievers'; + +const {Value, timing} = Animated; +const firstWebViewHeight = new Value(h * 0.5 - 50); +const secondWebViewHeight = new Value(h * 0.5 - 50); + +const primaryWebView = createRef(); +const secondaryWebView = createRef(); + +export function openEditorAnimation( + heightToAnimate, + extendedHeight = null, + siblingStatus, +) { + let openConfig = { + duration: 300, + toValue: !siblingStatus ? h - 100 : h * 0.5 - 50, + easing: Easing.inOut(Easing.ease), + }; + + let extendConfig = { + duration: 300, + toValue: h * 0.5 - 50, + easing: Easing.inOut(Easing.ease), + }; + + if (extendedHeight) { + timing(extendedHeight, extendConfig).start(); + } + timing(heightToAnimate, openConfig).start(); +} + +export function closeEditorAnimation(heightToAnimate, heightToExtend = null) { + let closeConfig = { + duration: 300, + toValue: 0, + easing: Easing.inOut(Easing.ease), + }; + + let extendConfig = { + duration: 300, + toValue: h - 100, + easing: Easing.inOut(Easing.ease), + }; + if (heightToExtend) { + timing(heightToExtend, extendConfig).start(); + } + + timing(heightToAnimate, closeConfig).start(); +} + +let primaryDelta = null; +let primaryText = 'Hello world, I am primary text conflict'; + +let secondaryDelta = null; +let secondaryText = 'Hello world, I am secondary text confilict'; + +const MergeEditor = () => { + const [state, dispatch] = useTracked(); + const {colors} = state; + const [visible, setVisible] = useState(true); + const [primary, setPrimary] = useState(true); + const [secondary, setSecondary] = useState(true); + const [keepContentFrom, setKeepContentFrom] = useState(null); + const [copyToSave, setCopyToSave] = useState(null); + const [disardedContent, setDiscardedContent] = useState(null); + + const postMessageToPrimaryWebView = message => + primaryWebView.current?.postMessage(JSON.stringify(message)); + + const postMessageToSecondaryWebView = message => + secondaryWebView.current?.postMessage(JSON.stringify(message)); + + const onPrimaryWebViewLoad = () => { + postMessageToPrimaryWebView({ + type: 'text', + value: primaryText, + }); + let c = {...colors}; + c.factor = normalize(1); + postMessageToPrimaryWebView({ + type: 'theme', + value: c, + }); + }; + + const onSecondaryWebViewLoad = () => { + postMessageToSecondaryWebView({ + type: 'text', + value: secondaryText, + }); + let c = {...colors}; + c.factor = normalize(1); + postMessageToSecondaryWebView({ + type: 'theme', + value: c, + }); + }; + + const _onShouldStartLoadWithRequest = request => { + if (request.url.includes('https')) { + Linking.openURL(request.url); + return false; + } else { + return true; + } + }; + + const onMessageFromPrimaryWebView = evt => { + if (evt.nativeEvent.data === 'loaded') { + } else if ( + evt.nativeEvent.data !== '' && + evt.nativeEvent.data !== 'loaded' + ) { + let data = JSON.parse(evt.nativeEvent.data); + primaryDelta = data.delta; + primaryText = data.text; + } + }; + + const onMessageFromSecondaryWebView = evt => { + if (evt.nativeEvent.data === 'loaded') { + } else if ( + evt.nativeEvent.data !== '' && + evt.nativeEvent.data !== 'loaded' + ) { + let data = JSON.parse(evt.nativeEvent.data); + secondaryDelta = data.delta; + secondaryText = data.text; + //Handle Here + } + }; + + const applyChanges = () => { + alert('hello'); + }; + + useEffect(() => { + eSubscribeEvent(eApplyChanges, applyChanges); + + return () => { + eUnSubscribeEvent(eApplyChanges, applyChanges); + }; + }); + + const onPressKeepFromPrimaryWebView = () => { + if (keepContentFrom == 'primary') { + setKeepContentFrom(null); + openEditorAnimation(firstWebViewHeight, secondWebViewHeight); + } else { + setKeepContentFrom('primary'); + closeEditorAnimation(firstWebViewHeight, secondWebViewHeight); + } + }; + + const onPressSaveCopyFromPrimaryWebView = () => { + setCopyToSave('primary'); + simpleDialogEvent(TEMPLATE_APPLY_CHANGES); + }; + + const onPressKeepFromSecondaryWebView = () => { + if (keepContentFrom == 'secondary') { + setKeepContentFrom(null); + openEditorAnimation(secondWebViewHeight, firstWebViewHeight); + } else { + setKeepContentFrom('secondary'); + closeEditorAnimation(secondWebViewHeight, firstWebViewHeight); + } + }; + + const onPressSaveCopyFromSecondaryWebView = () => { + setCopyToSave('secondary'); + simpleDialogEvent(TEMPLATE_APPLY_CHANGES); + }; + + const onPressDiscardFromPrimaryWebView = () => { + setDiscardedContent('primary'); + simpleDialogEvent(TEMPLATE_APPLY_CHANGES); + }; + + const onPressDiscardFromSecondaryWebView = () => { + setDiscardedContent('secondary'); + simpleDialogEvent(TEMPLATE_APPLY_CHANGES); + }; + + const params = 'platform=' + Platform.OS; + const sourceUri = + (Platform.OS === 'android' ? 'file:///android_asset/' : '') + + 'Web.bundle/loader.html'; + const injectedJS = `if (!window.location.search) { + var link = document.getElementById('progress-bar'); + link.href = './site2/plaineditor.html?${params}'; + link.click(); + }`; + + return ( + + + + + + { + if (keepContentFrom === 'primary') return; + if (!primary) { + openEditorAnimation( + firstWebViewHeight, + secondary && keepContentFrom !== 'secondary' + ? secondWebViewHeight + : null, + secondary && keepContentFrom !== 'secondary', + ); + setPrimary(true); + } else { + closeEditorAnimation( + firstWebViewHeight, + secondary && keepContentFrom !== 'secondary' + ? secondWebViewHeight + : null, + ); + setPrimary(false); + } + }} + style={{ + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'space-between', + }}> + + Saved on 10/10/20 {'\n'} + 12:30pm on Tablet + + + + + + + {keepContentFrom === 'secondary' ? ( + + + Save as a copy + + + ) : null} + + {keepContentFrom === 'secondary' ? ( + + + Discard + + + ) : null} + + {keepContentFrom === 'secondary' ? null : ( + + + {keepContentFrom === 'primary' ? 'Undo' : 'Keep'} + + + )} + + + + + + + + + + { + if (keepContentFrom === 'secondary') return; + if (!secondary) { + openEditorAnimation( + secondWebViewHeight, + primary && keepContentFrom !== 'primary' + ? firstWebViewHeight + : null, + primary && keepContentFrom !== 'primary', + ); + setSecondary(true); + } else { + closeEditorAnimation( + secondWebViewHeight, + primary && keepContentFrom !== 'primary' + ? firstWebViewHeight + : null, + ); + setSecondary(false); + } + }} + style={{ + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'space-between', + }}> + + Saved on 10/10/20 {'\n'} + 12:30pm on Tablet + + + + + + + {keepContentFrom === 'primary' ? ( + + + Save as a copy + + + ) : null} + + {keepContentFrom === 'primary' ? ( + + + Discard + + + ) : null} + + {keepContentFrom === 'primary' ? null : ( + + + {keepContentFrom === 'secondary' ? 'Undo' : 'Keep'} + + + )} + + + + + + + + + ); +}; + +export default MergeEditor; diff --git a/apps/mobile/src/services/events.js b/apps/mobile/src/services/events.js index 2523e1793..84327ada9 100644 --- a/apps/mobile/src/services/events.js +++ b/apps/mobile/src/services/events.js @@ -67,3 +67,5 @@ export const refreshNotesPage = '532'; export const eClearSearch = '533'; export const eClearEditor = '534'; + +export const eApplyChanges = '535'; diff --git a/apps/mobile/src/views/Editor/index.js b/apps/mobile/src/views/Editor/index.js index b95de42b1..1e2e43e83 100755 --- a/apps/mobile/src/views/Editor/index.js +++ b/apps/mobile/src/views/Editor/index.js @@ -348,7 +348,7 @@ const Editor = ({noMenu}) => { c.factor = normalize(1); post({ type: 'theme', - value: colors, + value: c, }); }; @@ -357,10 +357,6 @@ const Editor = ({noMenu}) => { id = note.id; setDateEdited(note.dateEdited); content = {...note.content}; - if (!note.locked) { - content.delta = await db.notes.note(id).delta(); - } - saveCounter = 0; if (title !== null || title === '') { @@ -383,10 +379,10 @@ const Editor = ({noMenu}) => { post({ type: 'clearEditor', }); - } else if (content.delta) { + } else if (note.content.delta) { let delta; - if (typeof content.delta !== 'string') { - delta = content.delta; + if (typeof note.content.delta !== 'string') { + delta = note.content.delta; } else { delta = await db.notes.note(id).delta(); }