Compare commits
139 Commits
v2.4.6
...
fix/sync-q
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2febd09613 | ||
|
|
91138f4911 | ||
|
|
f9bcfe2f7a | ||
|
|
3621f95dbc | ||
|
|
536dead44d | ||
|
|
39d74e80a9 | ||
|
|
46e03dd248 | ||
|
|
152fee2c29 | ||
|
|
492a4d16b2 | ||
|
|
3d7c1fa1e7 | ||
|
|
8a138d960d | ||
|
|
69bb0e3656 | ||
|
|
4875cfa108 | ||
|
|
a28beb62c6 | ||
|
|
21c8960146 | ||
|
|
59442b9107 | ||
|
|
2ba638b123 | ||
|
|
8548940cb9 | ||
|
|
909bdfa0cf | ||
|
|
bfb3c56abe | ||
|
|
e06836f701 | ||
|
|
bc16cb79f2 | ||
|
|
176c46e3f2 | ||
|
|
af65055ce9 | ||
|
|
ad23ff19de | ||
|
|
cf65fc4f57 | ||
|
|
9ab83e7fbb | ||
|
|
1acf2aadba | ||
|
|
06833bcac9 | ||
|
|
3bf6b5293a | ||
|
|
c40d33df37 | ||
|
|
fe609f8275 | ||
|
|
3566f47f2d | ||
|
|
4b5526dffd | ||
|
|
4977390394 | ||
|
|
87804de452 | ||
|
|
bc55d2b476 | ||
|
|
3ff34a5c82 | ||
|
|
7e01e90e22 | ||
|
|
d568be6536 | ||
|
|
734e79604f | ||
|
|
227a962042 | ||
|
|
a1640175e5 | ||
|
|
7cf61570ef | ||
|
|
83762c668e | ||
|
|
ecd4a08b1c | ||
|
|
7b66462300 | ||
|
|
41639fd325 | ||
|
|
2fe82841ef | ||
|
|
9b7af87611 | ||
|
|
d99ccbc243 | ||
|
|
0f191eba5c | ||
|
|
26657c7ee3 | ||
|
|
a12749eb82 | ||
|
|
1a56d38116 | ||
|
|
0b9025af11 | ||
|
|
6f5a44cd11 | ||
|
|
5e1cc307b1 | ||
|
|
2197f1ec5e | ||
|
|
1da5fd3661 | ||
|
|
49e79b52b2 | ||
|
|
c9a657298c | ||
|
|
cfd7caf16c | ||
|
|
9744679550 | ||
|
|
9cdc502ce5 | ||
|
|
300a104949 | ||
|
|
efad6520a2 | ||
|
|
cc58351731 | ||
|
|
cf2f4c4bbb | ||
|
|
cc161b844c | ||
|
|
45ebf0670f | ||
|
|
9cfaa90232 | ||
|
|
edf4a248ed | ||
|
|
14d7ec6b4e | ||
|
|
cd2ca94c3d | ||
|
|
f1609aaa46 | ||
|
|
851364c0bf | ||
|
|
913a1743b5 | ||
|
|
dc5572d4b9 | ||
|
|
554560903c | ||
|
|
885e4a325c | ||
|
|
156ce7e711 | ||
|
|
71ecc05bd6 | ||
|
|
98b93d42c1 | ||
|
|
2e7935cacc | ||
|
|
50d64af7f6 | ||
|
|
e452fd3d2f | ||
|
|
64dd481402 | ||
|
|
28f647fa06 | ||
|
|
9eb1061cd1 | ||
|
|
3cab264213 | ||
|
|
fb56e7c866 | ||
|
|
234e368c4d | ||
|
|
4de4693505 | ||
|
|
5563c7d5f8 | ||
|
|
93225e5a30 | ||
|
|
0ab9846732 | ||
|
|
f6f1cf0ae7 | ||
|
|
69615d54db | ||
|
|
a990d0f404 | ||
|
|
4aeff48e74 | ||
|
|
78c1a75ec9 | ||
|
|
9e6664a80e | ||
|
|
b306a09747 | ||
|
|
fab52012ad | ||
|
|
fc39c714b6 | ||
|
|
5fff4bbb0e | ||
|
|
0a29571ad8 | ||
|
|
275fa1b3ca | ||
|
|
79889665e5 | ||
|
|
9888ad327c | ||
|
|
77ab2d7740 | ||
|
|
509dc4b541 | ||
|
|
ff84ee2d42 | ||
|
|
d838c2e8ad | ||
|
|
28d718acf6 | ||
|
|
adf546f29c | ||
|
|
b18cf277f6 | ||
|
|
8ab26eb852 | ||
|
|
aac43274a0 | ||
|
|
2fb2c4247a | ||
|
|
cb1d32d177 | ||
|
|
75e1985a6f | ||
|
|
0093b39f64 | ||
|
|
d19c2ef735 | ||
|
|
db527cfbf3 | ||
|
|
7da8ddb24f | ||
|
|
5d401ac9ac | ||
|
|
9605eafa00 | ||
|
|
783460c685 | ||
|
|
af906d8ace | ||
|
|
fca26a8793 | ||
|
|
27863def9c | ||
|
|
f1d4fd1d5d | ||
|
|
61b7e43d08 | ||
|
|
87ebe1918c | ||
|
|
4c5253c267 | ||
|
|
df94f31998 | ||
|
|
aec1d601a3 |
@@ -8,9 +8,9 @@ Thank you so much for considering to contribute to Notesnook! If you have no ide
|
||||
|
||||
Ugh! Bugs!
|
||||
|
||||
> A bug is when software behaves in a way that you didn't expect, and the developer didn't intend.
|
||||
> A bug is when software behaves in a way you didn't expect, which the developer didn't intend.
|
||||
|
||||
To help us understand what's going on, we first want to **make sure you're using the latest version of Notesnook**.
|
||||
To help us understand what's happening, we first want to **make sure you're using the latest version of Notesnook**.
|
||||
|
||||
Once you've **confirmed that the bug still exists in the latest version**, you'll want to check to make sure it's not something we already know about in the [opened GitHub issues](https://github.com/streetwriters/notesnook/issues).
|
||||
|
||||
@@ -30,7 +30,7 @@ Before you open a new feature request, please make sure it's not a duplicate. **
|
||||
|
||||
### Helping out in the issue tracker
|
||||
|
||||
There are always new issues getting opened that need to be triaged, sorted & organized, so the developers can easily find the most critical and/or relevant bugs to fix. Any help in this regard is appreciated.
|
||||
New issues are always opened that need to be triaged, sorted & organized, so the developers can easily find the most critical and/or relevant bugs to fix. Any help in this regard is appreciated.
|
||||
|
||||
In addition to this, you can help out in the following ways:
|
||||
|
||||
@@ -62,7 +62,7 @@ Once you are done, [open a new pull request](https://docs.github.com/en/pull-req
|
||||
|
||||
1. Fork [the repository](https://github.com/streetwriters/notesnook) and create your branch from `master` (you can name your branch anything).
|
||||
2. Run `npm run bootstrap` in the repository root.
|
||||
3. If you’ve fixed a bug or added code that should be tested, add tests!
|
||||
3. If you've fixed a bug or added code that should be tested, add tests!
|
||||
4. Ensure the test suite passes (`npm run test`).
|
||||
5. Format your code with prettier (`npm run prettier`).
|
||||
6. Make sure your code lints (`npm run lint`). Tip: `npm run linc` to only check changed files.
|
||||
@@ -131,11 +131,11 @@ We use an automatic code formatter called [Prettier](https://prettier.io/). Run
|
||||
|
||||
Then, our linter will catch most issues that may exist in your code. You can check the status of your code styling by simply running `npm run lint`.
|
||||
|
||||
However, there are still some styles that the linter cannot pick up. If you are unsure about something, looking at [Airbnb’s Style Guide](https://github.com/airbnb/javascript) will guide you in the right direction.
|
||||
However, there are still some styles that the linter cannot pick up. If you are unsure about something, looking at [Airbnb's Style Guide](https://github.com/airbnb/javascript) will guide you in the right direction.
|
||||
|
||||
## Git Branch Organization
|
||||
|
||||
Submit all changes directly to the [`master branch`](https://github.com/streetwriters/notesnook). We don’t use separate branches for development or for upcoming releases. This requires us to always keep the `master` branch in a deployable state which means:
|
||||
Submit all changes directly to the [`master branch`](https://github.com/streetwriters/notesnook). We don't use separate branches for development or for upcoming releases. This requires us to always keep the `master` branch in a deployable state which means:
|
||||
|
||||
1. All tests must be passing at all times
|
||||
2. There should be as few breaking changes as possible
|
||||
|
||||
@@ -10,11 +10,11 @@
|
||||
|
||||
## Overview
|
||||
|
||||
Notesnook is a free (as in speech) & open source note taking app focused on user privacy & ease of use. To ensure zero knowledge principles, Notesnook encrypts everything on your device using `XChaCha20-Poly1305` & `Argon2`.
|
||||
Notesnook is a free (as in speech) & open-source note-taking app focused on user privacy & ease of use. To ensure zero knowledge principles, Notesnook encrypts everything on your device using `XChaCha20-Poly1305` & `Argon2`.
|
||||
|
||||
Notesnook is our **proof** that privacy does _not_ (always) have to come at the cost of convenience. Our goal is to provide users peace of mind & 100% confidence that their notes are safe and secure. The decision to go fully open source is one of the most crucial steps towards that.
|
||||
Notesnook is our **proof** that privacy does _not_ (always) have to come at the cost of convenience. We aim to provide users peace of mind & 100% confidence that their notes are safe and secure. The decision to go fully open source is one of the most crucial steps towards that.
|
||||
|
||||
This repository contains all the code required to build & use the Notesnook web, desktop & mobile clients. If you are looking for a full features list or screenshots, please check the [website](https://notesnook.com/).
|
||||
This repository contains all the code required to build & use the Notesnook web, desktop & mobile clients. If you are looking for a full feature list or screenshots, please check the [website](https://notesnook.com/).
|
||||
|
||||
## Developer guide
|
||||
|
||||
|
||||
@@ -19,9 +19,9 @@
|
||||
|
||||
## Build instructions
|
||||
|
||||
> **Before you start it is recommended that you read [the contributing guidelines](/CONTRIBUTING.md).**
|
||||
> **Before you start, it is recommended that you read [the contributing guidelines](/CONTRIBUTING.md).**
|
||||
|
||||
### Setting up development environment
|
||||
### Setting up the development environment
|
||||
|
||||
Requirements:
|
||||
|
||||
@@ -57,7 +57,7 @@ npm install
|
||||
|
||||
### Running the app on Android
|
||||
|
||||
[Setup an Android emulator from Android Studio](https://developer.android.com/studio/run/managing-avds) if you haven't already and then run the following command to start the app in the Emulator:
|
||||
[Setup an Android emulator from Android Studio](https://developer.android.com/studio/run/managing-avds) if you haven't already, and then run the following command to start the app in the Emulator:
|
||||
|
||||
```bash
|
||||
npm run start:android
|
||||
@@ -78,11 +78,11 @@ npm run start:ios
|
||||
|
||||
## Developer guide
|
||||
|
||||
> This project is in a transition state between Javascript & Typescript. We are gradually porting everything over to Typescript so if you can help with that, it'd be great!
|
||||
> This project is in a transition state between Javascript & Typescript. We are gradually porting everything over to Typescript, so if you can help with that, it'd be great!
|
||||
|
||||
### The tech stack
|
||||
|
||||
We try to keep the stack as lean as possible
|
||||
We try to keep the stack as lean as possible:
|
||||
|
||||
1. React Native
|
||||
2. Typescript/Javascript
|
||||
@@ -95,17 +95,17 @@ We try to keep the stack as lean as possible
|
||||
|
||||
The app codebase is distributed over two primary directories. `native/` and `app/`.
|
||||
|
||||
- `native/`: Includes `android/` and `ios/` folders and everything related to react native core functionality like bundling, development and packaging. Any react-native dependency that has native code i.e android & ios folders, is installed here.
|
||||
- `native/`: Includes `android/` and `ios/` folders and everything related to react native core functionality like bundling, development, and packaging. Any react-native dependency with native code, i.e., android & ios folders, is installed here.
|
||||
|
||||
- `app/`: Includes all the app code other than the native part. All JS only dependencies are installed here.
|
||||
- `components/`: Each component serves a specific purpose in the app UI, for example the `Paragraph` component is used to render paragraphs in the app and a `Header` component is used to render a `header` on all screens.
|
||||
- `common/`: Features that have integral role in app functionality, for example, notesnook core is initialized here.
|
||||
- `app/`: Includes all the app code other than the native part. All JS-only dependencies are installed here.
|
||||
- `components/`: Each component serves a specific purpose in the app UI. For example, the `Paragraph` component is used to render paragraphs in the app, and a `Header` component is used to render a `header` on all screens.
|
||||
- `common/`: Features that are integral to the app's functionality. For example, the notesnook core is initialized here.
|
||||
- `hooks/`: Hooks for different app logic
|
||||
- `navigation/`: Includes app navigation specific code. Here the app navigation, editor & side menu are rendered side by side in fluid tabs.
|
||||
- `navigation/`: Includes app navigation-specific code. Here the app navigation, editor & side menu are rendered side by side in fluid tabs.
|
||||
- `screens`: Navigator screens.
|
||||
- `services`: Parts of code that do a specific function, for example, the `sync` service is responsibe for running Sync from anywhere in the app.
|
||||
- `stores`: We use `zustand` for global state management in the app. There are multiple stores that provide the state for different parts of the app.
|
||||
- `utils`: General purpose stuff such as constant values, utility functions etc.
|
||||
- `services`: Parts of code that do a specific function. For example, the `sync` service runs Sync from anywhere in the app.
|
||||
- `stores`: We use `zustand` for global state management in the app. Multiple stores provide the state for different parts of the app.
|
||||
- `utils`: General purpose stuff such as constant values, utility functions, etc.
|
||||
|
||||
There are several other folders at the root:
|
||||
|
||||
@@ -115,11 +115,11 @@ There are several other folders at the root:
|
||||
|
||||
### Running the tests
|
||||
|
||||
When you are done making the required changes, you will need to run the tests to make sure you didn't break anything. We use Detox as the testing framework & the tests can be started as follows:
|
||||
When you are done making the required changes, you must run the tests to ensure you didn't break anything. We use Detox as the testing framework & the tests can be started as follows:
|
||||
|
||||
### Android
|
||||
|
||||
To run the tests on android, you will need to create an emulator device on your system:
|
||||
To run the tests on Android, you will need to create an emulator device on your system:
|
||||
|
||||
```
|
||||
$ANDROID_HOME/tools/bin/avdmanager create avd -n Pixel_5_API_31 -d pixel --package "system-images;android-31;default;x86_64"
|
||||
@@ -127,13 +127,13 @@ $ANDROID_HOME/tools/bin/avdmanager create avd -n Pixel_5_API_31 -d pixel --packa
|
||||
|
||||
If you face problems, follow the detailed guide in [Detox documentation](https://wix.github.io/Detox/docs/introduction/android-dev-env). Keep the emulator name set to `Pixel_5_API_31`.
|
||||
|
||||
Once you have created an emulator device, build the android apks
|
||||
Once you have created an emulator device, build the Android apks:
|
||||
|
||||
```
|
||||
npm run build:android
|
||||
```
|
||||
|
||||
Finally run the tests
|
||||
Finally, run the tests:
|
||||
|
||||
```
|
||||
npm run test:android
|
||||
@@ -141,9 +141,9 @@ npm run test:android
|
||||
|
||||
### iOS
|
||||
|
||||
To run e2e tests on iOS simulator, you must be on a Mac with XCode installed.
|
||||
To run e2e tests on the iOS simulator, you must be on a Mac with XCode installed.
|
||||
|
||||
First install [AppleSimulatorUtils](https://github.com/wix/AppleSimulatorUtils)
|
||||
First, install [AppleSimulatorUtils](https://github.com/wix/AppleSimulatorUtils):
|
||||
|
||||
```
|
||||
brew tap wix/brew
|
||||
@@ -156,7 +156,7 @@ Now build the iOS app for testing:
|
||||
npm run build:ios
|
||||
```
|
||||
|
||||
Finally run the tests:
|
||||
Finally, run the tests:
|
||||
|
||||
```
|
||||
npm run test:ios
|
||||
|
||||
BIN
apps/mobile/app/assets/images/notesnook-dark.png
Normal file
|
After Width: | Height: | Size: 38 KiB |
@@ -68,14 +68,3 @@ db.host(
|
||||
ISSUES_HOST: "https://issues.streetwriters.co"
|
||||
}
|
||||
);
|
||||
|
||||
export async function loadDatabase() {
|
||||
// if (!DB) {
|
||||
// let module = await import(/* webpackChunkName: "notes-core" */ 'notes-core/api/index');
|
||||
// DB = module.default;
|
||||
// }
|
||||
// db = new DB(Storage, Platform.OS === 'ios' ? EventSource : AndroidEventSource, filesystem);
|
||||
// if (DOMParser) {
|
||||
// await DOMParser.prepare();
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -36,7 +36,11 @@ function getFileExtension(filename) {
|
||||
var ext = /^.+\.([^.]+)$/.exec(filename);
|
||||
return ext == null ? "" : ext[1];
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {any} param0
|
||||
* @returns
|
||||
*/
|
||||
export const AttachmentItem = ({ attachment, encryption, setAttachments }) => {
|
||||
const colors = useThemeStore((state) => state.colors);
|
||||
const [currentProgress, setCurrentProgress] = useAttachmentProgress(
|
||||
|
||||
@@ -44,8 +44,10 @@ import Paragraph from "../ui/typography/paragraph";
|
||||
import { LoginSteps, useLogin } from "./use-login";
|
||||
|
||||
function getObfuscatedEmail(email) {
|
||||
if (!email) return null;
|
||||
return email.replace(/(.{2})(.*)(?=@)/, function (gp1, gp2, gp3) {
|
||||
if (!email) return "";
|
||||
const [username, provider] = email.split("@");
|
||||
if (username.length === 1) return `****@${provider}`;
|
||||
return email.replace(/(.{1})(.*)(?=@)/, function (gp1, gp2, gp3) {
|
||||
for (let i = 0; i < gp3.length; i++) {
|
||||
gp2 += "*";
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import { View } from "react-native";
|
||||
|
||||
import { useMenuStore } from "../../../stores/use-menu-store";
|
||||
import {
|
||||
eSendEvent,
|
||||
eSubscribeEvent,
|
||||
eUnSubscribeEvent,
|
||||
ToastEvent
|
||||
@@ -30,6 +31,7 @@ import Navigation from "../../../services/navigation";
|
||||
import { db } from "../../../common/database";
|
||||
import {
|
||||
eCloseAddTopicDialog,
|
||||
eOnTopicSheetUpdate,
|
||||
eOpenAddTopicDialog
|
||||
} from "../../../utils/events";
|
||||
import { sleep } from "../../../utils/time";
|
||||
@@ -40,6 +42,7 @@ import DialogHeader from "../../dialog/dialog-header";
|
||||
import Input from "../../ui/input";
|
||||
import Seperator from "../../ui/seperator";
|
||||
import { Toast } from "../../toast";
|
||||
import { useRelationStore } from "../../../stores/use-relation-store";
|
||||
|
||||
export class AddTopicDialog extends React.Component {
|
||||
constructor(props) {
|
||||
@@ -78,9 +81,11 @@ export class AddTopicDialog extends React.Component {
|
||||
}
|
||||
this.close();
|
||||
setTimeout(() => {
|
||||
Navigation.queueRoutesForUpdate("Notebooks", "Notebook", "TopicNotes");
|
||||
Navigation.queueRoutesForUpdate();
|
||||
useMenuStore.getState().setMenuPins();
|
||||
});
|
||||
eSendEvent(eOnTopicSheetUpdate);
|
||||
useRelationStore.getState().update();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
@@ -207,13 +207,7 @@ export class VaultDialog extends Component {
|
||||
return;
|
||||
}
|
||||
|
||||
Navigation.queueRoutesForUpdate(
|
||||
"Notes",
|
||||
"Favorites",
|
||||
"TopicNotes",
|
||||
"TaggedNotes",
|
||||
"ColoredNotes"
|
||||
);
|
||||
Navigation.queueRoutesForUpdate();
|
||||
|
||||
this.password = null;
|
||||
this.confirmPassword = null;
|
||||
|
||||
@@ -109,7 +109,7 @@ export const Title = () => {
|
||||
{!hide && !isHidden ? (
|
||||
<Heading
|
||||
onPress={navigateToNotebook}
|
||||
numberOfLines={isTopic ? 2 : 1}
|
||||
numberOfLines={1}
|
||||
size={SIZE.xl}
|
||||
style={{
|
||||
flexWrap: "wrap",
|
||||
|
||||
@@ -17,12 +17,14 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import notifee from "@notifee/react-native";
|
||||
import React, { useCallback, useEffect, useRef } from "react";
|
||||
import { Platform, View } from "react-native";
|
||||
import RNBootSplash from "react-native-bootsplash";
|
||||
import { checkVersion } from "react-native-check-version";
|
||||
import Config from "react-native-config";
|
||||
import { enabled } from "react-native-privacy-snapshot";
|
||||
import { DatabaseLogger, db, loadDatabase } from "../../common/database";
|
||||
import { DatabaseLogger, db } from "../../common/database";
|
||||
import { useAppState } from "../../hooks/use-app-state";
|
||||
import BiometricService from "../../services/biometrics";
|
||||
import { eSendEvent, presentSheet } from "../../services/event-manager";
|
||||
@@ -35,7 +37,9 @@ import { useNoteStore } from "../../stores/use-notes-store";
|
||||
import { useSettingStore } from "../../stores/use-setting-store";
|
||||
import { useThemeStore } from "../../stores/use-theme-store";
|
||||
import { useUserStore } from "../../stores/use-user-store";
|
||||
import { AndroidModule } from "../../utils";
|
||||
import { eOpenAnnouncementDialog } from "../../utils/events";
|
||||
import { getGithubVersion } from "../../utils/github-version";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { sleep } from "../../utils/time";
|
||||
import { SVG } from "../auth/background";
|
||||
@@ -50,9 +54,6 @@ import { SvgView } from "../ui/svg";
|
||||
import Heading from "../ui/typography/heading";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { Walkthrough } from "../walkthroughs";
|
||||
import Config from "react-native-config";
|
||||
import { getGithubVersion } from "../../utils/github-version";
|
||||
import notifee from "@notifee/react-native";
|
||||
|
||||
const Launcher = React.memo(
|
||||
function Launcher() {
|
||||
@@ -69,7 +70,7 @@ const Launcher = React.memo(
|
||||
const introCompleted = useSettingStore(
|
||||
(state) => state.settings.introCompleted
|
||||
);
|
||||
const dbInitCompleted = useRef(false);
|
||||
|
||||
const loadNotes = useCallback(async () => {
|
||||
if (verifyUser) {
|
||||
return;
|
||||
@@ -80,28 +81,25 @@ const Launcher = React.memo(
|
||||
initialize();
|
||||
setImmediate(() => {
|
||||
setLoading(false);
|
||||
if (!dbInitCompleted.current) {
|
||||
setImmediate(() => doAppLoadActions());
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}, [doAppLoadActions, setLoading, verifyUser]);
|
||||
}, [setLoading, verifyUser]);
|
||||
|
||||
const init = useCallback(async () => {
|
||||
if (!dbInitCompleted.current) {
|
||||
if (!db.isInitialized) {
|
||||
await RNBootSplash.hide({ fade: true });
|
||||
await loadDatabase();
|
||||
DatabaseLogger.info("Initializing database");
|
||||
await db.init();
|
||||
dbInitCompleted.current = true;
|
||||
}
|
||||
|
||||
if (db.migrations.required() && !verifyUser) {
|
||||
presentSheet({
|
||||
component: <Migrate />,
|
||||
onClose: async () => {
|
||||
await db.init();
|
||||
if (!db.isInitialized) {
|
||||
await db.init();
|
||||
}
|
||||
loadNotes();
|
||||
},
|
||||
disableClosing: true
|
||||
@@ -120,9 +118,6 @@ const Launcher = React.memo(
|
||||
if (!loading) {
|
||||
doAppLoadActions();
|
||||
}
|
||||
return () => {
|
||||
dbInitCompleted.current = false;
|
||||
};
|
||||
}, [doAppLoadActions, loading]);
|
||||
|
||||
const doAppLoadActions = useCallback(async () => {
|
||||
@@ -198,6 +193,11 @@ const Launcher = React.memo(
|
||||
|
||||
const onUnlockBiometrics = useCallback(async () => {
|
||||
if (!(await BiometricService.isBiometryAvailable())) return;
|
||||
if (Platform.OS === "android") {
|
||||
const activityName = await AndroidModule.getActivityName();
|
||||
if (activityName !== "MainActivity") return;
|
||||
}
|
||||
|
||||
let verified = await BiometricService.validateUser(
|
||||
"Unlock to access your notes",
|
||||
""
|
||||
|
||||
@@ -27,6 +27,7 @@ import { db } from "../../../common/database";
|
||||
import Notebook from "../../../screens/notebook";
|
||||
import { TaggedNotes } from "../../../screens/notes/tagged";
|
||||
import { TopicNotes } from "../../../screens/notes/topic-notes";
|
||||
import useNavigationStore from "../../../stores/use-navigation-store";
|
||||
import { useRelationStore } from "../../../stores/use-relation-store";
|
||||
import { useSettingStore } from "../../../stores/use-setting-store";
|
||||
import { useThemeStore } from "../../../stores/use-theme-store";
|
||||
@@ -52,12 +53,14 @@ const showActionSheet = (item) => {
|
||||
|
||||
function getNotebook(item) {
|
||||
const isTrash = item.type === "trash";
|
||||
const currentId = useNavigationStore.getState().currentScreen.id;
|
||||
if (isTrash) return [];
|
||||
const items = [];
|
||||
const notebooks = db.relations.to(item, "notebook") || [];
|
||||
|
||||
for (let notebook of notebooks) {
|
||||
if (items.length > 1) break;
|
||||
if (notebook.id === currentId) continue;
|
||||
items.push(notebook);
|
||||
}
|
||||
|
||||
@@ -68,6 +71,7 @@ function getNotebook(item) {
|
||||
if (!notebook) continue;
|
||||
for (let topicId of nb.topics) {
|
||||
if (items.length > 1) break;
|
||||
if (topicId === currentId) continue;
|
||||
const topic = notebook.topics.find((t) => t.id === topicId);
|
||||
if (!topic) continue;
|
||||
items.push(topic);
|
||||
@@ -77,10 +81,20 @@ function getNotebook(item) {
|
||||
return items;
|
||||
}
|
||||
|
||||
function getTags(item) {
|
||||
const noteTags = item.tags?.slice(0, 3) || [];
|
||||
const tags = [];
|
||||
for (const tagName of noteTags) {
|
||||
const tag = db.tags.tag(tagName);
|
||||
if (!tag) continue;
|
||||
tags.push(tag);
|
||||
}
|
||||
return tags;
|
||||
}
|
||||
|
||||
const NoteItem = ({
|
||||
item,
|
||||
isTrash,
|
||||
tags,
|
||||
dateBy = "dateCreated",
|
||||
noOpen = false
|
||||
}) => {
|
||||
@@ -96,6 +110,7 @@ const NoteItem = ({
|
||||
const reminders = db.relations.from(item, "reminder");
|
||||
const reminder = getUpcomingReminder(reminders);
|
||||
const noteColor = COLORS_NOTE[item.color?.toLowerCase()];
|
||||
const tags = getTags(item);
|
||||
return (
|
||||
<>
|
||||
<View
|
||||
@@ -117,7 +132,12 @@ const NoteItem = ({
|
||||
>
|
||||
{notebooks?.map((item) => (
|
||||
<Button
|
||||
title={item.title}
|
||||
title={
|
||||
item.title.length > 25
|
||||
? item.title.slice(0, 25) + "..."
|
||||
: item.title
|
||||
}
|
||||
tooltipText={item.title}
|
||||
key={item.id}
|
||||
height={25}
|
||||
icon={item.type === "topic" ? "bookmark" : "book-outline"}
|
||||
|
||||
@@ -100,7 +100,7 @@ export const openNote = async (item, isTrash, setSelectedItem, isSheet) => {
|
||||
};
|
||||
|
||||
export const NoteWrapper = React.memo(
|
||||
function NoteWrapper({ item, index, tags, dateBy, isSheet }) {
|
||||
function NoteWrapper({ item, index, dateBy, isSheet }) {
|
||||
const isTrash = item.type === "trash";
|
||||
const setSelectedItem = useSelectionStore((state) => state.setSelectedItem);
|
||||
|
||||
@@ -113,7 +113,7 @@ export const NoteWrapper = React.memo(
|
||||
isSheet={isSheet}
|
||||
item={item}
|
||||
>
|
||||
<NoteItem item={item} dateBy={dateBy} tags={tags} isTrash={isTrash} />
|
||||
<NoteItem item={item} dateBy={dateBy} isTrash={isTrash} />
|
||||
</SelectionWrapper>
|
||||
);
|
||||
},
|
||||
@@ -125,10 +125,6 @@ export const NoteWrapper = React.memo(
|
||||
return false;
|
||||
}
|
||||
|
||||
if (JSON.stringify(prev.tags) !== JSON.stringify(next.tags)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (prev.item !== next.item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -64,16 +64,7 @@ export const openNotebookTopic = (item) => {
|
||||
negativeText: "Delete",
|
||||
positivePress: async () => {
|
||||
await db.trash.restore(item.id);
|
||||
Navigation.queueRoutesForUpdate(
|
||||
"Tags",
|
||||
"Notes",
|
||||
"Notebooks",
|
||||
"Favorites",
|
||||
"Trash",
|
||||
"TaggedNotes",
|
||||
"ColoredNotes",
|
||||
"TopicNotes"
|
||||
);
|
||||
Navigation.queueRoutesForUpdate();
|
||||
useSelectionStore.getState().setSelectionMode(false);
|
||||
ToastEvent.show({
|
||||
heading: "Restore successful",
|
||||
|
||||
@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import React, { useRef } from "react";
|
||||
import React, { useEffect, useRef } from "react";
|
||||
import { RefreshControl, View } from "react-native";
|
||||
import { FlashList } from "@shopify/flash-list";
|
||||
import Animated, { FadeInDown } from "react-native-reanimated";
|
||||
@@ -57,25 +57,10 @@ const RenderItem = ({ item, index, type, ...restArgs }) => {
|
||||
const dateBy =
|
||||
groupOptions.sortBy !== "title" ? groupOptions.sortBy : "dateEdited";
|
||||
const totalNotes = getTotalNotes(item);
|
||||
const tags =
|
||||
item.tags
|
||||
?.slice(0, 3)
|
||||
?.map((item) => {
|
||||
let tag = db.tags.tag(item);
|
||||
|
||||
if (!tag) return null;
|
||||
return {
|
||||
title: tag.title,
|
||||
id: tag.id,
|
||||
alias: tag.alias
|
||||
};
|
||||
})
|
||||
.filter((t) => t !== null) || [];
|
||||
|
||||
return (
|
||||
<Item
|
||||
item={item}
|
||||
tags={tags}
|
||||
dateBy={dateBy}
|
||||
index={index}
|
||||
type={type}
|
||||
@@ -154,13 +139,20 @@ const List = ({
|
||||
[screen]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
eSendEvent(eScrollEvent, {
|
||||
y: 0,
|
||||
screen
|
||||
});
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
let styles = {
|
||||
width: "100%",
|
||||
minHeight: 1,
|
||||
minWidth: 1
|
||||
};
|
||||
|
||||
const _keyExtractor = (item) => item.id || item.title;
|
||||
const ListView = ScrollComponent ? ScrollComponent : FlashList;
|
||||
return (
|
||||
<>
|
||||
@@ -226,12 +218,14 @@ const List = ({
|
||||
}
|
||||
/>
|
||||
</Animated.View>
|
||||
<JumpToSectionDialog
|
||||
screen={screen}
|
||||
data={listData}
|
||||
type={screen === "Notes" ? "home" : type}
|
||||
scrollRef={scrollRef}
|
||||
/>
|
||||
{listData ? (
|
||||
<JumpToSectionDialog
|
||||
screen={screen}
|
||||
data={listData}
|
||||
type={screen === "Notes" ? "home" : type}
|
||||
scrollRef={scrollRef}
|
||||
/>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -85,13 +85,7 @@ const MergeConflicts = () => {
|
||||
}
|
||||
});
|
||||
}
|
||||
Navigation.queueRoutesForUpdate(
|
||||
"Notes",
|
||||
"Favorites",
|
||||
"ColoredNotes",
|
||||
"TaggedNotes",
|
||||
"TopicNotes"
|
||||
);
|
||||
Navigation.queueRoutesForUpdate();
|
||||
if (editorController.current?.note?.id === note.id) {
|
||||
// reload the note in editor
|
||||
eSendEvent(eOnLoadNote, {
|
||||
|
||||
@@ -44,16 +44,7 @@ export default function NotePreview({ session, content, note }) {
|
||||
async function restore() {
|
||||
if (note && note.type === "trash") {
|
||||
await db.trash.restore(note.id);
|
||||
Navigation.queueRoutesForUpdate(
|
||||
"Tags",
|
||||
"Notes",
|
||||
"Notebooks",
|
||||
"Favorites",
|
||||
"Trash",
|
||||
"TaggedNotes",
|
||||
"ColoredNotes",
|
||||
"TopicNotes"
|
||||
);
|
||||
Navigation.queueRoutesForUpdate();
|
||||
useSelectionStore.getState().setSelectionMode(false);
|
||||
ToastEvent.show({
|
||||
heading: "Restore successful",
|
||||
@@ -73,13 +64,7 @@ export default function NotePreview({ session, content, note }) {
|
||||
}
|
||||
eSendEvent(eCloseSheet, "note_history");
|
||||
eSendEvent(eCloseSheet);
|
||||
Navigation.queueRoutesForUpdate(
|
||||
"Notes",
|
||||
"Favorites",
|
||||
"ColoredNotes",
|
||||
"TaggedNotes",
|
||||
"TopicNotes"
|
||||
);
|
||||
Navigation.queueRoutesForUpdate();
|
||||
|
||||
ToastEvent.show({
|
||||
heading: "Note restored successfully",
|
||||
|
||||
@@ -43,13 +43,7 @@ export const ColorTags = ({ item }) => {
|
||||
let _note = db.notes.note(note.id).data;
|
||||
setNote({ ..._note });
|
||||
setColorNotes();
|
||||
Navigation.queueRoutesForUpdate(
|
||||
"Notes",
|
||||
"Favorites",
|
||||
"ColoredNotes",
|
||||
"TaggedNotes",
|
||||
"TopicNotes"
|
||||
);
|
||||
Navigation.queueRoutesForUpdate();
|
||||
eSendEvent(refreshNotesPage);
|
||||
};
|
||||
|
||||
|
||||
@@ -116,11 +116,11 @@ export const Items = ({ item, buttons, close }) => {
|
||||
key={item.id}
|
||||
testID={"icon-" + item.id}
|
||||
customStyle={{
|
||||
alignItems: "center",
|
||||
alignSelf: "flex-start",
|
||||
width: topBarItemWidth,
|
||||
marginBottom: 10,
|
||||
marginRight: isLast ? 0 : 10,
|
||||
backgroundColor: "transparent"
|
||||
backgroundColor: "transparent",
|
||||
paddingHorizontal: 0
|
||||
}}
|
||||
>
|
||||
<PressableButton
|
||||
@@ -150,11 +150,7 @@ export const Items = ({ item, buttons, close }) => {
|
||||
/>
|
||||
</PressableButton>
|
||||
|
||||
<Paragraph
|
||||
size={SIZE.xxs + 1}
|
||||
style={{ textAlign: "center" }}
|
||||
textBreakStrategy="simple"
|
||||
>
|
||||
<Paragraph size={SIZE.xxs + 1} style={{ textAlign: "center" }}>
|
||||
{item.title}
|
||||
</Paragraph>
|
||||
</PressableButton>
|
||||
|
||||
@@ -145,13 +145,7 @@ export default function Notebooks({ note, close, full }) {
|
||||
note
|
||||
);
|
||||
useNotebookStore.getState().setNotebooks();
|
||||
Navigation.queueRoutesForUpdate(
|
||||
"Notes",
|
||||
"Favorites",
|
||||
"ColoredNotes",
|
||||
"TaggedNotes",
|
||||
"TopicNotes"
|
||||
);
|
||||
Navigation.queueRoutesForUpdate();
|
||||
ToastEvent.show({
|
||||
heading: "Note removed from topic",
|
||||
context: "local",
|
||||
|
||||
@@ -21,18 +21,18 @@ import React, { useCallback, useEffect } from "react";
|
||||
import { BackHandler, Platform, View } from "react-native";
|
||||
import { db } from "../../common/database";
|
||||
import useGlobalSafeAreaInsets from "../../hooks/use-global-safe-area-insets";
|
||||
import { eSendEvent, ToastEvent } from "../../services/event-manager";
|
||||
import { ToastEvent } from "../../services/event-manager";
|
||||
import Navigation from "../../services/navigation";
|
||||
import SearchService from "../../services/search";
|
||||
import useNavigationStore from "../../stores/use-navigation-store";
|
||||
import { useSelectionStore } from "../../stores/use-selection-store";
|
||||
import { useThemeStore } from "../../stores/use-theme-store";
|
||||
import { eOpenMoveNoteDialog } from "../../utils/events";
|
||||
import { deleteItems } from "../../utils/functions";
|
||||
import { tabBarRef } from "../../utils/global-refs";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { sleep } from "../../utils/time";
|
||||
import { presentDialog } from "../dialog/functions";
|
||||
import MoveNoteSheet from "../sheets/add-to";
|
||||
import ExportNotesSheet from "../sheets/export-notes";
|
||||
import { IconButton } from "../ui/icon-button";
|
||||
import Heading from "../ui/typography/heading";
|
||||
@@ -64,13 +64,7 @@ export const SelectionHeader = React.memo(() => {
|
||||
selectedItemsList.forEach((item) => {
|
||||
db.notes.note(item.id).favorite();
|
||||
});
|
||||
Navigation.queueRoutesForUpdate(
|
||||
"Notes",
|
||||
"Favorites",
|
||||
"ColoredNotes",
|
||||
"TaggedNotes",
|
||||
"TopicNotes"
|
||||
);
|
||||
Navigation.queueRoutesForUpdate();
|
||||
clearSelection();
|
||||
}
|
||||
};
|
||||
@@ -82,16 +76,7 @@ export const SelectionHeader = React.memo(() => {
|
||||
noteIds.push(item.id);
|
||||
});
|
||||
await db.trash.restore(...noteIds);
|
||||
Navigation.queueRoutesForUpdate(
|
||||
"Notes",
|
||||
"Favorites",
|
||||
"ColoredNotes",
|
||||
"TaggedNotes",
|
||||
"TopicNotes",
|
||||
"Trash",
|
||||
"Notebooks",
|
||||
"Tags"
|
||||
);
|
||||
Navigation.queueRoutesForUpdate();
|
||||
|
||||
clearSelection();
|
||||
ToastEvent.show({
|
||||
@@ -118,16 +103,7 @@ export const SelectionHeader = React.memo(() => {
|
||||
noteIds.push(item.id);
|
||||
});
|
||||
await db.trash.delete(...noteIds);
|
||||
Navigation.queueRoutesForUpdate(
|
||||
"Notes",
|
||||
"Favorites",
|
||||
"ColoredNotes",
|
||||
"TaggedNotes",
|
||||
"TopicNotes",
|
||||
"Trash",
|
||||
"Notebooks",
|
||||
"Tags"
|
||||
);
|
||||
Navigation.queueRoutesForUpdate();
|
||||
clearSelection();
|
||||
}
|
||||
},
|
||||
@@ -237,7 +213,7 @@ export const SelectionHeader = React.memo(() => {
|
||||
onPress={async () => {
|
||||
//setSelectionMode(false);
|
||||
await sleep(100);
|
||||
eSendEvent(eOpenMoveNoteDialog);
|
||||
MoveNoteSheet.present();
|
||||
}}
|
||||
customStyle={{
|
||||
marginLeft: 10
|
||||
@@ -288,15 +264,7 @@ export const SelectionHeader = React.memo(() => {
|
||||
);
|
||||
}
|
||||
|
||||
Navigation.queueRoutesForUpdate(
|
||||
"Notes",
|
||||
"Favorites",
|
||||
"ColoredNotes",
|
||||
"TaggedNotes",
|
||||
"TopicNotes",
|
||||
"Notebooks",
|
||||
"Notebook"
|
||||
);
|
||||
Navigation.queueRoutesForUpdate();
|
||||
clearSelection();
|
||||
}
|
||||
}}
|
||||
|
||||
@@ -25,22 +25,22 @@ import {
|
||||
TouchableOpacity,
|
||||
View
|
||||
} from "react-native";
|
||||
import { FlatList } from "react-native-actions-sheet";
|
||||
import { notesnook } from "../../../../e2e/test.ids";
|
||||
import { db } from "../../../common/database";
|
||||
import { DDS } from "../../../services/device-detection";
|
||||
import { presentSheet, ToastEvent } from "../../../services/event-manager";
|
||||
import { ToastEvent, presentSheet } from "../../../services/event-manager";
|
||||
import Navigation from "../../../services/navigation";
|
||||
import { useMenuStore } from "../../../stores/use-menu-store";
|
||||
import { useRelationStore } from "../../../stores/use-relation-store";
|
||||
import { ph, pv, SIZE } from "../../../utils/size";
|
||||
import { SIZE, ph, pv } from "../../../utils/size";
|
||||
import { sleep } from "../../../utils/time";
|
||||
import DialogHeader from "../../dialog/dialog-header";
|
||||
import { Button } from "../../ui/button";
|
||||
import { IconButton } from "../../ui/icon-button";
|
||||
import Input from "../../ui/input";
|
||||
import Seperator from "../../ui/seperator";
|
||||
import Heading from "../../ui/typography/heading";
|
||||
import { MoveNotes } from "../move-notes/movenote";
|
||||
import { FlatList } from "react-native-actions-sheet";
|
||||
|
||||
let refs = [];
|
||||
export class AddNotebookSheet extends React.Component {
|
||||
@@ -92,7 +92,7 @@ export class AddNotebookSheet extends React.Component {
|
||||
|
||||
close = () => {
|
||||
refs = [];
|
||||
this.props.close();
|
||||
this.props.close(true);
|
||||
};
|
||||
|
||||
onDelete = (index) => {
|
||||
@@ -182,6 +182,7 @@ export class AddNotebookSheet extends React.Component {
|
||||
});
|
||||
|
||||
await db.notebooks.notebook(toEdit.id).topics.add(...nextTopics);
|
||||
this.close();
|
||||
} else {
|
||||
newNotebookId = await db.notebooks.add({
|
||||
title: this.title,
|
||||
@@ -191,14 +192,7 @@ export class AddNotebookSheet extends React.Component {
|
||||
});
|
||||
}
|
||||
useMenuStore.getState().setMenuPins();
|
||||
Navigation.queueRoutesForUpdate(
|
||||
"Notes",
|
||||
"ColoredNotes",
|
||||
"TaggedNotes",
|
||||
"TopicNotes",
|
||||
"Notebooks",
|
||||
"Notebook"
|
||||
);
|
||||
Navigation.queueRoutesForUpdate();
|
||||
useRelationStore.getState().update();
|
||||
MoveNotes.present(db.notebooks.notebook(newNotebookId).data);
|
||||
};
|
||||
@@ -251,13 +245,34 @@ export class AddNotebookSheet extends React.Component {
|
||||
willFocus && this.topicInputRef.current?.focus();
|
||||
};
|
||||
|
||||
renderTopicItem = ({ item, index }) => (
|
||||
<TopicItem
|
||||
item={item}
|
||||
onPress={(item, index) => {
|
||||
this.prevIndex = index;
|
||||
this.prevItem = item;
|
||||
this.topicInputRef.current?.setNativeProps({
|
||||
text: item
|
||||
});
|
||||
this.topicInputRef.current?.focus();
|
||||
this.currentInputValue = item;
|
||||
this.setState({
|
||||
editTopic: true
|
||||
});
|
||||
}}
|
||||
onDelete={this.onDelete}
|
||||
index={index}
|
||||
colors={this.props.colors}
|
||||
/>
|
||||
);
|
||||
|
||||
render() {
|
||||
const { colors } = this.props;
|
||||
const { topics, topicInputFocused, notebook } = this.state;
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
maxHeight: DDS.isTab ? "90%" : "96%",
|
||||
maxHeight: DDS.isTab ? "90%" : "97%",
|
||||
borderRadius: DDS.isTab ? 5 : 0,
|
||||
paddingHorizontal: 12
|
||||
}}
|
||||
@@ -272,17 +287,34 @@ export class AddNotebookSheet extends React.Component {
|
||||
}}
|
||||
blurOnSubmit={false}
|
||||
/>
|
||||
<DialogHeader
|
||||
title={
|
||||
notebook && notebook.dateCreated ? "Edit Notebook" : "New Notebook"
|
||||
}
|
||||
paragraph={
|
||||
notebook && notebook.dateCreated
|
||||
? "You are editing " + this.title + " notebook."
|
||||
: "Notebooks are the best way to organize your notes."
|
||||
}
|
||||
/>
|
||||
<Seperator half />
|
||||
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
width: "100%",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
<Heading size={SIZE.lg}>
|
||||
{notebook && notebook.dateCreated
|
||||
? "Edit Notebook"
|
||||
: "New Notebook"}
|
||||
</Heading>
|
||||
<Button
|
||||
title="Save"
|
||||
type="accent"
|
||||
height={40}
|
||||
style={{
|
||||
borderRadius: 100,
|
||||
paddingHorizontal: 24
|
||||
}}
|
||||
fontSize={SIZE.md}
|
||||
onPress={this.addNewNotebook}
|
||||
/>
|
||||
</View>
|
||||
|
||||
<Seperator />
|
||||
|
||||
<Input
|
||||
fwdRef={(ref) => (this.titleRef = ref)}
|
||||
@@ -350,48 +382,11 @@ export class AddNotebookSheet extends React.Component {
|
||||
keyExtractor={(item, index) => item + index.toString()}
|
||||
keyboardShouldPersistTaps="always"
|
||||
keyboardDismissMode="interactive"
|
||||
ListFooterComponent={<View style={{ height: 50 }} />}
|
||||
renderItem={({ item, index }) => (
|
||||
<TopicItem
|
||||
item={item}
|
||||
onPress={(item, index) => {
|
||||
this.prevIndex = index;
|
||||
this.prevItem = item;
|
||||
this.topicInputRef.current?.setNativeProps({
|
||||
text: item
|
||||
});
|
||||
this.topicInputRef.current?.focus();
|
||||
this.currentInputValue = item;
|
||||
this.setState({
|
||||
editTopic: true
|
||||
});
|
||||
}}
|
||||
onDelete={this.onDelete}
|
||||
index={index}
|
||||
colors={colors}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<Seperator />
|
||||
<Button
|
||||
width="100%"
|
||||
fontSize={SIZE.md}
|
||||
title={
|
||||
notebook && notebook.dateCreated
|
||||
? "Save changes"
|
||||
: "Create notebook"
|
||||
ListFooterComponent={
|
||||
topics.length === 0 ? null : <View style={{ height: 50 }} />
|
||||
}
|
||||
type="accent"
|
||||
onPress={this.addNewNotebook}
|
||||
renderItem={this.renderTopicItem}
|
||||
/>
|
||||
{/*
|
||||
{Platform.OS === 'ios' && (
|
||||
<View
|
||||
style={{
|
||||
height: 40
|
||||
}}
|
||||
/>
|
||||
)} */}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -21,13 +21,18 @@ import React, { useCallback, useEffect, useMemo } from "react";
|
||||
import { Keyboard, TouchableOpacity, View } from "react-native";
|
||||
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||
import { db } from "../../../common/database";
|
||||
import { presentSheet, ToastEvent } from "../../../services/event-manager";
|
||||
import {
|
||||
eSendEvent,
|
||||
presentSheet,
|
||||
ToastEvent
|
||||
} from "../../../services/event-manager";
|
||||
import Navigation from "../../../services/navigation";
|
||||
import SearchService from "../../../services/search";
|
||||
import { useNotebookStore } from "../../../stores/use-notebook-store";
|
||||
import { useSelectionStore } from "../../../stores/use-selection-store";
|
||||
import { useSettingStore } from "../../../stores/use-setting-store";
|
||||
import { useThemeStore } from "../../../stores/use-theme-store";
|
||||
import { eOnTopicSheetUpdate } from "../../../utils/events";
|
||||
import { Dialog } from "../../dialog";
|
||||
import DialogHeader from "../../dialog/dialog-header";
|
||||
import { presentDialog } from "../../dialog/functions";
|
||||
@@ -287,15 +292,9 @@ const MoveNoteSheet = ({ note, actionSheetRef }) => {
|
||||
}
|
||||
}
|
||||
}
|
||||
Navigation.queueRoutesForUpdate(
|
||||
"Notes",
|
||||
"Favorites",
|
||||
"ColoredNotes",
|
||||
"TaggedNotes",
|
||||
"TopicNotes",
|
||||
"Notebook"
|
||||
);
|
||||
Navigation.queueRoutesForUpdate();
|
||||
setNotebooks();
|
||||
eSendEvent(eOnTopicSheetUpdate);
|
||||
SearchService.updateAndSearch();
|
||||
actionSheetRef.current?.hide();
|
||||
};
|
||||
|
||||
@@ -103,15 +103,7 @@ const ManageTagsSheet = (props) => {
|
||||
});
|
||||
}
|
||||
|
||||
Navigation.queueRoutesForUpdate(
|
||||
"Notes",
|
||||
"Favorites",
|
||||
"ColoredNotes",
|
||||
"TaggedNotes",
|
||||
"TopicNotes",
|
||||
"Notebooks",
|
||||
"Notebook"
|
||||
);
|
||||
Navigation.queueRoutesForUpdate();
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -224,13 +216,7 @@ const TagItem = ({ tag, note, setNote }) => {
|
||||
console.error(e);
|
||||
}
|
||||
setTimeout(() => {
|
||||
Navigation.queueRoutesForUpdate(
|
||||
"Notes",
|
||||
"Favorites",
|
||||
"ColoredNotes",
|
||||
"TaggedNotes",
|
||||
"TopicNotes"
|
||||
);
|
||||
Navigation.queueRoutesForUpdate();
|
||||
}, 1);
|
||||
};
|
||||
|
||||
|
||||
@@ -122,15 +122,7 @@ export const MoveNotes = ({
|
||||
db.notebooks?.notebook(currentNotebook.id).data as NotebookType
|
||||
);
|
||||
|
||||
Navigation.queueRoutesForUpdate(
|
||||
"Notes",
|
||||
"Favorites",
|
||||
"ColoredNotes",
|
||||
"TaggedNotes",
|
||||
"TopicNotes",
|
||||
"Notebook",
|
||||
"Notebooks"
|
||||
);
|
||||
Navigation.queueRoutesForUpdate();
|
||||
return true;
|
||||
};
|
||||
|
||||
@@ -318,15 +310,7 @@ export const MoveNotes = ({
|
||||
},
|
||||
...selectedNoteIds
|
||||
);
|
||||
Navigation.queueRoutesForUpdate(
|
||||
"Notes",
|
||||
"Favorites",
|
||||
"ColoredNotes",
|
||||
"TaggedNotes",
|
||||
"TopicNotes",
|
||||
"Notebook",
|
||||
"Notebooks"
|
||||
);
|
||||
Navigation.queueRoutesForUpdate();
|
||||
SearchService.updateAndSearch();
|
||||
eSendEvent(eCloseSheet);
|
||||
}}
|
||||
|
||||
@@ -63,13 +63,7 @@ const PublishNoteSheet = ({ note: item, update }) => {
|
||||
password: isLocked && passwordValue.current
|
||||
});
|
||||
setNote(db.notes.note(note.id)?.data);
|
||||
Navigation.queueRoutesForUpdate(
|
||||
"Notes",
|
||||
"Favorites",
|
||||
"ColoredNotes",
|
||||
"TaggedNotes",
|
||||
"TopicNotes"
|
||||
);
|
||||
Navigation.queueRoutesForUpdate();
|
||||
setPublishLoading(false);
|
||||
}
|
||||
} catch (e) {
|
||||
@@ -95,13 +89,7 @@ const PublishNoteSheet = ({ note: item, update }) => {
|
||||
if (note?.id) {
|
||||
await db.monographs.unpublish(note.id);
|
||||
setNote(db.notes.note(note.id)?.data);
|
||||
Navigation.queueRoutesForUpdate(
|
||||
"Notes",
|
||||
"Favorites",
|
||||
"ColoredNotes",
|
||||
"TaggedNotes",
|
||||
"TopicNotes"
|
||||
);
|
||||
Navigation.queueRoutesForUpdate();
|
||||
setPublishLoading(false);
|
||||
}
|
||||
} catch (e) {
|
||||
|
||||
@@ -21,9 +21,9 @@ import { Platform, TextInput, View } from "react-native";
|
||||
import { ActionSheetRef, ScrollView } from "react-native-actions-sheet";
|
||||
import DateTimePickerModal from "react-native-modal-datetime-picker";
|
||||
import {
|
||||
presentSheet,
|
||||
PresentSheetOptions,
|
||||
ToastEvent
|
||||
ToastEvent,
|
||||
presentSheet
|
||||
} from "../../../services/event-manager";
|
||||
import { useThemeStore } from "../../../stores/use-theme-store";
|
||||
import { SIZE } from "../../../utils/size";
|
||||
@@ -33,6 +33,7 @@ import Input from "../../ui/input";
|
||||
import dayjs from "dayjs";
|
||||
import DatePicker from "react-native-date-picker";
|
||||
import { db } from "../../../common/database";
|
||||
import { DDS } from "../../../services/device-detection";
|
||||
import Navigation from "../../../services/navigation";
|
||||
import Notifications, { Reminder } from "../../../services/notifications";
|
||||
import PremiumService from "../../../services/premium";
|
||||
@@ -41,6 +42,7 @@ import { useRelationStore } from "../../../stores/use-relation-store";
|
||||
import { NoteType } from "../../../utils/types";
|
||||
import { Dialog } from "../../dialog";
|
||||
import { ReminderTime } from "../../ui/reminder-time";
|
||||
import Heading from "../../ui/typography/heading";
|
||||
import Paragraph from "../../ui/typography/paragraph";
|
||||
|
||||
type ReminderSheetProps = {
|
||||
@@ -198,7 +200,8 @@ export default function ReminderSheet({
|
||||
|
||||
if (!_reminder) {
|
||||
ToastEvent.show({
|
||||
heading: "Failed to add a new reminder"
|
||||
heading: "Failed to add a new reminder",
|
||||
context: "local"
|
||||
});
|
||||
}
|
||||
if (reference) {
|
||||
@@ -208,54 +211,68 @@ export default function ReminderSheet({
|
||||
});
|
||||
}
|
||||
Notifications.scheduleNotification(_reminder as Reminder);
|
||||
Navigation.queueRoutesForUpdate(
|
||||
"TaggedNotes",
|
||||
"ColoredNotes",
|
||||
"Notes",
|
||||
"NotesPage",
|
||||
"Reminders",
|
||||
"Favorites",
|
||||
"TopicNotes"
|
||||
);
|
||||
Navigation.queueRoutesForUpdate();
|
||||
useRelationStore.getState().update();
|
||||
close?.();
|
||||
} catch (e) {
|
||||
ToastEvent.error(e as Error);
|
||||
ToastEvent.error(e as Error, undefined, "local");
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
paddingHorizontal: 12
|
||||
paddingHorizontal: 12,
|
||||
maxHeight: DDS.isTab ? "90%" : "99.99%"
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
width: "100%",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
<Heading size={SIZE.lg}>Set reminder</Heading>
|
||||
<Button
|
||||
title="Save"
|
||||
type="accent"
|
||||
height={40}
|
||||
style={{
|
||||
borderRadius: 100,
|
||||
paddingHorizontal: 24
|
||||
}}
|
||||
fontSize={SIZE.md}
|
||||
onPress={saveReminder}
|
||||
/>
|
||||
</View>
|
||||
<Dialog context="local" />
|
||||
<ScrollView keyboardShouldPersistTaps="always">
|
||||
<ScrollView>
|
||||
<Input
|
||||
fwdRef={titleRef}
|
||||
defaultValue={reminder?.title || referencedItem?.title}
|
||||
placeholder="Remind me of..."
|
||||
onChangeText={(text) => (title.current = text)}
|
||||
containerStyle={{ borderWidth: 0, borderBottomWidth: 1 }}
|
||||
wrapperStyle={{
|
||||
marginTop: 10
|
||||
}}
|
||||
/>
|
||||
|
||||
<Input
|
||||
defaultValue={
|
||||
reminder ? reminder?.description : referencedItem?.headline
|
||||
}
|
||||
placeholder="Add a quick note"
|
||||
placeholder="Add a short note"
|
||||
onChangeText={(text) => (details.current = text)}
|
||||
containerStyle={{
|
||||
borderWidth: 0,
|
||||
borderBottomWidth: 1,
|
||||
maxHeight: 80,
|
||||
marginTop: 10
|
||||
maxHeight: 80
|
||||
}}
|
||||
multiline
|
||||
textAlignVertical="top"
|
||||
inputStyle={{
|
||||
height: 80
|
||||
minHeight: 80,
|
||||
paddingVertical: 12
|
||||
}}
|
||||
height={80}
|
||||
wrapperStyle={{
|
||||
@@ -293,6 +310,16 @@ export default function ReminderSheet({
|
||||
mode as keyof typeof ReminderModes
|
||||
] as Reminder["mode"]
|
||||
);
|
||||
if (mode === "Repeat") {
|
||||
setSelectedDays((days) => {
|
||||
if (days.length > 0) return days;
|
||||
if (days.indexOf(date.getDay()) > -1) {
|
||||
return days;
|
||||
}
|
||||
days.push(date.getDay());
|
||||
return [...days];
|
||||
});
|
||||
}
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
@@ -434,17 +461,13 @@ export default function ReminderSheet({
|
||||
|
||||
<DatePicker
|
||||
date={date}
|
||||
minimumDate={
|
||||
dayjs(date).subtract(3, "months").isBefore(dayjs())
|
||||
? dayjs().toDate()
|
||||
: dayjs(date).subtract(3, "months").toDate()
|
||||
}
|
||||
maximumDate={dayjs(date).add(3, "months").toDate()}
|
||||
onDateChange={handleConfirm}
|
||||
textColor={colors.night ? "#ffffff" : "#000000"}
|
||||
fadeToColor={colors.bg}
|
||||
theme={colors.night ? "dark" : "light"}
|
||||
is24hourSource="locale"
|
||||
androidVariant="nativeAndroid"
|
||||
mode={reminderMode === ReminderModes.Repeat ? "time" : "datetime"}
|
||||
/>
|
||||
|
||||
@@ -561,15 +584,6 @@ export default function ReminderSheet({
|
||||
alignSelf: "flex-start"
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
style={{
|
||||
width: "100%"
|
||||
}}
|
||||
title="Save"
|
||||
type="accent"
|
||||
fontSize={SIZE.md}
|
||||
onPress={saveReminder}
|
||||
/>
|
||||
</ScrollView>
|
||||
</View>
|
||||
);
|
||||
@@ -583,6 +597,7 @@ ReminderSheet.present = (
|
||||
presentSheet({
|
||||
context: isSheet ? "local" : undefined,
|
||||
enableGesturesInScrollView: true,
|
||||
noBottomPadding: true,
|
||||
component: (ref, close, update) => (
|
||||
<ReminderSheet
|
||||
actionSheetRef={ref}
|
||||
|
||||
@@ -25,23 +25,22 @@ import Navigation from "../../../services/navigation";
|
||||
import { useThemeStore } from "../../../stores/use-theme-store";
|
||||
import { GROUP, SORT } from "../../../utils/constants";
|
||||
import { refreshNotesPage } from "../../../utils/events";
|
||||
import layoutmanager from "../../../utils/layout-manager";
|
||||
import { SIZE } from "../../../utils/size";
|
||||
import { Button } from "../../ui/button";
|
||||
import Seperator from "../../ui/seperator";
|
||||
import Heading from "../../ui/typography/heading";
|
||||
const Sort = ({ type, screen }) => {
|
||||
const colors = useThemeStore((state) => state.colors);
|
||||
const isTopicSheet = screen === "TopicSheet";
|
||||
const [groupOptions, setGroupOptions] = useState(
|
||||
db.settings.getGroupOptions(type)
|
||||
);
|
||||
const updateGroupOptions = async (_groupOptions) => {
|
||||
await db.settings.setGroupOptions(type, _groupOptions);
|
||||
|
||||
layoutmanager.withSpringAnimation(600);
|
||||
setGroupOptions(_groupOptions);
|
||||
setTimeout(() => {
|
||||
Navigation.queueRoutesForUpdate(screen);
|
||||
if (screen !== "TopicSheet") Navigation.queueRoutesForUpdate(screen);
|
||||
eSendEvent("groupOptionsUpdate");
|
||||
eSendEvent(refreshNotesPage);
|
||||
}, 1);
|
||||
@@ -52,6 +51,9 @@ const Sort = ({ type, screen }) => {
|
||||
...groupOptions,
|
||||
sortDirection: groupOptions.sortDirection === "asc" ? "desc" : "asc"
|
||||
};
|
||||
if (type === "topics") {
|
||||
_groupOptions.groupBy = "none";
|
||||
}
|
||||
await updateGroupOptions(_groupOptions);
|
||||
};
|
||||
|
||||
@@ -119,7 +121,7 @@ const Sort = ({ type, screen }) => {
|
||||
flexDirection: "row",
|
||||
justifyContent: "flex-start",
|
||||
flexWrap: "wrap",
|
||||
borderBottomWidth: 1,
|
||||
borderBottomWidth: isTopicSheet ? 0 : 1,
|
||||
borderBottomColor: colors.nav,
|
||||
marginBottom: 12,
|
||||
paddingHorizontal: 12,
|
||||
@@ -166,6 +168,9 @@ const Sort = ({ type, screen }) => {
|
||||
...groupOptions,
|
||||
sortBy: type === "trash" ? "dateDeleted" : item
|
||||
};
|
||||
if (type === "topics") {
|
||||
_groupOptions.groupBy = "none";
|
||||
}
|
||||
await updateGroupOptions(_groupOptions);
|
||||
}}
|
||||
iconSize={SIZE.md}
|
||||
@@ -175,64 +180,70 @@ const Sort = ({ type, screen }) => {
|
||||
)}
|
||||
</View>
|
||||
|
||||
<Heading
|
||||
style={{
|
||||
marginLeft: 12
|
||||
}}
|
||||
size={SIZE.lg}
|
||||
>
|
||||
Group by
|
||||
</Heading>
|
||||
|
||||
<Seperator />
|
||||
|
||||
<View
|
||||
style={{
|
||||
borderRadius: 0,
|
||||
flexDirection: "row",
|
||||
flexWrap: "wrap",
|
||||
paddingHorizontal: 12
|
||||
}}
|
||||
>
|
||||
{Object.keys(GROUP).map((item) => (
|
||||
<Button
|
||||
key={item}
|
||||
testID={"btn-" + item}
|
||||
type={groupOptions.groupBy === GROUP[item] ? "grayBg" : "gray"}
|
||||
buttonType={{
|
||||
text:
|
||||
groupOptions.groupBy === GROUP[item]
|
||||
? colors.accent
|
||||
: colors.icon
|
||||
}}
|
||||
onPress={async () => {
|
||||
let _groupOptions = {
|
||||
...groupOptions,
|
||||
groupBy: GROUP[item]
|
||||
};
|
||||
|
||||
if (item === "abc") {
|
||||
_groupOptions.sortBy = "title";
|
||||
_groupOptions.sortDirection = "asc";
|
||||
} else {
|
||||
if (groupOptions.sortBy === "title") {
|
||||
_groupOptions.sortBy = "dateEdited";
|
||||
_groupOptions.sortDirection = "desc";
|
||||
}
|
||||
}
|
||||
updateGroupOptions(_groupOptions);
|
||||
}}
|
||||
height={40}
|
||||
icon={groupOptions.groupBy === GROUP[item] ? "check" : null}
|
||||
title={item.slice(0, 1).toUpperCase() + item.slice(1, item.length)}
|
||||
{isTopicSheet ? null : (
|
||||
<>
|
||||
<Heading
|
||||
style={{
|
||||
paddingHorizontal: 8,
|
||||
marginBottom: 10,
|
||||
marginRight: 10
|
||||
marginLeft: 12
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</View>
|
||||
size={SIZE.lg}
|
||||
>
|
||||
Group by
|
||||
</Heading>
|
||||
|
||||
<Seperator />
|
||||
|
||||
<View
|
||||
style={{
|
||||
borderRadius: 0,
|
||||
flexDirection: "row",
|
||||
flexWrap: "wrap",
|
||||
paddingHorizontal: 12
|
||||
}}
|
||||
>
|
||||
{Object.keys(GROUP).map((item) => (
|
||||
<Button
|
||||
key={item}
|
||||
testID={"btn-" + item}
|
||||
type={groupOptions.groupBy === GROUP[item] ? "grayBg" : "gray"}
|
||||
buttonType={{
|
||||
text:
|
||||
groupOptions.groupBy === GROUP[item]
|
||||
? colors.accent
|
||||
: colors.icon
|
||||
}}
|
||||
onPress={async () => {
|
||||
let _groupOptions = {
|
||||
...groupOptions,
|
||||
groupBy: GROUP[item]
|
||||
};
|
||||
|
||||
if (item === "abc") {
|
||||
_groupOptions.sortBy = "title";
|
||||
_groupOptions.sortDirection = "asc";
|
||||
} else {
|
||||
if (groupOptions.sortBy === "title") {
|
||||
_groupOptions.sortBy = "dateEdited";
|
||||
_groupOptions.sortDirection = "desc";
|
||||
}
|
||||
}
|
||||
updateGroupOptions(_groupOptions);
|
||||
}}
|
||||
height={40}
|
||||
icon={groupOptions.groupBy === GROUP[item] ? "check" : null}
|
||||
title={
|
||||
item.slice(0, 1).toUpperCase() + item.slice(1, item.length)
|
||||
}
|
||||
style={{
|
||||
paddingHorizontal: 8,
|
||||
marginBottom: 10,
|
||||
marginRight: 10
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</View>
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -19,12 +19,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import qclone from "qclone";
|
||||
import React, {
|
||||
createContext,
|
||||
RefObject,
|
||||
useCallback,
|
||||
useContext,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState
|
||||
} from "react";
|
||||
import { Animated, Dimensions, View, RefreshControl } from "react-native";
|
||||
import { RefreshControl, View } from "react-native";
|
||||
import ActionSheet, {
|
||||
ActionSheetRef,
|
||||
FlatList
|
||||
@@ -37,7 +39,8 @@ import { TopicNotes } from "../../../screens/notes/topic-notes";
|
||||
import {
|
||||
eSendEvent,
|
||||
eSubscribeEvent,
|
||||
eUnSubscribeEvent
|
||||
eUnSubscribeEvent,
|
||||
presentSheet
|
||||
} from "../../../services/event-manager";
|
||||
import useNavigationStore, {
|
||||
NotebookScreenParams
|
||||
@@ -49,18 +52,40 @@ import {
|
||||
eOpenAddTopicDialog
|
||||
} from "../../../utils/events";
|
||||
import { normalize, SIZE } from "../../../utils/size";
|
||||
import { NotebookType, TopicType } from "../../../utils/types";
|
||||
import { GroupHeader, NotebookType, TopicType } from "../../../utils/types";
|
||||
|
||||
import { groupArray } from "@notesnook/core/utils/grouping";
|
||||
import Config from "react-native-config";
|
||||
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||
import { notesnook } from "../../../../e2e/test.ids";
|
||||
import { MMKV } from "../../../common/database/mmkv";
|
||||
import { openEditor } from "../../../screens/notes/common";
|
||||
import { getTotalNotes, history } from "../../../utils";
|
||||
import { Properties } from "../../properties";
|
||||
import { deleteItems } from "../../../utils/functions";
|
||||
import { presentDialog } from "../../dialog/functions";
|
||||
import Config from "react-native-config";
|
||||
import { notesnook } from "../../../../e2e/test.ids";
|
||||
import { Properties } from "../../properties";
|
||||
import Sort from "../sort";
|
||||
import Heading from "../../ui/typography/heading";
|
||||
|
||||
type ConfigItem = { id: string; type: string };
|
||||
class TopicSheetConfig {
|
||||
static storageKey: "$$sp";
|
||||
|
||||
static makeId(item: ConfigItem) {
|
||||
return `${TopicSheetConfig.storageKey}:${item.type}:${item.id}`;
|
||||
}
|
||||
|
||||
static get(item: ConfigItem) {
|
||||
return MMKV.getInt(TopicSheetConfig.makeId(item)) || 0;
|
||||
}
|
||||
|
||||
static set(item: ConfigItem, index = 0) {
|
||||
MMKV.setInt(TopicSheetConfig.makeId(item), index);
|
||||
}
|
||||
}
|
||||
|
||||
export const TopicsSheet = () => {
|
||||
const [collapsed, setCollapsed] = useState(false);
|
||||
const currentScreen = useNavigationStore((state) => state.currentScreen);
|
||||
const canShow =
|
||||
currentScreen.name === "Notebook" || currentScreen.name === "TopicNotes";
|
||||
@@ -75,12 +100,19 @@ export const TopicsSheet = () => {
|
||||
const [enabled, setEnabled] = useState(false);
|
||||
const colors = useThemeStore((state) => state.colors);
|
||||
const ref = useRef<ActionSheetRef>(null);
|
||||
const [topics, setTopics] = useState(notebook ? qclone(notebook.topics) : []);
|
||||
const [animations] = useState({
|
||||
translate: new Animated.Value(0),
|
||||
display: new Animated.Value(-5000),
|
||||
opacity: new Animated.Value(0)
|
||||
});
|
||||
const isTopic = currentScreen.name === "TopicNotes";
|
||||
const [topics, setTopics] = useState(
|
||||
notebook
|
||||
? qclone(
|
||||
groupArray(notebook.topics, db.settings?.getGroupOptions("topics"))
|
||||
)
|
||||
: []
|
||||
);
|
||||
|
||||
const [groupOptions, setGroupOptions] = useState(
|
||||
db.settings?.getGroupOptions("topics")
|
||||
);
|
||||
|
||||
const onRequestUpdate = React.useCallback(
|
||||
(data?: NotebookScreenParams) => {
|
||||
if (!canShow) return;
|
||||
@@ -89,15 +121,34 @@ export const TopicsSheet = () => {
|
||||
?.data as NotebookType;
|
||||
if (_notebook) {
|
||||
setNotebook(_notebook);
|
||||
setTopics(qclone(_notebook.topics));
|
||||
|
||||
setTopics(
|
||||
qclone(
|
||||
groupArray(_notebook.topics, db.settings?.getGroupOptions("topics"))
|
||||
)
|
||||
);
|
||||
}
|
||||
},
|
||||
[notebook, canShow]
|
||||
[canShow, notebook]
|
||||
);
|
||||
|
||||
const onUpdate = useCallback(() => {
|
||||
setGroupOptions({ ...(db.settings?.getGroupOptions("topics") as any) });
|
||||
onRequestUpdate();
|
||||
}, [onRequestUpdate]);
|
||||
|
||||
useEffect(() => {
|
||||
eSubscribeEvent("groupOptionsUpdate", onUpdate);
|
||||
return () => {
|
||||
eUnSubscribeEvent("groupOptionsUpdate", onUpdate);
|
||||
};
|
||||
}, [onUpdate]);
|
||||
|
||||
useEffect(() => {
|
||||
const onTopicUpdate = () => {
|
||||
onRequestUpdate();
|
||||
setTimeout(() => {
|
||||
onRequestUpdate();
|
||||
}, 1);
|
||||
};
|
||||
eSubscribeEvent(eOnTopicSheetUpdate, onTopicUpdate);
|
||||
eSubscribeEvent(eOnNewTopicAdded, onRequestUpdate);
|
||||
@@ -117,9 +168,16 @@ export const TopicsSheet = () => {
|
||||
loading: "Loading notebook topics"
|
||||
};
|
||||
|
||||
const renderTopic = ({ item, index }: { item: TopicType; index: number }) => (
|
||||
<TopicItem item={item} index={index} />
|
||||
);
|
||||
const renderTopic = ({
|
||||
item,
|
||||
index
|
||||
}: {
|
||||
item: TopicType | GroupHeader;
|
||||
index: number;
|
||||
}) =>
|
||||
(item as GroupHeader).type === "header" ? null : (
|
||||
<TopicItem sheetRef={ref} item={item as TopicType} index={index} />
|
||||
);
|
||||
|
||||
const selectionContext = {
|
||||
selection: selection,
|
||||
@@ -146,29 +204,37 @@ export const TopicsSheet = () => {
|
||||
|
||||
useEffect(() => {
|
||||
if (canShow) {
|
||||
const isTopic = currentScreen.name === "TopicNotes";
|
||||
const id = isTopic ? currentScreen?.notebookId : currentScreen?.id;
|
||||
if (!ref.current?.isOpen()) {
|
||||
animations.display.setValue(5000);
|
||||
animations.opacity.setValue(0);
|
||||
}
|
||||
if (id) {
|
||||
onRequestUpdate({
|
||||
item: db.notebooks?.notebook(id).data
|
||||
} as any);
|
||||
}
|
||||
ref.current?.show();
|
||||
setTimeout(() => {
|
||||
const id = isTopic ? currentScreen?.notebookId : currentScreen?.id;
|
||||
const notebook = db.notebooks?.notebook(id as string)?.data;
|
||||
const snapPoint = isTopic
|
||||
? 0
|
||||
: TopicSheetConfig.get({
|
||||
type: isTopic ? "topic" : "notebook",
|
||||
id: currentScreen.id as string
|
||||
});
|
||||
|
||||
if (ref.current?.isOpen()) {
|
||||
ref.current?.snapToIndex(snapPoint);
|
||||
} else {
|
||||
ref.current?.show(snapPoint);
|
||||
}
|
||||
if (notebook) {
|
||||
onRequestUpdate({
|
||||
item: notebook
|
||||
} as any);
|
||||
}
|
||||
}, 300);
|
||||
} else {
|
||||
ref.current?.hide();
|
||||
}
|
||||
}, [
|
||||
animations.display,
|
||||
animations.opacity,
|
||||
canShow,
|
||||
currentScreen?.id,
|
||||
currentScreen.name,
|
||||
currentScreen?.notebookId,
|
||||
onRequestUpdate
|
||||
onRequestUpdate,
|
||||
isTopic
|
||||
]);
|
||||
|
||||
return (
|
||||
@@ -176,14 +242,27 @@ export const TopicsSheet = () => {
|
||||
ref={ref}
|
||||
isModal={false}
|
||||
containerStyle={{
|
||||
maxHeight: 400,
|
||||
maxHeight: 300,
|
||||
borderTopRightRadius: 15,
|
||||
borderTopLeftRadius: 15,
|
||||
backgroundColor: colors.bg,
|
||||
borderWidth: 1,
|
||||
borderColor: colors.border,
|
||||
borderColor: colors.nav,
|
||||
borderBottomWidth: 0
|
||||
}}
|
||||
openAnimationConfig={{
|
||||
friction: 10
|
||||
}}
|
||||
onSnapIndexChange={(index) => {
|
||||
setCollapsed(index === 0);
|
||||
TopicSheetConfig.set(
|
||||
{
|
||||
type: isTopic ? "topic" : "notebook",
|
||||
id: currentScreen.id as string
|
||||
},
|
||||
index
|
||||
);
|
||||
}}
|
||||
closable={!canShow}
|
||||
elevation={10}
|
||||
indicatorStyle={{
|
||||
@@ -191,66 +270,44 @@ export const TopicsSheet = () => {
|
||||
backgroundColor: colors.nav
|
||||
}}
|
||||
keyboardHandlerEnabled={false}
|
||||
snapPoints={Config.isTesting === "true" ? [100] : [15, 100]}
|
||||
initialSnapIndex={0}
|
||||
snapPoints={Config.isTesting === "true" ? [100] : [25, 100]}
|
||||
initialSnapIndex={1}
|
||||
backgroundInteractionEnabled
|
||||
onChange={(position, height) => {
|
||||
animations.translate.setValue(position - 60);
|
||||
const h = Dimensions.get("window").height;
|
||||
const minPos = h - height;
|
||||
if (position - 100 < minPos || !canShow) {
|
||||
animations.display.setValue(5000);
|
||||
animations.opacity.setValue(0);
|
||||
} else {
|
||||
animations.display.setValue(0);
|
||||
setTimeout(() => {
|
||||
animations.opacity.setValue(1);
|
||||
}, 300);
|
||||
}
|
||||
}}
|
||||
gestureEnabled
|
||||
ExtraOverlayComponent={
|
||||
<Animated.View
|
||||
style={{
|
||||
top: animations.translate,
|
||||
position: "absolute",
|
||||
right: 12,
|
||||
opacity: animations.opacity,
|
||||
transform: [
|
||||
{
|
||||
translateY: animations.display
|
||||
}
|
||||
]
|
||||
}}
|
||||
>
|
||||
<PressableButton
|
||||
testID={notesnook.buttons.add}
|
||||
type="accent"
|
||||
accentColor={"accent"}
|
||||
accentText="light"
|
||||
onPress={openEditor}
|
||||
customStyle={{
|
||||
borderRadius: 100
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
height: normalize(60),
|
||||
width: normalize(60)
|
||||
}}
|
||||
>
|
||||
<Icon name="plus" color="white" size={SIZE.xxl} />
|
||||
</View>
|
||||
</PressableButton>
|
||||
</Animated.View>
|
||||
}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
maxHeight: 400,
|
||||
height: 400,
|
||||
position: "absolute",
|
||||
right: 12,
|
||||
marginTop: -80
|
||||
}}
|
||||
>
|
||||
<PressableButton
|
||||
testID={notesnook.buttons.add}
|
||||
type="accent"
|
||||
accentColor={"accent"}
|
||||
accentText="light"
|
||||
onPress={openEditor}
|
||||
customStyle={{
|
||||
borderRadius: 100
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
height: normalize(60),
|
||||
width: normalize(60)
|
||||
}}
|
||||
>
|
||||
<Icon name="plus" color="white" size={SIZE.xxl} />
|
||||
</View>
|
||||
</PressableButton>
|
||||
</View>
|
||||
<View
|
||||
style={{
|
||||
maxHeight: 300,
|
||||
height: 300,
|
||||
width: "100%"
|
||||
}}
|
||||
>
|
||||
@@ -283,7 +340,7 @@ export const TopicsSheet = () => {
|
||||
selection.length > 1 ? "topics" : "topics"
|
||||
}`,
|
||||
paragraph: `Are you sure you want to delete ${
|
||||
selection.length > 1 ? "these topicss?" : "this topics?"
|
||||
selection.length > 1 ? "these topics?" : "this topic?"
|
||||
}`,
|
||||
positiveText: "Delete",
|
||||
negativeText: "Cancel",
|
||||
@@ -304,17 +361,57 @@ export const TopicsSheet = () => {
|
||||
size={22}
|
||||
/>
|
||||
) : (
|
||||
<IconButton
|
||||
name="plus"
|
||||
onPress={PLACEHOLDER_DATA.action}
|
||||
testID="add-topic-button"
|
||||
color={colors.pri}
|
||||
size={22}
|
||||
customStyle={{
|
||||
width: 40,
|
||||
height: 40
|
||||
}}
|
||||
/>
|
||||
<>
|
||||
<IconButton
|
||||
name={
|
||||
groupOptions?.sortDirection === "asc"
|
||||
? "sort-ascending"
|
||||
: "sort-descending"
|
||||
}
|
||||
onPress={() => {
|
||||
presentSheet({
|
||||
component: <Sort screen="TopicSheet" type="topics" />
|
||||
});
|
||||
}}
|
||||
testID="group-topic-button"
|
||||
color={colors.pri}
|
||||
size={22}
|
||||
customStyle={{
|
||||
width: 40,
|
||||
height: 40
|
||||
}}
|
||||
/>
|
||||
<IconButton
|
||||
name="plus"
|
||||
onPress={PLACEHOLDER_DATA.action}
|
||||
testID="add-topic-button"
|
||||
color={colors.pri}
|
||||
size={22}
|
||||
customStyle={{
|
||||
width: 40,
|
||||
height: 40
|
||||
}}
|
||||
/>
|
||||
|
||||
<IconButton
|
||||
name={collapsed ? "chevron-up" : "chevron-down"}
|
||||
onPress={() => {
|
||||
if (ref.current?.currentSnapIndex() !== 0) {
|
||||
setCollapsed(true);
|
||||
ref.current?.snapToIndex(0);
|
||||
} else {
|
||||
setCollapsed(false);
|
||||
ref.current?.snapToIndex(1);
|
||||
}
|
||||
}}
|
||||
color={colors.pri}
|
||||
size={22}
|
||||
customStyle={{
|
||||
width: 40,
|
||||
height: 40
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
@@ -334,7 +431,7 @@ export const TopicsSheet = () => {
|
||||
progressBackgroundColor={colors.bg}
|
||||
/>
|
||||
}
|
||||
keyExtractor={(item) => item.id}
|
||||
keyExtractor={(item) => (item as TopicType).id}
|
||||
renderItem={renderTopic}
|
||||
ListEmptyComponent={
|
||||
<View
|
||||
@@ -342,7 +439,7 @@ export const TopicsSheet = () => {
|
||||
flex: 1,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
height: 300
|
||||
height: 200
|
||||
}}
|
||||
>
|
||||
<Paragraph color={colors.icon}>No topics</Paragraph>
|
||||
@@ -364,12 +461,20 @@ const SelectionContext = createContext<{
|
||||
}>({
|
||||
selection: [],
|
||||
enabled: false,
|
||||
setEnabled: (value: boolean) => {},
|
||||
toggleSelection: (item: TopicType) => {}
|
||||
setEnabled: (_value: boolean) => {},
|
||||
toggleSelection: (_item: TopicType) => {}
|
||||
});
|
||||
const useSelection = () => useContext(SelectionContext);
|
||||
|
||||
const TopicItem = ({ item, index }: { item: TopicType; index: number }) => {
|
||||
const TopicItem = ({
|
||||
item,
|
||||
index,
|
||||
sheetRef
|
||||
}: {
|
||||
item: TopicType;
|
||||
index: number;
|
||||
sheetRef: RefObject<ActionSheetRef>;
|
||||
}) => {
|
||||
const screen = useNavigationStore((state) => state.currentScreen);
|
||||
const colors = useThemeStore((state) => state.colors);
|
||||
const selection = useSelection();
|
||||
|
||||
@@ -18,7 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import React, { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { Keyboard, TouchableOpacity, View } from "react-native";
|
||||
import { TouchableOpacity, View } from "react-native";
|
||||
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||
import { notesnook } from "../../../e2e/test.ids";
|
||||
import useGlobalSafeAreaInsets from "../../hooks/use-global-safe-area-insets";
|
||||
@@ -34,24 +34,25 @@ import { SIZE } from "../../utils/size";
|
||||
import { Button } from "../ui/button";
|
||||
import Heading from "../ui/typography/heading";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
let toastMessages = [];
|
||||
export const Toast = ({ context = "global" }) => {
|
||||
const colors = useThemeStore((state) => state.colors);
|
||||
const [keyboard, setKeyboard] = useState(false);
|
||||
const [data, setData] = useState({});
|
||||
const insets = useGlobalSafeAreaInsets();
|
||||
const hideTimeout = useRef();
|
||||
const [visible, setVisible] = useState(false);
|
||||
const toastMessages = useRef([]);
|
||||
|
||||
const showToastFunc = useCallback(
|
||||
const show = useCallback(
|
||||
async (data) => {
|
||||
if (!data) return;
|
||||
if (data.context !== context) return;
|
||||
if (toastMessages.findIndex((m) => m.message === data.message) >= 0) {
|
||||
if (
|
||||
toastMessages.current.findIndex((m) => m.message === data.message) >= 0
|
||||
) {
|
||||
return;
|
||||
}
|
||||
toastMessages.push(data);
|
||||
if (toastMessages?.length > 1) return;
|
||||
toastMessages.current.push(data);
|
||||
if (toastMessages.current?.length > 1) return;
|
||||
setData(data);
|
||||
|
||||
setVisible(true);
|
||||
@@ -59,16 +60,16 @@ export const Toast = ({ context = "global" }) => {
|
||||
clearTimeout(hideTimeout.current);
|
||||
}
|
||||
hideTimeout.current = setTimeout(() => {
|
||||
hideToastFunc();
|
||||
hide();
|
||||
}, data.duration);
|
||||
},
|
||||
[context, hideToastFunc]
|
||||
[context, hide]
|
||||
);
|
||||
|
||||
const showNext = useCallback(
|
||||
const next = useCallback(
|
||||
(data) => {
|
||||
if (!data) {
|
||||
hideToastFunc();
|
||||
hide();
|
||||
return;
|
||||
}
|
||||
setData(data);
|
||||
@@ -76,27 +77,28 @@ export const Toast = ({ context = "global" }) => {
|
||||
clearTimeout(hideTimeout.current);
|
||||
}
|
||||
hideTimeout.current = setTimeout(() => {
|
||||
hideToastFunc();
|
||||
hide();
|
||||
}, data?.duration);
|
||||
},
|
||||
[hideToastFunc]
|
||||
[hide]
|
||||
);
|
||||
|
||||
const hideToastFunc = useCallback(() => {
|
||||
const hide = useCallback(() => {
|
||||
if (hideTimeout.current) {
|
||||
clearTimeout(hideTimeout.current);
|
||||
}
|
||||
let msg = toastMessages.length > 1 ? toastMessages.shift() : null;
|
||||
let msg =
|
||||
toastMessages.current.length > 1 ? toastMessages.current.shift() : null;
|
||||
|
||||
if (msg) {
|
||||
setVisible(false);
|
||||
showNext(msg);
|
||||
next(msg);
|
||||
setTimeout(() => {
|
||||
setVisible(true);
|
||||
}, 300);
|
||||
} else {
|
||||
setVisible(false);
|
||||
toastMessages.shift();
|
||||
toastMessages.current.shift();
|
||||
setTimeout(() => {
|
||||
setData({});
|
||||
if (hideTimeout.current) {
|
||||
@@ -104,44 +106,22 @@ export const Toast = ({ context = "global" }) => {
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
}, [showNext]);
|
||||
|
||||
const _onKeyboardShow = () => {
|
||||
setKeyboard(true);
|
||||
};
|
||||
|
||||
const _onKeyboardHide = () => {
|
||||
setKeyboard(false);
|
||||
};
|
||||
}, [next]);
|
||||
|
||||
useEffect(() => {
|
||||
toastMessages = [];
|
||||
let sub1 = Keyboard.addListener("keyboardDidShow", _onKeyboardShow);
|
||||
let sub2 = Keyboard.addListener("keyboardDidHide", _onKeyboardHide);
|
||||
eSubscribeEvent(eShowToast, showToastFunc);
|
||||
eSubscribeEvent(eHideToast, hideToastFunc);
|
||||
eSubscribeEvent(eShowToast, show);
|
||||
eSubscribeEvent(eHideToast, hide);
|
||||
return () => {
|
||||
if (hideTimeout.current) {
|
||||
clearTimeout(hideTimeout.current);
|
||||
}
|
||||
|
||||
toastMessages = [];
|
||||
sub1?.remove();
|
||||
sub2?.remove();
|
||||
eUnSubscribeEvent(eShowToast, showToastFunc);
|
||||
eUnSubscribeEvent(eHideToast, hideToastFunc);
|
||||
toastMessages.current = [];
|
||||
eUnSubscribeEvent(eShowToast, show);
|
||||
eUnSubscribeEvent(eHideToast, hide);
|
||||
};
|
||||
}, [hideToastFunc, keyboard, showToastFunc]);
|
||||
}, [hide, show]);
|
||||
|
||||
return (
|
||||
visible && (
|
||||
<TouchableOpacity
|
||||
onPress={() => {
|
||||
if (hideTimeout.current) {
|
||||
clearTimeout(hideTimeout.current);
|
||||
}
|
||||
hideToastFunc();
|
||||
}}
|
||||
onPress={hide}
|
||||
activeOpacity={1}
|
||||
style={{
|
||||
width: DDS.isTab ? 400 : "100%",
|
||||
@@ -209,7 +189,7 @@ export const Toast = ({ context = "global" }) => {
|
||||
color={colors.pri}
|
||||
size={SIZE.md}
|
||||
onPress={() => {
|
||||
hideToastFunc();
|
||||
hide();
|
||||
}}
|
||||
>
|
||||
{data.heading}
|
||||
@@ -224,7 +204,7 @@ export const Toast = ({ context = "global" }) => {
|
||||
paddingRight: 10
|
||||
}}
|
||||
onPress={() => {
|
||||
hideToastFunc();
|
||||
hide();
|
||||
}}
|
||||
>
|
||||
{data.message}
|
||||
|
||||
@@ -19,4 +19,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { FeatureType } from "./components/sheets/new-feature";
|
||||
|
||||
export const features: FeatureType[] = [];
|
||||
export const features: FeatureType[] = [
|
||||
{
|
||||
title: "Default font size & font family",
|
||||
body: "Now you can set default font size and font family in editor that will be used across all your new and old notes."
|
||||
}
|
||||
];
|
||||
|
||||
@@ -52,7 +52,11 @@ import { useThemeStore } from "../stores/use-theme-store";
|
||||
import { useUserStore } from "../stores/use-user-store";
|
||||
import { toTXT } from "../utils";
|
||||
import { toggleDarkMode } from "../utils/color-scheme/utils";
|
||||
import { eOpenAddTopicDialog, eOpenLoginDialog } from "../utils/events";
|
||||
import {
|
||||
eOnTopicSheetUpdate,
|
||||
eOpenAddTopicDialog,
|
||||
eOpenLoginDialog
|
||||
} from "../utils/events";
|
||||
import { deleteItems } from "../utils/functions";
|
||||
import { sleep } from "../utils/time";
|
||||
|
||||
@@ -144,13 +148,7 @@ export const useActions = ({ close = () => null, item }) => {
|
||||
if (!item.id) return;
|
||||
close();
|
||||
await db.notes.note(item.id).favorite();
|
||||
Navigation.queueRoutesForUpdate(
|
||||
"TaggedNotes",
|
||||
"ColoredNotes",
|
||||
"TopicNotes",
|
||||
"Favorites",
|
||||
"Notes"
|
||||
);
|
||||
Navigation.queueRoutesForUpdate();
|
||||
}
|
||||
|
||||
async function pinItem() {
|
||||
@@ -158,14 +156,7 @@ export const useActions = ({ close = () => null, item }) => {
|
||||
close();
|
||||
let type = item.type;
|
||||
await db[`${type}s`][type](item.id).pin();
|
||||
Navigation.queueRoutesForUpdate(
|
||||
"TaggedNotes",
|
||||
"ColoredNotes",
|
||||
"TopicNotes",
|
||||
"Favorites",
|
||||
"Notes",
|
||||
"Notebooks"
|
||||
);
|
||||
Navigation.queueRoutesForUpdate();
|
||||
}
|
||||
|
||||
async function pinToNotifications() {
|
||||
@@ -179,9 +170,17 @@ export const useActions = ({ close = () => null, item }) => {
|
||||
checkNotifPinned();
|
||||
return;
|
||||
}
|
||||
if (item.locked) return;
|
||||
let html = await db.notes.note(item.id).content();
|
||||
let text = await toTXT(item);
|
||||
if (item.locked) {
|
||||
ToastEvent.show({
|
||||
heading: "Note is locked",
|
||||
type: "error",
|
||||
message: "Locked notes cannot be pinned to notifications",
|
||||
context: "local"
|
||||
});
|
||||
return;
|
||||
}
|
||||
let text = await toTXT(item, false);
|
||||
let html = text.replace(/\n/g, "<br />");
|
||||
Notifications.displayNotification({
|
||||
title: item.title,
|
||||
message: item.headline || text,
|
||||
@@ -200,15 +199,7 @@ export const useActions = ({ close = () => null, item }) => {
|
||||
if (!checkNoteSynced()) return;
|
||||
close();
|
||||
await db.trash.restore(item.id);
|
||||
Navigation.queueRoutesForUpdate(
|
||||
"TaggedNotes",
|
||||
"ColoredNotes",
|
||||
"TopicNotes",
|
||||
"Favorites",
|
||||
"Notes",
|
||||
"Notebooks",
|
||||
"Trash"
|
||||
);
|
||||
Navigation.queueRoutesForUpdate();
|
||||
let type = item.type === "trash" ? item.itemType : item.type;
|
||||
ToastEvent.show({
|
||||
heading:
|
||||
@@ -324,13 +315,7 @@ export const useActions = ({ close = () => null, item }) => {
|
||||
let note = db.notes.note(item.id).data;
|
||||
if (note.locked) {
|
||||
close();
|
||||
Navigation.queueRoutesForUpdate(
|
||||
"TaggedNotes",
|
||||
"ColoredNotes",
|
||||
"TopicNotes",
|
||||
"Favorites",
|
||||
"Notes"
|
||||
);
|
||||
Navigation.queueRoutesForUpdate();
|
||||
}
|
||||
} catch (e) {
|
||||
close();
|
||||
@@ -396,16 +381,11 @@ export const useActions = ({ close = () => null, item }) => {
|
||||
positivePress: async (value) => {
|
||||
if (!value || value === "" || value.trimStart().length == 0) return;
|
||||
await db.tags.rename(item.id, db.tags.sanitize(value));
|
||||
useTagStore.getState().setTags();
|
||||
useMenuStore.getState().setMenuPins();
|
||||
Navigation.queueRoutesForUpdate(
|
||||
"TaggedNotes",
|
||||
"ColoredNotes",
|
||||
"TopicNotes",
|
||||
"Favorites",
|
||||
"Notes",
|
||||
"Tags"
|
||||
);
|
||||
setImmediate(() => {
|
||||
useTagStore.getState().setTags();
|
||||
useMenuStore.getState().setMenuPins();
|
||||
Navigation.queueRoutesForUpdate();
|
||||
});
|
||||
},
|
||||
input: true,
|
||||
defaultValue: alias,
|
||||
@@ -448,24 +428,16 @@ export const useActions = ({ close = () => null, item }) => {
|
||||
? "This reminder will be removed"
|
||||
: "This tag will be removed from all notes.",
|
||||
positivePress: async () => {
|
||||
const routes = [];
|
||||
routes.push(
|
||||
"TaggedNotes",
|
||||
"ColoredNotes",
|
||||
"Notes",
|
||||
"NotesPage",
|
||||
"Reminders",
|
||||
"Favorites"
|
||||
);
|
||||
if (item.type === "reminder") {
|
||||
await db.reminders.remove(item.id);
|
||||
} else {
|
||||
await db.tags.remove(item.id);
|
||||
useTagStore.getState().setTags();
|
||||
routes.push("Tags");
|
||||
}
|
||||
Navigation.queueRoutesForUpdate(...routes);
|
||||
useRelationStore.getState().update();
|
||||
setImmediate(() => {
|
||||
useTagStore.getState().setTags();
|
||||
Navigation.queueRoutesForUpdate();
|
||||
useRelationStore.getState().update();
|
||||
});
|
||||
},
|
||||
positiveText: "Delete",
|
||||
positiveType: "errorShade"
|
||||
@@ -503,15 +475,8 @@ export const useActions = ({ close = () => null, item }) => {
|
||||
},
|
||||
item.id
|
||||
);
|
||||
Navigation.queueRoutesForUpdate(
|
||||
"TaggedNotes",
|
||||
"ColoredNotes",
|
||||
"TopicNotes",
|
||||
"Favorites",
|
||||
"Notes",
|
||||
"Notebook",
|
||||
"Notebooks"
|
||||
);
|
||||
Navigation.queueRoutesForUpdate();
|
||||
eSendEvent(eOnTopicSheetUpdate);
|
||||
close();
|
||||
}
|
||||
|
||||
@@ -519,15 +484,7 @@ export const useActions = ({ close = () => null, item }) => {
|
||||
const currentScreen = useNavigationStore.getState().currentScreen;
|
||||
if (currentScreen.name !== "Notebook") return;
|
||||
await db.relations.unlink({ type: "notebook", id: currentScreen.id }, item);
|
||||
Navigation.queueRoutesForUpdate(
|
||||
"TaggedNotes",
|
||||
"ColoredNotes",
|
||||
"TopicNotes",
|
||||
"Favorites",
|
||||
"Notes",
|
||||
"Notebook",
|
||||
"Notebooks"
|
||||
);
|
||||
Navigation.queueRoutesForUpdate();
|
||||
close();
|
||||
}
|
||||
|
||||
@@ -542,12 +499,14 @@ export const useActions = ({ close = () => null, item }) => {
|
||||
negativeText: "Cancel",
|
||||
positivePress: async () => {
|
||||
await db.trash.delete(item.id);
|
||||
Navigation.queueRoutesForUpdate("Trash");
|
||||
useSelectionStore.getState().setSelectionMode(false);
|
||||
ToastEvent.show({
|
||||
heading: "Permanantly deleted items",
|
||||
type: "success",
|
||||
context: "local"
|
||||
setImmediate(() => {
|
||||
Navigation.queueRoutesForUpdate();
|
||||
useSelectionStore.getState().setSelectionMode(false);
|
||||
ToastEvent.show({
|
||||
heading: "Permanantly deleted items",
|
||||
type: "success",
|
||||
context: "local"
|
||||
});
|
||||
});
|
||||
},
|
||||
positiveType: "errorShade"
|
||||
@@ -565,19 +524,22 @@ export const useActions = ({ close = () => null, item }) => {
|
||||
}
|
||||
|
||||
async function exportNote() {
|
||||
if (item.locked) {
|
||||
ToastEvent.show({
|
||||
heading: "Note is locked",
|
||||
type: "error",
|
||||
message: "Locked notes cannot be exported",
|
||||
context: "local"
|
||||
});
|
||||
return;
|
||||
}
|
||||
ExportNotesSheet.present([item]);
|
||||
}
|
||||
|
||||
async function toggleLocalOnly() {
|
||||
if (!checkNoteSynced() || !user) return;
|
||||
db.notes.note(item.id).localOnly();
|
||||
Navigation.queueRoutesForUpdate(
|
||||
"TaggedNotes",
|
||||
"ColoredNotes",
|
||||
"TopicNotes",
|
||||
"Favorites",
|
||||
"Notes"
|
||||
);
|
||||
Navigation.queueRoutesForUpdate();
|
||||
close();
|
||||
}
|
||||
|
||||
@@ -588,26 +550,14 @@ export const useActions = ({ close = () => null, item }) => {
|
||||
useEditorStore.getState().setReadonly(current);
|
||||
// tiny.call(EditorWebView, tiny.toogleReadMode(current ? 'readonly' : 'design'));
|
||||
}
|
||||
Navigation.queueRoutesForUpdate(
|
||||
"TaggedNotes",
|
||||
"ColoredNotes",
|
||||
"TopicNotes",
|
||||
"Favorites",
|
||||
"Notes"
|
||||
);
|
||||
Navigation.queueRoutesForUpdate();
|
||||
close();
|
||||
};
|
||||
|
||||
const duplicateNote = async () => {
|
||||
if (!checkNoteSynced()) return;
|
||||
await db.notes.note(item.id).duplicate();
|
||||
Navigation.queueRoutesForUpdate(
|
||||
"TaggedNotes",
|
||||
"ColoredNotes",
|
||||
"TopicNotes",
|
||||
"Favorites",
|
||||
"Notes"
|
||||
);
|
||||
Navigation.queueRoutesForUpdate();
|
||||
close();
|
||||
};
|
||||
const actions = [
|
||||
@@ -663,7 +613,7 @@ export const useActions = ({ close = () => null, item }) => {
|
||||
},
|
||||
{
|
||||
id: "pin",
|
||||
title: item.pinned ? "Unpin" : "Pin",
|
||||
title: "Pin",
|
||||
icon: item.pinned ? "pin-off-outline" : "pin-outline",
|
||||
func: pinItem,
|
||||
close: false,
|
||||
@@ -673,7 +623,7 @@ export const useActions = ({ close = () => null, item }) => {
|
||||
},
|
||||
{
|
||||
id: "favorite",
|
||||
title: !item.favorite ? "Favorite" : "Unfavorite",
|
||||
title: "Favorite",
|
||||
icon: item.favorite ? "star-off" : "star-outline",
|
||||
func: addToFavorites,
|
||||
close: false,
|
||||
@@ -686,7 +636,7 @@ export const useActions = ({ close = () => null, item }) => {
|
||||
id: "pin-to-notifications",
|
||||
title:
|
||||
notifPinned !== null
|
||||
? "Unpin from Notifications"
|
||||
? "Unpin from notifications"
|
||||
: "Pin to notifications",
|
||||
icon: "message-badge-outline",
|
||||
on: notifPinned !== null,
|
||||
@@ -835,15 +785,7 @@ export const useActions = ({ close = () => null, item }) => {
|
||||
});
|
||||
Notifications.scheduleNotification(item);
|
||||
useRelationStore.getState().update();
|
||||
Navigation.queueRoutesForUpdate(
|
||||
"TaggedNotes",
|
||||
"ColoredNotes",
|
||||
"TopicNotes",
|
||||
"Favorites",
|
||||
"Notes",
|
||||
"NotesPage",
|
||||
"Reminders"
|
||||
);
|
||||
Navigation.queueRoutesForUpdate();
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -558,7 +558,7 @@ export const useAppEvents = () => {
|
||||
let shareExtensionOpened = MMKV.getString("shareExtensionOpened");
|
||||
if (notesAddedFromIntent) {
|
||||
if (Platform.OS === "ios") {
|
||||
await db.init();
|
||||
await db.initCollections();
|
||||
await db.notes.init();
|
||||
}
|
||||
useNoteStore.getState().setNotes();
|
||||
@@ -571,8 +571,8 @@ export const useAppEvents = () => {
|
||||
if (notesAddedFromIntent || shareExtensionOpened) {
|
||||
let id = useEditorStore.getState().currentEditingNote;
|
||||
let note = id && db.notes.note(id).data;
|
||||
eSendEvent("loadingNote", note);
|
||||
eSendEvent("webview_reset");
|
||||
setTimeout(() => eSendEvent("loadingNote", note), 1);
|
||||
MMKV.removeItem("shareExtensionOpened");
|
||||
}
|
||||
} catch (e) {
|
||||
|
||||
@@ -17,35 +17,46 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { useState } from "react";
|
||||
import { useAttachmentStore } from "../stores/use-attachment-store";
|
||||
|
||||
export const useAttachmentProgress = (attachment, encryption) => {
|
||||
type AttachmentProgress = {
|
||||
type: string;
|
||||
value?: number;
|
||||
percent?: string;
|
||||
};
|
||||
|
||||
export const useAttachmentProgress = (
|
||||
attachment: any,
|
||||
encryption?: boolean
|
||||
) => {
|
||||
const progress = useAttachmentStore((state) => state.progress);
|
||||
const [currentProgress, setCurrentProgress] = useState(
|
||||
const [currentProgress, setCurrentProgress] = useState<
|
||||
AttachmentProgress | undefined
|
||||
>(
|
||||
encryption
|
||||
? {
|
||||
type: "encrypt"
|
||||
}
|
||||
: null
|
||||
: undefined
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
let prog = progress[attachment.metadata.hash];
|
||||
if (prog) {
|
||||
let type = prog.type;
|
||||
let loaded = prog.type === "download" ? prog.recieved : prog.sent;
|
||||
prog = loaded / prog.total;
|
||||
prog = (prog * 100).toFixed(0);
|
||||
setCurrentProgress({
|
||||
value: prog,
|
||||
percent: prog + "%",
|
||||
type: type
|
||||
});
|
||||
} else {
|
||||
setCurrentProgress(null);
|
||||
}
|
||||
}, [attachment.metadata.hash, progress]);
|
||||
const attachmentProgress = progress?.[attachment.metadata.hash];
|
||||
if (attachmentProgress) {
|
||||
const type = attachmentProgress.type;
|
||||
const loaded =
|
||||
attachmentProgress.type === "download"
|
||||
? attachmentProgress.recieved
|
||||
: attachmentProgress.sent;
|
||||
const value = loaded / attachmentProgress.total;
|
||||
setCurrentProgress({
|
||||
value: value * 100,
|
||||
percent: (value * 100).toFixed(0) + "%",
|
||||
type: type
|
||||
});
|
||||
} else {
|
||||
setCurrentProgress(undefined);
|
||||
}
|
||||
|
||||
return [currentProgress, setCurrentProgress];
|
||||
};
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
This file is part of the Notesnook project (https://notesnook.com/)
|
||||
|
||||
Copyright (C) 2023 Streetwriters (Private) Limited
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import React, { useCallback, useEffect } from "react";
|
||||
import BiometicService from "../services/biometrics";
|
||||
import { eSubscribeEvent, eUnSubscribeEvent } from "../services/event-manager";
|
||||
import { db } from "../common/database";
|
||||
|
||||
const VaultStatusCache = {
|
||||
exists: false,
|
||||
biometryEnrolled: false,
|
||||
isBiometryAvailable: false
|
||||
};
|
||||
|
||||
export const useVaultStatus = () => {
|
||||
const [vaultStatus, setVaultStatus] = React.useState(VaultStatusCache);
|
||||
|
||||
const checkVaultStatus = useCallback(() => {
|
||||
db.vault.exists().then(async (exists) => {
|
||||
let available = await BiometicService.isBiometryAvailable();
|
||||
let fingerprint = await BiometicService.hasInternetCredentials();
|
||||
if (
|
||||
VaultStatusCache.exists === exists &&
|
||||
VaultStatusCache.biometryEnrolled === fingerprint &&
|
||||
VaultStatusCache.isBiometryAvailable === available
|
||||
)
|
||||
return;
|
||||
setVaultStatus({
|
||||
exists: exists,
|
||||
biometryEnrolled: fingerprint,
|
||||
isBiometryAvailable: available ? true : false
|
||||
});
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
checkVaultStatus();
|
||||
eSubscribeEvent("vaultUpdated", () => checkVaultStatus());
|
||||
return () => {
|
||||
eUnSubscribeEvent("vaultUpdated", () => checkVaultStatus());
|
||||
};
|
||||
}, [checkVaultStatus]);
|
||||
|
||||
return vaultStatus;
|
||||
};
|
||||
@@ -69,6 +69,7 @@ import {
|
||||
import { editorRef, tabBarRef } from "../utils/global-refs";
|
||||
import { sleep } from "../utils/time";
|
||||
import { NavigationStack } from "./navigation-stack";
|
||||
import changeNavigationBarColor from "react-native-navigation-bar-color";
|
||||
|
||||
const _TabsHolder = () => {
|
||||
const colors = useThemeStore((state) => state.colors);
|
||||
@@ -386,6 +387,10 @@ const _TabsHolder = () => {
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
changeNavigationBarColor(colors.bg, !colors.night, true);
|
||||
}, [colors.night, colors.bg]);
|
||||
|
||||
return (
|
||||
<View
|
||||
onLayout={_onLayout}
|
||||
|
||||
@@ -4,18 +4,16 @@
|
||||
"main": "./App.js",
|
||||
"license": "GPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
"react": "18.0.0",
|
||||
"react-native": "0.69.7",
|
||||
"@flyerhq/react-native-link-preview": "^1.6.0",
|
||||
"@mdi/js": "^6.7.96",
|
||||
"absolutify": "^0.1.0",
|
||||
"buffer": "^6.0.3",
|
||||
"dayjs": "^1.10.4",
|
||||
"entities": "^3.0.1",
|
||||
"html-to-text": "8.1.0",
|
||||
"html-to-text": "9.0.5",
|
||||
"phone": "^3.1.14",
|
||||
"qclone": "^1.2.0",
|
||||
"react-native-actions-sheet": "^0.9.0-alpha.14",
|
||||
"react-native-actions-sheet": "0.9.0-alpha.18",
|
||||
"react-native-check-version": "https://github.com/flexible-agency/react-native-check-version",
|
||||
"react-native-drax": "^0.10.2",
|
||||
"react-native-image-zoom-viewer": "^3.0.1",
|
||||
|
||||
@@ -24,6 +24,7 @@ import React, {
|
||||
useCallback,
|
||||
useEffect,
|
||||
useImperativeHandle,
|
||||
useRef,
|
||||
useState
|
||||
} from "react";
|
||||
import { Platform, ViewStyle } from "react-native";
|
||||
@@ -89,7 +90,7 @@ const Editor = React.memo(
|
||||
noToolbar,
|
||||
noHeader
|
||||
});
|
||||
|
||||
const renderKey = useRef(`editor-0`);
|
||||
useImperativeHandle(ref, () => ({
|
||||
get: () => editor
|
||||
}));
|
||||
@@ -124,6 +125,8 @@ const Editor = React.memo(
|
||||
);
|
||||
|
||||
const onError = useCallback(() => {
|
||||
renderKey.current =
|
||||
renderKey.current === `editor-0` ? `editor-1` : `editor-0`;
|
||||
editor.setLoading(true);
|
||||
setTimeout(() => editor.setLoading(false), 10);
|
||||
}, [editor]);
|
||||
@@ -152,6 +155,7 @@ const Editor = React.memo(
|
||||
testID={notesnook.editor.id}
|
||||
ref={editor.ref}
|
||||
onLoad={editor.onLoad}
|
||||
key={renderKey.current}
|
||||
onRenderProcessGone={onError}
|
||||
nestedScrollEnabled
|
||||
onError={onError}
|
||||
|
||||
@@ -28,12 +28,12 @@ import { Button } from "../../components/ui/button";
|
||||
import { IconButton } from "../../components/ui/icon-button";
|
||||
import Paragraph from "../../components/ui/typography/paragraph";
|
||||
import useGlobalSafeAreaInsets from "../../hooks/use-global-safe-area-insets";
|
||||
import { DDS } from "../../services/device-detection";
|
||||
import {
|
||||
eSendEvent,
|
||||
eSubscribeEvent,
|
||||
eUnSubscribeEvent
|
||||
} from "../../services/event-manager";
|
||||
import { useSettingStore } from "../../stores/use-setting-store";
|
||||
import { useThemeStore } from "../../stores/use-theme-store";
|
||||
import { eClearEditor } from "../../utils/events";
|
||||
import { SIZE } from "../../utils/size";
|
||||
@@ -42,7 +42,9 @@ const EditorOverlay = ({ editorId = "", editor }) => {
|
||||
const colors = useThemeStore((state) => state.colors);
|
||||
const [error, setError] = useState(false);
|
||||
const opacity = useSharedValue(1);
|
||||
const translateValue = useSharedValue(6000);
|
||||
const translateValue = useSharedValue(0);
|
||||
const deviceMode = useSettingStore((state) => state.deviceMode);
|
||||
const isTablet = deviceMode !== "mobile";
|
||||
const insets = useGlobalSafeAreaInsets();
|
||||
const isDefaultEditor = editorId === "";
|
||||
const timers = useRef({
|
||||
@@ -50,6 +52,9 @@ const EditorOverlay = ({ editorId = "", editor }) => {
|
||||
error: 0,
|
||||
closing: 0
|
||||
});
|
||||
const loadingState = useRef({
|
||||
startTime: 0
|
||||
});
|
||||
|
||||
const clearTimers = () => {
|
||||
clearTimeout(timers.current.loading);
|
||||
@@ -62,6 +67,7 @@ const EditorOverlay = ({ editorId = "", editor }) => {
|
||||
editorState().overlay = true;
|
||||
clearTimers();
|
||||
if (_loading) {
|
||||
loadingState.current.startTime = Date.now();
|
||||
opacity.value = 1;
|
||||
translateValue.value = 0;
|
||||
timers.current.error = setTimeout(() => {
|
||||
@@ -69,7 +75,14 @@ const EditorOverlay = ({ editorId = "", editor }) => {
|
||||
}, 15 * 1000);
|
||||
} else {
|
||||
clearTimers();
|
||||
setTimeout(() => {
|
||||
const timeDiffSinceLoadStarted =
|
||||
Date.now() - loadingState.current.startTime > 300 ? 300 : 0;
|
||||
if (!timeDiffSinceLoadStarted) {
|
||||
setError(false);
|
||||
editorState().overlay = false;
|
||||
opacity.value = 0;
|
||||
translateValue.value = 6000;
|
||||
} else {
|
||||
setError(false);
|
||||
editorState().overlay = false;
|
||||
opacity.value = withTiming(0, {
|
||||
@@ -78,19 +91,24 @@ const EditorOverlay = ({ editorId = "", editor }) => {
|
||||
setTimeout(() => {
|
||||
translateValue.value = 6000;
|
||||
}, 500);
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
},
|
||||
[opacity, translateValue]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setTimeout(() => {
|
||||
if (!loadingState.current.startTime) {
|
||||
translateValue.value = 6000;
|
||||
}
|
||||
}, 1000);
|
||||
eSubscribeEvent("loadingNote" + editorId, load);
|
||||
return () => {
|
||||
clearTimers();
|
||||
eUnSubscribeEvent("loadingNote" + editorId, load);
|
||||
};
|
||||
}, [editorId, load]);
|
||||
}, [editorId, load, translateValue]);
|
||||
|
||||
const animatedStyle = useAnimatedStyle(() => {
|
||||
return {
|
||||
@@ -140,7 +158,7 @@ const EditorOverlay = ({ editorId = "", editor }) => {
|
||||
paddingRight: 12
|
||||
}}
|
||||
>
|
||||
{DDS.isTablet() ? (
|
||||
{isTablet ? (
|
||||
<View />
|
||||
) : (
|
||||
<IconButton
|
||||
@@ -184,7 +202,9 @@ const EditorOverlay = ({ editorId = "", editor }) => {
|
||||
alignItems: "center",
|
||||
flexDirection: "row",
|
||||
paddingHorizontal: 10,
|
||||
marginTop: 10
|
||||
marginTop: 5,
|
||||
borderWidth: 1,
|
||||
borderColor: colors.border
|
||||
}}
|
||||
>
|
||||
<Paragraph color={colors.icon} size={13}>
|
||||
|
||||
@@ -106,6 +106,7 @@ typeof globalThis.editorTitle !== "undefined" && editorTitle.current && editorTi
|
||||
if (editorController.content) editorController.content.current = null;
|
||||
editorController.onUpdate();
|
||||
editorController.setTitle(null);
|
||||
editorController.countWords(0);
|
||||
typeof globalThis.statusBar !== "undefined" && statusBar.current.set({date:"",saved:""});
|
||||
`
|
||||
);
|
||||
@@ -237,6 +238,10 @@ typeof globalThis.statusBar !== "undefined" && statusBar.current.set({date:"",sa
|
||||
'response = window.dispatchEvent(new Event("handleBackPress",{cancelable:true}));'
|
||||
);
|
||||
};
|
||||
|
||||
keyboardShown = async (keyboardShown: boolean) => {
|
||||
return this.doAsync(`globalThis['keyboardShown']=${keyboardShown};`);
|
||||
};
|
||||
//todo add replace image function
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +48,8 @@ export type Settings = {
|
||||
keyboardShown?: boolean;
|
||||
doubleSpacedLines?: boolean;
|
||||
corsProxy: string;
|
||||
fontSize: string;
|
||||
fontFamily: string;
|
||||
};
|
||||
|
||||
export type EditorProps = {
|
||||
|
||||
@@ -25,6 +25,8 @@ import { useCallback, useEffect, useRef } from "react";
|
||||
import {
|
||||
BackHandler,
|
||||
InteractionManager,
|
||||
Keyboard,
|
||||
KeyboardEventListener,
|
||||
NativeEventSubscription
|
||||
} from "react-native";
|
||||
import { WebViewMessageEvent } from "react-native-webview";
|
||||
@@ -32,13 +34,12 @@ import { db } from "../../../common/database";
|
||||
import ManageTagsSheet from "../../../components/sheets/manage-tags";
|
||||
import { RelationsList } from "../../../components/sheets/relations-list";
|
||||
import ReminderSheet from "../../../components/sheets/reminder";
|
||||
import useKeyboard from "../../../hooks/use-keyboard";
|
||||
import { DDS } from "../../../services/device-detection";
|
||||
import {
|
||||
ToastEvent,
|
||||
eSendEvent,
|
||||
eSubscribeEvent,
|
||||
eUnSubscribeEvent,
|
||||
ToastEvent
|
||||
eUnSubscribeEvent
|
||||
} from "../../../services/event-manager";
|
||||
import Navigation from "../../../services/navigation";
|
||||
import { useEditorStore } from "../../../stores/use-editor-store";
|
||||
@@ -135,8 +136,30 @@ export const useEditorEvents = (
|
||||
const doubleSpacedLines = useSettingStore(
|
||||
(state) => state.settings?.doubleSpacedLines
|
||||
);
|
||||
const defaultFontSize = useSettingStore(
|
||||
(state) => state.settings.defaultFontSize
|
||||
);
|
||||
const defaultFontFamily = useSettingStore(
|
||||
(state) => state.settings.defaultFontFamily
|
||||
);
|
||||
|
||||
const tools = useDragState((state) => state.data);
|
||||
const { keyboardShown } = useKeyboard();
|
||||
|
||||
useEffect(() => {
|
||||
const handleKeyboardDidShow: KeyboardEventListener = () => {
|
||||
editor.commands.keyboardShown(true);
|
||||
};
|
||||
const handleKeyboardDidHide: KeyboardEventListener = () => {
|
||||
editor.commands.keyboardShown(false);
|
||||
};
|
||||
const subscriptions = [
|
||||
Keyboard.addListener("keyboardDidShow", handleKeyboardDidShow),
|
||||
Keyboard.addListener("keyboardDidHide", handleKeyboardDidHide)
|
||||
];
|
||||
return () => {
|
||||
subscriptions.forEach((subscription) => subscription.remove());
|
||||
};
|
||||
}, [editor.commands]);
|
||||
|
||||
useEffect(() => {
|
||||
editor.commands.setSettings({
|
||||
@@ -147,9 +170,10 @@ export const useEditorEvents = (
|
||||
tools: tools || getDefaultPresets().default,
|
||||
noHeader: noHeader,
|
||||
noToolbar: readonly || editorPropReadonly || noToolbar,
|
||||
keyboardShown: keyboardShown || false,
|
||||
doubleSpacedLines: doubleSpacedLines,
|
||||
corsProxy: corsProxy
|
||||
corsProxy: corsProxy,
|
||||
fontSize: defaultFontSize,
|
||||
fontFamily: defaultFontFamily
|
||||
});
|
||||
}, [
|
||||
fullscreen,
|
||||
@@ -160,12 +184,13 @@ export const useEditorEvents = (
|
||||
deviceMode,
|
||||
tools,
|
||||
editor.commands,
|
||||
keyboardShown,
|
||||
doubleSpacedLines,
|
||||
editorPropReadonly,
|
||||
noHeader,
|
||||
noToolbar,
|
||||
corsProxy
|
||||
corsProxy,
|
||||
defaultFontSize,
|
||||
defaultFontFamily
|
||||
]);
|
||||
|
||||
const onBackPress = useCallback(async () => {
|
||||
@@ -189,12 +214,7 @@ export const useEditorEvents = (
|
||||
setImmediate(() => {
|
||||
useEditorStore.getState().setCurrentlyEditingNote(null);
|
||||
setTimeout(() => {
|
||||
Navigation.queueRoutesForUpdate(
|
||||
"ColoredNotes",
|
||||
"Notes",
|
||||
"TaggedNotes",
|
||||
"TopicNotes"
|
||||
);
|
||||
Navigation.queueRoutesForUpdate();
|
||||
}, 500);
|
||||
});
|
||||
editorState().currentlyEditing = false;
|
||||
@@ -273,12 +293,28 @@ export const useEditorEvents = (
|
||||
(event: WebViewMessageEvent) => {
|
||||
const data = event.nativeEvent.data;
|
||||
const editorMessage = JSON.parse(data) as EditorMessage;
|
||||
|
||||
if (editorMessage.type === EventTypes.content) {
|
||||
editor.saveContent({
|
||||
type: editorMessage.type,
|
||||
content: editorMessage.value as string,
|
||||
forSessionId: editorMessage.sessionId
|
||||
});
|
||||
} else if (editorMessage.type === EventTypes.title) {
|
||||
editor.saveContent({
|
||||
type: editorMessage.type,
|
||||
title: editorMessage.value as string,
|
||||
forSessionId: editorMessage.sessionId
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
editorMessage.sessionId !== editor.sessionId &&
|
||||
editorMessage.type !== EditorEvents.status
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (editorMessage.type) {
|
||||
case EventTypes.logger:
|
||||
logger.info("[WEBVIEW LOG]", editorMessage.value);
|
||||
@@ -286,21 +322,8 @@ export const useEditorEvents = (
|
||||
case EventTypes.contentchange:
|
||||
editor.onContentChanged();
|
||||
break;
|
||||
case EventTypes.content:
|
||||
editor.saveContent({
|
||||
type: editorMessage.type,
|
||||
content: editorMessage.value as string
|
||||
});
|
||||
break;
|
||||
case EventTypes.selection:
|
||||
break;
|
||||
case EventTypes.title:
|
||||
editor.saveContent({
|
||||
type: editorMessage.type,
|
||||
title: editorMessage.value as string
|
||||
});
|
||||
break;
|
||||
|
||||
case EventTypes.reminders:
|
||||
if (!editor.note.current) {
|
||||
ToastEvent.show({
|
||||
@@ -337,13 +360,7 @@ export const useEditorEvents = (
|
||||
.then(async () => {
|
||||
useTagStore.getState().setTags();
|
||||
await editor.commands.setTags(editor.note.current);
|
||||
Navigation.queueRoutesForUpdate(
|
||||
"ColoredNotes",
|
||||
"Notes",
|
||||
"TaggedNotes",
|
||||
"TopicNotes",
|
||||
"Tags"
|
||||
);
|
||||
Navigation.queueRoutesForUpdate();
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -43,9 +43,9 @@ import { NoteType } from "../../../utils/types";
|
||||
import Commands from "./commands";
|
||||
import { Content, EditorState, Note, SavePayload } from "./types";
|
||||
import {
|
||||
EditorEvents,
|
||||
clearAppState,
|
||||
defaultState,
|
||||
EditorEvents,
|
||||
getAppState,
|
||||
isContentInvalid,
|
||||
isEditorLoaded,
|
||||
@@ -77,6 +77,7 @@ export const useEditor = (
|
||||
const lastContentChangeTime = useRef<number>(0);
|
||||
const lock = useRef(false);
|
||||
const loadedImages = useRef<{ [name: string]: boolean }>({});
|
||||
const lockedSessionId = useRef<string>();
|
||||
|
||||
const postMessage = useCallback(
|
||||
async <T>(type: string, data: T) =>
|
||||
@@ -119,29 +120,9 @@ export const useEditor = (
|
||||
[editorId]
|
||||
);
|
||||
|
||||
const onReady = useCallback(async () => {
|
||||
if (!(await isEditorLoaded(editorRef, sessionIdRef.current))) {
|
||||
overlay(true);
|
||||
setLoading(true);
|
||||
}
|
||||
}, [overlay]);
|
||||
|
||||
useEffect(() => {
|
||||
state.current.saveCount = 0;
|
||||
async () => {
|
||||
await commands.setSessionId(sessionIdRef.current);
|
||||
if (sessionIdRef.current) {
|
||||
if (!state.current?.ready) return;
|
||||
await onReady();
|
||||
}
|
||||
};
|
||||
}, [sessionId, loading, commands, onReady]);
|
||||
|
||||
useEffect(() => {
|
||||
if (loading) {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [loading]);
|
||||
if (loading) {
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
const withTimer = useCallback(
|
||||
(id: string, fn: () => void, duration: number) => {
|
||||
@@ -152,7 +133,7 @@ export const useEditor = (
|
||||
);
|
||||
|
||||
const reset = useCallback(
|
||||
async (resetState = true) => {
|
||||
async (resetState = true, resetContent = true) => {
|
||||
currentNote.current?.id && db.fs.cancel(currentNote.current.id);
|
||||
currentNote.current = null;
|
||||
loadedImages.current = {};
|
||||
@@ -161,10 +142,10 @@ export const useEditor = (
|
||||
sessionHistoryId.current = undefined;
|
||||
saveCount.current = 0;
|
||||
useEditorStore.getState().setReadonly(false);
|
||||
postMessage(EditorEvents.title, "");
|
||||
resetContent && postMessage(EditorEvents.title, "");
|
||||
lastContentChangeTime.current = 0;
|
||||
await commands.clearContent();
|
||||
await commands.clearTags();
|
||||
resetContent && (await commands.clearContent());
|
||||
resetContent && (await commands.clearTags());
|
||||
if (resetState) {
|
||||
isDefaultEditor &&
|
||||
useEditorStore.getState().setCurrentlyEditingNote(null);
|
||||
@@ -239,9 +220,15 @@ export const useEditor = (
|
||||
|
||||
if (
|
||||
useEditorStore.getState().currentEditingNote !== id &&
|
||||
isDefaultEditor
|
||||
isDefaultEditor &&
|
||||
state.current.currentlyEditing
|
||||
) {
|
||||
setTimeout(() => {
|
||||
if (
|
||||
(currentNote.current?.id && currentNote.current?.id !== id) ||
|
||||
!state.current.currentlyEditing
|
||||
)
|
||||
return;
|
||||
id && useEditorStore.getState().setCurrentlyEditingNote(id);
|
||||
});
|
||||
}
|
||||
@@ -262,12 +249,7 @@ export const useEditor = (
|
||||
currentNote.current?.headline?.slice(0, 200) !==
|
||||
note.headline?.slice(0, 200)
|
||||
) {
|
||||
Navigation.queueRoutesForUpdate(
|
||||
"ColoredNotes",
|
||||
"Notes",
|
||||
"TaggedNotes",
|
||||
"TopicNotes"
|
||||
);
|
||||
Navigation.queueRoutesForUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -367,16 +349,26 @@ export const useEditor = (
|
||||
useEditorStore.getState().setReadonly(false);
|
||||
} else {
|
||||
if (!item.forced && currentNote.current?.id === item.id) return;
|
||||
state.current.movedAway = false;
|
||||
state.current.currentlyEditing = true;
|
||||
isDefaultEditor && editorState.setCurrentlyEditingNote(item.id);
|
||||
overlay(true, item);
|
||||
currentNote.current && (await reset(false));
|
||||
currentNote.current && (await reset(false, false));
|
||||
await loadContent(item as NoteType);
|
||||
if (
|
||||
!currentContent.current?.data ||
|
||||
currentContent.current?.data.length < 50000
|
||||
) {
|
||||
overlay(false);
|
||||
} else {
|
||||
overlay(true);
|
||||
}
|
||||
lastContentChangeTime.current = item.dateEdited;
|
||||
const nextSessionId = makeSessionId(item as NoteType);
|
||||
lockedSessionId.current = nextSessionId;
|
||||
sessionHistoryId.current = Date.now();
|
||||
setSessionId(nextSessionId);
|
||||
commands.setSessionId(nextSessionId);
|
||||
sessionIdRef.current = nextSessionId;
|
||||
await commands.setSessionId(nextSessionId);
|
||||
currentNote.current = item as NoteType;
|
||||
await commands.setStatus(timeConverter(item.dateEdited), "Saved");
|
||||
await postMessage(EditorEvents.title, item.title);
|
||||
@@ -384,6 +376,11 @@ export const useEditor = (
|
||||
useEditorStore.getState().setReadonly(item.readonly);
|
||||
await commands.setTags(currentNote.current);
|
||||
commands.setSettings();
|
||||
setTimeout(() => {
|
||||
if (lockedSessionId.current === nextSessionId) {
|
||||
lockedSessionId.current = undefined;
|
||||
}
|
||||
}, 300);
|
||||
overlay(false);
|
||||
loadImages();
|
||||
}
|
||||
@@ -490,14 +487,16 @@ export const useEditor = (
|
||||
({
|
||||
title,
|
||||
content,
|
||||
type
|
||||
type,
|
||||
forSessionId
|
||||
}: {
|
||||
title?: string;
|
||||
content?: string;
|
||||
type: string;
|
||||
forSessionId: string;
|
||||
}) => {
|
||||
if (lock.current || lockedSessionId.current === forSessionId) return;
|
||||
lastContentChangeTime.current = Date.now();
|
||||
if (lock.current) return;
|
||||
if (type === EditorEvents.content) {
|
||||
currentContent.current = {
|
||||
data: content,
|
||||
@@ -505,22 +504,27 @@ export const useEditor = (
|
||||
noteId: currentNote.current?.id as string
|
||||
};
|
||||
}
|
||||
const noteIdFromSessionId =
|
||||
!forSessionId || forSessionId.startsWith("session")
|
||||
? null
|
||||
: forSessionId.split("_")[0];
|
||||
|
||||
const noteId = noteIdFromSessionId || currentNote.current?.id;
|
||||
const params = {
|
||||
title,
|
||||
data: content,
|
||||
type: "tiptap",
|
||||
sessionId,
|
||||
id: currentNote.current?.id,
|
||||
sessionId: forSessionId,
|
||||
id: noteId,
|
||||
sessionHistoryId: sessionHistoryId.current
|
||||
};
|
||||
|
||||
withTimer(
|
||||
currentNote.current?.id || "newnote",
|
||||
noteId || "newnote",
|
||||
() => {
|
||||
if (
|
||||
currentNote.current &&
|
||||
!params.id &&
|
||||
params.sessionId === sessionId
|
||||
params.sessionId === forSessionId
|
||||
) {
|
||||
params.id = currentNote.current?.id;
|
||||
}
|
||||
@@ -530,10 +534,10 @@ export const useEditor = (
|
||||
}
|
||||
saveNote(params);
|
||||
},
|
||||
500
|
||||
150
|
||||
);
|
||||
},
|
||||
[sessionId, withTimer, onChange, saveNote]
|
||||
[withTimer, onChange, saveNote]
|
||||
);
|
||||
|
||||
const restoreEditorState = useCallback(async () => {
|
||||
@@ -543,6 +547,7 @@ export const useEditor = (
|
||||
state.current.isRestoringState = true;
|
||||
state.current.currentlyEditing = true;
|
||||
state.current.movedAway = false;
|
||||
|
||||
if (!DDS.isTab) {
|
||||
tabBarRef.current?.goToPage(1, false);
|
||||
}
|
||||
@@ -562,10 +567,6 @@ export const useEditor = (
|
||||
state.current.isRestoringState = false;
|
||||
}, [loadNote, overlay]);
|
||||
|
||||
useEffect(() => {
|
||||
isDefaultEditor && restoreEditorState();
|
||||
}, [isDefaultEditor, restoreEditorState]);
|
||||
|
||||
useEffect(() => {
|
||||
eSubscribeEvent(eOnLoadNote + editorId, loadNote);
|
||||
return () => {
|
||||
@@ -573,6 +574,29 @@ export const useEditor = (
|
||||
};
|
||||
}, [editorId, loadNote, restoreEditorState, isDefaultEditor]);
|
||||
|
||||
const onContentChanged = () => {
|
||||
lastContentChangeTime.current = Date.now();
|
||||
};
|
||||
|
||||
const onReady = useCallback(async () => {
|
||||
if (!(await isEditorLoaded(editorRef, sessionIdRef.current))) {
|
||||
eSendEvent("webview_reset");
|
||||
} else {
|
||||
isDefaultEditor && restoreEditorState();
|
||||
}
|
||||
}, [isDefaultEditor, restoreEditorState]);
|
||||
|
||||
useEffect(() => {
|
||||
state.current.saveCount = 0;
|
||||
(async () => {
|
||||
await commands.setSessionId(sessionIdRef.current);
|
||||
if (sessionIdRef.current) {
|
||||
if (!state.current?.ready) return;
|
||||
await onReady();
|
||||
}
|
||||
})();
|
||||
}, [sessionId, loading, commands, onReady]);
|
||||
|
||||
const onLoad = useCallback(async () => {
|
||||
state.current.ready = true;
|
||||
onReady();
|
||||
@@ -596,10 +620,6 @@ export const useEditor = (
|
||||
loadNote
|
||||
]);
|
||||
|
||||
const onContentChanged = () => {
|
||||
lastContentChangeTime.current = Date.now();
|
||||
};
|
||||
|
||||
return {
|
||||
ref: editorRef,
|
||||
onLoad,
|
||||
@@ -615,6 +635,7 @@ export const useEditor = (
|
||||
saveContent,
|
||||
onContentChanged,
|
||||
editorId: editorId,
|
||||
markImageLoaded
|
||||
markImageLoaded,
|
||||
overlay
|
||||
};
|
||||
};
|
||||
|
||||
@@ -51,6 +51,7 @@ export const EditorWrapper = ({ width }) => {
|
||||
if (editorState().movedAway) return;
|
||||
if (state === "active") {
|
||||
editorController.current.onReady();
|
||||
editorController.current.overlay(false);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -22,9 +22,9 @@ import { db } from "../../common/database";
|
||||
import DelayLayout from "../../components/delay-layout";
|
||||
import List from "../../components/list";
|
||||
import { NotebookHeader } from "../../components/list-items/headers/notebook-header";
|
||||
import { AddNotebookSheet } from "../../components/sheets/add-notebook";
|
||||
import { useNavigationFocus } from "../../hooks/use-navigation-focus";
|
||||
import {
|
||||
eSendEvent,
|
||||
eSubscribeEvent,
|
||||
eUnSubscribeEvent
|
||||
} from "../../services/event-manager";
|
||||
@@ -33,7 +33,7 @@ import SearchService from "../../services/search";
|
||||
import useNavigationStore, {
|
||||
NotebookScreenParams
|
||||
} from "../../stores/use-navigation-store";
|
||||
import { eOnNewTopicAdded, eOpenAddNotebookDialog } from "../../utils/events";
|
||||
import { eOnNewTopicAdded } from "../../utils/events";
|
||||
import { NotebookType } from "../../utils/types";
|
||||
import { openEditor, setOnFirstSave } from "../notes/common";
|
||||
const Notebook = ({ route, navigation }: NavigationProps<"Notebook">) => {
|
||||
@@ -148,7 +148,7 @@ const Notebook = ({ route, navigation }: NavigationProps<"Notebook">) => {
|
||||
ListHeader={
|
||||
<NotebookHeader
|
||||
onEditNotebook={() => {
|
||||
eSendEvent(eOpenAddNotebookDialog, params.current.item);
|
||||
AddNotebookSheet.present(params.current.item);
|
||||
}}
|
||||
notebook={params.current.item}
|
||||
/>
|
||||
|
||||
@@ -94,15 +94,6 @@ async function onNoteCreated(id: string, params: FirstSaveData) {
|
||||
{ type: "notebook", id: params.id },
|
||||
{ type: "note", id: id }
|
||||
);
|
||||
Navigation.queueRoutesForUpdate(
|
||||
"TaggedNotes",
|
||||
"ColoredNotes",
|
||||
"TopicNotes",
|
||||
"Favorites",
|
||||
"Notes",
|
||||
"Notebook",
|
||||
"Notebooks"
|
||||
);
|
||||
editorState().onNoteCreated = null;
|
||||
break;
|
||||
}
|
||||
@@ -116,41 +107,18 @@ async function onNoteCreated(id: string, params: FirstSaveData) {
|
||||
id
|
||||
);
|
||||
editorState().onNoteCreated = null;
|
||||
Navigation.queueRoutesForUpdate(
|
||||
"TaggedNotes",
|
||||
"ColoredNotes",
|
||||
"TopicNotes",
|
||||
"Favorites",
|
||||
"Notes",
|
||||
"Notebook",
|
||||
"Notebooks"
|
||||
);
|
||||
eSendEvent(eOnTopicSheetUpdate);
|
||||
break;
|
||||
}
|
||||
case "tag": {
|
||||
await db.notes?.note(id).tag(params.id);
|
||||
editorState().onNoteCreated = null;
|
||||
Navigation.queueRoutesForUpdate(
|
||||
"TaggedNotes",
|
||||
"ColoredNotes",
|
||||
"TopicNotes",
|
||||
"Favorites",
|
||||
"Notes"
|
||||
);
|
||||
useTagStore.getState().setTags();
|
||||
break;
|
||||
}
|
||||
case "color": {
|
||||
await db.notes?.note(id).color(params.color);
|
||||
editorState().onNoteCreated = null;
|
||||
Navigation.queueRoutesForUpdate(
|
||||
"TaggedNotes",
|
||||
"ColoredNotes",
|
||||
"TopicNotes",
|
||||
"Favorites",
|
||||
"Notes"
|
||||
);
|
||||
useMenuStore.getState().setColorNotes();
|
||||
break;
|
||||
}
|
||||
@@ -158,4 +126,5 @@ async function onNoteCreated(id: string, params: FirstSaveData) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Navigation.queueRoutesForUpdate();
|
||||
}
|
||||
|
||||
@@ -18,9 +18,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { View } from "react-native";
|
||||
import { db } from "../../common/database";
|
||||
import { FloatingButton } from "../../components/container/floating-button";
|
||||
import DelayLayout from "../../components/delay-layout";
|
||||
import List from "../../components/list";
|
||||
import { IconButton } from "../../components/ui/icon-button";
|
||||
import Paragraph from "../../components/ui/typography/paragraph";
|
||||
import { useNavigationFocus } from "../../hooks/use-navigation-focus";
|
||||
import {
|
||||
eSubscribeEvent,
|
||||
@@ -34,7 +38,9 @@ import useNavigationStore, {
|
||||
RouteName
|
||||
} from "../../stores/use-navigation-store";
|
||||
import { useNoteStore } from "../../stores/use-notes-store";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { NoteType, TopicType } from "../../utils/types";
|
||||
import Notebook from "../notebook/index";
|
||||
import {
|
||||
getAlias,
|
||||
openEditor,
|
||||
@@ -42,13 +48,6 @@ import {
|
||||
setOnFirstSave,
|
||||
toCamelCase
|
||||
} from "./common";
|
||||
import { View } from "react-native";
|
||||
import { db } from "../../common/database";
|
||||
import Paragraph from "../../components/ui/typography/paragraph";
|
||||
import { IconButton } from "../../components/ui/icon-button";
|
||||
import { useThemeStore } from "../../stores/use-theme-store";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import Notebook from "../notebook/index";
|
||||
export const WARNING_DATA = {
|
||||
title: "Some notes in this topic are not synced"
|
||||
};
|
||||
@@ -99,7 +98,6 @@ const NotesPage = ({
|
||||
}: RouteProps<
|
||||
"NotesPage" | "TaggedNotes" | "Monographs" | "ColoredNotes" | "TopicNotes"
|
||||
>) => {
|
||||
const colors = useThemeStore((state) => state.colors);
|
||||
const params = useRef<NotesScreenParams>(route?.params);
|
||||
const [notes, setNotes] = useState<NoteType[]>(get(route.params, true));
|
||||
const loading = useNoteStore((state) => state.loading);
|
||||
@@ -183,8 +181,9 @@ const NotesPage = ({
|
||||
if (isNew) setLoadingNotes(true);
|
||||
const notes = get(params.current, true) as NoteType[];
|
||||
if (
|
||||
(item.type === "tag" || item.type === "color") &&
|
||||
(!notes || notes.length === 0)
|
||||
((item.type === "tag" || item.type === "color") &&
|
||||
(!notes || notes.length === 0)) ||
|
||||
(item.type === "topic" && !notes)
|
||||
) {
|
||||
return Navigation.goBack();
|
||||
}
|
||||
@@ -245,19 +244,23 @@ const NotesPage = ({
|
||||
>
|
||||
Notebooks
|
||||
</Paragraph>
|
||||
<IconButton
|
||||
name="chevron-right"
|
||||
size={14}
|
||||
customStyle={{ width: 25, height: 25 }}
|
||||
/>
|
||||
<Paragraph
|
||||
onPress={() => {
|
||||
Notebook.navigate(notebook, true);
|
||||
}}
|
||||
size={SIZE.xs}
|
||||
>
|
||||
{notebook.title}
|
||||
</Paragraph>
|
||||
{notebook ? (
|
||||
<>
|
||||
<IconButton
|
||||
name="chevron-right"
|
||||
size={14}
|
||||
customStyle={{ width: 25, height: 25 }}
|
||||
/>
|
||||
<Paragraph
|
||||
onPress={() => {
|
||||
Notebook.navigate(notebook, true);
|
||||
}}
|
||||
size={SIZE.xs}
|
||||
>
|
||||
{notebook.title}
|
||||
</Paragraph>
|
||||
</>
|
||||
) : null}
|
||||
</View>
|
||||
) : null}
|
||||
<List
|
||||
@@ -276,7 +279,9 @@ const NotesPage = ({
|
||||
placeholderData={placeholderData}
|
||||
/>
|
||||
|
||||
{notes?.length > 0 || (isFocused && !isMonograph) ? (
|
||||
{!isMonograph &&
|
||||
route.name !== "TopicNotes" &&
|
||||
(notes?.length > 0 || isFocused) ? (
|
||||
<FloatingButton title="Create a note" onPress={onPressFloatingButton} />
|
||||
) : null}
|
||||
</DelayLayout>
|
||||
|
||||
@@ -75,7 +75,11 @@ export const TopicNotes = ({
|
||||
|
||||
TopicNotes.get = (params: NotesScreenParams, grouped = true) => {
|
||||
const { id, notebookId } = params.item as TopicType;
|
||||
const notes = db.notebooks?.notebook(notebookId)?.topics.topic(id)?.all || [];
|
||||
const topic = db.notebooks?.notebook(notebookId)?.topics.topic(id);
|
||||
if (!topic) {
|
||||
return null;
|
||||
}
|
||||
const notes = topic?.all || [];
|
||||
return grouped
|
||||
? groupArray(notes, db.settings?.getGroupOptions("notes"))
|
||||
: notes;
|
||||
|
||||
@@ -26,6 +26,7 @@ import { Licenses } from "./licenses";
|
||||
import SoundPicker from "./sound-picker";
|
||||
import { Subscription } from "./subscription";
|
||||
import { TrashIntervalSelector } from "./trash-interval-selector";
|
||||
import { FontSelector } from "./font-selector";
|
||||
export const components: { [name: string]: ReactElement } = {
|
||||
colorpicker: <AccentColorPicker />,
|
||||
homeselector: <HomagePageSelector />,
|
||||
@@ -35,5 +36,6 @@ export const components: { [name: string]: ReactElement } = {
|
||||
"debug-logs": <DebugLogs />,
|
||||
"sound-picker": <SoundPicker />,
|
||||
licenses: <Licenses />,
|
||||
"trash-interval-selector": <TrashIntervalSelector />
|
||||
"trash-interval-selector": <TrashIntervalSelector />,
|
||||
"font-selector": <FontSelector />
|
||||
};
|
||||
|
||||
@@ -20,8 +20,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import { ToolId } from "@notesnook/editor/dist/toolbar";
|
||||
import React, { RefObject } from "react";
|
||||
import { View } from "react-native";
|
||||
import ActionSheet from "react-native-actions-sheet";
|
||||
import { ScrollView } from "react-native-gesture-handler";
|
||||
import { PressableButton } from "../../../components/ui/pressable";
|
||||
import { SvgView } from "../../../components/ui/svg";
|
||||
import Paragraph from "../../../components/ui/typography/paragraph";
|
||||
@@ -34,13 +32,14 @@ import {
|
||||
getToolIcon,
|
||||
getUngroupedTools
|
||||
} from "./toolbar-definition";
|
||||
import { ActionSheetRef, ScrollView } from "react-native-actions-sheet";
|
||||
|
||||
export default function ToolSheet({
|
||||
group,
|
||||
fwdRef
|
||||
}: {
|
||||
group: DraggableItem;
|
||||
fwdRef: RefObject<ActionSheet>;
|
||||
fwdRef: RefObject<ActionSheetRef>;
|
||||
}) {
|
||||
const colors = useThemeStore((state) => state.colors);
|
||||
const data = useDragState((state) => state.data);
|
||||
@@ -50,6 +49,7 @@ export default function ToolSheet({
|
||||
(item: ToolId) => {
|
||||
const tool = findToolById(item);
|
||||
const iconSvgString = tool ? getToolIcon(tool.icon as ToolId) : null;
|
||||
if (item === "none") return;
|
||||
return (
|
||||
<PressableButton
|
||||
key={item}
|
||||
@@ -109,12 +109,7 @@ export default function ToolSheet({
|
||||
padding: 12
|
||||
}}
|
||||
>
|
||||
<ScrollView
|
||||
onMomentumScrollEnd={() => {
|
||||
fwdRef.current?.handleChildScrollEnd();
|
||||
}}
|
||||
nestedScrollEnabled={true}
|
||||
>
|
||||
<ScrollView nestedScrollEnabled={true}>
|
||||
{!ungrouped || ungrouped.length === 0 ? (
|
||||
<Paragraph
|
||||
style={{
|
||||
|
||||
110
apps/mobile/app/screens/settings/font-selector.jsx
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
This file is part of the Notesnook project (https://notesnook.com/)
|
||||
|
||||
Copyright (C) 2023 Streetwriters (Private) Limited
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import React, { useRef, useState } from "react";
|
||||
import { View } from "react-native";
|
||||
import Menu, { MenuItem } from "react-native-reanimated-material-menu";
|
||||
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||
import { PressableButton } from "../../components/ui/pressable";
|
||||
import Paragraph from "../../components/ui/typography/paragraph";
|
||||
import SettingsService from "../../services/settings";
|
||||
import { useSettingStore } from "../../stores/use-setting-store";
|
||||
import { useThemeStore } from "../../stores/use-theme-store";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { getFontById, getFonts } from "@notesnook/editor/dist/utils/font";
|
||||
|
||||
export const FontSelector = () => {
|
||||
const colors = useThemeStore((state) => state.colors);
|
||||
const defaultFontFamily = useSettingStore(
|
||||
(state) => state.settings.defaultFontFamily
|
||||
);
|
||||
const menuRef = useRef();
|
||||
const [width, setWidth] = useState(0);
|
||||
|
||||
const onChange = (item) => {
|
||||
menuRef.current?.hide();
|
||||
SettingsService.set({
|
||||
defaultFontFamily: item
|
||||
});
|
||||
};
|
||||
return (
|
||||
<View
|
||||
onLayout={(event) => {
|
||||
setWidth(event.nativeEvent.layout.width);
|
||||
}}
|
||||
style={{
|
||||
width: "100%"
|
||||
}}
|
||||
>
|
||||
<Menu
|
||||
ref={menuRef}
|
||||
animationDuration={200}
|
||||
style={{
|
||||
borderRadius: 5,
|
||||
backgroundColor: colors.bg,
|
||||
width: width,
|
||||
marginTop: 60
|
||||
}}
|
||||
onRequestClose={() => {
|
||||
menuRef.current?.hide();
|
||||
}}
|
||||
anchor={
|
||||
<PressableButton
|
||||
onPress={async () => {
|
||||
menuRef.current?.show();
|
||||
}}
|
||||
type="grayBg"
|
||||
customStyle={{
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
marginTop: 10,
|
||||
width: "100%",
|
||||
justifyContent: "space-between",
|
||||
padding: 12
|
||||
}}
|
||||
>
|
||||
<Paragraph>{getFontById(defaultFontFamily).title}</Paragraph>
|
||||
<Icon color={colors.icon} name="menu-down" size={SIZE.md} />
|
||||
</PressableButton>
|
||||
}
|
||||
>
|
||||
{getFonts().map((item) => (
|
||||
<MenuItem
|
||||
key={item.id}
|
||||
onPress={async () => {
|
||||
onChange(item.id);
|
||||
}}
|
||||
style={{
|
||||
backgroundColor:
|
||||
defaultFontFamily === item.id ? colors.nav : "transparent",
|
||||
width: "100%",
|
||||
maxWidth: width
|
||||
}}
|
||||
textStyle={{
|
||||
fontSize: SIZE.md,
|
||||
color: defaultFontFamily === item.id ? colors.accent : colors.pri
|
||||
}}
|
||||
>
|
||||
{item.title}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Menu>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
@@ -20,7 +20,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import { NativeStackScreenProps } from "@react-navigation/native-stack";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { View } from "react-native";
|
||||
import Animated, { FadeInDown, FadeOutDown } from "react-native-reanimated";
|
||||
import Animated, { FadeInDown } from "react-native-reanimated";
|
||||
import DelayLayout from "../../components/delay-layout";
|
||||
import BaseDialog from "../../components/dialog/base-dialog";
|
||||
import { ProgressBarComponent } from "../../components/ui/svg/lazy";
|
||||
@@ -75,57 +75,55 @@ const Home = ({
|
||||
|
||||
return (
|
||||
<DelayLayout delay={300} type="settings">
|
||||
<View>
|
||||
{loading && (
|
||||
//@ts-ignore // Migrate to typescript required.
|
||||
<BaseDialog animated={false} bounce={false} visible={true}>
|
||||
{loading && (
|
||||
//@ts-ignore // Migrate to typescript required.
|
||||
<BaseDialog animated={false} bounce={false} visible={true}>
|
||||
<View
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
backgroundColor: colors.bg,
|
||||
justifyContent: "center",
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
<Heading color={colors.pri} size={SIZE.lg}>
|
||||
Logging out
|
||||
</Heading>
|
||||
<Paragraph color={colors.icon}>
|
||||
Please wait while we log out and clear app data.
|
||||
</Paragraph>
|
||||
<View
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
backgroundColor: colors.bg,
|
||||
justifyContent: "center",
|
||||
alignItems: "center"
|
||||
flexDirection: "row",
|
||||
width: 100,
|
||||
marginTop: 15
|
||||
}}
|
||||
>
|
||||
<Heading color={colors.pri} size={SIZE.lg}>
|
||||
Logging out
|
||||
</Heading>
|
||||
<Paragraph color={colors.icon}>
|
||||
Please wait while we log out and clear app data.
|
||||
</Paragraph>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
width: 100,
|
||||
marginTop: 15
|
||||
}}
|
||||
>
|
||||
<ProgressBarComponent
|
||||
height={5}
|
||||
width={100}
|
||||
animated={true}
|
||||
useNativeDriver
|
||||
indeterminate
|
||||
indeterminateAnimationDuration={2000}
|
||||
unfilledColor={colors.nav}
|
||||
color={colors.accent}
|
||||
borderWidth={0}
|
||||
/>
|
||||
</View>
|
||||
<ProgressBarComponent
|
||||
height={5}
|
||||
width={100}
|
||||
animated={true}
|
||||
useNativeDriver
|
||||
indeterminate
|
||||
indeterminateAnimationDuration={2000}
|
||||
unfilledColor={colors.nav}
|
||||
color={colors.accent}
|
||||
borderWidth={0}
|
||||
/>
|
||||
</View>
|
||||
</BaseDialog>
|
||||
)}
|
||||
</View>
|
||||
</BaseDialog>
|
||||
)}
|
||||
|
||||
<Animated.FlatList
|
||||
entering={FadeInDown}
|
||||
exiting={FadeOutDown}
|
||||
data={settingsGroups}
|
||||
keyExtractor={keyExtractor}
|
||||
ListFooterComponent={<View style={{ height: 200 }} />}
|
||||
renderItem={renderItem}
|
||||
/>
|
||||
</View>
|
||||
<Animated.FlatList
|
||||
entering={FadeInDown}
|
||||
data={settingsGroups}
|
||||
windowSize={1}
|
||||
keyExtractor={keyExtractor}
|
||||
ListFooterComponent={<View style={{ height: 200 }} />}
|
||||
renderItem={renderItem}
|
||||
/>
|
||||
</DelayLayout>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -42,12 +42,12 @@ export const SectionGroup = ({ item }: { item: SettingSection }) => {
|
||||
color={colors.accent}
|
||||
size={SIZE.xs}
|
||||
>
|
||||
{item.name.toUpperCase()}
|
||||
{(item.name as string).toUpperCase()}
|
||||
</Heading>
|
||||
) : null}
|
||||
|
||||
{item.sections?.map((item) => (
|
||||
<SectionItem key={item.name} item={item} />
|
||||
<SectionItem key={item.name as string} item={item} />
|
||||
))}
|
||||
</View>
|
||||
);
|
||||
|
||||
@@ -37,6 +37,7 @@ import { useThemeStore } from "../../stores/use-theme-store";
|
||||
import { SIZE } from "../../utils/size";
|
||||
import { components } from "./components";
|
||||
import { RouteParams, SettingSection } from "./types";
|
||||
import { IconButton } from "../../components/ui/icon-button";
|
||||
|
||||
const _SectionItem = ({ item }: { item: SettingSection }) => {
|
||||
const colors = useThemeStore((state) => state.colors);
|
||||
@@ -64,6 +65,12 @@ const _SectionItem = ({ item }: { item: SettingSection }) => {
|
||||
backgroundColor: colors.errorBg
|
||||
}
|
||||
: {};
|
||||
|
||||
const updateInput = (value: any) => {
|
||||
inputRef?.current?.setNativeProps({
|
||||
text: value + ""
|
||||
});
|
||||
};
|
||||
return isHidden ? null : (
|
||||
<PressableButton
|
||||
disabled={item.type === "component"}
|
||||
@@ -169,6 +176,14 @@ const _SectionItem = ({ item }: { item: SettingSection }) => {
|
||||
}
|
||||
item.inputProperties?.onSubmitEditing?.(e);
|
||||
}}
|
||||
onChangeText={(text) => {
|
||||
if (text) {
|
||||
SettingsService.set({
|
||||
[item.property as string]: text
|
||||
});
|
||||
}
|
||||
item.inputProperties?.onSubmitEditing?.(text as any);
|
||||
}}
|
||||
containerStyle={{ marginTop: 12 }}
|
||||
fwdRef={inputRef}
|
||||
onLayout={() => {
|
||||
@@ -182,6 +197,95 @@ const _SectionItem = ({ item }: { item: SettingSection }) => {
|
||||
defaultValue={item.inputProperties?.defaultValue}
|
||||
/>
|
||||
)}
|
||||
|
||||
{item.type === "input-selector" && (
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
marginTop: 12
|
||||
}}
|
||||
>
|
||||
<IconButton
|
||||
name="minus"
|
||||
color={colors.pri}
|
||||
onPress={() => {
|
||||
const rawValue = SettingsService.get()[
|
||||
item.property as keyof SettingStore["settings"]
|
||||
] as string;
|
||||
if (rawValue) {
|
||||
const currentValue = parseInt(rawValue);
|
||||
if (currentValue <= 0) return;
|
||||
const nextValue = currentValue - 1;
|
||||
SettingsService.set({
|
||||
[item.property as string]: nextValue
|
||||
});
|
||||
updateInput(nextValue);
|
||||
}
|
||||
}}
|
||||
size={SIZE.xl}
|
||||
/>
|
||||
<Input
|
||||
{...item.inputProperties}
|
||||
onSubmit={(e) => {
|
||||
if (e.nativeEvent.text) {
|
||||
SettingsService.set({
|
||||
[item.property as string]: e.nativeEvent.text
|
||||
});
|
||||
}
|
||||
item.inputProperties?.onSubmitEditing?.(e);
|
||||
}}
|
||||
onChangeText={(text) => {
|
||||
if (text) {
|
||||
if (item.minInputValue) {
|
||||
text =
|
||||
parseInt(text) < item.minInputValue
|
||||
? item.minInputValue + ""
|
||||
: text;
|
||||
}
|
||||
SettingsService.set({
|
||||
[item.property as string]: text
|
||||
});
|
||||
}
|
||||
item.inputProperties?.onSubmitEditing?.(text as any);
|
||||
}}
|
||||
keyboardType="decimal-pad"
|
||||
containerStyle={{
|
||||
width: 45
|
||||
}}
|
||||
wrapperStyle={{
|
||||
maxWidth: 45,
|
||||
marginBottom: 0,
|
||||
marginHorizontal: 6
|
||||
}}
|
||||
fwdRef={inputRef}
|
||||
onLayout={() => {
|
||||
if (item.property) {
|
||||
updateInput(SettingsService.get()[item.property]);
|
||||
}
|
||||
}}
|
||||
defaultValue={item.inputProperties?.defaultValue}
|
||||
/>
|
||||
<IconButton
|
||||
name="plus"
|
||||
color={colors.pri}
|
||||
onPress={() => {
|
||||
const rawValue = SettingsService.get()[
|
||||
item.property as keyof SettingStore["settings"]
|
||||
] as string;
|
||||
if (rawValue) {
|
||||
const currentValue = parseInt(rawValue);
|
||||
const nextValue = currentValue + 1;
|
||||
SettingsService.set({
|
||||
[item.property as string]: nextValue
|
||||
});
|
||||
updateInput(nextValue);
|
||||
}
|
||||
}}
|
||||
size={SIZE.xl}
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import notifee from "@notifee/react-native";
|
||||
|
||||
import dayjs from "dayjs";
|
||||
import React from "react";
|
||||
import { Linking, Platform } from "react-native";
|
||||
@@ -317,7 +318,6 @@ export const settingsGroups: SettingSection[] = [
|
||||
await PremiumService.setPremiumStatus();
|
||||
await BiometicService.resetCredentials();
|
||||
MMKV.clearStore();
|
||||
await db.init();
|
||||
await clearAllStores();
|
||||
SettingsService.init();
|
||||
setTimeout(() => {
|
||||
@@ -451,13 +451,13 @@ export const settingsGroups: SettingSection[] = [
|
||||
},
|
||||
{
|
||||
id: "customize",
|
||||
name: "Customize",
|
||||
name: "Customization",
|
||||
sections: [
|
||||
{
|
||||
id: "personalization",
|
||||
type: "screen",
|
||||
name: "Theme",
|
||||
description: "Change app look and feel",
|
||||
description: "Change app look and feel with color themes",
|
||||
icon: "shape",
|
||||
sections: [
|
||||
{
|
||||
@@ -515,7 +515,7 @@ export const settingsGroups: SettingSection[] = [
|
||||
id: "behaviour",
|
||||
type: "screen",
|
||||
name: "Behaviour",
|
||||
description: "Change app homepage",
|
||||
description: "Change how the app behaves in different situations",
|
||||
sections: [
|
||||
{
|
||||
id: "default-home",
|
||||
@@ -533,6 +533,63 @@ export const settingsGroups: SettingSection[] = [
|
||||
component: "trash-interval-selector"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: "editor",
|
||||
name: "Editor",
|
||||
type: "screen",
|
||||
icon: "note-edit-outline",
|
||||
description: "Customize the editor to fit your needs",
|
||||
sections: [
|
||||
{
|
||||
id: "configure-toolbar",
|
||||
type: "screen",
|
||||
name: "Configure toolbar",
|
||||
description: "Make the toolbar adaptable to your needs.",
|
||||
component: "configuretoolbar"
|
||||
},
|
||||
{
|
||||
id: "reset-toolbar",
|
||||
name: "Reset toolbar",
|
||||
description: "Reset toolbar configuration to default",
|
||||
modifer: () => {
|
||||
useDragState.getState().setPreset("default");
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "double-spaced-lines",
|
||||
name: "Use double spaced lines",
|
||||
description:
|
||||
"New lines will be double spaced (old ones won't be affected).",
|
||||
type: "switch",
|
||||
property: "doubleSpacedLines",
|
||||
icon: "format-line-spacing",
|
||||
onChange: () => {
|
||||
ToastEvent.show({
|
||||
heading: "Line spacing changed",
|
||||
type: "success"
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "default-font-size",
|
||||
name: "Default font size",
|
||||
description: "Set the default font size in editor",
|
||||
type: "input-selector",
|
||||
minInputValue: 8,
|
||||
icon: "format-size",
|
||||
property: "defaultFontSize"
|
||||
},
|
||||
{
|
||||
id: "default-font-family",
|
||||
name: "Default font family",
|
||||
description: "Set the default font family in editor",
|
||||
type: "component",
|
||||
icon: "format-font",
|
||||
property: "defaultFontFamily",
|
||||
component: "font-selector"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -929,44 +986,6 @@ export const settingsGroups: SettingSection[] = [
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: "editor",
|
||||
name: "Editor",
|
||||
sections: [
|
||||
{
|
||||
id: "configure-toolbar",
|
||||
type: "screen",
|
||||
name: "Configure toolbar",
|
||||
description: "Make the toolbar adaptable to your needs.",
|
||||
component: "configuretoolbar"
|
||||
},
|
||||
{
|
||||
id: "reset-toolbar",
|
||||
name: "Reset toolbar",
|
||||
description: "Reset toolbar configuration to default",
|
||||
modifer: () => {
|
||||
useDragState.getState().setPreset("default");
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "double-spaced-lines",
|
||||
name: "Use double spaced lines",
|
||||
description:
|
||||
"New lines will be double spaced (old ones won't be affected).",
|
||||
type: "switch",
|
||||
property: "doubleSpacedLines",
|
||||
icon: "format-line-spacing",
|
||||
onChange: () => {
|
||||
ToastEvent.show({
|
||||
heading: "Line spacing changed",
|
||||
type: "success",
|
||||
message:
|
||||
"Close and reopen the current opened note or restart the app for changes to take affect."
|
||||
});
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: "help-support",
|
||||
name: "Help and support",
|
||||
@@ -1027,11 +1046,21 @@ export const settingsGroups: SettingSection[] = [
|
||||
id: "join-telegram",
|
||||
name: "Join our Telegram group",
|
||||
description: "We are on telegram, let's talk",
|
||||
// icon: 'telegram',
|
||||
modifer: () => {
|
||||
Linking.openURL("https://t.me/notesnook").catch(console.log);
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "join-mastodom",
|
||||
name: "Follow us on Mastodon",
|
||||
description: "We are on mastodom",
|
||||
icon: "mastodon",
|
||||
modifer: () => {
|
||||
Linking.openURL("https://fosstodon.org/@notesnook").catch(
|
||||
console.log
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "join-twitter",
|
||||
name: "Follow us on twitter",
|
||||
|
||||
@@ -87,7 +87,7 @@ export const TrashIntervalSelector = () => {
|
||||
>
|
||||
{[-1, 7, 30, 365].map((item) => (
|
||||
<MenuItem
|
||||
key={item.name}
|
||||
key={item.toString()}
|
||||
onPress={async () => {
|
||||
if (item === -1) {
|
||||
await PremiumService.verify(() => {
|
||||
|
||||
@@ -22,7 +22,14 @@ import { Settings } from "../../stores/use-setting-store";
|
||||
|
||||
export type SettingSection = {
|
||||
id: string;
|
||||
type?: "screen" | "switch" | "component" | "danger" | "input";
|
||||
type?:
|
||||
| "screen"
|
||||
| "switch"
|
||||
| "component"
|
||||
| "danger"
|
||||
| "input"
|
||||
| "input-selector"
|
||||
| "dropdown-selector";
|
||||
name?: string | ((current?: unknown) => string);
|
||||
description?: string | ((current: unknown) => string);
|
||||
icon?: string;
|
||||
@@ -35,6 +42,8 @@ export type SettingSection = {
|
||||
hidden?: (current: unknown) => boolean;
|
||||
onChange?: (property: boolean) => void;
|
||||
inputProperties?: TextInput["props"];
|
||||
options?: any[];
|
||||
minInputValue?: number;
|
||||
};
|
||||
|
||||
export type SettingsGroup = {
|
||||
|
||||
@@ -35,6 +35,7 @@ import { eOnNewTopicAdded } from "../utils/events";
|
||||
import { rootNavigatorRef, tabBarRef } from "../utils/global-refs";
|
||||
import { eSendEvent } from "./event-manager";
|
||||
import SettingsService from "./settings";
|
||||
import SearchService from "./search";
|
||||
|
||||
/**
|
||||
* Routes that should be updated on focus
|
||||
@@ -86,7 +87,8 @@ const routeUpdateFunctions: {
|
||||
ColoredNotes: (params) => eSendEvent("ColoredNotes", params),
|
||||
TopicNotes: (params) => eSendEvent("TopicNotes", params),
|
||||
Monographs: (params) => eSendEvent("Monographs", params),
|
||||
Reminders: () => useReminderStore.getState().setReminders()
|
||||
Reminders: () => useReminderStore.getState().setReminders(),
|
||||
Search: () => SearchService.updateAndSearch()
|
||||
};
|
||||
|
||||
function clearRouteFromQueue(routeName: RouteName) {
|
||||
@@ -106,10 +108,14 @@ function routeNeedsUpdate(routeName: RouteName, callback: () => void) {
|
||||
}
|
||||
}
|
||||
|
||||
function queueRoutesForUpdate(...routes: RouteName[]) {
|
||||
function queueRoutesForUpdate(...routesToUpdate: RouteName[]) {
|
||||
const routes =
|
||||
routesToUpdate?.length > 0
|
||||
? routesToUpdate
|
||||
: (Object.keys(routeNames) as (keyof RouteParams)[]);
|
||||
const currentScreen = useNavigationStore.getState().currentScreen;
|
||||
if (routes.indexOf(currentScreen.name) > -1) {
|
||||
routeUpdateFunctions[currentScreen.name]();
|
||||
routeUpdateFunctions[currentScreen.name]?.();
|
||||
clearRouteFromQueue(currentScreen.name);
|
||||
// Remove focused screen from queue
|
||||
routes.splice(routes.indexOf(currentScreen.name), 1);
|
||||
@@ -125,7 +131,7 @@ function navigate<T extends RouteName>(
|
||||
useNavigationStore.getState().update(screen, !!params?.canGoBack);
|
||||
if (screen.name === "Notebook") routeUpdateFunctions["Notebook"](params);
|
||||
if (screen.name.endsWith("Notes") && screen.name !== "Notes")
|
||||
routeUpdateFunctions[screen.name](params);
|
||||
routeUpdateFunctions[screen.name]?.(params);
|
||||
//@ts-ignore Not sure how to fix this for now ignore it.
|
||||
rootNavigatorRef.current?.navigate<RouteName>(screen.name, params);
|
||||
}
|
||||
|
||||
@@ -85,13 +85,21 @@ async function getNextMonthlyReminderDate(
|
||||
return await getNextMonthlyReminderDate(reminder, dayjs().year() + 1);
|
||||
}
|
||||
|
||||
async function initDatabase(notes = true) {
|
||||
if (!db.isInitialized) {
|
||||
await db.initCollections();
|
||||
}
|
||||
if (notes) {
|
||||
await db.notes?.init();
|
||||
}
|
||||
}
|
||||
|
||||
const onEvent = async ({ type, detail }: Event) => {
|
||||
const { notification, pressAction, input } = detail;
|
||||
if (type === EventType.DELIVERED && Platform.OS === "android") {
|
||||
const reminder = db.reminders?.reminder(notification?.id?.split("_")[0]);
|
||||
if (reminder && reminder.recurringMode === "month") {
|
||||
await db.init();
|
||||
await db.notes?.init();
|
||||
await initDatabase();
|
||||
await scheduleNotification(reminder);
|
||||
}
|
||||
return;
|
||||
@@ -100,10 +108,10 @@ const onEvent = async ({ type, detail }: Event) => {
|
||||
notifee.decrementBadgeCount();
|
||||
if (notification?.data?.type === "quickNote") return;
|
||||
MMKV.removeItem("appState");
|
||||
await db.init();
|
||||
await db.notes?.init();
|
||||
await initDatabase();
|
||||
if (notification?.data?.type === "reminder") {
|
||||
const reminder = db.reminders?.reminder(notification.id?.split("_")[0]);
|
||||
if (!reminder) return;
|
||||
await sleep(1000);
|
||||
const ReminderNotify =
|
||||
require("../components/sheets/reminder-notify").default;
|
||||
@@ -131,8 +139,7 @@ const onEvent = async ({ type, detail }: Event) => {
|
||||
notifee.decrementBadgeCount();
|
||||
switch (pressAction?.id) {
|
||||
case "REMINDER_SNOOZE": {
|
||||
await db.init();
|
||||
await db.notes?.init();
|
||||
await initDatabase();
|
||||
const reminder = db.reminders?.reminder(
|
||||
notification?.id?.split("_")[0]
|
||||
);
|
||||
@@ -151,8 +158,7 @@ const onEvent = async ({ type, detail }: Event) => {
|
||||
break;
|
||||
}
|
||||
case "REMINDER_DISABLE": {
|
||||
await db.init();
|
||||
await db.notes?.init();
|
||||
await initDatabase();
|
||||
const reminder = db.reminders?.reminder(
|
||||
notification?.id?.split("_")[0]
|
||||
);
|
||||
@@ -168,8 +174,7 @@ const onEvent = async ({ type, detail }: Event) => {
|
||||
break;
|
||||
}
|
||||
case "UNPIN": {
|
||||
await db.init();
|
||||
await db.notes?.init();
|
||||
await initDatabase();
|
||||
remove(notification?.id as string);
|
||||
const reminder = db.reminders?.reminder(
|
||||
notification?.id?.split("_")[0]
|
||||
@@ -198,14 +203,15 @@ const onEvent = async ({ type, detail }: Event) => {
|
||||
reply_button_text: "Take note",
|
||||
reply_placeholder_text: "Write something..."
|
||||
});
|
||||
await db.init();
|
||||
if (!db.isInitialized) await db.init();
|
||||
await db.notes?.init();
|
||||
await db.notes?.add({
|
||||
content: {
|
||||
type: "tiptap",
|
||||
data: `<p>${input} </p>`
|
||||
}
|
||||
});
|
||||
await db.notes?.init();
|
||||
await db.sync(false, false);
|
||||
useNoteStore.getState().setNotes();
|
||||
break;
|
||||
}
|
||||
@@ -367,7 +373,8 @@ async function scheduleNotification(
|
||||
|
||||
function loadNote(id: string, jump: boolean) {
|
||||
if (!id || id === "notesnook_note_input") return;
|
||||
const note = db.notes?.note(id).data;
|
||||
const note = db.notes?.note(id)?.data;
|
||||
if (!note) return;
|
||||
if (!DDS.isTab && jump) {
|
||||
tabBarRef.current?.goToPage(1);
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ let searchInformation = {
|
||||
placeholder: "Search in all notes",
|
||||
data: [],
|
||||
type: "notes",
|
||||
get: () => null
|
||||
get: () => []
|
||||
};
|
||||
|
||||
let keyword = null;
|
||||
|
||||
@@ -27,14 +27,6 @@ import { DatabaseLogger } from "../common/database/index";
|
||||
import { ToastEvent } from "./event-manager";
|
||||
import SettingsService from "./settings";
|
||||
|
||||
NetInfo.configure({
|
||||
reachabilityUrl: "https://notesnook.com",
|
||||
reachabilityTest: (response) => {
|
||||
if (!response) return false;
|
||||
return response?.status >= 200 && response?.status < 300;
|
||||
}
|
||||
});
|
||||
|
||||
export const ignoredMessages = [
|
||||
"Sync already running",
|
||||
"Not allowed to start service intent",
|
||||
|
||||
@@ -19,22 +19,19 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { db } from "../common/database";
|
||||
import Navigation from "../services/navigation";
|
||||
import Notifications from "../services/notifications";
|
||||
import { useFavoriteStore } from "./use-favorite-store";
|
||||
import { useMenuStore } from "./use-menu-store";
|
||||
import { RouteName } from "./use-navigation-store";
|
||||
import { useNotebookStore } from "./use-notebook-store";
|
||||
import { useNoteStore } from "./use-notes-store";
|
||||
import { useRelationStore } from "./use-relation-store";
|
||||
import { useReminderStore } from "./use-reminder-store";
|
||||
import { useTagStore } from "./use-tag-store";
|
||||
import { useTrashStore } from "./use-trash-store";
|
||||
import { useReminderStore } from "./use-reminder-store";
|
||||
import Notifications from "../services/notifications";
|
||||
import { useRelationStore } from "./use-relation-store";
|
||||
export function initAfterSync() {
|
||||
useMenuStore.getState().setColorNotes();
|
||||
useMenuStore.getState().setMenuPins();
|
||||
Navigation.queueRoutesForUpdate(
|
||||
...(Object.keys(Navigation.routeUpdateFunctions) as unknown as RouteName[])
|
||||
);
|
||||
Navigation.queueRoutesForUpdate();
|
||||
// Whenever sync completes, try to reschedule
|
||||
// any new/updated reminders.
|
||||
Notifications.setupReminders(true);
|
||||
|
||||
@@ -24,7 +24,6 @@ import { db } from "../common/database";
|
||||
import { MMKV } from "../common/database/mmkv";
|
||||
import PremiumService from "../services/premium";
|
||||
import { SUBSCRIPTION_STATUS } from "../utils/constants";
|
||||
import layoutmanager from "../utils/layout-manager";
|
||||
export interface MessageStore extends State {
|
||||
message: Message;
|
||||
setMessage: (message: Message) => void;
|
||||
@@ -96,13 +95,7 @@ export const useMessageStore = create<MessageStore>((set, get) => ({
|
||||
icon: "account-outline"
|
||||
},
|
||||
setMessage: (message) => {
|
||||
setTimeout(() => {
|
||||
if (get().message.visible || message.visible) {
|
||||
layoutmanager.withAnimation();
|
||||
}
|
||||
|
||||
set({ message: { ...message } });
|
||||
}, 1);
|
||||
set({ message: { ...message } });
|
||||
},
|
||||
announcements: [],
|
||||
remove: async (id) => {
|
||||
|
||||
@@ -69,6 +69,7 @@ export type RouteParams = {
|
||||
AppLock: AppLockRouteParams;
|
||||
Auth: AuthParams;
|
||||
Reminders: GenericRouteParam;
|
||||
SettingsGroup: GenericRouteParam;
|
||||
};
|
||||
|
||||
export type RouteName = keyof RouteParams;
|
||||
|
||||
@@ -73,6 +73,8 @@ export type Settings = {
|
||||
corsProxy: string;
|
||||
disableRealtimeSync?: boolean;
|
||||
notificationSound?: Sound & { platform: PlatformOSType };
|
||||
defaultFontSize: string;
|
||||
defaultFontFamily: string;
|
||||
};
|
||||
|
||||
type DimensionsType = {
|
||||
@@ -149,7 +151,9 @@ export const useSettingStore = create<SettingStore>((set) => ({
|
||||
defaultSnoozeTime: "5",
|
||||
corsProxy: "https://cors.notesnook.com",
|
||||
reminderNotificationMode: "urgent",
|
||||
notificationSound: undefined
|
||||
notificationSound: undefined,
|
||||
defaultFontFamily: "sans-serif",
|
||||
defaultFontSize: "16"
|
||||
},
|
||||
sheetKeyboardHandler: true,
|
||||
fullscreen: false,
|
||||
|
||||
@@ -25,7 +25,7 @@ import SearchService from "../services/search";
|
||||
import { useSelectionStore } from "../stores/use-selection-store";
|
||||
import { useMenuStore } from "../stores/use-menu-store";
|
||||
import { db } from "../common/database";
|
||||
import { eClearEditor } from "./events";
|
||||
import { eClearEditor, eOnTopicSheetUpdate } from "./events";
|
||||
import { useRelationStore } from "../stores/use-relation-store";
|
||||
import { presentDialog } from "../components/dialog/functions";
|
||||
|
||||
@@ -38,11 +38,14 @@ function deleteConfirmDialog(items, type, context) {
|
||||
positiveText: "Delete",
|
||||
negativeText: "Cancel",
|
||||
positivePress: (value) => {
|
||||
console.log(value);
|
||||
resolve({ delete: true, deleteNotes: value });
|
||||
setTimeout(() => {
|
||||
resolve({ delete: true, deleteNotes: value });
|
||||
});
|
||||
},
|
||||
onClose: () => {
|
||||
resolve({ delete: false });
|
||||
setTimeout(() => {
|
||||
resolve({ delete: false });
|
||||
});
|
||||
},
|
||||
context: context,
|
||||
check: {
|
||||
@@ -158,7 +161,7 @@ export const deleteItems = async (item, context) => {
|
||||
}
|
||||
}
|
||||
|
||||
Navigation.queueRoutesForUpdate(...routesForUpdate);
|
||||
Navigation.queueRoutesForUpdate();
|
||||
|
||||
let msgPart = history.selectedItemsList.length === 1 ? " item" : " items";
|
||||
let message = history.selectedItemsList.length + msgPart + " moved to trash.";
|
||||
@@ -182,7 +185,7 @@ export const deleteItems = async (item, context) => {
|
||||
}
|
||||
await db.trash.restore(...ids);
|
||||
|
||||
Navigation.queueRoutesForUpdate(routesForUpdate);
|
||||
Navigation.queueRoutesForUpdate();
|
||||
useMenuStore.getState().setMenuPins();
|
||||
useMenuStore.getState().setColorNotes();
|
||||
ToastEvent.hide();
|
||||
@@ -191,11 +194,12 @@ export const deleteItems = async (item, context) => {
|
||||
});
|
||||
}
|
||||
history.selectedItemsList = [];
|
||||
Navigation.queueRoutesForUpdate("Trash");
|
||||
Navigation.queueRoutesForUpdate();
|
||||
useSelectionStore.getState().clearSelection(true);
|
||||
useMenuStore.getState().setMenuPins();
|
||||
useMenuStore.getState().setColorNotes();
|
||||
SearchService.updateAndSearch();
|
||||
eSendEvent(eOnTopicSheetUpdate);
|
||||
};
|
||||
|
||||
export const openLinkInBrowser = async (link) => {
|
||||
|
||||
@@ -27,7 +27,6 @@ import { db } from "../common/database";
|
||||
import { tabBarRef } from "./global-refs";
|
||||
|
||||
let prevTarget = null;
|
||||
let htmlToText;
|
||||
|
||||
export const TOOLTIP_POSITIONS = {
|
||||
LEFT: 1,
|
||||
@@ -145,19 +144,12 @@ export function getTotalNotes(item) {
|
||||
return db.notebooks.notebook(item.id)?.totalNotes || 0;
|
||||
}
|
||||
|
||||
export async function toTXT(note, notitle) {
|
||||
export async function toTXT(note, template = true) {
|
||||
let text;
|
||||
if (note.locked) {
|
||||
text = note.content.data;
|
||||
text = await db.notes.note(note.id).export("txt", note.content, template);
|
||||
} else {
|
||||
text = await db.notes.note(note.id).content();
|
||||
}
|
||||
htmlToText = htmlToText || require("html-to-text");
|
||||
text = htmlToText.convert(text, {
|
||||
selectors: [{ selector: "img", format: "skip" }]
|
||||
});
|
||||
if (!notitle) {
|
||||
text = `${note.title}\n \n ${text}`;
|
||||
text = await db.notes.note(note.id).export("txt", undefined, template);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
@@ -178,3 +170,8 @@ export function showTooltip(event, text, position = 2) {
|
||||
clickToHide: true
|
||||
});
|
||||
}
|
||||
|
||||
export function toTitleCase(value) {
|
||||
if (!value) return;
|
||||
return value.slice(0, 1).toUpperCase() + value.slice(1);
|
||||
}
|
||||
|
||||
@@ -46,18 +46,18 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* @return {String} Sanitized filename
|
||||
*/
|
||||
|
||||
var illegalRe = /[/?<>\\:*|"]/g;
|
||||
const illegalRe = /[/?<>\\:*|"]/g;
|
||||
//var controlRe = /[x00-x1f\x80-\x9f]/g;
|
||||
var reservedRe = /^\.+$/;
|
||||
var windowsReservedRe = /^(con|prn|aux|nul|com[0-9]|lpt[0-9])(\..*)?$/i;
|
||||
var windowsTrailingRe = /[. ]+$/;
|
||||
var whitespace = /\s+/g;
|
||||
const reservedRe = /^\.+$/;
|
||||
const windowsReservedRe = /^(con|prn|aux|nul|com[0-9]|lpt[0-9])(\..*)?$/i;
|
||||
const windowsTrailingRe = /[. ]+$/;
|
||||
const whitespace = /\s+/g;
|
||||
|
||||
function sanitize(input, replacement) {
|
||||
function sanitize(input: string, replacement: string) {
|
||||
if (typeof input !== "string") {
|
||||
throw new Error("Input must be string");
|
||||
}
|
||||
var sanitized = input
|
||||
const sanitized = input
|
||||
.replace(whitespace, replacement)
|
||||
.replace(illegalRe, replacement)
|
||||
.replace(reservedRe, replacement)
|
||||
@@ -67,7 +67,10 @@ function sanitize(input, replacement) {
|
||||
return sanitized.slice(0, 254).toLowerCase();
|
||||
}
|
||||
|
||||
export function sanitizeFilename(input, options) {
|
||||
var replacement = (options && options.replacement) || "";
|
||||
export function sanitizeFilename(
|
||||
input: string,
|
||||
options: { replacement: string }
|
||||
) {
|
||||
const replacement = (options && options.replacement) || "";
|
||||
return sanitize(input, replacement);
|
||||
}
|
||||
@@ -80,10 +80,10 @@ export const normalize = (size) => {
|
||||
}
|
||||
};
|
||||
export const SIZE = {
|
||||
xxs: normalize(10.5) * scale.fontScale,
|
||||
xs: normalize(12) * scale.fontScale,
|
||||
sm: normalize(14.5) * scale.fontScale,
|
||||
md: normalize(16) * scale.fontScale,
|
||||
xxs: normalize(11) * scale.fontScale,
|
||||
xs: normalize(12.5) * scale.fontScale,
|
||||
sm: normalize(15) * scale.fontScale,
|
||||
md: normalize(16.5) * scale.fontScale,
|
||||
lg: normalize(22) * scale.fontScale,
|
||||
xl: normalize(24) * scale.fontScale,
|
||||
xxl: normalize(28) * scale.fontScale,
|
||||
@@ -91,10 +91,10 @@ export const SIZE = {
|
||||
};
|
||||
|
||||
export function updateSize() {
|
||||
SIZE.xxs = normalize(10.5) * scale.fontScale;
|
||||
SIZE.xs = normalize(12) * scale.fontScale;
|
||||
SIZE.sm = normalize(14.5) * scale.fontScale;
|
||||
SIZE.md = normalize(16) * scale.fontScale;
|
||||
SIZE.xxs = normalize(11) * scale.fontScale;
|
||||
SIZE.xs = normalize(12.5) * scale.fontScale;
|
||||
SIZE.sm = normalize(15) * scale.fontScale;
|
||||
SIZE.md = normalize(16.5) * scale.fontScale;
|
||||
SIZE.lg = normalize(22) * scale.fontScale;
|
||||
SIZE.xl = normalize(24) * scale.fontScale;
|
||||
SIZE.xxl = normalize(28) * scale.fontScale;
|
||||
|
||||
@@ -48,19 +48,20 @@ describe("NOTE TESTS", () => {
|
||||
await prepare();
|
||||
let note = await createNote();
|
||||
await tapById(notesnook.listitem.menu);
|
||||
await visibleByText(note.body);
|
||||
await visibleByText("Created at:");
|
||||
});
|
||||
|
||||
it("Favorite and unfavorite a note", async () => {
|
||||
await prepare();
|
||||
let note = await createNote();
|
||||
await tapById(notesnook.listitem.menu);
|
||||
await tapById("icon-Favorite");
|
||||
await tapById("icon-favorite");
|
||||
await visibleById("icon-star");
|
||||
await navigate("Favorites");
|
||||
await visibleByText(note.body);
|
||||
await sleep(500);
|
||||
await tapById(notesnook.listitem.menu);
|
||||
await tapById("icon-Favorite");
|
||||
await tapById("icon-favorite");
|
||||
await expect(element(by.text(note.body))).not.toBeVisible();
|
||||
await navigate("Notes");
|
||||
});
|
||||
@@ -69,11 +70,11 @@ describe("NOTE TESTS", () => {
|
||||
await prepare();
|
||||
await createNote();
|
||||
await tapById(notesnook.listitem.menu);
|
||||
await tapById("icon-Pin");
|
||||
await tapById("icon-pin");
|
||||
await visibleByText("Pinned");
|
||||
await visibleById("icon-pinned");
|
||||
await tapById(notesnook.listitem.menu);
|
||||
await tapById("icon-Pin");
|
||||
await tapById("icon-pin");
|
||||
expect(element(by.id("icon-pinned"))).not.toBeVisible();
|
||||
});
|
||||
|
||||
@@ -81,11 +82,12 @@ describe("NOTE TESTS", () => {
|
||||
await prepare();
|
||||
await createNote();
|
||||
await tapById(notesnook.listitem.menu);
|
||||
await tapById("icon-PinToNotif");
|
||||
await visibleByText("Unpin from Notifications");
|
||||
await tapById("icon-pin-to-notifications");
|
||||
await visibleByText("Unpin from notifications");
|
||||
await sleep(500);
|
||||
await tapById("icon-PinToNotif");
|
||||
await visibleByText("Pin to Notifications");
|
||||
await tapById("icon-pin-to-notifications");
|
||||
await sleep(500);
|
||||
await visibleByText("Pin to notifications");
|
||||
});
|
||||
|
||||
// it("Copy note", async () => {
|
||||
@@ -100,7 +102,7 @@ describe("NOTE TESTS", () => {
|
||||
await prepare();
|
||||
await createNote();
|
||||
await tapById(notesnook.listitem.menu);
|
||||
await tapById("icon-Export");
|
||||
await tapById("icon-export");
|
||||
await visibleByText("PDF");
|
||||
});
|
||||
|
||||
@@ -122,8 +124,9 @@ describe("NOTE TESTS", () => {
|
||||
await prepare();
|
||||
await createNote();
|
||||
await tapById(notesnook.listitem.menu);
|
||||
await tapById("icon-Delete");
|
||||
await tapById("icon-trash");
|
||||
await navigate("Trash");
|
||||
await sleep(500);
|
||||
await tapById(notesnook.listitem.menu);
|
||||
await tapByText("Restore note");
|
||||
await device.pressBack();
|
||||
|
||||
@@ -56,7 +56,7 @@ async function createNotebook(
|
||||
await tapById("topic-add-button");
|
||||
}
|
||||
}
|
||||
await tapByText("Create notebook");
|
||||
await tapByText("Save");
|
||||
await sleep(500);
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ describe("NOTEBOOKS", () => {
|
||||
await visibleByText(note.body);
|
||||
});
|
||||
|
||||
it("Add new topic to notebook", async () => {
|
||||
it.only("Add new topic to notebook", async () => {
|
||||
await prepare();
|
||||
await navigate("Notebooks");
|
||||
await sleep(500);
|
||||
@@ -133,7 +133,7 @@ describe("NOTEBOOKS", () => {
|
||||
await elementById("input-title").typeText("Topic");
|
||||
await tapByText("Add");
|
||||
await sleep(500);
|
||||
await visibleById("topic-sheet-item-0");
|
||||
await tapByText("Topic");
|
||||
});
|
||||
|
||||
it("Edit topic", async () => {
|
||||
@@ -146,7 +146,6 @@ describe("NOTEBOOKS", () => {
|
||||
await sleep(500);
|
||||
await tapByText("Notebook 1");
|
||||
await sleep(300);
|
||||
await visibleById("topic-sheet-item-0");
|
||||
await tapById(notesnook.ids.notebook.menu);
|
||||
await tapByText("Edit topic");
|
||||
await elementById("input-title").typeText(" (edited)");
|
||||
@@ -254,7 +253,7 @@ describe("NOTEBOOKS", () => {
|
||||
"Topic 2"
|
||||
);
|
||||
await tapById("topic-add-button");
|
||||
await tapByText("Save changes");
|
||||
await tapByText("Save");
|
||||
await sleep(500);
|
||||
await visibleByText("Notebook 1 (Edited)");
|
||||
await visibleByText("Description of Notebook 1 (Edited)");
|
||||
@@ -274,7 +273,7 @@ describe("NOTEBOOKS", () => {
|
||||
await tapById(notesnook.ids.notebook.menu);
|
||||
await tapByText("Move to trash");
|
||||
await sleep(2000);
|
||||
await tapByText("No");
|
||||
await tapByText("Delete");
|
||||
await sleep(4000);
|
||||
await navigate("Trash");
|
||||
await visibleByText("Notebook 1");
|
||||
@@ -296,7 +295,9 @@ describe("NOTEBOOKS", () => {
|
||||
await tapById(notesnook.ids.notebook.menu);
|
||||
await tapByText("Move to trash");
|
||||
await sleep(2000);
|
||||
await tapByText("Yes");
|
||||
await tapByText("Move all notes in this notebook to trash");
|
||||
await sleep(500);
|
||||
await tapByText("Delete");
|
||||
await sleep(4000);
|
||||
await navigate("Trash");
|
||||
await visibleByText("Notebook 1");
|
||||
@@ -319,7 +320,9 @@ describe("NOTEBOOKS", () => {
|
||||
await tapById(notesnook.ids.notebook.menu);
|
||||
await tapByText("Delete topic");
|
||||
await sleep(2000);
|
||||
await tapByText("Yes");
|
||||
await tapByText("Move all notes in this topic to trash");
|
||||
await sleep(500);
|
||||
await tapByText("Delete");
|
||||
await device.pressBack();
|
||||
await sleep(4000);
|
||||
await navigate("Trash");
|
||||
|
||||
@@ -17,13 +17,15 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { notesnook } from "../test.ids";
|
||||
import {
|
||||
tapById,
|
||||
visibleByText,
|
||||
createNote,
|
||||
prepare,
|
||||
elementById,
|
||||
sleep
|
||||
sleep,
|
||||
tapByText
|
||||
} from "./utils";
|
||||
|
||||
describe("Search", () => {
|
||||
@@ -34,6 +36,10 @@ describe("Search", () => {
|
||||
await sleep(300);
|
||||
await elementById("search-input").typeText("n");
|
||||
await sleep(1000);
|
||||
await tapByText(note.body);
|
||||
await sleep(1000);
|
||||
await device.pressBack();
|
||||
await device.pressBack();
|
||||
await visibleByText(note.body);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -164,7 +164,7 @@ android {
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
multiDexEnabled true
|
||||
versionCode 2039
|
||||
versionCode 2044
|
||||
versionName getNpmVersion()
|
||||
testBuildType System.getProperty('testBuildType', 'debug')
|
||||
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
||||
|
||||
@@ -4,6 +4,7 @@ package com.streetwriters.notesnook;
|
||||
import android.graphics.Color;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import com.facebook.react.bridge.Promise;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
@@ -36,6 +37,16 @@ public class RCTNNativeModule extends ReactContextBaseJavaModule {
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void getActivityName(Promise promise) {
|
||||
try {
|
||||
promise.resolve(getCurrentActivity().getClass().getSimpleName());
|
||||
} catch (Exception e) {
|
||||
promise.resolve(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ReactMethod
|
||||
public void setSecureMode(final boolean mode) {
|
||||
|
||||
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 9.6 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 32 KiB |
@@ -1,4 +1,10 @@
|
||||
- Fix note publishing not working with password protection
|
||||
- Some fixes and improvements in notebook/topic linking
|
||||
- Added default font size & font family settings
|
||||
- Redesign reminder/notebook sheets to improve UX
|
||||
- Fixed an issue causing sync to fail
|
||||
- Fix tag suggestions in share extension
|
||||
- Fix app font sizes too small in some places
|
||||
- Improved mobile editor performance on low-end devices
|
||||
- Fix pin to notifications not working
|
||||
- Bug fixes and performance improvements
|
||||
|
||||
Thank you for using Notesnook!
|
||||
@@ -33,6 +33,8 @@
|
||||
65B5014725A672B200E2D264 /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 65B5014525A672B200E2D264 /* MainInterface.storyboard */; };
|
||||
65B5014B25A672B200E2D264 /* Make Note.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 65B5014025A672B200E2D264 /* Make Note.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
65B5020325A6756700E2D264 /* File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65B5020225A6756700E2D264 /* File.swift */; };
|
||||
65D145C529DC30470056FE7D /* MaterialCommunityIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 65D145C429DC30470056FE7D /* MaterialCommunityIcons.ttf */; };
|
||||
65D145C629DC30470056FE7D /* MaterialCommunityIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 65D145C429DC30470056FE7D /* MaterialCommunityIcons.ttf */; };
|
||||
65E0340B257B9FF100793428 /* File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65E0340A257B9FF100793428 /* File.swift */; };
|
||||
7C72B5EA418785B334F3B5EB /* libPods-Notesnook-Make Note.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 35547D7C07E83F889159A73D /* libPods-Notesnook-Make Note.a */; };
|
||||
87CE5B71DC72F3D95B7B1AA5 /* libPods-Notesnook-tvOSTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A03E3F5851D27269540E147C /* libPods-Notesnook-tvOSTests.a */; };
|
||||
@@ -129,6 +131,7 @@
|
||||
65B501AA25A6733400E2D264 /* Make Note.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "Make Note.entitlements"; sourceTree = "<group>"; };
|
||||
65B5020125A6756700E2D264 /* Make Note-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Make Note-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
65B5020225A6756700E2D264 /* File.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = File.swift; sourceTree = "<group>"; };
|
||||
65D145C429DC30470056FE7D /* MaterialCommunityIcons.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = MaterialCommunityIcons.ttf; path = "../../node_modules/react-native-vector-icons/Fonts/MaterialCommunityIcons.ttf"; sourceTree = "<group>"; };
|
||||
65E03409257B9FF100793428 /* Notesnook-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Notesnook-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
65E0340A257B9FF100793428 /* File.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = File.swift; sourceTree = "<group>"; };
|
||||
65EC5B71272A7EE200FB3748 /* NotesWidgetExtensionDebug.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = NotesWidgetExtensionDebug.entitlements; sourceTree = "<group>"; };
|
||||
@@ -292,6 +295,7 @@
|
||||
65EC5B71272A7EE200FB3748 /* NotesWidgetExtensionDebug.entitlements */,
|
||||
6552012F27019F7700A43C51 /* OpenSans-Regular.ttf */,
|
||||
6552012E27019F6E00A43C51 /* OpenSans-SemiBold.ttf */,
|
||||
65D145C429DC30470056FE7D /* MaterialCommunityIcons.ttf */,
|
||||
13B07FAE1A68108700A75B9A /* Notesnook */,
|
||||
832341AE1AAA6A7D00B99B32 /* Libraries */,
|
||||
00E356EF1AD99517003FC87E /* NotesnookTests */,
|
||||
@@ -533,6 +537,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
6510626F27042891009661C3 /* OpenSans-Regular.ttf in Resources */,
|
||||
65D145C529DC30470056FE7D /* MaterialCommunityIcons.ttf in Resources */,
|
||||
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
|
||||
6529A13E279BC4C70048D4A8 /* BootSplash.storyboard in Resources */,
|
||||
6510E6D72877215700DACAA9 /* build.bundle in Resources */,
|
||||
@@ -569,6 +574,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
6510E6D82877215700DACAA9 /* build.bundle in Resources */,
|
||||
65D145C629DC30470056FE7D /* MaterialCommunityIcons.ttf in Resources */,
|
||||
6510627727042896009661C3 /* OpenSans-SemiBold.ttf in Resources */,
|
||||
6510627527042893009661C3 /* OpenSans-Regular.ttf in Resources */,
|
||||
65B5014725A672B200E2D264 /* MainInterface.storyboard in Resources */,
|
||||
@@ -621,42 +627,10 @@
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Notesnook/Pods-Notesnook-resources.sh",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/AntDesign.ttf",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/Entypo.ttf",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/EvilIcons.ttf",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/Feather.ttf",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/FontAwesome.ttf",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/FontAwesome5_Brands.ttf",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/FontAwesome5_Regular.ttf",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/FontAwesome5_Solid.ttf",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/Fontisto.ttf",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/Foundation.ttf",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/Ionicons.ttf",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/MaterialCommunityIcons.ttf",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/MaterialIcons.ttf",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/Octicons.ttf",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/SimpleLineIcons.ttf",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/Zocial.ttf",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/React-Core/AccessibilityResources.bundle",
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AntDesign.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Entypo.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EvilIcons.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Feather.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/FontAwesome.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/FontAwesome5_Brands.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/FontAwesome5_Regular.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/FontAwesome5_Solid.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Fontisto.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Foundation.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Ionicons.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/MaterialCommunityIcons.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/MaterialIcons.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Octicons.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/SimpleLineIcons.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Zocial.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AccessibilityResources.bundle",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -770,42 +744,10 @@
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Notesnook-NotesnookTests/Pods-Notesnook-NotesnookTests-resources.sh",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/AntDesign.ttf",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/Entypo.ttf",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/EvilIcons.ttf",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/Feather.ttf",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/FontAwesome.ttf",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/FontAwesome5_Brands.ttf",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/FontAwesome5_Regular.ttf",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/FontAwesome5_Solid.ttf",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/Fontisto.ttf",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/Foundation.ttf",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/Ionicons.ttf",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/MaterialCommunityIcons.ttf",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/MaterialIcons.ttf",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/Octicons.ttf",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/SimpleLineIcons.ttf",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/Zocial.ttf",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/React-Core/AccessibilityResources.bundle",
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AntDesign.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Entypo.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EvilIcons.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Feather.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/FontAwesome.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/FontAwesome5_Brands.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/FontAwesome5_Regular.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/FontAwesome5_Solid.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Fontisto.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Foundation.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Ionicons.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/MaterialCommunityIcons.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/MaterialIcons.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Octicons.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/SimpleLineIcons.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Zocial.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AccessibilityResources.bundle",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -842,42 +784,10 @@
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Notesnook-Make Note/Pods-Notesnook-Make Note-resources.sh",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/AntDesign.ttf",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/Entypo.ttf",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/EvilIcons.ttf",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/Feather.ttf",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/FontAwesome.ttf",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/FontAwesome5_Brands.ttf",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/FontAwesome5_Regular.ttf",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/FontAwesome5_Solid.ttf",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/Fontisto.ttf",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/Foundation.ttf",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/Ionicons.ttf",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/MaterialCommunityIcons.ttf",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/MaterialIcons.ttf",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/Octicons.ttf",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/SimpleLineIcons.ttf",
|
||||
"${PODS_ROOT}/../../../node_modules/react-native-vector-icons/Fonts/Zocial.ttf",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/React-Core/AccessibilityResources.bundle",
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AntDesign.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Entypo.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EvilIcons.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Feather.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/FontAwesome.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/FontAwesome5_Brands.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/FontAwesome5_Regular.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/FontAwesome5_Solid.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Fontisto.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Foundation.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Ionicons.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/MaterialCommunityIcons.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/MaterialIcons.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Octicons.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/SimpleLineIcons.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Zocial.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AccessibilityResources.bundle",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -1083,7 +993,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 2031;
|
||||
CURRENT_PROJECT_VERSION = 2036;
|
||||
DEVELOPMENT_TEAM = 53CWBG3QUC;
|
||||
ENABLE_BITCODE = NO;
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
|
||||
@@ -1157,7 +1067,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.4.8;
|
||||
MARKETING_VERSION = 2.4.13;
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
"-ObjC",
|
||||
@@ -1187,7 +1097,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = Notesnook/Notesnook.entitlements;
|
||||
CODE_SIGN_IDENTITY = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 2031;
|
||||
CURRENT_PROJECT_VERSION = 2036;
|
||||
DEVELOPMENT_TEAM = 53CWBG3QUC;
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
|
||||
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
|
||||
@@ -1260,7 +1170,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.4.8;
|
||||
MARKETING_VERSION = 2.4.13;
|
||||
ONLY_ACTIVE_ARCH = NO;
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
@@ -1418,7 +1328,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 2031;
|
||||
CURRENT_PROJECT_VERSION = 2036;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = 53CWBG3QUC;
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
|
||||
@@ -1430,7 +1340,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.4.8;
|
||||
MARKETING_VERSION = 2.4.13;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.notewidget;
|
||||
@@ -1460,7 +1370,7 @@
|
||||
CODE_SIGN_IDENTITY = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 2031;
|
||||
CURRENT_PROJECT_VERSION = 2036;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_TEAM = 53CWBG3QUC;
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
|
||||
@@ -1472,7 +1382,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.4.8;
|
||||
MARKETING_VERSION = 2.4.13;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.notewidget;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@@ -1501,7 +1411,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = "Make Note/Make Note.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 2031;
|
||||
CURRENT_PROJECT_VERSION = 2036;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = 53CWBG3QUC;
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
|
||||
@@ -1575,7 +1485,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.4.8;
|
||||
MARKETING_VERSION = 2.4.13;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.share;
|
||||
@@ -1605,7 +1515,7 @@
|
||||
CODE_SIGN_IDENTITY = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 2031;
|
||||
CURRENT_PROJECT_VERSION = 2036;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_TEAM = 53CWBG3QUC;
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
|
||||
@@ -1679,7 +1589,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.4.8;
|
||||
MARKETING_VERSION = 2.4.13;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.share;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
|
||||
@@ -418,8 +418,6 @@ PODS:
|
||||
- pop (~> 1.0)
|
||||
- React
|
||||
- SexyTooltip
|
||||
- RNVectorIcons (9.2.0):
|
||||
- React-Core
|
||||
- SexyTooltip (1.2.5):
|
||||
- pop (~> 1.0)
|
||||
- toolbar-android (0.2.1):
|
||||
@@ -504,7 +502,6 @@ DEPENDENCIES:
|
||||
- RNShare (from `../../node_modules/react-native-share`)
|
||||
- RNSVG (from `../../node_modules/react-native-svg`)
|
||||
- RNTooltips (from `../../node_modules/react-native-tooltips`)
|
||||
- RNVectorIcons (from `../../node_modules/react-native-vector-icons`)
|
||||
- SexyTooltip (from `https://github.com/ammarahm-ed/SexyTooltip.git`)
|
||||
- "toolbar-android (from `../../node_modules/@react-native-community/toolbar-android`)"
|
||||
- Yoga (from `../../node_modules/react-native/ReactCommon/yoga`)
|
||||
@@ -667,8 +664,6 @@ EXTERNAL SOURCES:
|
||||
:path: "../../node_modules/react-native-svg"
|
||||
RNTooltips:
|
||||
:path: "../../node_modules/react-native-tooltips"
|
||||
RNVectorIcons:
|
||||
:path: "../../node_modules/react-native-vector-icons"
|
||||
SexyTooltip:
|
||||
:git: https://github.com/ammarahm-ed/SexyTooltip.git
|
||||
toolbar-android:
|
||||
@@ -762,7 +757,6 @@ SPEC CHECKSUMS:
|
||||
RNShare: a5dc3b9c53ddc73e155b8cd9a94c70c91913c43c
|
||||
RNSVG: ecd661f380a07ba690c9c5929c475a44f432d674
|
||||
RNTooltips: 5424d4bf0b3d441104127943b1115cc7f0616b1f
|
||||
RNVectorIcons: fcc2f6cb32f5735b586e66d14103a74ce6ad61f8
|
||||
SexyTooltip: 5c9b4dec52bfb317938cb0488efd9da3717bb6fd
|
||||
toolbar-android: 2a73856e98b750d7e71ce4644d3f41cc98211719
|
||||
Yoga: 0b84a956f7393ef1f37f3bb213c516184e4a689d
|
||||
|
||||
@@ -57,7 +57,9 @@
|
||||
"@react-native-community/datetimepicker":"6.6.0",
|
||||
"react-native-date-picker": "4.2.6",
|
||||
"react-native-notification-sounds": "0.5.5",
|
||||
"@bam.tech/react-native-image-resizer": "3.0.5"
|
||||
"@bam.tech/react-native-image-resizer": "3.0.5",
|
||||
"react-native-navigation-bar-color": "2.0.2",
|
||||
"react-native-actions-shortcuts": "^1.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.12.9",
|
||||
|
||||
@@ -9,15 +9,19 @@ const config = {
|
||||
}
|
||||
};
|
||||
|
||||
if (!config.dependencies) config.dependencies = {};
|
||||
config.dependencies['react-native-vector-icons'] = {
|
||||
platforms: {
|
||||
ios: null,
|
||||
},
|
||||
}
|
||||
|
||||
if (isGithubRelease) {
|
||||
config.dependencies = {
|
||||
"react-native-iap": {
|
||||
platforms: {
|
||||
android:null
|
||||
}
|
||||
},
|
||||
config.dependencies["react-native-iap"] = {
|
||||
platforms: {
|
||||
android:null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
module.exports = config;
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
- Fix note publishing not working with password protection
|
||||
- Some fixes and improvements in notebook/topic linking
|
||||
- Added default font size & font family settings
|
||||
- Redesign reminder/notebook sheets to improve UX
|
||||
- Fixed an issue causing sync to fail
|
||||
- Fix tag suggestions in share extension
|
||||
- Fix app font sizes too small in some places
|
||||
- Improved mobile editor performance on low-end devices
|
||||
- Fix pin to notifications not working
|
||||
- Bug fixes and performance improvements
|
||||
|
||||
Thank you for using Notesnook!
|
||||
@@ -86,7 +86,17 @@ module.exports = (env) => {
|
||||
"@notesnook": path.join(__dirname, "../../../packages"),
|
||||
"@streetwriters/showdown": path.join(__dirname, "../node_modules/@streetwriters/showdown"),
|
||||
"qclone": path.join(__dirname, "../node_modules/qclone"),
|
||||
"@notifee/react-native": path.join(__dirname, "../node_modules/@ammarahmed/notifee-react-native")
|
||||
"@notifee/react-native": path.join(__dirname, "../node_modules/@ammarahmed/notifee-react-native"),
|
||||
"html-to-text": path.join(__dirname, "../node_modules/html-to-text"),
|
||||
"leac": path.join(__dirname, "../node_modules/leac"),
|
||||
"parseley": path.join(__dirname, "../node_modules/parseley"),
|
||||
"htmlparser2": path.join(__dirname, "../node_modules/htmlparser2"),
|
||||
"selderee": path.join(__dirname, "../node_modules/selderee"),
|
||||
"minimist": path.join(__dirname, "../node_modules/minimist"),
|
||||
"entities": path.join(__dirname, "../node_modules/entities"),
|
||||
"deepmerge": path.join(__dirname, "../node_modules/deepmerge"),
|
||||
"@selderee/plugin-htmlparser2": path.join(__dirname, "../node_modules/@selderee/plugin-htmlparser2"),
|
||||
"peberminta": path.join(__dirname, "../node_modules/peberminta"),
|
||||
},
|
||||
},
|
||||
/**
|
||||
|
||||
503
apps/mobile/package-lock.json
generated
@@ -1,22 +1,20 @@
|
||||
{
|
||||
"name": "@notesnook/mobile",
|
||||
"version": "2.4.7",
|
||||
"version": "2.4.13",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@notesnook/mobile",
|
||||
"version": "2.4.7",
|
||||
"version": "2.4.13",
|
||||
"license": "GPL-3.0-or-later",
|
||||
"workspaces": [
|
||||
"native/",
|
||||
"app/"
|
||||
],
|
||||
"dependencies": {
|
||||
"fflate": "^0.7.3",
|
||||
"react-native-actions-shortcuts": "^1.0.1",
|
||||
"react-native-fingerprint-scanner": "https://github.com/ammarahm-ed/react-native-fingerprint-scanner.git",
|
||||
"react-native-iap": "7.5.6"
|
||||
"react": "18.0.0",
|
||||
"react-native": "0.69.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"otplib": "12.0.1",
|
||||
@@ -37,12 +35,10 @@
|
||||
"dayjs": "^1.10.4",
|
||||
"entities": "^3.0.1",
|
||||
"fflate": "^0.7.3",
|
||||
"html-to-text": "8.1.0",
|
||||
"html-to-text": "9.0.5",
|
||||
"phone": "^3.1.14",
|
||||
"qclone": "^1.2.0",
|
||||
"react": "18.0.0",
|
||||
"react-native": "0.69.7",
|
||||
"react-native-actions-sheet": "^0.9.0-alpha.14",
|
||||
"react-native-actions-sheet": "0.9.0-alpha.18",
|
||||
"react-native-check-version": "https://github.com/flexible-agency/react-native-check-version",
|
||||
"react-native-drax": "^0.10.2",
|
||||
"react-native-image-zoom-viewer": "^3.0.1",
|
||||
@@ -80,6 +76,7 @@
|
||||
"deprecated-react-native-prop-types": "^2.3.0",
|
||||
"react": "18.0.0",
|
||||
"react-native": "0.69.7",
|
||||
"react-native-actions-shortcuts": "^1.0.1",
|
||||
"react-native-background-actions": "^2.6.6",
|
||||
"react-native-begin-background-task": "https://github.com/blockfirm/react-native-begin-background-task.git",
|
||||
"react-native-bootsplash": "^4.1.4",
|
||||
@@ -100,6 +97,7 @@
|
||||
"react-native-keychain": "4.0.5",
|
||||
"react-native-mmkv-storage": "^0.8.0",
|
||||
"react-native-modal-datetime-picker": "14.0.0",
|
||||
"react-native-navigation-bar-color": "2.0.2",
|
||||
"react-native-notification-sounds": "0.5.5",
|
||||
"react-native-orientation": "https://github.com/yamill/react-native-orientation.git",
|
||||
"react-native-privacy-snapshot": "https://github.com/standardnotes/react-native-privacy-snapshot.git",
|
||||
@@ -5622,12 +5620,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@selderee/plugin-htmlparser2": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.6.0.tgz",
|
||||
"integrity": "sha512-J3jpy002TyBjd4N/p6s+s90eX42H2eRhK3SbsZuvTDv977/E8p2U3zikdiehyJja66do7FlxLomZLPlvl2/xaA==",
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.11.0.tgz",
|
||||
"integrity": "sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==",
|
||||
"dependencies": {
|
||||
"domhandler": "^4.2.0",
|
||||
"selderee": "^0.6.0"
|
||||
"domhandler": "^5.0.3",
|
||||
"selderee": "^0.11.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://ko-fi.com/killymxi"
|
||||
@@ -8144,57 +8142,6 @@
|
||||
"url": "https://github.com/sponsors/fb55"
|
||||
}
|
||||
},
|
||||
"node_modules/css-select/node_modules/dom-serializer": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
|
||||
"integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
|
||||
"dependencies": {
|
||||
"domelementtype": "^2.3.0",
|
||||
"domhandler": "^5.0.2",
|
||||
"entities": "^4.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/css-select/node_modules/domhandler": {
|
||||
"version": "5.0.3",
|
||||
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
|
||||
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
|
||||
"dependencies": {
|
||||
"domelementtype": "^2.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/domhandler?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/css-select/node_modules/domutils": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz",
|
||||
"integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==",
|
||||
"dependencies": {
|
||||
"dom-serializer": "^2.0.0",
|
||||
"domelementtype": "^2.3.0",
|
||||
"domhandler": "^5.0.1"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/domutils?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/css-select/node_modules/entities": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz",
|
||||
"integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==",
|
||||
"engines": {
|
||||
"node": ">=0.12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/css-tree": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz",
|
||||
@@ -8290,9 +8237,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/deepmerge": {
|
||||
"version": "4.2.2",
|
||||
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz",
|
||||
"integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==",
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
|
||||
"integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
@@ -8575,11 +8522,6 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/discontinuous-range": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/discontinuous-range/-/discontinuous-range-1.0.0.tgz",
|
||||
"integrity": "sha512-c68LpLbO+7kP/b1Hr1qs8/BJ09F5khZGTxqxZuhzxpmwJKOgRFHJWIb9/KmqnqHhLdO55aOxFH/EGBvUQbL/RQ=="
|
||||
},
|
||||
"node_modules/doctrine": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
|
||||
@@ -8593,22 +8535,25 @@
|
||||
}
|
||||
},
|
||||
"node_modules/dom-serializer": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz",
|
||||
"integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==",
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
|
||||
"integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
|
||||
"dependencies": {
|
||||
"domelementtype": "^2.0.1",
|
||||
"domhandler": "^4.2.0",
|
||||
"entities": "^2.0.0"
|
||||
"domelementtype": "^2.3.0",
|
||||
"domhandler": "^5.0.2",
|
||||
"entities": "^4.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/dom-serializer/node_modules/entities": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
|
||||
"integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
|
||||
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
|
||||
"engines": {
|
||||
"node": ">=0.12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||
}
|
||||
@@ -8630,11 +8575,11 @@
|
||||
]
|
||||
},
|
||||
"node_modules/domhandler": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz",
|
||||
"integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==",
|
||||
"version": "5.0.3",
|
||||
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
|
||||
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
|
||||
"dependencies": {
|
||||
"domelementtype": "^2.2.0"
|
||||
"domelementtype": "^2.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
@@ -8644,13 +8589,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/domutils": {
|
||||
"version": "2.8.0",
|
||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
|
||||
"integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==",
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz",
|
||||
"integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==",
|
||||
"dependencies": {
|
||||
"dom-serializer": "^1.0.1",
|
||||
"domelementtype": "^2.2.0",
|
||||
"domhandler": "^4.2.0"
|
||||
"dom-serializer": "^2.0.0",
|
||||
"domelementtype": "^2.3.0",
|
||||
"domhandler": "^5.0.1"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/domutils?sponsor=1"
|
||||
@@ -10969,14 +10914,6 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/he": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
|
||||
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
|
||||
"bin": {
|
||||
"he": "bin/he"
|
||||
}
|
||||
},
|
||||
"node_modules/hermes-engine": {
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/hermes-engine/-/hermes-engine-0.11.0.tgz",
|
||||
@@ -11026,28 +10963,24 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/html-to-text": {
|
||||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmjs.org/html-to-text/-/html-to-text-8.1.0.tgz",
|
||||
"integrity": "sha512-Z9iYAqYK2c18GswSbnxJSeMs7lyJgwR2oIkDOyOHGBbYsPsG4HvT379jj3Lcbfko8A5ceyyMHAfkmp/BiXA9/Q==",
|
||||
"version": "9.0.5",
|
||||
"resolved": "https://registry.npmjs.org/html-to-text/-/html-to-text-9.0.5.tgz",
|
||||
"integrity": "sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg==",
|
||||
"dependencies": {
|
||||
"@selderee/plugin-htmlparser2": "^0.6.0",
|
||||
"deepmerge": "^4.2.2",
|
||||
"he": "^1.2.0",
|
||||
"htmlparser2": "^6.1.0",
|
||||
"minimist": "^1.2.5",
|
||||
"selderee": "^0.6.0"
|
||||
},
|
||||
"bin": {
|
||||
"html-to-text": "bin/cli.js"
|
||||
"@selderee/plugin-htmlparser2": "^0.11.0",
|
||||
"deepmerge": "^4.3.1",
|
||||
"dom-serializer": "^2.0.0",
|
||||
"htmlparser2": "^8.0.2",
|
||||
"selderee": "^0.11.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.23.2"
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/htmlparser2": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz",
|
||||
"integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==",
|
||||
"version": "8.0.2",
|
||||
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz",
|
||||
"integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==",
|
||||
"funding": [
|
||||
"https://github.com/fb55/htmlparser2?sponsor=1",
|
||||
{
|
||||
@@ -11056,16 +10989,19 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"domelementtype": "^2.0.1",
|
||||
"domhandler": "^4.0.0",
|
||||
"domutils": "^2.5.2",
|
||||
"entities": "^2.0.0"
|
||||
"domelementtype": "^2.3.0",
|
||||
"domhandler": "^5.0.3",
|
||||
"domutils": "^3.0.1",
|
||||
"entities": "^4.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/htmlparser2/node_modules/entities": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
|
||||
"integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
|
||||
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
|
||||
"engines": {
|
||||
"node": ">=0.12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||
}
|
||||
@@ -14379,6 +14315,14 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/leac": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/leac/-/leac-0.6.0.tgz",
|
||||
"integrity": "sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==",
|
||||
"funding": {
|
||||
"url": "https://ko-fi.com/killymxi"
|
||||
}
|
||||
},
|
||||
"node_modules/leven": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
|
||||
@@ -16190,11 +16134,6 @@
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/moo": {
|
||||
"version": "0.5.2",
|
||||
"resolved": "https://registry.npmjs.org/moo/-/moo-0.5.2.tgz",
|
||||
"integrity": "sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q=="
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
@@ -16300,27 +16239,6 @@
|
||||
"ncp": "bin/ncp"
|
||||
}
|
||||
},
|
||||
"node_modules/nearley": {
|
||||
"version": "2.20.1",
|
||||
"resolved": "https://registry.npmjs.org/nearley/-/nearley-2.20.1.tgz",
|
||||
"integrity": "sha512-+Mc8UaAebFzgV+KpI5n7DasuuQCHA89dmwm7JXw3TV43ukfNQ9DnBH3Mdb2g/I4Fdxc26pwimBWvjIw0UAILSQ==",
|
||||
"dependencies": {
|
||||
"commander": "^2.19.0",
|
||||
"moo": "^0.5.0",
|
||||
"railroad-diagrams": "^1.0.0",
|
||||
"randexp": "0.4.6"
|
||||
},
|
||||
"bin": {
|
||||
"nearley-railroad": "bin/nearley-railroad.js",
|
||||
"nearley-test": "bin/nearley-test.js",
|
||||
"nearley-unparse": "bin/nearley-unparse.js",
|
||||
"nearleyc": "bin/nearleyc.js"
|
||||
},
|
||||
"funding": {
|
||||
"type": "individual",
|
||||
"url": "https://nearley.js.org/#give-to-nearley"
|
||||
}
|
||||
},
|
||||
"node_modules/negotiator": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
|
||||
@@ -16979,12 +16897,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/parseley": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/parseley/-/parseley-0.7.0.tgz",
|
||||
"integrity": "sha512-xyOytsdDu077M3/46Am+2cGXEKM9U9QclBDv7fimY7e+BBlxh2JcBp2mgNsmkyA9uvgyTjVzDi7cP1v4hcFxbw==",
|
||||
"version": "0.12.0",
|
||||
"resolved": "https://registry.npmjs.org/parseley/-/parseley-0.12.0.tgz",
|
||||
"integrity": "sha512-uLqDm6IQVb6m50a3dIxF66hI8VWr7wFDYUULtHa1ITRh9mwYIXzFpPTkPM66Cm5V0t+bMyeSHgUCGzoXTV96LQ==",
|
||||
"dependencies": {
|
||||
"moo": "^0.5.1",
|
||||
"nearley": "^2.20.1"
|
||||
"leac": "^0.6.0",
|
||||
"peberminta": "^0.9.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://ko-fi.com/killymxi"
|
||||
@@ -17071,6 +16989,14 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/peberminta": {
|
||||
"version": "0.9.0",
|
||||
"resolved": "https://registry.npmjs.org/peberminta/-/peberminta-0.9.0.tgz",
|
||||
"integrity": "sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ==",
|
||||
"funding": {
|
||||
"url": "https://ko-fi.com/killymxi"
|
||||
}
|
||||
},
|
||||
"node_modules/phin": {
|
||||
"version": "2.9.3",
|
||||
"resolved": "https://registry.npmjs.org/phin/-/phin-2.9.3.tgz",
|
||||
@@ -17809,31 +17735,6 @@
|
||||
"resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz",
|
||||
"integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg=="
|
||||
},
|
||||
"node_modules/railroad-diagrams": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz",
|
||||
"integrity": "sha512-cz93DjNeLY0idrCNOH6PviZGRN9GJhsdm9hpn1YCS879fj4W+x5IFJhhkRZcwVgMmFF7R82UA/7Oh+R8lLZg6A=="
|
||||
},
|
||||
"node_modules/randexp": {
|
||||
"version": "0.4.6",
|
||||
"resolved": "https://registry.npmjs.org/randexp/-/randexp-0.4.6.tgz",
|
||||
"integrity": "sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ==",
|
||||
"dependencies": {
|
||||
"discontinuous-range": "1.0.0",
|
||||
"ret": "~0.1.10"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.12"
|
||||
}
|
||||
},
|
||||
"node_modules/randexp/node_modules/ret": {
|
||||
"version": "0.1.15",
|
||||
"resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
|
||||
"integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
|
||||
"engines": {
|
||||
"node": ">=0.12"
|
||||
}
|
||||
},
|
||||
"node_modules/randombytes": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
||||
@@ -17957,9 +17858,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-actions-sheet": {
|
||||
"version": "0.9.0-alpha.14",
|
||||
"resolved": "https://registry.npmjs.org/react-native-actions-sheet/-/react-native-actions-sheet-0.9.0-alpha.14.tgz",
|
||||
"integrity": "sha512-O1fktAenv2+yv/j72Z/jKsNFMMv6pobcavokbmWY/xcOJqHgo7YNtKZ0xU1s6KTk6VitH7TQXkP22hmM7KpQbg==",
|
||||
"version": "0.9.0-alpha.18",
|
||||
"resolved": "https://registry.npmjs.org/react-native-actions-sheet/-/react-native-actions-sheet-0.9.0-alpha.18.tgz",
|
||||
"integrity": "sha512-X3PBVXyI7DQMfa1p3TbEFY2UjAUGqwl9ej6HxZ6ohm4KacqmGoDUZKLNz9lKCzw0vYeK8lwxtCC7qDSuEEgGQg==",
|
||||
"peerDependencies": {
|
||||
"react-native": "*",
|
||||
"react-native-gesture-handler": "*"
|
||||
@@ -17969,6 +17870,7 @@
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-actions-shortcuts/-/react-native-actions-shortcuts-1.0.1.tgz",
|
||||
"integrity": "sha512-oAVi15d4Y3YygsObRzPVcV6ZYPbPb25iHTeO4UYNwYVnW8VtpguOj6d4u6kZ7dh9c7fQvyCSf1gEyLwqydlYqg==",
|
||||
"dev": true,
|
||||
"peerDependencies": {
|
||||
"react": "*",
|
||||
"react-native": "*"
|
||||
@@ -18418,6 +18320,11 @@
|
||||
"react-native": ">=0.65.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-navigation-bar-color": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react-native-navigation-bar-color/-/react-native-navigation-bar-color-2.0.2.tgz",
|
||||
"integrity": "sha512-ZmpLWRocyme1au11e5ZuecMS/UCi57nlzgnioi03Q6ERMbeUOqqbWgNBaNB7SsCeqBV6fZPjo3+A64zEIpzw4w=="
|
||||
},
|
||||
"node_modules/react-native-notification-sounds": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/react-native-notification-sounds/-/react-native-notification-sounds-0.5.5.tgz",
|
||||
@@ -19155,11 +19062,11 @@
|
||||
"integrity": "sha512-ZQruFgZnIWH+WyO9t5rWt4ZEGqCKPwhiw+YbzTwpmT9elgLrLcfuyUiSnwwjUiVy9r4VM3urtbNF1xmEh9IL2w=="
|
||||
},
|
||||
"node_modules/selderee": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/selderee/-/selderee-0.6.0.tgz",
|
||||
"integrity": "sha512-ibqWGV5aChDvfVdqNYuaJP/HnVBhlRGSRrlbttmlMpHcLuTqqbMH36QkSs9GEgj5M88JDYLI8eyP94JaQ8xRlg==",
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/selderee/-/selderee-0.11.0.tgz",
|
||||
"integrity": "sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA==",
|
||||
"dependencies": {
|
||||
"parseley": "^0.7.0"
|
||||
"parseley": "^0.12.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://ko-fi.com/killymxi"
|
||||
@@ -24307,12 +24214,10 @@
|
||||
"dayjs": "^1.10.4",
|
||||
"entities": "^3.0.1",
|
||||
"fflate": "^0.7.3",
|
||||
"html-to-text": "8.1.0",
|
||||
"html-to-text": "9.0.5",
|
||||
"phone": "^3.1.14",
|
||||
"qclone": "^1.2.0",
|
||||
"react": "18.0.0",
|
||||
"react-native": "0.69.7",
|
||||
"react-native-actions-sheet": "^0.9.0-alpha.14",
|
||||
"react-native-actions-sheet": "0.9.0-alpha.18",
|
||||
"react-native-check-version": "https://github.com/flexible-agency/react-native-check-version",
|
||||
"react-native-drax": "^0.10.2",
|
||||
"react-native-image-zoom-viewer": "^3.0.1",
|
||||
@@ -24401,6 +24306,7 @@
|
||||
"react-native-keychain": "4.0.5",
|
||||
"react-native-mmkv-storage": "^0.8.0",
|
||||
"react-native-modal-datetime-picker": "14.0.0",
|
||||
"react-native-navigation-bar-color": "2.0.2",
|
||||
"react-native-notification-sounds": "0.5.5",
|
||||
"react-native-orientation": "https://github.com/yamill/react-native-orientation.git",
|
||||
"react-native-privacy-snapshot": "https://github.com/standardnotes/react-native-privacy-snapshot.git",
|
||||
@@ -25570,12 +25476,12 @@
|
||||
"integrity": "sha512-1k57PXJIfhZrjA4ZQr+goTEYer8MBhe1At6XjVYJq1oBuhG/CIu0gX1EH9fU9exC65e5uDs/zAwjl6Ps+3lCgg=="
|
||||
},
|
||||
"@selderee/plugin-htmlparser2": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.6.0.tgz",
|
||||
"integrity": "sha512-J3jpy002TyBjd4N/p6s+s90eX42H2eRhK3SbsZuvTDv977/E8p2U3zikdiehyJja66do7FlxLomZLPlvl2/xaA==",
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.11.0.tgz",
|
||||
"integrity": "sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==",
|
||||
"requires": {
|
||||
"domhandler": "^4.2.0",
|
||||
"selderee": "^0.6.0"
|
||||
"domhandler": "^5.0.3",
|
||||
"selderee": "^0.11.0"
|
||||
}
|
||||
},
|
||||
"@shopify/flash-list": {
|
||||
@@ -27517,41 +27423,6 @@
|
||||
"domhandler": "^5.0.2",
|
||||
"domutils": "^3.0.1",
|
||||
"nth-check": "^2.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"dom-serializer": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
|
||||
"integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
|
||||
"requires": {
|
||||
"domelementtype": "^2.3.0",
|
||||
"domhandler": "^5.0.2",
|
||||
"entities": "^4.2.0"
|
||||
}
|
||||
},
|
||||
"domhandler": {
|
||||
"version": "5.0.3",
|
||||
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
|
||||
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
|
||||
"requires": {
|
||||
"domelementtype": "^2.3.0"
|
||||
}
|
||||
},
|
||||
"domutils": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz",
|
||||
"integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==",
|
||||
"requires": {
|
||||
"dom-serializer": "^2.0.0",
|
||||
"domelementtype": "^2.3.0",
|
||||
"domhandler": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"entities": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz",
|
||||
"integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"css-tree": {
|
||||
@@ -27624,9 +27495,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"deepmerge": {
|
||||
"version": "4.2.2",
|
||||
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz",
|
||||
"integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg=="
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
|
||||
"integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="
|
||||
},
|
||||
"defaults": {
|
||||
"version": "1.0.4",
|
||||
@@ -27820,11 +27691,6 @@
|
||||
"path-type": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"discontinuous-range": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/discontinuous-range/-/discontinuous-range-1.0.0.tgz",
|
||||
"integrity": "sha512-c68LpLbO+7kP/b1Hr1qs8/BJ09F5khZGTxqxZuhzxpmwJKOgRFHJWIb9/KmqnqHhLdO55aOxFH/EGBvUQbL/RQ=="
|
||||
},
|
||||
"doctrine": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
|
||||
@@ -27835,19 +27701,19 @@
|
||||
}
|
||||
},
|
||||
"dom-serializer": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz",
|
||||
"integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==",
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
|
||||
"integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
|
||||
"requires": {
|
||||
"domelementtype": "^2.0.1",
|
||||
"domhandler": "^4.2.0",
|
||||
"entities": "^2.0.0"
|
||||
"domelementtype": "^2.3.0",
|
||||
"domhandler": "^5.0.2",
|
||||
"entities": "^4.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"entities": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
|
||||
"integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A=="
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
|
||||
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -27862,21 +27728,21 @@
|
||||
"integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="
|
||||
},
|
||||
"domhandler": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz",
|
||||
"integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==",
|
||||
"version": "5.0.3",
|
||||
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
|
||||
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
|
||||
"requires": {
|
||||
"domelementtype": "^2.2.0"
|
||||
"domelementtype": "^2.3.0"
|
||||
}
|
||||
},
|
||||
"domutils": {
|
||||
"version": "2.8.0",
|
||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
|
||||
"integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==",
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz",
|
||||
"integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==",
|
||||
"requires": {
|
||||
"dom-serializer": "^1.0.1",
|
||||
"domelementtype": "^2.2.0",
|
||||
"domhandler": "^4.2.0"
|
||||
"dom-serializer": "^2.0.0",
|
||||
"domelementtype": "^2.3.0",
|
||||
"domhandler": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"dooboolab-welcome": {
|
||||
@@ -29591,11 +29457,6 @@
|
||||
"type-fest": "^0.8.0"
|
||||
}
|
||||
},
|
||||
"he": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
|
||||
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
|
||||
},
|
||||
"hermes-engine": {
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/hermes-engine/-/hermes-engine-0.11.0.tgz",
|
||||
@@ -29642,33 +29503,32 @@
|
||||
"dev": true
|
||||
},
|
||||
"html-to-text": {
|
||||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmjs.org/html-to-text/-/html-to-text-8.1.0.tgz",
|
||||
"integrity": "sha512-Z9iYAqYK2c18GswSbnxJSeMs7lyJgwR2oIkDOyOHGBbYsPsG4HvT379jj3Lcbfko8A5ceyyMHAfkmp/BiXA9/Q==",
|
||||
"version": "9.0.5",
|
||||
"resolved": "https://registry.npmjs.org/html-to-text/-/html-to-text-9.0.5.tgz",
|
||||
"integrity": "sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg==",
|
||||
"requires": {
|
||||
"@selderee/plugin-htmlparser2": "^0.6.0",
|
||||
"deepmerge": "^4.2.2",
|
||||
"he": "^1.2.0",
|
||||
"htmlparser2": "^6.1.0",
|
||||
"minimist": "^1.2.5",
|
||||
"selderee": "^0.6.0"
|
||||
"@selderee/plugin-htmlparser2": "^0.11.0",
|
||||
"deepmerge": "^4.3.1",
|
||||
"dom-serializer": "^2.0.0",
|
||||
"htmlparser2": "^8.0.2",
|
||||
"selderee": "^0.11.0"
|
||||
}
|
||||
},
|
||||
"htmlparser2": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz",
|
||||
"integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==",
|
||||
"version": "8.0.2",
|
||||
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz",
|
||||
"integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==",
|
||||
"requires": {
|
||||
"domelementtype": "^2.0.1",
|
||||
"domhandler": "^4.0.0",
|
||||
"domutils": "^2.5.2",
|
||||
"entities": "^2.0.0"
|
||||
"domelementtype": "^2.3.0",
|
||||
"domhandler": "^5.0.3",
|
||||
"domutils": "^3.0.1",
|
||||
"entities": "^4.4.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"entities": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
|
||||
"integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A=="
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
|
||||
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -32130,6 +31990,11 @@
|
||||
"resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
|
||||
"integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="
|
||||
},
|
||||
"leac": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/leac/-/leac-0.6.0.tgz",
|
||||
"integrity": "sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg=="
|
||||
},
|
||||
"leven": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
|
||||
@@ -33538,11 +33403,6 @@
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"moo": {
|
||||
"version": "0.5.2",
|
||||
"resolved": "https://registry.npmjs.org/moo/-/moo-0.5.2.tgz",
|
||||
"integrity": "sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q=="
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
@@ -33629,17 +33489,6 @@
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"nearley": {
|
||||
"version": "2.20.1",
|
||||
"resolved": "https://registry.npmjs.org/nearley/-/nearley-2.20.1.tgz",
|
||||
"integrity": "sha512-+Mc8UaAebFzgV+KpI5n7DasuuQCHA89dmwm7JXw3TV43ukfNQ9DnBH3Mdb2g/I4Fdxc26pwimBWvjIw0UAILSQ==",
|
||||
"requires": {
|
||||
"commander": "^2.19.0",
|
||||
"moo": "^0.5.0",
|
||||
"railroad-diagrams": "^1.0.0",
|
||||
"randexp": "0.4.6"
|
||||
}
|
||||
},
|
||||
"negotiator": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
|
||||
@@ -34116,12 +33965,12 @@
|
||||
}
|
||||
},
|
||||
"parseley": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/parseley/-/parseley-0.7.0.tgz",
|
||||
"integrity": "sha512-xyOytsdDu077M3/46Am+2cGXEKM9U9QclBDv7fimY7e+BBlxh2JcBp2mgNsmkyA9uvgyTjVzDi7cP1v4hcFxbw==",
|
||||
"version": "0.12.0",
|
||||
"resolved": "https://registry.npmjs.org/parseley/-/parseley-0.12.0.tgz",
|
||||
"integrity": "sha512-uLqDm6IQVb6m50a3dIxF66hI8VWr7wFDYUULtHa1ITRh9mwYIXzFpPTkPM66Cm5V0t+bMyeSHgUCGzoXTV96LQ==",
|
||||
"requires": {
|
||||
"moo": "^0.5.1",
|
||||
"nearley": "^2.20.1"
|
||||
"leac": "^0.6.0",
|
||||
"peberminta": "^0.9.0"
|
||||
}
|
||||
},
|
||||
"parseurl": {
|
||||
@@ -34181,6 +34030,11 @@
|
||||
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
|
||||
"dev": true
|
||||
},
|
||||
"peberminta": {
|
||||
"version": "0.9.0",
|
||||
"resolved": "https://registry.npmjs.org/peberminta/-/peberminta-0.9.0.tgz",
|
||||
"integrity": "sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ=="
|
||||
},
|
||||
"phin": {
|
||||
"version": "2.9.3",
|
||||
"resolved": "https://registry.npmjs.org/phin/-/phin-2.9.3.tgz",
|
||||
@@ -34731,27 +34585,6 @@
|
||||
"resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz",
|
||||
"integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg=="
|
||||
},
|
||||
"railroad-diagrams": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz",
|
||||
"integrity": "sha512-cz93DjNeLY0idrCNOH6PviZGRN9GJhsdm9hpn1YCS879fj4W+x5IFJhhkRZcwVgMmFF7R82UA/7Oh+R8lLZg6A=="
|
||||
},
|
||||
"randexp": {
|
||||
"version": "0.4.6",
|
||||
"resolved": "https://registry.npmjs.org/randexp/-/randexp-0.4.6.tgz",
|
||||
"integrity": "sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ==",
|
||||
"requires": {
|
||||
"discontinuous-range": "1.0.0",
|
||||
"ret": "~0.1.10"
|
||||
},
|
||||
"dependencies": {
|
||||
"ret": {
|
||||
"version": "0.1.15",
|
||||
"resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
|
||||
"integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"randombytes": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
||||
@@ -34856,14 +34689,15 @@
|
||||
}
|
||||
},
|
||||
"react-native-actions-sheet": {
|
||||
"version": "0.9.0-alpha.14",
|
||||
"resolved": "https://registry.npmjs.org/react-native-actions-sheet/-/react-native-actions-sheet-0.9.0-alpha.14.tgz",
|
||||
"integrity": "sha512-O1fktAenv2+yv/j72Z/jKsNFMMv6pobcavokbmWY/xcOJqHgo7YNtKZ0xU1s6KTk6VitH7TQXkP22hmM7KpQbg=="
|
||||
"version": "0.9.0-alpha.18",
|
||||
"resolved": "https://registry.npmjs.org/react-native-actions-sheet/-/react-native-actions-sheet-0.9.0-alpha.18.tgz",
|
||||
"integrity": "sha512-X3PBVXyI7DQMfa1p3TbEFY2UjAUGqwl9ej6HxZ6ohm4KacqmGoDUZKLNz9lKCzw0vYeK8lwxtCC7qDSuEEgGQg=="
|
||||
},
|
||||
"react-native-actions-shortcuts": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-actions-shortcuts/-/react-native-actions-shortcuts-1.0.1.tgz",
|
||||
"integrity": "sha512-oAVi15d4Y3YygsObRzPVcV6ZYPbPb25iHTeO4UYNwYVnW8VtpguOj6d4u6kZ7dh9c7fQvyCSf1gEyLwqydlYqg=="
|
||||
"integrity": "sha512-oAVi15d4Y3YygsObRzPVcV6ZYPbPb25iHTeO4UYNwYVnW8VtpguOj6d4u6kZ7dh9c7fQvyCSf1gEyLwqydlYqg==",
|
||||
"dev": true
|
||||
},
|
||||
"react-native-background-actions": {
|
||||
"version": "2.6.7",
|
||||
@@ -35172,6 +35006,11 @@
|
||||
"prop-types": "^15.7.2"
|
||||
}
|
||||
},
|
||||
"react-native-navigation-bar-color": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react-native-navigation-bar-color/-/react-native-navigation-bar-color-2.0.2.tgz",
|
||||
"integrity": "sha512-ZmpLWRocyme1au11e5ZuecMS/UCi57nlzgnioi03Q6ERMbeUOqqbWgNBaNB7SsCeqBV6fZPjo3+A64zEIpzw4w=="
|
||||
},
|
||||
"react-native-notification-sounds": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/react-native-notification-sounds/-/react-native-notification-sounds-0.5.5.tgz",
|
||||
@@ -35701,11 +35540,11 @@
|
||||
"integrity": "sha512-ZQruFgZnIWH+WyO9t5rWt4ZEGqCKPwhiw+YbzTwpmT9elgLrLcfuyUiSnwwjUiVy9r4VM3urtbNF1xmEh9IL2w=="
|
||||
},
|
||||
"selderee": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/selderee/-/selderee-0.6.0.tgz",
|
||||
"integrity": "sha512-ibqWGV5aChDvfVdqNYuaJP/HnVBhlRGSRrlbttmlMpHcLuTqqbMH36QkSs9GEgj5M88JDYLI8eyP94JaQ8xRlg==",
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/selderee/-/selderee-0.11.0.tgz",
|
||||
"integrity": "sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA==",
|
||||
"requires": {
|
||||
"parseley": "^0.7.0"
|
||||
"parseley": "^0.12.0"
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@notesnook/mobile",
|
||||
"version": "2.4.8",
|
||||
"version": "2.4.13",
|
||||
"private": true,
|
||||
"license": "GPL-3.0-or-later",
|
||||
"workspaces": [
|
||||
@@ -28,12 +28,10 @@
|
||||
"otplib": "12.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"react": "18.0.0",
|
||||
"react-native": "0.69.7",
|
||||
"@notesnook/core": "*",
|
||||
"@notesnook/editor": "*",
|
||||
"@notesnook/editor-mobile": "*",
|
||||
"fflate": "^0.7.3",
|
||||
"react-native-actions-shortcuts": "^1.0.1",
|
||||
"react-native-fingerprint-scanner": "https://github.com/ammarahm-ed/react-native-fingerprint-scanner.git",
|
||||
"react-native-iap": "7.5.6"
|
||||
"@notesnook/editor-mobile": "*"
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
diff --git a/node_modules/html-to-text/lib/formatter.js b/node_modules/html-to-text/lib/formatter.js
|
||||
index d6cb1e6..68d0337 100644
|
||||
--- a/node_modules/html-to-text/lib/formatter.js
|
||||
+++ b/node_modules/html-to-text/lib/formatter.js
|
||||
@@ -1,4 +1,4 @@
|
||||
-const he = require('he');
|
||||
+const {decode} = require('entities');
|
||||
|
||||
const { get, numberToLetterSequence, numberToRoman, splitClassesAndIds, trimCharacter } = require('./helper');
|
||||
|
||||
@@ -146,7 +146,7 @@ function withBrackets (str, brackets) {
|
||||
function formatImage (elem, walk, builder, formatOptions) {
|
||||
const attribs = elem.attribs || {};
|
||||
const alt = (attribs.alt)
|
||||
- ? he.decode(attribs.alt, builder.options.decodeOptions)
|
||||
+ ? decode(attribs.alt, builder.options.decodeOptions)
|
||||
: '';
|
||||
const src = (!attribs.src)
|
||||
? ''
|
||||
@@ -176,7 +176,7 @@ function formatAnchor (elem, walk, builder, formatOptions) {
|
||||
href = (formatOptions.baseUrl && href[0] === '/')
|
||||
? formatOptions.baseUrl + href
|
||||
: href;
|
||||
- return he.decode(href, builder.options.decodeOptions);
|
||||
+ return decode(href, builder.options.decodeOptions);
|
||||
}
|
||||
const href = getHref();
|
||||
if (!href) {
|
||||
diff --git a/node_modules/html-to-text/lib/html-to-text.js b/node_modules/html-to-text/lib/html-to-text.js
|
||||
index 9ebda73..8c5345f 100644
|
||||
--- a/node_modules/html-to-text/lib/html-to-text.js
|
||||
+++ b/node_modules/html-to-text/lib/html-to-text.js
|
||||
@@ -1,6 +1,6 @@
|
||||
const { hp2Builder } = require('@selderee/plugin-htmlparser2');
|
||||
const merge = require('deepmerge');
|
||||
-const he = require('he');
|
||||
+const {decode, EntityLevel} = require("entities");
|
||||
const htmlparser = require('htmlparser2');
|
||||
const selderee = require('selderee');
|
||||
|
||||
@@ -27,8 +27,7 @@ const DEFAULT_OPTIONS = {
|
||||
returnDomByDefault: true
|
||||
},
|
||||
decodeOptions: {
|
||||
- isAttributeValue: false,
|
||||
- strict: false
|
||||
+ level:EntityLevel.HTML
|
||||
},
|
||||
formatters: {},
|
||||
limits: {
|
||||
@@ -377,7 +376,7 @@ function recursiveWalk (walk, dom, builder) {
|
||||
for (const elem of dom) {
|
||||
switch (elem.type) {
|
||||
case 'text': {
|
||||
- builder.addInline(he.decode(elem.data, options.decodeOptions));
|
||||
+ builder.addInline(decode(elem.data, options.decodeOptions));
|
||||
break;
|
||||
}
|
||||
case 'tag': {
|
||||
89
apps/mobile/patches/leac+0.6.0.patch
Normal file
@@ -0,0 +1,89 @@
|
||||
diff --git a/node_modules/leac/lib/leac.cjs b/node_modules/leac/lib/leac.cjs
|
||||
index 13123da..9d490e2 100644
|
||||
--- a/node_modules/leac/lib/leac.cjs
|
||||
+++ b/node_modules/leac/lib/leac.cjs
|
||||
@@ -1 +1,83 @@
|
||||
-"use strict";Object.defineProperty(exports,"__esModule",{value:!0});const e=/\n/g;function t(t){const o=[...t.matchAll(e)].map((e=>e.index||0));o.unshift(-1);const s=n(o,0,o.length);return e=>r(s,e)}function n(e,t,r){if(r-t==1)return{offset:e[t],index:t+1};const o=Math.ceil((t+r)/2),s=n(e,t,o),l=n(e,o,r);return{offset:s.offset,low:s,high:l}}function r(e,t){return function(e){return Object.prototype.hasOwnProperty.call(e,"index")}(e)?{line:e.index,column:t-e.offset}:r(e.high.offset<t?e.high:e.low,t)}function o(e,t){return{...e,regex:s(e,t)}}function s(e,t){if(0===e.name.length)throw new Error(`Rule #${t} has empty name, which is not allowed.`);if(function(e){return Object.prototype.hasOwnProperty.call(e,"regex")}(e))return function(e){if(e.global)throw new Error(`Regular expression /${e.source}/${e.flags} contains the global flag, which is not allowed.`);return e.sticky?e:new RegExp(e.source,e.flags+"y")}(e.regex);if(function(e){return Object.prototype.hasOwnProperty.call(e,"str")}(e)){if(0===e.str.length)throw new Error(`Rule #${t} ("${e.name}") has empty "str" property, which is not allowed.`);return new RegExp(l(e.str),"y")}return new RegExp(l(e.name),"y")}function l(e){return e.replace(/[-[\]{}()*+!<=:?./\\^$|#\s,]/g,"\\$&")}exports.createLexer=function(e,n="",r={}){const s="string"!=typeof n?n:r,l="string"==typeof n?n:"",c=e.map(o),i=!!s.lineNumbers;return function(e,n=0){const r=i?t(e):()=>({line:0,column:0});let o=n;const s=[];e:for(;o<e.length;){let t=!1;for(const n of c){n.regex.lastIndex=o;const c=n.regex.exec(e);if(c&&c[0].length>0){if(!n.discard){const e=r(o),t="string"==typeof n.replace?c[0].replace(new RegExp(n.regex.source,n.regex.flags),n.replace):c[0];s.push({state:l,name:n.name,text:t,offset:o,len:c[0].length,line:e.line,column:e.column})}if(o=n.regex.lastIndex,t=!0,n.push){const t=n.push(e,o);s.push(...t.tokens),o=t.offset}if(n.pop)break e;break}}if(!t)break}return{tokens:s,offset:o,complete:e.length<=o}}};
|
||||
+"use strict";
|
||||
+Object.defineProperty(exports, "__esModule", { value: !0 });
|
||||
+const e = /\n/g;
|
||||
+function t(t) {
|
||||
+ const o = [...t.matchAll(e)].map((e) => e.index || 0);
|
||||
+ o.unshift(-1);
|
||||
+ const s = n(o, 0, o.length);
|
||||
+ return (e) => r(s, e);
|
||||
+}
|
||||
+function n(e, t, r) {
|
||||
+ if (r - t == 1) return { offset: e[t], index: t + 1 };
|
||||
+ const o = Math.ceil((t + r) / 2),
|
||||
+ s = n(e, t, o),
|
||||
+ l = n(e, o, r);
|
||||
+ return { offset: s.offset, low: s, high: l };
|
||||
+}
|
||||
+function r(e, t) {
|
||||
+ return (function (e) {
|
||||
+ return Object.prototype.hasOwnProperty.call(e, "index");
|
||||
+ })(e)
|
||||
+ ? { line: e.index, column: t - e.offset }
|
||||
+ : r(e.high.offset < t ? e.high : e.low, t);
|
||||
+}
|
||||
+function _o(e, t) {
|
||||
+ return { ...e, regex: s(e, t) };
|
||||
+}
|
||||
+function s(e, t) {
|
||||
+ if (0 === e.name.length) throw new Error(`Rule #${t} has empty name, which is not allowed.`);
|
||||
+ if (
|
||||
+ (function (e) {
|
||||
+ return Object.prototype.hasOwnProperty.call(e, "regex");
|
||||
+ })(e)
|
||||
+ )
|
||||
+ return (function (e) {
|
||||
+ if (e.global) throw new Error(`Regular expression /${e.source}/${e.flags} contains the global flag, which is not allowed.`);
|
||||
+ return e.sticky ? e : new RegExp(e.source, e.flags + "y");
|
||||
+ })(e.regex);
|
||||
+ if (
|
||||
+ (function (e) {
|
||||
+ return Object.prototype.hasOwnProperty.call(e, "str");
|
||||
+ })(e)
|
||||
+ ) {
|
||||
+ if (0 === e.str.length) throw new Error(`Rule #${t} ("${e.name}") has empty "str" property, which is not allowed.`);
|
||||
+ return new RegExp(l(e.str), "y");
|
||||
+ }
|
||||
+ return new RegExp(l(e.name), "y");
|
||||
+}
|
||||
+function l(e) {
|
||||
+ return e.replace(/[-[\]{}()*+!<=:?./\\^$|#\s,]/g, "\\$&");
|
||||
+}
|
||||
+exports.createLexer = function (_e, n = "", r = {}) {
|
||||
+ const s = "string" != typeof n ? n : r,
|
||||
+ l = "string" == typeof n ? n : "",
|
||||
+ i = !!s.lineNumbers;
|
||||
+ return function (e, n = 0) {
|
||||
+ const r = i ? t(e) : () => ({ line: 0, column: 0 });
|
||||
+ let o = n;
|
||||
+ const s = [];
|
||||
+ e: for (; o < e.length; ) {
|
||||
+ let t = !1;
|
||||
+ let z = _e.map(_o);
|
||||
+ for (const n of z) {
|
||||
+ n.regex.lastIndex = o;
|
||||
+ const c = n.regex.exec(e);
|
||||
+ if (c && c[0].length > 0) {
|
||||
+ if (!n.discard) {
|
||||
+ const e = r(o),
|
||||
+ t = "string" == typeof n.replace ? c[0].replace(new RegExp(n.regex.source, n.regex.flags), n.replace) : c[0];
|
||||
+ s.push({ state: l, name: n.name, text: t, offset: o, len: c[0].length, line: e.line, column: e.column });
|
||||
+ }
|
||||
+ if (((o = n.regex.lastIndex), (t = !0), n.push)) {
|
||||
+ const t = n.push(e, o);
|
||||
+ s.push(...t.tokens), (o = t.offset);
|
||||
+ }
|
||||
+ if (n.pop) break e;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ if (!t) break;
|
||||
+ }
|
||||
+ return { tokens: s, offset: o, complete: true };
|
||||
+ };
|
||||
+};
|
||||
3748
apps/mobile/patches/react-native-navigation-bar-color+2.0.2.patch
Normal file
@@ -17,53 +17,217 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { FlashList } from "@shopify/flash-list";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import {
|
||||
ActivityIndicator,
|
||||
FlatList,
|
||||
Platform,
|
||||
StatusBar,
|
||||
Text,
|
||||
TextInput,
|
||||
TouchableOpacity,
|
||||
useWindowDimensions,
|
||||
View
|
||||
View,
|
||||
useWindowDimensions
|
||||
} from "react-native";
|
||||
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||
import { db } from "../app/common/database";
|
||||
import { getElevation } from "../app/utils";
|
||||
import { useShareStore } from "./store";
|
||||
import { initDatabase, useShareStore } from "./store";
|
||||
|
||||
export const Search = ({ close, getKeyboardHeight, quicknote }) => {
|
||||
const ListItem = ({ item, mode, close }) => {
|
||||
const colors = useShareStore((state) => state.colors);
|
||||
const setAppendNote = useShareStore((state) => state.setAppendNote);
|
||||
const [results, setResults] = useState([]);
|
||||
const [searching, setSearching] = useState(false);
|
||||
const searchKeyword = useRef(null);
|
||||
const selectedNotebooks = useShareStore((state) => state.selectedNotebooks);
|
||||
const selectedTags = useShareStore((state) => state.selectedTags);
|
||||
const isSelected =
|
||||
mode === "appendNote"
|
||||
? false
|
||||
: mode === "selectTags"
|
||||
? selectedTags.indexOf(item.alias) > -1
|
||||
: selectedNotebooks.findIndex(
|
||||
(selected) => selected.id === item.id && selected.type === item.type
|
||||
) > -1;
|
||||
|
||||
const SearchSetters = React.useMemo(
|
||||
() => ({
|
||||
appendNote: (item) => {
|
||||
useShareStore.getState().setAppendNote(item);
|
||||
close();
|
||||
},
|
||||
selectNotebooks: (item) => {
|
||||
const selectedNotebooks = [
|
||||
...useShareStore.getState().selectedNotebooks
|
||||
];
|
||||
const currentIndex = selectedNotebooks.findIndex(
|
||||
(selected) => selected.id === item.id && selected.type === item.type
|
||||
);
|
||||
if (currentIndex === -1) {
|
||||
selectedNotebooks.push(item);
|
||||
} else {
|
||||
selectedNotebooks.splice(currentIndex, 1);
|
||||
}
|
||||
useShareStore.getState().setSelectedNotebooks(selectedNotebooks);
|
||||
},
|
||||
selectTags: (item) => {
|
||||
const selectedTags = [...useShareStore.getState().selectedTags];
|
||||
const currentIndex = selectedTags.indexOf(item.alias);
|
||||
if (currentIndex === -1) {
|
||||
selectedTags.push(item.alias);
|
||||
} else {
|
||||
selectedTags.splice(currentIndex, 1);
|
||||
}
|
||||
useShareStore.getState().setSelectedTags(selectedTags);
|
||||
}
|
||||
}),
|
||||
[close]
|
||||
);
|
||||
const set = React.useMemo(() => SearchSetters[mode], [mode, SearchSetters]);
|
||||
|
||||
const onSelectItem = async (item) => {
|
||||
if (item.locked) {
|
||||
return;
|
||||
}
|
||||
set(item);
|
||||
};
|
||||
|
||||
return (
|
||||
<TouchableOpacity
|
||||
activeOpacity={0.7}
|
||||
onPress={() => onSelectItem(item)}
|
||||
style={{
|
||||
flexDirection: "column",
|
||||
borderBottomWidth: item.topics?.length > 0 ? 0 : 1,
|
||||
borderBottomColor: colors.nav,
|
||||
justifyContent: "center",
|
||||
paddingVertical: 12
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
paddingHorizontal: 12,
|
||||
paddingLeft: item.type === "topic" ? 0 : 12
|
||||
}}
|
||||
>
|
||||
{item.type !== "note" ? (
|
||||
<Icon
|
||||
name={
|
||||
!isSelected
|
||||
? "checkbox-blank-circle-outline"
|
||||
: "check-circle-outline"
|
||||
}
|
||||
style={{
|
||||
marginRight: 10
|
||||
}}
|
||||
size={20}
|
||||
color={isSelected ? colors.accent : colors.icon}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "column"
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
style={{
|
||||
color: colors.pri,
|
||||
fontFamily:
|
||||
item.type === "topic"
|
||||
? "OpenSans-Regular"
|
||||
: "OpenSans-SemiBold",
|
||||
fontSize: 15
|
||||
}}
|
||||
>
|
||||
{item.type === "tag" ? "#" : ""}
|
||||
{item.alias || item.title}
|
||||
</Text>
|
||||
|
||||
{item.type === "note" ? (
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
style={{
|
||||
color: colors.icon,
|
||||
fontSize: 12,
|
||||
fontFamily: "OpenSans-Regular"
|
||||
}}
|
||||
>
|
||||
{item.headline}
|
||||
</Text>
|
||||
) : null}
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{item.type === "notebook" && item.topics && item.topics.length > 0 ? (
|
||||
<View
|
||||
style={{
|
||||
paddingLeft: 40,
|
||||
marginTop: 5
|
||||
}}
|
||||
>
|
||||
{item.topics.map((topic) => (
|
||||
<ListItem key={topic.id} item={topic} mode={mode} close={close} />
|
||||
))}
|
||||
</View>
|
||||
) : null}
|
||||
</TouchableOpacity>
|
||||
);
|
||||
};
|
||||
|
||||
const SearchGetters = {
|
||||
appendNote: () => db.notes.all,
|
||||
selectNotebooks: () => db.notebooks.all,
|
||||
selectTags: () => {
|
||||
const selected = useShareStore.getState().selectedTags;
|
||||
const tags = [];
|
||||
if (selected)
|
||||
tags.push(
|
||||
...selected.map((t) => ({
|
||||
alias: t,
|
||||
type: "tag"
|
||||
}))
|
||||
);
|
||||
|
||||
for (let tag of db.tags.all) {
|
||||
const index = tags.findIndex((t) => t.alias === tag.alias);
|
||||
// Skip selected tags as they are already in the list.
|
||||
if (index > -1) continue;
|
||||
tags.push(tag);
|
||||
}
|
||||
return tags;
|
||||
}
|
||||
};
|
||||
|
||||
const SearchLookup = {
|
||||
appendNote: (items, kwd) => db.lookup.notes(items, kwd),
|
||||
selectNotebooks: (items, kwd) => db.lookup.notebooks(items, kwd),
|
||||
selectTags: (items, kwd) => db.lookup.tags(items, kwd)
|
||||
};
|
||||
|
||||
export const Search = ({ close, getKeyboardHeight, quicknote, mode }) => {
|
||||
const colors = useShareStore((state) => state.colors);
|
||||
|
||||
const { height } = useWindowDimensions();
|
||||
const notes = useRef(null);
|
||||
const timer = useRef(null);
|
||||
const inputRef = useRef();
|
||||
|
||||
const [searchResults, setSearchResults] = useState([]);
|
||||
const searchableItems = useRef(null);
|
||||
const searchKeyword = useRef(null);
|
||||
|
||||
const insets =
|
||||
Platform.OS === "android"
|
||||
? { top: StatusBar.currentHeight }
|
||||
: // eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
useSafeAreaInsets();
|
||||
|
||||
const onSelectItem = async (item) => {
|
||||
if (item.locked) {
|
||||
return;
|
||||
}
|
||||
setAppendNote(item);
|
||||
close();
|
||||
};
|
||||
const get = SearchGetters[mode];
|
||||
const lookup = SearchLookup[mode];
|
||||
|
||||
const onSearch = async () => {
|
||||
if (!notes.current) {
|
||||
await db.init();
|
||||
await db.notes.init();
|
||||
notes.current = db.notes.all;
|
||||
if (!searchableItems.current) {
|
||||
await initDatabase();
|
||||
searchableItems.current = get();
|
||||
}
|
||||
if (timer.current) {
|
||||
clearTimeout(timer.current);
|
||||
@@ -71,61 +235,26 @@ export const Search = ({ close, getKeyboardHeight, quicknote }) => {
|
||||
}
|
||||
timer.current = setTimeout(async () => {
|
||||
if (!searchKeyword.current) {
|
||||
setResults([]);
|
||||
setResults(db.notes.all);
|
||||
setSearchResults([]);
|
||||
setSearchResults(get());
|
||||
return;
|
||||
}
|
||||
setSearching(true);
|
||||
setResults(await db.lookup.notes(notes.current, searchKeyword.current));
|
||||
setSearching(false);
|
||||
}, 500);
|
||||
setSearchResults(
|
||||
await lookup(searchableItems.current, searchKeyword.current)
|
||||
);
|
||||
}, 150);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
await db.init();
|
||||
await db.notes.init();
|
||||
notes.current = db.notes.all;
|
||||
setResults(notes.current);
|
||||
await initDatabase();
|
||||
searchableItems.current = get();
|
||||
setSearchResults(searchableItems.current);
|
||||
})();
|
||||
setTimeout(() => {
|
||||
inputRef.current?.focus();
|
||||
}, 300);
|
||||
}, []);
|
||||
}, [get]);
|
||||
|
||||
const renderItem = ({ item }) =>
|
||||
!item.locked ? (
|
||||
<TouchableOpacity
|
||||
activeOpacity={0.7}
|
||||
onPress={() => onSelectItem(item)}
|
||||
style={{
|
||||
height: 50,
|
||||
paddingHorizontal: 12
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
style={{
|
||||
color: colors.pri,
|
||||
fontFamily: "OpenSans-SemiBold",
|
||||
fontSize: 15
|
||||
}}
|
||||
>
|
||||
{item.title}
|
||||
</Text>
|
||||
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
style={{
|
||||
color: colors.icon,
|
||||
fontSize: 12,
|
||||
fontFamily: "OpenSans-Regular"
|
||||
}}
|
||||
>
|
||||
{item.headline}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
) : null;
|
||||
!item.locked ? <ListItem item={item} mode={mode} close={close} /> : null;
|
||||
|
||||
let extra = quicknote
|
||||
? {
|
||||
@@ -133,6 +262,7 @@ export const Search = ({ close, getKeyboardHeight, quicknote }) => {
|
||||
paddingTop: insets.top
|
||||
}
|
||||
: {};
|
||||
const searchHeight = height - getKeyboardHeight();
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
@@ -160,7 +290,15 @@ export const Search = ({ close, getKeyboardHeight, quicknote }) => {
|
||||
height: 50
|
||||
}}
|
||||
>
|
||||
<Icon name="arrow-left" color={colors.pri} size={25} onPress={close} />
|
||||
<Icon
|
||||
name="arrow-left"
|
||||
color={colors.pri}
|
||||
style={{
|
||||
marginRight: 10
|
||||
}}
|
||||
size={25}
|
||||
onPress={close}
|
||||
/>
|
||||
<TextInput
|
||||
ref={inputRef}
|
||||
placeholder="Search for a note"
|
||||
@@ -168,58 +306,76 @@ export const Search = ({ close, getKeyboardHeight, quicknote }) => {
|
||||
style={{
|
||||
fontSize: 15,
|
||||
fontFamily: "OpenSans-Regular",
|
||||
width: "85%"
|
||||
flex: 1
|
||||
}}
|
||||
onChangeText={(value) => {
|
||||
searchKeyword.current = value;
|
||||
if (mode === "selectTags") {
|
||||
searchKeyword.current = db.tags.sanitize(value);
|
||||
} else {
|
||||
searchKeyword.current = value;
|
||||
}
|
||||
onSearch();
|
||||
}}
|
||||
onSubmitEditing={onSearch}
|
||||
/>
|
||||
{searching ? (
|
||||
<ActivityIndicator size={25} color={colors.icon} />
|
||||
) : (
|
||||
<Icon
|
||||
name="magnify"
|
||||
color={colors.pri}
|
||||
size={25}
|
||||
onPress={onSearch}
|
||||
/>
|
||||
)}
|
||||
|
||||
<Icon name="magnify" color={colors.pri} size={25} onPress={onSearch} />
|
||||
</View>
|
||||
|
||||
<FlatList
|
||||
data={results}
|
||||
<View
|
||||
style={{
|
||||
maxHeight: height - getKeyboardHeight()
|
||||
maxHeight: searchHeight > 550 ? 550 : searchHeight,
|
||||
height: searchHeight > 550 ? 550 : searchHeight
|
||||
}}
|
||||
keyboardShouldPersistTaps="always"
|
||||
keyboardDismissMode="none"
|
||||
keyExtractor={(item) => item.id}
|
||||
renderItem={renderItem}
|
||||
ListFooterComponent={<View style={{ height: 200 }} />}
|
||||
ListEmptyComponent={
|
||||
<View
|
||||
style={{
|
||||
flex: 1,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
height: 200
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
>
|
||||
<FlashList
|
||||
data={searchResults}
|
||||
keyboardShouldPersistTaps="always"
|
||||
keyboardDismissMode="none"
|
||||
renderItem={renderItem}
|
||||
estimatedItemSize={50}
|
||||
ListHeaderComponent={
|
||||
mode === "selectTags" &&
|
||||
(searchResults.length === 0 ||
|
||||
(searchKeyword.current &&
|
||||
searchKeyword.current.length > 0 &&
|
||||
!searchResults.find(
|
||||
(item) => item.title === searchKeyword.current
|
||||
))) ? (
|
||||
<ListItem
|
||||
item={{
|
||||
type: "tag",
|
||||
alias: searchKeyword.current
|
||||
}}
|
||||
mode={mode}
|
||||
close={close}
|
||||
/>
|
||||
) : null
|
||||
}
|
||||
ListFooterComponent={<View style={{ height: 200 }} />}
|
||||
ListEmptyComponent={
|
||||
<View
|
||||
style={{
|
||||
fontFamily: "OpenSans-Regular",
|
||||
color: colors.icon
|
||||
flex: 1,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
height: 200
|
||||
}}
|
||||
>
|
||||
{searchKeyword.current
|
||||
? `No results found for "${searchKeyword.current}"`
|
||||
: "Search for a note to append to it."}
|
||||
</Text>
|
||||
</View>
|
||||
}
|
||||
/>
|
||||
<Text
|
||||
style={{
|
||||
fontFamily: "OpenSans-Regular",
|
||||
color: colors.icon
|
||||
}}
|
||||
>
|
||||
{searchKeyword.current
|
||||
? `No results found for "${searchKeyword.current}"`
|
||||
: "Search for a note to append to it."}
|
||||
</Text>
|
||||
</View>
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -26,11 +26,12 @@ import {
|
||||
Keyboard,
|
||||
Platform,
|
||||
SafeAreaView,
|
||||
ScrollView,
|
||||
StatusBar,
|
||||
Text,
|
||||
TouchableOpacity,
|
||||
useWindowDimensions,
|
||||
View
|
||||
View,
|
||||
useWindowDimensions
|
||||
} from "react-native";
|
||||
import {
|
||||
SafeAreaProvider,
|
||||
@@ -44,10 +45,9 @@ import Storage from "../app/common/database/storage";
|
||||
import { eSendEvent } from "../app/services/event-manager";
|
||||
import { getElevation } from "../app/utils";
|
||||
import { eOnLoadNote } from "../app/utils/events";
|
||||
import { sleep } from "../app/utils/time";
|
||||
import { Search } from "./search";
|
||||
import { useShareStore } from "./store";
|
||||
import { Editor } from "./editor";
|
||||
import { Search } from "./search";
|
||||
import { initDatabase, useShareStore } from "./store";
|
||||
const getLinkPreview = (url) => {
|
||||
return getPreviewData(url, 5000);
|
||||
};
|
||||
@@ -194,7 +194,6 @@ const ShareView = ({ quicknote = false }) => {
|
||||
const appendNote = useShareStore((state) => state.appendNote);
|
||||
const [note, setNote] = useState({ ...defaultNote });
|
||||
const noteContent = useRef();
|
||||
const [loadingIntent, setLoadingIntent] = useState(true);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [loadingExtension, setLoadingExtension] = useState(true);
|
||||
const [rawData, setRawData] = useState({
|
||||
@@ -209,9 +208,9 @@ const ShareView = ({ quicknote = false }) => {
|
||||
? { top: StatusBar.currentHeight }
|
||||
: // eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
useSafeAreaInsets();
|
||||
const [showSearch, setShowSearch] = useState(false);
|
||||
const [searchMode, setSearchMode] = useState(null);
|
||||
|
||||
const [kh, setKh] = useState(0);
|
||||
const editorRef = useRef();
|
||||
|
||||
const onKeyboardDidShow = (event) => {
|
||||
let kHeight = event.endCoordinates.height;
|
||||
@@ -261,7 +260,6 @@ const ShareView = ({ quicknote = false }) => {
|
||||
setRawData({
|
||||
value: ""
|
||||
});
|
||||
setLoadingIntent(false);
|
||||
return;
|
||||
}
|
||||
let note = { ...defaultNote };
|
||||
@@ -281,7 +279,6 @@ const ShareView = ({ quicknote = false }) => {
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
setLoadingIntent(false);
|
||||
}, [onLoad]);
|
||||
|
||||
const onLoad = useCallback(() => {
|
||||
@@ -300,13 +297,12 @@ const ShareView = ({ quicknote = false }) => {
|
||||
//await loadDatabase();
|
||||
setLoadingExtension(false);
|
||||
loadData();
|
||||
useShareStore.getState().restoreAppendNote();
|
||||
useShareStore.getState().restore();
|
||||
})();
|
||||
}, [loadData]);
|
||||
|
||||
const close = async () => {
|
||||
setNote({ ...defaultNote });
|
||||
setLoadingIntent(true);
|
||||
setLoadingExtension(true);
|
||||
if (quicknote) {
|
||||
ShareExtension.openURL("ShareMedia://MainApp");
|
||||
@@ -317,9 +313,7 @@ const ShareView = ({ quicknote = false }) => {
|
||||
|
||||
const onPress = async () => {
|
||||
setLoading(true);
|
||||
await db.init();
|
||||
await db.notes.init();
|
||||
await sleep(1500);
|
||||
await initDatabase();
|
||||
if (!noteContent.current) return;
|
||||
if (appendNote && !db.notes.note(appendNote.id)) {
|
||||
useShareStore.getState().setAppendNote(null);
|
||||
@@ -332,7 +326,7 @@ const ShareView = ({ quicknote = false }) => {
|
||||
let raw = await db.content.raw(appendNote.contentId);
|
||||
_note = {
|
||||
content: {
|
||||
data: raw.data + "\n" + noteContent.current,
|
||||
data: raw.data + noteContent.current,
|
||||
type: "tiptap"
|
||||
},
|
||||
id: appendNote.id,
|
||||
@@ -340,10 +334,29 @@ const ShareView = ({ quicknote = false }) => {
|
||||
};
|
||||
} else {
|
||||
_note = { ...note };
|
||||
_note.tags = useShareStore.getState().selectedTags || [];
|
||||
|
||||
_note.content.data = noteContent.current;
|
||||
_note.sessionId = Date.now();
|
||||
}
|
||||
await db.notes.add(_note);
|
||||
|
||||
let id = await db.notes.add(_note);
|
||||
if (!appendNote) {
|
||||
for (const item of useShareStore.getState().selectedNotebooks) {
|
||||
if (item.type === "notebook") {
|
||||
db.relations.add(item, { id, type: "note" });
|
||||
} else {
|
||||
db.notes.addToNotebook(
|
||||
{
|
||||
id: item.notebookId,
|
||||
topic: item.id
|
||||
},
|
||||
id
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
await db.sync(false, false);
|
||||
await Storage.write("notesAddedFromIntent", "added");
|
||||
close();
|
||||
setLoading(false);
|
||||
@@ -389,6 +402,8 @@ const ShareView = ({ quicknote = false }) => {
|
||||
loadData();
|
||||
}, [loadData]);
|
||||
|
||||
const WrapperView = Platform.OS === "android" ? View : ScrollView;
|
||||
|
||||
return loadingExtension ? null : (
|
||||
<SafeAreaView
|
||||
style={{
|
||||
@@ -398,7 +413,7 @@ const ShareView = ({ quicknote = false }) => {
|
||||
justifyContent: quicknote ? "flex-start" : "flex-end"
|
||||
}}
|
||||
>
|
||||
{quicknote && !showSearch ? (
|
||||
{quicknote && !searchMode ? (
|
||||
<View
|
||||
style={{
|
||||
width: "100%",
|
||||
@@ -417,8 +432,8 @@ const ShareView = ({ quicknote = false }) => {
|
||||
icon="close"
|
||||
iconColor={colors.pri}
|
||||
onPress={() => {
|
||||
if (showSearch) {
|
||||
setShowSearch(false);
|
||||
if (searchMode) {
|
||||
setSearchMode(null);
|
||||
} else {
|
||||
close();
|
||||
}
|
||||
@@ -458,8 +473,8 @@ const ShareView = ({ quicknote = false }) => {
|
||||
<TouchableOpacity
|
||||
activeOpacity={1}
|
||||
onPress={() => {
|
||||
if (showSearch) {
|
||||
setShowSearch(false);
|
||||
if (searchMode) {
|
||||
setSearchMode(null);
|
||||
} else {
|
||||
close();
|
||||
}
|
||||
@@ -482,28 +497,31 @@ const ShareView = ({ quicknote = false }) => {
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
|
||||
{showSearch ? (
|
||||
{searchMode ? (
|
||||
<Search
|
||||
quicknote={quicknote}
|
||||
getKeyboardHeight={() => keyboardHeight.current}
|
||||
mode={searchMode}
|
||||
close={() => {
|
||||
setShowSearch(false);
|
||||
setSearchMode(null);
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
<View
|
||||
<WrapperView
|
||||
style={{
|
||||
paddingVertical: 25,
|
||||
backgroundColor: "transparent",
|
||||
marginBottom: insets.top,
|
||||
display: showSearch ? "none" : "flex"
|
||||
paddingVertical: 12,
|
||||
backgroundColor: colors.bg,
|
||||
display: searchMode ? "none" : "flex",
|
||||
borderTopRightRadius: Platform.OS === "ios" ? 10 : 15,
|
||||
borderTopLeftRadius: Platform.OS === "ios" ? 10 : 15,
|
||||
maxHeight: Platform.OS === "android" ? undefined : "100%"
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
maxHeight: "100%",
|
||||
paddingHorizontal: 12
|
||||
maxHeight: "100%"
|
||||
//paddingHorizontal: 12
|
||||
}}
|
||||
>
|
||||
<View
|
||||
@@ -513,20 +531,56 @@ const ShareView = ({ quicknote = false }) => {
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
marginTop: 10,
|
||||
minHeight: 100,
|
||||
borderRadius: 10,
|
||||
...getElevation(quicknote ? 1 : 5),
|
||||
backgroundColor: colors.bg,
|
||||
overflow: "hidden"
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
justifyContent: "space-between",
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
borderBottomWidth: 1,
|
||||
paddingBottom: 12,
|
||||
borderBottomColor: colors.nav,
|
||||
paddingHorizontal: 12
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: 18,
|
||||
fontFamily: "OpenSans-SemiBold"
|
||||
}}
|
||||
>
|
||||
Save to Notesnook
|
||||
</Text>
|
||||
|
||||
<Button
|
||||
title="Done"
|
||||
style={{
|
||||
backgroundColor: colors.accent,
|
||||
height: Platform.OS === "ios" ? 35 : 40,
|
||||
paddingHorizontal: 15,
|
||||
marginBottom: 0
|
||||
}}
|
||||
loading={loading}
|
||||
iconColor={colors.light}
|
||||
onPress={onPress}
|
||||
textStyle={{
|
||||
fontSize: 16,
|
||||
marginLeft: 0
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
<View
|
||||
style={{
|
||||
width: "100%",
|
||||
height: height * 0.3,
|
||||
height: 200,
|
||||
paddingBottom: 15,
|
||||
borderRadius: 10
|
||||
marginBottom: 10,
|
||||
borderBottomColor: colors.nav,
|
||||
borderBottomWidth: 1
|
||||
}}
|
||||
>
|
||||
<SafeAreaProvider
|
||||
@@ -574,59 +628,47 @@ const ShareView = ({ quicknote = false }) => {
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
paddingHorizontal: 12,
|
||||
alignItems: "flex-end",
|
||||
justifyContent: "space-between",
|
||||
width: "100%"
|
||||
width: "100%",
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
<View
|
||||
<Text
|
||||
style={{
|
||||
flexDirection: "row"
|
||||
color: colors.pri,
|
||||
marginRight: 10
|
||||
}}
|
||||
>
|
||||
{rawData.value && isURL(rawData.value) ? (
|
||||
<Button
|
||||
color={mode == 2 ? colors.shade : colors.nav}
|
||||
icon={modes[2].icon}
|
||||
onPress={() => changeMode(2)}
|
||||
title={modes[2].title}
|
||||
iconSize={18}
|
||||
iconColor={mode == 2 ? accent.color : colors.icon}
|
||||
textColor={mode == 2 ? accent.color : colors.icon}
|
||||
type="rounded"
|
||||
style={{ paddingHorizontal: 12 }}
|
||||
/>
|
||||
) : null}
|
||||
Clip Mode:
|
||||
</Text>
|
||||
{rawData.value && isURL(rawData.value) ? (
|
||||
<Button
|
||||
color={mode == 1 ? colors.shade : colors.nav}
|
||||
icon={modes[1].icon}
|
||||
onPress={() => changeMode(1)}
|
||||
title={modes[1].title}
|
||||
iconSize={18}
|
||||
iconColor={mode == 1 ? accent.color : colors.icon}
|
||||
textColor={mode == 1 ? accent.color : colors.icon}
|
||||
type="rounded"
|
||||
style={{ paddingHorizontal: 12 }}
|
||||
/>
|
||||
</View>
|
||||
|
||||
{!quicknote ? (
|
||||
<Button
|
||||
color={accent.color}
|
||||
onPress={onPress}
|
||||
loading={loading || loadingIntent}
|
||||
icon="check"
|
||||
iconSize={20}
|
||||
iconColor={colors.light}
|
||||
color="transparent"
|
||||
icon={mode === 2 ? "radiobox-marked" : "radiobox-blank"}
|
||||
onPress={() => changeMode(2)}
|
||||
title={modes[2].title}
|
||||
iconSize={16}
|
||||
fontSize={14}
|
||||
iconColor={mode == 2 ? accent.color : colors.icon}
|
||||
textColor={mode == 2 ? accent.color : colors.icon}
|
||||
style={{
|
||||
paddingHorizontal: 0,
|
||||
height: 40,
|
||||
width: 40,
|
||||
borderRadius: 100,
|
||||
minWidth: 0
|
||||
height: 30,
|
||||
marginRight: 12,
|
||||
marginBottom: 0
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
<Button
|
||||
color="transparent"
|
||||
icon={mode === 1 ? "radiobox-marked" : "radiobox-blank"}
|
||||
onPress={() => changeMode(1)}
|
||||
title={modes[1].title}
|
||||
iconSize={16}
|
||||
fontSize={14}
|
||||
iconColor={mode == 1 ? accent.color : colors.icon}
|
||||
textColor={mode == 1 ? accent.color : colors.icon}
|
||||
style={{ paddingHorizontal: 0, height: 30, marginBottom: 0 }}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
@@ -638,7 +680,8 @@ const ShareView = ({ quicknote = false }) => {
|
||||
flexDirection: "column",
|
||||
marginTop: 10,
|
||||
alignSelf: "center",
|
||||
alignItems: "center"
|
||||
alignItems: "center",
|
||||
paddingHorizontal: 12
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
@@ -656,38 +699,56 @@ const ShareView = ({ quicknote = false }) => {
|
||||
fontSize: 15
|
||||
}}
|
||||
style={{
|
||||
paddingHorizontal: 0,
|
||||
...getElevation(1),
|
||||
paddingHorizontal: 12,
|
||||
height: 45,
|
||||
width: "100%",
|
||||
marginRight: 0
|
||||
marginRight: 0,
|
||||
borderWidth: 1,
|
||||
borderColor: colors.nav,
|
||||
justifyContent: "flex-start"
|
||||
}}
|
||||
/>
|
||||
|
||||
<Button
|
||||
color={colors.bg}
|
||||
onPress={() => {
|
||||
setShowSearch(true);
|
||||
setSearchMode("appendNote");
|
||||
}}
|
||||
icon="text-short"
|
||||
iconSize={18}
|
||||
iconColor={appendNote ? accent.color : colors.icon}
|
||||
title={`${
|
||||
appendNote ? appendNote.title.slice(0, 25) : "Append to note"
|
||||
}`}
|
||||
textColor={appendNote ? accent.color : colors.icon}
|
||||
title={`Append to a note`}
|
||||
textColor={colors.icon}
|
||||
type="button"
|
||||
textStyle={{
|
||||
fontSize: 15
|
||||
}}
|
||||
style={{
|
||||
paddingHorizontal: 0,
|
||||
...getElevation(1),
|
||||
paddingHorizontal: 12,
|
||||
height: 45,
|
||||
width: "100%",
|
||||
marginRight: 0
|
||||
marginRight: 0,
|
||||
borderWidth: 1,
|
||||
borderColor: colors.nav,
|
||||
justifyContent: "flex-start"
|
||||
}}
|
||||
/>
|
||||
|
||||
{!appendNote ? (
|
||||
<AddTags
|
||||
onPress={() => {
|
||||
setSearchMode("selectTags");
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{!appendNote ? (
|
||||
<AddNotebooks
|
||||
onPress={() => {
|
||||
setSearchMode("selectNotebooks");
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
</View>
|
||||
|
||||
<View
|
||||
@@ -696,11 +757,222 @@ const ShareView = ({ quicknote = false }) => {
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</WrapperView>
|
||||
</SafeAreaView>
|
||||
);
|
||||
};
|
||||
|
||||
const AddNotebooks = ({ onPress }) => {
|
||||
const colors = useShareStore((state) => state.colors);
|
||||
const notebooks = useShareStore((state) => state.selectedNotebooks);
|
||||
return (
|
||||
<TouchableOpacity
|
||||
onPress={onPress}
|
||||
activeOpacity={0.7}
|
||||
style={{
|
||||
paddingHorizontal: 12,
|
||||
width: "100%",
|
||||
marginRight: 0,
|
||||
borderWidth: 1,
|
||||
borderColor: colors.nav,
|
||||
justifyContent: "center",
|
||||
borderRadius: 5,
|
||||
marginBottom: 10,
|
||||
paddingVertical: 10,
|
||||
paddingTop: 5
|
||||
}}
|
||||
>
|
||||
{!notebooks || !notebooks.length ? (
|
||||
<>
|
||||
<View
|
||||
style={{
|
||||
width: "100%",
|
||||
flexDirection: "row",
|
||||
marginTop: 5
|
||||
}}
|
||||
>
|
||||
<Icon
|
||||
name="notebook-outline"
|
||||
size={20}
|
||||
style={{
|
||||
marginRight: 10
|
||||
}}
|
||||
color={colors.icon}
|
||||
/>
|
||||
<Text
|
||||
style={{
|
||||
color: colors.icon,
|
||||
fontSize: 15
|
||||
}}
|
||||
>
|
||||
Add to notebook
|
||||
</Text>
|
||||
</View>
|
||||
</>
|
||||
) : (
|
||||
<View
|
||||
style={{
|
||||
flexWrap: "wrap",
|
||||
width: "100%",
|
||||
flexDirection: "row"
|
||||
}}
|
||||
>
|
||||
{notebooks.map((item) => (
|
||||
<Text
|
||||
style={{
|
||||
color: colors.icon,
|
||||
marginRight: 5,
|
||||
fontSize: 14,
|
||||
borderRadius: 4,
|
||||
paddingHorizontal: 8,
|
||||
backgroundColor: colors.nav,
|
||||
paddingVertical: 5,
|
||||
marginTop: 5
|
||||
}}
|
||||
onPress={() => {
|
||||
const index = notebooks.findIndex(
|
||||
(nb) => nb.id === item.id && nb.type === item.type
|
||||
);
|
||||
const selectedNotebooks = [...notebooks];
|
||||
selectedNotebooks.splice(index, 1);
|
||||
useShareStore
|
||||
.getState()
|
||||
.setSelectedNotebooks(selectedNotebooks);
|
||||
}}
|
||||
key={item.id}
|
||||
>
|
||||
<Icon
|
||||
name={item.type === "topic" ? "bookmark" : "notebook-outline"}
|
||||
size={15}
|
||||
/>{" "}
|
||||
{item.title}
|
||||
</Text>
|
||||
))}
|
||||
|
||||
<Text
|
||||
style={{
|
||||
color: colors.accent,
|
||||
marginRight: 5,
|
||||
fontSize: 14,
|
||||
borderRadius: 4,
|
||||
paddingHorizontal: 8,
|
||||
backgroundColor: colors.nav,
|
||||
paddingVertical: 5,
|
||||
marginTop: 5
|
||||
}}
|
||||
onPress={() => {
|
||||
onPress();
|
||||
}}
|
||||
key="$add-more"
|
||||
>
|
||||
<Icon name="plus" size={16} /> Add more
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
);
|
||||
};
|
||||
|
||||
const AddTags = ({ onPress }) => {
|
||||
const colors = useShareStore((state) => state.colors);
|
||||
const tags = useShareStore((state) => state.selectedTags);
|
||||
return (
|
||||
<TouchableOpacity
|
||||
onPress={onPress}
|
||||
activeOpacity={0.7}
|
||||
style={{
|
||||
paddingHorizontal: 12,
|
||||
height: 45,
|
||||
width: "100%",
|
||||
marginRight: 0,
|
||||
borderWidth: 1,
|
||||
borderColor: colors.nav,
|
||||
justifyContent: "center",
|
||||
borderRadius: 5,
|
||||
marginBottom: 10
|
||||
}}
|
||||
>
|
||||
{!tags || !tags.length ? (
|
||||
<>
|
||||
<View
|
||||
style={{
|
||||
width: "100%",
|
||||
flexDirection: "row"
|
||||
}}
|
||||
>
|
||||
<Icon
|
||||
name="pound"
|
||||
size={20}
|
||||
style={{
|
||||
marginRight: 10
|
||||
}}
|
||||
color={colors.icon}
|
||||
/>
|
||||
<Text
|
||||
style={{
|
||||
color: colors.icon,
|
||||
fontSize: 15
|
||||
}}
|
||||
>
|
||||
Add tags
|
||||
</Text>
|
||||
</View>
|
||||
</>
|
||||
) : (
|
||||
<View
|
||||
style={{
|
||||
flexWrap: "wrap",
|
||||
width: "100%",
|
||||
flexDirection: "row"
|
||||
}}
|
||||
>
|
||||
{tags.map((tag) => (
|
||||
<Text
|
||||
style={{
|
||||
color: colors.icon,
|
||||
marginRight: 5,
|
||||
fontSize: 14,
|
||||
borderRadius: 4,
|
||||
paddingHorizontal: 8,
|
||||
backgroundColor: colors.nav,
|
||||
paddingVertical: 5
|
||||
}}
|
||||
onPress={() => {
|
||||
const index = tags.indexOf(tag);
|
||||
const selectedTags = [...tags];
|
||||
selectedTags.splice(index, 1);
|
||||
useShareStore.getState().setSelectedTags(selectedTags);
|
||||
}}
|
||||
key={tag}
|
||||
>
|
||||
#{tag}
|
||||
</Text>
|
||||
))}
|
||||
|
||||
<Text
|
||||
style={{
|
||||
color: colors.accent,
|
||||
marginRight: 5,
|
||||
fontSize: 14,
|
||||
borderRadius: 4,
|
||||
paddingHorizontal: 8,
|
||||
backgroundColor: colors.nav,
|
||||
paddingVertical: 5
|
||||
}}
|
||||
onPress={() => {
|
||||
onPress();
|
||||
}}
|
||||
key="$add-tag"
|
||||
>
|
||||
<Icon name="plus" size={17} />
|
||||
Add tag
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
);
|
||||
};
|
||||
|
||||
const Button = ({
|
||||
title,
|
||||
onPress,
|
||||
@@ -734,7 +1006,6 @@ const Button = ({
|
||||
alignItems: "center",
|
||||
flexDirection: "row",
|
||||
marginBottom: 10,
|
||||
minWidth: 80,
|
||||
paddingHorizontal: 20
|
||||
},
|
||||
textStyle: {}
|
||||
@@ -767,11 +1038,9 @@ const Button = ({
|
||||
alignItems: "center",
|
||||
flexDirection: "row",
|
||||
marginBottom: 10,
|
||||
minWidth: 80,
|
||||
paddingHorizontal: 20
|
||||
},
|
||||
types[type].style,
|
||||
style
|
||||
{ ...types[type].style, ...style }
|
||||
]}
|
||||
>
|
||||
{loading ? <ActivityIndicator color={iconColor} /> : null}
|
||||
|
||||
@@ -25,6 +25,21 @@ import {
|
||||
COLOR_SCHEME_LIGHT
|
||||
} from "../app/utils/color-scheme";
|
||||
import { MMKV } from "../app/common/database/mmkv";
|
||||
import { db } from "../app/common/database";
|
||||
|
||||
export async function initDatabase() {
|
||||
if (!db.isInitialized) {
|
||||
await db.init();
|
||||
}
|
||||
await db.notes.init();
|
||||
}
|
||||
|
||||
const StorageKeys = {
|
||||
appendNote: "shareMenuAppendNote",
|
||||
selectedNotebooks: "shareMenuSelectedNotebooks",
|
||||
selectedTag: "shareMenuSelectedTag",
|
||||
appSettings: "appSettings"
|
||||
};
|
||||
|
||||
export const useShareStore = create((set) => ({
|
||||
colors:
|
||||
@@ -33,7 +48,7 @@ export const useShareStore = create((set) => ({
|
||||
: COLOR_SCHEME_LIGHT,
|
||||
accent: ACCENT,
|
||||
setAccent: async () => {
|
||||
let appSettings = MMKV.getString("appSettings");
|
||||
let appSettings = MMKV.getString(StorageKeys.appSettings);
|
||||
|
||||
if (appSettings) {
|
||||
appSettings = JSON.parse(appSettings);
|
||||
@@ -56,14 +71,31 @@ export const useShareStore = create((set) => ({
|
||||
},
|
||||
appendNote: null,
|
||||
setAppendNote: (note) => {
|
||||
MMKV.setItem("shareMenuAppendNote", JSON.stringify(note));
|
||||
MMKV.setItem(StorageKeys.appendNote, JSON.stringify(note));
|
||||
set({ appendNote: note });
|
||||
},
|
||||
restoreAppendNote: async () => {
|
||||
let note = MMKV.getString("shareMenuAppendNote");
|
||||
if (note) {
|
||||
note = JSON.parse(note);
|
||||
set({ appendNote: note });
|
||||
}
|
||||
restore: () => {
|
||||
let appendNote = MMKV.getString(StorageKeys.appendNote);
|
||||
let selectedNotebooks = MMKV.getString(StorageKeys.selectedNotebooks);
|
||||
let selectedTags = MMKV.getString(StorageKeys.selectedTag);
|
||||
appendNote = JSON.parse(appendNote);
|
||||
set({
|
||||
appendNote: appendNote ? JSON.parse(appendNote) : null,
|
||||
selectedNotebooks: selectedNotebooks ? JSON.parse(selectedNotebooks) : [],
|
||||
selectedTag: selectedTags ? JSON.parse(selectedTags) : []
|
||||
});
|
||||
},
|
||||
selectedTags: [],
|
||||
selectedNotebooks: [],
|
||||
setSelectedNotebooks: (selectedNotebooks) => {
|
||||
MMKV.setItem(
|
||||
StorageKeys.selectedNotebooks,
|
||||
JSON.stringify(selectedNotebooks)
|
||||
);
|
||||
set({ selectedNotebooks });
|
||||
},
|
||||
setSelectedTags: (selectedTags) => {
|
||||
MMKV.setItem(StorageKeys.selectedTag, JSON.stringify(selectedTags));
|
||||
set({ selectedTags });
|
||||
}
|
||||
}));
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
### The desktop app?
|
||||
|
||||
You can find all the desktop related code in [the `desktop/` directory](./desktop/). Since it uses the web app directly, we are keeping both together. (We should probably move it to it's own project at some point.)
|
||||
You can find all the desktop-related code in [the `desktop/` directory](./desktop/). Since it uses the web app directly, we are keeping both together. (We should probably move it to its own project at some point.)
|
||||
|
||||
### Downloads & releases
|
||||
|
||||
@@ -21,7 +21,7 @@ You can find all the desktop related code in [the `desktop/` directory](./deskto
|
||||
|
||||
## Build instructions
|
||||
|
||||
**Before you start it is recommended that you read [the contributing guidelines](/CONTRIBUTING.md).**
|
||||
> **Before you start, it is recommended that you read [the contributing guidelines](/CONTRIBUTING.md).**
|
||||
|
||||
### Setting up the development environment
|
||||
|
||||
@@ -66,11 +66,11 @@ npx serve apps/web/build
|
||||
|
||||
## Developer guide
|
||||
|
||||
> This project is in a transition state between Javascript & Typescript. We are gradually porting everything over to Typescript so if you can help with that, it'd be great!
|
||||
> This project is in a transition state between Javascript & Typescript. We are gradually porting everything over to Typescript, so if you can help with that, it'd be great!
|
||||
|
||||
### The tech stack
|
||||
|
||||
We try to keep the stack as lean as possible
|
||||
We try to keep the stack as lean as possible:
|
||||
|
||||
1. React v17: UI framework
|
||||
2. Typescript/Javascript: The logical side of the app
|
||||
@@ -82,21 +82,21 @@ We try to keep the stack as lean as possible
|
||||
|
||||
### Project structure
|
||||
|
||||
1. `src/`: 99% of the source code lives here & this is also where you'll be spending most of your time.
|
||||
1. `index.tsx`: **the app entrypoint** responsible for loading the appropriate view based on the current route.
|
||||
2. `app.js`: **the default route** that contains the whole note taking experience (notes list, navigation, editor etc.)
|
||||
3. `views/`: Contains **all the views** including views for login, settings, notes, notebooks & topics.
|
||||
4. `components/`: All the **reusuable UI components** are here (e.g. button, editor, etc.)
|
||||
5. `stores/`: Contains the glue code & **logic for all the UI interaction**. For example, when you pin a note the `src/stores/note-store.js` is responsible for everything including refreshing the list to reflect the changes.
|
||||
6. `navigation/`: All the **routing & navigation** logic lives here. The app uses 2 kinds of routers:
|
||||
1. `routes.js`: This contains all the main routes like `/notes`, `/notebooks` with information on what to render when user goes to a particular route.
|
||||
2. `hash-routes.js`: The hash routes are used for temporary navigation like opening dialogs, opening a note. These look like `#/notes/6307bbd65d5d5d5cb86f6f74/edit`.
|
||||
7. `interfaces/`: This is where the **platform specific storage & encryption logic** lives. These interface implementations are used by the `@notesnook/core` to provide capabilities such as persistence & encryption.
|
||||
8. `hooks/`: Contains all the **general purpose React hooks**
|
||||
9. `utils/`: These are **general-purpose utilities** for performing various tasks such as downloading files, storing configuration etc.
|
||||
1. `src/`: 99% of the source code lives here & this is also where you'll spend most of your time.
|
||||
1. `index.tsx`: **the app entry point** responsible for loading the appropriate view based on the current route.
|
||||
2. `app.js`: **the default route** that contains the whole note-taking experience (notes list, navigation, editor, etc.)
|
||||
3. `views/`: Contains **all the views**, including views for login, settings, notes, notebooks & topics.
|
||||
4. `components/`: All the **reusable UI components** are here (e.g., button, editor, etc.)
|
||||
5. `stores/`: Contains the glue code & **logic for all the UI interactions**. For example, when you pin a note, the `src/stores/note-store.js` is responsible for everything, including refreshing the list to reflect the changes.
|
||||
6. `navigation/`: All the **routing & navigation** logic lives here. The app uses two kinds of routers:
|
||||
1. `routes.js`: This contains all the main routes like `/notes`, `/notebooks` with information on what to render when the user goes to a particular route.
|
||||
2. `hash-routes.js`: The hash routes are used for temporary navigation, like opening dialogs or opening a note. These look like `#/notes/6307bbd65d5d5d5cb86f6f74/edit`.
|
||||
7. `interfaces/`: This is where the **platform-specific storage & encryption logic** lives. These interface implementations are used by the `@notesnook/core` to provide capabilities such as persistence & encryption.
|
||||
8. `hooks/`: Contains all the **general-purpose React hooks**
|
||||
9. `utils/`: These are **general-purpose utilities** for performing various tasks such as downloading files, storing configuration, etc.
|
||||
10. `common/`: This directory contains **the shared logic between the whole app**. For example, this is where the database is instantiated for use throughout the app.
|
||||
11. `commands/`: These are **commands used by the desktop app** for things like checking for updates, storing backups etc.
|
||||
2. `desktop/`: The Electron layer for **the desktop app lives here**. (This should be moved outside into it's own project).
|
||||
11. `commands/`: These are **commands the desktop app uses** for things like checking for updates, storing backups etc.
|
||||
2. `desktop/`: The Electron layer for **the desktop app lives here**. (This should be moved outside into its own project).
|
||||
|
||||
### Running the tests
|
||||
|
||||
|
||||
@@ -33,6 +33,22 @@
|
||||
h6 {
|
||||
color: #212121;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
p[data-spacing="double"] {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
p[data-spacing="single"] {
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
p[data-spacing="single"]:empty {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
pre.codeblock {
|
||||
overflow-x: auto;
|
||||
@@ -147,9 +163,9 @@
|
||||
font-family: PT Mono, Consolas, Monaco, "Andale Mono", "Ubuntu Mono",
|
||||
monospace;
|
||||
text-align: left;
|
||||
white-space: pre;
|
||||
white-space: pre-wrap;
|
||||
word-spacing: normal;
|
||||
word-break: normal;
|
||||
word-break: break-word;
|
||||
word-wrap: normal;
|
||||
line-height: 1.5;
|
||||
|
||||
|
||||
4
apps/web/desktop/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@notesnook/desktop",
|
||||
"version": "2.4.6",
|
||||
"version": "2.4.8",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@notesnook/desktop",
|
||||
"version": "2.4.6",
|
||||
"version": "2.4.8",
|
||||
"dependencies": {
|
||||
"diary": "^0.3.1",
|
||||
"electron-updater": "^5.3.0",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "@notesnook/desktop",
|
||||
"productName": "Notesnook",
|
||||
"description": "Your private note taking space",
|
||||
"version": "2.4.6",
|
||||
"version": "2.4.8",
|
||||
"appAppleId": "1544027013",
|
||||
"private": true,
|
||||
"main": "./build/electron.js",
|
||||
|
||||
4
apps/web/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@notesnook/web",
|
||||
"version": "2.4.6",
|
||||
"version": "2.4.8",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@notesnook/web",
|
||||
"version": "2.4.6",
|
||||
"version": "2.4.8",
|
||||
"license": "GPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
"@aws-sdk/util-base64-browser": "^3.208.0",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@notesnook/web",
|
||||
"description": "Your private note taking space",
|
||||
"version": "2.4.6",
|
||||
"version": "2.4.8",
|
||||
"private": true,
|
||||
"main": "./src/app.js",
|
||||
"homepage": "https://notesnook.com/",
|
||||
|
||||