Merge pull request #67 from streetwriters/revert-66-feat-notebook-header

Revert "Feat notebook header"
This commit is contained in:
Ammar Ahmed
2021-12-02 10:39:20 +05:00
committed by GitHub
38 changed files with 670 additions and 960 deletions

View File

@@ -112,6 +112,7 @@ const App = () => {
useEffect(() => {
databaseHasLoaded = false;
useMessageStore.getState().setAnnouncement();
(async () => {
try {
await SettingsService.init();

View File

@@ -1,22 +1,21 @@
body {
margin: 0px !important;
font-family: 'Open Sans';
font-family:"Open Sans";
}
.app-main {
overflow: visible;
}
#formBox input {
font-family: 'Open Sans';
#formBox textarea {
font-family: "Open Sans";
font-weight: 600 !important;
background-color: transparent;
border: none;
width: 100%;
outline: none;
resize: none;
font-size: 25px;
height: 45x;
font-size: 32px;
}
#formBox {
@@ -28,30 +27,47 @@ body {
background-color: transparent;
padding-left: 12px;
padding-right: 12px;
min-height: 45px;
display: flex;
flex-direction: column;
justify-content: flex-end;
}
#formBox > div,
#formBox > input {
#formBox > textarea {
word-wrap: break-word; /* make sure the div and the textarea wrap words in the same way */
box-sizing: border-box;
width: 100%;
}
#titlebar input:focus {
outline: none;
#formBox > textarea {
overflow: hidden;
position: absolute;
height: 100%;
padding-top: 4px;
padding-bottom: 5px;
}
#textCopy {
font-family: "Open Sans";
visibility: hidden;
font-weight: 600 !important;
font-size: 32px;
padding-top: 4px;
padding-bottom: 5px;
}
#formBox > div {
min-height: 45px;
}
.info-bar {
font-family: 'Open Sans';
font-family: "Open Sans";
color: gray;
font-size: 11.5px;
height: 13px;
font-size: 11px;
height: 15px;
display: flex;
padding-left: 4px !important;
justify-content: space-between;
margin-top:5px;
}
.info-bar a {
@@ -59,16 +75,29 @@ body {
color: gray;
}
#infowords,#infodate,#infosaved {
font-family: 'Open Sans';
#titlebar textarea:focus {
outline: none;
}
#infowords {
font-family: "Open Sans";
margin-right: 5px;
margin-left: 0px;
border-radius: 5px;
border-radius: 5;
margin-top: 0;
height:16px;
padding-top:2.5px;
}
.visible {
display: inline-flex !important;
#infodate {
font-family: "Open Sans";
margin-right: 5px;
margin-left: 5px;
margin-top: 0;
border-radius: 5;
}
#infosaved {
font-family: "Open Sans";
margin-right: 5px;
margin-left: 5px;
border-radius: 5;
margin-top: 0;
}

View File

@@ -126,9 +126,13 @@ function setTheme() {
let node = `
#titleInput {
color:${pageTheme.colors.heading};
font-size:${25 * pageTheme.colors.factor};
font-size:${32 * pageTheme.colors.factor};
}
#textCopy {
color:${pageTheme.colors.pri};
font-size:${32 * pageTheme.colors.factor};
}
#titleInput::-webkit-input-placeholder {
color:${pageTheme.colors.icon}
}
@@ -136,7 +140,6 @@ function setTheme() {
.info-bar {
color:${pageTheme.colors.icon};
}
#titlebar {
display:flex !important;
}
@@ -222,6 +225,7 @@ function setTheme() {
background: none !important;
border-bottom: 1px solid ${pageTheme.colors.nav} !important;
}`;
let node2 = `
.mce-content-body table[data-mce-selected], {
@@ -338,8 +342,9 @@ code {
`;
let editorHead =
tinymce.activeEditor.contentDocument.getElementsByTagName('head')[0];
let editorHead = tinymce.activeEditor.contentDocument.getElementsByTagName(
'head'
)[0];
let css2 = document.createElement('style');
css2.appendChild(document.createTextNode(node2));
editorHead.appendChild(css2);

View File

@@ -1,76 +1,102 @@
body {
margin: 0px !important;
font-family: 'Open Sans';
margin:0px !important;
overflow: visible;
font-family:"Open Sans";
}
.app-main {
overflow: visible;
}
#formBox textarea {
font-family: "Open Sans";
font-weight: 600 !important;
background-color: transparent;
border: none;
width: 100%;
outline: none;
resize: none;
font-size: 32px;
}
#formBox {
margin-block-end: 0px;
position: relative;
}
#titlebar {
background-color: transparent;
padding-left: 0px;
padding-right: 12px;
min-height: 45px;
display: flex;
flex-direction: column;
justify-content: flex-end;
}
#formBox > div,
#formBox > textarea {
word-wrap: break-word; /* make sure the div and the textarea wrap words in the same way */
box-sizing: border-box;
width: 100%;
}
#formBox > textarea {
overflow: hidden;
position: absolute;
height: 100%;
#formBox input {
font-family: 'Open Sans';
font-weight: 600 !important;
background-color: transparent;
border: none;
width: 100%;
outline: none;
resize: none;
font-size: 25px;
height: 45x;
}
padding-top: 4px;
padding-bottom: 5px;
}
#textCopy {
font-family: "Open Sans";
font-weight: 600 !important;
font-size: 32px;
padding-top: 4px;
padding-bottom: 5px;
padding-right: 0.5em;
padding-left: 0.5em;
}
#formBox > div {
min-height: 45px;
}
.info-bar {
font-family: "Open Sans";
color: gray;
font-size: 11px;
height: 15px;
display: flex;
padding-left: 14px !important;
justify-content: space-between;
}
#formBox {
margin-block-end: 0px;
position: relative;
}
#titlebar {
background-color: transparent;
padding-left: 0px;
padding-right: 12px;
display: flex;
flex-direction: column;
justify-content: flex-end;
}
#formBox > div,
#formBox > input {
word-wrap: break-word; /* make sure the div and the textarea wrap words in the same way */
box-sizing: border-box;
width: 100%;
}
#titlebar input:focus {
outline: none;
}
.info-bar {
font-family: 'Open Sans';
color: gray;
font-size: 11.5px;
height: 13px;
display: flex;
padding-left: 4px !important;
justify-content: space-between;
margin-top: 5px;
}
.info-bar a {
text-decoration: none;
color: gray;
}
#infowords,
#infodate,
#infosaved {
font-family: 'Open Sans';
margin-right: 5px;
margin-left: 0px;
border-radius: 5px;
margin-top: 0;
height: 16px;
padding-top: 2.5px;
}
.visible {
display: inline-flex !important;
}
.info-bar a {
text-decoration: none;
color: gray
}
#titlebar textarea:focus {
outline: none;
}
#infowords {
font-family: "Open Sans";
margin-right: 5px;
margin-left: 0px;
border-radius: 5;
margin-top: 0;
}
#infodate {
font-family: "Open Sans";
margin-right: 5px;
margin-left: 5px;
margin-top: 0;
border-radius: 5;
}
#infosaved {
font-family: "Open Sans";
margin-right: 5px;
margin-left: 5px;
border-radius: 5;
margin-top: 0;
}

View File

@@ -14,15 +14,15 @@
<input id="image-input" accept='image/png, image/gif, image/jpeg, image/bmp, image/x-icon' type="file"
name="name" style="display: none;" />
<div id="titlebar">
<div id="formBox">
<input maxlength="150" id="titleInput"
placeholder="Note title"></input>
</div>
<form id="formBox">
<textarea maxlength="150" id="titleInput" placeholder="Note title"></textarea>
<div id="textCopy"></div>
</form>
<div class="info-bar">
<div style="display:flex;">
<p id="infowords"></p>
<p style="display:none" id="infodate"></p>
<p style="display:none" id="infosaved"></p>
<p id="infodate"></p>
<p id="infosaved"></p>
</div>
</div>
</div>

View File

@@ -263,109 +263,6 @@ function init_tiny(size) {
console.error(e);
}
},
init_instance_callback: function (_editor) {
editor = _editor;
setTheme();
editor.on('SelectionChange', function (e) {
selectchange();
});
editor.on('ClearUndos', onUndoChange);
editor.on('Undo', onUndoChange);
editor.on('Redo', onUndoChange);
editor.on('TypingUndos', onUndoChange);
editor.on('BeforeAddUndo', onUndoChange);
editor.on('AddUndo', onUndoChange);
editor.on('cut', function () {
onChange({type: 'cut'});
onUndoChange();
});
editor.on('copy', onUndoChange);
editor.on('paste', function () {
onChange({type: 'paste'});
});
editor.on('focus', function () {
reactNativeEventHandler('focus', 'editor');
});
editor.on('SetContent', function (event) {
console.log('content set', event.paste, globalThis.isClearingNoteData);
if (globalThis.isClearingNoteData) {
globalThis.isClearingNoteData = false;
return;
}
setTimeout(function () {
editor.undoManager.transact(function () {});
}, 1000);
if (!event.paste) {
reactNativeEventHandler('noteLoaded', true);
}
if (event.paste) {
isLoading = false;
onChange(event);
}
});
editor.on('NewBlock', function (e) {
console.log('New Block');
const {newBlock} = e;
let target;
if (newBlock) {
target = newBlock.previousElementSibling;
}
if (target && target.classList.contains(COLLAPSED_KEY)) {
target.classList.remove(COLLAPSED_KEY);
collapseElement(target);
}
});
editor.on('touchstart mousedown', function (e) {
const {target} = e;
if (
e.offsetX < 6 &&
collapsibleTags[target.tagName] &&
target.parentElement &&
target.parentElement.tagName === 'BODY'
) {
e.preventDefault();
e.stopImmediatePropagation();
e.stopPropagation();
editor.undoManager.transact(function () {
if (target.classList.contains(COLLAPSED_KEY)) {
target.classList.remove(COLLAPSED_KEY);
} else {
target.classList.add(COLLAPSED_KEY);
}
collapseElement(target);
editor.getHTML().then(function (html) {
reactNativeEventHandler('tiny', html);
});
});
}
});
editor.on('tap', function (e) {
if (
e.target.classList.contains('mce-content-body') &&
!e.target.innerText.length > 0
) {
e.preventDefault();
}
});
editor.on('ScrollIntoView', function (e) {
e.preventDefault();
e.elm.scrollIntoView({
behavior: 'smooth',
block: 'nearest'
});
});
editor.on('input', onChange);
editor.on('keyup', onChange);
editor.on('NodeChange', onChange);
editor.on('compositionend', onChange);
},
setup: function (_editor) {
editor = _editor;
editor.ui.registry.addButton('deleteimage', {
@@ -384,7 +281,9 @@ function init_tiny(size) {
});
editor.on('init', function (e) {
reactNativeEventHandler('status', true);
setTimeout(function () {
reactNativeEventHandler('status', true);
}, 300);
});
editor.ui.registry.addButton('deletevideo', {
@@ -467,6 +366,106 @@ function init_tiny(size) {
},
onclick: function () {}
});
},
init_instance_callback: function (_editor) {
editor = _editor;
setTheme();
editor.on('SelectionChange', function (e) {
selectchange();
});
editor.on('ClearUndos', onUndoChange);
editor.on('Undo', onUndoChange);
editor.on('Redo', onUndoChange);
editor.on('TypingUndos', onUndoChange);
editor.on('BeforeAddUndo', onUndoChange);
editor.on('AddUndo', onUndoChange);
editor.on('cut', function () {
onChange({type: 'cut'});
onUndoChange();
});
editor.on('copy', onUndoChange);
editor.on('paste', function () {
onChange({type: 'paste'});
});
editor.on('tap', e => {
if (e.target.classList.contains('mce-content-body')) {
e.preventDefault();
}
});
editor.on('focus', function () {
reactNativeEventHandler('focus', 'editor');
});
editor.on('SetContent', function (event) {
if (globalThis.isClearingNoteData) {
globalThis.isClearingNoteData = false;
return;
}
setTimeout(function() {
editor.undoManager.transact(function () {});
},1000);
if (!event.paste) {
reactNativeEventHandler('noteLoaded', true);
}
if (event.paste) {
isLoading = false;
onChange(event);
}
});
editor.on('NewBlock', function (e) {
console.log('New Block');
const {newBlock} = e;
let target;
if (newBlock) {
target = newBlock.previousElementSibling;
}
if (target && target.classList.contains(COLLAPSED_KEY)) {
target.classList.remove(COLLAPSED_KEY);
collapseElement(target);
}
});
editor.on('touchstart mousedown', function (e) {
const {target} = e;
if (
e.offsetX < 6 &&
collapsibleTags[target.tagName] &&
target.parentElement &&
target.parentElement.tagName === 'BODY'
) {
e.preventDefault();
e.stopImmediatePropagation();
e.stopPropagation();
editor.undoManager.transact(function () {
if (target.classList.contains(COLLAPSED_KEY)) {
target.classList.remove(COLLAPSED_KEY);
} else {
target.classList.add(COLLAPSED_KEY);
}
collapseElement(target);
editor.getHTML().then(function (html) {
reactNativeEventHandler('tiny', html);
});
});
}
});
editor.on('ScrollIntoView', function (e) {
e.preventDefault();
e.elm.scrollIntoView({
behavior: 'smooth',
block: 'nearest'
});
});
editor.on('input', onChange);
editor.on('keyup', onChange);
editor.on('NodeChange', onChange);
editor.on('compositionend', onChange);
}
});
}

View File

@@ -2,31 +2,38 @@ let titleInput = document.getElementById('titleInput');
let infoBar = '.info-bar';
let info = null;
let scrollTimer = null;
function onDomContentLoaded() {
document.body.onscroll = function (event) {
if (scrollTimer) {
clearTimeout(scrollTimer);
scrollTimer = null;
}
updateInfoBar();
scrollTimer = setTimeout(function () {
window.ReactNativeWebView.postMessage(
JSON.stringify({
visible: event.target.documentElement.scrollTop,
title: document.getElementById('titleInput').value,
type: 'scroll'
})
);
}, 100);
};
}
function attachTitleInputListeners() {
infoBar = '.info-bar';
document.addEventListener('DOMContentLoaded', onDomContentLoaded, false);
document.addEventListener(
'DOMContentLoaded',
function () {
autosize();
document.body.onscroll = function (event) {
if (scrollTimer) {
clearTimeout(scrollTimer);
scrollTimer = null;
}
scrollTimer = setTimeout(function () {
window.ReactNativeWebView.postMessage(
JSON.stringify({
visible: event.target.documentElement.scrollTop,
title: document.getElementById('titleInput').value,
type: 'scroll'
})
);
}, 100);
};
},
false
);
document.getElementById('formBox').onsubmit = function (evt) {
evt.preventDefault();
if (tinymce.activeEditor) {
tinymce.activeEditor && tinymce.activeEditor.focus();
}
onTitleChange();
};
document.getElementById('titleInput').onkeypress = function (evt) {
if (evt.keyCode === 13 || evt.which === 13) {
@@ -42,6 +49,7 @@ function attachTitleInputListeners() {
document
.getElementById('titleInput')
.addEventListener('focus', function (evt) {
autosize();
if (window.ReactNativeWebView) {
window.ReactNativeWebView.postMessage(
JSON.stringify({
@@ -61,10 +69,10 @@ function attachTitleInputListeners() {
onTitleChange();
};
}
let titleTimeout = 0;
function onTitleChange() {
clearTimeout(titleTimeout);
titleTimeout = setTimeout(() => {
setTimeout(() => {
autosize();
if (isLoading) {
return;
}
@@ -76,8 +84,7 @@ function onTitleChange() {
info = document.querySelector(infoBar);
if (tinymce.activeEditor) {
info.querySelector('#infowords').innerText =
editor.countWords() + ' words';
updateInfoBar()
editor.countWords() + ' words';
}
if (titleMessage && typeof titleMessage.value === 'string') {
@@ -85,51 +92,24 @@ function onTitleChange() {
window.ReactNativeWebView.postMessage(JSON.stringify(titleMessage));
}
}
}, 300);
}, 500);
}
function autosize() {
// let ele = document.getElementById('textCopy');
// ele.innerHTML = document
// .getElementById('titleInput')
// .value.replace(/\n/g, '<br/>');
// let newHeight = document.getElementById('titlebar').scrollHeight;
// let css = document.createElement('style');
// css.type = 'text/css';
// let node = `
// .tox-tinymce {
// min-height:calc(100vh - ${newHeight}px) !important;
// };
// `;
// css.appendChild(document.createTextNode(node));
// document.getElementsByTagName('head')[0].appendChild(css);
}
function isInvalidValue(value) {
return (
value === '' ||
value === '<p></p>' ||
value === '<p><br></p>' ||
value === '<p>&nbsp;</p>'
);
}
function updateInfoBar() {
let ids = ['infodate', 'infosaved'];
ids.forEach(id => {
let element = document.getElementById(id);
if (!element) return;
if (element.textContent && element.textContent !== '') {
if (!element.classList.contains("visible")) {
element.classList.add('visible');
}
} else {
if (element.classList.contains("visible")) {
element.classList.remove('visible');
}
}
});
let ele = document.getElementById('textCopy');
ele.innerHTML = document
.getElementById('titleInput')
.value.replace(/\n/g, '<br/>');
let newHeight = document.getElementById('titlebar').scrollHeight;
let css = document.createElement('style');
css.type = 'text/css';
let node = `
.tox-tinymce {
min-height:calc(100vh - ${newHeight}px) !important;
};
`;
css.appendChild(document.createTextNode(node));
document.getElementsByTagName('head')[0].appendChild(css);
}
function attachMessageListener() {
@@ -138,7 +118,6 @@ function attachMessageListener() {
if (isSafari) {
listenerHandler = window;
}
listenerHandler.addEventListener('message', function (data) {
let message = JSON.parse(data.data);
let type = message.type;
@@ -152,12 +131,7 @@ function attachMessageListener() {
isLoading = true;
globalThis.isClearingNoteData = false;
tinymce.activeEditor.mode.set('readonly');
if (isInvalidValue(value)) {
tinymce.activeEditor.setContent('');
} else {
tinymce.activeEditor.setContent(value);
}
tinymce.activeEditor.setContent(value);
setTimeout(function () {
document.activeElement.blur();
window.blur();
@@ -167,8 +141,7 @@ function attachMessageListener() {
}, 300);
info = document.querySelector(infoBar);
info.querySelector('#infowords').innerText =
editor.countWords() + ' words';
updateInfoBar()
editor.countWords() + ' words';
break;
case 'htmldiff':
document.getElementsByClassName('htmldiff_div')[0].innerHTML = value;
@@ -182,6 +155,9 @@ function attachMessageListener() {
break;
case 'title':
document.getElementById('titleInput').value = value;
setTimeout(function () {
autosize();
}, 100);
break;
default:
break;

View File

@@ -5,14 +5,13 @@ export const BouncingView = ({
children,
style,
duration = 600,
animated = true,
initialScale = 0.9
animated = true
}) => {
const scale = Animated.useValue(!animated ? 1 : initialScale);
const scale = Animated.useValue(!animated ? 1 : 0.9);
useEffect(() => {
if (!animated) return;
scale.setValue(initialScale);
scale.setValue(0.9);
timing(scale, {
toValue: 1,
duration: duration,
@@ -20,7 +19,7 @@ export const BouncingView = ({
}).start();
return () => {
if (!animated) return;
scale.setValue(initialScale);
scale.setValue(0.9);
};
}, []);

View File

@@ -400,11 +400,6 @@ export class AddNotebookDialog extends React.Component {
type="accent"
onPress={this.addNewNotebook}
/>
<View
style={{
height:35
}}
/>
</View>
<Toast context="local" />

View File

@@ -49,7 +49,7 @@ export const Announcement = ({color}) => {
marginTop: 15
}}
data={announcement?.body.filter(item =>
allowedOnPlatform(item.platforms)
allowedOnPlatform(item.platform)
)}
renderItem={({item, index}) =>
renderItem({item: item, index: index, color: colors[color],inline:true})

View File

@@ -1,21 +1,22 @@
import React from 'react';
import {View} from 'react-native';
import {useTracked} from '../../provider';
import {eSendEvent, presentSheet} from '../../services/EventManager';
import {eCloseAnnouncementDialog} from '../../utils/Events';
import {openLinkInBrowser} from '../../utils/functions';
import {SIZE} from '../../utils/SizeUtils';
import {sleep} from '../../utils/TimeUtils';
import { View } from 'react-native';
import { useTracked } from '../../provider';
import { eSendEvent, presentSheet } from '../../services/EventManager';
import { eCloseAnnouncementDialog, eOpenPremiumDialog } from '../../utils/Events';
import { openLinkInBrowser } from '../../utils/functions';
import { SIZE } from '../../utils/SizeUtils';
import { sleep } from '../../utils/TimeUtils';
import SettingsBackupAndRestore from '../../views/Settings/backup-restore';
import {Button} from '../Button';
import GeneralSheet from '../GeneralSheet';
import {PricingPlans} from '../Premium/pricing-plans';
import {allowedOnPlatform, getStyle} from './functions';
import { Button } from '../Button';
import { allowedOnPlatform, getStyle } from './functions';
export const Cta = ({actions, style = {}, color, inline}) => {
export const Cta = ({actions, style = {}, color,inline}) => {
const [state] = useTracked();
const colors = state.colors;
let buttons = actions.filter(item => allowedOnPlatform(item.platforms)) || [];
let buttons =
actions.filter(item =>
allowedOnPlatform(item.platforms)
) || [];
const onPress = async item => {
if (!inline) {
@@ -27,18 +28,9 @@ export const Cta = ({actions, style = {}, color, inline}) => {
await openLinkInBrowser(item.data, colors);
} catch (e) {}
} else if (item.type === 'promo') {
presentSheet({
component: (
<PricingPlans
marginTop={1}
promo={{
promoCode: item.data,
text: item.title
}}
/>
),
noIcon: true,
noProgress: true
eSendEvent(eOpenPremiumDialog, {
promoCode: item.data,
text: item.title
});
} else if (item.type === 'backup') {
presentSheet({
@@ -56,7 +48,6 @@ export const Cta = ({actions, style = {}, color, inline}) => {
paddingHorizontal: 12,
...getStyle(style)
}}>
<GeneralSheet context="premium_cta" />
{buttons.length > 0 &&
buttons.slice(0, 1).map(item => (
<Button

View File

@@ -1,4 +1,4 @@
import React, { Fragment } from 'react';
import React from 'react';
import {View} from 'react-native';
import {allowedPlatforms} from '../../provider/stores';
import {ProFeatures} from '../ResultDialog/pro-features';
@@ -47,7 +47,6 @@ const renderItems = {
title: Title,
description: Description,
body: Body,
text:Body,
image: Photo,
list: List,
subheading: SubHeading,
@@ -56,7 +55,7 @@ const renderItems = {
};
export const renderItem = ({item, index, color,inline}) => {
const Item = renderItems[item.type] || Fragment
const Item = renderItems[item.type];
return <Item key={item.text || item.src || item.type} {...item} index={index} color={color} inline={inline} />;
};

View File

@@ -2,14 +2,13 @@ import React, {useEffect, useState} from 'react';
import {FlatList, View} from 'react-native';
import {useTracked} from '../../provider';
import {useMessageStore} from '../../provider/stores';
import {DDS} from '../../services/DeviceDetection';
import {eSubscribeEvent, eUnSubscribeEvent} from '../../services/EventManager';
import {
eCloseAnnouncementDialog,
eOpenAnnouncementDialog
} from '../../utils/Events';
import BaseDialog from '../Dialog/base-dialog';
import {allowedOnPlatform, renderItem} from './functions';
import {renderItem} from './functions';
export const AnnouncementDialog = () => {
const [state] = useTracked();
@@ -29,6 +28,7 @@ export const AnnouncementDialog = () => {
const open = data => {
setInfo(data);
console.log(info);
setVisible(true);
};
@@ -49,18 +49,15 @@ export const AnnouncementDialog = () => {
visible={visible}>
<View
style={{
width: DDS.isTab ? 600 : '100%',
width: '100%',
backgroundColor: colors.bg,
maxHeight: DDS.isTab ? '90%' : '100%',
borderRadius: DDS.isTab ? 10 : 0,
overflow: 'hidden',
marginBottom: DDS.isTab ? 20 : 0
maxHeight: '100%'
}}>
<FlatList
style={{
width: '100%'
}}
data={info?.body.filter(item => allowedOnPlatform(item.platforms))}
data={info?.body}
renderItem={renderItem}
/>

View File

@@ -5,7 +5,6 @@ import AnimatedProgress from 'react-native-reanimated-progress-bar';
import {useTracked} from '../../provider';
import {
useFavoriteStore,
useMessageStore,
useNoteStore,
useSettingStore,
useUserStore
@@ -24,11 +23,7 @@ import PremiumService from '../../services/PremiumService';
import {editing} from '../../utils';
import {COLOR_SCHEME_DARK} from '../../utils/Colors';
import {db} from '../../utils/database';
import {
eOpenAnnouncementDialog,
eOpenLoginDialog,
eOpenRateDialog
} from '../../utils/Events';
import {eOpenLoginDialog, eOpenRateDialog} from '../../utils/Events';
import {MMKV} from '../../utils/mmkv';
import {tabBarRef} from '../../utils/Refs';
import {SIZE} from '../../utils/SizeUtils';
@@ -56,7 +51,6 @@ const AppLoader = ({onLoad}) => {
const verifyUser = useUserStore(state => state.verifyUser);
const setVerifyUser = useUserStore(state => state.setVerifyUser);
const deviceMode = useSettingStore(state => state.deviceMode);
const isIntroCompleted = useSettingStore(state => state.isIntroCompleted);
const pwdInput = useRef();
const load = async value => {
@@ -92,7 +86,6 @@ const AppLoader = ({onLoad}) => {
eSendEvent(eOpenLoginDialog, 4);
return;
}
let settingsStore = useSettingStore.getState();
if (await Backup.checkBackupRequired(settingsStore.settings.reminder)) {
await Backup.checkAndRun();
@@ -100,15 +93,7 @@ const AppLoader = ({onLoad}) => {
}
if (await checkForRateAppRequest()) return;
if (await checkNeedsBackup()) return;
if (await PremiumService.getRemainingTrialDaysStatus()) return;
await useMessageStore.getState().setAnnouncement();
if (isIntroCompleted) {
let dialogs = useMessageStore.getState().dialogs;
if (dialogs.length > 0) {
eSendEvent(eOpenAnnouncementDialog, dialogs[0]);
}
}
PremiumService.getRemainingTrialDaysStatus();
})();
}
}, [_loading]);

View File

@@ -7,8 +7,9 @@ import {
StyleSheet,
TouchableOpacity
} from 'react-native';
import {useTracked} from '../../provider';
import useIsFloatingKeyboard from '../../utils/use-is-floating-keyboard';
import { BouncingView } from '../ActionSheetComponent/BouncingView';
import {BouncingView} from '../ActionSheetComponent/BouncingView';
const BaseDialog = ({
visible,

View File

@@ -1,14 +1,15 @@
import React, { useEffect, useRef, useState } from 'react';
import { View } from 'react-native';
import { useTracked } from '../../provider';
import { DDS } from '../../services/DeviceDetection';
import { eSubscribeEvent, eUnSubscribeEvent } from '../../services/EventManager';
import { getElevation } from '../../utils';
import { eCloseSimpleDialog, eOpenSimpleDialog } from '../../utils/Events';
import { sleep } from '../../utils/TimeUtils';
import React, {useEffect, useRef, useState} from 'react';
import {View} from 'react-native';
import {useTracked} from '../../provider';
import {DDS} from '../../services/DeviceDetection';
import {eSubscribeEvent, eUnSubscribeEvent} from '../../services/EventManager';
import {getElevation} from '../../utils';
import {eCloseSimpleDialog, eOpenSimpleDialog} from '../../utils/Events';
import {ph, pv} from '../../utils/SizeUtils';
import {sleep} from '../../utils/TimeUtils';
import Input from '../Input';
import Seperator from '../Seperator';
import { Toast } from '../Toast';
import {Toast} from '../Toast';
import BaseDialog from './base-dialog';
import DialogButtons from './dialog-buttons';
import DialogHeader from './dialog-header';

View File

@@ -12,7 +12,7 @@ import {HeaderRightMenu} from './HeaderRightMenu';
import {Title} from './title';
export const Header = React.memo(
({root, title, screen, isBack, color, action, rightButtons,notebook}) => {
({root, title, screen, isBack, color, action, rightButtons}) => {
const [state] = useTracked();
const {colors} = state;
const insets = useSafeAreaInsets();
@@ -52,7 +52,6 @@ export const Header = React.memo(
{screen !== 'Search' ? (
<Title
notebook={notebook}
headerColor={color}
heading={title}
screen={screen}

View File

@@ -1,57 +1,12 @@
import React, {useEffect, useState} from 'react';
import React from 'react';
import {View} from 'react-native';
import {useTracked} from '../../provider';
import {
eSendEvent,
eSubscribeEvent,
eUnSubscribeEvent
} from '../../services/EventManager';
import Navigation from '../../services/Navigation';
import {eOnNewTopicAdded, eScrollEvent} from '../../utils/Events';
import {SIZE} from '../../utils/SizeUtils';
import { SIZE } from '../../utils/SizeUtils';
import Heading from '../Typography/Heading';
import Paragraph from '../Typography/Paragraph';
export const Title = ({heading, headerColor, screen, notebook}) => {
export const Title = ({heading, headerColor}) => {
const [state] = useTracked();
const {colors} = state;
const [hide, setHide] = useState(screen === 'Notebook' ? true : false);
const onScroll = data => {
if (screen !== 'Notebook') {
setHide(false);
return;
}
if (data.y > 150) {
setHide(false);
} else {
setHide(true);
}
};
useEffect(() => {
eSubscribeEvent(eScrollEvent, onScroll);
return () => {
eUnSubscribeEvent(eScrollEvent, onScroll);
};
}, []);
function navigateToNotebook() {
if (!notebook) return;
let routeName = 'Notebook';
let params = {
menu: false,
notebook: notebook,
title: notebook.title
};
let headerState = {
heading: notebook.title,
id: notebook.id,
type: notebook.type
};
eSendEvent(eOnNewTopicAdded, params);
Navigation.navigate(routeName, params, headerState);
}
return (
<View
@@ -60,27 +15,17 @@ export const Title = ({heading, headerColor, screen, notebook}) => {
flexShrink: 1,
flexDirection: 'row'
}}>
{!hide ? (
<Heading
onPress={navigateToNotebook}
numberOfLines={notebook ? 2 : 1}
size={notebook ? SIZE.md + 2 : SIZE.xl}
style={{
flexWrap: 'wrap'
}}
color={headerColor}>
{notebook && (
<Paragraph numberOfLines={1} size={SIZE.xs + 2}>
{notebook?.title}
{'\n'}
</Paragraph>
)}
<Heading color={colors.accent}>
{heading.slice(0, 1) === '#' ? '#' : null}
</Heading>
{heading.slice(0, 1) === '#' ? heading.slice(1) : heading}
<Heading
numberOfLines={1}
style={{
flexWrap: 'wrap'
}}
color={headerColor}>
<Heading color={colors.accent}>
{heading.slice(0, 1) === '#' ? '#' : null}
</Heading>
) : null}
{heading.slice(0, 1) === '#' ? heading.slice(1) : heading}
</Heading>
</View>
);
};

View File

@@ -16,17 +16,23 @@ import {TimeSince} from '../Menu/TimeSince';
import Heading from '../Typography/Heading';
import Paragraph from '../Typography/Paragraph';
const navigateToTopic = topic => {
let routeName = 'NotesPage';
let params = {...topic, menu: false, get: 'topics'};
let headerState = {
heading: topic.title,
id: topic.id,
type: topic.type
function navigateToNotebook(item) {
let notebook = item;
let routeName = 'Notebook';
let params = {
menu: false,
notebook: notebook,
title: notebook.title
};
eSendEvent(refreshNotesPage, params);
let headerState = {
heading: notebook.title,
id: notebook.id,
type: notebook.type
};
eSendEvent(eOnNewTopicAdded, params);
Navigation.navigate(routeName, params, headerState);
};
}
function navigateToTag(item) {
let tags = db.tags.all;
@@ -78,26 +84,6 @@ const NoteItem = ({item, isTrash, tags}) => {
const compactMode = settings.notesListMode === 'compact';
const allTags = useTagStore(state => state.tags);
function getNotebook() {
if (isTrash || !item.notebooks) return [];
let item_notebook = item.notebooks?.slice(0, 1)[0];
notebook = db.notebooks.notebook(item_notebook.id);
if (!notebook) return [];
let topic = notebook.topics.topic(item_notebook.topics[0])?._topic;
notebook = notebook.data;
return [
{
title: `${notebook?.title} ${topic?.title}`,
notebook: notebook,
topic: topic
}
];
}
return (
<>
<View
@@ -113,30 +99,37 @@ const NoteItem = ({item, isTrash, tags}) => {
zIndex: 10,
elevation: 10
}}>
{getNotebook().map(_item => (
<Button
title={_item.title}
key={_item}
height={20}
icon="book-outline"
type="grayBg"
fontSize={SIZE.xs + 1}
iconSize={SIZE.sm}
textStyle={{
marginRight: 0,
fontWeight: 'normal',
fontFamily: null
}}
style={{
borderRadius: 5,
marginRight: 5,
borderWidth: 0.5,
borderColor: colors.icon,
paddingHorizontal: 6
}}
onPress={() => navigateToTopic(_item.topic)}
/>
))}
{!isTrash && item.notebooks
? item.notebooks?.slice(0, 1)?.map(_item => {
let notebook = db.notebooks.notebook(_item.id);
notebook = notebook?.data;
return notebook ? (
<Button
title={notebook.title}
key={_item}
height={20}
icon="book-outline"
type="grayBg"
fontSize={SIZE.xs + 1}
iconSize={SIZE.sm}
textStyle={{
marginRight: 0,
fontWeight: 'normal',
fontFamily: null
}}
style={{
borderRadius: 5,
marginRight: 5,
borderWidth: 0.5,
borderColor: colors.icon,
paddingHorizontal: 6
}}
onPress={() => navigateToNotebook(notebook)}
/>
) : null;
})
: null}
{!isTrash && tags
? tags.slice(0, 2)?.map(item => (
<Button

View File

@@ -1,17 +1,17 @@
import React from 'react';
import {View} from 'react-native';
import { View } from 'react-native';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import {notesnook} from '../../../e2e/test.ids';
import {useTracked} from '../../provider';
import {useSettingStore} from '../../provider/stores';
import {eSendEvent} from '../../services/EventManager';
import { notesnook } from '../../../e2e/test.ids';
import { useTracked } from '../../provider';
import { useSettingStore } from '../../provider/stores';
import { eSendEvent } from '../../services/EventManager';
import Navigation from '../../services/Navigation';
import {getTotalNotes, history} from '../../utils';
import {eOnNewTopicAdded, refreshNotesPage} from '../../utils/Events';
import {SIZE} from '../../utils/SizeUtils';
import {ActionIcon} from '../ActionIcon';
import {Button} from '../Button';
import {ActionSheetEvent} from '../DialogManager/recievers';
import { getTotalNotes, history } from '../../utils';
import { eOnNewTopicAdded, refreshNotesPage } from '../../utils/Events';
import { SIZE } from '../../utils/SizeUtils';
import { ActionIcon } from '../ActionIcon';
import { Button } from '../Button';
import { ActionSheetEvent } from '../DialogManager/recievers';
import Heading from '../Typography/Heading';
import Paragraph from '../Typography/Paragraph';
@@ -47,6 +47,7 @@ export const NotebookItem = ({item, isTopic = false, notebookID, isTrash}) => {
};
eSendEvent(refreshNotesPage, params);
Navigation.navigate(routeName, params, headerState);
};
return (
@@ -86,10 +87,10 @@ export const NotebookItem = ({item, isTopic = false, notebookID, isTrash}) => {
<Button
title={topic.title}
key={topic.id}
height={null}
height={SIZE.xl}
textStyle={{
fontWeight: 'normal',
fontFamily: null
fontFamily: null,
}}
type="grayBg"
fontSize={SIZE.xs + 1}
@@ -102,11 +103,10 @@ export const NotebookItem = ({item, isTopic = false, notebookID, isTrash}) => {
borderRadius: 5,
maxWidth: 120,
borderWidth: 0.5,
paddingVertical:2.5,
borderColor: colors.icon,
paddingHorizontal: 6,
marginVertical: 5,
marginRight: 5
marginVertical:5,
marginRight:5
}}
onPress={() => navigateToTopic(topic)}
/>

View File

@@ -1,24 +1,24 @@
import React, { useState } from 'react';
import { ScrollView, View } from 'react-native';
import { LAUNCH_ROCKET } from '../../assets/images/assets';
import { useTracked } from '../../provider';
import { useUserStore } from '../../provider/stores';
import { DDS } from '../../services/DeviceDetection';
import { eSendEvent, presentSheet } from '../../services/EventManager';
import { getElevation } from '../../utils';
import { eOpenLoginDialog } from '../../utils/Events';
import { SIZE } from '../../utils/SizeUtils';
import { ActionIcon } from '../ActionIcon';
import { Button } from '../Button';
import React, {useState} from 'react';
import {Image, ScrollView, View} from 'react-native';
import {LAUNCH_ROCKET} from '../../assets/images/assets';
import {useTracked} from '../../provider';
import {useUserStore} from '../../provider/stores';
import {DDS} from '../../services/DeviceDetection';
import {eSendEvent, presentSheet} from '../../services/EventManager';
import {getElevation} from '../../utils';
import {eOpenLoginDialog} from '../../utils/Events';
import {SIZE} from '../../utils/SizeUtils';
import {ActionIcon} from '../ActionIcon';
import {Button} from '../Button';
import GeneralSheet from '../GeneralSheet';
import { SvgToPngView } from '../ListPlaceholders';
import {SvgToPngView} from '../ListPlaceholders';
import Seperator from '../Seperator';
import { Toast } from '../Toast';
import {Toast} from '../Toast';
import Heading from '../Typography/Heading';
import Paragraph from '../Typography/Paragraph';
import { features } from './features';
import { Group } from './group';
import { PricingPlans } from './pricing-plans';
import {features} from './features';
import {Group} from './group';
import {PricingPlans} from './pricing-plans';
export const Component = ({close, promo, getRef}) => {
const [state, dispatch] = useTracked();
@@ -84,8 +84,6 @@ export const Component = ({close, promo, getRef}) => {
style={{
paddingHorizontal: DDS.isTab ? DDS.width / 5 : 0
}}
keyboardDismissMode="none"
keyboardShouldPersistTaps="always"
onScroll={onScroll}>
<View
style={{

View File

@@ -1,5 +1,5 @@
import React, {useEffect, useState} from 'react';
import {ActivityIndicator, Platform, Text, View} from 'react-native';
import {ActivityIndicator, Platform, View} from 'react-native';
import * as RNIap from 'react-native-iap';
import {useTracked} from '../../provider';
import {useUserStore} from '../../provider/stores';
@@ -13,7 +13,6 @@ import {db} from '../../utils/database';
import {
eClosePremiumDialog,
eCloseProgressDialog,
eCloseSimpleDialog,
eOpenLoginDialog
} from '../../utils/Events';
import {openLinkInBrowser} from '../../utils/functions';
@@ -52,12 +51,10 @@ export const PricingPlans = ({
const [products, setProducts] = useState([]);
const [offers, setOffers] = useState(null);
const [buying, setBuying] = useState(false);
const [loading, setLoading] = useState(false);
const getSkus = async () => {
try {
setLoading(true);
let products = await PremiumService.getProducts();
let products = PremiumService.getProducts();
if (products.length > 0) {
let offers = {
monthly: products.find(
@@ -73,48 +70,34 @@ export const PricingPlans = ({
}
setProducts(products);
}
setLoading(false);
} catch (e) {
setLoading(false);
console.log('error getting sku', e);
}
};
const getPromo = async code => {
try {
let productId;
if (code.startsWith('com.streetwriters.notesnook')) {
productId = code;
} else {
productId = await db.offers.getCode(code.split(':')[0], Platform.OS);
}
const getPromo = async productId => {
await sleep(500);
let products = PremiumService.getProducts();
let product = products.find(p => p.productId === productId);
if (!product) return;
let isMonthly = product.productId.indexOf('.mo') > -1;
let cycleText = isMonthly
? promoCyclesMonthly[
product.introductoryPriceCyclesAndroid ||
product.introductoryPriceNumberOfPeriodsIOS
]
: promoCyclesYearly[
product.introductoryPriceCyclesAndroid ||
product.introductoryPriceNumberOfPeriodsIOS
];
let products = await PremiumService.getProducts();
let product = products.find(p => p.productId === productId);
if (!product) return false;
let isMonthly = product.productId.indexOf('.mo') > -1;
let cycleText = isMonthly
? promoCyclesMonthly[
product.introductoryPriceCyclesAndroid ||
product.introductoryPriceNumberOfPeriodsIOS
]
: promoCyclesYearly[
product.introductoryPriceCyclesAndroid ||
product.introductoryPriceNumberOfPeriodsIOS
];
setProduct({
type: 'promo',
offerType: isMonthly ? 'monthly' : 'yearly',
data: product,
cycleText: cycleText,
info: 'Pay monthly, cancel anytime'
});
return true;
} catch (e) {
console.log('PROMOCODE ERROR:', code, e);
return false;
}
setProduct({
type: 'promo',
offerType: isMonthly ? 'monthly' : 'yearly',
data: product,
cycleText: cycleText,
info: 'Pay monthly, cancel anytime'
});
};
useEffect(() => {
@@ -157,17 +140,7 @@ export const PricingPlans = ({
}
};
return loading ? (
<View
style={{
paddingHorizontal: 12,
justifyContent: 'center',
alignItems: 'center',
height: 100
}}>
<ActivityIndicator color={colors.accent} size={25} />
</View>
) : (
return (
<View
style={{
paddingHorizontal: 12
@@ -261,19 +234,23 @@ export const PricingPlans = ({
positivePress: async value => {
if (!value) return;
console.log(value);
eSendEvent(eCloseSimpleDialog);
setBuying(true);
try {
if (!(await getPromo(value)))
throw new Error('Error applying promo code');
ToastEvent.show({
heading: 'Discount applied!',
type: 'success',
context: 'local'
});
setBuying(false);
let productId = await db.offers.getCode(value, Platform.OS);
if (productId) {
getPromo(productId);
ToastEvent.show({
heading: 'Discount applied!',
type: 'success',
context: 'local'
});
} else {
ToastEvent.show({
heading: 'Promo code invalid or expired',
type: 'error',
context: 'local'
});
}
} catch (e) {
setBuying(false);
ToastEvent.show({
heading: 'Promo code invalid or expired',
message: e.message,
@@ -292,63 +269,32 @@ export const PricingPlans = ({
) : (
<View>
{!user ? (
<>
<Button
onPress={() => {
eSendEvent(eClosePremiumDialog);
eSendEvent(eCloseProgressDialog);
setTimeout(() => {
eSendEvent(eOpenLoginDialog, 1);
}, 400);
}}
title={'Try free for 14 days'}
type="accent"
style={{
paddingHorizontal: 24,
marginTop: 20,
marginBottom: 10
}}
/>
{promo &&
!promo.promoCode.startsWith('com.streetwriters.notesnook') ? (
<Paragraph
size={SIZE.md}
textBreakStrategy="balanced"
style={{
alignSelf: 'center',
justifyContent: 'center',
textAlign: 'center'
}}>
Use promo code{' '}
<Text
style={{
fontFamily: 'OpenSans-SemiBold'
}}>
{promo.promoCode}
</Text>{' '}
at checkout
</Paragraph>
) : null}
</>
<Button
onPress={() => {
eSendEvent(eClosePremiumDialog);
setTimeout(() => {
eSendEvent(eOpenLoginDialog, 1);
}, 400);
}}
title={'Try free for 14 days'}
type="accent"
style={{
paddingHorizontal: 24,
marginTop: 20,
marginBottom: 10
}}
/>
) : (
<>
<Button
<PricingItem
product={product}
onPress={() => buySubscription(product.data)}
height={40}
width="50%"
type="accent"
title="Subscribe now"
/>
<Button
onPress={() => {
setProduct(null);
}}
style={{
marginTop: 5
}}
height={30}
fontSize={13}
type="errorShade"
title="Cancel promo code"
/>

View File

@@ -1,8 +1,11 @@
import React from 'react';
import { View } from 'react-native';
import { useTracked } from '../../provider';
import {View} from 'react-native';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import {useTracked} from '../../provider';
import { useEditorStore } from '../../provider/stores';
import { hexToRGBA } from '../../utils/ColorUtils';
import {hexToRGBA} from '../../utils/ColorUtils';
import {SIZE} from '../../utils/SizeUtils';
import Heading from '../Typography/Heading';
export const Filler = ({item, background}) => {
const [state] = useTracked();

View File

@@ -1,12 +1,13 @@
import React, { useEffect, useState } from 'react';
import { useTracked } from '../../provider';
import React, {useEffect, useState} from 'react';
import {useWindowDimensions} from 'react-native';
import {useTracked} from '../../provider';
import { useSettingStore } from '../../provider/stores';
import { eSubscribeEvent, eUnSubscribeEvent } from '../../services/EventManager';
import { history } from '../../utils';
import { PressableButton } from '../PressableButton';
import { ActionStrip } from './action-strip';
import { Filler } from './back-fill';
import { SelectionIcon } from './selection';
import {eSubscribeEvent, eUnSubscribeEvent} from '../../services/EventManager';
import {history} from '../../utils';
import {PressableButton} from '../PressableButton';
import {ActionStrip} from './action-strip';
import {Filler} from './back-fill';
import {SelectionIcon} from './selection';
const SelectionWrapper = ({
children,
@@ -54,7 +55,7 @@ const SelectionWrapper = ({
testID={testID}
onLongPress={_onLongPress}
onPress={_onPress}
customSelectedColor={colors.transGray}
customSelectedColor={colors.nav}
customAlpha={!colors.night ? -0.02 : 0.02}
customOpacity={1}
customStyle={{

View File

@@ -1,15 +1,17 @@
import React from 'react';
import { View } from 'react-native';
import { useTracked } from '../../provider';
import { useMessageStore } from '../../provider/stores';
import { COLORS_NOTE } from '../../utils/Colors';
import { hexToRGBA } from '../../utils/ColorUtils';
import { normalize, SIZE } from '../../utils/SizeUtils';
import { Announcement } from '../Announcements/announcement';
import { Button } from '../Button';
import { Placeholder } from '../ListPlaceholders';
import React, { useEffect } from 'react';
import {View} from 'react-native';
import {useTracked} from '../../provider';
import {useMessageStore} from '../../provider/stores';
import {COLORS_NOTE} from '../../utils/Colors';
import {hexToRGBA} from '../../utils/ColorUtils';
import {normalize, SIZE} from '../../utils/SizeUtils';
import {Button} from '../Button';
import {Placeholder} from '../ListPlaceholders';
import Heading from '../Typography/Heading';
import { Card } from './card';
import {Announcement} from '../Announcements/announcement';
import {Card} from './card';
import { eSendEvent } from '../../services/EventManager';
import { eOpenAnnouncementDialog } from '../../utils/Events';
export const Header = React.memo(
({
@@ -28,7 +30,13 @@ export const Header = React.memo(
const [state] = useTracked();
const {colors} = state;
const announcements = useMessageStore(state => state.announcements);
const dialogs = useMessageStore(state => state.dialogs);
useEffect(() => {
if (dialogs.length > 0) {
eSendEvent(eOpenAnnouncementDialog,dialogs[0]);
}
},[dialogs])
return announcements.length !== 0 && !noAnnouncement ? (
<Announcement color={color || colors.accent} />
) : type === 'search' ? null : !shouldShow ? (

View File

@@ -41,8 +41,7 @@ const SimpleList = ({
headerProps = {
heading: 'Home'
},
screen,
ListHeader
screen
}) => {
const [state] = useTracked();
const {colors} = state;
@@ -104,10 +103,10 @@ const SimpleList = ({
let styles = {
height: '100%',
backgroundColor: colors.bg,
width: '100%',
minHeight: 1,
minWidth: 1,
backgroundColor:colors.bg
minWidth: 1
};
const _keyExtractor = item => item.id || item.title;
@@ -148,19 +147,15 @@ const SimpleList = ({
ListFooterComponent={<Footer />}
ListHeaderComponent={
<>
{ListHeader ? (
ListHeader
) : (
<Header
title={headerProps.heading}
paragraph={headerProps.paragraph}
onPress={headerProps.onPress}
icon={headerProps.icon}
color={headerProps.color}
type={type}
screen={screen}
/>
)}
<Header
title={headerProps.heading}
paragraph={headerProps.paragraph}
onPress={headerProps.onPress}
icon={headerProps.icon}
color={headerProps.color}
type={type}
screen={screen}
/>
</>
}
/>

View File

@@ -1,147 +0,0 @@
import React, {useState} from 'react';
import {View} from 'react-native';
import {useTracked} from '../../provider';
import {useMenuStore} from '../../provider/stores';
import {ToastEvent} from '../../services/EventManager';
import {db} from '../../utils/database';
import {SIZE} from '../../utils/SizeUtils';
import {ActionIcon} from '../ActionIcon';
import {Button} from '../Button';
import Heading from '../Typography/Heading';
import Paragraph from '../Typography/Paragraph';
export const NotebookHeader = ({notebook, onPress, onEditNotebook}) => {
const [state] = useTracked();
const {colors} = state;
const [isPinnedToMenu, setIsPinnedToMenu] = useState(
db.settings.isPinned(notebook.id)
);
const setMenuPins = useMenuStore(state => state.setMenuPins);
const onPinNotebook = async () => {
try {
if (isPinnedToMenu) {
await db.settings.unpin(notebook.id);
} else {
await db.settings.pin(notebook.type, {id: notebook.id});
ToastEvent.show({
heading: 'Shortcut created',
type: 'success'
});
}
setIsPinnedToMenu(db.settings.isPinned(notebook.id));
setMenuPins();
} catch (e) {}
};
return (
<View
style={{
marginBottom: 5,
padding: 0,
width: '100%',
paddingVertical: 15,
paddingHorizontal: 12,
alignSelf: 'center',
borderRadius: 10,
paddingTop: 25
}}>
<View
style={{
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center'
}}>
<Heading size={SIZE.xxl}>{notebook.title}</Heading>
<View
style={{
flexDirection: 'row'
}}>
<ActionIcon
name="link-variant"
onPress={onPinNotebook}
customStyle={{
marginRight: 15,
width:40,
height:40
}}
type={isPinnedToMenu ? "transparent" : "grayBg"}
color={isPinnedToMenu ? colors.accent : colors.icon}
size={SIZE.lg}
/>
<ActionIcon
size={SIZE.lg}
onPress={onEditNotebook}
name="pencil"
type="grayBg"
color={colors.icon}
customStyle={{
width:40,
height:40
}}
/>
</View>
</View>
{notebook.description && (
<Paragraph size={SIZE.md} color={colors.pri}>
{notebook.description}
</Paragraph>
)}
{/* <View
style={{
marginTop: 15,
flexDirection: 'row'
}}>
<Button
title="Edit notebook"
width={null}
height={null}
type="transparent"
icon="pencil"
fontSize={SIZE.sm}
onPress={onEditNotebook}
style={{
alignSelf: 'flex-start',
paddingHorizontal: 12,
borderRadius: 100,
height: 30,
marginRight: 10
}}
/>
<Button
width={null}
height={null}
type={isPinnedToMenu ? 'shade' : 'transparent'}
icon="link-variant"
onPress={onPinNotebook}
style={{
alignSelf: 'flex-start',
paddingVertical: 0,
paddingHorizontal: 0,
width: 30,
height: 30,
borderColor: isPinnedToMenu ? colors.accent : colors.icon,
marginRight: 10
}}
/>
</View> */}
<Paragraph
style={{
marginTop: 10,
fontStyle: 'italic'
}}
size={SIZE.xs + 1}
color={colors.icon}>
{notebook.topics.length === 1
? '1 topic'
: `${notebook.topics.length} topics`}
, last modified on {new Date(notebook.dateEdited).toLocaleString()}
</Paragraph>
</View>
);
};

View File

@@ -364,11 +364,9 @@ export const useMessageStore = create<MessageStore>((set, get) => ({
announcements = [];
}
} catch (e) {
console.log("ERROR",e);
set({announcements: []});
} finally {
let all = await getFiltered(announcements);
console.log("all", all)
set({
announcements: all.filter(a => a.type === 'inline'),
dialogs: all.filter(a => a.type === 'dialog')
@@ -417,7 +415,9 @@ async function shouldShowAnnouncement(announcement) {
let show = announcement.platforms.some(
platform => allowedPlatforms.indexOf(platform) > -1
);
if (!show) return false;
const subStatus = PremiumService.getUser()?.subscription?.type;
show = announcement.userTypes.some(userType => {
switch (userType) {
@@ -428,15 +428,22 @@ async function shouldShowAnnouncement(announcement) {
case 'trialExpired':
return subStatus === SUBSCRIPTION_STATUS.BASIC;
case 'loggedOut':
return !PremiumService.getUser();
show = !PremiumService.getUser();
break;
case 'verified':
return PremiumService.getUser()?.isEmailVerified;
show = PremiumService.getUser()?.isEmailVerified;
break;
case 'loggedIn':
return !!PremiumService.getUser();
show = !!PremiumService.getUser();
break;
case 'unverified':
return !PremiumService.getUser()?.isEmailVerified;
show = !PremiumService.getUser()?.isEmailVerified;
break;
case 'proExpired':
return subStatus === SUBSCRIPTION_STATUS.PREMIUM_EXPIRED || subStatus === SUBSCRIPTION_STATUS.PREMIUM_CANCELED;
show =
subStatus === SUBSCRIPTION_STATUS.PREMIUM_EXPIRED ||
subStatus === SUBSCRIPTION_STATUS.PREMIUM_CANCELED;
break;
case 'any':
default:
return true;

View File

@@ -1,20 +1,20 @@
import { CHECK_IDS } from 'notes-core/common';
import {CHECK_IDS} from 'notes-core/common';
import React from 'react';
import * as RNIap from 'react-native-iap';
import DialogHeader from '../components/Dialog/dialog-header';
import { CompactFeatures } from '../components/Premium/compact-features';
import { PricingPlans } from '../components/Premium/pricing-plans';
import {CompactFeatures} from '../components/Premium/compact-features';
import {PricingPlans} from '../components/Premium/pricing-plans';
import Seperator from '../components/Seperator';
import { useUserStore } from '../provider/stores';
import { itemSkus, SUBSCRIPTION_STATUS } from '../utils';
import { db } from '../utils/database';
import {useMessageStore, useUserStore} from '../provider/stores';
import {itemSkus, SUBSCRIPTION_STATUS} from '../utils';
import {db} from '../utils/database';
import {
eOpenPremiumDialog,
eOpenTrialEndingDialog,
eShowGetPremium
} from '../utils/Events';
import { MMKV } from '../utils/mmkv';
import { eSendEvent, presentSheet, ToastEvent } from './EventManager';
import {MMKV} from '../utils/mmkv';
import {eSendEvent, presentSheet, ToastEvent} from './EventManager';
let premiumStatus = 0;
let products = [];
@@ -39,6 +39,7 @@ async function setPremiumStatus() {
} catch (e) {
premiumStatus = 0;
} finally {
useMessageStore.getState().setAnnouncement();
if (get()) {
await subscriptions.clear();
}
@@ -64,10 +65,7 @@ function getMontlySub() {
return _product;
}
async function getProducts() {
if (!products || products.length === 0) {
products = await RNIap.getSubscriptions(itemSkus);
}
function getProducts() {
return products;
}
@@ -282,7 +280,7 @@ const subscriptions = {
async function getRemainingTrialDaysStatus() {
let user = await db.user.getUser();
if (!user) return false;
if (!user) return;
let premium = user.subscription.type !== SUBSCRIPTION_STATUS.BASIC;
let isTrial = user.subscription.type === SUBSCRIPTION_STATUS.TRIAL;
let total = user.subscription.expiry - user.subscription.start;
@@ -298,7 +296,7 @@ async function getRemainingTrialDaysStatus() {
extend: false
});
MMKV.setItem('lastTrialDialogShownAt', 'ending');
return true;
return;
}
if (!premium && lastTrialDialogShownAt !== 'expired') {
@@ -308,9 +306,7 @@ async function getRemainingTrialDaysStatus() {
extend: false
});
MMKV.setItem('lastTrialDialogShownAt', 'expired');
return true;
}
return false;
}
const features_list = [

View File

@@ -14,15 +14,15 @@ export const db = new Database(
db.host(
__DEV__
? {
API_HOST: 'https://api.notesnook.com',
AUTH_HOST: 'https://auth.streetwriters.co',
SSE_HOST: 'https://events.streetwriters.co',
SUBSCRIPTIONS_HOST: 'https://subscriptions.streetwriters.co'
// API_HOST: 'http://192.168.10.29:5264',
// AUTH_HOST: 'http://192.168.10.29:8264',
// SSE_HOST: 'http://192.168.10.29:7264',
// SUBSCRIPTIONS_HOST: 'http://192.168.10.29:9264',
// ISSUES_HOST: 'http://192.168.10.29:2624'
// API_HOST: 'https://api.notesnook.com',
// AUTH_HOST: 'https://auth.streetwriters.co',
// SSE_HOST: 'https://events.streetwriters.co',
// SUBSCRIPTIONS_HOST: 'https://subscriptions.streetwriters.co'
API_HOST: 'http://192.168.10.29:5264',
AUTH_HOST: 'http://192.168.10.29:8264',
SSE_HOST: 'http://192.168.10.29:7264',
SUBSCRIPTIONS_HOST: 'http://192.168.10.29:9264',
ISSUES_HOST: 'http://192.168.10.29:2624'
}
: {
API_HOST: 'https://api.notesnook.com',

View File

@@ -112,6 +112,7 @@ export const useAppEvents = () => {
EV.subscribe(EVENTS.userSessionExpired, onSessionExpired);
EV.subscribe(EVENTS.userCheckStatus, PremiumService.onUserStatusCheck);
EV.subscribe(EVENTS.userSubscriptionUpdated, onAccountStatusChange);
EV.subscribe(EVENTS.noteRemoved, onNoteRemoved);
EV.subscribe(EVENTS.mediaAttachmentDownloaded, onMediaDownloaded);
EV.subscribe(EVENTS.attachmentsLoading, onLoadingAttachment);
@@ -132,6 +133,7 @@ export const useAppEvents = () => {
EV.unsubscribe(EVENTS.databaseSyncRequested, partialSync);
EV.unsubscribe(EVENTS.userLoggedOut, onLogout);
EV.unsubscribe(EVENTS.userEmailConfirmed, onEmailVerified);
EV.unsubscribe(EVENTS.noteRemoved, onNoteRemoved);
EV.unsubscribe(EVENTS.mediaAttachmentDownloaded, onMediaDownloaded);
EV.subscribe(EVENTS.attachmentsLoading, onLoadingAttachment);
EV.unsubscribe(EVENTS.userCheckStatus, PremiumService.onUserStatusCheck);
@@ -157,8 +159,7 @@ export const useAppEvents = () => {
Navigation.routeNames.Trash,
Navigation.routeNames.Notebook
]);
eSendEvent(eClearEditor, id);
eSendEvent(eClearEditor);
} catch (e) {}
};
@@ -204,7 +205,6 @@ export const useAppEvents = () => {
try {
if (url.startsWith('https://app.notesnook.com/account/verified')) {
await onEmailVerified();
} else {
return;
}

View File

@@ -1,4 +1,3 @@
import {EV, EVENTS} from 'notes-core/common';
import React, {useEffect, useRef} from 'react';
import {
BackHandler,
@@ -170,29 +169,12 @@ const EditorHeader = () => {
useEffect(() => {
eSubscribeEvent(eOnLoadNote, load);
eSubscribeEvent(eClearEditor, onCallClear);
EV.subscribe(EVENTS.noteRemoved, onNoteRemoved);
return () => {
EV.unsubscribe(EVENTS.noteRemoved, onNoteRemoved);
eUnSubscribeEvent(eClearEditor, onCallClear);
eUnSubscribeEvent(eOnLoadNote, load);
};
}, []);
const onNoteRemoved = async id => {
try {
console.log('NOTE REMOVED', id);
await db.notes.remove(id);
if (id !== getNote().id) return;
Navigation.setRoutesToUpdate([
Navigation.routeNames.Favorites,
Navigation.routeNames.Notes,
Navigation.routeNames.NotesPage,
Navigation.routeNames.Trash,
Navigation.routeNames.Notebook
]);
} catch (e) {}
};
useEffect(() => {
if (fullscreen && DDS.isTab) {
handleBack.current = BackHandler.addEventListener(
@@ -312,15 +294,11 @@ const EditorHeader = () => {
name="crown"
color={colors.yellow}
customStyle={{
marginLeft: 10
marginLeft: 10,
borderRadius: 5
}}
top={50}
onPress={async () => {
let note = getNote();
clearEditor(true, true, true);
await loadNote(note);
return;
onPress={() => {
if (editing.isFocused) {
safeKeyboardDismiss();
editing.isFocused = true;
@@ -334,7 +312,8 @@ const EditorHeader = () => {
name="cloud-upload-outline"
color={colors.pri}
customStyle={{
marginLeft: 10
marginLeft: 10,
borderRadius: 5
}}
top={50}
onPress={publishNote}
@@ -346,7 +325,8 @@ const EditorHeader = () => {
name="attachment"
color={colors.pri}
customStyle={{
marginLeft: 10
marginLeft: 10,
borderRadius: 5
}}
top={50}
onPress={picker.pick}

View File

@@ -44,6 +44,7 @@ const EditorOverlay = () => {
easing: Easing.in(Easing.ease)
}).start();
timerClosing = setTimeout(() => {
console.log('clearing now');
opacity.setValue(1);
setLoading(null);
}, 150);

View File

@@ -1,8 +1,8 @@
import { createRef } from 'react';
import { Platform } from 'react-native';
import { presentDialog } from '../../components/Dialog/functions';
import { useEditorStore, useMenuStore } from '../../provider/stores';
import { DDS } from '../../services/DeviceDetection';
import {createRef} from 'react';
import {Platform} from 'react-native';
import {presentDialog} from '../../components/Dialog/functions';
import {useEditorStore, useMenuStore} from '../../provider/stores';
import {DDS} from '../../services/DeviceDetection';
import {
eSendEvent,
eSubscribeEvent,
@@ -10,23 +10,24 @@ import {
} from '../../services/EventManager';
import Navigation from '../../services/Navigation';
import PremiumService from '../../services/PremiumService';
import { editing } from '../../utils';
import { COLORS_NOTE, COLOR_SCHEME } from '../../utils/Colors';
import { hexToRGBA } from '../../utils/ColorUtils';
import { db } from '../../utils/database';
import {editing} from '../../utils';
import {COLORS_NOTE, COLOR_SCHEME} from '../../utils/Colors';
import {hexToRGBA} from '../../utils/ColorUtils';
import {db} from '../../utils/database';
import {
eOnLoadNote,
eShowGetPremium,
eShowMergeDialog
} from '../../utils/Events';
import filesystem from '../../utils/filesystem';
import { openLinkInBrowser } from '../../utils/functions';
import { MMKV } from '../../utils/mmkv';
import { tabBarRef } from '../../utils/Refs';
import { normalize } from '../../utils/SizeUtils';
import { sleep, timeConverter } from '../../utils/TimeUtils';
import {openLinkInBrowser} from '../../utils/functions';
import {MMKV} from '../../utils/mmkv';
import {tabBarRef} from '../../utils/Refs';
import {normalize} from '../../utils/SizeUtils';
import {sleep, timeConverter} from '../../utils/TimeUtils';
import tiny from './tiny/tiny';
import { IMAGE_TOOLTIP_CONFIG } from './tiny/toolbar/config';
import {IMAGE_TOOLTIP_CONFIG} from './tiny/toolbar/config';
import {parse} from 'node-html-parser';
export let EditorWebView = createRef();
export const editorTitleInput = createRef();
@@ -58,7 +59,6 @@ let disableSaving = false;
let isSaving = false;
let waitForContent = false;
let prevNoteContent = null;
let timerForEditor = null;
export function startClosingSession() {
closingSession = true;
@@ -234,6 +234,7 @@ function clearNote() {
type: 'tiny'
};
}
export const loadNote = async item => {
console.log('.....OPEN NOTE.....');
editing.currentlyEditing = true;
@@ -260,12 +261,12 @@ export const loadNote = async item => {
clearNote();
noteEdited = false;
if (Platform.OS === 'android') {
await sleep(300);
await sleep(100);
textInput.current?.focus();
EditorWebView.current?.requestFocus();
tiny.call(EditorWebView, tiny.focusEditor);
} else {
await sleep(150);
await sleep(50);
tiny.call(EditorWebView, tiny.focusEditor);
}
if (EDITOR_SETTINGS) {
@@ -280,7 +281,6 @@ export const loadNote = async item => {
if (!webviewInit) {
EditorWebView.current?.reload();
}
tiny.call(EditorWebView, tiny.notLoading);
checkStatus();
} else {
@@ -351,7 +351,6 @@ export const _onMessage = async evt => {
eSendEvent('historyEvent', message.value);
break;
case 'tiny':
console.log(message.value);
if (message.value === '<br>') return;
if (message.value !== content.data) {
if (prevNoteContent && message.value === prevNoteContent) {
@@ -393,7 +392,7 @@ export const _onMessage = async evt => {
tiny.call(EditorWebView, tiny.notLoading);
setTimeout(() => {
eSendEvent('loadingNote');
}, 150);
},150);
break;
case 'premium':
let user = await db.user.getUser();
@@ -582,7 +581,6 @@ export async function saveNote(preventUpdate) {
try {
if (id && !db.notes.note(id)) {
clearNote();
useEditorStore.getState().setCurrentlyEditingNote(null);
return;
}
let locked = false;
@@ -633,11 +631,8 @@ export async function saveNote(preventUpdate) {
]);
let n = db.notes.note(id)?.data?.dateEdited;
lastEditTime = n + 10;
tiny.call(
EditorWebView,
tiny.updateDateEdited(n ? timeConverter(n) : '')
);
tiny.call(EditorWebView, tiny.updateSavingState(!n ? '' : 'Saved'));
tiny.call(EditorWebView, tiny.updateDateEdited(timeConverter(n)));
tiny.call(EditorWebView, tiny.updateSavingState('Saved'));
}
} catch (e) {
console.log('note save error', e, e.stack);
@@ -651,7 +646,6 @@ export async function onWebViewLoad(premium, colors) {
} else {
tiny.call(EditorWebView, tiny.removeMarkdown, true);
}
if (getNote()?.id) {
loadNoteInEditor();
}
@@ -702,18 +696,17 @@ export const presentResolveConflictDialog = _note => {
};
const loadNoteInEditor = async (keepHistory = true) => {
clearTimeout(timerForEditor);
timerForEditor = setTimeout(async () => {
if (!webviewInit) return;
console.log('loading note', id, webviewInit);
console.log('loading note', id, webviewInit);
if (note?.id) {
post('title', title);
intent = false;
if (!content || !content.data || content?.data?.length === 0) {
tiny.call(
EditorWebView,
`
if (!webviewInit) return;
saveCounter = 0;
if (note?.id) {
post('title', title);
intent = false;
if (!content || !content.data || content?.data?.length === 0) {
tiny.call(
EditorWebView,
`
globalThis.isClearingNoteData = false;
window.ReactNativeWebView.postMessage(
JSON.stringify({
@@ -722,30 +715,30 @@ const loadNoteInEditor = async (keepHistory = true) => {
}),
);
`
);
} else {
console.log('opening in editor', content.data);
post('html', content.data);
}
if (id) {
db.attachments.downloadImages(id);
}
setColors();
tiny.call(
EditorWebView,
tiny.updateDateEdited(timeConverter(note.dateEdited))
);
tiny.call(EditorWebView, tiny.updateSavingState('Saved'));
} else {
await restoreEditorState();
console.log('opening in editor');
post('html', content.data);
}
loadingNote = null;
disableSaving = false;
if (keepHistory) {
tiny.call(EditorWebView, tiny.clearHistory);
if (id) {
db.attachments.downloadImages(id);
}
}, 50);
setColors();
tiny.call(
EditorWebView,
tiny.updateDateEdited(timeConverter(note.dateEdited))
);
tiny.call(EditorWebView, tiny.updateSavingState('Saved'));
} else {
await restoreEditorState();
}
await sleep(500);
loadingNote = null;
disableSaving = false;
if (keepHistory) {
tiny.call(EditorWebView, tiny.clearHistory);
}
};
export async function updateNoteInEditor() {

View File

@@ -14,7 +14,6 @@ info = document.querySelector(infoBar);
info.querySelector('#infosaved').innerText = "";
info.querySelector('#infodate').innerText = "";
info.querySelector('#infowords').innerText = ""
updateInfoBar()
document.activeElement.blur();
window.blur();
`;
@@ -73,7 +72,6 @@ const updateDateEdited = value => `
(function() {
info = document.querySelector(infoBar);
info.querySelector('#infodate').innerText = "${value}";
updateInfoBar()
})();
`;
@@ -81,7 +79,6 @@ const updateSavingState = value => `
(function() {
info = document.querySelector(infoBar);
info.querySelector('#infosaved').innerText = "${value}";
updateInfoBar()
})();
`;

View File

@@ -59,7 +59,7 @@ export const IMAGE_TOOLTIP_CONFIG = {
default: null,
type: 'imageoptions',
pageX: 0
};
}
export const TOOLBAR_CONFIG = [
[
@@ -93,7 +93,6 @@ export const TOOLBAR_CONFIG = [
type: 'tooltip',
valueIcon: 'alignleft',
fullname: 'Text Alignment',
premium: true,
group: [
{
format: 'alignleft',
@@ -386,7 +385,7 @@ export const TOOLBAR_CONFIG = [
}
],
[
/* {
/* {
format: 'filepicker',
type: 'format',
fullname: 'Attach file',

View File

@@ -5,7 +5,6 @@ import { ContainerTopSection } from '../../components/Container/ContainerTopSect
import { Header } from '../../components/Header';
import SelectionHeader from '../../components/SelectionHeader';
import SimpleList from '../../components/SimpleList';
import { NotebookHeader } from '../../components/SimpleList/notebook-header';
import {
eSendEvent,
eSubscribeEvent,
@@ -28,7 +27,6 @@ export const Notebook = ({route, navigation}) => {
db.settings.getGroupOptions('topics')
)
);
console.log('params',route?.params.notebook?.topics)
const params = useRef(route?.params);
const onLoad = data => {
@@ -94,13 +92,20 @@ export const Notebook = ({route, navigation}) => {
return (
<>
<SelectionHeader screen="Notebook" />
<ContainerTopSection>
<Header
title={params.current.title}
isBack={!params.current.menu}
screen="Notebook"
action={_onPressBottomButton}
rightButtons={[
{
icon: 'pencil',
title: 'Edit notebook',
func: () =>
eSendEvent(eOpenAddNotebookDialog, params.current.notebook)
}
]}
/>
</ContainerTopSection>
<SimpleList
@@ -118,15 +123,6 @@ export const Notebook = ({route, navigation}) => {
},
icon: 'pencil'
}}
ListHeader={
<NotebookHeader
onEditNotebook={() => {
eSendEvent(eOpenAddNotebookDialog, params.current.notebook);
}}
onPress={_onPressBottomButton}
notebook={params.current.notebook}
/>
}
focused={() => navigation.isFocused()}
placeholderData={{
heading: params.current.notebook.title,

View File

@@ -24,7 +24,7 @@ import {
} from '../../utils/Events';
import {openLinkInBrowser} from '../../utils/functions';
import {tabBarRef} from '../../utils/Refs';
import {getNote} from '../Editor/Functions';
import { getNote } from '../Editor/Functions';
const getNotes = params => {
if (!params) return [];
@@ -170,7 +170,7 @@ export const Notes = ({route, navigation}) => {
eSendEvent(eOnLoadNote, {type: 'new'});
editing.currentlyEditing = true;
editing.movedAway = false;
}
}
tabBarRef.current?.goToPage(1);
} else {
eSendEvent(eOnLoadNote, {type: 'new'});
@@ -190,7 +190,7 @@ export const Notes = ({route, navigation}) => {
onPress: () => {
if (params.current?.type !== 'topic') return;
eSendEvent(eOpenAddTopicDialog, {
notebookId: params.current?.notebookId,
notebookId: params.current?.notebookId,
toEdit: params.current
});
},
@@ -253,10 +253,6 @@ export const Notes = ({route, navigation}) => {
isBack={!params.current?.menu}
screen="NotesPage"
action={_onPressBottomButton}
notebook={
params.current?.notebookId &&
db.notebooks?.notebook(params.current?.notebookId).data
}
rightButtons={
params.current?.type !== 'topic' ? null : headerRightButtons
}