mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-21 22:19:41 +01:00
feat: fully implement new note widget on android
This commit is contained in:
@@ -6,6 +6,7 @@
|
|||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<title>Note Diff Preview</title>
|
<title>Note Diff Preview</title>
|
||||||
<link rel="stylesheet" href="./index.css">
|
<link rel="stylesheet" href="./index.css">
|
||||||
|
<link rel="stylesheet" href="./fonts.css">
|
||||||
<link id="dark_sheet" disabled rel="stylesheet" href="./dist/skins/notesnook-dark/content.min.css">
|
<link id="dark_sheet" disabled rel="stylesheet" href="./dist/skins/notesnook-dark/content.min.css">
|
||||||
<link id="light_sheet" disabled rel="stylesheet" href="./dist/skins/notesnook/content.min.css">
|
<link id="light_sheet" disabled rel="stylesheet" href="./dist/skins/notesnook/content.min.css">
|
||||||
<style>
|
<style>
|
||||||
@@ -80,17 +81,41 @@
|
|||||||
padding: 12px !important;
|
padding: 12px !important;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
|
min-height: 150px;
|
||||||
|
font-family: "Open Sans";
|
||||||
|
}
|
||||||
|
|
||||||
|
[contenteditable] {
|
||||||
|
outline: 0px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
[contenteditable=true]:empty:before {
|
||||||
|
content: attr(placeholder);
|
||||||
|
pointer-events: none;
|
||||||
|
display: block;
|
||||||
|
color: gray;
|
||||||
|
/* For Firefox */
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div class="htmldiff_div">
|
<div placeholder="Write something..." contenteditable="true" class="htmldiff_div">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<script src="./listeners.js"></script>
|
<script src="./listeners.js"></script>
|
||||||
<script src="./constants.js"></script>
|
<script src="./constants.js"></script>
|
||||||
<script>
|
<script>
|
||||||
|
function reactNativeEventHandler(type, value) {
|
||||||
|
if (window.ReactNativeWebView) {
|
||||||
|
window.ReactNativeWebView.postMessage(
|
||||||
|
JSON.stringify({
|
||||||
|
type: type,
|
||||||
|
value: value
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
attachMessageListener()
|
attachMessageListener()
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
BIN
apps/mobile/android/app/src/main/res/drawable/widget_preview.png
Normal file
BIN
apps/mobile/android/app/src/main/res/drawable/widget_preview.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
@@ -6,6 +6,7 @@
|
|||||||
android:padding="@dimen/widget_margin"
|
android:padding="@dimen/widget_margin"
|
||||||
android:theme="@style/ThemeOverlay.Notesnook.AppWidgetContainer">
|
android:theme="@style/ThemeOverlay.Notesnook.AppWidgetContainer">
|
||||||
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:id="@+id/widget_button"
|
android:id="@+id/widget_button"
|
||||||
@@ -14,7 +15,7 @@
|
|||||||
android:layout_centerVertical="true"
|
android:layout_centerVertical="true"
|
||||||
android:background="@drawable/layout_bg"
|
android:background="@drawable/layout_bg"
|
||||||
android:paddingHorizontal="10dp"
|
android:paddingHorizontal="10dp"
|
||||||
|
android:elevation="5dp"
|
||||||
android:orientation="horizontal">
|
android:orientation="horizontal">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
|
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:initialKeyguardLayout="@layout/note_widget"
|
android:initialKeyguardLayout="@layout/note_widget"
|
||||||
android:initialLayout="@layout/note_widget"
|
android:initialLayout="@layout/note_widget"
|
||||||
android:minWidth="110dp"
|
android:minWidth="300dp"
|
||||||
android:minHeight="40dp"
|
android:minHeight="50dp"
|
||||||
android:previewImage="@drawable/example_appwidget_preview"
|
android:previewImage="@drawable/widget_preview"
|
||||||
android:resizeMode="horizontal"
|
android:resizeMode="horizontal"
|
||||||
android:updatePeriodMillis="86400000"
|
android:updatePeriodMillis="86400000"
|
||||||
android:widgetCategory="home_screen"></appwidget-provider>
|
android:widgetCategory="home_screen"></appwidget-provider>
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<title>Note Diff Preview</title>
|
<title>Note Diff Preview</title>
|
||||||
<link rel="stylesheet" href="./index.css">
|
<link rel="stylesheet" href="./index.css">
|
||||||
|
<link rel="stylesheet" href="./fonts.css">
|
||||||
<link id="dark_sheet" disabled rel="stylesheet" href="./dist/skins/notesnook-dark/content.min.css">
|
<link id="dark_sheet" disabled rel="stylesheet" href="./dist/skins/notesnook-dark/content.min.css">
|
||||||
<link id="light_sheet" disabled rel="stylesheet" href="./dist/skins/notesnook/content.min.css">
|
<link id="light_sheet" disabled rel="stylesheet" href="./dist/skins/notesnook/content.min.css">
|
||||||
<style>
|
<style>
|
||||||
@@ -80,17 +81,41 @@
|
|||||||
padding: 12px !important;
|
padding: 12px !important;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
|
min-height: 150px;
|
||||||
|
font-family: "Open Sans";
|
||||||
|
}
|
||||||
|
|
||||||
|
[contenteditable] {
|
||||||
|
outline: 0px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
[contenteditable=true]:empty:before {
|
||||||
|
content: attr(placeholder);
|
||||||
|
pointer-events: none;
|
||||||
|
display: block;
|
||||||
|
color: gray;
|
||||||
|
/* For Firefox */
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div class="htmldiff_div">
|
<div placeholder="Write something..." contenteditable="true" class="htmldiff_div">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<script src="./listeners.js"></script>
|
<script src="./listeners.js"></script>
|
||||||
<script src="./constants.js"></script>
|
<script src="./constants.js"></script>
|
||||||
<script>
|
<script>
|
||||||
|
function reactNativeEventHandler(type, value) {
|
||||||
|
if (window.ReactNativeWebView) {
|
||||||
|
window.ReactNativeWebView.postMessage(
|
||||||
|
JSON.stringify({
|
||||||
|
type: type,
|
||||||
|
value: value
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
attachMessageListener()
|
attachMessageListener()
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
|
import Clipboard from '@react-native-clipboard/clipboard';
|
||||||
import absolutify from 'absolutify';
|
import absolutify from 'absolutify';
|
||||||
import {getLinkPreview} from 'link-preview-js';
|
import { getLinkPreview } from 'link-preview-js';
|
||||||
import React, {useEffect, useRef, useState} from 'react';
|
import React, { useEffect, useRef, useState } from 'react';
|
||||||
import {
|
import {
|
||||||
ActivityIndicator,
|
ActivityIndicator,
|
||||||
Appearance,
|
Appearance,
|
||||||
@@ -9,24 +10,25 @@ import {
|
|||||||
Platform,
|
Platform,
|
||||||
SafeAreaView,
|
SafeAreaView,
|
||||||
Text,
|
Text,
|
||||||
TextInput,
|
|
||||||
TouchableOpacity,
|
TouchableOpacity,
|
||||||
useWindowDimensions,
|
useWindowDimensions,
|
||||||
View
|
View
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import Animated, {Easing, timing, useValue} from 'react-native-reanimated';
|
import Animated, { Easing, timing, useValue } from 'react-native-reanimated';
|
||||||
|
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||||
import WebView from 'react-native-webview';
|
import WebView from 'react-native-webview';
|
||||||
import ShareExtension from 'rn-extensions-share';
|
import ShareExtension from 'rn-extensions-share';
|
||||||
import sanitize from 'sanitize-html';
|
|
||||||
import validator from 'validator';
|
import validator from 'validator';
|
||||||
import {getElevation, showTooltip, TOOLTIP_POSITIONS} from '../src/utils';
|
import {
|
||||||
import {COLOR_SCHEME_DARK, COLOR_SCHEME_LIGHT} from '../src/utils/Colors';
|
eSendEvent,
|
||||||
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
|
eSubscribeEvent,
|
||||||
import Clipboard from '@react-native-clipboard/clipboard';
|
eUnSubscribeEvent
|
||||||
import {db} from '../src/utils/database';
|
} from '../src/services/EventManager';
|
||||||
import {SIZE} from '../src/utils/SizeUtils';
|
import { getElevation } from '../src/utils';
|
||||||
|
import { COLOR_SCHEME_DARK, COLOR_SCHEME_LIGHT } from '../src/utils/Colors';
|
||||||
|
import { db } from '../src/utils/database';
|
||||||
import Storage from '../src/utils/storage';
|
import Storage from '../src/utils/storage';
|
||||||
import {sleep} from '../src/utils/TimeUtils';
|
import { sleep } from '../src/utils/TimeUtils';
|
||||||
|
|
||||||
const AnimatedKAV = Animated.createAnimatedComponent(KeyboardAvoidingView);
|
const AnimatedKAV = Animated.createAnimatedComponent(KeyboardAvoidingView);
|
||||||
const AnimatedSAV = Animated.createAnimatedComponent(SafeAreaView);
|
const AnimatedSAV = Animated.createAnimatedComponent(SafeAreaView);
|
||||||
@@ -34,19 +36,10 @@ async function sanitizeHtml(site) {
|
|||||||
try {
|
try {
|
||||||
let html = await fetch(site);
|
let html = await fetch(site);
|
||||||
html = await html.text();
|
html = await html.text();
|
||||||
let siteHtml = sanitize(html, {
|
let siteHtml = html.replace(
|
||||||
allowedTags: sanitize.defaults.allowedTags.concat([
|
/(?:<(script|button|input|textarea|style|link)(?:\s[^>]*)?>)\s*((?:(?!<\1)[\s\S])*)\s*(?:<\/\1>)/g,
|
||||||
'img',
|
''
|
||||||
'style',
|
);
|
||||||
'head',
|
|
||||||
'link'
|
|
||||||
]),
|
|
||||||
allowedClasses: true,
|
|
||||||
allowVulnerableTags: true,
|
|
||||||
allowedAttributes: false,
|
|
||||||
allowProtocolRelative: true,
|
|
||||||
allowedSchemes: false
|
|
||||||
});
|
|
||||||
return absolutify(siteHtml, site);
|
return absolutify(siteHtml, site);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return '';
|
return '';
|
||||||
@@ -62,6 +55,30 @@ function makeHtmlFromPlainText(text) {
|
|||||||
return `<p style="overflow-wrap:anywhere;white-space:pre-wrap" >${text}</p>`;
|
return `<p style="overflow-wrap:anywhere;white-space:pre-wrap" >${text}</p>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getBaseUrl(site) {
|
||||||
|
var url = site.split('/').slice(0, 3).join('/');
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function absolutifyImgs(html, site) {
|
||||||
|
let parser = global.HTMLParser;
|
||||||
|
global.HTMLParser.body.innerHTML = html;
|
||||||
|
|
||||||
|
let images = parser.querySelectorAll('img');
|
||||||
|
for (var i = 0; i < images.length; i++) {
|
||||||
|
let img = images[i];
|
||||||
|
let url = getBaseUrl(site);
|
||||||
|
if (!img.src.startsWith('http')) {
|
||||||
|
if (img.src.startsWith('//')) {
|
||||||
|
img.src = img.src.replace('//', 'https://');
|
||||||
|
} else {
|
||||||
|
img.src = url + img.src;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return parser.body.innerHTML;
|
||||||
|
}
|
||||||
|
|
||||||
let defaultNote = {
|
let defaultNote = {
|
||||||
title: null,
|
title: null,
|
||||||
id: null,
|
id: null,
|
||||||
@@ -71,7 +88,6 @@ let defaultNote = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let editorContentValue = null;
|
|
||||||
|
|
||||||
const modes = {
|
const modes = {
|
||||||
1: {
|
1: {
|
||||||
@@ -101,13 +117,10 @@ const NotesnookShare = () => {
|
|||||||
const [loadingIntent, setLoadingIntent] = useState(true);
|
const [loadingIntent, setLoadingIntent] = useState(true);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [floating, setFloating] = useState(false);
|
const [floating, setFloating] = useState(false);
|
||||||
const [quickNote, setQuickNote] = useState(false);
|
|
||||||
const [rawData, setRawData] = useState({
|
const [rawData, setRawData] = useState({
|
||||||
type: null,
|
type: null,
|
||||||
value: null
|
value: null
|
||||||
});
|
});
|
||||||
const textInputRef = useRef();
|
|
||||||
const titleInputRef = useRef();
|
|
||||||
const {width, height} = useWindowDimensions();
|
const {width, height} = useWindowDimensions();
|
||||||
const webviewRef = useRef();
|
const webviewRef = useRef();
|
||||||
const opacity = useValue(0);
|
const opacity = useValue(0);
|
||||||
@@ -117,7 +130,6 @@ const NotesnookShare = () => {
|
|||||||
};
|
};
|
||||||
const prevAnimation = useRef(null);
|
const prevAnimation = useRef(null);
|
||||||
const [mode, setMode] = useState(1);
|
const [mode, setMode] = useState(1);
|
||||||
const [keyboard,setKeyboard] = useState(false);
|
|
||||||
|
|
||||||
const animate = (opacityV, translateV) => {
|
const animate = (opacityV, translateV) => {
|
||||||
prevAnimation.current = translateV;
|
prevAnimation.current = translateV;
|
||||||
@@ -134,86 +146,79 @@ const NotesnookShare = () => {
|
|||||||
}).start();
|
}).start();
|
||||||
};
|
};
|
||||||
|
|
||||||
const onKeyboardDidShow = (event) => {
|
const onKeyboardDidShow = event => {
|
||||||
let kHeight = event.endCoordinates.height;
|
let kHeight = event.endCoordinates.height;
|
||||||
console.log('called')
|
//translate.setValue(-150);
|
||||||
translate.setValue(-kHeight/1.8);
|
};
|
||||||
}
|
|
||||||
|
|
||||||
const onKeyboardDidHide = () => {
|
const onKeyboardDidHide = () => {
|
||||||
translate.setValue(0);
|
translate.setValue(0);
|
||||||
}
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let keyboardWillChangeFrame = Keyboard.addListener('keyboardWillChangeFrame', onKeyboardWillChangeFrame);
|
let keyboardWillChangeFrame = Keyboard.addListener(
|
||||||
let keyboardDidShow = Keyboard.addListener("keyboardDidShow", onKeyboardDidShow);
|
'keyboardWillChangeFrame',
|
||||||
let keyboardDidHide = Keyboard.addListener("keyboardDidHide", onKeyboardDidHide);
|
onKeyboardWillChangeFrame
|
||||||
|
);
|
||||||
|
let keyboardDidShow = Keyboard.addListener(
|
||||||
|
'keyboardDidShow',
|
||||||
|
onKeyboardDidShow
|
||||||
|
);
|
||||||
|
let keyboardDidHide = Keyboard.addListener(
|
||||||
|
'keyboardDidHide',
|
||||||
|
onKeyboardDidHide
|
||||||
|
);
|
||||||
return () => {
|
return () => {
|
||||||
keyboardWillChangeFrame?.remove();
|
keyboardWillChangeFrame?.remove();
|
||||||
keyboardDidShow?.remove();
|
keyboardDidShow?.remove();
|
||||||
keyboardDidHide?.remove();
|
keyboardDidHide?.remove();
|
||||||
};
|
};
|
||||||
},[]);
|
}, []);
|
||||||
|
|
||||||
const onKeyboardWillChangeFrame = event => {
|
const onKeyboardWillChangeFrame = event => {
|
||||||
console.log('keyboad change frame',event)
|
|
||||||
setFloating(event.endCoordinates.width !== width);
|
setFloating(event.endCoordinates.width !== width);
|
||||||
};
|
};
|
||||||
|
|
||||||
const showLinkPreview = async link => {
|
const showLinkPreview = async (note, link) => {
|
||||||
let _note = {...defaultNote};
|
let _note = note;
|
||||||
_note.title = 'Web link share';
|
_note.content.data = makeHtmlFromUrl(link);
|
||||||
_note.content.data = !note.content.data
|
|
||||||
? makeHtmlFromUrl(link)
|
|
||||||
: note.content.data + '\n' + makeHtmlFromUrl(link);
|
|
||||||
try {
|
try {
|
||||||
let preview = await getLinkPreview(link);
|
let preview = await getLinkPreview(link);
|
||||||
_note.title = preview.siteName || preview.title;
|
_note.title = preview.siteName || preview.title;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
}
|
}
|
||||||
setNote(_note);
|
return note;
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadData = async () => {
|
const loadData = async () => {
|
||||||
try {
|
try {
|
||||||
setNote(() => {
|
|
||||||
defaultNote.content.data = null;
|
|
||||||
return defaultNote;
|
|
||||||
});
|
|
||||||
const data = await ShareExtension.data();
|
const data = await ShareExtension.data();
|
||||||
console.log(data);
|
|
||||||
if (!data || data.length === 0) {
|
if (!data || data.length === 0) {
|
||||||
setRawData({
|
setRawData({
|
||||||
value: ''
|
value: ''
|
||||||
});
|
});
|
||||||
|
setNote({...defaultNote});
|
||||||
setLoadingIntent(false);
|
setLoadingIntent(false);
|
||||||
setQuickNote(true);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
let note = defaultNote;
|
||||||
for (item of data) {
|
for (item of data) {
|
||||||
if (item.type === 'text') {
|
if (item.type === 'text') {
|
||||||
setRawData(item);
|
setRawData(item);
|
||||||
if (validator.isURL(item.value)) {
|
if (validator.isURL(item.value)) {
|
||||||
await showLinkPreview(item.value);
|
note = await showLinkPreview(note, item.value);
|
||||||
} else {
|
} else {
|
||||||
setNote(note => {
|
note.content.data = makeHtmlFromPlainText(item.value);
|
||||||
note.title = 'Note Share';
|
|
||||||
note.content.data = note.content.data
|
|
||||||
? note.content.data + '\n' + makeHtmlFromPlainText(item.value)
|
|
||||||
: makeHtmlFromPlainText(item.value);
|
|
||||||
|
|
||||||
return note;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
setNote({...note});
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
setLoadingIntent(false);
|
setLoadingIntent(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setNote(defaultNote);
|
|
||||||
loadData();
|
loadData();
|
||||||
sleep(50).then(() => {
|
sleep(50).then(() => {
|
||||||
animate(1, 0);
|
animate(1, 0);
|
||||||
@@ -244,15 +249,20 @@ const NotesnookShare = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const onPress = async () => {
|
const onPress = async () => {
|
||||||
titleInputRef.current?.blur();
|
content = await getContent();
|
||||||
textInputRef.current?.blur();
|
if (!content || content === '') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
||||||
let add = async () => {
|
let add = async () => {
|
||||||
let _note = {...note};
|
let _note = {
|
||||||
_note.content.data =
|
...note,
|
||||||
_note.content.data + makeHtmlFromPlainText(editorContentValue);
|
content: {
|
||||||
await db.notes.add(note);
|
data: content,
|
||||||
|
type: 'tiny'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
await db.notes.add(_note);
|
||||||
};
|
};
|
||||||
if (db && db.notes) {
|
if (db && db.notes) {
|
||||||
await add();
|
await add();
|
||||||
@@ -276,6 +286,35 @@ const NotesnookShare = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getContent = () => {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
let oncontent = value => {
|
||||||
|
eUnSubscribeEvent('share_content_event', oncontent);
|
||||||
|
resolve(value);
|
||||||
|
};
|
||||||
|
eSubscribeEvent('share_content_event', oncontent);
|
||||||
|
webviewRef.current?.injectJavaScript(`(function() {
|
||||||
|
let html = document.querySelector(".htmldiff_div").innerHTML;
|
||||||
|
if (!html) {
|
||||||
|
html = '';
|
||||||
|
}
|
||||||
|
reactNativeEventHandler('tiny', html);
|
||||||
|
})();`);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const onMessage = event => {
|
||||||
|
if (!event) return;
|
||||||
|
let data = JSON.parse(event.nativeEvent.data);
|
||||||
|
if (data.type === 'tiny') {
|
||||||
|
eSendEvent('share_content_event', data.value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
onLoad();
|
||||||
|
}, [note]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AnimatedSAV
|
<AnimatedSAV
|
||||||
style={{
|
style={{
|
||||||
@@ -307,7 +346,6 @@ const NotesnookShare = () => {
|
|||||||
enabled={!floating && Platform.OS === 'ios'}
|
enabled={!floating && Platform.OS === 'ios'}
|
||||||
onLayout={event => {
|
onLayout={event => {
|
||||||
if (prevAnimation.current === 0) return;
|
if (prevAnimation.current === 0) return;
|
||||||
console.log('setting value here');
|
|
||||||
translate.setValue(event.nativeEvent.layout.height + 30);
|
translate.setValue(event.nativeEvent.layout.height + 30);
|
||||||
}}
|
}}
|
||||||
style={{
|
style={{
|
||||||
@@ -321,325 +359,180 @@ const NotesnookShare = () => {
|
|||||||
]
|
]
|
||||||
}}
|
}}
|
||||||
behavior="padding">
|
behavior="padding">
|
||||||
{quickNote ? null : (
|
<View
|
||||||
|
style={{
|
||||||
|
maxHeight: '100%',
|
||||||
|
paddingHorizontal: 12
|
||||||
|
}}>
|
||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
width: 50,
|
width: '100%'
|
||||||
height: 6,
|
|
||||||
borderRadius: 100,
|
|
||||||
backgroundColor: colors.nav,
|
|
||||||
alignSelf: 'center',
|
|
||||||
position: 'absolute',
|
|
||||||
marginTop: 15
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{loadingIntent ? (
|
|
||||||
<View
|
|
||||||
style={{
|
|
||||||
height: 150,
|
|
||||||
width: '100%',
|
|
||||||
justifyContent: 'center',
|
|
||||||
alignItems: 'center'
|
|
||||||
}}>
|
}}>
|
||||||
<ActivityIndicator color={colors.accent} />
|
<Button
|
||||||
|
color={colors.accent}
|
||||||
<Text
|
onPress={onPress}
|
||||||
|
loading={loading || loadingIntent}
|
||||||
|
icon="check"
|
||||||
|
iconSize={25}
|
||||||
|
type="action"
|
||||||
|
loading={loading}
|
||||||
style={{
|
style={{
|
||||||
color: colors.pri,
|
position: 'absolute',
|
||||||
fontSize: SIZE.md,
|
zIndex: 999,
|
||||||
marginTop: 5
|
...getElevation(10),
|
||||||
}}>
|
right: 24,
|
||||||
Parsing Data...
|
bottom: -35
|
||||||
</Text>
|
}}
|
||||||
</View>
|
/>
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
maxHeight: '100%'
|
marginTop: 10,
|
||||||
|
minHeight: 100,
|
||||||
|
borderRadius: 10,
|
||||||
|
...getElevation(5),
|
||||||
|
backgroundColor: colors.bg
|
||||||
}}>
|
}}>
|
||||||
{quickNote ? null : (
|
|
||||||
<View
|
|
||||||
style={{
|
|
||||||
borderBottomWidth: 1,
|
|
||||||
borderBottomColor: colors.nav,
|
|
||||||
paddingHorizontal: 12
|
|
||||||
}}>
|
|
||||||
<TextInput
|
|
||||||
ref={titleInputRef}
|
|
||||||
style={{
|
|
||||||
fontSize: 25,
|
|
||||||
fontFamily:
|
|
||||||
Platform.OS === 'android' ? 'Roboto-Medium' : null,
|
|
||||||
fontWeight: Platform.OS === 'ios' ? '600' : null,
|
|
||||||
color: colors.pri,
|
|
||||||
flexGrow: 1,
|
|
||||||
maxWidth: '100%'
|
|
||||||
}}
|
|
||||||
placeholderTextColor={colors.icon}
|
|
||||||
defaultValue={note?.title}
|
|
||||||
onChangeText={v =>
|
|
||||||
setNote(_note => {
|
|
||||||
_note.title = v;
|
|
||||||
return _note;
|
|
||||||
})
|
|
||||||
}
|
|
||||||
onSubmitEditing={() => {
|
|
||||||
textInputRef.current?.focus();
|
|
||||||
}}
|
|
||||||
blurOnSubmit={false}
|
|
||||||
placeholder="Note title"
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{quickNote ? null : (
|
|
||||||
<View
|
|
||||||
style={{
|
|
||||||
flexDirection: 'row',
|
|
||||||
alignItems: 'center',
|
|
||||||
marginVertical: 10,
|
|
||||||
borderBottomWidth: 1,
|
|
||||||
borderBottomColor: colors.nav
|
|
||||||
}}>
|
|
||||||
{[
|
|
||||||
{
|
|
||||||
title: 'Plain text',
|
|
||||||
onPress: () => {
|
|
||||||
let html = validator.isURL(rawData.value)
|
|
||||||
? makeHtmlFromUrl(rawData.value)
|
|
||||||
: makeHtmlFromPlainText(rawData.value);
|
|
||||||
setNote(note => {
|
|
||||||
note.content.data = html;
|
|
||||||
return note;
|
|
||||||
});
|
|
||||||
onLoad();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
...[
|
|
||||||
rawData?.value && validator.isURL(rawData.value)
|
|
||||||
? {
|
|
||||||
title: 'Clip webpage',
|
|
||||||
onPress: async () => {
|
|
||||||
let html = await sanitizeHtml(rawData.value);
|
|
||||||
setNote(note => {
|
|
||||||
note.content.data = html;
|
|
||||||
return note;
|
|
||||||
});
|
|
||||||
onLoad();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
: null
|
|
||||||
]
|
|
||||||
].map(
|
|
||||||
(item, index) =>
|
|
||||||
item && (
|
|
||||||
<Button
|
|
||||||
title={item.title}
|
|
||||||
color={colors.nav}
|
|
||||||
textStyle={{
|
|
||||||
color: colors.icon,
|
|
||||||
fontWeight: 'normal',
|
|
||||||
fontSize: 14,
|
|
||||||
fontFamily: null
|
|
||||||
}}
|
|
||||||
onPress={item.onPress}
|
|
||||||
style={{
|
|
||||||
borderWidth: 0.5,
|
|
||||||
borderRadius: 100,
|
|
||||||
borderColor: colors.icon,
|
|
||||||
height: 30,
|
|
||||||
marginRight: 10,
|
|
||||||
marginLeft: index === 0 ? 12 : 0,
|
|
||||||
paddingHorizontal: 12
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{quickNote ? null : (
|
|
||||||
<View
|
|
||||||
style={{
|
|
||||||
height: height * 0.25,
|
|
||||||
width: '100%'
|
|
||||||
}}>
|
|
||||||
<WebView
|
|
||||||
onLoad={onLoad}
|
|
||||||
ref={webviewRef}
|
|
||||||
style={{
|
|
||||||
width: '100%',
|
|
||||||
height: '100%',
|
|
||||||
backgroundColor: 'transparent'
|
|
||||||
}}
|
|
||||||
cacheMode="LOAD_DEFAULT"
|
|
||||||
domStorageEnabled={true}
|
|
||||||
scrollEnabled={true}
|
|
||||||
bounces={false}
|
|
||||||
allowFileAccess={true}
|
|
||||||
scalesPageToFit={true}
|
|
||||||
allowingReadAccessToURL={
|
|
||||||
Platform.OS === 'android' ? true : null
|
|
||||||
}
|
|
||||||
onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
|
|
||||||
allowFileAccessFromFileURLs={true}
|
|
||||||
allowUniversalAccessFromFileURLs={true}
|
|
||||||
originWhitelist={['*']}
|
|
||||||
javaScriptEnabled={true}
|
|
||||||
cacheEnabled={true}
|
|
||||||
source={
|
|
||||||
Platform.OS === 'ios'
|
|
||||||
? {uri: sourceUri}
|
|
||||||
: {
|
|
||||||
uri: 'file:///android_asset/plaineditor.html',
|
|
||||||
baseUrl: 'file:///android_asset/'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
width: '100%',
|
width: '100%',
|
||||||
paddingHorizontal: 12
|
height: height * 0.25,
|
||||||
|
paddingBottom: 15
|
||||||
|
}}>
|
||||||
|
<WebView
|
||||||
|
onLoad={onLoad}
|
||||||
|
ref={webviewRef}
|
||||||
|
style={{
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
backgroundColor: 'transparent'
|
||||||
|
}}
|
||||||
|
cacheMode="LOAD_DEFAULT"
|
||||||
|
domStorageEnabled={true}
|
||||||
|
scrollEnabled={true}
|
||||||
|
bounces={false}
|
||||||
|
allowFileAccess={true}
|
||||||
|
scalesPageToFit={true}
|
||||||
|
allowingReadAccessToURL={
|
||||||
|
Platform.OS === 'android' ? true : null
|
||||||
|
}
|
||||||
|
onMessage={onMessage}
|
||||||
|
onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
|
||||||
|
allowFileAccessFromFileURLs={true}
|
||||||
|
allowUniversalAccessFromFileURLs={true}
|
||||||
|
originWhitelist={['*']}
|
||||||
|
javaScriptEnabled={true}
|
||||||
|
cacheEnabled={true}
|
||||||
|
source={
|
||||||
|
Platform.OS === 'ios'
|
||||||
|
? {uri: sourceUri}
|
||||||
|
: {
|
||||||
|
uri: 'file:///android_asset/plaineditor.html',
|
||||||
|
baseUrl: 'file:///android_asset/'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View
|
||||||
|
style={{
|
||||||
|
flexDirection: 'row',
|
||||||
|
paddingHorizontal: 12,
|
||||||
|
paddingRight: 80,
|
||||||
|
alignItems: 'center'
|
||||||
}}>
|
}}>
|
||||||
<Button
|
<Button
|
||||||
color={colors.accent}
|
color={colors.shade}
|
||||||
onPress={onPress}
|
onPress={onPress}
|
||||||
loading={loading}
|
icon={modes[mode].icon}
|
||||||
icon="check"
|
onPress={async () => {
|
||||||
iconSize={25}
|
let _mode = modes[mode];
|
||||||
type="action"
|
if (
|
||||||
|
_mode.type === 'text' &&
|
||||||
|
validator.isURL(rawData.value)
|
||||||
|
) {
|
||||||
|
let html = await sanitizeHtml(rawData.value);
|
||||||
|
html = await absolutifyImgs(html, rawData.value);
|
||||||
|
|
||||||
|
setNote(note => {
|
||||||
|
note.content.data = html;
|
||||||
|
return {...note};
|
||||||
|
});
|
||||||
|
setMode(2);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_mode.type === 'clip') {
|
||||||
|
let html = validator.isURL(rawData.value)
|
||||||
|
? makeHtmlFromUrl(rawData.value)
|
||||||
|
: makeHtmlFromPlainText(rawData.value);
|
||||||
|
setNote(note => {
|
||||||
|
note.content.data = html;
|
||||||
|
return {...note};
|
||||||
|
});
|
||||||
|
setMode(1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
title={modes[mode].title}
|
||||||
|
iconSize={18}
|
||||||
|
iconColor={colors.accent}
|
||||||
|
textStyle={{
|
||||||
|
fontSize: 12,
|
||||||
|
color: colors.accent,
|
||||||
|
marginLeft: 5
|
||||||
|
}}
|
||||||
style={{
|
style={{
|
||||||
position: 'absolute',
|
marginRight: 10,
|
||||||
zIndex: 999,
|
height: 30,
|
||||||
...getElevation(10),
|
borderRadius: 100,
|
||||||
right: 24,
|
paddingHorizontal: 12,
|
||||||
bottom: -35
|
marginTop: -2.5
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<View
|
{Clipboard.hasString() ? (
|
||||||
style={{
|
<Button
|
||||||
marginTop: 10,
|
color={colors.nav}
|
||||||
minHeight: 100,
|
onPress={onPress}
|
||||||
borderRadius: 10,
|
icon="clipboard"
|
||||||
...getElevation(5),
|
onPress={async () => {
|
||||||
backgroundColor: colors.bg
|
let text = await Clipboard.getString();
|
||||||
}}>
|
if (text) {
|
||||||
<TextInput
|
let content = await getContent();
|
||||||
ref={textInputRef}
|
setNote(note => {
|
||||||
style={{
|
note.content.data =
|
||||||
fontSize: 16,
|
content + '\n' + makeHtmlFromPlainText(text);
|
||||||
color: colors.pri,
|
return {...note};
|
||||||
fontFamily: 'OpenSans-Regular',
|
});
|
||||||
padding: 12,
|
}
|
||||||
width: '100%'
|
}}
|
||||||
|
iconSize={18}
|
||||||
|
iconColor={colors.icon}
|
||||||
|
title="Paste"
|
||||||
|
textStyle={{
|
||||||
|
fontSize: 12,
|
||||||
|
color: colors.icon,
|
||||||
|
marginLeft: 5
|
||||||
}}
|
}}
|
||||||
placeholderTextColor={colors.icon}
|
|
||||||
onChangeText={v => (editorContentValue = v)}
|
|
||||||
multiline={true}
|
|
||||||
numberOfLines={quickNote ? 5 : 3}
|
|
||||||
textAlignVertical="top"
|
|
||||||
value={editorContentValue}
|
|
||||||
blurOnSubmit={false}
|
|
||||||
placeholder={
|
|
||||||
quickNote
|
|
||||||
? 'Write something...'
|
|
||||||
: 'Add some additional notes here'
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<View
|
|
||||||
style={{
|
style={{
|
||||||
flexDirection: 'row',
|
marginRight: 15,
|
||||||
paddingHorizontal: 12,
|
height: 30,
|
||||||
paddingRight: 80
|
borderRadius: 100,
|
||||||
}}>
|
paddingHorizontal: 6,
|
||||||
<Button
|
marginTop: -2.5
|
||||||
color={colors.shade}
|
}}
|
||||||
onPress={onPress}
|
/>
|
||||||
loading={loading}
|
) : null}
|
||||||
icon={modes[mode].icon}
|
|
||||||
onPress={async () => {
|
|
||||||
let _mode = modes[mode];
|
|
||||||
if (_mode.type === "text") {
|
|
||||||
setMode(2);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (_mode.type === "clip") {
|
|
||||||
setMode(1);
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_mode.type == "link") {
|
|
||||||
setMode(3)
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
title={modes[mode].title}
|
|
||||||
iconSize={18}
|
|
||||||
iconColor={colors.accent}
|
|
||||||
textStyle={{
|
|
||||||
fontSize: 12,
|
|
||||||
color: colors.accent,
|
|
||||||
marginLeft: 5
|
|
||||||
}}
|
|
||||||
style={{
|
|
||||||
marginRight: 10,
|
|
||||||
height: 30,
|
|
||||||
borderRadius: 100,
|
|
||||||
paddingHorizontal: 12,
|
|
||||||
marginTop: -2.5
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{Clipboard.hasString() ? (
|
|
||||||
<Button
|
|
||||||
color={colors.nav}
|
|
||||||
onPress={onPress}
|
|
||||||
loading={loading}
|
|
||||||
icon="clipboard"
|
|
||||||
onPress={async () => {
|
|
||||||
let text = await Clipboard.getString();
|
|
||||||
if (text) {
|
|
||||||
textInputRef.current?.setNativeProps({
|
|
||||||
text: text
|
|
||||||
});
|
|
||||||
editorContentValue = text;
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
iconSize={18}
|
|
||||||
iconColor={colors.icon}
|
|
||||||
title="Paste"
|
|
||||||
textStyle={{
|
|
||||||
fontSize: 12,
|
|
||||||
color: colors.icon,
|
|
||||||
marginLeft: 5
|
|
||||||
}}
|
|
||||||
style={{
|
|
||||||
marginRight: 15,
|
|
||||||
height: 30,
|
|
||||||
borderRadius: 100,
|
|
||||||
paddingHorizontal: 6,
|
|
||||||
marginTop: -2.5
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</View>
|
</View>
|
||||||
<View
|
|
||||||
style={{
|
|
||||||
height: 40
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</View>
|
</View>
|
||||||
</>
|
</View>
|
||||||
)}
|
<View
|
||||||
|
style={{
|
||||||
|
height: 40
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
</AnimatedKAV>
|
</AnimatedKAV>
|
||||||
</AnimatedSAV>
|
</AnimatedSAV>
|
||||||
);
|
);
|
||||||
@@ -699,7 +592,7 @@ const Button = ({
|
|||||||
]}>
|
]}>
|
||||||
{loading && <ActivityIndicator color="white" />}
|
{loading && <ActivityIndicator color="white" />}
|
||||||
|
|
||||||
{icon && (
|
{icon && !loading && (
|
||||||
<Icon name={icon} size={iconSize} color={iconColor || 'white'} />
|
<Icon name={icon} size={iconSize} color={iconColor || 'white'} />
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user