desktop: overhaul desktop core and migrate to typescript
|
Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 118 KiB |
|
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.2 KiB |
|
Before Width: | Height: | Size: 520 B After Width: | Height: | Size: 520 B |
|
Before Width: | Height: | Size: 917 B After Width: | Height: | Size: 917 B |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 353 KiB After Width: | Height: | Size: 353 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
52
apps/desktop/global.d.ts
vendored
Normal 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
@@ -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"
|
||||
@@ -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");
|
||||
})
|
||||
});
|
||||
@@ -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;
|
||||
145
apps/desktop/src/api/os-integration.ts
Normal 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))
|
||||
});
|
||||
@@ -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;
|
||||
})
|
||||
});
|
||||
@@ -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();
|
||||
})
|
||||
});
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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";
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
});
|
||||
59
apps/desktop/src/preload.ts
Normal 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;
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
77
apps/desktop/src/rpc/index.ts
Normal 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";
|
||||
55
apps/desktop/src/rpc/types.ts
Normal 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;
|
||||
};
|
||||
@@ -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
|
||||
@@ -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 };
|
||||
@@ -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();
|
||||
};
|
||||
}
|
||||
55
apps/desktop/src/utils/config.ts
Normal 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)
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -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 };
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
]);
|
||||
@@ -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
|
||||
)
|
||||
})
|
||||
94
apps/desktop/src/utils/protocol.ts
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -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 };
|
||||
@@ -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() {
|
||||
@@ -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" },
|
||||
@@ -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;
|
||||
|
||||
8
apps/desktop/tsconfig.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "../../tsconfig",
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist/",
|
||||
"lib": ["ESNext"]
|
||||
},
|
||||
"include": ["src", "global.d.ts"]
|
||||
}
|
||||
16050
apps/mobile/package-lock.json
generated
@@ -37,4 +37,4 @@
|
||||
"react-native-swiper-flatlist": "3.2.2",
|
||||
"@notesnook/logger": "*"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 };
|
||||
@@ -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"
|
||||
};
|
||||
@@ -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);
|
||||
};
|
||||
@@ -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();
|
||||
};
|
||||
@@ -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);
|
||||
};
|
||||
@@ -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];
|
||||
}
|
||||
@@ -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));
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
@@ -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);
|
||||
};
|
||||
@@ -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);
|
||||
};
|
||||
@@ -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);
|
||||
};
|
||||
@@ -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);
|
||||
};
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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];
|
||||
};
|
||||
@@ -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];
|
||||
}
|
||||
@@ -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);
|
||||
});
|
||||
@@ -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;
|
||||
7613
apps/web/desktop/package-lock.json
generated
@@ -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
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -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 };
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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 };
|
||||
833
apps/web/package-lock.json
generated
@@ -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",
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
@@ -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 });
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
// });
|
||||
// }
|
||||
|
||||
@@ -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" });
|
||||
}
|
||||
@@ -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 });
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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 });
|
||||
}
|
||||
@@ -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 });
|
||||
}
|
||||