Merge branch 'develop'

This commit is contained in:
ammarahm-ed
2021-12-02 21:10:57 +05:00
18 changed files with 584 additions and 288 deletions

View File

@@ -1,7 +1,9 @@
- Added issue reporting from within the app. Click on "Report an issue" in settings.
- Fixed undo manager not updated on cut.
- Fixed note is not saved when content is directly pasted
- Fixed editor is empty sometimes when note is opened
- Other minor performance improvements
- Add new header for notebook screen & topic
- Ensure that products are loaded before showing pricing
- Show notebook & topic on note items
- Fixed sorting on items in groups
- Fixed editor losing focus in checklists
- Fixed cursor jump to end of paragraph on removing new line
- Minor bug fixes and performance improvements.
Thank you for using Notesnook!

View File

@@ -224,8 +224,16 @@ function setTheme() {
.tox .tox-toolbar__primary {
background: none !important;
border-bottom: 1px solid ${pageTheme.colors.nav} !important;
}`;
}
::selection {
color: white !important;
background: ${pageTheme.colors.accent} !important;
}
`;
let node2 = `
.mce-content-body table[data-mce-selected], {
@@ -254,6 +262,24 @@ function setTheme() {
opacity:0.5;
}
.mce-content-body a {
color: ${pageTheme.colors.accent} !important;
}
.mce-content-body [data-mce-selected="inline-boundary"] {
background-color: ${pageTheme.colors.shade} !important;
}
::selection {
color: white !important;
background: ${pageTheme.colors.accent} !important;
}
.mce-content-body a[data-mce-selected] {
box-shadow: none !important;
}
span.attachment {
overflow: hidden;
position: relative;

View File

@@ -4,70 +4,75 @@ body {
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: 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%;
.app-main {
overflow: visible;
}
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 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:0px;
padding-bottom:0px;
}
#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: 14px !important;
justify-content: space-between;
margin-top: 0px;
}
.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;
}
.info-bar a {
text-decoration: none;

View File

@@ -136,6 +136,7 @@ function init_tiny(size) {
'media imagetools table paste wordcount autoresize directionality blockescape contenthandler'
],
toolbar: false,
keep_styles:false,
paste_data_images: true,
statusbar: false,
textpattern_patterns: markdownPatterns,
@@ -263,6 +264,104 @@ 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) {
if (globalThis.isClearingNoteData) {
globalThis.isClearingNoteData = false;
return;
}
setTimeout(function () {
editor.undoManager.transact(function () {});
}, 1000);
if (!event.paste) {
reactNativeEventHandler('noteLoaded', true);
}
});
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', {

View File

@@ -1118,7 +1118,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1670;
CURRENT_PROJECT_VERSION = 1680;
DEVELOPMENT_TEAM = 53CWBG3QUC;
ENABLE_BITCODE = NO;
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
@@ -1191,7 +1191,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.6.70;
MARKETING_VERSION = 1.6.80;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
@@ -1219,7 +1219,7 @@
CODE_SIGN_ENTITLEMENTS = Notesnook/Notesnook.entitlements;
CODE_SIGN_IDENTITY = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 1670;
CURRENT_PROJECT_VERSION = 1680;
DEVELOPMENT_TEAM = 53CWBG3QUC;
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
HEADER_SEARCH_PATHS = (
@@ -1291,7 +1291,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.6.70;
MARKETING_VERSION = 1.6.80;
ONLY_ACTIVE_ARCH = NO;
OTHER_LDFLAGS = (
"$(inherited)",
@@ -1449,7 +1449,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1670;
CURRENT_PROJECT_VERSION = 1680;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = 53CWBG3QUC;
GCC_C_LANGUAGE_STANDARD = gnu11;
@@ -1460,7 +1460,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 1.6.70;
MARKETING_VERSION = 1.6.80;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.notewidget;
@@ -1490,7 +1490,7 @@
CODE_SIGN_IDENTITY = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1670;
CURRENT_PROJECT_VERSION = 1680;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = 53CWBG3QUC;
GCC_C_LANGUAGE_STANDARD = gnu11;
@@ -1501,7 +1501,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 1.6.70;
MARKETING_VERSION = 1.6.80;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.notewidget;
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -1530,7 +1530,7 @@
CODE_SIGN_ENTITLEMENTS = "Make Note/Make Note.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1670;
CURRENT_PROJECT_VERSION = 1680;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = 53CWBG3QUC;
GCC_C_LANGUAGE_STANDARD = gnu11;
@@ -1603,7 +1603,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 1.6.70;
MARKETING_VERSION = 1.6.80;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.share;
@@ -1633,7 +1633,7 @@
CODE_SIGN_IDENTITY = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1670;
CURRENT_PROJECT_VERSION = 1680;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = 53CWBG3QUC;
GCC_C_LANGUAGE_STANDARD = gnu11;
@@ -1706,7 +1706,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 1.6.70;
MARKETING_VERSION = 1.6.80;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.share;
PRODUCT_NAME = "$(TARGET_NAME)";

View File

@@ -1,7 +1,9 @@
- Added issue reporting from within the app. Click on "Report an issue" in settings.
- Fixed undo manager not updated on cut.
- Fixed note is not saved when content is directly pasted
- Fixed editor is empty sometimes when note is opened
- Other minor performance improvements
- Add new header for notebook screen & topic
- Ensure that products are loaded before showing pricing
- Show notebook & topic on note items
- Fixed sorting on items in groups
- Fixed editor losing focus in checklists
- Fixed cursor jump to end of paragraph on removing new line
- Minor bug fixes and performance improvements.
Thank you for using Notesnook!

View File

@@ -1,17 +1,19 @@
import React, {useRef, useState} from 'react';
import {Linking, Platform, Text, TextInput, View} from 'react-native';
import deviceInfoModule from 'react-native-device-info';
import {useTracked} from '../../provider';
import {eSendEvent, ToastEvent} from '../../services/EventManager';
import {APP_VERSION} from '../../utils';
import {db} from '../../utils/database';
import {eCloseProgressDialog} from '../../utils/Events';
import {openLinkInBrowser} from '../../utils/functions';
import {SIZE} from '../../utils/SizeUtils';
import {sleep} from '../../utils/TimeUtils';
import {Button} from '../Button';
import Clipboard from '@react-native-clipboard/clipboard';
import React, { useRef, useState } from 'react';
import { Linking, Platform, Text, TextInput, View } from 'react-native';
import { useTracked } from '../../provider';
import { useUserStore } from '../../provider/stores';
import { eSendEvent, ToastEvent } from '../../services/EventManager';
import PremiumService from '../../services/PremiumService';
import { APP_VERSION } from '../../utils';
import { db } from '../../utils/database';
import { eCloseProgressDialog } from '../../utils/Events';
import { openLinkInBrowser } from '../../utils/functions';
import { SIZE } from '../../utils/SizeUtils';
import { sleep } from '../../utils/TimeUtils';
import { Button } from '../Button';
import DialogHeader from '../Dialog/dialog-header';
import {presentDialog} from '../Dialog/functions';
import { presentDialog } from '../Dialog/functions';
import Seperator from '../Seperator';
import Paragraph from '../Typography/Paragraph';
@@ -20,6 +22,7 @@ export const Issue = () => {
const colors = state.colors;
const body = useRef(null);
const title = useRef(null);
const user = useUserStore(state => state.user);
const [loading, setLoading] = useState(false);
const onPress = async () => {
@@ -30,15 +33,21 @@ export const Issue = () => {
try {
setLoading(true);
let issue_url = await db.debug.report(
title.current,
body.current +
let issue_url = await db.debug.report({
title: title.current,
body:
body.current +
`\n_______________
**Device information:**
App version: ${APP_VERSION}
Platform: ${Platform.OS}
Model: ${Platform.constants.Brand}-${Platform.constants.Model}-${Platform.constants.Version}`
);
Model: ${Platform.constants.Brand}-${Platform.constants.Model}-${
Platform.constants.Version
}
Pro: ${PremiumService.get()}
Logged in: ${user ? 'yes' : 'no'}`,
userId: user?.id
});
setLoading(false);
eSendEvent(eCloseProgressDialog);
await sleep(300);
@@ -55,10 +64,21 @@ Model: ${Platform.constants.Brand}-${Platform.constants.Model}-${Platform.consta
onPress={() => {
Linking.openURL(issue_url);
}}>
{issue_url}
</Text>
{issue_url}.
</Text>{' '}
Please note that we will respond to your issue on the given link. We
recommend that you save it.
</Text>
),
positiveText: 'Copy link',
positivePress: () => {
Clipboard.setString(issue_url);
ToastEvent.show({
heading: 'Issue url copied!',
type: 'success',
context: 'global'
});
},
negativeText: 'Close'
});
} catch (e) {
@@ -141,7 +161,7 @@ For example:
marginTop: 10,
textAlign: 'center'
}}>
The information above will be is publically available on{' '}
The information above will be publically available at{' '}
<Text
onPress={() => {
Linking.openURL('https://github.com/streetwriters/notesnook');
@@ -152,8 +172,8 @@ For example:
}}>
github.com/streetwriters/notesnook.
</Text>{' '}
If you want to ask something general or need some assistance, we would
suggest that you{' '}
If you want to ask something in general or need some assistance, we
would suggest that you{' '}
<Text
style={{
textDecorationLine: 'underline',

View File

@@ -97,64 +97,31 @@ const NoteItem = ({item, isTrash, tags}) => {
flexDirection: 'row',
alignItems: 'center',
zIndex: 10,
elevation: 10
elevation: 10,
marginBottom:2.5
}}>
{!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
title={'#' + db.tags.alias(item)}
key={item}
height={20}
textStyle={{
marginRight: 0,
fontWeight: 'normal',
fontFamily: null
}}
type="grayBg"
fontSize={SIZE.xs + 1}
style={{
borderRadius: 5,
marginRight: 5,
borderWidth: 0.5,
borderColor: colors.icon,
paddingHorizontal: 6,
zIndex: 10
}}
onPress={() => navigateToTag(item)}
/>
))
: null}
{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
}}
style={{
borderRadius: 5,
marginRight: 5,
borderWidth: 0.5,
borderColor: colors.icon,
paddingHorizontal: 6
}}
onPress={() => navigateToTopic(_item.topic)}
/>
))}
</View>
)}
@@ -189,11 +156,21 @@ const NoteItem = ({item, isTrash, tags}) => {
}}>
{!isTrash ? (
<>
{item.conflicted ? (
<Icon
name="alert-circle"
style={{
marginRight: 6
}}
size={SIZE.sm}
color={colors.red}
/>
) : null}
<TimeSince
style={{
fontSize: SIZE.xs + 1,
color: colors.icon,
marginRight: 10
marginRight: 6
}}
time={item.dateCreated}
updateFrequency={
@@ -201,27 +178,26 @@ const NoteItem = ({item, isTrash, tags}) => {
}
/>
{item.color ? (
{/* {db.attachments?.ofNote(item.id)?.length === 0 ? (
<View
key={item}
style={{
width: SIZE.xs,
height: SIZE.xs,
borderRadius: 100,
backgroundColor: COLORS_NOTE[item.color.toLowerCase()],
marginRight: -4.5,
marginRight: 10
}}
/>
) : null}
flexDirection: 'row',
alignItems: 'center',
marginRight: 6
}}>
<Icon name="attachment" size={SIZE.md} color={colors.icon} />
<Paragraph color={colors.icon} size={SIZE.xs + 1}>
10
</Paragraph>
</View>
) : null} */}
{item.pinned ? (
<Icon
style={{marginRight: 10}}
name="pin"
size={SIZE.sm}
style={{
marginRight: 5
marginRight: 6
}}
color={
COLORS_NOTE[item.color?.toLowerCase()] || colors.accent
@@ -231,11 +207,10 @@ const NoteItem = ({item, isTrash, tags}) => {
{item.locked ? (
<Icon
style={{marginRight: 10}}
name="lock"
size={SIZE.sm}
style={{
marginRight: 10
marginRight: 6
}}
color={colors.icon}
/>
@@ -246,35 +221,35 @@ const NoteItem = ({item, isTrash, tags}) => {
name="star"
size={SIZE.md}
style={{
marginRight: 10
marginRight: 6
}}
color="orange"
/>
) : null}
{item.conflicted ? (
<View
style={{
marginRight: 10,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between'
}}>
<Icon
name="alert-circle"
size={SIZE.xs + 1}
color={colors.red}
/>
<Heading
size={SIZE.xs}
style={{
color: colors.red,
marginLeft: 2
}}>
CONFLICTS
</Heading>
</View>
) : null}
{!isTrash && !compactMode && tags
? tags.slice(0, 3)?.map(item => (
<Button
title={'#' + db.tags.alias(item)}
key={item}
height={20}
type="gray"
textStyle={{
textDecorationLine: 'underline'
}}
hitSlop={{top: 8, bottom: 12, left: 0, right: 0}}
fontSize={SIZE.xs + 1}
style={{
borderRadius: 5,
paddingHorizontal: 2,
marginRight: 4,
zIndex: 10,
maxWidth: tags?.slice(0, 3)?.length > 1 ? 130 : null
}}
onPress={() => navigateToTag(item)}
/>
))
: null}
</>
) : (
<>
@@ -282,7 +257,7 @@ const NoteItem = ({item, isTrash, tags}) => {
color={colors.icon}
size={SIZE.xs}
style={{
marginRight: 10
marginRight: 6
}}>
Deleted on{' '}
{item && item.dateDeleted
@@ -294,7 +269,7 @@ const NoteItem = ({item, isTrash, tags}) => {
color={colors.accent}
size={SIZE.xs}
style={{
marginRight: 10
marginRight: 6
}}>
{item.itemType[0].toUpperCase() + item.itemType.slice(1)}
</Paragraph>

View File

@@ -124,9 +124,9 @@ export const NotebookItem = ({item, isTopic = false, notebookID, isTrash}) => {
}}>
<Paragraph
color={colors.accent}
size={SIZE.xs}
size={SIZE.xs + 1}
style={{
marginRight: 10
marginRight: 6
}}>
{isTopic ? 'Topic' : 'Notebook'}
</Paragraph>
@@ -135,20 +135,20 @@ export const NotebookItem = ({item, isTopic = false, notebookID, isTrash}) => {
<>
<Paragraph
color={colors.icon}
size={SIZE.xs}
size={SIZE.xs + 1}
style={{
textAlignVertical: 'center',
marginRight: 10
marginRight: 6
}}>
{'Deleted on ' +
new Date(item.dateDeleted).toISOString().slice(0, 10)}
</Paragraph>
<Paragraph
color={colors.accent}
size={SIZE.xs}
size={SIZE.xs + 1}
style={{
textAlignVertical: 'center',
marginRight: 10
marginRight: 6
}}>
{item.itemType[0].toUpperCase() + item.itemType.slice(1)}
</Paragraph>
@@ -156,18 +156,18 @@ export const NotebookItem = ({item, isTopic = false, notebookID, isTrash}) => {
) : (
<Paragraph
color={colors.icon}
size={SIZE.xs}
size={SIZE.xs + 1}
style={{
marginRight: 10
marginRight: 6
}}>
{new Date(item.dateCreated).toDateString().substring(4)}
</Paragraph>
)}
<Paragraph
color={colors.icon}
size={SIZE.xs}
size={SIZE.xs + 1}
style={{
marginRight: 10
marginRight: 6
}}>
{item && totalNotes > 1
? totalNotes + ' notes'
@@ -178,7 +178,7 @@ export const NotebookItem = ({item, isTopic = false, notebookID, isTrash}) => {
{item.pinned ? (
<Icon
style={{marginRight: 10}}
style={{marginRight: 6}}
name="pin"
size={SIZE.sm}
style={{

View File

@@ -0,0 +1,116 @@
import React, {useState} from 'react';
import {Platform, View} from 'react-native';
import {useTracked} from '../../provider';
import {useMenuStore} from '../../provider/stores';
import {ToastEvent} from '../../services/EventManager';
import {getTotalNotes} from '../../utils';
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 totalNotes = getTotalNotes(notebook);
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
}}>
<Paragraph color={colors.icon} size={SIZE.xs + 1}>
{new Date(notebook.dateEdited).toLocaleString()}
</Paragraph>
<View
style={{
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center'
}}>
<Heading size={SIZE.xxl}>{notebook.title}</Heading>
<View
style={{
flexDirection: 'row'
}}>
<ActionIcon
name={isPinnedToMenu ? 'link-variant-off' : 'link-variant'}
onPress={onPinNotebook}
customStyle={{
marginRight: 15,
width: 40,
height: 40
}}
type={isPinnedToMenu ? 'grayBg' : '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>
)}
<Paragraph
style={{
marginTop: 10,
fontStyle: 'italic',
fontFamily: null
}}
size={SIZE.xs + 1}
color={colors.icon}>
{notebook.topics.length === 1
? '1 topic'
: `${notebook.topics.length} topics`}, {notebook && totalNotes > 1
? totalNotes + ' notes'
: totalNotes === 1
? totalNotes + ' note'
: '0 notes'}
</Paragraph>
</View>
);
};

View File

@@ -66,8 +66,10 @@ class SortDialog extends React.Component {
this.setState({
groupOptions: _groupOptions
});
Navigation.setRoutesToUpdate([this.props.screen]);
eSendEvent('groupOptionsUpdate');
setTimeout(() => {
Navigation.setRoutesToUpdate([this.props.screen]);
eSendEvent('groupOptionsUpdate');
}, 1);
};
render() {
@@ -145,7 +147,11 @@ class SortDialog extends React.Component {
paddingHorizontal: 12
}}>
{this.state.groupOptions.groupBy === 'abc' ? (
<Paragraph color={colors.icon}>
<Paragraph
style={{
height: 40
}}
color={colors.icon}>
No sort options available.
</Paragraph>
) : (
@@ -162,7 +168,6 @@ class SortDialog extends React.Component {
: 'checkbox-blank-circle-outline'
}
textStyle={{
fontWeight: 'normal',
color: colors.pri
}}
fontSize={SIZE.sm}
@@ -183,13 +188,16 @@ class SortDialog extends React.Component {
</View>
<View
style={{
paddingHorizontal: 12
paddingHorizontal: 0,
borderRadius: 0
}}>
{Object.keys(GROUP).map((item, index) => (
<PressableButton
key={item}
testID={'btn-' + item}
type={groupOptions.groupBy === GROUP[item] ? 'shade' : 'gray'}
type={
groupOptions.groupBy === GROUP[item] ? 'transparent' : 'gray'
}
onPress={async () => {
let _groupOptions = {
...groupOptions,
@@ -198,6 +206,7 @@ class SortDialog extends React.Component {
if (item === 'alphabetical') {
_groupOptions.sortBy = 'title';
_groupOptions.sortDirection = 'asc';
} else {
if (this.state.groupOptions.sortBy === 'title') {
_groupOptions.sortBy = 'dateEdited';
@@ -219,8 +228,10 @@ class SortDialog extends React.Component {
<Paragraph
size={SIZE.sm}
style={{
fontWeight:
groupOptions.groupBy === GROUP[item] ? 'bold' : 'normal'
fontFamily:
groupOptions.groupBy === GROUP[item]
? 'OpenSans-SemiBold'
: 'OpenSans-Regular'
}}
color={
groupOptions.groupBy === GROUP[item]
@@ -229,6 +240,7 @@ class SortDialog extends React.Component {
}>
{item.slice(0, 1).toUpperCase() + item.slice(1, item.length)}
</Paragraph>
{groupOptions.groupBy === GROUP[item] ? (
<Icon color={colors.accent} name="check" size={SIZE.lg} />
) : null}

View File

@@ -65,7 +65,7 @@ const TagItem = ({item, index}) => {
</Heading>
<Paragraph
color={colors.icon}
size={SIZE.xs}
size={SIZE.xs + 1}
style={{
marginTop: 5
}}>

View File

@@ -2,7 +2,7 @@ import {Platform} from 'react-native';
import {Dimensions} from 'react-native';
import create from 'zustand';
import PremiumService from '../services/PremiumService';
import {history, SUBSCRIPTION_STATUS} from '../utils';
import {APP_VERSION, history, SUBSCRIPTION_STATUS} from '../utils';
import {db} from '../utils/database';
import {MMKV} from '../utils/mmkv';
import {
@@ -416,6 +416,10 @@ async function shouldShowAnnouncement(announcement) {
platform => allowedPlatforms.indexOf(platform) > -1
);
if (announcement.appVersion) {
return announcement.appVersion === APP_VERSION;
}
if (!show) return false;
const subStatus = PremiumService.getUser()?.subscription?.type;

View File

@@ -1,33 +1,41 @@
export const sleep = (duration) =>
new Promise((resolve) => setTimeout(() => resolve(), duration));
export function timeSince(date) {
let seconds = Math.floor((new Date() - date) / 1000);
seconds = seconds + (86400 * 7 * 4);
let interval = Math.floor(seconds / 31536000);
if (interval > 0.9) {
return interval < 2 ? interval + ' year ago' : interval + ' years ago';
return interval < 2 ? interval + 'yr ago' : interval + 'yr ago';
}
interval = Math.floor(seconds / 2592000);
if (interval > 0.9) {
return interval < 2 ? interval + ' month ago' : interval + ' months ago';
return interval < 2 ? interval + 'mo ago' : interval + 'mo ago';
}
interval = Math.floor(seconds / (86400 * 7));
if (interval > 0.9) {
if (interval === 4) return "1mo ago";
return interval < 2 ? interval + 'w ago' : interval + 'w ago';
}
interval = Math.floor(seconds / 86400);
if (interval > 0.9) {
return interval < 2 ? interval + ' day ago' : interval + ' days ago';
return interval < 2 ? interval + 'd ago' : interval + 'd ago';
}
interval = Math.floor(seconds / 3600);
if (interval > 0.9) {
return interval < 2 ? interval + ' hour ago' : interval + ' hours ago';
return interval < 2 ? interval + 'h ago' : interval + 'h ago';
}
interval = Math.floor(seconds / 60);
if (interval > 0.9) {
return interval < 2 ? interval + ' min ago' : interval + ' min ago';
return interval < 2 ? interval + 'm ago' : interval + 'm ago';
}
return Math.floor(seconds) < 0
? '0 secs ago'
: Math.floor(seconds) + ' secs ago';
? '0s ago'
: Math.floor(seconds) + 's ago';
}
export const timeConverter = (timestamp) => {

View File

@@ -16,7 +16,7 @@ import {MMKV} from './mmkv';
import {tabBarRef} from './Refs';
import {SIZE} from './SizeUtils';
export const APP_VERSION = 1670;
export const APP_VERSION = 1680;
export const Tracker = ackeeTracker.create('https://sa.streetwriters.co', {
ignoreLocalhost: true

View File

@@ -27,7 +27,6 @@ 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 {parse} from 'node-html-parser';
export let EditorWebView = createRef();
export const editorTitleInput = createRef();
@@ -136,14 +135,11 @@ export async function clearTimer(clear) {
}
export const CHECK_STATUS = `(function() {
setTimeout(() => {
let msg = JSON.stringify({
data: true,
type: 'running',
});
window.ReactNativeWebView.postMessage(msg)
},${Platform.OS === 'ios' ? '300' : '1'})
})();`;
const request_content = `(function() {
@@ -285,27 +281,29 @@ export const loadNote = async item => {
checkStatus();
} else {
if (id === item.id && !item.forced) {
console.log('return from here duhh.');
return;
}
eSendEvent('loadingNote', item);
if (getNote()) {
console.log('clearing');
await clearEditor(true, false, true);
}
console.log('done clearing');
closingSession = false;
disableSaving = false;
noteEdited = false;
await setNote(item);
webviewInit = false;
editing.isFocused = false;
console.log('opening note');
setTimeout(async () => {
if (await checkStatus(true)) {
requestedReload = true;
EditorWebView.current?.reload();
} else {
eSendEvent('webviewreset');
}
requestedReload = true;
EditorWebView.current?.reload();
}, 1);
useEditorStore.getState().setCurrentlyEditingNote(item.id);
setTimeout(() => {
useEditorStore.getState().setCurrentlyEditingNote(item.id);
}, 300);
}
};
@@ -323,9 +321,15 @@ const checkStatus = async noreset => {
eUnSubscribeEvent('webviewOk', onWebviewOk);
};
eSubscribeEvent('webviewOk', onWebviewOk);
EditorWebView.current?.injectJavaScript(CHECK_STATUS);
setTimeout(
() => {
EditorWebView.current?.injectJavaScript(CHECK_STATUS);
},
Platform.OS === 'ios' ? 300 : 1
);
webviewTimer = setTimeout(() => {
console.log('timeout has ended');
if (!webviewOK && !noreset) {
console.log('webview not ok', 'ERROR');
webviewInit = false;
@@ -411,6 +415,7 @@ export const _onMessage = async evt => {
if (!requestedReload && getNote()) return;
requestedReload = false;
setColors(COLOR_SCHEME);
eSendEvent('webviewOk');
webviewInit = true;
webviewOK = true;
if (PremiumService.get()) {
@@ -715,6 +720,18 @@ const loadNoteInEditor = async (keepHistory = true) => {
}),
);
`
);
} else {
post('html', content.data);
}
if (id) {
db.attachments.downloadImages(id);
}
setColors();
tiny.call(
EditorWebView,
tiny.updateDateEdited(timeConverter(note.dateEdited))
);
} else {
console.log('opening in editor');

View File

@@ -2,7 +2,7 @@ import React, {useEffect, useRef, useState} from 'react';
import {TextInput, View} from 'react-native';
import {Button} from '../../../../components/Button';
import {useTracked} from '../../../../provider';
import {eSendEvent} from '../../../../services/EventManager';
import {eSendEvent, ToastEvent} from '../../../../services/EventManager';
import {editing} from '../../../../utils';
import {normalize, SIZE} from '../../../../utils/SizeUtils';
import {EditorWebView} from '../../Functions';
@@ -15,6 +15,7 @@ import {
properties
} from './constants';
import LinkPreview from './linkpreview';
import validator from 'validator';
let inputValue = null;
@@ -36,11 +37,6 @@ const ToolbarLinkInput = ({format, value, setVisible}) => {
properties.inputMode = value ? INPUT_MODE.NO_EDIT : INPUT_MODE.EDITING;
editing.tooltip = format;
properties.userBlur = false;
if (properties.pauseSelectionChange) {
setTimeout(() => {
properties.pauseSelectionChange = false;
}, 100);
}
return () => {
properties.inputMode = null;
editing.tooltip = null;
@@ -53,10 +49,16 @@ const ToolbarLinkInput = ({format, value, setVisible}) => {
if (properties.pauseSelectionChange) {
setTimeout(() => {
properties.pauseSelectionChange = false;
}, 100);
}, 1000);
}
inputRef.current?.focus();
return;
} else {
if (properties.pauseSelectionChange) {
setTimeout(() => {
properties.pauseSelectionChange = false;
}, 1000);
}
}
}, [mode]);
@@ -68,11 +70,21 @@ const ToolbarLinkInput = ({format, value, setVisible}) => {
if (value === 'clear') {
inputValue = null;
}
properties.userBlur = true;
if (inputValue === '' || !inputValue) {
properties.userBlur = true;
formatSelection(execCommands.unlink);
setVisible(false);
} else {
if (!inputValue.includes('://')) inputValue = 'https://' + inputValue;
if (!validator.isURL(inputValue)) {
ToastEvent.show({
heading: 'Invalid url',
message: 'Please enter a valid url',
type: 'error'
});
return;
}
properties.userBlur = true;
formatSelection(execCommands[format](inputValue));
}
@@ -115,8 +127,8 @@ const ToolbarLinkInput = ({format, value, setVisible}) => {
flexWrap: 'wrap',
fontSize: SIZE.sm,
flexShrink: 1,
minWidth:'80%',
fontFamily:"OpenSans-Regular"
minWidth: '80%',
fontFamily: 'OpenSans-Regular'
}}
autoCapitalize="none"
autoCorrect={false}

View File

@@ -1,14 +1,14 @@
import { getLinkPreview } from 'link-preview-js';
import React, { useEffect, useState } from 'react';
import { Image, ScrollView, TouchableOpacity, View } from 'react-native';
import {getLinkPreview} from 'link-preview-js';
import React, {useEffect, useState} from 'react';
import {Image, ScrollView, TouchableOpacity, View} from 'react-native';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import { ActionIcon } from '../../../../components/ActionIcon';
import {ActionIcon} from '../../../../components/ActionIcon';
import Heading from '../../../../components/Typography/Heading';
import Paragraph from '../../../../components/Typography/Paragraph';
import { useTracked } from '../../../../provider';
import { openLinkInBrowser } from '../../../../utils/functions';
import { SIZE } from '../../../../utils/SizeUtils';
import { INPUT_MODE, properties, reFocusEditor } from './constants';
import {useTracked} from '../../../../provider';
import {openLinkInBrowser} from '../../../../utils/functions';
import {SIZE} from '../../../../utils/SizeUtils';
import {INPUT_MODE, properties, reFocusEditor} from './constants';
let prevLink = {};
let prevHeight = 50;
@@ -21,9 +21,8 @@ const LinkPreview = ({setMode, value, onSubmit}) => {
useEffect(() => {
console.log('previewing', value);
if (value && prevLink.value !== value) {
getLinkPreview(value)
.then((r) => {
.then(r => {
if (r.contentType?.includes('text/html')) {
prevLink = {
value: value,
@@ -31,12 +30,12 @@ const LinkPreview = ({setMode, value, onSubmit}) => {
title: r.title,
description: r.description,
image: r.images[0],
favicon: r.favicons[0],
favicon: r.favicons[0]
};
setLink(prevLink);
}
})
.catch((e) => console.log);
.catch(e => console.log);
}
}, [value]);
@@ -50,9 +49,9 @@ const LinkPreview = ({setMode, value, onSubmit}) => {
marginVertical: 5,
borderWidth: 1,
borderColor: colors.nav,
backgroundColor: colors.nav,
backgroundColor: colors.nav
}}
resizeMode="center"
resizeMode="contain"
source={{uri: imageLink}}
/>
) : faviconLink ? (
@@ -62,12 +61,12 @@ const LinkPreview = ({setMode, value, onSubmit}) => {
backgroundColor: colors.nav,
borderWidth: 1,
marginVertical: 5,
borderRadius: 5,
borderRadius: 5
}}>
<Image
style={{
width: height,
height: height,
height: height
}}
resizeMode="center"
source={{uri: faviconLink}}
@@ -82,7 +81,7 @@ const LinkPreview = ({setMode, value, onSubmit}) => {
justifyContent: 'center',
alignItems: 'center',
backgroundColor: colors.shade,
borderRadius: 5,
borderRadius: 5
}}>
<Icon size={height - 4} color={colors.accent} name="web" />
</View>
@@ -91,8 +90,8 @@ const LinkPreview = ({setMode, value, onSubmit}) => {
const openLink = () => {
openLinkInBrowser(value, colors)
.catch((e) => {})
.then(async (r) => {
.catch(e => {})
.then(async r => {
console.log('closed browser now');
await reFocusEditor();
});
@@ -101,17 +100,17 @@ const LinkPreview = ({setMode, value, onSubmit}) => {
const renderText = (name, title, description) => {
return (
<View
onLayout={(e) => {
onLayout={e => {
prevHeight = e.nativeEvent.layout.height;
e.nativeEvent && setHeight(prevHeight);
}}
style={{
flex: 1,
flex: 1
}}>
<TouchableOpacity onPress={openLink} activeOpacity={1}>
<ScrollView
style={{
marginRight: 10,
marginRight: 10
}}
horizontal
showsHorizontalScrollIndicator={false}>
@@ -142,7 +141,7 @@ const LinkPreview = ({setMode, value, onSubmit}) => {
<View
style={{
flexDirection: 'row',
alignItems: 'center',
alignItems: 'center'
}}>
<ActionIcon
onPress={() => {
@@ -150,10 +149,10 @@ const LinkPreview = ({setMode, value, onSubmit}) => {
}}
customStyle={{
width: 40,
marginHorizontal: 10,
height: 40,
marginRight: 10,
height: 40
}}
name="delete"
name="link-off"
size={SIZE.xl}
color={colors.pri}
/>
@@ -165,8 +164,7 @@ const LinkPreview = ({setMode, value, onSubmit}) => {
}}
customStyle={{
width: 40,
marginHorizontal: 10,
height: 40,
height: 40
}}
name="pencil"
size={SIZE.xl}