desktop: overhaul desktop core and migrate to typescript

This commit is contained in:
Abdullah Atta
2023-03-30 16:49:48 +05:00
committed by Abdullah Atta
parent 2a31f70b4a
commit 28927e705b
159 changed files with 32423 additions and 18037 deletions

View File

Before

Width:  |  Height:  |  Size: 118 KiB

After

Width:  |  Height:  |  Size: 118 KiB

View File

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

View File

Before

Width:  |  Height:  |  Size: 520 B

After

Width:  |  Height:  |  Size: 520 B

View File

Before

Width:  |  Height:  |  Size: 917 B

After

Width:  |  Height:  |  Size: 917 B

View File

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

View File

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

Before

Width:  |  Height:  |  Size: 353 KiB

After

Width:  |  Height:  |  Size: 353 KiB

View File

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

View File

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

View File

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

View File

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

View File

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

View File

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

View File

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

View File

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

View File

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

View File

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

52
apps/desktop/global.d.ts vendored Normal file
View File

@@ -0,0 +1,52 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* eslint-disable no-var */
import { BrowserWindow } from "electron";
import * as undici_types from "undici";
declare global {
export const {
fetch,
FormData,
Headers,
Request,
Response
}: typeof import("undici");
type FormData = undici_types.FormData;
type Headers = undici_types.Headers;
type HeadersInit = undici_types.HeadersInit;
type BodyInit = undici_types.BodyInit;
type Request = undici_types.Request;
type RequestInit = undici_types.RequestInit;
type RequestInfo = undici_types.RequestInfo;
type RequestMode = undici_types.RequestMode;
type RequestRedirect = undici_types.RequestRedirect;
type RequestCredentials = undici_types.RequestCredentials;
type RequestDestination = undici_types.RequestDestination;
type ReferrerPolicy = undici_types.ReferrerPolicy;
type Response = undici_types.Response;
type ResponseInit = undici_types.ResponseInit;
type ResponseType = undici_types.ResponseType;
var window: BrowserWindow | null;
var RELEASE: boolean;
var MAC_APP_STORE: boolean;
}

4943
apps/desktop/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -5,26 +5,36 @@
"version": "2.5.2",
"appAppleId": "1544027013",
"private": true,
"main": "./build/electron.js",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"homepage": "https://notesnook.com/",
"repository": "https://github.com/streetwriters/notesnook",
"dependencies": {
"@notesnook/crypto": "*",
"@trpc/client": "^10.18.0",
"@trpc/server": "^10.18.0",
"diary": "^0.3.1",
"electron-trpc": "^0.4.2",
"electron-updater": "^5.3.0",
"icojs": "^0.17.1",
"yargs": "^17.6.2"
"yargs": "^17.6.2",
"zod": "^3.21.4"
},
"devDependencies": {
"@electron/rebuild": "^3.2.10",
"@types/node": "^18.15.0",
"electron": "^25.1.0",
"electron-builder": "^23.6.0",
"electron-builder-notarize": "^1.5.0",
"electron-builder-notarize": "^1.5.1",
"electron-reloader": "^1.2.3",
"esbuild": "^0.17.19",
"patch-package": "^6.5.1"
"patch-package": "^6.5.1",
"undici": "^5.22.1"
},
"scripts": {
"build": "esbuild ./electron.js ./preload.js --external:electron --external:fsevents --minify --bundle --outdir=./build --platform=node --tsconfig=tsconfig.json --define:MAC_APP_STORE=false --define:RELEASE=true",
"start": "npm run build:electron && electron build/electron.js",
"build": "tsc",
"build:electron": "esbuild electron=./src/main.ts ./src/preload.ts --external:electron --external:fsevents --minify --bundle --outdir=./build --platform=node --tsconfig=tsconfig.json --define:MAC_APP_STORE=false --define:RELEASE=true",
"build:mas": "esbuild ./electron.js ./preload.js --minify --external:electron --external:fsevents --bundle --outdir=./build --platform=node --tsconfig=tsconfig.json --define:MAC_APP_STORE=true --define:RELEASE=true",
"pack": "rm -rf ./build && cp -r ../build ./ && npm run build && yarn electron-builder --linux AppImage:x64 AppImage:arm64",
"postinstall": "patch-package"

View File

@@ -18,16 +18,22 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import zlib from "node:zlib";
import utils from "node:util";
import { initTRPC } from "@trpc/server";
import { z } from "zod";
const t = initTRPC.create();
const gzipAsync = utils.promisify(zlib.gzip);
const gunzipAsync = utils.promisify(zlib.gunzip);
export async function gzip(args) {
const { data, level } = args;
return (await gzipAsync(data, { level })).toString("base64");
}
export async function gunzip(args) {
const { data } = args;
return (await gunzipAsync(Buffer.from(data, "base64"))).toString("utf-8");
}
export const compressionRouter = t.router({
gzip: t.procedure
.input(z.object({ data: z.string(), level: z.number() }))
.query(async ({ input }) => {
const { data, level } = input;
return (await gzipAsync(data, { level })).toString("base64");
}),
gunzip: t.procedure.input(z.string()).query(async ({ input }) => {
return (await gunzipAsync(Buffer.from(input, "base64"))).toString("utf-8");
})
});

View File

@@ -17,21 +17,23 @@ 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 { isDesktop } from "../utils/platform";
import { invokeCommand } from "./index";
import { initTRPC } from "@trpc/server";
import { compressionRouter } from "./compression";
import { osIntegrationRouter } from "./os-integration";
import { spellCheckerRouter } from "./spell-checker";
import { updaterRouter } from "./updater";
export default async function installUpdate() {
if (isDesktop()) invokeCommand("installUpdate");
else {
const registrations =
(await navigator.serviceWorker?.getRegistrations()) || [];
let reload = false;
for (let registration of registrations) {
if (registration.waiting) {
registration.waiting.postMessage({ type: "SKIP_WAITING" });
reload = true;
}
}
if (reload) window.location.reload();
}
}
const t = initTRPC.create();
export const router = t.router({
compress: compressionRouter,
integration: osIntegrationRouter,
spellChecker: spellCheckerRouter,
updater: updaterRouter
});
export const api = router.createCaller({});
// Export type router type signature,
// NOT the router itself.
export type AppRouter = typeof router;

View File

@@ -0,0 +1,145 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { initTRPC } from "@trpc/server";
import { z } from "zod";
import { dialog, Notification, shell } from "electron";
import { AutoLaunch } from "../utils/autolaunch";
import { config, DesktopIntegration } from "../utils/config";
import { bringToFront } from "../utils/bring-to-front";
import { setTheme, Theme } from "../utils/theme";
import { mkdirSync, writeFileSync } from "fs";
import { dirname, join } from "path";
import { platform } from "os";
import { resolvePath } from "../utils/resolve-path";
import { client } from "../rpc/electron";
const t = initTRPC.create();
const NotificationOptions = z.object({
title: z.string().optional(),
body: z.string().optional(),
silent: z.boolean().optional(),
timeoutType: z.union([z.literal("default"), z.literal("never")]).optional(),
urgency: z
.union([z.literal("normal"), z.literal("critical"), z.literal("low")])
.optional(),
tag: z.string()
});
export const osIntegrationRouter = t.router({
zoomFactor: t.procedure.query(() => config.zoomFactor),
setZoomFactor: t.procedure.input(z.number()).mutation(({ input: factor }) => {
globalThis.window?.webContents.setZoomFactor(factor);
config.zoomFactor = factor;
}),
privacyMode: t.procedure.query(() => config.privacyMode),
setPrivacyMode: t.procedure
.input(z.boolean())
.mutation(({ input: privacyMode }) => {
if (!globalThis.window || !["win32", "darwin"].includes(process.platform))
return;
globalThis.window.setContentProtection(privacyMode);
if (process.platform === "win32") {
globalThis.window.setThumbnailClip(
privacyMode
? { x: 0, y: 0, width: 1, height: 1 }
: { x: 0, y: 0, width: 0, height: 0 }
);
}
config.privacyMode = privacyMode;
}),
desktopIntegration: t.procedure.query(() => config.desktopSettings),
setDesktopIntegration: t.procedure
.input(DesktopIntegration)
.mutation(({ input: settings }) => {
if (settings.autoStart) {
AutoLaunch.enable(settings.startMinimized);
} else {
AutoLaunch.disable();
}
config.desktopSettings = settings;
}),
selectDirectory: t.procedure
.input(
z.object({
title: z.string().optional(),
buttonLabel: z.string().optional(),
defaultPath: z.string().optional()
})
)
.query(async ({ input }) => {
if (!globalThis.window) return undefined;
const { title, buttonLabel, defaultPath } = input;
const result = await dialog.showOpenDialog(globalThis.window, {
title,
buttonLabel,
properties: ["openDirectory"],
defaultPath: defaultPath && resolvePath(defaultPath)
});
if (result.canceled) return undefined;
return result.filePaths[0];
}),
saveFile: t.procedure
.input(z.object({ data: z.string(), filePath: z.string() }))
.query(({ input }) => {
const { data, filePath } = input;
if (!data || !filePath) return;
const resolvedPath = resolvePath(filePath);
mkdirSync(dirname(resolvedPath), { recursive: true });
writeFileSync(resolvedPath, data);
}),
showNotification: t.procedure
.input(NotificationOptions)
.query(({ input }) => {
const notification = new Notification({
...input,
icon: join(
__dirname,
platform() === "win32" ? "app.ico" : "favicon-72x72.png"
)
});
notification.show();
if (input.urgency === "critical") {
shell.beep();
}
client.onNotificationClicked(input.tag);
}),
openPath: t.procedure
.input(z.object({ type: z.literal("path"), link: z.string() }))
.query(({ input }) => {
const { type, link } = input;
if (type === "path") return shell.openPath(resolvePath(link));
}),
bringToFront: t.procedure.query(() => bringToFront()),
changeTheme: t.procedure.input(Theme).mutation(({ input }) => setTheme(input))
});

View File

@@ -17,9 +17,13 @@ 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 { getIsSpellCheckerEnabled } from "../../config/spellChecker";
import { initTRPC } from "@trpc/server";
import { z } from "zod";
import { config } from "../utils/config";
const LANGUAGES = {
const t = initTRPC.create();
const LANGUAGES: Record<string, string> = {
af: "Afrikaans",
bg: "Bulgarian",
ca: "Catalan",
@@ -78,28 +82,39 @@ const LANGUAGES = {
vi: "Vietnamese"
};
/**
*
* @param {*} args
* @param {import("electron").BrowserWindow} win
* @returns
*/
export default function (_args, win) {
if (!win) return;
type Language = { code: string; name: string };
return {
enabled: getIsSpellCheckerEnabled(),
languages: win.webContents.session.availableSpellCheckerLanguages.map(
(code) => ({
code,
name: LANGUAGES[code]
})
export const spellCheckerRouter = t.router({
isEnabled: t.procedure.query(() => config.isSpellCheckerEnabled),
languages: t.procedure.query(
() =>
<Language[]>(
globalThis.window?.webContents.session.availableSpellCheckerLanguages.map(
(code) => ({
code,
name: LANGUAGES[code]
})
)
)
),
enabledLanguages: t.procedure.query(
() =>
<Language[]>(
globalThis.window?.webContents.session
.getSpellCheckerLanguages()
.map((code) => ({
code,
name: LANGUAGES[code]
}))
)
),
setLanguages: t.procedure
.input(z.array(z.string()))
.mutation(({ input: languages }) =>
globalThis.window?.webContents.session.setSpellCheckerLanguages(languages)
),
enabledLanguages: win.webContents.session
.getSpellCheckerLanguages()
.map((code) => ({
code,
name: LANGUAGES[code]
}))
};
}
toggle: t.procedure.input(z.boolean()).mutation(({ input: enabled }) => {
globalThis.window?.webContents.session.setSpellCheckerEnabled(enabled);
config.isSpellCheckerEnabled = enabled;
})
});

View File

@@ -17,15 +17,18 @@ 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 { JSONStorage } from "../jsonstorage";
import { initTRPC } from "@trpc/server";
import { CancellationToken, autoUpdater } from "electron-updater";
function getPrivacyMode() {
let mode = JSONStorage.get("privacyMode");
return mode === undefined ? false : mode;
}
const t = initTRPC.create();
function setPrivacyMode(mode) {
return JSONStorage.set("privacyMode", mode);
}
export { setPrivacyMode, getPrivacyMode };
export const updaterRouter = t.router({
install: t.procedure.query(() => autoUpdater.quitAndInstall()),
download: t.procedure.query(async () => {
const cancellationToken = new CancellationToken();
await autoUpdater.downloadUpdate(cancellationToken);
}),
check: t.procedure.query(async () => {
await autoUpdater.checkForUpdates();
})
});

View File

@@ -21,10 +21,10 @@ import yargs from "yargs";
import { hideBin } from "yargs/helpers";
export type CLIOptions = {
note?: boolean | string;
notebook?: boolean | string;
reminder?: boolean | string;
hidden?: boolean;
note: boolean | string;
notebook: boolean | string;
reminder: boolean | string;
hidden: boolean;
};
export async function parseArguments(): Promise<CLIOptions> {
@@ -55,7 +55,7 @@ export async function parseArguments(): Promise<CLIOptions> {
"Open a note",
{ id: { string: true, description: "Id of the note" } },
(args) => {
result.note = args.id;
result.note = args.id || false;
}
)
.command(
@@ -63,7 +63,7 @@ export async function parseArguments(): Promise<CLIOptions> {
"Open a notebook",
{ id: { string: true, description: "Id of the notebook" } },
(args) => {
result.notebook = args.id;
result.notebook = args.id || false;
}
)
.command(
@@ -79,6 +79,6 @@ export async function parseArguments(): Promise<CLIOptions> {
);
})
.parse();
result.hidden = hidden;
result.hidden = hidden || false;
return result;
}

View File

@@ -17,8 +17,6 @@ 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 { autoUpdater } from "electron-updater";
export default () => {
autoUpdater.quitAndInstall();
};
export * from "./constants";
export type { AppRouter } from "./api";
export * from "./rpc";

View File

@@ -18,28 +18,22 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* global MAC_APP_STORE, RELEASE */
import "isomorphic-fetch";
import { client } from "./rpc/electron";
import { app, BrowserWindow, nativeTheme, shell } from "electron";
import { isDevelopment } from "./utils";
import { registerProtocol, PROTOCOL_URL } from "./protocol";
import { configureAutoUpdater } from "./autoupdate";
import { getBackgroundColor, getTheme, setTheme } from "./config/theme";
import getZoomFactor from "./ipc/calls/getZoomFactor";
import { logger } from "./logger";
import { setupMenu } from "./menu";
import { WindowState } from "./config/window-state";
import { sendMessageToRenderer } from "./ipc/utils";
import { EVENTS } from "./events";
import "./ipc/index.js";
import getPrivacyMode from "./ipc/calls/getPrivacyMode";
import setPrivacyMode from "./ipc/actions/setPrivacyMode";
import { getIsSpellCheckerEnabled } from "./config/spellChecker";
import { getDesktopIntegration } from "./config/desktopIntegration";
import { AutoLaunch } from "./autolaunch";
import { setupJumplist } from "./jumplist";
import { setupTray } from "./tray";
import { parseArguments } from "./cli";
import { AssetManager } from "./asset-manager";
import { registerProtocol, PROTOCOL_URL } from "./utils/protocol";
import { configureAutoUpdater } from "./utils/autoupdater";
import { getBackgroundColor, getTheme, setTheme } from "./utils/theme";
import { setupMenu } from "./utils/menu";
import { WindowState } from "./utils/window-state";
import { AutoLaunch } from "./utils/autolaunch";
import { setupJumplist } from "./utils/jumplist";
import { setupTray } from "./utils/tray";
import { CLIOptions, parseArguments } from "./cli";
import { AssetManager } from "./utils/asset-manager";
import { createIPCHandler } from "electron-trpc/main";
import { router, api } from "./api";
import { config } from "./utils/config";
if (!RELEASE) {
require("electron-reloader")(module);
@@ -55,12 +49,11 @@ if (process.platform === "win32") {
app.setAppUserModelId(app.name);
}
var mainWindowState;
async function createWindow() {
await AssetManager.loadIcons();
const cliOptions = await parseArguments();
mainWindowState = new WindowState({});
const mainWindowState = new WindowState({});
setTheme(getTheme());
const mainWindow = new BrowserWindow({
@@ -78,19 +71,18 @@ async function createWindow() {
format: process.platform === "win32" ? "ico" : "png"
}),
webPreferences: {
zoomFactor: getZoomFactor(),
zoomFactor: config.zoomFactor,
devTools: true, // isDev,
nodeIntegration: false, //true,
contextIsolation: true,
nativeWindowOpen: true,
spellcheck: getIsSpellCheckerEnabled(),
nodeIntegration: true, //true,
contextIsolation: false,
spellcheck: config.isSpellCheckerEnabled,
preload: __dirname + "/preload.js"
}
});
mainWindow.on("show", () => {
if (getPrivacyMode()) {
setPrivacyMode({ privacyMode: getPrivacyMode() });
mainWindow.on("show", async () => {
if (config.privacyMode) {
await api.integration.setPrivacyMode(config.privacyMode);
}
});
@@ -99,6 +91,7 @@ async function createWindow() {
setupMenu();
setupJumplist();
setupDesktopIntegration(cliOptions.hidden);
createIPCHandler({ router, windows: [mainWindow] });
mainWindow.webContents.session.setSpellCheckerDictionaryDownloadURL(
"http://dictionaries.notesnook.com/"
@@ -110,7 +103,7 @@ async function createWindow() {
try {
await mainWindow.loadURL(`${createURL(cliOptions)}`);
} catch (e) {
logger.error(e);
if (e instanceof Error) console.error(e);
}
mainWindow.on("closed", () => {
@@ -127,16 +120,14 @@ async function createWindow() {
setupJumplist();
if (getTheme() === "system") {
sendMessageToRenderer(EVENTS.themeChanged, {
theme: nativeTheme.shouldUseDarkColors ? "dark" : "light"
});
client.onThemeChanged(nativeTheme.shouldUseDarkColors ? "dark" : "light");
}
});
}
app.commandLine.appendSwitch("lang", "en-US");
app.on("ready", async () => {
logger.info("App ready. Opening window.");
console.info("App ready. Opening window.");
registerProtocol();
await createWindow();
@@ -155,10 +146,7 @@ app.on("activate", () => {
}
});
/**
* @param {import("./cli").CLIOptions} options
*/
function createURL(options) {
function createURL(options: CLIOptions) {
const url = new URL(isDevelopment() ? "http://localhost:3000" : PROTOCOL_URL);
if (options.note === true) url.hash = "/notes/create/1";
@@ -172,8 +160,8 @@ function createURL(options) {
return url;
}
function setupDesktopIntegration(hidden) {
const desktopIntegration = getDesktopIntegration();
function setupDesktopIntegration(hidden: boolean) {
const desktopIntegration = config.desktopSettings;
if (
desktopIntegration.closeToSystemTray ||
@@ -182,14 +170,14 @@ function setupDesktopIntegration(hidden) {
setupTray();
}
globalThis.window.on("ready-to-show", () => {
globalThis.window?.on("ready-to-show", () => {
if (!hidden) {
globalThis.window.show();
globalThis.window?.show();
}
if (hidden && !desktopIntegration.minimizeToSystemTray) {
globalThis.window.show();
globalThis.window.minimize();
globalThis.window?.show();
globalThis.window?.minimize();
}
});
@@ -199,27 +187,27 @@ function setupDesktopIntegration(hidden) {
app.on("before-quit", () => app.exit(0));
}
globalThis.window.on("close", (e) => {
if (getDesktopIntegration().closeToSystemTray) {
globalThis.window?.on("close", (e) => {
if (config.desktopSettings.closeToSystemTray) {
e.preventDefault();
if (process.platform == "darwin") {
// on macOS window cannot be minimized/hidden if it is already fullscreen
// so we just close it.
if (globalThis.window.isFullScreen()) app.exit(0);
if (globalThis.window?.isFullScreen()) app.exit(0);
else app.hide();
} else {
globalThis.window.minimize();
globalThis.window.hide();
globalThis.window?.minimize();
globalThis.window?.hide();
}
}
});
globalThis.window.on("minimize", () => {
if (getDesktopIntegration().minimizeToSystemTray) {
globalThis.window?.on("minimize", () => {
if (config.desktopSettings.minimizeToSystemTray) {
if (process.platform == "darwin") {
app.hide();
} else {
globalThis.window.hide();
globalThis.window?.hide();
}
}
});

View File

@@ -0,0 +1,59 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* eslint-disable no-var */
import { ELECTRON_TRPC_CHANNEL } from "electron-trpc/main";
import { type RendererGlobalElectronTRPC } from "electron-trpc/src/types";
import { NNCrypto } from "@notesnook/crypto";
import { ipcRenderer } from "electron";
import { CHANNEL, ITransport } from "./rpc";
declare global {
var os: string;
var electronTRPC: RendererGlobalElectronTRPC;
var RPCTransport: ITransport;
var NativeNNCrypto: new () => NNCrypto;
}
process.once("loaded", async () => {
const electronTRPC: RendererGlobalElectronTRPC = {
sendMessage: (operation) =>
ipcRenderer.send(ELECTRON_TRPC_CHANNEL, operation),
onMessage: (callback) =>
ipcRenderer.on(ELECTRON_TRPC_CHANNEL, (_event, args) => callback(args))
};
globalThis.electronTRPC = electronTRPC;
globalThis.RPCTransport = {
send(message) {
console.log("[browser] sending message", message);
ipcRenderer.send(CHANNEL, message);
},
receive(callback) {
ipcRenderer.removeAllListeners(CHANNEL);
ipcRenderer.addListener(CHANNEL, (_event, args) => {
console.log("[browser] recevied message", args);
callback(args);
});
}
};
});
globalThis.NativeNNCrypto = NNCrypto;
globalThis.os = MAC_APP_STORE ? "mas" : process.platform;

View File

@@ -16,10 +16,10 @@ 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/>.
*/
/* eslint-disable no-var */
import { BrowserWindow } from "electron";
import { ITransport } from "./types";
declare global {
// eslint-disable-next-line no-var
var window: BrowserWindow;
var RPCTransport: ITransport;
}

View File

@@ -17,24 +17,21 @@ 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 { AutoLaunch } from "../../autolaunch";
import { setDesktopIntegration } from "../../config/desktopIntegration";
import { destroyTray, setupTray } from "../../tray";
import { ipcMain } from "electron";
import { CHANNEL, createRPCClient } from ".";
import { ClientPrototype, ITransport } from "./types";
export default (args) => {
if (!globalThis.window) return;
if (args.autoStart) {
AutoLaunch.enable(args.startMinimized);
} else {
AutoLaunch.disable();
const transport: ITransport = {
send(message) {
console.log("[electron] sending message", message);
globalThis.window?.webContents.send(CHANNEL, message);
},
receive(callback) {
ipcMain.on(CHANNEL, (_event, message) => {
console.log("[electron] received message", message);
callback(message);
});
}
if (args.closeToSystemTray || args.minimizeToSystemTray) {
setupTray();
} else {
destroyTray();
}
setDesktopIntegration(args);
};
export const client = createRPCClient(transport, ClientPrototype);

View File

@@ -0,0 +1,77 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { ITransport } from "./types";
export const CHANNEL = "RPC_COM_CHANNEL";
type RPCApi = Record<string, (...args: any[]) => any>;
type WrappedAPI<TApi extends RPCApi> = {
[P in keyof TApi]: (
...args: Parameters<TApi[P]>
) => ReturnType<TApi[P]> extends void
? void
: ReturnType<TApi[P]> extends Promise<infer T>
? Promise<T>
: Promise<ReturnType<TApi[P]>>;
};
export function createRPCClient<TApi extends RPCApi>(
transport: ITransport,
api: TApi
): WrappedAPI<TApi> {
const wrappedAPI = <WrappedAPI<TApi>>{};
for (const method in api) {
if (Object.hasOwn(api, method)) {
wrappedAPI[<keyof TApi>method] = (...args: any[]) => {
return <any>new Promise<unknown>((resolve) => {
transport.receive((message) => {
if (message.type === "response" && message.id === method) {
resolve(message.result);
}
});
transport.send({
type: "message",
id: method,
args
});
});
};
}
}
return wrappedAPI;
}
export function createRPCServer<TApi extends RPCApi>(
transport: ITransport,
api: TApi
) {
transport.receive(async (message) => {
if (
message.type === "message" &&
message.id &&
Object.hasOwn(api, message.id)
) {
const result = await api[<keyof TApi>message.id](...message.args);
transport.send({ type: "response", id: message.id, result });
}
});
}
export * from "./types";

View File

@@ -0,0 +1,55 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import type {
UpdateInfo,
ProgressInfo,
UpdateDownloadedEvent
} from "electron-updater";
import type { Theme } from "../utils/theme";
export const ClientPrototype = {
onCheckingForUpdate() {},
onUpdateAvailable(info: UpdateInfo) {},
onUpdateDownloadProgress(progress: ProgressInfo) {},
onUpdateDownloadCompleted(info: UpdateDownloadedEvent) {},
onUpdateNotAvailable(info: UpdateInfo) {},
onThemeChanged(theme: Theme) {},
onNotificationClicked(tag: string) {},
onCreateItem(type: "note" | "notebook" | "reminder") {
return type;
}
};
export type IClient = typeof ClientPrototype;
export type IClientMethod = keyof IClient;
export type IMessage = {
type: "message";
id: string;
args: unknown[];
};
export type IResponse = {
type: "response";
id: string;
result: unknown;
};
export type ITransport = {
send(message: IMessage | IResponse): void;
receive(callback: (message: IMessage | IResponse) => void): void;
};

View File

@@ -19,10 +19,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import { NativeImage, nativeImage } from "electron";
import path from "path";
import { isDevelopment } from "./utils";
import { isDevelopment } from "./index";
import { parse, ParsedImage } from "icojs";
import { readFileSync } from "fs";
import { getSystemTheme } from "./config/theme";
import { getSystemTheme } from "./theme";
type Formats = "ico" | "png" | "icns";
type IconOptions<TFormat extends Formats> = {
@@ -30,8 +30,8 @@ type IconOptions<TFormat extends Formats> = {
format?: TFormat;
};
type IconNames = typeof icons[number];
type Prefixes = typeof prefixes[number];
type IconNames = (typeof icons)[number];
type Prefixes = (typeof prefixes)[number];
type FlexibleIcon<TFormat extends Formats> = TFormat extends "ico"
? string

View File

@@ -18,8 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { autoUpdater } from "electron-updater";
import { EVENTS } from "./events";
import { sendMessageToRenderer } from "./ipc/utils";
import { client } from "../rpc/electron";
async function configureAutoUpdater() {
autoUpdater.setFeedURL({
@@ -32,21 +31,14 @@ async function configureAutoUpdater() {
autoUpdater.allowDowngrade = false;
autoUpdater.allowPrerelease = false;
autoUpdater.autoInstallOnAppQuit = true;
autoUpdater.addListener("checking-for-update", () => {
sendMessageToRenderer(EVENTS.checkingForUpdate);
});
autoUpdater.addListener("update-available", (info) => {
sendMessageToRenderer(EVENTS.updateAvailable, info);
});
autoUpdater.addListener("download-progress", (progress) => {
sendMessageToRenderer(EVENTS.updateDownloadProgress, progress);
});
autoUpdater.addListener("update-downloaded", (info) => {
sendMessageToRenderer(EVENTS.updateDownloadCompleted, info);
});
autoUpdater.addListener("update-not-available", (info) => {
sendMessageToRenderer(EVENTS.updateNotAvailable, info);
});
autoUpdater.addListener("checking-for-update", client.onCheckingForUpdate);
autoUpdater.addListener("update-available", client.onUpdateAvailable);
autoUpdater.addListener("download-progress", client.onUpdateDownloadProgress);
autoUpdater.addListener(
"update-downloaded",
client.onUpdateDownloadCompleted
);
autoUpdater.addListener("update-not-available", client.onUpdateNotAvailable);
}
export { configureAutoUpdater };

View File

@@ -17,9 +17,9 @@ 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 { WindowState } from "../../config/window-state";
import { WindowState } from "./window-state";
export default () => {
export function bringToFront() {
if (!globalThis.window) return;
if (globalThis.window.isMinimized()) {
@@ -31,4 +31,4 @@ export default () => {
globalThis.window.focus();
globalThis.window.moveTop();
globalThis.window.webContents.focus();
};
}

View File

@@ -0,0 +1,55 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { nativeTheme } from "electron";
import { JSONStorage } from "./json-storage";
import { z } from "zod";
export const DesktopIntegration = z.object({
autoStart: z.boolean(),
startMinimized: z.boolean(),
minimizeToSystemTray: z.boolean(),
closeToSystemTray: z.boolean()
});
export type DesktopIntegration = z.infer<typeof DesktopIntegration>;
export const config = {
desktopSettings: <DesktopIntegration>{
autoStart: false,
startMinimized: false,
minimizeToSystemTray: false,
closeToSystemTray: false
},
privacyMode: false,
isSpellCheckerEnabled: false,
zoomFactor: 0,
theme: nativeTheme.themeSource
};
type ConfigKey = keyof typeof config;
for (const key in config) {
const defaultValue = config[<ConfigKey>key];
if (Object.hasOwn(config, key)) {
Object.defineProperty(config, key, {
get: () => JSONStorage.get(key, defaultValue),
set: (value) => JSONStorage.set(key, value)
});
}
}

View File

@@ -17,15 +17,21 @@ 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 { JSONStorage } from "../jsonstorage";
import { app } from "electron";
import { join } from "path";
import { existsSync } from "fs";
function getZoomFactor() {
let factor = parseFloat(JSONStorage.get("zoomFactor"));
return isNaN(factor) ? 1.0 : factor;
export const APP_ICON_PATH = join(
__dirname,
process.platform === "win32" ? "app.ico" : "favicon-72x72.png"
);
export function isDevelopment() {
return process.env.ELECTRON_IS_DEV
? Number.parseInt(process.env.ELECTRON_IS_DEV, 10) === 1
: !app.isPackaged;
}
function setZoomFactor(factor) {
return JSONStorage.set("zoomFactor", factor.toString());
export function isFlatpak() {
return existsSync("/.flatpak-info");
}
export { setZoomFactor, getZoomFactor };

View File

@@ -18,10 +18,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { app, Menu } from "electron";
import { client } from "../rpc/electron";
import { AssetManager } from "./asset-manager";
import { EVENTS } from "./events";
import bringToFront from "./ipc/actions/bringToFront";
import { sendMessageToRenderer } from "./ipc/utils";
import { bringToFront } from "./bring-to-front";
export function setupJumplist() {
if (process.platform === "win32") {
@@ -76,7 +75,7 @@ function setDockMenuOnMacOs() {
type: "normal",
click: () => {
bringToFront();
sendMessageToRenderer(EVENTS.createItem, { itemType: "note" });
client.onCreateItem("note");
}
},
{
@@ -84,7 +83,7 @@ function setDockMenuOnMacOs() {
type: "normal",
click: () => {
bringToFront();
sendMessageToRenderer(EVENTS.createItem, { itemType: "notebook" });
client.onCreateItem("notebook");
}
},
{
@@ -92,7 +91,7 @@ function setDockMenuOnMacOs() {
type: "normal",
click: () => {
bringToFront();
sendMessageToRenderer(EVENTS.createItem, { itemType: "reminder" });
client.onCreateItem("reminder");
}
}
]);

View File

@@ -20,6 +20,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import { Menu, MenuItem, clipboard, shell } from "electron";
function setupMenu() {
if (!globalThis.window) return;
globalThis.window.webContents.on("context-menu", (_event, params) => {
const menu = new Menu();
@@ -29,7 +31,7 @@ function setupMenu() {
new MenuItem({
label: suggestion,
click: () =>
globalThis.window.webContents.replaceMisspelling(suggestion)
globalThis.window?.webContents.replaceMisspelling(suggestion)
})
);
}
@@ -40,7 +42,7 @@ function setupMenu() {
new MenuItem({
label: "Add to dictionary",
click: () =>
globalThis.window.webContents.session.addWordToSpellCheckerDictionary(
globalThis.window?.webContents.session.addWordToSpellCheckerDictionary(
params.misspelledWord
)
})

View File

@@ -0,0 +1,94 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { protocol, net } from "electron";
import { isDevelopment } from "./index";
import { createReadStream, statSync } from "fs";
import { extname, join, normalize } from "path";
import { URL } from "url";
const BASE_PATH = isDevelopment() ? "../public" : "";
const HOSTNAME = `app.notesnook.com`;
const SCHEME = "https";
const extensionToMimeType: Record<string, string> = {
html: "text/html",
json: "application/json",
js: "application/javascript",
css: "text/css",
svg: "image/svg+xml",
png: "image/png"
};
function registerProtocol() {
protocol.handle(SCHEME, (request) => {
const url = new URL(request.url);
if (shouldInterceptRequest(url)) {
console.info("Intercepting request:", request);
const loadIndex = !extname(url.pathname);
const absoluteFilePath = normalize(
`${__dirname}${
loadIndex ? `${BASE_PATH}/index.html` : `${BASE_PATH}/${url.pathname}`
}`
);
const filePath = getPath(absoluteFilePath);
if (!filePath) {
console.error("Local asset file not found at", filePath);
return new Response(undefined, {
status: 404,
statusText: "FILE_NOT_FOUND"
});
}
const fileExtension = extname(filePath).replace(".", "");
const data = createReadStream(filePath);
const headers = new Headers();
headers.set("Content-Type", extensionToMimeType[fileExtension]);
return new Response(data, { headers });
} else {
return net.fetch(request);
}
});
console.info(`${SCHEME} protocol inteception "successful"`);
}
const bypassedRoutes: string[] = [];
function shouldInterceptRequest(url: URL) {
const shouldIntercept = url.hostname === HOSTNAME;
return shouldIntercept && !bypassedRoutes.includes(url.pathname);
}
const PROTOCOL_URL = `${SCHEME}://${HOSTNAME}/`;
export { registerProtocol, PROTOCOL_URL };
function getPath(filePath: string): string | undefined {
try {
const result = statSync(filePath);
if (result.isFile()) {
return filePath;
}
if (result.isDirectory()) {
return getPath(join(filePath, "index.html"));
}
} catch (_) {
// ignore
}
}

View File

@@ -17,25 +17,17 @@ 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 { logger } from "../logger";
import { app } from "electron";
import { isAbsolute, join } from "path";
function sendMessageToRenderer(type, payload = {}) {
const message = { type, ...payload };
logger.info("Sending message to renderer", message);
if (globalThis.window)
globalThis.window.webContents.send("fromMain", message);
}
function resolvePath(_path) {
export function resolvePath(_path: string) {
if (isAbsolute(_path)) return _path;
return join(
..._path.split("/").map((segment) => {
let resolved = segment;
try {
resolved = app.getPath(resolved);
resolved = app.getPath(resolved as any);
} catch (e) {
// ignore
}
@@ -43,5 +35,3 @@ function resolvePath(_path) {
})
);
}
export { resolvePath, sendMessageToRenderer };

View File

@@ -17,19 +17,27 @@ 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 { JSONStorage } from "../jsonstorage";
import { nativeTheme } from "electron";
import { config } from "./config";
import { z } from "zod";
type Theme = typeof nativeTheme.themeSource;
function getTheme(): Theme {
return JSONStorage.get("theme", nativeTheme.themeSource);
export const Theme = z.union([
z.literal("system"),
z.literal("light"),
z.literal("dark")
]);
export type Theme = z.infer<typeof Theme>;
function getTheme() {
return config.theme;
}
function setTheme(theme: Theme) {
changeTheme(theme);
if (globalThis.window)
globalThis.window.setBackgroundColor(getBackgroundColor());
return JSONStorage.set("theme", theme);
config.theme = theme;
}
function getBackgroundColor() {

View File

@@ -19,10 +19,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import { app, Menu, Tray } from "electron";
import { AssetManager } from "./asset-manager";
import { EVENTS } from "./events";
import bringToFront from "./ipc/actions/bringToFront";
import { sendMessageToRenderer } from "./ipc/utils";
import { isFlatpak } from "./utils";
import { isFlatpak } from "./index";
import { bringToFront } from "./bring-to-front";
import { client } from "../rpc/electron";
let tray: Tray | undefined = undefined;
export function destroyTray() {
@@ -59,7 +58,7 @@ export function setupTray() {
: AssetManager.icon("note-add", { size: trayIconSize }),
click: () => {
bringToFront();
sendMessageToRenderer(EVENTS.createItem, { itemType: "note" });
client.onCreateItem("note");
}
},
{
@@ -70,7 +69,7 @@ export function setupTray() {
: AssetManager.icon("notebook-add", { size: trayIconSize }),
click: () => {
bringToFront();
sendMessageToRenderer(EVENTS.createItem, { itemType: "notebook" });
client.onCreateItem("notebook");
}
},
{ type: "separator" },

View File

@@ -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 { JSONStorage } from "../jsonstorage";
import { JSONStorage } from "./json-storage";
import { screen as _screen, BrowserWindow } from "electron";
const screen = _screen;

View File

@@ -0,0 +1,8 @@
{
"extends": "../../tsconfig",
"compilerOptions": {
"outDir": "./dist/",
"lib": ["ESNext"]
},
"include": ["src", "global.d.ts"]
}

File diff suppressed because it is too large Load Diff

View File

@@ -37,4 +37,4 @@
"react-native-swiper-flatlist": "3.2.2",
"@notesnook/logger": "*"
}
}
}

View File

@@ -1,31 +0,0 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { JSONStorage } from "../jsonstorage";
function getIsSpellCheckerEnabled() {
let mode = JSONStorage.get("isSpellCheckerEnabled");
return mode === undefined ? true : mode;
}
function setIsSpellCheckerEnabled(mode) {
return JSONStorage.set("isSpellCheckerEnabled", mode);
}
export { getIsSpellCheckerEnabled, setIsSpellCheckerEnabled };

View File

@@ -1,29 +0,0 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
export const EVENTS = {
checkingForUpdate: "checkingForUpdate",
updateAvailable: "updateAvailable",
updateDownloadProgress: "updateDownloadProgress",
updateDownloadCompleted: "updateDownloadCompleted",
updateNotAvailable: "updateNotAvailable",
themeChanged: "themeChanged",
notificationClicked: "notificationClicked",
createItem: "createItem"
};

View File

@@ -1,26 +0,0 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { setTheme } from "../../config/theme";
export default (args) => {
if (!globalThis.window) return;
const { theme } = args;
setTheme(theme);
};

View File

@@ -1,24 +0,0 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { autoUpdater } from "electron-updater";
export default () => {
autoUpdater.checkForUpdates();
};

View File

@@ -1,29 +0,0 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { CancellationToken } from "builder-util-runtime";
import { autoUpdater } from "electron-updater";
import { EVENTS } from "../../events";
import { sendMessageToRenderer } from "../utils";
export default () => {
sendMessageToRenderer(EVENTS.updateDownloadProgress, { progress: 0 });
autoUpdater.cancellationToken = new CancellationToken();
autoUpdater.downloadUpdate(autoUpdater.cancellationToken);
};

View File

@@ -1,57 +0,0 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import changeAppTheme from "./changeAppTheme";
import checkForUpdate from "./checkForUpdate";
import downloadUpdate from "./downloadUpdate";
import installUpdate from "./installUpdate";
import open from "./open";
import saveFile from "./saveFile";
import setZoomFactor from "./setZoomFactor";
import setPrivacyMode from "./setPrivacyMode";
import showNotification from "./showNotification";
import bringToFront from "./bringToFront";
import setSpellCheckerLanguages from "./setSpellCheckerLanguages";
import toggleSpellChecker from "./toggleSpellChecker";
import setDesktopIntegration from "./setDesktopIntegration";
const actions = {
changeAppTheme,
checkForUpdate,
downloadUpdate,
installUpdate,
open,
saveFile,
setZoomFactor,
setPrivacyMode,
showNotification,
bringToFront,
setSpellCheckerLanguages,
toggleSpellChecker,
setDesktopIntegration,
};
export function getAction(actionName) {
try {
if (!actions[actionName]) throw new Error("Invalid action name.");
} catch (e) {
console.error(e);
}
return actions[actionName];
}

View File

@@ -1,26 +0,0 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { shell } from "electron";
import { resolvePath } from "../utils";
export default (args) => {
const { link, linkType } = args;
if (linkType === "path") return shell.openPath(resolvePath(link));
};

View File

@@ -1,41 +0,0 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { mkdirSync, writeFileSync } from "fs";
import { dirname } from "path";
import { logger } from "../../logger";
import { resolvePath } from "../utils";
export default (args) => {
try {
const { data, filePath } = args;
if (!data || !filePath) return;
const resolvedPath = resolvePath(filePath);
logger.info("Saving file to", resolvedPath);
mkdirSync(dirname(resolvedPath), { recursive: true });
writeFileSync(resolvedPath, data);
logger.info("File saved to", resolvedPath);
} catch (e) {
logger.error("Could not save file.", e);
}
};

View File

@@ -1,38 +0,0 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { setPrivacyMode } from "../../config/privacyMode";
export default (args) => {
if (!globalThis.window || !["win32", "darwin"].includes(process.platform))
return;
const { privacyMode } = args;
globalThis.window.setContentProtection(privacyMode);
if (process.platform === "win32") {
globalThis.window.setThumbnailClip(
privacyMode
? { x: 0, y: 0, width: 1, height: 1 }
: { x: 0, y: 0, width: 0, height: 0 }
);
}
setPrivacyMode(privacyMode);
};

View File

@@ -1,25 +0,0 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
export default (args) => {
if (!globalThis.window) return;
const { languages } = args;
globalThis.window.webContents.session.setSpellCheckerLanguages(languages);
};

View File

@@ -1,27 +0,0 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { setZoomFactor } from "../../config/zoomfactor";
export default (args) => {
if (!globalThis.window) return;
const { zoomFactor } = args;
globalThis.window.webContents.setZoomFactor(zoomFactor);
setZoomFactor(zoomFactor);
};

View File

@@ -1,27 +0,0 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { setIsSpellCheckerEnabled } from "../../config/spellChecker";
export default (args) => {
if (!globalThis.window) return;
const { enabled } = args;
globalThis.window.webContents.session.setSpellCheckerEnabled(enabled);
setIsSpellCheckerEnabled(enabled);
};

View File

@@ -1,24 +0,0 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { getDesktopIntegration } from "../../config/desktopIntegration";
export default function () {
return getDesktopIntegration();
}

View File

@@ -1,24 +0,0 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { getPrivacyMode } from "../../config/privacyMode";
export default function () {
return getPrivacyMode();
}

View File

@@ -1,24 +0,0 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { getZoomFactor } from "../../config/zoomfactor";
export default function () {
return getZoomFactor();
}

View File

@@ -1,44 +0,0 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import getZoomFactor from "./getZoomFactor";
import getPrivacyMode from "./getPrivacyMode";
import selectDirectory from "./selectDirectory";
import { gunzip, gzip } from "./gzip";
import getSpellChecker from "./getSpellChecker";
import getDesktopIntegration from "./getDesktopIntegration";
const calls = {
getZoomFactor,
getPrivacyMode,
selectDirectory,
gunzip,
gzip,
getSpellChecker,
getDesktopIntegration,
};
export const getCall = function getAction(callName) {
try {
if (!calls[callName]) throw new Error("Invalid call name.");
} catch (e) {
console.error(e);
}
return calls[callName];
};

View File

@@ -1,35 +0,0 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { dialog } from "electron";
import { resolvePath } from "../utils";
export default async function (args, win) {
const { title, buttonLabel, defaultPath } = args;
const result = await dialog.showOpenDialog(win, {
title,
buttonLabel,
properties: ["openDirectory"],
defaultPath: resolvePath(defaultPath)
});
if (result.canceled) return;
return result.filePaths[0];
}

View File

@@ -1,41 +0,0 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { ipcMain } from "electron";
import { logger } from "../logger";
import { getAction } from "./actions";
import { getCall } from "./calls";
ipcMain.on("fromRenderer", async (event, args) => {
logger.info("Action requested by renderer", args);
const { type } = args;
const action = getAction(type);
if (!action) return;
await action(args);
});
ipcMain.handle("fromRenderer", async (event, args) => {
const { type } = args;
logger.info("Call requested by renderer", type);
const call = getCall(type);
if (!call) return;
return await call(args, globalThis.window);
});

View File

@@ -1,54 +0,0 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { app } from "electron";
import { diary, enable, default_reporter } from "diary";
import { createWriteStream } from "fs";
import { join } from "path";
import { isDevelopment } from "./utils";
enable("native");
const LOG_FILE_PATH = join(app.getPath("logs"), "notesnook.log");
const logFileStream = createWriteStream(LOG_FILE_PATH, {
autoClose: true,
flags: "a"
});
const native = diary("native", (e) => {
if (isDevelopment()) default_reporter(e);
logFileReporter(e);
});
function logFileReporter(e) {
const time = new Date().toLocaleString("en", {
month: "2-digit",
day: "2-digit",
year: "numeric",
hour12: true,
hour: "2-digit",
minute: "2-digit",
second: "2-digit"
});
const extra = e.extra.map((ex) => JSON.stringify(ex)).join(" ");
let str = `[${time}] | ${e.level} | ${e.message} ${extra}\n`;
logFileStream.write(str);
}
export const logger = native;

File diff suppressed because it is too large Load Diff

View File

@@ -1,94 +0,0 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* global MAC_APP_STORE */
import { contextBridge, ipcRenderer } from "electron";
contextBridge.exposeInMainWorld("os", MAC_APP_STORE ? "mas" : process.platform);
// Expose protected methods that allow the renderer process to use
// the ipcRenderer without exposing the entire object
contextBridge.exposeInMainWorld("api", {
send: (channel, data) => {
// whitelist channels
let validChannels = ["fromRenderer"];
if (validChannels.includes(channel)) {
ipcRenderer.send(channel, data);
}
},
receive: (channel, func) => {
let validChannels = ["fromMain"];
if (validChannels.includes(channel)) {
ipcRenderer.removeAllListeners(channel);
// Deliberately strip event as it includes `sender`
ipcRenderer.addListener(channel, (event, args) => {
func(args);
});
}
}
});
// Expose protected methods that allow the renderer process to use
// the ipcRenderer without exposing the entire object
contextBridge.exposeInMainWorld("config", {
zoomFactor: () => {
return ipcRenderer.invoke("fromRenderer", {
type: "getZoomFactor"
});
},
privacyMode: () => {
return ipcRenderer.invoke("fromRenderer", {
type: "getPrivacyMode"
});
},
spellChecker: () => {
return ipcRenderer.invoke("fromRenderer", {
type: "getSpellChecker"
});
},
desktopIntegration: () => {
return ipcRenderer.invoke("fromRenderer", {
type: "getDesktopIntegration"
});
}
});
contextBridge.exposeInMainWorld("native", {
selectDirectory: ({ title, buttonLabel, defaultPath }) => {
return ipcRenderer.invoke("fromRenderer", {
type: "selectDirectory",
title,
buttonLabel,
defaultPath
});
},
gzip: ({ data, level }) => {
return ipcRenderer.invoke("fromRenderer", {
type: "gzip",
data,
level
});
},
gunzip: ({ data }) => {
return ipcRenderer.invoke("fromRenderer", {
type: "gunzip",
data
});
}
});

View File

@@ -1,138 +0,0 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { protocol } from "electron";
import { isDevelopment, getPath } from "./utils";
import { createReadStream } from "fs";
import { extname, normalize } from "path";
import { logger } from "./logger";
import { URL } from "url";
import { Blob } from "buffer";
const FILE_NOT_FOUND = -6;
const BASE_PATH = isDevelopment() ? "../public" : "";
const HOSTNAME = `app.notesnook.com`;
const PROTOCOL = "https";
const extensionToMimeType = {
html: "text/html",
json: "application/json",
js: "application/javascript",
css: "text/css",
svg: "image/svg+xml",
png: "image/png"
};
function registerProtocol() {
const protocolInterceptionResult = protocol.interceptStreamProtocol(
PROTOCOL,
async (request, callback) => {
const url = new URL(request.url);
if (shouldInterceptRequest(url)) {
logger.info("Intercepting request:", request);
const loadIndex = !extname(url.pathname);
const absoluteFilePath = normalize(
`${__dirname}${
loadIndex
? `${BASE_PATH}/index.html`
: `${BASE_PATH}/${url.pathname}`
}`
);
const filePath = getPath(absoluteFilePath);
if (!filePath) {
logger.error("Local asset file not found at", filePath);
callback({ error: FILE_NOT_FOUND });
return;
}
const fileExtension = extname(filePath).replace(".", "");
const data = createReadStream(filePath);
callback({
data,
mimeType: extensionToMimeType[fileExtension]
});
} else {
var response;
try {
const body = await getBody(request);
response = await fetch(request.url, {
...request,
body,
headers: {
...request.headers
// origin: `${PROTOCOL}://${HOSTNAME}/`
},
referrer: request.referrer,
redirect: "manual"
});
} catch (e) {
console.error(e);
logger.error(`Error sending request to `, request.url, "Error: ", e);
callback({ statusCode: 400 });
return;
}
callback({
statusCode: response.status,
data: response.body,
headers: Object.fromEntries(response.headers.entries()),
mimeType: response.headers.get("Content-Type")
});
}
}
);
logger.info(
`${PROTOCOL} protocol inteception ${
protocolInterceptionResult ? "successful" : "failed"
}.`
);
}
const bypassedRoutes = [];
function shouldInterceptRequest(url) {
let shouldIntercept = url.hostname === HOSTNAME;
return shouldIntercept && !bypassedRoutes.includes(url.pathname);
}
/**
*
* @param {Electron.ProtocolRequest} request
*/
async function getBody(request) {
/**
* @type {Electron.Session}
*/
const session = globalThis?.window?.webContents?.session;
const blobParts = [];
if (!request.uploadData || !request.uploadData.length) return null;
for (let data of request.uploadData) {
if (data.type === "rawData") {
blobParts.push(new Uint8Array(data.bytes));
} else if (session && data.type === "blob") {
const buffer = await session.getBlobData(data.blobUUID);
blobParts.push(new Uint8Array(buffer));
}
}
const blob = new Blob(blobParts);
return await blob.arrayBuffer();
}
const PROTOCOL_URL = `${PROTOCOL}://${HOSTNAME}/`;
export { registerProtocol, PROTOCOL_URL };

View File

@@ -1,21 +0,0 @@
{
"compilerOptions": {
"target": "ES6",
"lib": ["esnext", "DOM"],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"downlevelIteration": true,
"maxNodeModuleJsDepth": 5
}
}

View File

@@ -1,59 +0,0 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { app } from "electron";
import { join } from "path";
import { statSync, existsSync } from "fs";
const APP_ICON_PATH = join(
__dirname,
process.platform === "win32" ? "app.ico" : "favicon-72x72.png"
);
function isDevelopment() {
if (typeof electron === "string") {
throw new TypeError("Not running in an Electron environment!");
}
const isEnvSet = "ELECTRON_IS_DEV" in process.env;
const getFromEnv = Number.parseInt(process.env.ELECTRON_IS_DEV, 10) === 1;
return isEnvSet ? getFromEnv : !app.isPackaged;
}
function getPath(filePath) {
try {
const result = statSync(filePath);
if (result.isFile()) {
return filePath;
}
if (result.isDirectory()) {
return getPath(join(filePath, "index.html"));
}
} catch (_) {
// ignore
}
}
function isFlatpak() {
return existsSync("/.flatpak-info");
}
export { getPath, isDevelopment, isFlatpak, APP_ICON_PATH };

File diff suppressed because it is too large Load Diff

View File

@@ -29,9 +29,12 @@
"@notesnook/web-clipper": "*",
"@react-pdf-viewer/core": "^3.12.0",
"@react-pdf-viewer/toolbar": "^3.12.0",
"@tanstack/react-query": "^4.28.0",
"@tanstack/react-virtual": "^3.0.0-beta.18",
"@theme-ui/components": "^0.14.7",
"@theme-ui/core": "^0.14.7",
"@trpc/client": "^10.18.0",
"@trpc/react-query": "^10.18.0",
"allotment": "^1.12.1",
"async-mutex": "^0.3.2",
"axios": "^1.3.4",
@@ -39,6 +42,7 @@
"comlink": "^4.3.1",
"cronosjs": "^1.7.1",
"dayjs": "^1.10.4",
"electron-trpc": "^0.4.2",
"event-source-polyfill": "^1.0.25",
"fflate": "^0.7.4",
"file-saver": "^2.0.5",

View File

@@ -30,7 +30,7 @@ import { introduceFeatures, showUpgradeReminderDialogs } from "./common";
import { AppEventManager, AppEvents } from "./common/app-events";
import { db } from "./common/db";
import { EV, EVENTS } from "@notesnook/core/common";
import { EVENTS as DESKTOP_APP_EVENTS } from "@notesnook/desktop/events";
import { EVENTS as DESKTOP_APP_EVENTS } from "@notesnook/desktop";
import { registerKeyMap } from "./common/key-map";
import { isUserPremium } from "./hooks/use-is-user-premium";
import {

View File

@@ -1,24 +0,0 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { invokeCommand } from "./index";
export default function bringToFront() {
invokeCommand("bringToFront");
}

View File

@@ -1,24 +0,0 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { invokeCommand } from "./index";
export default function changeAppTheme(theme) {
invokeCommand("changeAppTheme", { theme });
}

View File

@@ -1,31 +0,0 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { isDesktop } from "../utils/platform";
import { invokeCommand } from "./index";
export default async function downloadUpdate() {
if (isDesktop()) invokeCommand("downloadUpdate");
else {
console.log("Force updating");
if (!("serviceWorker" in navigator)) return;
const registration = await navigator.serviceWorker.ready;
await registration.update();
}
}

View File

@@ -23,16 +23,16 @@ import { isDesktop } from "../utils/platform";
export function invokeCommand(type, payload = {}) {
if (!isDesktop()) return;
window.api.send("fromRenderer", {
type,
...payload
});
// window.api.send("fromRenderer", {
// type,
// ...payload
// });
}
if (isDesktop()) {
window.api.receive("fromMain", (args) => {
console.log(args);
const { type, ...other } = args;
AppEventManager.publish(type, other);
});
}
// if (isDesktop()) {
// window.api.receive("fromMain", (args) => {
// console.log(args);
// const { type, ...other } = args;
// AppEventManager.publish(type, other);
// });
// }

View File

@@ -1,24 +0,0 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { invokeCommand } from "./index";
export function openPath(path) {
invokeCommand("open", { link: path, linkType: "path" });
}

View File

@@ -1,24 +0,0 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { invokeCommand } from "./index";
export default function saveFile(filePath, data) {
invokeCommand("saveFile", { filePath, data });
}

View File

@@ -1,26 +0,0 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { invokeCommand } from "./index";
export default function setDesktopIntegration(
settings: DesktopIntegrationSettings
) {
invokeCommand("setDesktopIntegration", settings);
}

View File

@@ -1,24 +0,0 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { invokeCommand } from "./index";
export default function setPrivacyMode(privacyMode) {
invokeCommand("setPrivacyMode", { privacyMode });
}

View File

@@ -1,24 +0,0 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { invokeCommand } from "./index";
export default function setSpellCheckerLanguages(languages) {
invokeCommand("setSpellCheckerLanguages", { languages });
}

Some files were not shown because too many files have changed in this diff Show More