Compare commits
110 Commits
fix/reacha
...
3.3.18-and
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e2cf3e81af | ||
|
|
28fa133b6d | ||
|
|
37893ced80 | ||
|
|
900c48292c | ||
|
|
302ae5ddb4 | ||
|
|
24fca08fdc | ||
|
|
91077dc132 | ||
|
|
273bbea938 | ||
|
|
36c44ad201 | ||
|
|
46f5a2d7a7 | ||
|
|
9b359a91cc | ||
|
|
0af831d50b | ||
|
|
3efaeaeeb9 | ||
|
|
00a20dda48 | ||
|
|
ec45160b27 | ||
|
|
eda284ca25 | ||
|
|
1ed331b4bb | ||
|
|
ee74bb4fbf | ||
|
|
df104669a3 | ||
|
|
9621b43bf2 | ||
|
|
503c1a5c8d | ||
|
|
a2fa1d4d78 | ||
|
|
6c6ad9a766 | ||
|
|
fc8807f74d | ||
|
|
edec48f9d4 | ||
|
|
ce98551057 | ||
|
|
74a2cc5b19 | ||
|
|
9628a940e9 | ||
|
|
d48643cbb9 | ||
|
|
558beaf216 | ||
|
|
6cc5d2452b | ||
|
|
e934ef7ffd | ||
|
|
e2d8032ef4 | ||
|
|
81e6101fb5 | ||
|
|
070354920b | ||
|
|
404168fb86 | ||
|
|
d5fa9fd02b | ||
|
|
6cc66d91be | ||
|
|
20a3b3b95e | ||
|
|
9145ea4234 | ||
|
|
0fa79433bd | ||
|
|
5185273b38 | ||
|
|
eadd23de4d | ||
|
|
71d9738980 | ||
|
|
80328af888 | ||
|
|
5e83da5575 | ||
|
|
521afe90ca | ||
|
|
ee3b7b5d7d | ||
|
|
95a9775c26 | ||
|
|
93d1319b25 | ||
|
|
b2bac3808b | ||
|
|
ebf58e68cf | ||
|
|
dc3e909dfe | ||
|
|
bf09e9615a | ||
|
|
b2d30d47d6 | ||
|
|
b1296fd24f | ||
|
|
62d8c89300 | ||
|
|
80c44eee89 | ||
|
|
153eb126fc | ||
|
|
f1fc166713 | ||
|
|
dda36bb036 | ||
|
|
843ad08813 | ||
|
|
a0e3c923e4 | ||
|
|
3095b03b09 | ||
|
|
ea5a0e0a7c | ||
|
|
2b4ec5b03b | ||
|
|
59f7add065 | ||
|
|
9c7bfc2347 | ||
|
|
ef90f40be4 | ||
|
|
bca6a4f22c | ||
|
|
1d3e2b56b2 | ||
|
|
a93a20ed5b | ||
|
|
971a80c183 | ||
|
|
125b60facc | ||
|
|
ef99b47178 | ||
|
|
d65f870213 | ||
|
|
5b3f1c9de2 | ||
|
|
4afb090cb1 | ||
|
|
8cf6e65ed8 | ||
|
|
c85c51ec08 | ||
|
|
dbeabea6c5 | ||
|
|
dfbe2d0f0f | ||
|
|
ea2277ea4e | ||
|
|
ad78105a6e | ||
|
|
36584175e2 | ||
|
|
084b1fdfd2 | ||
|
|
bed091e20f | ||
|
|
4420663687 | ||
|
|
677ae82ffa | ||
|
|
48a3fac9e0 | ||
|
|
e797d37b01 | ||
|
|
ffafd2e787 | ||
|
|
8500c971eb | ||
|
|
5dc62e6df2 | ||
|
|
4479d6cf56 | ||
|
|
1faaf1f6b1 | ||
|
|
1f33ef191a | ||
|
|
d5bf8a6e3c | ||
|
|
5c252c7843 | ||
|
|
d2e10ccaf6 | ||
|
|
89d2b6870f | ||
|
|
26a9086d96 | ||
|
|
9fc8e6b1e5 | ||
|
|
6718650619 | ||
|
|
a622949f23 | ||
|
|
5a2df5b2c1 | ||
|
|
ae751cdd65 | ||
|
|
6f3fc8db3d | ||
|
|
db731856f8 | ||
|
|
217f1dd6d4 |
30
.github/pull_request_template.md
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
## Description
|
||||
<!-- Add a detailed summary of what this feature/bugfix does -->
|
||||
|
||||
## Type of Change
|
||||
- [ ] Bug fix
|
||||
- [ ] Feature
|
||||
|
||||
## Visuals
|
||||
- [ ] Attached relevant screenshots / screen recording / GIF
|
||||
- [ ] N/A (not a feature or no UI changes)
|
||||
|
||||
## Testing
|
||||
- [ ] Ran all E2E tests
|
||||
- [ ] Ran all integration tests
|
||||
- [ ] Added/updated tests for this change (if needed)
|
||||
- [ ] N/A (tests not needed — explanation provided below)
|
||||
|
||||
### If tests were not added, explain why
|
||||
<!-- explanation -->
|
||||
|
||||
## Platform
|
||||
<!-- Describe which platforms this PR is related to -->
|
||||
|
||||
- [ ] Web
|
||||
- [ ] Mobile
|
||||
- [ ] Desktop
|
||||
|
||||
## Sign-off
|
||||
- [ ] QA passed
|
||||
- [ ] UI/UX passed
|
||||
4
apps/desktop/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@notesnook/desktop",
|
||||
"version": "3.3.9-beta.2",
|
||||
"version": "3.3.11",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@notesnook/desktop",
|
||||
"version": "3.3.9-beta.2",
|
||||
"version": "3.3.11",
|
||||
"hasInstallScript": true,
|
||||
"license": "GPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "@notesnook/desktop",
|
||||
"productName": "Notesnook",
|
||||
"description": "Your private note taking space",
|
||||
"version": "3.3.9-beta.2",
|
||||
"version": "3.3.11",
|
||||
"appAppleId": "1544027013",
|
||||
"private": true,
|
||||
"main": "./dist/cjs/index.js",
|
||||
|
||||
@@ -252,6 +252,7 @@ export const osIntegrationRouter = t.router({
|
||||
if (menuItem) menu.append(menuItem);
|
||||
}
|
||||
if (menu.items.length > 0) menu.popup();
|
||||
menu.on("menu-will-close", () => emit.next([]));
|
||||
return () => {
|
||||
menu.removeAllListeners();
|
||||
menu.closePopup();
|
||||
|
||||
@@ -34,6 +34,17 @@ export const windowRouter = t.router({
|
||||
}),
|
||||
maximized: t.procedure.query(() => globalThis.window?.isMaximized()),
|
||||
fullscreen: t.procedure.query(() => globalThis.window?.isFullScreen()),
|
||||
onClose: t.procedure.subscription(() => {
|
||||
return observable<void>((emit) => {
|
||||
function listener() {
|
||||
emit.next();
|
||||
}
|
||||
globalThis.window?.addListener("close", listener);
|
||||
return () => {
|
||||
globalThis.window?.removeListener("close", listener);
|
||||
};
|
||||
});
|
||||
}),
|
||||
onWindowStateChanged: t.procedure.subscription(() => {
|
||||
return observable<{ maximized: boolean; fullscreen: boolean }>((emit) => {
|
||||
function listener() {
|
||||
|
||||
@@ -52,6 +52,9 @@ locale.then(({ default: locale }) => {
|
||||
});
|
||||
setI18nGlobal(i18n);
|
||||
|
||||
const appHostnames = isDevelopment()
|
||||
? ["localhost", "127.0.0.1"]
|
||||
: ["app.notesnook.com"];
|
||||
// only run a single instance
|
||||
if (!MAC_APP_STORE && !app.requestSingleInstanceLock()) {
|
||||
console.log("Another instance is already running!");
|
||||
@@ -173,6 +176,19 @@ async function createWindow() {
|
||||
return { action: "deny" };
|
||||
});
|
||||
|
||||
mainWindow.webContents.on("will-navigate", (event, url) => {
|
||||
try {
|
||||
const parsedUrl = new URL(url);
|
||||
if (!appHostnames.includes(parsedUrl.hostname)) {
|
||||
event.preventDefault();
|
||||
shell.openExternal(url);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("will-navigate: failed to parse URL", url, e);
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
nativeTheme.on("updated", () => {
|
||||
setupTray();
|
||||
setupJumplist();
|
||||
|
||||
@@ -62,7 +62,17 @@ function registerProtocol() {
|
||||
headers: { "Content-Type": extensionToMimeType[fileExtension] }
|
||||
});
|
||||
} else {
|
||||
return net.fetch(request, { bypassCustomProtocolHandlers: true });
|
||||
const requestHeaders = new Headers(request.headers);
|
||||
if (!requestHeaders.has("referer"))
|
||||
requestHeaders.set("referer", PROTOCOL_URL);
|
||||
return await net.fetch(
|
||||
new Request(request, {
|
||||
headers: requestHeaders
|
||||
}),
|
||||
{
|
||||
bypassCustomProtocolHandlers: true
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
console.info(`${SCHEME} protocol inteception "successful"`);
|
||||
|
||||
@@ -125,7 +125,7 @@ android {
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
multiDexEnabled true
|
||||
versionCode 3094
|
||||
versionCode 3098
|
||||
versionName getNpmVersion()
|
||||
testBuildType System.getProperty('testBuildType', 'debug')
|
||||
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
||||
|
||||
@@ -39,28 +39,32 @@ public class BootTaskService extends HeadlessJsTaskService {
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
|
||||
NotificationChannel channel = new NotificationChannel("com.streetwriters.notesnook",
|
||||
"Default",
|
||||
NotificationManager.IMPORTANCE_DEFAULT);
|
||||
try {
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
|
||||
NotificationChannel channel = new NotificationChannel("com.streetwriters.notesnook",
|
||||
"Default",
|
||||
NotificationManager.IMPORTANCE_DEFAULT);
|
||||
|
||||
((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).createNotificationChannel(channel);
|
||||
notification = new NotificationCompat.Builder(this, channel.getId())
|
||||
.setContentTitle("Sync on boot")
|
||||
.setContentText("")
|
||||
.setSmallIcon(R.drawable.ic_stat_name)
|
||||
.build();
|
||||
if (android.os.Build.VERSION.SDK_INT >= 34) {
|
||||
this.startForeground(
|
||||
1,
|
||||
notification,
|
||||
ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE);
|
||||
} else {
|
||||
this.startForeground(
|
||||
1,
|
||||
notification);
|
||||
}
|
||||
|
||||
((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).createNotificationChannel(channel);
|
||||
notification = new NotificationCompat.Builder(this, channel.getId())
|
||||
.setContentTitle("Sync on boot")
|
||||
.setContentText("")
|
||||
.setSmallIcon(R.drawable.ic_stat_name)
|
||||
.build();
|
||||
if (android.os.Build.VERSION.SDK_INT >= 34) {
|
||||
this.startForeground(
|
||||
1,
|
||||
notification,
|
||||
ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE);
|
||||
} else {
|
||||
this.startForeground(
|
||||
1,
|
||||
notification);
|
||||
}
|
||||
|
||||
} catch (Exception ignored) {
|
||||
stopSelf(startId);
|
||||
}
|
||||
|
||||
return super.onStartCommand(intent, flags, startId);
|
||||
|
||||
@@ -4,4 +4,10 @@
|
||||
<domain includeSubdomains="true">10.0.2.2</domain>
|
||||
<domain includeSubdomains="true">localhost</domain>
|
||||
</domain-config>
|
||||
<base-config>
|
||||
<trust-anchors>
|
||||
<certificates src="system" />
|
||||
<certificates src="user" />
|
||||
</trust-anchors>
|
||||
</base-config>
|
||||
</network-security-config>
|
||||
@@ -1,3 +1,3 @@
|
||||
- Bug fixes and minor improvements
|
||||
- Minor bug fixes and performance improvements
|
||||
|
||||
Thank you for using Notesnook!
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"name": "Notesnook",
|
||||
"displayName": "Notesnook"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,8 +127,12 @@ export const withTheme = (Element: (props: any) => JSX.Element) => {
|
||||
.then((theme) => {
|
||||
if (theme) {
|
||||
theme.colorScheme === "dark"
|
||||
? useThemeStore.getState().setDarkTheme(theme)
|
||||
: useThemeStore.getState().setLightTheme(theme);
|
||||
? useThemeStore.setState({
|
||||
darkTheme: theme
|
||||
})
|
||||
: useThemeStore.setState({
|
||||
lightTheme: theme
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
@@ -138,9 +142,9 @@ export const withTheme = (Element: (props: any) => JSX.Element) => {
|
||||
|
||||
const listener = Appearance.addChangeListener(({ colorScheme }) => {
|
||||
if (colorScheme && SettingsService.getProperty("useSystemTheme")) {
|
||||
useThemeStore
|
||||
.getState()
|
||||
.setColorScheme(colorScheme as "light" | "dark");
|
||||
useThemeStore.setState({
|
||||
colorScheme: colorScheme as "light" | "dark"
|
||||
});
|
||||
}
|
||||
});
|
||||
return () => {
|
||||
|
||||
@@ -205,8 +205,9 @@ export async function getDatabaseKey(appLockPassword?: string) {
|
||||
}
|
||||
|
||||
if (await Keychain.hasInternetCredentials("notesnook")) {
|
||||
const userKeyCredentials =
|
||||
await Keychain.getInternetCredentials("notesnook");
|
||||
const userKeyCredentials = await Keychain.getInternetCredentials(
|
||||
"notesnook"
|
||||
);
|
||||
|
||||
if (userKeyCredentials) {
|
||||
const userKeyCipher: Cipher = (await encrypt(
|
||||
|
||||
@@ -72,7 +72,7 @@ export async function setupDatabase(password?: string) {
|
||||
({
|
||||
compress: Gzip.deflate,
|
||||
decompress: Gzip.inflate
|
||||
}) as ICompressor,
|
||||
} as ICompressor),
|
||||
batchSize: 50,
|
||||
sqliteOptions: {
|
||||
dialect: (name) => ({
|
||||
|
||||
@@ -33,6 +33,8 @@ import {
|
||||
} from "./utils";
|
||||
import Upload from "@ammarahmed/react-native-upload";
|
||||
import { CloudUploader } from "react-native-nitro-cloud-uploader";
|
||||
import { useUserStore } from "../../stores/use-user-store";
|
||||
import { sleep } from "../../utils/time";
|
||||
|
||||
// Upload constants
|
||||
const CHUNK_SIZE = 10 * 1024 * 1024; // 10 MB
|
||||
@@ -212,6 +214,9 @@ export async function uploadFile(
|
||||
);
|
||||
|
||||
if (Platform.OS === "android") {
|
||||
useUserStore.setState({
|
||||
disableAppLockRequests: true
|
||||
});
|
||||
const status = await PermissionsAndroid.request(
|
||||
"android.permission.POST_NOTIFICATIONS"
|
||||
);
|
||||
@@ -221,6 +226,10 @@ export async function uploadFile(
|
||||
type: "info"
|
||||
});
|
||||
}
|
||||
await sleep(500);
|
||||
useUserStore.setState({
|
||||
disableAppLockRequests: false
|
||||
});
|
||||
}
|
||||
|
||||
let uploaded = false;
|
||||
|
||||
@@ -161,10 +161,10 @@ export async function checkUpload(
|
||||
size === 0
|
||||
? `File size is 0.`
|
||||
: size === -1
|
||||
? `File verification check failed.`
|
||||
: expectedSize !== decryptedLength
|
||||
? `File size mismatch. Expected ${size} bytes but got ${decryptedLength} bytes.`
|
||||
: undefined;
|
||||
? `File verification check failed.`
|
||||
: expectedSize !== decryptedLength
|
||||
? `File size mismatch. Expected ${size} bytes but got ${decryptedLength} bytes.`
|
||||
: undefined;
|
||||
if (error) throw new Error(error);
|
||||
}
|
||||
|
||||
|
||||
@@ -239,8 +239,8 @@ const AppLocked = () => {
|
||||
deviceMode !== "mobile"
|
||||
? "50%"
|
||||
: Platform.OS == "ios"
|
||||
? "95%"
|
||||
: "100%",
|
||||
? "95%"
|
||||
: "100%",
|
||||
paddingHorizontal: 12,
|
||||
marginBottom: 30,
|
||||
marginTop: 15,
|
||||
|
||||
@@ -59,6 +59,7 @@ import Heading from "../ui/typography/heading";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
import Navigation from "../../services/navigation";
|
||||
|
||||
const Actions = ({
|
||||
attachment,
|
||||
@@ -304,9 +305,9 @@ const Actions = ({
|
||||
<Pressable
|
||||
onPress={async () => {
|
||||
eSendEvent(eCloseSheet, contextId);
|
||||
await sleep(150);
|
||||
close?.();
|
||||
eSendEvent(eCloseAttachmentDialog);
|
||||
await sleep(300);
|
||||
Navigation.navigate("FluidPanelsView");
|
||||
openNote(item, (item as any).type === "trash");
|
||||
}}
|
||||
style={{
|
||||
|
||||
@@ -195,8 +195,8 @@ export const Login = ({
|
||||
? "50%"
|
||||
: "49.99%"
|
||||
: focused
|
||||
? "100%"
|
||||
: "99.9%",
|
||||
? "100%"
|
||||
: "99.9%",
|
||||
backgroundColor: colors.primary.background,
|
||||
alignSelf: "center",
|
||||
paddingHorizontal: DDS.isTab ? 0 : DefaultAppStyles.GAP,
|
||||
|
||||
@@ -161,10 +161,10 @@ const FloatingButton = ({
|
||||
icon
|
||||
? icon
|
||||
: route.name === "Notebooks"
|
||||
? "notebook-plus"
|
||||
: route.name === "Trash"
|
||||
? "delete"
|
||||
: "plus"
|
||||
? "notebook-plus"
|
||||
: route.name === "Trash"
|
||||
? "delete"
|
||||
: "plus"
|
||||
}
|
||||
color={color || colors.primary.accent}
|
||||
size={size === "small" ? AppFontSize.xl : AppFontSize.xxxl}
|
||||
|
||||
@@ -136,8 +136,8 @@ const BaseDialog = ({
|
||||
backgroundColor: background
|
||||
? background
|
||||
: transparent
|
||||
? "transparent"
|
||||
: "rgba(0,0,0,0.3)"
|
||||
? "transparent"
|
||||
: "rgba(0,0,0,0.3)"
|
||||
}}
|
||||
>
|
||||
<KeyboardAvoidingView
|
||||
@@ -155,8 +155,8 @@ const BaseDialog = ({
|
||||
justifyContent: centered
|
||||
? "center"
|
||||
: bottom
|
||||
? "flex-end"
|
||||
: "flex-start"
|
||||
? "flex-end"
|
||||
: "flex-start"
|
||||
}
|
||||
]}
|
||||
>
|
||||
|
||||
@@ -201,14 +201,12 @@ export const AppLockPassword = () => {
|
||||
accountPass
|
||||
? strings.enterAccountPassword()
|
||||
: mode === "change"
|
||||
? keyboardType === "pin"
|
||||
? strings.newPin()
|
||||
: strings.newPassword()
|
||||
: `${
|
||||
keyboardType === "pin"
|
||||
? strings.pin()
|
||||
: strings.password()
|
||||
}`
|
||||
? keyboardType === "pin"
|
||||
? strings.newPin()
|
||||
: strings.newPassword()
|
||||
: `${
|
||||
keyboardType === "pin" ? strings.pin() : strings.password()
|
||||
}`
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -385,8 +383,8 @@ export const AppLockPassword = () => {
|
||||
mode === "remove"
|
||||
? strings.remove()
|
||||
: mode === "change"
|
||||
? strings.change()
|
||||
: strings.save()
|
||||
? strings.change()
|
||||
: strings.save()
|
||||
}
|
||||
negativeTitle={strings.cancel()}
|
||||
positiveType="transparent"
|
||||
|
||||
@@ -56,7 +56,12 @@ import Seperator from "../../ui/seperator";
|
||||
import Paragraph from "../../ui/typography/paragraph";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { DefaultAppStyles } from "../../../utils/styles";
|
||||
import { Note, NoteContent, VAULT_ERRORS } from "@notesnook/core";
|
||||
import {
|
||||
isEncryptedContent,
|
||||
Note,
|
||||
NoteContent,
|
||||
VAULT_ERRORS
|
||||
} from "@notesnook/core";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
|
||||
export const VaultDialog: React.FC = () => {
|
||||
@@ -109,9 +114,17 @@ export const VaultDialog: React.FC = () => {
|
||||
const biometry = await BiometricService.isBiometryAvailable();
|
||||
const available = !!biometry;
|
||||
const fingerprint = await BiometricService.hasInternetCredentials();
|
||||
const noteLocked = data.item
|
||||
? await db.vaults.itemExists(data.item)
|
||||
: false;
|
||||
|
||||
if (data.item) {
|
||||
const locked = await db.vaults.itemExists(data.item);
|
||||
noteLockedRef.current = locked;
|
||||
if (!locked) {
|
||||
const content = await db.content.findByNoteId(data.item!.id);
|
||||
if (content && isEncryptedContent(content)) {
|
||||
noteLockedRef.current = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set refs
|
||||
noteRef.current = data.item;
|
||||
@@ -122,7 +135,6 @@ export const VaultDialog: React.FC = () => {
|
||||
positiveButtonTypeRef.current = data.positiveButtonType || "transparent";
|
||||
customActionTitleRef.current = data.customActionTitle || null;
|
||||
customActionParagraphRef.current = data.customActionParagraph || null;
|
||||
noteLockedRef.current = noteLocked;
|
||||
onUnlockRef.current = data.onUnlock;
|
||||
requestTypeRef.current = data.requestType;
|
||||
|
||||
@@ -417,9 +429,10 @@ export const VaultDialog: React.FC = () => {
|
||||
onUnlockRef.current
|
||||
) {
|
||||
const password = passwordRef.current;
|
||||
const unlock = onUnlockRef.current;
|
||||
close();
|
||||
await sleep(300);
|
||||
onUnlockRef.current(note, password);
|
||||
await sleep(500);
|
||||
unlock(note, password);
|
||||
}
|
||||
} catch (e) {
|
||||
takeErrorAction();
|
||||
|
||||
@@ -32,9 +32,11 @@ import { eOnLoadNote, eShowMergeDialog } from "../../../utils/events";
|
||||
import { fluidTabsRef } from "../../../utils/global-refs";
|
||||
|
||||
import { NotebooksWithDateEdited, TagsWithDateEdited } from "@notesnook/common";
|
||||
import { useTabStore } from "../../../screens/editor/tiptap/use-tab-store";
|
||||
import { editorController } from "../../../screens/editor/tiptap/utils";
|
||||
import { RouteParams } from "../../../stores/use-navigation-store";
|
||||
import NotePreview from "../../note-history/preview";
|
||||
import SelectionWrapper, { selectItem } from "../selection-wrapper";
|
||||
import { RouteParams } from "../../../stores/use-navigation-store";
|
||||
|
||||
export const openNote = async (
|
||||
item: Note,
|
||||
@@ -63,11 +65,19 @@ export const openNote = async (
|
||||
component: <NotePreview note={item} content={content} />
|
||||
});
|
||||
} else {
|
||||
if (!useTabStore.getState().hasTabForNote(note.id!)) {
|
||||
editorController.current.commands.setLoading(
|
||||
true,
|
||||
useTabStore.getState().currentTab
|
||||
);
|
||||
}
|
||||
eSendEvent(eOnLoadNote, {
|
||||
item: note
|
||||
});
|
||||
if (!DDS.isTab) {
|
||||
fluidTabsRef.current?.goToPage("editor");
|
||||
setTimeout(() => {
|
||||
fluidTabsRef.current?.goToPage("editor");
|
||||
}, 32);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -77,10 +77,10 @@ export default function List(props: ListProps) {
|
||||
props.renderedInRoute === "Notes"
|
||||
? "home"
|
||||
: props.renderedInRoute === "Favorites"
|
||||
? "favorites"
|
||||
: props.renderedInRoute === "Trash" || props.dataType === "trash"
|
||||
? "trash"
|
||||
: `${props.dataType}s`;
|
||||
? "favorites"
|
||||
: props.renderedInRoute === "Trash" || props.dataType === "trash"
|
||||
? "trash"
|
||||
: `${props.dataType}s`;
|
||||
|
||||
const groupOptions = useGroupOptions(groupType);
|
||||
|
||||
|
||||
@@ -60,6 +60,7 @@ import { IconButton } from "../ui/icon-button";
|
||||
import Seperator from "../ui/seperator";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { presentDialog } from "../dialog/functions";
|
||||
import { Cipher } from "@notesnook/crypto";
|
||||
|
||||
const MergeConflicts = () => {
|
||||
const { colors } = useThemeColors();
|
||||
@@ -84,12 +85,21 @@ const MergeConflicts = () => {
|
||||
dateEdited: contentToSave.dateEdited
|
||||
});
|
||||
|
||||
const noteLocked = await db.vaults.itemExists(note);
|
||||
const noteContent = await db.content.findByNoteId(note.id);
|
||||
|
||||
if (noteLocked) {
|
||||
await db.vault.save({
|
||||
...contentToSave,
|
||||
sessionId: `${Date.now()}`
|
||||
if (noteContent?.locked) {
|
||||
const selectedContent = contentToSave.conflicted
|
||||
? noteContent
|
||||
: noteContent.conflicted;
|
||||
|
||||
await db.content.add({
|
||||
id: note.contentId,
|
||||
dateResolved: noteContent?.conflicted?.dateModified || Date.now(),
|
||||
sessionId: `${Date.now()}`,
|
||||
data: selectedContent?.data as Cipher<"base64">,
|
||||
type: selectedContent?.type,
|
||||
locked: true,
|
||||
conflicted: undefined
|
||||
});
|
||||
} else {
|
||||
await db.content.add({
|
||||
@@ -138,7 +148,6 @@ const MergeConflicts = () => {
|
||||
onUnlock: async (item, password) => {
|
||||
if (!item || !password) return;
|
||||
const currentContent = await db.content.get(item.contentId!);
|
||||
|
||||
try {
|
||||
noteContent = {
|
||||
...(await db.content.get(item.contentId!)),
|
||||
|
||||
@@ -33,7 +33,6 @@ import AppIcon from "../ui/AppIcon";
|
||||
import { Button } from "../ui/button";
|
||||
import { Pressable } from "../ui/pressable";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { Dialog } from "../dialog";
|
||||
|
||||
const TOP_BAR_ITEMS: ActionId[] = [
|
||||
"pin",
|
||||
@@ -174,15 +173,15 @@ export const Items = ({
|
||||
DDS.isTab
|
||||
? AppFontSize.xxl
|
||||
: shouldShrink
|
||||
? AppFontSize.xxl
|
||||
: AppFontSize.lg
|
||||
? AppFontSize.xxl
|
||||
: AppFontSize.lg
|
||||
}
|
||||
color={
|
||||
item.checked
|
||||
? item.activeColor || colors.primary.accent
|
||||
: item.id.match(/(delete|trash)/g)
|
||||
? colors.error.icon
|
||||
: colors.secondary.icon
|
||||
? colors.error.icon
|
||||
: colors.secondary.icon
|
||||
}
|
||||
/>
|
||||
</Pressable>
|
||||
@@ -213,8 +212,8 @@ export const Items = ({
|
||||
text: item.checked
|
||||
? item.activeColor || colors.primary.accent
|
||||
: item.id === "delete" || item.id === "trash"
|
||||
? colors.error.paragraph
|
||||
: colors.primary.paragraph
|
||||
? colors.error.paragraph
|
||||
: colors.primary.paragraph
|
||||
}}
|
||||
testID={"icon-" + item.id}
|
||||
onPress={item.onPress}
|
||||
@@ -278,8 +277,8 @@ export const Items = ({
|
||||
item.checked
|
||||
? item.activeColor || colors.primary.accent
|
||||
: item.id === "delete" || item.id === "trash"
|
||||
? colors.error.icon
|
||||
: colors.secondary.icon
|
||||
? colors.error.icon
|
||||
: colors.secondary.icon
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -327,8 +326,9 @@ export const Items = ({
|
||||
|
||||
const getTopBarItemChunksOfFour = () => {
|
||||
const chunks = [];
|
||||
for (let i = 0; i < topBarItems.length; i += 5) {
|
||||
chunks.push(topBarItems.slice(i, i + 5));
|
||||
const itemCount = shouldShrink ? 4 : 5;
|
||||
for (let i = 0; i < topBarItems.length; i += itemCount) {
|
||||
chunks.push(topBarItems.slice(i, i + itemCount));
|
||||
}
|
||||
return chunks;
|
||||
};
|
||||
@@ -375,7 +375,8 @@ export const Items = ({
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
paddingHorizontal: DefaultAppStyles.GAP,
|
||||
gap: 5
|
||||
gap: 5,
|
||||
width: width
|
||||
}}
|
||||
>
|
||||
{item.map(renderTopBarItem)}
|
||||
|
||||
@@ -356,7 +356,7 @@ const ProductItem = (props: {
|
||||
(product as RNIap.Subscription)?.productId
|
||||
) ||
|
||||
props.pricingPlans.user?.subscription?.productId ===
|
||||
(product as Plan).id);
|
||||
(product as Plan)?.id);
|
||||
|
||||
useEffect(() => {
|
||||
props.pricingPlans
|
||||
|
||||
@@ -102,9 +102,17 @@ const TabItemComponent = (props: {
|
||||
{props.tab.session?.noteLocked ? (
|
||||
<>
|
||||
{props.tab.session?.locked ? (
|
||||
<Icon size={AppFontSize.md} name="lock" />
|
||||
<Icon
|
||||
size={AppFontSize.md}
|
||||
name="lock"
|
||||
color={colors.primary.icon}
|
||||
/>
|
||||
) : (
|
||||
<Icon size={AppFontSize.md} name="lock-open-outline" />
|
||||
<Icon
|
||||
size={AppFontSize.md}
|
||||
name="lock-open-outline"
|
||||
color={colors.primary.icon}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
) : null}
|
||||
|
||||
@@ -118,8 +118,8 @@ const ListBlockItem = ({
|
||||
{item?.content.length > 200
|
||||
? item?.content.slice(0, 200) + "..."
|
||||
: !item.content || item.content.trim() === ""
|
||||
? strings.linkNoteEmptyBlock()
|
||||
: item.content}
|
||||
? strings.linkNoteEmptyBlock()
|
||||
: item.content}
|
||||
</Paragraph>
|
||||
|
||||
<View
|
||||
|
||||
@@ -104,8 +104,8 @@ const ListBlockItem = ({
|
||||
{item?.content.length > 200
|
||||
? item?.content.slice(0, 200) + "..."
|
||||
: !item.content || item.content.trim() === ""
|
||||
? strings.linkNoteEmptyBlock()
|
||||
: item.content}
|
||||
? strings.linkNoteEmptyBlock()
|
||||
: item.content}
|
||||
</Paragraph>
|
||||
|
||||
<View
|
||||
|
||||
@@ -114,8 +114,8 @@ export const UserSheet = () => {
|
||||
progress ? `(${progress.current})` : ""
|
||||
}`
|
||||
: lastSyncStatus === SyncStatus.Failed
|
||||
? strings.syncFailed()
|
||||
: strings.synced()}{" "}
|
||||
? strings.syncFailed()
|
||||
: strings.synced()}{" "}
|
||||
{!syncing ? (
|
||||
<TimeSince
|
||||
style={{
|
||||
@@ -139,8 +139,8 @@ export const UserSheet = () => {
|
||||
!user || lastSyncStatus === SyncStatus.Failed
|
||||
? colors.error.icon
|
||||
: isOffline
|
||||
? colors.static.orange
|
||||
: colors.success.icon
|
||||
? colors.static.orange
|
||||
: colors.success.icon
|
||||
}
|
||||
/>
|
||||
</Paragraph>
|
||||
|
||||
@@ -136,8 +136,8 @@ const SimpleTabView = ({
|
||||
{loadedKeysRef.current.has(route.key)
|
||||
? getSceneForRoute(route)
|
||||
: navigationState.index === routeIndex
|
||||
? getSceneForRoute(route)
|
||||
: null}
|
||||
? getSceneForRoute(route)
|
||||
: null}
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
@@ -435,8 +435,9 @@ const TabBar = (props: SimpleTabBarProps) => {
|
||||
color={colors.primary.icon}
|
||||
onPress={async () => {
|
||||
if (props.navigationState.index === 1) {
|
||||
const notebooksFeature =
|
||||
await isFeatureAvailable("notebooks");
|
||||
const notebooksFeature = await isFeatureAvailable(
|
||||
"notebooks"
|
||||
);
|
||||
if (!notebooksFeature.isAllowed) {
|
||||
PaywallSheet.present(notebooksFeature);
|
||||
return;
|
||||
|
||||
@@ -151,8 +151,8 @@ export function MenuItem({
|
||||
item.icon === "crown"
|
||||
? colors.static.yellow
|
||||
: isFocused
|
||||
? colors.selected.icon
|
||||
: colors.secondary.icon
|
||||
? colors.selected.icon
|
||||
: colors.secondary.icon
|
||||
}
|
||||
size={AppFontSize.md}
|
||||
/>
|
||||
|
||||
@@ -98,8 +98,8 @@ export const NotebookItem = ({
|
||||
item.depth === 0
|
||||
? undefined
|
||||
: item.depth < 6
|
||||
? 15 * item.depth
|
||||
: 15 * 5,
|
||||
? 15 * item.depth
|
||||
: 15 * 5,
|
||||
width: "100%",
|
||||
marginTop: 2
|
||||
}}
|
||||
@@ -187,8 +187,8 @@ export const NotebookItem = ({
|
||||
!item.hasChildren || disableExpand
|
||||
? "book-outline"
|
||||
: expanded
|
||||
? "chevron-down"
|
||||
: "chevron-right"
|
||||
? "chevron-down"
|
||||
: "chevron-right"
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -241,6 +241,7 @@ export const NotebookItem = ({
|
||||
name="plus"
|
||||
size={AppFontSize.md}
|
||||
testID={`add-notebook-${index}`}
|
||||
color={colors.primary.icon}
|
||||
top={0}
|
||||
left={0}
|
||||
bottom={0}
|
||||
|
||||
@@ -303,7 +303,7 @@ export const SideMenuTags = () => {
|
||||
} catch (e) {
|
||||
DatabaseLogger.error(e);
|
||||
}
|
||||
}, 500);
|
||||
}, 100);
|
||||
}}
|
||||
placeholderTextColor={colors.primary.placeholder}
|
||||
/>
|
||||
|
||||
@@ -158,22 +158,22 @@ export const Toast = ({ context = "global" }) => {
|
||||
toastOptions.icon
|
||||
? toastOptions.icon
|
||||
: toastOptions.type === "success"
|
||||
? "check"
|
||||
: toastOptions.type === "info"
|
||||
? "information"
|
||||
: "close"
|
||||
? "check"
|
||||
: toastOptions.type === "info"
|
||||
? "information"
|
||||
: "close"
|
||||
}
|
||||
size={isFullToastMessage ? AppFontSize.xxxl : AppFontSize.xl}
|
||||
color={
|
||||
toastOptions?.icon
|
||||
? toastOptions?.icon
|
||||
: toastOptions.type === "error"
|
||||
? colors.error.icon
|
||||
: toastOptions.type === "info"
|
||||
? isDark
|
||||
? colors.static.white
|
||||
: colors.static.black
|
||||
: colors.success.icon
|
||||
? colors.error.icon
|
||||
: toastOptions.type === "info"
|
||||
? isDark
|
||||
? colors.static.white
|
||||
: colors.static.black
|
||||
: colors.success.icon
|
||||
}
|
||||
/>
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import { useThemeColors } from "@notesnook/theme";
|
||||
import React from "react";
|
||||
import { ColorValue, TextProps } from "react-native";
|
||||
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||
import EvilIcon from "react-native-vector-icons/EvilIcons";
|
||||
import { AppFontSize } from "../../../utils/size";
|
||||
|
||||
export interface IconProps extends TextProps {
|
||||
@@ -43,11 +44,22 @@ export interface IconProps extends TextProps {
|
||||
*
|
||||
*/
|
||||
color?: ColorValue | number | undefined;
|
||||
|
||||
iconFamily?: "evilicons" | "material";
|
||||
}
|
||||
|
||||
export default function AppIcon(props: IconProps) {
|
||||
export default function AppIcon({
|
||||
iconFamily = "material",
|
||||
...props
|
||||
}: IconProps) {
|
||||
const { colors } = useThemeColors();
|
||||
return (
|
||||
return iconFamily === "evilicons" ? (
|
||||
<EvilIcon
|
||||
size={AppFontSize.md}
|
||||
color={colors.primary.icon}
|
||||
{...(props as any)}
|
||||
/>
|
||||
) : (
|
||||
<Icon
|
||||
size={AppFontSize.md}
|
||||
color={colors.primary.icon}
|
||||
|
||||
@@ -107,7 +107,7 @@ export const IconButton = ({
|
||||
color={
|
||||
restProps.disabled
|
||||
? RGB_Linear_Shade(-0.05, hexToRGBA(colors.secondary.background))
|
||||
: colors.static[color as never] || color
|
||||
: colors.static[color as never] || color || colors.primary.icon
|
||||
}
|
||||
size={size}
|
||||
/>
|
||||
|
||||
@@ -121,8 +121,8 @@ const Input = ({
|
||||
const color = error
|
||||
? colors.error.border
|
||||
: focus
|
||||
? customColor || colors.selected.border
|
||||
: colors.primary.border;
|
||||
? customColor || colors.selected.border
|
||||
: colors.primary.border;
|
||||
|
||||
const validate = async (value: string) => {
|
||||
if (!validationType) return;
|
||||
|
||||
@@ -268,8 +268,8 @@ export const Pressable = ({
|
||||
const opacity = customOpacity
|
||||
? customOpacity
|
||||
: type === "accent"
|
||||
? 1
|
||||
: colorOpacity;
|
||||
? 1
|
||||
: colorOpacity;
|
||||
const alpha = customAlpha ? customAlpha : isDark ? 0.03 : -0.03;
|
||||
const { fontScale } = useWindowDimensions();
|
||||
const growFactor = 1 + (fontScale - 1) / 8;
|
||||
|
||||
@@ -159,7 +159,7 @@ const SheetWrapper = ({
|
||||
{bottomPadding ? (
|
||||
<View
|
||||
style={{
|
||||
height: bottomInsets
|
||||
height: 10
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
@@ -21,6 +21,7 @@ import { isFeatureAvailable, useAreFeaturesAvailable } from "@notesnook/common";
|
||||
import {
|
||||
Color,
|
||||
createInternalLink,
|
||||
isEncryptedContent,
|
||||
Item,
|
||||
ItemReference,
|
||||
Note,
|
||||
@@ -221,7 +222,15 @@ export const useActions = ({
|
||||
|
||||
useEffect(() => {
|
||||
if (item.type === "note") {
|
||||
db.vaults.itemExists(item).then((locked) => setLocked(locked));
|
||||
db.vaults.itemExists(item).then(async (locked) => {
|
||||
setLocked(locked);
|
||||
if (!locked) {
|
||||
const content = await db.content.findByNoteId(item.id);
|
||||
if (content && isEncryptedContent(content)) {
|
||||
setLocked(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}, [item]);
|
||||
|
||||
|
||||
@@ -537,7 +537,6 @@ const initializeDatabase = async (password?: string) => {
|
||||
Notifications.restorePinnedNotes();
|
||||
expiringNotesTimer();
|
||||
deleteDCacheFiles();
|
||||
db.attachments.removeOrphaned();
|
||||
}
|
||||
Walkthrough.init();
|
||||
};
|
||||
|
||||
@@ -60,23 +60,17 @@ export const useDBItem = <T extends keyof ItemTypeKey>(
|
||||
): [ItemTypeKey[T] | undefined, () => void] => {
|
||||
const [item, setItem] = useState<ItemTypeKey[T]>();
|
||||
const itemIdRef = useRef<string>(undefined);
|
||||
const prevIdOrIndexRef = useRef<string | number>(undefined);
|
||||
|
||||
if (prevIdOrIndexRef.current !== idOrIndex) {
|
||||
itemIdRef.current = undefined;
|
||||
prevIdOrIndexRef.current = idOrIndex;
|
||||
}
|
||||
const itemsRef = useRef(item);
|
||||
itemsRef.current = item;
|
||||
|
||||
useEffect(() => {
|
||||
const onUpdateItem = async (itemId?: string) => {
|
||||
if (typeof itemId === "string" && itemId !== itemIdRef.current) return;
|
||||
if (!isValidIdOrIndex(idOrIndex)) return;
|
||||
|
||||
let item: ItemTypeKey[T] | undefined = undefined;
|
||||
if (items && typeof idOrIndex === "number") {
|
||||
const item = (await items.item(idOrIndex))?.item;
|
||||
setItem(item);
|
||||
itemIdRef.current = item?.id;
|
||||
onItemUpdated?.(item);
|
||||
item = (await items.item(idOrIndex))?.item;
|
||||
} else {
|
||||
if (!(db as any)[type + "s"][type]) {
|
||||
console.warn(
|
||||
@@ -84,24 +78,30 @@ export const useDBItem = <T extends keyof ItemTypeKey>(
|
||||
`db.${type}s.${type}(id: string)`
|
||||
);
|
||||
} else {
|
||||
const item = await (db as any)[type + "s"]?.[type]?.(
|
||||
idOrIndex as string
|
||||
);
|
||||
setItem(item);
|
||||
itemIdRef.current = item.id;
|
||||
onItemUpdated?.(item);
|
||||
item = await (db as any)[type + "s"]?.[type]?.(idOrIndex as string);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (
|
||||
itemsRef.current === item ||
|
||||
itemsRef.current?.dateModified === item?.dateModified
|
||||
)
|
||||
return;
|
||||
setItem(item);
|
||||
itemIdRef.current = item?.id;
|
||||
onItemUpdated?.(item);
|
||||
};
|
||||
let unsub: (() => void) | undefined;
|
||||
if (
|
||||
useSettingStore.getState().isAppLoading &&
|
||||
//@ts-ignore
|
||||
!globalThis["IS_SHARE_EXTENSION"]
|
||||
) {
|
||||
useSettingStore.subscribe((state) => {
|
||||
unsub = useSettingStore.subscribe((state) => {
|
||||
if (!state.isAppLoading) {
|
||||
onUpdateItem();
|
||||
unsub?.();
|
||||
unsub = undefined;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
@@ -109,9 +109,10 @@ export const useDBItem = <T extends keyof ItemTypeKey>(
|
||||
}
|
||||
eSubscribeEvent(eDBItemUpdate, onUpdateItem);
|
||||
return () => {
|
||||
unsub?.();
|
||||
eUnSubscribeEvent(eDBItemUpdate, onUpdateItem);
|
||||
};
|
||||
}, [idOrIndex, type, items, onItemUpdated]);
|
||||
}, [idOrIndex, type, items]);
|
||||
|
||||
return [
|
||||
isValidIdOrIndex(idOrIndex) ? (item as ItemTypeKey[T]) : undefined,
|
||||
@@ -134,8 +135,9 @@ export const useNoteLocked = (noteId: string | undefined) => {
|
||||
//@ts-ignore
|
||||
!globalThis["IS_SHARE_EXTENSION"]
|
||||
) {
|
||||
useSettingStore.subscribe((state) => {
|
||||
let unsub = useSettingStore.subscribe((state) => {
|
||||
if (!state.isAppLoading) {
|
||||
unsub();
|
||||
db.vaults
|
||||
.itemExists({
|
||||
type: "note",
|
||||
@@ -181,25 +183,27 @@ export const useTotalNotes = (type: "notebook" | "tag" | "color") => {
|
||||
const [totalNotesById, setTotalNotesById] = useState<{
|
||||
[id: string]: number;
|
||||
}>({});
|
||||
const totalNotesRef = useRef(0);
|
||||
|
||||
const getTotalNotes = React.useCallback(
|
||||
(ids: string[]) => {
|
||||
if (!ids || !ids.length || !type) return;
|
||||
db.relations
|
||||
.from({ type: type, ids: ids as string[] }, ["note"])
|
||||
.get()
|
||||
.then((relations) => {
|
||||
const totalNotesById: any = {};
|
||||
for (const id of ids) {
|
||||
totalNotesById[id] = relations.filter(
|
||||
(relation) => relation.fromId === id && relation.toType === "note"
|
||||
)?.length;
|
||||
}
|
||||
setTotalNotesById(totalNotesById);
|
||||
});
|
||||
},
|
||||
[type]
|
||||
);
|
||||
const getTotalNotes = React.useCallback((ids: string[]) => {
|
||||
if (!ids || !ids.length || !type) return;
|
||||
db.relations
|
||||
.from({ type: type, ids: ids as string[] }, ["note"])
|
||||
.get()
|
||||
.then((relations) => {
|
||||
const totalNotesById: any = {};
|
||||
|
||||
for (const id of ids) {
|
||||
totalNotesById[id] = relations.filter(
|
||||
(relation) => relation.fromId === id && relation.toType === "note"
|
||||
)?.length;
|
||||
}
|
||||
|
||||
if (totalNotesById === totalNotesRef.current) return;
|
||||
totalNotesRef.current = totalNotesById;
|
||||
setTotalNotesById(totalNotesById);
|
||||
});
|
||||
}, []);
|
||||
|
||||
return {
|
||||
totalNotes: (id: string) => {
|
||||
|
||||
@@ -276,8 +276,8 @@ const usePricingPlans = (options?: PricingPlansOptions) => {
|
||||
(product as Plan).period === "yearly"
|
||||
? (product as Plan).price.gross
|
||||
: (product as Plan).period === "5-year"
|
||||
? (product as Plan).price.gross
|
||||
: (product as Plan).price.gross
|
||||
? (product as Plan).price.gross
|
||||
: (product as Plan).price.gross
|
||||
}`;
|
||||
}
|
||||
|
||||
@@ -432,8 +432,8 @@ const usePricingPlans = (options?: PricingPlansOptions) => {
|
||||
return period.endsWith("W")
|
||||
? "week"
|
||||
: period.endsWith("M")
|
||||
? "month"
|
||||
: "year";
|
||||
? "month"
|
||||
: "year";
|
||||
} else {
|
||||
const unit = (product as RNIap.SubscriptionIOS)
|
||||
?.subscriptionPeriodUnitIOS;
|
||||
@@ -475,8 +475,8 @@ const usePricingPlans = (options?: PricingPlansOptions) => {
|
||||
type: phase.billingPeriod.endsWith("W")
|
||||
? "week"
|
||||
: phase.billingPeriod.endsWith("M")
|
||||
? "month"
|
||||
: "year"
|
||||
? "month"
|
||||
: "year"
|
||||
};
|
||||
} else {
|
||||
const productIos = product as RNIap.SubscriptionIOS;
|
||||
@@ -607,8 +607,8 @@ const usePricingPlans = (options?: PricingPlansOptions) => {
|
||||
(product as Plan).period === "yearly"
|
||||
? ((product as Plan).price.gross / 12).toFixed(2)
|
||||
: (product as Plan).period === "5-year"
|
||||
? ((product as Plan).price.gross / (12 * 5)).toFixed(2)
|
||||
: (product as Plan).price.gross
|
||||
? ((product as Plan).price.gross / (12 * 5)).toFixed(2)
|
||||
: (product as Plan).price.gross
|
||||
}`;
|
||||
}
|
||||
|
||||
|
||||
@@ -243,8 +243,8 @@ export const FluidPanelsView = React.memo(
|
||||
const nextDeviceMode = DDS.isLargeTablet()
|
||||
? "tablet"
|
||||
: DDS.isSmallTab
|
||||
? "smallTablet"
|
||||
: "mobile";
|
||||
? "smallTablet"
|
||||
: "mobile";
|
||||
setDeviceMode(nextDeviceMode, size);
|
||||
},
|
||||
[orientation, setDeviceMode, setDimensions]
|
||||
|
||||
@@ -400,45 +400,17 @@ export default function AddReminder(props: NavigationProps<"AddReminder">) {
|
||||
recurringMode === RecurringModes.Year
|
||||
? null
|
||||
: recurringMode === RecurringModes.Week
|
||||
? (weekFormat === "Mon" ? WeekDaysMon : WeekDays).map(
|
||||
(item) => (
|
||||
<Button
|
||||
key={strings.weekDayNamesShort[
|
||||
item as keyof typeof strings.weekDayNamesShort
|
||||
]()}
|
||||
title={strings.weekDayNamesShort[
|
||||
item as keyof typeof strings.weekDayNamesShort
|
||||
]()}
|
||||
type={
|
||||
selectedDays.indexOf(item) > -1
|
||||
? "selected"
|
||||
: "plain"
|
||||
}
|
||||
fontSize={AppFontSize.xs}
|
||||
style={{
|
||||
height: 40,
|
||||
borderRadius: 100,
|
||||
marginRight: 10
|
||||
}}
|
||||
onPress={() => {
|
||||
setSelectedDays((days) => {
|
||||
if (days.indexOf(item) > -1) {
|
||||
days.splice(days.indexOf(item), 1);
|
||||
return [...days];
|
||||
}
|
||||
days.push(item);
|
||||
return [...days];
|
||||
});
|
||||
}}
|
||||
/>
|
||||
)
|
||||
)
|
||||
: MonthDays.map((item, index) => (
|
||||
? (weekFormat === "Mon" ? WeekDaysMon : WeekDays).map(
|
||||
(item) => (
|
||||
<Button
|
||||
key={index + "monthday"}
|
||||
title={index + 1 + ""}
|
||||
key={strings.weekDayNamesShort[
|
||||
item as keyof typeof strings.weekDayNamesShort
|
||||
]()}
|
||||
title={strings.weekDayNamesShort[
|
||||
item as keyof typeof strings.weekDayNamesShort
|
||||
]()}
|
||||
type={
|
||||
selectedDays.indexOf(index + 1) > -1
|
||||
selectedDays.indexOf(item) > -1
|
||||
? "selected"
|
||||
: "plain"
|
||||
}
|
||||
@@ -450,16 +422,44 @@ export default function AddReminder(props: NavigationProps<"AddReminder">) {
|
||||
}}
|
||||
onPress={() => {
|
||||
setSelectedDays((days) => {
|
||||
if (days.indexOf(index + 1) > -1) {
|
||||
days.splice(days.indexOf(index + 1), 1);
|
||||
if (days.indexOf(item) > -1) {
|
||||
days.splice(days.indexOf(item), 1);
|
||||
return [...days];
|
||||
}
|
||||
days.push(index + 1);
|
||||
days.push(item);
|
||||
return [...days];
|
||||
});
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
)
|
||||
)
|
||||
: MonthDays.map((item, index) => (
|
||||
<Button
|
||||
key={index + "monthday"}
|
||||
title={index + 1 + ""}
|
||||
type={
|
||||
selectedDays.indexOf(index + 1) > -1
|
||||
? "selected"
|
||||
: "plain"
|
||||
}
|
||||
fontSize={AppFontSize.xs}
|
||||
style={{
|
||||
height: 40,
|
||||
borderRadius: 100,
|
||||
marginRight: 10
|
||||
}}
|
||||
onPress={() => {
|
||||
setSelectedDays((days) => {
|
||||
if (days.indexOf(index + 1) > -1) {
|
||||
days.splice(days.indexOf(index + 1), 1);
|
||||
return [...days];
|
||||
}
|
||||
days.push(index + 1);
|
||||
return [...days];
|
||||
});
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</ScrollView>
|
||||
</View>
|
||||
) : null}
|
||||
@@ -542,24 +542,24 @@ export default function AddReminder(props: NavigationProps<"AddReminder">) {
|
||||
dayjs(date).format("hh:mm A")
|
||||
)
|
||||
: recurringMode === RecurringModes.Year
|
||||
? strings.reminderRepeatStrings.year(
|
||||
dayjs(date).format("dddd, MMMM D, h:mm A")
|
||||
)
|
||||
: selectedDays.length === 7 &&
|
||||
recurringMode === RecurringModes.Week
|
||||
? strings.reminderRepeatStrings.week.daily(
|
||||
dayjs(date).format("hh:mm A")
|
||||
)
|
||||
: selectedDays.length === 0
|
||||
? strings.reminderRepeatStrings[
|
||||
recurringMode as "week" | "month"
|
||||
].selectDays()
|
||||
: strings.reminderRepeatStrings.repeats(
|
||||
repeatFrequency,
|
||||
recurringMode as string,
|
||||
getSelectedDaysText(selectedDays),
|
||||
dayjs(date).format("hh:mm A")
|
||||
)}
|
||||
? strings.reminderRepeatStrings.year(
|
||||
dayjs(date).format("dddd, MMMM D, h:mm A")
|
||||
)
|
||||
: selectedDays.length === 7 &&
|
||||
recurringMode === RecurringModes.Week
|
||||
? strings.reminderRepeatStrings.week.daily(
|
||||
dayjs(date).format("hh:mm A")
|
||||
)
|
||||
: selectedDays.length === 0
|
||||
? strings.reminderRepeatStrings[
|
||||
recurringMode as "week" | "month"
|
||||
].selectDays()
|
||||
: strings.reminderRepeatStrings.repeats(
|
||||
repeatFrequency,
|
||||
recurringMode as string,
|
||||
getSelectedDaysText(selectedDays),
|
||||
dayjs(date).format("hh:mm A")
|
||||
)}
|
||||
</Paragraph>
|
||||
</>
|
||||
</View>
|
||||
@@ -587,8 +587,8 @@ export default function AddReminder(props: NavigationProps<"AddReminder">) {
|
||||
mode === "Silent"
|
||||
? "minus-circle"
|
||||
: mode === "Vibrate"
|
||||
? "vibrate"
|
||||
: "volume-high"
|
||||
? "vibrate"
|
||||
: "volume-high"
|
||||
}
|
||||
fontSize={AppFontSize.xs}
|
||||
height={35}
|
||||
|
||||
@@ -471,8 +471,9 @@ export const useEditorEvents = (
|
||||
relationType: "from",
|
||||
title: strings.dataTypesPluralCamelCase.reminder(),
|
||||
onAdd: async () => {
|
||||
const reminderFeature =
|
||||
await isFeatureAvailable("activeReminders");
|
||||
const reminderFeature = await isFeatureAvailable(
|
||||
"activeReminders"
|
||||
);
|
||||
if (!reminderFeature.isAllowed) {
|
||||
ToastManager.show({
|
||||
type: "info",
|
||||
|
||||
@@ -487,6 +487,17 @@ export const useEditor = (
|
||||
};
|
||||
} else if (note.contentId) {
|
||||
const rawContent = await db.content?.get(note.contentId);
|
||||
|
||||
if (rawContent && isEncryptedContent(rawContent)) {
|
||||
useTabStore.getState().updateTab(useTabStore.getState().currentTab, {
|
||||
session: {
|
||||
noteLocked: true,
|
||||
locked: true
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (rawContent && !isDeleted(rawContent) && !rawContent.locked) {
|
||||
currentContents.current[note.id] = {
|
||||
data: rawContent.data,
|
||||
|
||||
@@ -237,8 +237,9 @@ const LinkNotebooks = (props: NavigationProps<"LinkNotebooks">) => {
|
||||
button={{
|
||||
icon: "plus",
|
||||
onPress: async () => {
|
||||
const notebooksFeature =
|
||||
await isFeatureAvailable("notebooks");
|
||||
const notebooksFeature = await isFeatureAvailable(
|
||||
"notebooks"
|
||||
);
|
||||
if (!notebooksFeature.isAllowed) {
|
||||
ToastManager.show({
|
||||
message: notebooksFeature.error,
|
||||
@@ -387,8 +388,8 @@ const NotebookItemWrapper = React.memo(
|
||||
!selected
|
||||
? "selected"
|
||||
: !state.initialState[item.notebook.id]
|
||||
? undefined
|
||||
: "deselected"
|
||||
? undefined
|
||||
: "deselected"
|
||||
);
|
||||
}}
|
||||
canDisableSelectionMode={false}
|
||||
|
||||
@@ -417,15 +417,15 @@ const TagItem = ({
|
||||
selection === "selected"
|
||||
? "check-circle-outline"
|
||||
: selection === "intermediate"
|
||||
? "minus-circle-outline"
|
||||
: "checkbox-blank-circle-outline"
|
||||
? "minus-circle-outline"
|
||||
: "checkbox-blank-circle-outline"
|
||||
}
|
||||
name={
|
||||
selection === "selected"
|
||||
? "check-circle-outline"
|
||||
: selection === "intermediate"
|
||||
? "minus-circle-outline"
|
||||
: "checkbox-blank-circle-outline"
|
||||
? "minus-circle-outline"
|
||||
: "checkbox-blank-circle-outline"
|
||||
}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -242,8 +242,9 @@ export const MoveNotebook = (props: NavigationProps<"MoveNotebook">) => {
|
||||
button={{
|
||||
icon: "plus",
|
||||
onPress: async () => {
|
||||
const notebooksFeature =
|
||||
await isFeatureAvailable("notebooks");
|
||||
const notebooksFeature = await isFeatureAvailable(
|
||||
"notebooks"
|
||||
);
|
||||
if (!notebooksFeature.isAllowed) {
|
||||
ToastManager.show({
|
||||
message: notebooksFeature.error,
|
||||
|
||||
@@ -322,8 +322,8 @@ export const MFASetup = ({
|
||||
method?.id === "email"
|
||||
? user?.email
|
||||
: method?.id === "app"
|
||||
? authenticatorDetails?.sharedKey || ""
|
||||
: undefined
|
||||
? authenticatorDetails?.sharedKey || ""
|
||||
: undefined
|
||||
}
|
||||
multiline={method.id === "app"}
|
||||
onChangeText={(value) => {
|
||||
@@ -356,12 +356,12 @@ export const MFASetup = ({
|
||||
sending
|
||||
? null
|
||||
: method.id === "app"
|
||||
? strings.copy()
|
||||
: `${
|
||||
seconds
|
||||
? strings.resendCode(seconds as number)
|
||||
: strings.sendCode()
|
||||
}`
|
||||
? strings.copy()
|
||||
: `${
|
||||
seconds
|
||||
? strings.resendCode(seconds as number)
|
||||
: strings.sendCode()
|
||||
}`
|
||||
}
|
||||
/>
|
||||
)
|
||||
|
||||
@@ -75,15 +75,15 @@ export default function DebugLogs() {
|
||||
item.level === LogLevel.Error || item.level === LogLevel.Fatal
|
||||
? hexToRGBA(colors.error.paragraph, 0.2)
|
||||
: item.level === LogLevel.Warn
|
||||
? hexToRGBA(colors.static.orange, 0.2)
|
||||
: "transparent";
|
||||
? hexToRGBA(colors.static.orange, 0.2)
|
||||
: "transparent";
|
||||
|
||||
const color =
|
||||
item.level === LogLevel.Error || item.level === LogLevel.Fatal
|
||||
? colors.error.paragraph
|
||||
: item.level === LogLevel.Warn
|
||||
? colors.static.black
|
||||
: colors.primary.paragraph;
|
||||
? colors.static.black
|
||||
: colors.primary.paragraph;
|
||||
|
||||
return !item ? null : (
|
||||
<TouchableOpacity
|
||||
|
||||
@@ -123,8 +123,8 @@ export const TrashIntervalPicker = createSettingsPicker({
|
||||
return item === -1
|
||||
? strings.never()
|
||||
: item === 1
|
||||
? strings.reminderRecurringMode.day()
|
||||
: strings.days(item);
|
||||
? strings.reminderRecurringMode.day()
|
||||
: strings.days(item);
|
||||
},
|
||||
getItemKey: (item) => item.toString(),
|
||||
options: [-1, 1, 7, 30, 365],
|
||||
@@ -276,10 +276,10 @@ export const ApplockTimerPicker = createSettingsPicker({
|
||||
return item === -1
|
||||
? strings.never()
|
||||
: item === 0 || item === undefined
|
||||
? strings.immediately()
|
||||
: item === 1
|
||||
? strings.minutes(1)
|
||||
: strings.minutes(item);
|
||||
? strings.immediately()
|
||||
: item === 1
|
||||
? strings.minutes(1)
|
||||
: strings.minutes(item);
|
||||
},
|
||||
getItemKey: (item) => item.toString(),
|
||||
options: [-1, 0, 1, 5, 15, 30],
|
||||
|
||||
@@ -570,13 +570,17 @@ const BackupItem = ({
|
||||
paragraph: strings.restoreBackupConfirm(),
|
||||
positiveText: strings.restore(),
|
||||
negativeText: strings.cancel(),
|
||||
context: "global",
|
||||
positivePress: async () => {
|
||||
restoreBackup({
|
||||
uri:
|
||||
Platform.OS === "android"
|
||||
? (item as ScopedStorage.FileType).uri
|
||||
: (item as ReactNativeBlobUtilStat).path
|
||||
});
|
||||
setTimeout(() => {
|
||||
restoreBackup({
|
||||
uri:
|
||||
Platform.OS === "android"
|
||||
? (item as ScopedStorage.FileType).uri
|
||||
: (item as ReactNativeBlobUtilStat).path
|
||||
});
|
||||
}, 500);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}}
|
||||
|
||||
@@ -25,7 +25,6 @@ import {
|
||||
} from "@react-navigation/native";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { ActivityIndicator, TextInput, View } from "react-native";
|
||||
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||
import { FeatureResult, useIsFeatureAvailable } from "@notesnook/common";
|
||||
//@ts-ignore
|
||||
import ToggleSwitch from "toggle-switch-react-native";
|
||||
@@ -218,14 +217,15 @@ const _SectionItem = ({ item }: { item: SettingSection }) => {
|
||||
}}
|
||||
>
|
||||
{!!item.icon && (
|
||||
<Icon
|
||||
<AppIcon
|
||||
color={
|
||||
item.type === "danger"
|
||||
? colors.error.icon
|
||||
: colors.secondary.icon
|
||||
}
|
||||
iconFamily={item.iconFamily}
|
||||
name={item.icon}
|
||||
size={30}
|
||||
size={item.iconSize || 30}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
|
||||
@@ -92,6 +92,7 @@ export const settingsGroups: SettingSection[] = [
|
||||
{
|
||||
id: "delete-data",
|
||||
name: strings.deleteData(),
|
||||
icon: "delete",
|
||||
description: strings.deleteAccountDesc(),
|
||||
modifer: () => {
|
||||
presentDialog({
|
||||
@@ -205,15 +206,15 @@ export const settingsGroups: SettingSection[] = [
|
||||
return status === SubscriptionStatus.TRIAL
|
||||
? strings.trialOnGoing(trialEndDate)
|
||||
: status === SubscriptionStatus.ACTIVE
|
||||
? strings.subRenewOn(expiryDate)
|
||||
: status === SubscriptionStatus.CANCELED ||
|
||||
status === SubscriptionStatus.PAUSED
|
||||
? strings.subEndsOn(expiryDate)
|
||||
: status === SubscriptionStatus.EXPIRED
|
||||
? subscriptionDaysLeft.time < -3
|
||||
? strings.subEnded()
|
||||
: strings.accountDowngradedIn(3)
|
||||
: strings.neverHesitate();
|
||||
? strings.subRenewOn(expiryDate)
|
||||
: status === SubscriptionStatus.CANCELED ||
|
||||
status === SubscriptionStatus.PAUSED
|
||||
? strings.subEndsOn(expiryDate)
|
||||
: status === SubscriptionStatus.EXPIRED
|
||||
? subscriptionDaysLeft.time < -3
|
||||
? strings.subEnded()
|
||||
: strings.accountDowngradedIn(3)
|
||||
: strings.neverHesitate();
|
||||
}
|
||||
|
||||
return strings.neverHesitate();
|
||||
@@ -1243,7 +1244,7 @@ export const settingsGroups: SettingSection[] = [
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "backup-now",
|
||||
id: "backup-now-with-attachments",
|
||||
name: strings.backupNowWithAttachments(),
|
||||
description: strings.backupNowWithAttachmentsDesc(),
|
||||
hidden: () => !useUserStore.getState().user,
|
||||
@@ -1545,6 +1546,9 @@ export const settingsGroups: SettingSection[] = [
|
||||
id: "join-telegram",
|
||||
name: strings.joinTelegram(),
|
||||
description: strings.joinTelegramDesc(),
|
||||
icon: "sc-telegram",
|
||||
iconFamily: "evilicons",
|
||||
iconSize: 35,
|
||||
modifer: () => {
|
||||
Linking.openURL("https://t.me/notesnook").catch(() => {
|
||||
/* empty */
|
||||
|
||||
@@ -20,6 +20,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import { TextInput } from "react-native";
|
||||
import { Settings } from "../../stores/use-setting-store";
|
||||
import { FeatureId } from "@notesnook/common";
|
||||
import { IconProps } from "../../components/ui/AppIcon";
|
||||
|
||||
export type SettingSection = {
|
||||
id: string;
|
||||
@@ -34,6 +35,8 @@ export type SettingSection = {
|
||||
name?: string | ((current?: unknown) => string);
|
||||
description?: string | ((current: unknown) => string);
|
||||
icon?: string;
|
||||
iconFamily?: IconProps["iconFamily"];
|
||||
iconSize?: number;
|
||||
property?: keyof Settings;
|
||||
sections?: SettingSection[];
|
||||
component?: string;
|
||||
|
||||
@@ -319,9 +319,8 @@ async function run(
|
||||
};
|
||||
}
|
||||
|
||||
await sleep(300);
|
||||
|
||||
if (canShowCompletionStatus) {
|
||||
await sleep(500);
|
||||
presentBackupCompleteSheet(path);
|
||||
}
|
||||
|
||||
|
||||
@@ -146,7 +146,7 @@ const updateAvailableMessage = (
|
||||
icon: "update",
|
||||
type: "normal",
|
||||
id: "app-update"
|
||||
}) as Message;
|
||||
} as Message);
|
||||
|
||||
export function setUpdateAvailableMessage(
|
||||
version: GithubVersionInfo | CheckVersionResponse
|
||||
|
||||
@@ -195,8 +195,8 @@ const NotebookItem = ({
|
||||
!nestedNotebooks?.placeholders.length
|
||||
? "book-outline"
|
||||
: isExpanded
|
||||
? "chevron-down"
|
||||
: "chevron-right"
|
||||
? "chevron-down"
|
||||
: "chevron-right"
|
||||
}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
@@ -538,10 +538,10 @@ export const Search = ({
|
||||
{searchKeyword
|
||||
? `No results found for "${searchKeyword}"`
|
||||
: mode === "appendNote"
|
||||
? "No notes"
|
||||
: mode === "selectTags"
|
||||
? "No tags"
|
||||
: "No notebooks"}
|
||||
? "No notes"
|
||||
: mode === "selectTags"
|
||||
? "No tags"
|
||||
: "No notebooks"}
|
||||
</Text>
|
||||
</View>
|
||||
}
|
||||
|
||||
@@ -71,6 +71,7 @@ import { initDatabase, useShareStore } from "./store";
|
||||
import { isTablet } from "react-native-device-info";
|
||||
import { NotesnookModule } from "../utils/notesnook-module";
|
||||
import { DefaultAppStyles } from "../utils/styles";
|
||||
import { encodeHTML5 } from "entities";
|
||||
|
||||
const getLinkPreview = (url: string) => {
|
||||
return getPreviewData(url, 5000);
|
||||
@@ -81,7 +82,7 @@ async function sanitizeHtml(site: string, title?: string) {
|
||||
return (
|
||||
html +
|
||||
"<hr/>" +
|
||||
`<p>Clipped from <a href="${site}">${title || site}</a></p>
|
||||
`<p>Clipped from <a href="${site}">${encodeHTML5(title || site)}</a></p>
|
||||
<p>Date clipped ${getFormattedDate(Date.now())}</p>`
|
||||
);
|
||||
} catch (e) {
|
||||
@@ -96,7 +97,7 @@ function makeHtmlFromUrl(url: string) {
|
||||
function makeHtmlFromPlainText(text: string) {
|
||||
if (!text) return "";
|
||||
|
||||
return `<p>${text
|
||||
return `<p>${encodeHTML5(text)
|
||||
.replace(/[\n]+/g, "\n")
|
||||
.replace(/(?:\r\n|\r|\n)/g, "</p><p>")}</p>`;
|
||||
}
|
||||
@@ -419,8 +420,8 @@ const ShareView = () => {
|
||||
let html = !rawData.value
|
||||
? ""
|
||||
: isURL(rawData?.value)
|
||||
? makeHtmlFromUrl(rawData?.value)
|
||||
: makeHtmlFromPlainText(rawData?.value);
|
||||
? makeHtmlFromUrl(rawData?.value)
|
||||
: makeHtmlFromPlainText(rawData?.value);
|
||||
setNote((note) => {
|
||||
note.content.data = html;
|
||||
noteContent.current = html;
|
||||
|
||||
@@ -76,18 +76,14 @@ export const useThemeStore = create<ThemeStore>((set, get) => ({
|
||||
? (Appearance.getColorScheme() as "dark" | "light")
|
||||
: SettingsService.get().colorScheme,
|
||||
setDarkTheme: (darkTheme) => {
|
||||
switchThemeWithAnimation(() => {
|
||||
set({ darkTheme });
|
||||
changeSystemBarColors();
|
||||
SettingsService.setProperty("darkTheme", darkTheme);
|
||||
});
|
||||
set({ darkTheme });
|
||||
changeSystemBarColors();
|
||||
SettingsService.setProperty("darkTheme", darkTheme);
|
||||
},
|
||||
setLightTheme: (lightTheme) => {
|
||||
switchThemeWithAnimation(() => {
|
||||
set({ lightTheme });
|
||||
changeSystemBarColors();
|
||||
SettingsService.setProperty("lighTheme", lightTheme);
|
||||
});
|
||||
set({ lightTheme });
|
||||
changeSystemBarColors();
|
||||
SettingsService.setProperty("lighTheme", lightTheme);
|
||||
},
|
||||
setColorScheme: (colorScheme) => {
|
||||
switchThemeWithAnimation(() => {
|
||||
|
||||
@@ -46,7 +46,7 @@ export interface UserStore {
|
||||
appLocked: boolean;
|
||||
lockApp: (verified: boolean) => void;
|
||||
disableAppLockRequests: boolean;
|
||||
setDisableAppLockRequests: (shouldBlockVerifyUser: boolean) => void;
|
||||
setDisableAppLockRequests: (disableAppLockRequests: boolean) => void;
|
||||
profile?: Partial<Profile>;
|
||||
}
|
||||
|
||||
|
||||
@@ -159,7 +159,7 @@ function show(event: any, text: string, position = 2) {
|
||||
duration: 2000,
|
||||
autoHide: true,
|
||||
clickToHide: true,
|
||||
shadow: true
|
||||
shadow: false
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ import { notesnook } from "../test.ids";
|
||||
import { TestBuilder } from "./utils";
|
||||
|
||||
describe("Sort & filter", () => {
|
||||
it.only("Sort by date-edited/date-created", async () => {
|
||||
it("Sort by date-edited/date-created", async () => {
|
||||
await TestBuilder.create()
|
||||
.prepare()
|
||||
.createNote("Note 1", "Note 1")
|
||||
@@ -34,7 +34,7 @@ describe("Sort & filter", () => {
|
||||
.element(by.web.className("ProseMirror"))
|
||||
.typeText("Edited ", true);
|
||||
})
|
||||
.pressBack(1)
|
||||
.pressBack(2)
|
||||
.waitAndTapById("icon-sort")
|
||||
.wait(500)
|
||||
.waitAndTapByText("Date created")
|
||||
|
||||
@@ -46,9 +46,10 @@ describe("Tags", () => {
|
||||
.waitAndTapByText('Add "#testtag"')
|
||||
.isVisibleByText("#testtag")
|
||||
.pressBack(2)
|
||||
.wait(1000)
|
||||
.openSideMenu()
|
||||
.waitAndTapById("tab-tags")
|
||||
.waitAndTapByText("#testtag")
|
||||
.waitAndTapByText("testtag")
|
||||
.processResult(async (note) => {
|
||||
await TestBuilder.create().isVisibleByText(note.body).run();
|
||||
})
|
||||
|
||||
@@ -32,10 +32,7 @@ const testvars = {
|
||||
|
||||
class Element {
|
||||
element: Detox.NativeElement;
|
||||
constructor(
|
||||
public type: "id" | "text",
|
||||
public value: string
|
||||
) {
|
||||
constructor(public type: "id" | "text", public value: string) {
|
||||
if (type == "id") {
|
||||
this.element = element(by.id(value)).atIndex(0);
|
||||
} else {
|
||||
|
||||
BIN
apps/mobile/fonts/EvilIcons.ttf
Normal file
@@ -34,6 +34,8 @@
|
||||
65AA857E25E6DDEC00772A01 /* NotesWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65AA857D25E6DDEC00772A01 /* NotesWidget.swift */; };
|
||||
65AA858025E6DDEE00772A01 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 65AA857F25E6DDEE00772A01 /* Assets.xcassets */; };
|
||||
65AA858425E6DDEE00772A01 /* NotesWidgetExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 65AA857725E6DDEC00772A01 /* NotesWidgetExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
65AD1F4A2F6289110033176F /* EvilIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 65AD1F492F6289110033176F /* EvilIcons.ttf */; };
|
||||
65AD1F4B2F6289110033176F /* EvilIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 65AD1F492F6289110033176F /* EvilIcons.ttf */; };
|
||||
65B5014425A672B200E2D264 /* ShareViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 65B5014325A672B200E2D264 /* ShareViewController.m */; };
|
||||
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, ); }; };
|
||||
@@ -129,6 +131,7 @@
|
||||
65AA857D25E6DDEC00772A01 /* NotesWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotesWidget.swift; sourceTree = "<group>"; };
|
||||
65AA857F25E6DDEE00772A01 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
65AA858125E6DDEE00772A01 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
65AD1F492F6289110033176F /* EvilIcons.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = EvilIcons.ttf; path = ../fonts/EvilIcons.ttf; sourceTree = SOURCE_ROOT; };
|
||||
65B5014025A672B200E2D264 /* Make Note.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "Make Note.appex"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
65B5014325A672B200E2D264 /* ShareViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ShareViewController.m; sourceTree = "<group>"; };
|
||||
65B5014625A672B200E2D264 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/MainInterface.storyboard; sourceTree = "<group>"; };
|
||||
@@ -291,6 +294,7 @@
|
||||
83CBB9F61A601CBA00E9B192 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
65AD1F492F6289110033176F /* EvilIcons.ttf */,
|
||||
653F4E042EA3887C009A42A2 /* Inter-Bold.ttf */,
|
||||
653F4E052EA3887C009A42A2 /* Inter-Italic.ttf */,
|
||||
653F4E062EA3887C009A42A2 /* Inter-Regular.ttf */,
|
||||
@@ -536,6 +540,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
659201D82EA78265006B16DB /* Inter-Bold.ttf in Resources */,
|
||||
65AD1F4B2F6289110033176F /* EvilIcons.ttf in Resources */,
|
||||
659201D92EA78265006B16DB /* Inter-Italic.ttf in Resources */,
|
||||
659201DA2EA78265006B16DB /* Inter-Regular.ttf in Resources */,
|
||||
659201DB2EA78265006B16DB /* Inter-SemiBold.ttf in Resources */,
|
||||
@@ -581,6 +586,7 @@
|
||||
659201DE2EA7826D006B16DB /* Inter-Regular.ttf in Resources */,
|
||||
659201DF2EA7826D006B16DB /* Inter-SemiBold.ttf in Resources */,
|
||||
65C400DF2A80B6B600AA3DF5 /* MaterialCommunityIcons.ttf in Resources */,
|
||||
65AD1F4A2F6289110033176F /* EvilIcons.ttf in Resources */,
|
||||
65C149872A61151B005C40F1 /* extension.bundle in Resources */,
|
||||
65B5014725A672B200E2D264 /* MainInterface.storyboard in Resources */,
|
||||
);
|
||||
@@ -1029,7 +1035,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 2174;
|
||||
CURRENT_PROJECT_VERSION = 2178;
|
||||
DEVELOPMENT_TEAM = 53CWBG3QUC;
|
||||
ENABLE_BITCODE = NO;
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
|
||||
@@ -1104,7 +1110,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 3.3.15;
|
||||
MARKETING_VERSION = 3.3.18;
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
"-ObjC",
|
||||
@@ -1135,7 +1141,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 2174;
|
||||
CURRENT_PROJECT_VERSION = 2178;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 53CWBG3QUC;
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
|
||||
@@ -1210,7 +1216,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 3.3.15;
|
||||
MARKETING_VERSION = 3.3.18;
|
||||
ONLY_ACTIVE_ARCH = NO;
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
@@ -1367,7 +1373,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 2174;
|
||||
CURRENT_PROJECT_VERSION = 2178;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = 53CWBG3QUC;
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
|
||||
@@ -1379,7 +1385,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 3.3.15;
|
||||
MARKETING_VERSION = 3.3.18;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.notewidget;
|
||||
@@ -1410,7 +1416,7 @@
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 2174;
|
||||
CURRENT_PROJECT_VERSION = 2178;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 53CWBG3QUC;
|
||||
@@ -1423,7 +1429,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 3.3.15;
|
||||
MARKETING_VERSION = 3.3.18;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.notewidget;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@@ -1453,7 +1459,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = "Make Note/Make Note.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 2174;
|
||||
CURRENT_PROJECT_VERSION = 2178;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = 53CWBG3QUC;
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
|
||||
@@ -1534,7 +1540,7 @@
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift$(inherited)";
|
||||
MARKETING_VERSION = 3.3.15;
|
||||
MARKETING_VERSION = 3.3.18;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.share;
|
||||
@@ -1565,7 +1571,7 @@
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 2174;
|
||||
CURRENT_PROJECT_VERSION = 2178;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 53CWBG3QUC;
|
||||
@@ -1647,7 +1653,7 @@
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift$(inherited)";
|
||||
MARKETING_VERSION = 3.3.15;
|
||||
MARKETING_VERSION = 3.3.18;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.share;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@@ -1724,10 +1730,7 @@
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
OTHER_CFLAGS = "$(inherited)";
|
||||
OTHER_CPLUSPLUSFLAGS = "$(inherited)";
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
" ",
|
||||
);
|
||||
OTHER_LDFLAGS = "$(inherited) ";
|
||||
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG";
|
||||
@@ -1792,10 +1795,7 @@
|
||||
ONLY_ACTIVE_ARCH = NO;
|
||||
OTHER_CFLAGS = "$(inherited)";
|
||||
OTHER_CPLUSPLUSFLAGS = "$(inherited)";
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
" ",
|
||||
);
|
||||
OTHER_LDFLAGS = "$(inherited) ";
|
||||
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
|
||||
SDKROOT = iphoneos;
|
||||
USE_HERMES = true;
|
||||
|
||||
@@ -97,6 +97,7 @@
|
||||
<string>Inter-Regular.ttf</string>
|
||||
<string>Inter-Bold.ttf</string>
|
||||
<string>MaterialCommunityIcons.ttf</string>
|
||||
<string>EvilIcons.ttf</string>
|
||||
</array>
|
||||
<key>UIApplicationSceneManifest</key>
|
||||
<dict>
|
||||
|
||||
31
apps/mobile/package-lock.json
generated
@@ -1,22 +1,22 @@
|
||||
{
|
||||
"name": "@notesnook/mobile",
|
||||
"version": "3.3.15-beta.1",
|
||||
"version": "3.3.17",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@notesnook/mobile",
|
||||
"version": "3.3.15-beta.1",
|
||||
"version": "3.3.17",
|
||||
"hasInstallScript": true,
|
||||
"license": "GPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
"@ammarahmed/notifee-react-native": "^7.4.11",
|
||||
"@ammarahmed/react-native-background-fetch": "^4.2.2",
|
||||
"@ammarahmed/notifee-react-native": "^7.4.12",
|
||||
"@ammarahmed/react-native-background-fetch": "^4.2.3",
|
||||
"@ammarahmed/react-native-eventsource": "1.1.0",
|
||||
"@ammarahmed/react-native-fingerprint-scanner": "^5.0.1",
|
||||
"@ammarahmed/react-native-share-extension": "^2.9.5",
|
||||
"@ammarahmed/react-native-sodium": "^1.6.8",
|
||||
"@ammarahmed/react-native-upload": "^6.32.0",
|
||||
"@ammarahmed/react-native-upload": "^6.33.0",
|
||||
"@azure/core-asynciterator-polyfill": "^1.0.2",
|
||||
"@bam.tech/react-native-image-resizer": "3.0.11",
|
||||
"@callstack/repack": "~5.2.1",
|
||||
@@ -181,7 +181,6 @@
|
||||
"otplib": "12.0.1",
|
||||
"patch-package": "7.0.0",
|
||||
"pixelmatch": "^6.0.0",
|
||||
"prettier": "3.5.3",
|
||||
"react-native-bundle-visualizer": "^3.1.1",
|
||||
"react-native-cli-bump-version": "1.5.0",
|
||||
"react-refresh": "0.14.0",
|
||||
@@ -300,7 +299,7 @@
|
||||
"@notesnook/intl": "file:../intl",
|
||||
"@notesnook/theme": "file:../theme",
|
||||
"@notesnook/ui": "file:../ui",
|
||||
"@social-embed/lib": "^0.1.0-next.7",
|
||||
"@social-embed/lib": "^0.1.0-next.11",
|
||||
"@tiptap/core": "2.6.6",
|
||||
"@tiptap/extension-blockquote": "^2.6.6",
|
||||
"@tiptap/extension-bullet-list": "^2.6.6",
|
||||
@@ -490,18 +489,18 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@ammarahmed/notifee-react-native": {
|
||||
"version": "7.4.11",
|
||||
"resolved": "https://registry.npmjs.org/@ammarahmed/notifee-react-native/-/notifee-react-native-7.4.11.tgz",
|
||||
"integrity": "sha512-9zKhONgir2FN/sMj/rsKAhDwfxadDuxB6LJILKxpGwzqvcIuG70oCKWmBBG9LJJpSfcVpNTdxBoH9RtNZTZSsQ==",
|
||||
"version": "7.4.12",
|
||||
"resolved": "https://registry.npmjs.org/@ammarahmed/notifee-react-native/-/notifee-react-native-7.4.12.tgz",
|
||||
"integrity": "sha512-rZPtHdWZ3PxtMHreVszo0ehw6gnsabw7fpgDv8ztYcMNj4A22ZTyfTAQrSZ534D7iDkWgHi2my82b31MsnlQzQ==",
|
||||
"license": "Apache-2.0",
|
||||
"peerDependencies": {
|
||||
"react-native": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@ammarahmed/react-native-background-fetch": {
|
||||
"version": "4.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@ammarahmed/react-native-background-fetch/-/react-native-background-fetch-4.2.2.tgz",
|
||||
"integrity": "sha512-PLBlb/DD+6Fv1auxdD6VRxtuC7GKPhQqR69bovRm5oGavbdSzRr+ZTr8AyNMCcayxKGdgEX2JysrJg8WIySSFQ==",
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@ammarahmed/react-native-background-fetch/-/react-native-background-fetch-4.2.3.tgz",
|
||||
"integrity": "sha512-cgO9EEFoU1HYuDNMpdTTke7DYzEDQfLsyd/cWIZ5Lpp4zz76+dgp1+LBqbLYdSenhJU1Omghq3xWPsoWDRaemQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@ammarahmed/react-native-eventsource": {
|
||||
@@ -538,9 +537,9 @@
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/@ammarahmed/react-native-upload": {
|
||||
"version": "6.32.0",
|
||||
"resolved": "https://registry.npmjs.org/@ammarahmed/react-native-upload/-/react-native-upload-6.32.0.tgz",
|
||||
"integrity": "sha512-rb14iQPDFKSefcqdeak2uXg4pOTYPYMn4IpPnODOhKt+ju/nqO7mx2pvPi623z2J/+mJ5qOpaFMK8AS65K5jyw==",
|
||||
"version": "6.33.0",
|
||||
"resolved": "https://registry.npmjs.org/@ammarahmed/react-native-upload/-/react-native-upload-6.33.0.tgz",
|
||||
"integrity": "sha512-hvr/LN1wgbhZv3WsRhrAPC1D8YW0ClgrE5NArqUgHWreSHBCS2zVQhEferTt5fGESaJvx+c69VqaIPqzzb8Y3A==",
|
||||
"license": "BSD-3-Clause",
|
||||
"peerDependencies": {
|
||||
"react": "*",
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"name": "@notesnook/mobile",
|
||||
"version": "3.3.15-beta.1",
|
||||
"version": "3.3.18",
|
||||
"private": true,
|
||||
"license": "GPL-3.0-or-later",
|
||||
"scripts": {
|
||||
"postinstall": "patch-package && node ./scripts/optimize-fonts.mjs",
|
||||
"run-android": "react-native run-android --active-arch-only",
|
||||
"run-android": "react-native run-android --active-arch-only --mode=release",
|
||||
"build": "echo 'No build script defined'",
|
||||
"run-ios": "react-native run-ios",
|
||||
"start": "react-native start",
|
||||
@@ -26,13 +26,13 @@
|
||||
"react": "19.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ammarahmed/notifee-react-native": "^7.4.11",
|
||||
"@ammarahmed/react-native-background-fetch": "^4.2.2",
|
||||
"@ammarahmed/notifee-react-native": "^7.4.12",
|
||||
"@ammarahmed/react-native-background-fetch": "^4.2.3",
|
||||
"@ammarahmed/react-native-eventsource": "1.1.0",
|
||||
"@ammarahmed/react-native-fingerprint-scanner": "^5.0.1",
|
||||
"@ammarahmed/react-native-share-extension": "^2.9.5",
|
||||
"@ammarahmed/react-native-sodium": "^1.6.8",
|
||||
"@ammarahmed/react-native-upload": "^6.32.0",
|
||||
"@ammarahmed/react-native-upload": "^6.33.0",
|
||||
"@azure/core-asynciterator-polyfill": "^1.0.2",
|
||||
"@bam.tech/react-native-image-resizer": "3.0.11",
|
||||
"@callstack/repack": "~5.2.1",
|
||||
@@ -197,7 +197,6 @@
|
||||
"otplib": "12.0.1",
|
||||
"patch-package": "7.0.0",
|
||||
"pixelmatch": "^6.0.0",
|
||||
"prettier": "3.5.3",
|
||||
"react-native-bundle-visualizer": "^3.1.1",
|
||||
"react-native-cli-bump-version": "1.5.0",
|
||||
"react-refresh": "0.14.0",
|
||||
@@ -208,4 +207,4 @@
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
diff --git a/node_modules/react-native-theme-switch-animation/android/src/main/java/com/themeswitchanimation/ThemeSwitchAnimationModule.java b/node_modules/react-native-theme-switch-animation/android/src/main/java/com/themeswitchanimation/ThemeSwitchAnimationModule.java
|
||||
index f4630ac..a3a837f 100644
|
||||
--- a/node_modules/react-native-theme-switch-animation/android/src/main/java/com/themeswitchanimation/ThemeSwitchAnimationModule.java
|
||||
+++ b/node_modules/react-native-theme-switch-animation/android/src/main/java/com/themeswitchanimation/ThemeSwitchAnimationModule.java
|
||||
@@ -13,7 +13,7 @@ import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
||||
|
||||
-public class ThemeSwitchAnimationModule extends ThemeSwitchAnimationModuleSpec {
|
||||
+public class ThemeSwitchAnimationModule extends com.themeswitchanimation.ThemeSwitchAnimationModuleSpec {
|
||||
public static final String NAME = "ThemeSwitchAnimationModule";
|
||||
|
||||
private ReactContext reactContext;
|
||||
@@ -38,6 +38,12 @@ public class ThemeSwitchAnimationModule extends ThemeSwitchAnimationModuleSpec {
|
||||
this.isAnimating = true;
|
||||
this.rootView = (ViewGroup) getCurrentActivity().getWindow().getDecorView();
|
||||
this.capturedImageBitmap = captureScreenshot(this.rootView, this.reactContext);
|
||||
+ if (this.capturedImageBitmap == null) {
|
||||
+ reactContext
|
||||
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
|
||||
+ .emit("FINISHED_FREEZING_SCREEN", null);
|
||||
+ return;
|
||||
+ }
|
||||
this.capturedImageView = createImageView(this.capturedImageBitmap, this.reactContext);
|
||||
|
||||
reactContext.runOnUiQueueThread(() -> {
|
||||
@@ -57,6 +63,9 @@ public class ThemeSwitchAnimationModule extends ThemeSwitchAnimationModuleSpec {
|
||||
@Override
|
||||
public void run() {
|
||||
if (isAnimating) {
|
||||
+ if (capturedImageView == null) {
|
||||
+ cleanUp();
|
||||
+ }
|
||||
switch (animationType) {
|
||||
case "circular":
|
||||
Animations.performCircleAnimation(capturedImageView, rootView, (int) duration, cxRatio, cyRatio, reactContext, new Runnable() {
|
||||
@@ -94,16 +103,22 @@ public class ThemeSwitchAnimationModule extends ThemeSwitchAnimationModuleSpec {
|
||||
capturedImageBitmap.recycle();
|
||||
capturedImageBitmap = null;
|
||||
}
|
||||
- rootView.removeView(capturedImageView);
|
||||
+ if (capturedImageView != null) {
|
||||
+ rootView.removeView(capturedImageView);
|
||||
+ }
|
||||
isAnimating = false;
|
||||
}
|
||||
|
||||
public static Bitmap captureScreenshot(View rootView, ReactContext reactContext) {
|
||||
- Bitmap capturedImageBitmap = Bitmap.createBitmap(rootView.getWidth(), rootView.getHeight(), Bitmap.Config.ARGB_8888);
|
||||
- Canvas canvas = new Canvas(capturedImageBitmap);
|
||||
- rootView.draw(canvas);
|
||||
-
|
||||
- return capturedImageBitmap;
|
||||
+ try {
|
||||
+ Bitmap capturedImageBitmap = Bitmap.createBitmap(rootView.getWidth(), rootView.getHeight(), Bitmap.Config.ARGB_8888);
|
||||
+ Canvas canvas = new Canvas(capturedImageBitmap);
|
||||
+ rootView.draw(canvas);
|
||||
+
|
||||
+ return capturedImageBitmap;
|
||||
+ } catch (Exception e) {
|
||||
+ return null;
|
||||
+ }
|
||||
}
|
||||
|
||||
public static ImageView createImageView(Bitmap capturedImageBitmap, ReactContext reactContext) {
|
||||
@@ -89,6 +89,50 @@ index 978045f..59c64f1 100644
|
||||
- implementation 'com.github.florent37:viewtooltip:1.1.6'
|
||||
+ implementation 'com.github.florent37:ViewTooltip:f79a8955ef'
|
||||
}
|
||||
diff --git a/node_modules/react-native-tooltips/android/src/main/java/px/tooltips/RNTooltipsModule.java b/node_modules/react-native-tooltips/android/src/main/java/px/tooltips/RNTooltipsModule.java
|
||||
index e987ffb..e898a40 100644
|
||||
--- a/node_modules/react-native-tooltips/android/src/main/java/px/tooltips/RNTooltipsModule.java
|
||||
+++ b/node_modules/react-native-tooltips/android/src/main/java/px/tooltips/RNTooltipsModule.java
|
||||
@@ -11,9 +11,11 @@ import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
import com.facebook.react.bridge.Callback;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
-import com.facebook.react.uimanager.UIManagerModule;
|
||||
+import com.facebook.react.bridge.UIManager;
|
||||
import com.facebook.react.uimanager.UIBlock;
|
||||
import com.facebook.react.uimanager.NativeViewHierarchyManager;
|
||||
+import com.facebook.react.uimanager.UIManagerHelper;
|
||||
+import com.facebook.react.uimanager.common.UIManagerType;
|
||||
import com.github.florent37.viewtooltip.ViewTooltip;
|
||||
|
||||
public class RNTooltipsModule extends ReactContextBaseJavaModule {
|
||||
@@ -34,12 +36,12 @@ public class RNTooltipsModule extends ReactContextBaseJavaModule {
|
||||
|
||||
@ReactMethod
|
||||
public void Show(final int targetId, final int parentId, final ReadableMap props, final Callback onHide) {
|
||||
- this.reactContext.getNativeModule(UIManagerModule.class).prependUIBlock(new UIBlock() {
|
||||
|
||||
- @Override
|
||||
- public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
|
||||
|
||||
- final ViewGroup target = (ViewGroup) nativeViewHierarchyManager.resolveView(targetId);
|
||||
+ UIManager uiManager = UIManagerHelper.getUIManager(reactContext, UIManagerType.FABRIC);
|
||||
+ if (uiManager == null) return;
|
||||
+
|
||||
+ final ViewGroup target = (ViewGroup) uiManager.resolveView(targetId);
|
||||
|
||||
reactContext.runOnUiQueueThread(new Runnable() {
|
||||
@Override
|
||||
@@ -121,8 +123,7 @@ public class RNTooltipsModule extends ReactContextBaseJavaModule {
|
||||
}
|
||||
|
||||
});
|
||||
- }
|
||||
- });
|
||||
+
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
diff --git a/node_modules/react-native-tooltips/ios/RNTooltips.h b/node_modules/react-native-tooltips/ios/RNTooltips.h
|
||||
index a150e3e..096ad86 100644
|
||||
--- a/node_modules/react-native-tooltips/ios/RNTooltips.h
|
||||
@@ -116,7 +160,7 @@ index fb96466..75a6fdb 100644
|
||||
|
||||
@interface TooltipDelegate : NSObject <SexyTooltipDelegate>
|
||||
|
||||
@@ -7,9 +9,15 @@
|
||||
@@ -7,9 +9,15 @@ @interface TooltipDelegate : NSObject <SexyTooltipDelegate>
|
||||
@end
|
||||
|
||||
@implementation TooltipDelegate
|
||||
@@ -132,7 +176,7 @@ index fb96466..75a6fdb 100644
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -17,77 +25,120 @@
|
||||
@@ -17,77 +25,120 @@ - (void)tooltipDidDismiss:(SexyTooltip *)tooltip {
|
||||
|
||||
@implementation RNTooltips
|
||||
|
||||
|
||||
@@ -36,27 +36,27 @@ const fontMap = JSON.parse(
|
||||
);
|
||||
|
||||
// Register fonts
|
||||
const OpenSans = path.join(
|
||||
const Inter = path.join(
|
||||
__dirname,
|
||||
import.meta.env.DEV ? "../assets/fonts/" : "../../assets/fonts/",
|
||||
"open-sans-v34-vietnamese_latin-ext_latin_hebrew_greek-ext_greek_cyrillic-ext_cyrillic-regular.ttf"
|
||||
"Inter-Regular.ttf"
|
||||
);
|
||||
const OpenSansBold = path.join(
|
||||
const InterBold = path.join(
|
||||
__dirname,
|
||||
import.meta.env.DEV ? "../assets/fonts/" : "../../assets/fonts/",
|
||||
"open-sans-v34-vietnamese_latin-ext_latin_hebrew_greek-ext_greek_cyrillic-ext_cyrillic-600.ttf"
|
||||
"Inter-SemiBold.ttf"
|
||||
);
|
||||
|
||||
console.log("OpenSans", GlobalFonts.registerFromPath(OpenSans, "OpenSans"));
|
||||
console.log("Inter", GlobalFonts.registerFromPath(Inter, "Inter"));
|
||||
console.log(
|
||||
"registering",
|
||||
"OpenSansBold",
|
||||
GlobalFonts.registerFromPath(OpenSansBold, "OpenSansBold")
|
||||
"InterBold",
|
||||
GlobalFonts.registerFromPath(InterBold, "InterBold")
|
||||
);
|
||||
|
||||
const fontFamilies = {
|
||||
regular: ["OpenSans"],
|
||||
bold: ["OpenSansBold"]
|
||||
regular: ["Inter"],
|
||||
bold: ["InterBold"]
|
||||
};
|
||||
for (const font of fontMap) {
|
||||
const id = (font.name + font.weight).replace(/ /g, "");
|
||||
@@ -115,11 +115,11 @@ export async function makeImage(metadata: OGMetadata, cacheKey: string) {
|
||||
|
||||
// Draw bottom text
|
||||
ctx.fillStyle = theme.primary.heading;
|
||||
ctx.font = "600 32px OpenSansBold";
|
||||
ctx.font = "600 32px InterBold";
|
||||
ctx.fillText("Notesnook Monograph", PADDING + 95, HEIGHT - PADDING - 55);
|
||||
|
||||
ctx.fillStyle = theme.secondary.paragraph;
|
||||
ctx.font = "25px OpenSans";
|
||||
ctx.font = "25px Inter";
|
||||
ctx.fillText(
|
||||
"Anonymous, secure, and encrypted note sharing with password protection.",
|
||||
PADDING + 95,
|
||||
@@ -128,7 +128,7 @@ export async function makeImage(metadata: OGMetadata, cacheKey: string) {
|
||||
|
||||
// Draw date
|
||||
ctx.fillStyle = theme.secondary.paragraph;
|
||||
ctx.font = "25px OpenSans";
|
||||
ctx.font = "25px Inter";
|
||||
ctx.fillText(metadata.date, PADDING, PADDING + 25);
|
||||
|
||||
// Draw title
|
||||
|
||||
4
apps/monograph/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@notesnook/monograph",
|
||||
"version": "1.2.7",
|
||||
"version": "1.2.8",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@notesnook/monograph",
|
||||
"version": "1.2.7",
|
||||
"version": "1.2.8",
|
||||
"dependencies": {
|
||||
"@emotion/cache": "11.11.0",
|
||||
"@emotion/react": "11.11.1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@notesnook/monograph",
|
||||
"version": "1.2.7",
|
||||
"version": "1.2.8",
|
||||
"private": true,
|
||||
"sideEffects": false,
|
||||
"type": "module",
|
||||
|
||||
@@ -17,9 +17,8 @@ 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 { test, expect } from "@playwright/test";
|
||||
import { AppModel } from "./models/app.model";
|
||||
import { APP_LOCK_PASSWORD, USER } from "./utils";
|
||||
import { test, expect, APP_LOCK_PASSWORD, USER } from "./utils";
|
||||
|
||||
test("don't show status bar lock app button to unauthenticated user", async ({
|
||||
page
|
||||
|
||||
@@ -16,9 +16,8 @@ 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 { test, expect } from "@playwright/test";
|
||||
import { AppModel } from "./models/app.model";
|
||||
import { USER } from "./utils";
|
||||
import { test, expect, USER } from "./utils";
|
||||
|
||||
test("create an unencrypted backup", async ({ page }) => {
|
||||
const app = new AppModel(page);
|
||||
@@ -38,6 +37,7 @@ test("restore an unencrypted backup", async ({ page }) => {
|
||||
const settings = await app.goToSettings();
|
||||
|
||||
await settings.restoreData("backup.nnbackup");
|
||||
await app.toasts.waitForToast("Backup restored");
|
||||
|
||||
await settings.close();
|
||||
const notes = await app.goToNotes();
|
||||
@@ -67,6 +67,7 @@ test("restore an encrypted backup", async ({ page }) => {
|
||||
const settings = await app.goToSettings();
|
||||
|
||||
await settings.restoreData("encrypted.nnbackup", USER.CURRENT.password);
|
||||
await app.toasts.waitForToast("Backup restored");
|
||||
|
||||
await settings.close();
|
||||
const notes = await app.goToNotes();
|
||||
|
||||
@@ -17,8 +17,8 @@ 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 { test, Page, expect } from "@playwright/test";
|
||||
import { USER } from "./utils";
|
||||
import { Page } from "@playwright/test";
|
||||
import { test, expect, USER } from "./utils";
|
||||
import { AppModel } from "./models/app.model";
|
||||
import { PriceItem } from "./models/types";
|
||||
|
||||
|
||||
@@ -16,9 +16,8 @@ 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 { test, expect } from "@playwright/test";
|
||||
import { AppModel } from "./models/app.model";
|
||||
import { getTestId, NOTE } from "./utils";
|
||||
import { test, expect, getTestId, NOTE } from "./utils";
|
||||
|
||||
test("delete the last note of a color", async ({ page }) => {
|
||||
const app = new AppModel(page);
|
||||
|
||||
@@ -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 { expect, test } from "@playwright/test";
|
||||
import { test, expect } from "./utils";
|
||||
import { AppModel } from "./models/app.model";
|
||||
import { NotesViewModel } from "./models/notes-view.model";
|
||||
|
||||
|
||||
@@ -17,9 +17,8 @@ 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 { test, expect } from "@playwright/test";
|
||||
import { AppModel } from "./models/app.model";
|
||||
import { getTestId, NOTE, TITLE_ONLY_NOTE } from "./utils";
|
||||
import { test, expect, NOTE, TITLE_ONLY_NOTE } from "./utils";
|
||||
|
||||
test("focus mode", async ({ page }) => {
|
||||
const app = new AppModel(page);
|
||||
@@ -80,7 +79,7 @@ test("creating a new note should clear the editor contents & title", async ({
|
||||
await notes.newNote();
|
||||
|
||||
expect(await notes.editor.isUnloaded()).toBeTruthy();
|
||||
expect(await notes.editor.getTitle()).toBe("");
|
||||
await expect(notes.editor.title).toHaveValue("");
|
||||
expect(await notes.editor.getContent("text")).toBe("");
|
||||
});
|
||||
|
||||
@@ -114,7 +113,7 @@ test("opening an empty titled note should empty out editor contents", async ({
|
||||
await onlyTitle?.openNote();
|
||||
|
||||
expect(await notes.editor.getContent("text")).toBe("");
|
||||
expect(await notes.editor.getTitle()).toBe(TITLE_ONLY_NOTE.title);
|
||||
await expect(notes.editor.title).toHaveValue(TITLE_ONLY_NOTE.title);
|
||||
});
|
||||
|
||||
test("focus should not jump to editor while typing in title input", async ({
|
||||
@@ -127,7 +126,7 @@ test("focus should not jump to editor while typing in title input", async ({
|
||||
|
||||
await notes.editor.typeTitle("Hello", 200);
|
||||
|
||||
expect(await notes.editor.getTitle()).toBe("Hello");
|
||||
await expect(notes.editor.title).toHaveValue("Hello");
|
||||
expect(await notes.editor.getContent("text")).toBe("");
|
||||
});
|
||||
|
||||
@@ -143,21 +142,21 @@ test("when title format is set to headline, title should be generated from headl
|
||||
const notes = await app.goToNotes();
|
||||
await notes.createNote({ content: "my precious" });
|
||||
|
||||
expect(await notes.editor.getTitle()).toBe("my precious");
|
||||
await expect(notes.editor.title).toHaveValue("my precious");
|
||||
|
||||
await notes.editor.setContent(", my precious note");
|
||||
await notes.editor.waitForSaving();
|
||||
|
||||
expect(await notes.editor.getTitle()).toBe("my precious, my precious note");
|
||||
await expect(notes.editor.title).toHaveValue("my precious, my precious note");
|
||||
|
||||
await notes.editor.setTitle("not precious");
|
||||
|
||||
expect(await notes.editor.getTitle()).toBe("not precious");
|
||||
await expect(notes.editor.title).toHaveValue("not precious");
|
||||
|
||||
await notes.editor.setContent(", but...");
|
||||
await notes.editor.waitForSaving();
|
||||
|
||||
expect(await notes.editor.getTitle()).toBe("not precious");
|
||||
await expect(notes.editor.title).toHaveValue("not precious");
|
||||
});
|
||||
|
||||
test("select all & backspace should clear all content in editor", async ({
|
||||
@@ -178,7 +177,7 @@ test("select all & backspace should clear all content in editor", async ({
|
||||
test("editing a note and switching immediately to another note and making an edit shouldn't overlap both notes", async ({
|
||||
page
|
||||
}, test) => {
|
||||
test.setTimeout(45 * 1000);
|
||||
test.setTimeout(3 * 60 * 1000);
|
||||
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
@@ -217,7 +216,7 @@ test("editing a note and switching immediately to another note and making an edi
|
||||
test("editing a note and switching immediately to another note and editing the title shouldn't overlap both notes", async ({
|
||||
page
|
||||
}, test) => {
|
||||
test.setTimeout(45 * 1000);
|
||||
test.setTimeout(3 * 60 * 1000);
|
||||
|
||||
const app = new AppModel(page);
|
||||
await app.goto();
|
||||
@@ -333,7 +332,6 @@ test("disable autosave when note crosses MAX_AUTO_SAVEABLE_WORDS", async ({
|
||||
"Auto-save is disabled for large notes. Press Ctrl + S to save."
|
||||
)
|
||||
).toBe(true);
|
||||
await expect(notes.editor.notSavedIcon).toBeVisible();
|
||||
});
|
||||
|
||||
test("when autosave is disabled, pressing ctrl+s should save the note", async ({
|
||||
@@ -470,12 +468,12 @@ test("control + alt + right arrow should go to next note", async ({ page }) => {
|
||||
await note2?.openNote(true);
|
||||
await page.keyboard.press("ControlOrMeta+Alt+ArrowRight");
|
||||
|
||||
expect(await notes.editor.getTitle()).toBe("Note 1");
|
||||
await expect(notes.editor.title).toHaveValue("Note 1");
|
||||
expect(await notes.editor.getContent("text")).toBe("Note 1 content");
|
||||
|
||||
await page.keyboard.press("ControlOrMeta+Alt+ArrowRight");
|
||||
|
||||
expect(await notes.editor.getTitle()).toBe("Note 2");
|
||||
await expect(notes.editor.title).toHaveValue("Note 2");
|
||||
expect(await notes.editor.getContent("text")).toBe("Note 2 content");
|
||||
});
|
||||
|
||||
@@ -498,11 +496,11 @@ test("control + alt + left arrow should go to previous note", async ({
|
||||
await note2?.openNote(true);
|
||||
await page.keyboard.press("ControlOrMeta+Alt+ArrowLeft");
|
||||
|
||||
expect(await notes.editor.getTitle()).toBe("Note 1");
|
||||
await expect(notes.editor.title).toHaveValue("Note 1");
|
||||
expect(await notes.editor.getContent("text")).toBe("Note 1 content");
|
||||
|
||||
await page.keyboard.press("ControlOrMeta+Alt+ArrowLeft");
|
||||
|
||||
expect(await notes.editor.getTitle()).toBe("Note 2");
|
||||
await expect(notes.editor.title).toHaveValue("Note 2");
|
||||
expect(await notes.editor.getContent("text")).toBe("Note 2 content");
|
||||
});
|
||||
|
||||
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 65 KiB |
|
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 65 KiB |
|
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 65 KiB |
@@ -17,7 +17,8 @@ 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 { expect, Page, test } from "@playwright/test";
|
||||
import { Page } from "@playwright/test";
|
||||
import { test, expect } from "./utils";
|
||||
import { AppModel } from "./models/app.model";
|
||||
import { NoteItemModel } from "./models/note-item.model";
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { Locator, Page } from "@playwright/test";
|
||||
import { getTestId } from "../utils";
|
||||
import { authenticator } from "otplib";
|
||||
import { generateSync } from "otplib";
|
||||
|
||||
type User = {
|
||||
email: string;
|
||||
@@ -62,7 +62,7 @@ export class AuthModel {
|
||||
}
|
||||
|
||||
if (user.totpSecret) {
|
||||
const token = authenticator.generate(user.totpSecret);
|
||||
const token = generateSync({ secret: user.totpSecret });
|
||||
await this.codeInput.fill(token);
|
||||
|
||||
await this.submitButton.click();
|
||||
|
||||
@@ -24,7 +24,7 @@ import { iterateList } from "./utils";
|
||||
|
||||
export class EditorModel {
|
||||
private readonly page: Page;
|
||||
private readonly title: Locator;
|
||||
readonly title: Locator;
|
||||
readonly content: Locator;
|
||||
private readonly tags: Locator;
|
||||
private readonly tagInput: Locator;
|
||||
@@ -88,8 +88,9 @@ export class EditorModel {
|
||||
{ expected: title }
|
||||
);
|
||||
|
||||
if (content !== undefined)
|
||||
await this.content.locator(":scope", { hasText: content }).waitFor();
|
||||
if (content !== undefined) {
|
||||
await this.waitForContent(content);
|
||||
}
|
||||
}
|
||||
|
||||
async waitForUnloading() {
|
||||
@@ -109,6 +110,22 @@ export class EditorModel {
|
||||
await this.wordCountText.waitFor();
|
||||
}
|
||||
|
||||
async waitForContent(text: string) {
|
||||
await this.page.waitForFunction(
|
||||
({ expected }) => {
|
||||
const contentElement = document.querySelector(
|
||||
`.active .ProseMirror`
|
||||
) as HTMLElement | null;
|
||||
if (contentElement)
|
||||
return contentElement.innerText
|
||||
.replace(/\s+/g, "")
|
||||
.includes(expected.replace(/\s+/g, ""));
|
||||
return false;
|
||||
},
|
||||
{ expected: text }
|
||||
);
|
||||
}
|
||||
|
||||
async isUnloaded() {
|
||||
return (
|
||||
(await this.tagInput.isDisabled()) &&
|
||||
@@ -128,7 +145,7 @@ export class EditorModel {
|
||||
await this.title.focus();
|
||||
await this.title.selectText();
|
||||
await this.title.press("ArrowRight");
|
||||
await this.title.type(text, { delay });
|
||||
await this.title.pressSequentially(text, { delay });
|
||||
});
|
||||
}
|
||||
|
||||
@@ -136,6 +153,7 @@ export class EditorModel {
|
||||
await this.editAndWait(async () => {
|
||||
await this.content.focus();
|
||||
await this.content.pressSequentially(text);
|
||||
await this.waitForContent(text);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -143,6 +161,7 @@ export class EditorModel {
|
||||
await this.editAndWait(async () => {
|
||||
await this.selectAll();
|
||||
await this.content.press("Backspace");
|
||||
await this.waitForContent("");
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ import {
|
||||
iterateList
|
||||
} from "./utils";
|
||||
import { SessionHistoryItemModel } from "./session-history-item-model";
|
||||
import dayjs from "dayjs";
|
||||
import { Dayjs } from "dayjs";
|
||||
import { Reminder } from "@notesnook/core";
|
||||
|
||||
abstract class BaseProperties {
|
||||
@@ -235,7 +235,7 @@ export class NotePropertiesModel extends BaseProperties {
|
||||
return dateCreated;
|
||||
}
|
||||
|
||||
async editDateCreated(newDateCreated: number) {
|
||||
async editDateCreated(date: Dayjs) {
|
||||
await this.open();
|
||||
|
||||
const editIcon = this.page.locator(getTestId("edit-date-created"));
|
||||
@@ -253,9 +253,8 @@ export class NotePropertiesModel extends BaseProperties {
|
||||
getTestId("time-created-input")
|
||||
);
|
||||
|
||||
const date = new Date(newDateCreated);
|
||||
await dateInput.fill(dayjs(date).format("DD-MM-YYYY"));
|
||||
await timeInput.fill(dayjs(date).format("hh:mm A"));
|
||||
await dateInput.fill(date.format("DD-MM-YYYY"));
|
||||
await timeInput.fill(date.format("hh:mm A"));
|
||||
|
||||
await confirmDialog(editDateCreatedDialog);
|
||||
|
||||
|
||||
@@ -53,6 +53,7 @@ export class NotesViewModel extends BaseViewModel {
|
||||
if (note.content) await this.editor.setContent(note.content);
|
||||
|
||||
await this.editor.waitForSaving();
|
||||
if (note.content) await this.editor.waitForContent(note.content);
|
||||
if (note.title) await this.waitForItem(note.title);
|
||||
return await this.findNote(note);
|
||||
}
|
||||
|
||||
@@ -141,8 +141,6 @@ export class SettingsViewModel {
|
||||
|
||||
await uploadFile(this.page, restoreBackup, filename);
|
||||
if (password) await fillPasswordDialog(this.page, password);
|
||||
|
||||
await waitForDialog(this.page, "Restoring backup");
|
||||
}
|
||||
|
||||
async selectImageCompression(option: { value: string; label: string }) {
|
||||
|
||||