Compare commits

..

1 Commits

Author SHA1 Message Date
ammarahm-ed
59264d1ed0 mobile: fix appending link to empty note stuck 2023-06-15 16:43:04 +05:00
1123 changed files with 90523 additions and 127009 deletions

View File

@@ -14,16 +14,13 @@ const SCOPES = [
"mobile",
"web",
"vericrypt",
"desktop",
"crypto",
"editor",
"logger",
"theme",
"server",
"core",
"fs",
"ui",
"clipper",
"config",
"ci",
@@ -31,9 +28,7 @@ const SCOPES = [
"docs",
"refactor",
"misc",
"common",
"global",
"docs"
"global"
];
module.exports = {

1
.gitattributes vendored
View File

@@ -1 +0,0 @@
* text=auto eol=lf

View File

@@ -1,5 +1,5 @@
name: "Setup node with cache action"
description: "Setups node with cache"
name: 'Setup node with cache action'
description: 'Setups node with cache'
runs:
using: "composite"
@@ -24,4 +24,4 @@ runs:
packages/editor/package-lock.json
packages/logger/package-lock.json
packages/streamable-fs/package-lock.json
packages/theme/package-lock.json
packages/theme/package-lock.json

4
.github/dco.yml vendored Normal file
View File

@@ -0,0 +1,4 @@
allowRemediationCommits:
individual: true
require:
members: false

View File

@@ -17,14 +17,12 @@ jobs:
- name: Use specific Java version for the builds
uses: joschi/setup-jdk@v2
with:
java-version: "11"
architecture: "x64"
java-version: '11'
architecture: 'x64'
- name: Install node modules
run: |
npm ci --ignore-scripts --prefer-offline --no-audit
npm run bootstrap -- --scope=mobile
npm ci
- name: Make Gradlew Executable
run: cd apps/mobile/native/android && chmod +x ./gradlew
@@ -39,7 +37,7 @@ jobs:
signingKeyBase64: ${{ secrets.SIGNING_KEY }}
alias: ${{ secrets.ALIAS }}
keyStorePassword: ${{ secrets.KEY_PASSWORD }}
keyPassword: ${{ secrets.KEY_PASSWORD }}
keyPassword: ${{ secrets.KEY_PASSWORD }}
- name: Publish to Playstore
id: deploy
@@ -50,4 +48,4 @@ jobs:
releaseFile: ${{steps.sign_app.outputs.signedReleaseFile}}
track: internal
status: completed
whatsNewDirectory: apps/mobile/native/android/releasenotes/
whatsNewDirectory: apps/mobile/native/android/releasenotes/

View File

@@ -17,14 +17,12 @@ jobs:
- name: Use specific Java version for the builds
uses: joschi/setup-jdk@v2
with:
java-version: "11"
architecture: "x64"
java-version: '11'
architecture: 'x64'
- name: Install node modules
run: |
npm ci --ignore-scripts --prefer-offline --no-audit
npm run bootstrap -- --scope=mobile
npm ci
- name: Make Gradlew Executable
run: cd apps/mobile/native/android && chmod +x ./gradlew
@@ -39,7 +37,7 @@ jobs:
signingKeyBase64: ${{ secrets.SIGNING_KEY }}
alias: ${{ secrets.ALIAS }}
keyStorePassword: ${{ secrets.KEY_PASSWORD }}
keyPassword: ${{ secrets.KEY_PASSWORD }}
keyPassword: ${{ secrets.KEY_PASSWORD }}
- name: Publish to Playstore
id: deploy
@@ -50,7 +48,7 @@ jobs:
releaseFiles: ${{steps.sign_app.outputs.signedReleaseFile}}
track: production
status: completed
whatsNewDirectory: apps/mobile/native/android/releasenotes/
whatsNewDirectory: apps/mobile/native/android/releasenotes/
- name: Build apks for Github release
run: yarn release:android
@@ -63,7 +61,7 @@ jobs:
signingKeyBase64: ${{ secrets.PUBLIC_SIGNING_KEY }}
alias: ${{ secrets.PUBLIC_ALIAS }}
keyStorePassword: ${{ secrets.PUBLIC_KEY_PASSWORD }}
keyPassword: ${{ secrets.PUBLIC_KEY_PASSWORD }}
keyPassword: ${{ secrets.PUBLIC_KEY_PASSWORD }}
- name: Rename apk files
run: |
@@ -91,4 +89,4 @@ jobs:
apps/mobile/native/android/app/build/outputs/apk/release/notesnook-arm64-v8a.apk
apps/mobile/native/android/app/build/outputs/apk/release/notesnook-armeabi-v7a.apk
apps/mobile/native/android/app/build/outputs/apk/release/notesnook-x86.apk
apps/mobile/native/android/app/build/outputs/apk/release/notesnook-x86_64.apk
apps/mobile/native/android/app/build/outputs/apk/release/notesnook-x86_64.apk

View File

@@ -8,7 +8,7 @@ on:
paths:
- "packages/core/**"
# re-run workflow if workflow file changes
- ".github/workflows/core.tests.yml"
- ".github/workflows/core.tests.yml"
pull_request:
types:
- "ready_for_review"
@@ -28,8 +28,7 @@ jobs:
- name: Prepare environment
run: |
npm ci --ignore-scripts --prefer-offline --no-audit
npm run bootstrap -- --scope=core
npm ci --prefer-offline --no-audit
- name: Add environment variables
run: |
echo "USER_EMAIL=${{ secrets.USER_EMAIL }}" >> $GITHUB_ENV

View File

@@ -32,8 +32,8 @@ jobs:
- name: Install packages
run: |
npm ci --ignore-scripts --prefer-offline --no-audit
npm run bootstrap -- --scope=web
npm i --ignore-scripts --prefer-offline --no-audit
npx lerna bootstrap --ignore=@notesnook/mobile -- --prefer-offline --no-audit
- name: Setup environment
run: |
@@ -93,7 +93,7 @@ jobs:
echo ::set-output name=app_bundle_id::$(cat package.json | jq -r .build.appId)
echo ::set-output name=app_version::$(cat package.json | jq -r .version)
echo ::set-output name=bundle_version::$(cat package.json | jq -r .build.mac.bundleVersion)
- name: Get App Store Version
id: appstore
uses: streetwriters/appstore-connect-app-version@develop
@@ -108,13 +108,13 @@ jobs:
uses: actions/download-artifact@v3
with:
name: build
path: ./apps/web/build
path: ./apps/desktop/build
- name: Install packages
run: |
npm ci --ignore-scripts --prefer-offline --no-audit
npm run bootstrap -- --scope=desktop
npm i --ignore-scripts --prefer-offline --no-audit
npx lerna bootstrap --ignore=@notesnook/mobile -- --prefer-offline --no-audit
- name: Install provisioning profile
run: echo "${{ secrets.MAC_PROVISIONING_PROFILE }}" | base64 --decode > embedded.provisionprofile
working-directory: ./apps/desktop
@@ -126,7 +126,7 @@ jobs:
CSC_KEY_PASSWORD: ${{ secrets.mac_certs_password }}
run: |
npx nx run release --project @notesnook/desktop -- --variant=mas
npx electron-builder --mac mas --universal -p never
npm run builder -- --mac mas --universal -p never
working-directory: ./apps/desktop
- name: Build zip and dmg
@@ -140,9 +140,9 @@ jobs:
run: |
npx nx run release --project @notesnook/desktop
if [ ${{ inputs.publish-github }} == true ]; then
npx electron-builder --mac zip dmg --arm64 --x64 -p always
npm run builder -- --mac zip dmg --arm64 --x64 -p always
else
npx electron-builder --mac zip dmg --arm64 --x64 -p never
npm run builder -- --mac zip dmg --arm64 --x64 -p never
fi
working-directory: ./apps/desktop
@@ -151,7 +151,7 @@ jobs:
env:
API_KEY_ID: ${{ secrets.api_key_id }}
API_KEY_ISSUER_ID: ${{ secrets.api_key_issuer_id }}
run: |
run: |
package=$(find ./output/mas-universal/notesnook*.pkg)
echo "Uploading ${package} using altool..."
@@ -183,12 +183,12 @@ jobs:
uses: actions/download-artifact@v3
with:
name: build
path: ./apps/web/build
path: ./apps/desktop/build
- name: Install packages
run: |
npm ci --ignore-scripts --prefer-offline --no-audit
npm run bootstrap -- --scope=desktop
npm i --ignore-scripts --prefer-offline --no-audit
npx lerna bootstrap --ignore=@notesnook/mobile -- --prefer-offline --no-audit
- name: Build Electron wrapper
run: npx nx run release --project @notesnook/desktop
@@ -197,7 +197,7 @@ jobs:
- name: Build snap
if: inputs.publish-snap
run: |
npx electron-builder --linux snap:x64 -p never
npm run builder -- --linux snap:x64 -p never
working-directory: ./apps/desktop
- name: Build AppImage
@@ -205,9 +205,9 @@ jobs:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
if [ ${{ inputs.publish-github }} == true ]; then
npx electron-builder --linux AppImage:x64 AppImage:arm64 -p always
npm run builder -- --linux AppImage:x64 AppImage:arm64 -p always
else
npx electron-builder --linux AppImage:x64 AppImage:arm64 -p never
npm run builder -- --linux AppImage:x64 AppImage:arm64 -p never
fi
working-directory: ./apps/desktop
@@ -233,17 +233,18 @@ jobs:
uses: actions/download-artifact@v3
with:
name: build
path: ./apps/web/build
path: ./apps/desktop/build
- name: Install packages
run: |
npm ci --ignore-scripts --prefer-offline --no-audit
npm run bootstrap -- --scope=desktop
npm i --ignore-scripts --prefer-offline --no-audit
npx lerna bootstrap --ignore=@notesnook/mobile -- --prefer-offline --no-audit
- name: Build
- name: Build Electron wrapper
run: npx nx run release --project @notesnook/desktop
working-directory: ./apps/desktop
- name: Publish
- name: Build app
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
@@ -252,4 +253,4 @@ jobs:
} else {
yarn electron-builder --win --publish never
}
working-directory: ./apps/desktop
working-directory: ./apps/desktop

View File

@@ -29,8 +29,8 @@ jobs:
- name: Install packages
run: |
npm ci --ignore-scripts --prefer-offline --no-audit
npm run bootstrap -- --scope=editor
npm i --ignore-scripts --prefer-offline --no-audit
npx lerna bootstrap --ignore=@notesnook/mobile -- --prefer-offline --no-audit
- name: Setup environment
run: |

View File

@@ -1,35 +0,0 @@
name: Publish Notesnook Help
on:
workflow_dispatch:
push:
branches:
- "master"
paths:
- "docs/help/**"
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Install docgen
run: cargo install --git https://github.com/thecodrr/docgen
- name: Build site
run: docgen build --release
working-directory: docs/help
- name: Setup environment
run: |
echo "CLOUDFLARE_ACCOUNT_ID=${{ secrets.CLOUDFLARE_ACCOUNT_ID }}" >> $GITHUB_ENV
echo "CLOUDFLARE_API_TOKEN=${{ secrets.CLOUDFLARE_API_TOKEN }}" >> $GITHUB_ENV
- name: Publish on Cloudflare Pages
run: npx --yes wrangler pages deploy --project-name notesnook-help ./docs/help/site/ --branch main

View File

@@ -11,4 +11,4 @@ jobs:
steps:
- name: Run ats-diagnostics
run: nscurl --ats-diagnostics https://payments.streetwriters.co
run: nscurl --ats-diagnostics https://payments.streetwriters.co

View File

@@ -1,31 +0,0 @@
name: Publish @notesnook/vericrypt
on: workflow_dispatch
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Node
uses: ./.github/actions/setup-node-with-cache
- name: Install packages
run: |
npm ci --ignore-scripts --prefer-offline --no-audit
npm run bootstrap -- --scope=vericrypt
- name: Setup environment
run: |
echo "NX_CLOUD_ACCESS_TOKEN=${{ secrets.NX_CLOUD_ACCESS_TOKEN }}" >> $GITHUB_ENV
echo "CLOUDFLARE_ACCOUNT_ID=${{ secrets.CLOUDFLARE_ACCOUNT_ID }}" >> $GITHUB_ENV
echo "CLOUDFLARE_API_TOKEN=${{ secrets.CLOUDFLARE_API_TOKEN }}" >> $GITHUB_ENV
- name: Generate build
run: npm run build:vericrypt
- name: Publish on Cloudflare Pages
run: npx --yes wrangler pages deploy --project-name=vericrypt ./apps/vericrypt/build/

View File

@@ -1,67 +0,0 @@
name: Publish @notesnook/web Beta
on:
workflow_dispatch:
push:
branches:
- master
paths-ignore:
- "apps/mobile/**"
- "packages/editor-mobile/**"
- "apps/desktop/**"
- "apps/vericrypt/**"
- "servers/**"
- "packages/clipper/**"
- "extensions/web-clipper/**"
pull_request:
types:
- closed
- ready_for_review
- reopened
- opened
- synchronize
branches:
- master
paths-ignore:
- "apps/mobile/**"
- "packages/editor-mobile/**"
- "apps/desktop/**"
- "apps/vericrypt/**"
- "servers/**"
- "packages/clipper/**"
- "extensions/web-clipper/**"
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Node
uses: ./.github/actions/setup-node-with-cache
- name: Install packages
run: |
npm ci --ignore-scripts --prefer-offline --no-audit
npm run bootstrap -- --scope=web
- name: Setup environment
run: |
echo "NX_CLOUD_ACCESS_TOKEN=${{ secrets.NX_CLOUD_ACCESS_TOKEN }}" >> $GITHUB_ENV
echo "CLOUDFLARE_ACCOUNT_ID=${{ secrets.CLOUDFLARE_ACCOUNT_ID }}" >> $GITHUB_ENV
echo "CLOUDFLARE_API_TOKEN=${{ secrets.CLOUDFLARE_API_TOKEN }}" >> $GITHUB_ENV
- name: Generate beta build
run: npm run build:beta:web
- name: Publish to Cloudflare Pages
uses: unlike-ltd/github-actions-cloudflare-pages@v0.1.1
id: pages
with:
cloudflare-api-token: ${{ secrets.CLOUDFLARE_API_TOKEN }}
cloudflare-account-id: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
cloudflare-project-name: notesnook-beta-app
directory: ./apps/web/build
github-token: ${{ secrets.GITHUB_TOKEN }}
github-environment: ${{ (github.ref == 'refs/heads/master' && 'beta') || 'preview' }}

View File

@@ -15,8 +15,8 @@ jobs:
- name: Install packages
run: |
npm ci --ignore-scripts --prefer-offline --no-audit
npm run bootstrap -- --scope=web
npm i --ignore-scripts --prefer-offline --no-audit
npx lerna bootstrap --ignore=@notesnook/mobile -- --prefer-offline --no-audit
- name: Setup environment
run: |
@@ -24,16 +24,8 @@ jobs:
echo "CLOUDFLARE_ACCOUNT_ID=${{ secrets.CLOUDFLARE_ACCOUNT_ID }}" >> $GITHUB_ENV
echo "CLOUDFLARE_API_TOKEN=${{ secrets.CLOUDFLARE_API_TOKEN }}" >> $GITHUB_ENV
- name: Generate build
- name: Generate desktop build
run: npm run build:web
- name: Publish to Cloudflare Pages
uses: unlike-ltd/github-actions-cloudflare-pages@v0.1.1
id: pages
with:
cloudflare-api-token: ${{ secrets.CLOUDFLARE_API_TOKEN }}
cloudflare-account-id: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
cloudflare-project-name: notesnook-app
directory: ./apps/web/build
github-token: ${{ secrets.GITHUB_TOKEN }}
github-environment: production
- name: Publish on Cloudflare Pages
run: npx --yes wrangler pages publish --project-name=notesnook-app ./apps/web/build/

View File

@@ -29,8 +29,8 @@ jobs:
- name: Install packages
run: |
npm ci --ignore-scripts --prefer-offline --no-audit
npm run bootstrap -- --scope=web
npm i --ignore-scripts --prefer-offline --no-audit
npx lerna bootstrap --ignore=@notesnook/mobile -- --prefer-offline --no-audit
- name: Setup environment
run: |
@@ -66,7 +66,7 @@ jobs:
- name: Install packages
run: |
npm ci --ignore-scripts --prefer-offline --no-audit
npm i --ignore-scripts --prefer-offline --no-audit
npm install -D @playwright/test otplib
- name: Validate build extraction

4
.gitignore vendored
View File

@@ -7,6 +7,4 @@ nx-cloud.env
.idea
.eslintcache
.env.local
.nyc_output
site
node_modules.backup
.nyc_output

View File

@@ -5,6 +5,5 @@ module.exports = {
printWidth: 80,
useTabs: false,
tabWidth: 2,
bracketSpacing: true,
endOfLine: "lf"
bracketSpacing: true
};

72
.vscode/notesnook.code-workspace vendored Normal file
View File

@@ -0,0 +1,72 @@
{
"folders": [
{
"name": "✨ notesnook",
"path": ".."
},
{
"name": "🚀 @notesnook/mobile",
"path": "../apps/mobile"
},
{
"name": "🚀 @notesnook/web",
"path": "../apps/web"
},
{
"name": "🚀 @notesnook/desktop",
"path": "../apps/web/desktop"
},
{
"name": "🚀 @notesnook/web-clipper",
"path": "../extensions/web-clipper"
},
{
"name": "📦 @notesnook/clipper",
"path": "../packages/clipper"
},
{
"name": "📦 @notesnook/core",
"path": "../packages/core"
},
{
"name": "📦 @notesnook/crypto",
"path": "../packages/crypto"
},
{
"name": "📦 @notesnook/crypto-worker",
"path": "../packages/crypto-worker"
},
{
"name": "📦 @notesnook/editor",
"path": "../packages/editor"
},
{
"name": "📦 @notesnook/editor-mobile",
"path": "../packages/editor-mobile"
},
{
"name": "📦 @notesnook/logger",
"path": "../packages/logger"
},
{
"name": "📦 @notesnook/streamable-fs",
"path": "../packages/streamable-fs"
},
{
"name": "📦 @notesnook/theme",
"path": "../packages/theme"
}
],
"settings": {
"typescript.tsdk": "node_modules/typescript/lib",
"javascript.format.enable": true,
"editor.formatOnSave": true,
"editor.formatOnSaveMode": "modificationsIfAvailable",
"eslint.packageManager": "npm",
"eslint.run": "onSave",
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"eslint.execArgv": ["--cache"]
}
}

15
.vscode/settings.json vendored
View File

@@ -1,15 +0,0 @@
{
"files.eol": "\n",
"typescript.tsdk": "node_modules/typescript/lib",
"editor.formatOnSave": true,
"editor.formatOnSaveMode": "file",
"eslint.run": "onSave",
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"eslint.options": {
"cache": true,
"cacheStrategy": "content"
},
"git.rebaseWhenSync": true
}

View File

@@ -27,7 +27,7 @@ Notesnook is built using the following technologies:
3. React Native — For mobile apps we are using React Native
4. Electron — For desktop app
5. NPM — listed here because we **don't** use Yarn or PNPM or XYZ across any of our projects.
6. Nx — maintaining monorepos is hard but Nx makes it easier.
6. Lerna & Nx — maintaining monorepos is hard but Nx makes it easier.
> **Note: Each project in the monorepo contains its own architecture details which you can refer to.**

View File

@@ -19,8 +19,33 @@ 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;

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
"name": "@notesnook/desktop",
"productName": "Notesnook",
"description": "Your private note taking space",
"version": "2.5.8",
"version": "2.5.2",
"appAppleId": "1544027013",
"private": true,
"main": "./dist/index.js",
@@ -11,37 +11,38 @@
"repository": "https://github.com/streetwriters/notesnook",
"license": "GPL-3.0-or-later",
"dependencies": {
"@notesnook/crypto": "file:../../packages/crypto",
"@trpc/client": "10.31.0",
"@trpc/server": "10.31.0",
"electron-trpc": "0.5.2",
"electron-updater": "6.1.1",
"@notesnook/crypto": "*",
"@trpc/client": "^10.29.1",
"@trpc/server": "^10.29.1",
"diary": "^0.3.1",
"electron-trpc": "^0.5.0",
"electron-updater": "^5.3.0",
"icojs": "^0.17.1",
"typed-emitter": "^2.1.0",
"yargs": "^17.6.2",
"zod": "^3.21.4"
},
"devDependencies": {
"@electron/rebuild": "^3.2.13",
"@types/node": "^18.15.0",
"@types/yargs": "^17.0.24",
"chokidar": "^3.5.3",
"electron": "24.5.1",
"electron-builder": "24.4.0",
"electron": "^24.4.0",
"electron-builder": "^23.6.0",
"electron-builder-notarize": "^1.5.1",
"electron-reloader": "^1.2.3",
"esbuild": "^0.17.19",
"node-fetch": "^3.3.1",
"tree-kill": "^1.2.2"
"undici": "^5.22.1"
},
"optionalDependencies": {
"dmg-license": "^1.0.11"
},
"scripts": {
"start": "node scripts/dev.mjs",
"staging": "node scripts/build.mjs --run",
"release": "node scripts/build.mjs",
"start": "turbowatch scripts/dev.ts",
"staging": "zx scripts/build.mjs --run",
"release": "zx scripts/build.mjs",
"build": "tsc",
"bundle": "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",
"bundle:mas": "esbuild electron=./src/main.ts ./src/preload.ts --minify --external:electron --external:fsevents --bundle --outdir=./build --platform=node --tsconfig=tsconfig.json --define:MAC_APP_STORE=true --define:RELEASE=true",
"builder": "./node_modules/.bin/electron-builder",
"postinstall": "patch-package"
},
"author": {
@@ -54,16 +55,11 @@
"productName": "Notesnook",
"copyright": "Copyright © 2023 Streetwriters (Private) Limited",
"artifactName": "notesnook_${os}_${arch}.${ext}",
"npmRebuild": false,
"asar": false,
"files": [
"!*.chunk.js.map",
"!*.chunk.js.LICENSE.txt",
"build/",
"!build/screenshots${/*}",
"!build/banner.jpg",
"!build/*.ico",
"!build/*.png",
"!node_modules${/*}"
],
"afterSign": "electron-builder-notarize",

View File

@@ -1,5 +1,5 @@
diff --git a/node_modules/app-builder-lib/out/targets/LinuxTargetHelper.js b/node_modules/app-builder-lib/out/targets/LinuxTargetHelper.js
index 3ba5d6a..cf8e147 100644
index ffcc8bd..7e57c9e 100644
--- a/node_modules/app-builder-lib/out/targets/LinuxTargetHelper.js
+++ b/node_modules/app-builder-lib/out/targets/LinuxTargetHelper.js
@@ -105,6 +105,7 @@ class LinuxTargetHelper {
@@ -9,12 +9,12 @@ index 3ba5d6a..cf8e147 100644
+ actions: undefined
};
const description = this.getDescription(targetSpecificOptions);
if (!(0, builder_util_1.isEmptyOrSpaces)(description)) {
if (!builder_util_1.isEmptyOrSpaces(description)) {
@@ -148,6 +149,23 @@ class LinuxTargetHelper {
data += `\n${name}=${desktopMeta[name]}`;
}
data += "\n";
+
+
+ if (targetSpecificOptions.desktop.actions) {
+ let actionsData = "";
+ const validActions = [];

View File

@@ -1,23 +0,0 @@
diff --git a/node_modules/electron-trpc/dist/main.mjs b/node_modules/electron-trpc/dist/main.mjs
index 379cf3b..2644e5d 100644
--- a/node_modules/electron-trpc/dist/main.mjs
+++ b/node_modules/electron-trpc/dist/main.mjs
@@ -221,9 +221,16 @@ class G {
i(this, c).includes(r) || (i(this, c).push(r), I(this, T, W).call(this, r));
}
detachWindow(r) {
+
y(this, c, i(this, c).filter((n) => n !== r));
- for (const [n, t] of i(this, u).entries())
- n.startsWith(`${r.webContents.id}-`) && (t.unsubscribe(), i(this, u).delete(n));
+ for (const [n, t] of i(this, u).entries()) {
+ try {
+ n.startsWith(`${r.webContents.id}-`) && (t.unsubscribe(), i(this, u).delete(n));
+ } catch(e) {
+ console.error(e);
+ // ignore
+ }
+ }
}
}
c = new WeakMap(), u = new WeakMap(), T = new WeakSet(), W = function(r) {

View File

@@ -19,99 +19,54 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import path from "path";
import fs from "fs/promises";
import { existsSync } from "fs";
import yargs from "yargs-parser";
import os from "os";
import * as childProcess from "child_process";
import { fileURLToPath } from "url";
import { $, argv, os } from "zx";
const args = yargs(process.argv);
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const sodiumNativePrebuildPath = (arch) =>
path.join(
`node_modules`,
`@notesnook`,
`crypto`,
`node_modules`,
`@notesnook`,
`sodium`,
`node_modules`,
`sodium-native`,
`prebuilds`,
`${os.platform()}-${arch}`
);
const webAppPath = path.resolve(path.join(__dirname, "..", "..", "web"));
$.env = process.env;
await fs.rm("./build/", { force: true, recursive: true });
const sodiumNativePrebuildPath = path.join(
`node_modules`,
`@notesnook`,
`crypto`,
`node_modules`,
`@notesnook`,
`sodium`,
`node_modules`,
`sodium-native`,
`prebuilds`,
`${os.platform()}-x64`
);
if (args.rebuild || !existsSync(path.join(webAppPath, "build"))) {
await exec(`cd ${webAppPath} && npm run build:desktop`);
}
if (argv.rebuild) {
await fs.rm("./build/", { force: true, recursive: true });
await fs.cp(path.join(webAppPath, "build"), "build", {
recursive: true,
force: true
});
await $`cd ../web/ && npm run build:desktop`;
if (args.variant === "mas") {
await exec(`npm run bundle:mas`);
} else {
await exec(`npm run bundle`);
}
await exec(`npx tsc`);
if (existsSync(sodiumNativePrebuildPath("x64"))) {
console.log("copying sodium-native-x64");
await fs.cp(
sodiumNativePrebuildPath("x64"),
path.join("build", "prebuilds", `${process.platform}-x64`),
{
recursive: true,
force: true
}
);
}
if (existsSync(sodiumNativePrebuildPath("ia32"))) {
console.log("copying sodium-native-ia32");
await fs.cp(
sodiumNativePrebuildPath("ia32"),
path.join("build", "prebuilds", `${process.platform}-ia32`),
{
recursive: true,
force: true
}
);
}
if (existsSync(sodiumNativePrebuildPath("arm64"))) {
console.log("copying sodium-native-arm64");
await fs.cp(
sodiumNativePrebuildPath("arm64"),
path.join("build", "prebuilds", `${process.platform}-arm64`),
{
recursive: true,
force: true
}
);
}
if (args.run) {
await exec(`npx electron-builder --dir --x64`);
if (process.platform === "win32") {
await exec(`.\\output\\win-unpacked\\Notesnook.exe`);
} else if (process.platform === "darwin") {
await exec(`./output/darwin-unpacked/Notesnook`);
} else {
await exec(`./output/linux-unpacked/Notesnook`);
}
}
async function exec(cmd) {
return childProcess.execSync(cmd, {
env: process.env,
stdio: "inherit"
await fs.cp(path.join("..", "web", "build"), "build", {
recursive: true,
force: true
});
}
if (argv.variant === "mas") {
await $`npm run bundle:mas`;
} else {
await $`npm run bundle`;
}
await $`tsc`;
await $`npm rebuild`;
await fs.cp(
sodiumNativePrebuildPath,
path.join("build", "prebuilds", `${process.platform}-x64`),
{
recursive: true,
force: true
}
);
if (argv.run) {
await $`npm run builder -- --linux AppImage:x64`;
await $`./output/notesnook_linux_x86_64.AppImage`;
}

View File

@@ -1,197 +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 path from "path";
import fs from "fs/promises";
import chokidar from "chokidar";
import { execSync, spawn } from "child_process";
import { fileURLToPath } from "url";
import treekill from "tree-kill";
import crypto from "crypto";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const sodiumNativePrebuildPath = path.join(
`node_modules`,
`@notesnook`,
`crypto`,
`node_modules`,
`@notesnook`,
`sodium`,
`node_modules`,
`sodium-native`,
`prebuilds`
);
const RUNNING_PROCESSES = [];
const RESTARTABLE_PROCESSES = [];
let lastBundleHash = null;
await onChange(true);
console.log("Watching...");
const watcher = chokidar.watch("src/", { ignoreInitial: true });
watcher.on("all", () => {
onChange(false);
});
process.on("SIGINT", async (s) => {
await cleanup();
});
async function onChange(first) {
if (first) {
await fs.rm("./build/", { force: true, recursive: true });
}
await exec(`npm run bundle`);
execAsync(`npx`, [`tsc`]);
if (await isBundleSame()) {
console.log("Bundle is same. Doing nothing.");
return;
}
if (first) {
await fs.cp(sodiumNativePrebuildPath, "build/prebuilds", {
recursive: true,
force: true
});
}
if (first) {
await spawnAndWaitUntil(
["npx", "nx", "start:desktop", "@notesnook/web"],
path.join(__dirname, "..", "..", ".."),
(data) => data.includes("Network: use --host to expose")
);
}
if (!first) {
console.log("Restarting...", RESTARTABLE_PROCESSES.length);
await killProcesses(RESTARTABLE_PROCESSES);
}
execAsync(
"npx",
["electron", path.join("build", "electron.js")],
true,
cleanup
);
}
function spawnAndWaitUntil(cmd, cwd, predicate) {
return new Promise((resolve) => {
console.log(">", ...cmd);
const s = spawn(cmd[0], cmd.slice(1), {
cwd,
env: { ...process.env, NO_COLOR: "true" },
shell: false
});
RUNNING_PROCESSES.push(s);
s.stderr.pipe(process.stderr);
s.stdout.on("data", (data) => {
process.stdout.write(data);
if (predicate(data)) resolve(undefined); //
});
});
}
async function exec(cmd) {
try {
console.log(">", cmd);
return execSync(cmd, {
env: process.env,
stdio: "inherit",
shell: false
});
} catch {
//ignore
}
}
function execAsync(cmd, args, restartable, onExit) {
try {
console.log(">", cmd, ...args);
const proc = spawn(cmd, args, {
stdio: "inherit",
env: process.env,
shell: false
});
const array = restartable ? RESTARTABLE_PROCESSES : RUNNING_PROCESSES;
array.push(proc);
proc.on("exit", (code, signal) => {
console.log(cmd, ...args, "closed with code", code);
if (code === 0 && !signal) {
array.splice(array.indexOf(proc), 1);
onExit && onExit();
}
});
} catch {
//ignore
}
}
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
async function killProcesses(processes) {
for (const process of processes.slice()) {
processes.splice(processes.indexOf(process), 1);
await new Promise((resolve, reject) =>
treekill(process.pid, (err) => (err ? reject(err) : resolve()))
);
}
}
async function cleanup() {
console.log("Cleaning up");
await killProcesses(RESTARTABLE_PROCESSES);
await killProcesses(RUNNING_PROCESSES);
await sleep(1000);
await fs.rm("./build/", { force: true, recursive: true });
process.exit();
}
async function isBundleSame() {
const bundle = await fs.readFile(
path.join(__dirname, "..", "build", "electron.js")
);
const hashSum = crypto.createHash("sha256");
hashSum.update(bundle);
const hex = hashSum.digest("hex");
if (!lastBundleHash) {
lastBundleHash = hex;
return false;
}
if (hex === lastBundleHash) return true;
lastBundleHash = hex;
return false;
}

117
apps/desktop/scripts/dev.ts Normal file
View File

@@ -0,0 +1,117 @@
/*
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 path from "path";
import fs from "fs/promises";
import { watch } from "turbowatch";
import { $, within } from "zx";
const sodiumNativePrebuildPath = path.join(
`node_modules`,
`@notesnook`,
`crypto`,
`node_modules`,
`@notesnook`,
`sodium`,
`node_modules`,
`sodium-native`,
`prebuilds`
);
let isServerRunning = false;
async function main() {
const { shutdown } = await watch({
project: path.join(__dirname, ".."),
cwd: path.join(__dirname, ".."),
triggers: [
{
expression: [
"allof",
["not", ["dirname", "node_modules"]],
["match", "*.ts", "basename"]
],
name: "dev",
// retry: { retries: 0 },
onTeardown: async () => {
await fs.rm("./build/", { force: true, recursive: true });
},
onChange: async ({ spawn: $, first, log }) => {
if (first) {
await fs.rm("./build/", { force: true, recursive: true });
}
await $`npm run build:electron`;
await $`tsc`;
if (first) {
await fs.cp(sodiumNativePrebuildPath, "build/prebuilds", {
recursive: true,
force: true
});
}
if (!isServerRunning) {
await spawnAndWaitUntil(
path.join(__dirname, "..", "..", "web"),
"npm run start:desktop",
(data) => data.includes("Compiled successfully!")
);
isServerRunning = true;
}
log("Starting desktop app!");
await $`npx electron ${path.join("build", "electron.js")}`;
}
}
]
});
// SIGINT is the signal sent when we press Ctrl+C
process.once("SIGINT", () => {
void shutdown();
});
}
main();
function spawnAndWaitUntil(
cwd: string,
cmd: string,
predicate: (data: string) => boolean
) {
return new Promise((resolve) => {
within(async () => {
$.env = process.env;
$.quote = (c) => c;
try {
const s = $`cd ${cwd} && ${cmd}`;
s.stdout.on("data", (data) => {
if (predicate(data)) resolve(undefined); //
});
await s;
} catch (e) {
//ignore
} finally {
isServerRunning = false;
}
});
});
}

View File

@@ -25,10 +25,10 @@ import { config, DesktopIntegration } from "../utils/config";
import { bringToFront } from "../utils/bring-to-front";
import { getTheme, setTheme, Theme } from "../utils/theme";
import { mkdirSync, writeFileSync } from "fs";
import { dirname } from "path";
import { dirname, join } from "path";
import { platform } from "os";
import { resolvePath } from "../utils/resolve-path";
import { observable } from "@trpc/server/observable";
import { AssetManager } from "../utils/asset-manager";
const t = initTRPC.create();
@@ -52,12 +52,12 @@ export const osIntegrationRouter = t.router({
privacyMode: t.procedure.query(() => config.privacyMode),
setPrivacyMode: t.procedure
.input(z.boolean().optional())
.input(z.boolean())
.mutation(({ input: privacyMode }) => {
if (!globalThis.window || !["win32", "darwin"].includes(process.platform))
return;
globalThis.window.setContentProtection(!!privacyMode);
globalThis.window.setContentProtection(privacyMode);
if (process.platform === "win32") {
globalThis.window.setThumbnailClip(
@@ -66,7 +66,7 @@ export const osIntegrationRouter = t.router({
: { x: 0, y: 0, width: 0, height: 0 }
);
}
config.privacyMode = !!privacyMode;
config.privacyMode = privacyMode;
}),
desktopIntegration: t.procedure.query(() => config.desktopSettings),
@@ -74,7 +74,7 @@ export const osIntegrationRouter = t.router({
.input(DesktopIntegration)
.mutation(({ input: settings }) => {
if (settings.autoStart) {
AutoLaunch.enable(!!settings.startMinimized);
AutoLaunch.enable(settings.startMinimized);
} else {
AutoLaunch.disable();
}
@@ -122,10 +122,10 @@ export const osIntegrationRouter = t.router({
.query(({ input }) => {
const notification = new Notification({
...input,
icon: AssetManager.appIcon({
size: 64,
format: process.platform === "win32" ? "ico" : "png"
})
icon: join(
__dirname,
platform() === "win32" ? "app.ico" : "favicon-72x72.png"
)
});
notification.show();
if (input.urgency === "critical") {

View File

@@ -113,10 +113,8 @@ export const spellCheckerRouter = t.router({
.mutation(({ input: languages }) =>
globalThis.window?.webContents.session.setSpellCheckerLanguages(languages)
),
toggle: t.procedure
.input(z.boolean().optional())
.mutation(({ input: enabled }) => {
globalThis.window?.webContents.session.setSpellCheckerEnabled(!!enabled);
config.isSpellCheckerEnabled = !!enabled;
})
toggle: t.procedure.input(z.boolean()).mutation(({ input: enabled }) => {
globalThis.window?.webContents.session.setSpellCheckerEnabled(enabled);
config.isSpellCheckerEnabled = enabled;
})
});

View File

@@ -21,8 +21,6 @@ import { initTRPC } from "@trpc/server";
import { observable } from "@trpc/server/observable";
import { CancellationToken, autoUpdater } from "electron-updater";
import type { AppUpdaterEvents } from "electron-updater/out/AppUpdater";
import { z } from "zod";
import { config } from "../utils/config";
type UpdateInfo = { version: string };
type Progress = { percent: number };
@@ -30,7 +28,6 @@ type Progress = { percent: number };
const t = initTRPC.create();
export const updaterRouter = t.router({
autoUpdates: t.procedure.query(() => config.automaticUpdates),
install: t.procedure.query(() => autoUpdater.quitAndInstall()),
download: t.procedure.query(async () => {
const cancellationToken = new CancellationToken();
@@ -40,13 +37,6 @@ export const updaterRouter = t.router({
await autoUpdater.checkForUpdates();
}),
toggleAutoUpdates: t.procedure
.input(z.boolean().optional())
.mutation(({ input }) => {
config.automaticUpdates =
input === undefined ? !config.automaticUpdates : input;
}),
onChecking: createSubscription("checking-for-update"),
onDownloaded: createSubscription<"update-downloaded", UpdateInfo>(
"update-downloaded"

View File

@@ -16,8 +16,9 @@ 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, RELEASE */
import { app, BrowserWindow, nativeTheme, session, shell } from "electron";
import { app, BrowserWindow, nativeTheme, shell } from "electron";
import { isDevelopment } from "./utils";
import { registerProtocol, PROTOCOL_URL } from "./utils/protocol";
import { configureAutoUpdater } from "./utils/autoupdater";
@@ -32,17 +33,13 @@ import { AssetManager } from "./utils/asset-manager";
import { createIPCHandler } from "electron-trpc/main";
import { router, api } from "./api";
import { config } from "./utils/config";
import path from "path";
if (process.platform == "win32" && process.env.PORTABLE_EXECUTABLE_DIR) {
console.log("Portable app: true");
const root = path.join(process.env.PORTABLE_EXECUTABLE_DIR, "Notesnook");
app.setPath("appData", path.join(root, "AppData"));
app.setPath("documents", path.join(root, "Documents"));
app.setPath("userData", path.join(root, "UserData"));
if (!RELEASE) {
require("electron-reloader")(module);
}
// only run a single instance
if (!MAC_APP_STORE && !app.requestSingleInstanceLock()) {
app.exit();
}
@@ -51,22 +48,22 @@ if (process.platform === "win32") {
app.setAppUserModelId(app.name);
}
app.commandLine.appendSwitch("lang", "en-US");
async function createWindow() {
await AssetManager.loadIcons();
const cliOptions = await parseArguments();
setTheme(getTheme());
const mainWindowState = new WindowState({});
setTheme(getTheme());
const mainWindow = new BrowserWindow({
show: !cliOptions.hidden,
show: false,
x: mainWindowState.x,
y: mainWindowState.y,
width: mainWindowState.width,
height: mainWindowState.height,
darkTheme: getTheme() === "dark",
backgroundColor: getBackgroundColor(),
opacity: 0,
autoHideMenuBar: true,
icon: AssetManager.appIcon({
size: 512,
@@ -74,44 +71,44 @@ async function createWindow() {
}),
webPreferences: {
zoomFactor: config.zoomFactor,
nodeIntegration: true,
devTools: true, // isDev,
nodeIntegration: true, //true,
contextIsolation: false,
spellcheck: config.isSpellCheckerEnabled,
preload: __dirname + "/preload.js"
}
});
globalThis.window = mainWindow;
mainWindow.on("show", async () => {
if (config.privacyMode) {
await api.integration.setPrivacyMode(config.privacyMode);
}
});
mainWindowState.manage(mainWindow);
if (cliOptions.hidden && !config.desktopSettings.minimizeToSystemTray)
mainWindow.minimize();
await mainWindow.webContents.loadURL(`${createURL(cliOptions, "/")}`);
mainWindow.setOpacity(1);
if (config.privacyMode) {
await api.integration.setPrivacyMode(config.privacyMode);
}
await AssetManager.loadIcons();
setupDesktopIntegration();
globalThis.window = mainWindow;
setupMenu();
setupJumplist();
setupDesktopIntegration(cliOptions.hidden);
createIPCHandler({ router, windows: [mainWindow] });
mainWindow.webContents.session.setSpellCheckerDictionaryDownloadURL(
"http://dictionaries.notesnook.com/"
);
mainWindow.once("closed", () => {
globalThis.window = null;
});
setupMenu();
setupJumplist();
if (isDevelopment())
mainWindow.webContents.openDevTools({ mode: "right", activate: true });
try {
await mainWindow.loadURL(`${createURL(cliOptions)}`);
} catch (e) {
if (e instanceof Error) console.error(e);
}
mainWindow.on("closed", () => {
globalThis.window = null;
});
mainWindow.webContents.setWindowOpenHandler((details) => {
shell.openExternal(details.url);
return { action: "deny" };
@@ -123,7 +120,8 @@ async function createWindow() {
});
}
app.once("ready", async () => {
app.commandLine.appendSwitch("lang", "en-US");
app.on("ready", async () => {
console.info("App ready. Opening window.");
if (!isDevelopment()) registerProtocol();
@@ -131,7 +129,7 @@ app.once("ready", async () => {
configureAutoUpdater();
});
app.once("window-all-closed", () => {
app.on("window-all-closed", () => {
if (process.platform !== "darwin" || MAC_APP_STORE) {
app.quit();
}
@@ -143,10 +141,9 @@ app.on("activate", () => {
}
});
function createURL(options: CLIOptions, path = "/") {
function createURL(options: CLIOptions) {
const url = new URL(isDevelopment() ? "http://localhost:3000" : PROTOCOL_URL);
url.pathname = path;
if (options.note === true) url.hash = "/notes/create/1";
else if (options.notebook === true) url.hash = "/notebooks/create";
else if (options.reminder === true) url.hash = "/reminders/create";
@@ -158,7 +155,7 @@ function createURL(options: CLIOptions, path = "/") {
return url;
}
function setupDesktopIntegration() {
function setupDesktopIntegration(hidden: boolean) {
const desktopIntegration = config.desktopSettings;
if (
@@ -168,13 +165,24 @@ function setupDesktopIntegration() {
setupTray();
}
globalThis.window?.on("ready-to-show", () => {
if (!hidden) {
globalThis.window?.show();
}
if (hidden && !desktopIntegration.minimizeToSystemTray) {
globalThis.window?.show();
globalThis.window?.minimize();
}
});
// when close to system tray is enabled, it becomes nigh impossible
// to "quit" the app. This is necessary in order to fix that.
if (desktopIntegration.closeToSystemTray) {
app.on("before-quit", () => app.exit(0));
}
globalThis.window?.once("close", (e) => {
globalThis.window?.on("close", (e) => {
if (config.desktopSettings.closeToSystemTray) {
e.preventDefault();
if (process.platform == "darwin") {
@@ -200,6 +208,6 @@ function setupDesktopIntegration() {
});
if (desktopIntegration.autoStart) {
AutoLaunch.enable(!!desktopIntegration.startMinimized);
AutoLaunch.enable(desktopIntegration.startMinimized);
}
}

View File

@@ -20,16 +20,15 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import { ELECTRON_TRPC_CHANNEL } from "electron-trpc/main";
import { type RendererGlobalElectronTRPC } from "electron-trpc/src/types";
import type { NNCrypto } from "@notesnook/crypto";
import { NNCrypto } from "@notesnook/crypto";
import { ipcRenderer } from "electron";
import { platform } from "os";
declare global {
var os: () => "mas" | ReturnType<typeof platform>;
var os: string;
var electronTRPC: RendererGlobalElectronTRPC;
var NativeNNCrypto: (new () => NNCrypto) | undefined;
var NativeNNCrypto: new () => NNCrypto;
}
console.log("HELLO", process);
process.once("loaded", async () => {
console.log("HELLO!");
const electronTRPC: RendererGlobalElectronTRPC = {
@@ -41,11 +40,5 @@ process.once("loaded", async () => {
globalThis.electronTRPC = electronTRPC;
});
globalThis.NativeNNCrypto =
process.platform === "win32" &&
process.arch !== "x64" &&
process.arch !== "ia32"
? undefined
: require("@notesnook/crypto").NNCrypto;
globalThis.os = () => (MAC_APP_STORE ? "mas" : platform());
globalThis.NativeNNCrypto = NNCrypto;
globalThis.os = MAC_APP_STORE ? "mas" : process.platform;

View File

@@ -21,8 +21,8 @@ import { NativeImage, nativeImage } from "electron";
import path from "path";
import { isDevelopment } from "./index";
import { parse, ParsedImage } from "icojs";
import { readFileSync } from "fs";
import { getSystemTheme } from "./theme";
import { readFile } from "fs/promises";
type Formats = "ico" | "png" | "icns";
type IconOptions<TFormat extends Formats> = {
@@ -70,7 +70,7 @@ export class AssetManager {
"icons",
`${icon}${prefix}.ico`
);
const icoBuffer = await readFile(icoPath);
const icoBuffer = readFileSync(icoPath);
const images = await parse(icoBuffer, "image/png");
ALL_ICONS.push({ id: icon, images, prefix });
}
@@ -80,10 +80,10 @@ export class AssetManager {
static appIcon(options: IconOptions<Formats>) {
const { size = 32, format = "png" } = options;
if (format === "ico") return "assets\\icons\\app.ico";
if (format === "icns") return "assets/icons/app.icns";
if (format === "ico") return path.join("assets", "icons", "app.ico");
if (format === "icns") return path.join("assets", "icons", "app.icns");
return `assets/icons/${size}x${size}.png`;
return path.join("assets", "icons", `${size}x${size}.png`);
}
static icon<TFormat extends Formats>(

View File

@@ -18,7 +18,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { autoUpdater } from "electron-updater";
import { config } from "./config";
async function configureAutoUpdater() {
autoUpdater.setFeedURL({
@@ -27,7 +26,7 @@ async function configureAutoUpdater() {
useMultipleRangeRequest: false
});
autoUpdater.autoDownload = config.automaticUpdates;
autoUpdater.autoDownload = false;
autoUpdater.allowDowngrade = false;
autoUpdater.allowPrerelease = false;
autoUpdater.autoInstallOnAppQuit = true;

View File

@@ -22,10 +22,10 @@ import { JSONStorage } from "./json-storage";
import { z } from "zod";
export const DesktopIntegration = z.object({
autoStart: z.boolean().optional(),
startMinimized: z.boolean().optional(),
minimizeToSystemTray: z.boolean().optional(),
closeToSystemTray: z.boolean().optional()
autoStart: z.boolean(),
startMinimized: z.boolean(),
minimizeToSystemTray: z.boolean(),
closeToSystemTray: z.boolean()
});
export type DesktopIntegration = z.infer<typeof DesktopIntegration>;
@@ -40,8 +40,7 @@ export const config = {
privacyMode: false,
isSpellCheckerEnabled: false,
zoomFactor: 0,
theme: nativeTheme.themeSource,
automaticUpdates: true
theme: nativeTheme.themeSource
};
type ConfigKey = keyof typeof config;

View File

@@ -18,8 +18,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { app } from "electron";
import { join } from "path";
import { existsSync } from "fs";
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

View File

@@ -101,26 +101,6 @@ function setupMenu() {
})
);
if (params.linkURL?.length) {
menu.append(
new MenuItem({
label: "Copy link",
click() {
clipboard.writeText(params.linkURL);
}
})
);
menu.append(
new MenuItem({
label: "Copy link text",
click() {
clipboard.writeText(params.linkText);
}
})
);
}
if (params.selectionText.length) {
menu.append(
new MenuItem({

View File

@@ -19,10 +19,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import { protocol, ProtocolRequest } from "electron";
import { isDevelopment } from "./index";
import { createReadStream } from "fs";
import { extname, normalize } from "path";
import { createReadStream, statSync } from "fs";
import { extname, join, normalize } from "path";
import { URL } from "url";
import fetch, { Response } from "node-fetch";
import { Readable } from "stream";
const BASE_PATH = isDevelopment() ? "../public" : "";
const HOSTNAME = `app.notesnook.com`;
@@ -46,13 +46,14 @@ function registerProtocol() {
console.info("Intercepting request:", request.url);
const loadIndex = !extname(url.pathname);
const filePath = normalize(
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);
callback({ error: FILE_NOT_FOUND });
@@ -87,7 +88,7 @@ function registerProtocol() {
}
callback({
statusCode: response.status,
data: response.body || undefined,
data: response.body ? Readable.fromWeb(response.body) : undefined,
headers: Object.fromEntries(response.headers.entries()),
mimeType: response.headers.get("Content-Type") || undefined
});
@@ -155,6 +156,21 @@ async function getBody(request: ProtocolRequest) {
}
}
const blob = new Blob(blobParts);
return blob;
return await blob.arrayBuffer();
}
function getPath(filePath: string): string | undefined {
try {
const result = statSync(filePath);
if (result.isFile()) {
return filePath;
}
if (result.isDirectory()) {
return getPath(join(filePath, "index.html"));
}
} catch (_) {
// ignore
}
}

View File

@@ -17,6 +17,15 @@ jobs:
with:
persist-credentials: false
- name: Setup npmrc
run: |
echo "registry=https://npm.pkg.github.com" > .npmrc
echo "@streetwriters:registry=https://npm.pkg.github.com" >> .npmrc
echo "//npm.pkg.github.com/:_authToken=${{secrets.PACKAGES_TOKEN}}" >> .npmrc
- name: Setup yarnrc
run: echo "\"@streetwriters:registry\" \"https://npm.pkg.github.com\"" > .yarnrc
- uses: actions/setup-node@master
with:
node-version: "16"

View File

@@ -17,6 +17,15 @@ jobs:
with:
persist-credentials: false
- name: Setup npmrc
run: |
echo "registry=https://npm.pkg.github.com" > .npmrc
echo "@streetwriters:registry=https://npm.pkg.github.com" >> .npmrc
echo "//npm.pkg.github.com/:_authToken=${{secrets.PACKAGES_TOKEN}}" >> .npmrc
- name: Setup yarnrc
run: echo "\"@streetwriters:registry\" \"https://npm.pkg.github.com\"" > .yarnrc
- uses: actions/setup-node@master
with:
node-version: "16"

View File

@@ -5,6 +5,7 @@ artifacts/
.DS_Store
native/android/app/src/main/assets/
*Issues.md
build_cache/
#
@@ -13,9 +14,7 @@ build_cache/
.yarnrc.yml
.yarn
*.log
.cxx/
*.keystore
!debug.keystore
# Xcode
#

View File

@@ -25,4 +25,4 @@
"request": "attach"
}
]
}
}

View File

@@ -3,7 +3,6 @@
*/
import "react-native";
import { it } from "@jest/globals";
// Note: test renderer must be required after react-native.
import renderer from "react-test-renderer";
import Heading from "../app/components/ui/typography/heading";

View File

@@ -16,37 +16,34 @@ 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 {
THEME_COMPATIBILITY_VERSION,
useThemeEngineStore
} from "@notesnook/theme";
import React, { useEffect } from "react";
import { View } from "react-native";
import "react-native-gesture-handler";
import React, { useEffect } from "react";
import { GestureHandlerRootView } from "react-native-gesture-handler";
import { SafeAreaProvider } from "react-native-safe-area-context";
import AppLockedOverlay from "./components/app-lock-overlay";
import { withErrorBoundry } from "./components/exception-handler";
import GlobalSafeAreaProvider from "./components/globalsafearea";
import Launcher from "./components/launcher";
import { useAppEvents } from "./hooks/use-app-events";
import { ApplicationHolder } from "./navigation";
import Notifications from "./services/notifications";
import SettingsService from "./services/settings";
import { TipManager } from "./services/tip-manager";
import { useThemeStore } from "./stores/use-theme-store";
import { useUserStore } from "./stores/use-user-store";
import { themeTrpcClient } from "./screens/settings/theme-selector";
import { View } from "react-native";
import { useState } from "react";
SettingsService.init();
SettingsService.checkOrientation();
const App = () => {
const init = useAppEvents();
useAppEvents();
const [init, setInit] = useState(false);
useEffect(() => {
let { appLockMode } = SettingsService.get();
if (appLockMode && appLockMode !== "none") {
useUserStore.getState().lockApp(true);
useUserStore.getState().setVerifyUser(true);
}
init();
//BackgroundSync.start();
setInit(true);
setTimeout(async () => {
SettingsService.onFirstLaunch();
await Notifications.get();
@@ -55,10 +52,7 @@ const App = () => {
}
TipManager.init();
}, 100);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return (
<View
style={{
@@ -87,49 +81,10 @@ const App = () => {
}}
>
<ApplicationHolder />
{init && <Launcher />}
</GestureHandlerRootView>
<AppLockedOverlay />
</View>
);
};
export const withTheme = (Element) => {
return function AppWithThemeProvider() {
const [colorScheme, darkTheme, lightTheme] = useThemeStore((state) => [
state.colorScheme,
state.darkTheme,
state.lightTheme
]);
useEffect(() => {
const currentTheme = colorScheme === "dark" ? darkTheme : lightTheme;
if (!currentTheme) return;
themeTrpcClient.updateTheme
.query({
version: currentTheme.version,
compatibilityVersion: THEME_COMPATIBILITY_VERSION,
id: currentTheme.id
})
.then((theme) => {
if (theme) {
console.log(theme.version, "theme updated");
theme.colorScheme === "dark"
? useThemeStore.getState().setDarkTheme(theme)
: useThemeStore.getState().setLightTheme(theme);
}
})
.catch(console.log);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
useEffect(() => {
useThemeEngineStore
.getState()
.setTheme(colorScheme === "dark" ? darkTheme : lightTheme);
}, [colorScheme, darkTheme, lightTheme]);
return <Element />;
};
};
export default withTheme(withErrorBoundry(App, "App"));
export default withErrorBoundry(App, "App");

View File

@@ -16,7 +16,8 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { database } from "@notesnook/common";
import Database from "@notesnook/core/api/index";
import { initalize, logger as dbLogger } from "@notesnook/core/logger";
import { Platform } from "react-native";
import { MMKVLoader } from "react-native-mmkv-storage";
@@ -29,8 +30,23 @@ import * as Gzip from "react-native-gzip";
const LoggerStorage = new MMKVLoader()
.withInstanceID("notesnook_logs")
.initialize();
initalize(new KV(LoggerStorage), true);
export const DatabaseLogger = dbLogger;
database.host(
/**
* @type {import("@notesnook/core/api/index").default}
*/
export var db = new Database(
Storage,
Platform.OS === "ios" ? EventSource : AndroidEventSource,
filesystem,
{
compress: Gzip.deflate,
decompress: Gzip.inflate
}
);
db.host(
__DEV__
? {
API_HOST: "https://api.notesnook.com",
@@ -52,18 +68,3 @@ database.host(
ISSUES_HOST: "https://issues.streetwriters.co"
}
);
database.setup(
Storage,
Platform.OS === "ios" ? EventSource : AndroidEventSource,
filesystem,
{
compress: Gzip.deflate,
decompress: Gzip.inflate
}
);
initalize(new KV(LoggerStorage), true);
export const db = database;
export const DatabaseLogger = dbLogger;

View File

@@ -46,7 +46,6 @@ export async function downloadFile(filename, data, cancelToken) {
if (!downloadUrl) throw new Error("Unable to resolve download url");
let totalSize = 0;
console.log("Download starting");
let request = RNFetchBlob.config({
path: path,
IOSBackgroundTask: true

View File

@@ -19,7 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import RNFetchBlob from "react-native-blob-util";
import { useAttachmentStore } from "../../stores/use-attachment-store";
import { DatabaseLogger, db } from "../database";
import { db } from "../database";
import { cacheDir } from "./utils";
import { isImage, isDocument } from "@notesnook/core/utils/filename";
import { Platform } from "react-native";
@@ -29,8 +29,7 @@ export async function uploadFile(filename, data, cancelToken) {
if (!data) return false;
let { url, headers } = data;
DatabaseLogger.info(`Preparing to upload file: ${filename}`);
console.log("uploading file: ", filename, headers);
try {
let res = await fetch(url, {
method: "PUT",
@@ -38,7 +37,7 @@ export async function uploadFile(filename, data, cancelToken) {
});
if (!res.ok) throw new Error(`${res.status}: Unable to resolve upload url`);
const uploadUrl = await res.text();
if (!uploadUrl) throw new Error("Unable to resolve attachment upload url");
if (!uploadUrl) throw new Error("Unable to resolve upload url");
let uploadFilePath = `${cacheDir}/${filename}`;
const iosAppGroup =
@@ -50,8 +49,6 @@ export async function uploadFile(filename, data, cancelToken) {
if (!exists && Platform.OS === "ios") {
uploadFilePath = appGroupPath;
}
DatabaseLogger.info(`Starting upload: ${filename}`);
let request = RNFetchBlob.config({
IOSBackgroundTask: !globalThis["IS_SHARE_EXTENSION"]
})
@@ -67,11 +64,8 @@ export async function uploadFile(filename, data, cancelToken) {
useAttachmentStore
.getState()
.setProgress(sent, total, filename, 0, "upload");
DatabaseLogger.info(
`File upload progress: ${filename}, ${sent}/${total}`
);
console.log("uploading: ", sent, total);
});
cancelToken.cancel = request.cancel;
let response = await request;
@@ -80,9 +74,6 @@ export async function uploadFile(filename, data, cancelToken) {
let result = status >= 200 && status < 300 && text.length === 0;
useAttachmentStore.getState().remove(filename);
if (result) {
DatabaseLogger.info(
`File upload status: ${filename}, ${status}, ${text}`
);
let attachment = db.attachments.attachment(filename);
if (!attachment) return result;
if (
@@ -91,20 +82,12 @@ export async function uploadFile(filename, data, cancelToken) {
) {
RNFetchBlob.fs.unlink(`${cacheDir}/${filename}`).catch(console.log);
}
} else {
const fileInfo = await RNFetchBlob.fs.stat(uploadFilePath);
throw new Error(
`${status}, ${text}, name: ${fileInfo.filename}, length: ${
fileInfo.size
}, info: ${JSON.stringify(response.info())}`
);
}
return result;
} catch (e) {
useAttachmentStore.getState().remove(filename);
DatabaseLogger.info(`File upload error: ${filename}, ${e}`);
DatabaseLogger.error(e);
console.log("upload file: ", e, url, headers);
return false;
}
}

View File

@@ -21,18 +21,18 @@ import React from "react";
import { FlatList, View } from "react-native";
import { useSelectionStore } from "../../stores/use-selection-store";
import { useMessageStore } from "../../stores/use-message-store";
import { useThemeColors } from "@notesnook/theme";
import { useThemeStore } from "../../stores/use-theme-store";
import { allowedOnPlatform, renderItem } from "./functions";
export const Announcement = ({ color }) => {
const { colors } = useThemeColors();
const colors = useThemeStore((state) => state.colors);
const announcements = useMessageStore((state) => state.announcements);
let announcement = announcements.length > 0 ? announcements[0] : null;
const selectionMode = useSelectionStore((state) => state.selectionMode);
return !announcement || selectionMode ? null : (
<View
style={{
backgroundColor: colors.primary.background,
backgroundColor: colors.bg,
width: "100%",
paddingHorizontal: 12,
paddingTop: 12,
@@ -44,26 +44,28 @@ export const Announcement = ({ color }) => {
width: "100%",
borderRadius: 10,
overflow: "hidden",
backgroundColor: colors.secondary.background,
backgroundColor: colors.nav,
paddingBottom: 12
}}
>
<View
style={{
width: "100%",
marginTop: 12
}}
>
{announcement?.body
.filter((item) => allowedOnPlatform(item.platforms))
.map((item, index) =>
<View>
<FlatList
style={{
width: "100%",
marginTop: 12
}}
data={announcement?.body.filter((item) =>
allowedOnPlatform(item.platforms)
)}
renderItem={({ item, index }) =>
renderItem({
item: item,
index: index,
color: colors[color],
inline: true
})
)}
}
/>
</View>
</View>
</View>

View File

@@ -22,7 +22,7 @@ import { Linking, View } from "react-native";
//import SettingsBackupAndRestore from '../../screens/settings/backup-restore';
import { eSendEvent, presentSheet } from "../../services/event-manager";
import Sync from "../../services/sync";
import { useThemeColors } from "@notesnook/theme";
import { useThemeStore } from "../../stores/use-theme-store";
import { eCloseAnnouncementDialog, eCloseSheet } from "../../utils/events";
import { SIZE } from "../../utils/size";
import { sleep } from "../../utils/time";
@@ -33,7 +33,7 @@ import { Button } from "../ui/button";
import { allowedOnPlatform, getStyle } from "./functions";
export const Cta = ({ actions, style = {}, color, inline }) => {
const { colors } = useThemeColors();
const colors = useThemeStore((state) => state.colors);
let buttons =
actions.filter((item) => allowedOnPlatform(item.platforms)) || [];
@@ -92,7 +92,8 @@ export const Cta = ({ actions, style = {}, color, inline }) => {
style={{
height: 30,
alignSelf: "flex-start",
paddingHorizontal: 0
paddingHorizontal: 0,
marginTop: -6
}}
/>
))}
@@ -110,6 +111,7 @@ export const Cta = ({ actions, style = {}, color, inline }) => {
style={{
alignSelf: "flex-start",
paddingHorizontal: 0,
marginTop: -6,
marginLeft: 12
}}
textStyle={{
@@ -127,9 +129,9 @@ export const Cta = ({ actions, style = {}, color, inline }) => {
title={item.title}
fontSize={SIZE.md}
buttonType={{
color: color ? color : colors.primary.accent,
text: colors.static.white,
selected: color ? color : colors.primary.accent,
color: color ? color : colors.accent,
text: colors.light,
selected: color ? color : colors.accent,
opacity: 1
}}
onPress={() => onPress(item)}

View File

@@ -25,7 +25,7 @@ import {
eUnSubscribeEvent
} from "../../services/event-manager";
import { useMessageStore } from "../../stores/use-message-store";
import { useThemeColors } from "@notesnook/theme";
import { useThemeStore } from "../../stores/use-theme-store";
import {
eCloseAnnouncementDialog,
eOpenAnnouncementDialog
@@ -35,7 +35,7 @@ import { allowedOnPlatform, renderItem } from "./functions";
import { useCallback } from "react";
export const AnnouncementDialog = () => {
const { colors } = useThemeColors();
const colors = useThemeStore((state) => state.colors);
const [visible, setVisible] = useState(false);
const [info, setInfo] = useState(null);
const remove = useMessageStore((state) => state.remove);
@@ -73,7 +73,7 @@ export const AnnouncementDialog = () => {
<View
style={{
width: DDS.isTab ? 600 : "100%",
backgroundColor: colors.primary.background,
backgroundColor: colors.bg,
maxHeight: DDS.isTab ? "90%" : "100%",
borderRadius: DDS.isTab ? 10 : 0,
overflow: "hidden",

View File

@@ -1,215 +0,0 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React, { useCallback, useEffect, useRef } from "react";
import { Platform, View } from "react-native";
import { enabled } from "react-native-privacy-snapshot";
import { db } from "../../common/database";
import { useAppState } from "../../hooks/use-app-state";
import BiometricService from "../../services/biometrics";
import { useSettingStore } from "../../stores/use-setting-store";
import { useThemeColors } from "@notesnook/theme";
import { useUserStore } from "../../stores/use-user-store";
import { NotesnookModule } from "../../utils/notesnook-module";
import { SIZE } from "../../utils/size";
import { Button } from "../ui/button";
import { IconButton } from "../ui/icon-button";
import Input from "../ui/input";
import Seperator from "../ui/seperator";
import Heading from "../ui/typography/heading";
import Paragraph from "../ui/typography/paragraph";
const AppLockedOverlay = () => {
const { colors } = useThemeColors();
const user = useUserStore((state) => state.user);
const appLocked = useUserStore((state) => state.appLocked);
const lockApp = useUserStore((state) => state.lockApp);
const deviceMode = useSettingStore((state) => state.deviceMode);
const passwordInputRef = useRef();
const password = useRef();
const appState = useAppState();
const biometricUnlockAwaitingUserInput = useRef(false);
const onUnlockAppRequested = useCallback(async () => {
if (!(await BiometricService.isBiometryAvailable())) return;
if (Platform.OS === "android") {
const activityName = await NotesnookModule.getActivityName();
if (activityName !== "MainActivity") return;
}
useSettingStore.getState().setRequestBiometrics(true);
let unlocked = await BiometricService.validateUser(
"Unlock to access your notes",
""
);
if (unlocked) {
lockApp(false);
enabled(false);
password.current = null;
}
setTimeout(() => {
biometricUnlockAwaitingUserInput.current = false;
useSettingStore.getState().setRequestBiometrics(false);
}, 1);
}, [lockApp]);
const onSubmit = async () => {
if (!password.current) return;
try {
let unlocked = await db.user.verifyPassword(password.current);
if (unlocked) {
lockApp(false);
enabled(false);
password.current = null;
}
} catch (e) {
console.error(e);
}
};
useEffect(() => {
if (
biometricUnlockAwaitingUserInput.current ||
useUserStore.getState().disableAppLockRequests
)
return;
if (appLocked && appState === "active") {
biometricUnlockAwaitingUserInput.current = true;
onUnlockAppRequested();
}
}, [appState, onUnlockAppRequested, appLocked]);
return (
appLocked && (
<View
style={{
backgroundColor: colors.bg,
width: "100%",
height: "100%",
position: "absolute",
zIndex: 999,
justifyContent: "center"
}}
>
<View
style={{
flex: 1,
justifyContent: "center",
width:
deviceMode !== "mobile"
? "50%"
: Platform.OS == "ios"
? "95%"
: "100%",
paddingHorizontal: 12,
marginBottom: 30,
marginTop: 15,
alignSelf: "center"
}}
>
<IconButton
name="fingerprint"
size={100}
customStyle={{
width: 100,
height: 100,
marginBottom: 20,
marginTop: user ? 0 : 50
}}
onPress={onUnlockAppRequested}
color={colors.primary.border}
/>
<Heading
color={colors.primary.heading}
style={{
alignSelf: "center",
textAlign: "center"
}}
>
Unlock your notes
</Heading>
<Paragraph
style={{
alignSelf: "center",
textAlign: "center",
maxWidth: "90%"
}}
>
{"Please verify it's you"}
</Paragraph>
<Seperator />
<View
style={{
width: "100%",
padding: 12,
backgroundColor: colors.bg
}}
>
{user ? (
<>
<Input
fwdRef={passwordInputRef}
secureTextEntry
placeholder="Enter account password"
onChangeText={(v) => (password.current = v)}
onSubmit={onSubmit}
/>
</>
) : null}
<View
style={{
marginTop: user ? 25 : 25
}}
>
{user ? (
<>
<Button
title="Continue"
type="accent"
onPress={onSubmit}
width={250}
height={45}
style={{
borderRadius: 150,
marginBottom: 10
}}
fontSize={SIZE.md}
/>
</>
) : null}
<Button
title="Unlock with Biometrics"
width={250}
onPress={onUnlockAppRequested}
icon={"fingerprint"}
type="transparent"
/>
</View>
</View>
</View>
</View>
)
);
};
export default AppLockedOverlay;

View File

@@ -33,7 +33,8 @@ import {
} from "../../services/event-manager";
import PremiumService from "../../services/premium";
import { useAttachmentStore } from "../../stores/use-attachment-store";
import { useThemeColors } from "@notesnook/theme";
import { useThemeStore } from "../../stores/use-theme-store";
import { formatBytes } from "../../utils";
import { eCloseAttachmentDialog, eCloseSheet } from "../../utils/events";
import { SIZE } from "../../utils/size";
import { sleep } from "../../utils/time";
@@ -46,10 +47,9 @@ import { Notice } from "../ui/notice";
import { PressableButton } from "../ui/pressable";
import Heading from "../ui/typography/heading";
import Paragraph from "../ui/typography/paragraph";
import { formatBytes } from "@notesnook/common";
const Actions = ({ attachment, setAttachments, fwdRef }) => {
const { colors } = useThemeColors();
const colors = useThemeStore((state) => state.colors);
const contextId = attachment.metadata.hash;
const [filename, setFilename] = useState(attachment.metadata.filename);
const [currentProgress] = useAttachmentProgress(attachment);
@@ -194,7 +194,7 @@ const Actions = ({ attachment, setAttachments, fwdRef }) => {
<View
style={{
borderBottomWidth: 1,
borderBottomColor: colors.secondary.background,
borderBottomColor: colors.nav,
marginBottom: notes && notes.length > 0 ? 0 : 12
}}
>
@@ -219,7 +219,7 @@ const Actions = ({ attachment, setAttachments, fwdRef }) => {
style={{
marginRight: 10
}}
color={colors.secondary.paragraph}
color={colors.icon}
>
{attachment.metadata.type}
</Paragraph>
@@ -228,7 +228,7 @@ const Actions = ({ attachment, setAttachments, fwdRef }) => {
marginRight: 10
}}
size={SIZE.xs}
color={colors.secondary.paragraph}
color={colors.icon}
>
{formatBytes(attachment.length)}
</Paragraph>
@@ -239,7 +239,7 @@ const Actions = ({ attachment, setAttachments, fwdRef }) => {
marginRight: 10
}}
size={SIZE.xs}
color={colors.secondary.paragraph}
color={colors.icon}
>
{attachment.noteIds.length} note
{attachment.noteIds.length > 1 ? "s" : ""}
@@ -255,7 +255,7 @@ const Actions = ({ attachment, setAttachments, fwdRef }) => {
});
}}
size={SIZE.xs}
color={colors.secondary.paragraph}
color={colors.icon}
>
{attachment.metadata.hash}
</Paragraph>
@@ -268,7 +268,7 @@ const Actions = ({ attachment, setAttachments, fwdRef }) => {
<View
style={{
borderBottomWidth: 1,
borderBottomColor: colors.secondary.background,
borderBottomColor: colors.nav,
marginBottom: 12,
paddingVertical: 12
}}
@@ -322,10 +322,10 @@ const Actions = ({ attachment, setAttachments, fwdRef }) => {
key={item.name}
buttonType={{
text: item.on
? colors.primary.accent
? colors.accent
: item.name === "Delete" || item.name === "PermDelete"
? colors.error.paragraph
: colors.primary.paragraph
? colors.errorText
: colors.pri
}}
onPress={item.onPress}
title={item.name}

View File

@@ -17,14 +17,15 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { formatBytes } from "@notesnook/common";
import React from "react";
import { TouchableOpacity, View } from "react-native";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { db } from "../../common/database";
import { useAttachmentProgress } from "../../hooks/use-attachment-progress";
import { useThemeColors } from "@notesnook/theme";
import { useThemeStore } from "../../stores/use-theme-store";
import { formatBytes } from "../../utils";
import { SIZE } from "../../utils/size";
import SheetProvider from "../sheet-provider";
import { IconButton } from "../ui/icon-button";
import { ProgressCircleComponent } from "../ui/svg/lazy";
import Paragraph from "../ui/typography/paragraph";
@@ -40,17 +41,17 @@ export const AttachmentItem = ({
encryption,
setAttachments,
pressable = true,
hideWhenNotDownloading,
context
hideWhenNotDownloading
}) => {
const { colors } = useThemeColors();
const colors = useThemeStore((state) => state.colors);
const [currentProgress, setCurrentProgress] = useAttachmentProgress(
attachment,
encryption
);
const onPress = () => {
if (!pressable) return;
Actions.present(attachment, setAttachments, context);
Actions.present(attachment, setAttachments, attachment.metadata.hash);
};
return hideWhenNotDownloading &&
@@ -65,10 +66,11 @@ export const AttachmentItem = ({
padding: 12,
paddingVertical: 6,
borderRadius: 5,
backgroundColor: colors.secondary.background
backgroundColor: colors.nav
}}
type="grayBg"
>
<SheetProvider context={attachment.metadata.hash} />
<View
style={{
flexShrink: 1,
@@ -83,12 +85,12 @@ export const AttachmentItem = ({
marginLeft: -5
}}
>
<Icon name="file" size={SIZE.xxxl} color={colors.primary.icon} />
<Icon name="file" size={SIZE.xxxl} color={colors.icon} />
<Paragraph
adjustsFontSizeToFit
size={6}
color={colors.static.white}
color={colors.light}
style={{
position: "absolute"
}}
@@ -111,13 +113,13 @@ export const AttachmentItem = ({
}}
numberOfLines={1}
lineBreakMode="middle"
color={colors.primary.paragraph}
color={colors.pri}
>
{attachment.metadata.filename}
</Paragraph>
{!hideWhenNotDownloading ? (
<Paragraph color={colors.secondary.paragraph} size={SIZE.xs}>
<Paragraph color={colors.icon} size={SIZE.xs}>
{formatBytes(attachment.length)}{" "}
{currentProgress?.type
? "(" + currentProgress.type + "ing - tap to cancel)"
@@ -149,7 +151,7 @@ export const AttachmentItem = ({
textStyle={{
fontSize: 10
}}
color={colors.primary.accent}
color={colors.accent}
formatText={(progress) => (progress * 100).toFixed(0)}
borderWidth={0}
thickness={2}
@@ -161,7 +163,7 @@ export const AttachmentItem = ({
<IconButton
onPress={onPress}
name="alert-circle-outline"
color={colors.error.paragraph}
color={colors.errorText}
/>
) : null}
</>

View File

@@ -26,12 +26,12 @@ import { Button } from "../ui/button";
import Heading from "../ui/typography/heading";
import Paragraph from "../ui/typography/paragraph";
import { ProgressBarComponent } from "../ui/svg/lazy";
import { useThemeColors } from "@notesnook/theme";
import { useThemeStore } from "../../stores/use-theme-store";
import { FlatList } from "react-native-actions-sheet";
import { AttachmentItem } from "./attachment-item";
const DownloadAttachments = ({ close, attachments, isNote, update }) => {
const { colors } = useThemeColors();
const colors = useThemeStore((state) => state.colors);
const [downloading, setDownloading] = useState(false);
const [progress, setProgress] = useState({
value: 0,
@@ -158,8 +158,8 @@ const DownloadAttachments = ({ close, attachments, isNote, update }) => {
animated={true}
useNativeDriver
progress={progress.value ? progress.value / attachments.length : 0}
unfilledColor={colors.secondary.background}
color={colors.primary.accent}
unfilledColor={colors.nav}
color={colors.accent}
borderWidth={0}
/>
</View>
@@ -170,7 +170,7 @@ const DownloadAttachments = ({ close, attachments, isNote, update }) => {
maxHeight: 300,
width: "100%",
minHeight: 60,
backgroundColor: colors.secondary.background,
backgroundColor: colors.nav,
borderRadius: 5,
marginVertical: 12
}}
@@ -184,9 +184,7 @@ const DownloadAttachments = ({ close, attachments, isNote, update }) => {
height: 60
}}
>
<Paragraph color={colors.secondary.paragraph}>
No downloads in progress.
</Paragraph>
<Paragraph color={colors.icon}>No downloads in progress.</Paragraph>
</View>
}
keyExtractor={(item) => item.id}

View File

@@ -19,12 +19,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import React, { useRef, useState } from "react";
import { ActivityIndicator, ScrollView, View } from "react-native";
import { FlatList } from "react-native-actions-sheet";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { db } from "../../common/database";
import filesystem from "../../common/filesystem";
import { presentSheet } from "../../services/event-manager";
import { useThemeColors } from "@notesnook/theme";
import { useThemeStore } from "../../stores/use-theme-store";
import { SIZE } from "../../utils/size";
import SheetProvider from "../sheet-provider";
import { IconButton } from "../ui/icon-button";
@@ -41,12 +41,10 @@ import {
isImage,
isVideo
} from "@notesnook/core/utils/filename";
import { useSettingStore } from "../../stores/use-setting-store";
import { FlashList } from "react-native-actions-sheet/dist/src/views/FlashList";
export const AttachmentDialog = ({ note }) => {
const { colors } = useThemeColors();
const { height } = useSettingStore((state) => state.dimensions);
const colors = useThemeStore((state) => state.colors);
const [attachments, setAttachments] = useState(
note
? db.attachments.ofNote(note.id, "all")
@@ -82,11 +80,7 @@ export const AttachmentDialog = ({ note }) => {
};
const renderItem = ({ item }) => (
<AttachmentItem
setAttachments={setAttachments}
attachment={item}
context="attachments-list"
/>
<AttachmentItem setAttachments={setAttachments} attachment={item} />
);
const onCheck = async () => {
@@ -165,8 +159,7 @@ export const AttachmentDialog = ({ note }) => {
style={{
width: "100%",
alignSelf: "center",
paddingHorizontal: 12,
height: height * 0.85
paddingHorizontal: 12
}}
>
<SheetProvider context="attachments-list" />
@@ -201,7 +194,7 @@ export const AttachmentDialog = ({ note }) => {
width: 40,
marginRight: 10
}}
color={colors.primary.paragraph}
color={colors.pri}
size={SIZE.lg}
onPress={onCheck}
/>
@@ -213,7 +206,7 @@ export const AttachmentDialog = ({ note }) => {
height: 40,
width: 40
}}
color={colors.primary.paragraph}
color={colors.pri}
onPress={() => {
DownloadAttachments.present(
"attachments-list",
@@ -235,48 +228,51 @@ export const AttachmentDialog = ({ note }) => {
}}
/>
<View>
<ScrollView
style={{
width: "100%",
height: 50,
flexDirection: "row",
backgroundColor: colors.bg
}}
contentContainerStyle={{
minWidth: "100%",
height: 50
}}
horizontal
>
{attachmentTypes.map((item) => (
<Button
type={currentFilter === item.filterBy ? "grayAccent" : "gray"}
key={item.title}
title={
item.title +
` (${filterAttachments(item.filterBy)?.length || 0})`
}
style={{
borderRadius: 0,
borderBottomWidth: 1,
flexGrow: 1,
borderBottomColor:
currentFilter !== item.filterBy
? "transparent"
: colors.primary.accent
}}
onPress={() => {
setCurrentFilter(item.filterBy);
setAttachments(filterAttachments(item.filterBy));
}}
/>
))}
</ScrollView>
</View>
<FlashList
<FlatList
keyboardDismissMode="none"
keyboardShouldPersistTaps="always"
maxToRenderPerBatch={10}
initialNumToRender={10}
windowSize={5}
stickyHeaderIndices={[0]}
ListHeaderComponent={
<ScrollView
style={{
width: "100%",
height: 50,
flexDirection: "row",
backgroundColor: colors.bg
}}
contentContainerStyle={{
minWidth: "100%"
}}
horizontal
>
{attachmentTypes.map((item) => (
<Button
type={currentFilter === item.filterBy ? "grayAccent" : "gray"}
key={item.title}
title={
item.title +
` (${filterAttachments(item.filterBy)?.length || 0})`
}
style={{
borderRadius: 0,
borderBottomWidth: 1,
flexGrow: 1,
borderBottomColor:
currentFilter !== item.filterBy
? "transparent"
: colors.accent
}}
onPress={() => {
setCurrentFilter(item.filterBy);
setAttachments(filterAttachments(item.filterBy));
}}
/>
))}
</ScrollView>
}
ListEmptyComponent={
<View
style={{
@@ -285,7 +281,7 @@ export const AttachmentDialog = ({ note }) => {
alignItems: "center"
}}
>
<Icon name="attachment" size={60} color={colors.secondary.icon} />
<Icon name="attachment" size={60} color={colors.icon} />
<Paragraph>
{note ? "No attachments on this note" : "No attachments"}
</Paragraph>
@@ -298,24 +294,20 @@ export const AttachmentDialog = ({ note }) => {
}}
/>
}
estimatedItemSize={50}
data={attachments}
keyExtractor={(item) => item.id}
renderItem={renderItem}
/>
<Paragraph
color={colors.secondary.paragraph}
color={colors.icon}
size={SIZE.xs}
style={{
textAlign: "center",
marginTop: 10
}}
>
<Icon
name="shield-key-outline"
size={SIZE.xs}
color={colors.primary.icon}
/>
<Icon name="shield-key-outline" size={SIZE.xs} color={colors.icon} />
{" "}All attachments are end-to-end encrypted.
</Paragraph>
</View>

View File

@@ -18,13 +18,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React, { useEffect, useRef, useState } from "react";
import { Platform, View } from "react-native";
import { View } from "react-native";
import useGlobalSafeAreaInsets from "../../hooks/use-global-safe-area-insets";
import {
eSubscribeEvent,
eUnSubscribeEvent
} from "../../services/event-manager";
import { useThemeColors } from "@notesnook/theme";
import { useThemeStore } from "../../stores/use-theme-store";
import { eCloseLoginDialog, eOpenLoginDialog } from "../../utils/events";
import { sleep } from "../../utils/time";
import BaseDialog from "../dialog/base-dialog";
@@ -34,7 +34,6 @@ import { IconButton } from "../ui/icon-button";
import { hideAuth, initialAuthMode } from "./common";
import { Login } from "./login";
import { Signup } from "./signup";
import { KeyboardAwareScrollView } from "react-native-keyboard-aware-scroll-view";
export const AuthMode = {
login: 0,
@@ -44,7 +43,7 @@ export const AuthMode = {
};
const AuthModal = () => {
const { colors } = useThemeColors();
const colors = useThemeStore((state) => state.colors);
const [visible, setVisible] = useState(false);
const [currentAuthMode, setCurrentAuthMode] = useState(AuthMode.login);
const actionSheetRef = useRef();
@@ -76,89 +75,75 @@ const AuthModal = () => {
return !visible ? null : (
<BaseDialog
overlayOpacity={0}
statusBarTranslucent={false}
statusBarTranslucent={true}
onRequestClose={currentAuthMode !== AuthMode.welcomeSignup && close}
visible={true}
onClose={close}
useSafeArea={false}
bounce={false}
background={colors.primary.background}
background={colors.bg}
transparent={false}
animated={false}
avoidKeyboardResize
>
<KeyboardAwareScrollView
style={{
width: "100%"
}}
keyboardShouldPersistTaps="handled"
>
{currentAuthMode !== AuthMode.login ? (
<Signup
changeMode={(mode) => setCurrentAuthMode(mode)}
trial={AuthMode.trialSignup === currentAuthMode}
welcome={initialAuthMode.current === AuthMode.welcomeSignup}
/>
) : (
<Login
welcome={initialAuthMode.current === AuthMode.welcomeSignup}
changeMode={(mode) => setCurrentAuthMode(mode)}
/>
)}
</KeyboardAwareScrollView>
{currentAuthMode !== AuthMode.login ? (
<Signup
changeMode={(mode) => setCurrentAuthMode(mode)}
trial={AuthMode.trialSignup === currentAuthMode}
welcome={initialAuthMode.current === AuthMode.welcomeSignup}
/>
) : (
<Login
welcome={initialAuthMode.current === AuthMode.welcomeSignup}
changeMode={(mode) => setCurrentAuthMode(mode)}
/>
)}
<View
style={{
position: "absolute",
paddingTop: Platform.OS === "android" ? 0 : insets.top,
top: 0,
top: insets.top,
zIndex: 999,
backgroundColor: colors.secondary.background,
width: "100%"
flexDirection: "row",
alignItems: "center",
paddingHorizontal: 12,
width: "100%",
height: 50,
justifyContent:
initialAuthMode.current !== AuthMode.welcomeSignup
? "space-between"
: "flex-end"
}}
>
<View
style={{
flexDirection: "row",
alignItems: "center",
paddingHorizontal: 12,
width: "100%",
height: 50,
justifyContent:
initialAuthMode.current !== AuthMode.welcomeSignup
? "space-between"
: "flex-end"
}}
>
{initialAuthMode.current === AuthMode.welcomeSignup ? null : (
<IconButton
name="arrow-left"
onPress={() => {
hideAuth();
}}
color={colors.primary.paragraph}
/>
)}
{initialAuthMode.current === AuthMode.welcomeSignup ? null : (
<IconButton
name="arrow-left"
onPress={() => {
hideAuth();
}}
color={colors.pri}
/>
)}
{initialAuthMode.current !== AuthMode.welcomeSignup ? null : (
<Button
title="Skip"
onPress={() => {
hideAuth();
}}
iconSize={16}
type="gray"
iconPosition="right"
icon="chevron-right"
height={25}
iconStyle={{
marginTop: 2
}}
style={{
paddingHorizontal: 6
}}
/>
)}
</View>
{initialAuthMode.current !== AuthMode.welcomeSignup ? null : (
<Button
title="Skip"
onPress={() => {
hideAuth();
}}
iconSize={16}
type="gray"
iconPosition="right"
icon="chevron-right"
height={25}
iconStyle={{
marginTop: 2
}}
style={{
paddingHorizontal: 6
}}
/>
)}
</View>
<Toast context="local" />

View File

@@ -24,7 +24,7 @@ import { db } from "../../common/database";
import { DDS } from "../../services/device-detection";
import { ToastEvent } from "../../services/event-manager";
import SettingsService from "../../services/settings";
import { useThemeColors } from "@notesnook/theme";
import { useThemeStore } from "../../stores/use-theme-store";
import DialogHeader from "../dialog/dialog-header";
import { Button } from "../ui/button";
import { IconButton } from "../ui/icon-button";
@@ -34,7 +34,7 @@ import Heading from "../ui/typography/heading";
import Paragraph from "../ui/typography/paragraph";
export const ForgotPassword = () => {
const { colors } = useThemeColors("sheet");
const colors = useThemeStore((state) => state.colors);
const email = useRef();
const emailInputRef = useRef();
const [error, setError] = useState(false);
@@ -117,7 +117,7 @@ export const ForgotPassword = () => {
width: null,
height: null
}}
color={colors.primary.accent}
color={colors.accent}
name="email"
size={50}
/>
@@ -134,7 +134,7 @@ export const ForgotPassword = () => {
<View
style={{
borderRadius: DDS.isTab ? 5 : 0,
backgroundColor: colors.primary.background,
backgroundColor: colors.bg,
zIndex: 10,
width: "100%",
padding: 12

View File

@@ -65,7 +65,7 @@ const Auth = ({ navigation, route }) => {
onPress={() => {
hideAuth();
}}
color={colors.primary.paragraph}
color={colors.pri}
customStyle={{
position: 'absolute',
zIndex: 999,

View File

@@ -18,11 +18,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React, { useEffect, useState } from "react";
import { TouchableOpacity, View, useWindowDimensions } from "react-native";
import { TouchableOpacity, View } from "react-native";
import { SheetManager } from "react-native-actions-sheet";
import { DDS } from "../../services/device-detection";
import { eSendEvent } from "../../services/event-manager";
import { useThemeColors } from "@notesnook/theme";
import { useThemeStore } from "../../stores/use-theme-store";
import { SIZE } from "../../utils/size";
import { sleep } from "../../utils/time";
import SheetProvider from "../sheet-provider";
@@ -35,9 +35,6 @@ import { hideAuth } from "./common";
import { ForgotPassword } from "./forgot-password";
import { useLogin } from "./use-login";
import { useSettingStore } from "../../stores/use-setting-store";
import { eUserLoggedIn } from "../../utils/events";
import { useUserStore } from "../../stores/use-user-store";
import Sync from "../../services/sync";
const LoginSteps = {
emailAuth: 1,
@@ -46,7 +43,7 @@ const LoginSteps = {
};
export const Login = ({ changeMode }) => {
const { colors } = useThemeColors();
const colors = useThemeStore((state) => state.colors);
const [focused, setFocused] = useState(false);
const {
step,
@@ -61,17 +58,12 @@ export const Login = ({ changeMode }) => {
login
} = useLogin(async () => {
hideAuth();
eSendEvent(eUserLoggedIn, true);
eSendEvent("userLoggedIn", true);
await sleep(500);
Progress.present();
setTimeout(() => {
if (!useUserStore.getState().syncing) {
Sync.run("global", false, true);
}
}, 5000);
});
const deviceMode = useSettingStore((state) => state.deviceMode);
const { width, height } = useWindowDimensions();
useEffect(() => {
async () => {
setStep(LoginSteps.emailAuth);
@@ -92,27 +84,29 @@ export const Login = ({ changeMode }) => {
<View
style={{
borderRadius: DDS.isTab ? 5 : 0,
backgroundColor: colors.primary.background,
backgroundColor: colors.bg,
zIndex: 10,
width: "100%",
alignSelf: "center"
alignSelf: "center",
height: "100%",
minHeight: "100%"
}}
>
<View
style={{
flexGrow: 0.8,
justifyContent: "flex-end",
paddingHorizontal: 20,
backgroundColor: colors.secondary.background,
backgroundColor: colors.nav,
borderBottomWidth: 1,
marginBottom: 12,
borderBottomColor: colors.primary.border,
borderBottomColor: colors.border,
alignSelf: deviceMode !== "mobile" ? "center" : undefined,
borderWidth: deviceMode !== "mobile" ? 1 : null,
borderColor: deviceMode !== "mobile" ? colors.primary.border : null,
borderColor: deviceMode !== "mobile" ? colors.border : null,
borderRadius: deviceMode !== "mobile" ? 20 : null,
marginTop: deviceMode !== "mobile" ? 50 : null,
width: deviceMode === "mobile" ? null : "50%",
minHeight: height * 0.4
width: deviceMode === "mobile" ? null : "50%"
}}
>
<View
@@ -124,7 +118,7 @@ export const Login = ({ changeMode }) => {
style={{
width: 100,
height: 5,
backgroundColor: colors.primary.accent,
backgroundColor: colors.accent,
borderRadius: 2,
marginRight: 7
}}
@@ -134,7 +128,7 @@ export const Login = ({ changeMode }) => {
style={{
width: 20,
height: 5,
backgroundColor: colors.secondary.background,
backgroundColor: colors.nav,
borderRadius: 2
}}
/>
@@ -160,9 +154,10 @@ export const Login = ({ changeMode }) => {
: focused
? "100%"
: "99.9%",
backgroundColor: colors.primary.background,
backgroundColor: colors.bg,
alignSelf: "center",
paddingHorizontal: 20
paddingHorizontal: 20,
flexGrow: 1
}}
>
<Input
@@ -281,14 +276,11 @@ export const Login = ({ changeMode }) => {
paddingVertical: 12
}}
>
<Paragraph
size={SIZE.xs + 1}
color={colors.secondary.paragraph}
>
<Paragraph size={SIZE.xs + 1} color={colors.icon}>
Don't have an account?{" "}
<Paragraph
size={SIZE.xs + 1}
style={{ color: colors.primary.accent }}
style={{ color: colors.accent }}
>
Sign up
</Paragraph>

View File

@@ -17,23 +17,19 @@ 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 { useThemeColors } from "@notesnook/theme";
import React, { useEffect, useState } from "react";
import { Modal, View } from "react-native";
import { db } from "../../common/database";
import { MMKV } from "../../common/database/mmkv";
import BiometricService from "../../services/biometrics";
import {
ToastEvent,
eSendEvent,
eSubscribeEvent
eSubscribeEvent,
eUnSubscribeEvent,
ToastEvent
} from "../../services/event-manager";
import { setLoginMessage } from "../../services/message";
import SettingsService from "../../services/settings";
import Sync from "../../services/sync";
import { clearAllStores } from "../../stores";
import { useUserStore } from "../../stores/use-user-store";
import { eLoginSessionExpired, eUserLoggedIn } from "../../utils/events";
import { useThemeStore } from "../../stores/use-theme-store";
import { SIZE } from "../../utils/size";
import { sleep } from "../../utils/time";
import { Dialog } from "../dialog";
@@ -60,14 +56,13 @@ function getObfuscatedEmail(email) {
}
export const SessionExpired = () => {
const { colors } = useThemeColors();
const colors = useThemeStore((state) => state.colors);
const [visible, setVisible] = useState(false);
const [focused, setFocused] = useState(false);
const { step, password, email, passwordInputRef, loading, login } = useLogin(
() => {
eSendEvent(eUserLoggedIn, true);
eSendEvent("userLoggedIn", true);
setVisible(false);
setFocused(false);
}
);
@@ -75,12 +70,9 @@ export const SessionExpired = () => {
try {
await db.user.logout();
await BiometricService.resetCredentials();
setLoginMessage();
SettingsService.resetSettings();
useUserStore.getState().setUser(null);
useUserStore.getState().setSyncing(false);
MMKV.clearStore();
clearAllStores();
SettingsService.set({
introCompleted: true
});
setVisible(false);
} catch (e) {
ToastEvent.show({
@@ -92,9 +84,10 @@ export const SessionExpired = () => {
};
useEffect(() => {
const sub = eSubscribeEvent(eLoginSessionExpired, open);
eSubscribeEvent("session_expired", open);
return () => {
sub.unsubscribe?.();
eUnSubscribeEvent("session_expired", open);
setFocused(false);
};
}, [visible, open]);
@@ -110,7 +103,6 @@ export const SessionExpired = () => {
if (!user) return;
email.current = user.email;
setVisible(true);
setFocused(false);
return;
}
SettingsService.set({
@@ -123,7 +115,6 @@ export const SessionExpired = () => {
let user = await db.user.getUser();
if (!user) return;
email.current = user.email;
setFocused(false);
setVisible(true);
}
}, [email]);
@@ -145,7 +136,7 @@ export const SessionExpired = () => {
padding: 12,
justifyContent: "center",
flex: 1,
backgroundColor: colors.primary.background
backgroundColor: colors.bg
}}
>
<View
@@ -164,10 +155,10 @@ export const SessionExpired = () => {
height: 60
}}
name="alert"
color={colors.error.icon}
color={colors.errorText}
size={50}
/>
<Heading size={SIZE.xxxl} color={colors.primary.heading}>
<Heading size={SIZE.xxxl} color={colors.heading}>
Session expired
</Heading>
<Paragraph

View File

@@ -18,13 +18,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React, { useRef, useState } from "react";
import { TouchableOpacity, View, useWindowDimensions } from "react-native";
import { TouchableOpacity, View } from "react-native";
import { db } from "../../common/database";
import { DDS } from "../../services/device-detection";
import { ToastEvent } from "../../services/event-manager";
import { clearMessage, setEmailVerifyMessage } from "../../services/message";
import PremiumService from "../../services/premium";
import { useThemeColors } from "@notesnook/theme";
import { useThemeStore } from "../../stores/use-theme-store";
import { useUserStore } from "../../stores/use-user-store";
import { openLinkInBrowser } from "../../utils/functions";
import { SIZE } from "../../utils/size";
@@ -37,7 +37,7 @@ import { hideAuth } from "./common";
import { useSettingStore } from "../../stores/use-setting-store";
export const Signup = ({ changeMode, trial }) => {
const { colors } = useThemeColors();
const colors = useThemeStore((state) => state.colors);
const email = useRef();
const emailInputRef = useRef();
const passwordInputRef = useRef();
@@ -49,7 +49,7 @@ export const Signup = ({ changeMode, trial }) => {
const setUser = useUserStore((state) => state.setUser);
const setLastSynced = useUserStore((state) => state.setLastSynced);
const deviceMode = useSettingStore((state) => state.deviceMode);
const { width, height } = useWindowDimensions();
const validateInfo = () => {
if (!password.current || !email.current || !confirmPassword.current) {
ToastEvent.show({
@@ -98,27 +98,29 @@ export const Signup = ({ changeMode, trial }) => {
<View
style={{
borderRadius: DDS.isTab ? 5 : 0,
backgroundColor: colors.primary.background,
backgroundColor: colors.bg,
zIndex: 10,
width: "100%",
alignSelf: "center"
alignSelf: "center",
height: "100%",
minHeight: "100%"
}}
>
<View
style={{
flexGrow: 1,
justifyContent: "flex-end",
paddingHorizontal: 20,
backgroundColor: colors.secondary.background,
backgroundColor: colors.nav,
marginBottom: 20,
borderBottomWidth: 1,
borderBottomColor: colors.primary.border,
borderBottomColor: colors.border,
alignSelf: deviceMode !== "mobile" ? "center" : undefined,
borderWidth: deviceMode !== "mobile" ? 1 : null,
borderColor: deviceMode !== "mobile" ? colors.primary.border : null,
borderColor: deviceMode !== "mobile" ? colors.border : null,
borderRadius: deviceMode !== "mobile" ? 20 : null,
marginTop: deviceMode !== "mobile" ? 50 : null,
width: deviceMode === "mobile" ? null : "50%",
minHeight: height * 0.4
width: deviceMode === "mobile" ? null : "50%"
}}
>
<View
@@ -130,7 +132,7 @@ export const Signup = ({ changeMode, trial }) => {
style={{
width: 100,
height: 5,
backgroundColor: colors.primary.accent,
backgroundColor: colors.accent,
borderRadius: 2,
marginRight: 7
}}
@@ -140,7 +142,7 @@ export const Signup = ({ changeMode, trial }) => {
style={{
width: 20,
height: 5,
backgroundColor: colors.secondary.background,
backgroundColor: colors.nav,
borderRadius: 2
}}
/>
@@ -161,8 +163,9 @@ export const Signup = ({ changeMode, trial }) => {
style={{
width: DDS.isTab ? "50%" : "100%",
paddingHorizontal: 20,
backgroundColor: colors.primary.background,
alignSelf: "center"
backgroundColor: colors.bg,
alignSelf: "center",
flexGrow: 0.5
}}
>
<Input
@@ -230,7 +233,7 @@ export const Signup = ({ changeMode, trial }) => {
marginBottom: 25
}}
size={SIZE.xs}
color={colors.secondary.paragraph}
color={colors.icon}
>
By signing up, you agree to our{" "}
<Paragraph
@@ -241,7 +244,7 @@ export const Signup = ({ changeMode, trial }) => {
style={{
textDecorationLine: "underline"
}}
color={colors.primary.accent}
color={colors.accent}
>
Terms of Service{" "}
</Paragraph>
@@ -254,7 +257,7 @@ export const Signup = ({ changeMode, trial }) => {
style={{
textDecorationLine: "underline"
}}
color={colors.primary.accent}
color={colors.accent}
>
Privacy Policy.
</Paragraph>{" "}
@@ -287,12 +290,9 @@ export const Signup = ({ changeMode, trial }) => {
paddingVertical: 12
}}
>
<Paragraph size={SIZE.xs + 1} color={colors.secondary.paragraph}>
<Paragraph size={SIZE.xs + 1} color={colors.icon}>
Already have an account?{" "}
<Paragraph
size={SIZE.xs + 1}
style={{ color: colors.primary.accent }}
>
<Paragraph size={SIZE.xs + 1} style={{ color: colors.accent }}>
Login
</Paragraph>
</Paragraph>

View File

@@ -26,7 +26,7 @@ import {
presentSheet,
ToastEvent
} from "../../services/event-manager";
import { useThemeColors } from "@notesnook/theme";
import { useThemeStore } from "../../stores/use-theme-store";
import { eCloseSheet } from "../../utils/events";
import { SIZE } from "../../utils/size";
import { Button } from "../ui/button";
@@ -39,7 +39,7 @@ import Paragraph from "../ui/typography/paragraph";
import { useCallback } from "react";
const TwoFactorVerification = ({ onMfaLogin, mfaInfo }) => {
const { colors } = useThemeColors();
const colors = useThemeStore((state) => state.colors);
const code = useRef();
const [currentMethod, setCurrentMethod] = useState({
method: mfaInfo?.primaryMethod,
@@ -157,7 +157,7 @@ const TwoFactorVerification = ({ onMfaLogin, mfaInfo }) => {
}}
size={50}
name="key"
color={colors.primary.accent}
color={colors.accent}
/>
<Heading
style={{
@@ -281,7 +281,7 @@ const TwoFactorVerification = ({ onMfaLogin, mfaInfo }) => {
marginRight: 10
}}
size={15}
color={colors.primary.accent}
color={colors.accent}
name={item.icon}
/>
<View

View File

@@ -20,16 +20,16 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import React from "react";
import { View } from "react-native";
import { useSelectionStore } from "../../stores/use-selection-store";
import { useThemeColors } from "@notesnook/theme";
import { useThemeStore } from "../../stores/use-theme-store";
export const ContainerHeader = ({ children }) => {
const { colors } = useThemeColors();
const colors = useThemeStore((state) => state.colors);
const selectionMode = useSelectionStore((state) => state.selectionMode);
return !selectionMode ? (
<View
style={{
backgroundColor: colors.primary.background,
backgroundColor: colors.bg,
width: "100%",
overflow: "hidden"
}}

View File

@@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React, { useCallback, useEffect } from "react";
import React, { useEffect } from "react";
import { Keyboard, Platform, View } from "react-native";
import Animated, {
Easing,
@@ -30,19 +30,17 @@ import { notesnook } from "../../../e2e/test.ids";
import { editorState } from "../../screens/editor/tiptap/utils";
import { useSelectionStore } from "../../stores/use-selection-store";
import { useSettingStore } from "../../stores/use-setting-store";
import { getElevationStyle } from "../../utils/elevation";
import { SIZE, normalize } from "../../utils/size";
import NativeTooltip from "../../utils/tooltip";
import { getElevation, showTooltip, TOOLTIP_POSITIONS } from "../../utils";
import { normalize, SIZE } from "../../utils/size";
import { PressableButton } from "../ui/pressable";
import { useThemeColors } from "@notesnook/theme";
import { useCallback } from "react";
export const FloatingButton = ({
title,
onPress,
color,
color = "accent",
shouldShow = false
}) => {
const { colors } = useThemeColors();
const deviceMode = useSettingStore((state) => state.deviceMode);
const selectionMode = useSelectionStore((state) => state.selectionMode);
const translate = useSharedValue(0);
@@ -115,16 +113,14 @@ export const FloatingButton = ({
<PressableButton
testID={notesnook.buttons.add}
type="accent"
buttonType={{
color: colors.static[color],
text: colors.static.white
}}
accentColor={color || "accent"}
accentText="light"
customStyle={{
...getElevationStyle(5),
...getElevation(5),
borderRadius: 100
}}
onLongPress={(event) => {
NativeTooltip.show(event, title, NativeTooltip.POSITIONS.LEFT);
showTooltip(event, title, TOOLTIP_POSITIONS.LEFT);
}}
onPress={onPress}
>

View File

@@ -20,21 +20,21 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import React from "react";
import { View } from "react-native";
import { useMessageStore } from "../../stores/use-message-store";
import { useThemeColors } from "@notesnook/theme";
import { ColorValues } from "../../utils/colors";
import { hexToRGBA } from "../../utils/colors";
import { useThemeStore } from "../../stores/use-theme-store";
import { COLORS_NOTE } from "../../utils/color-scheme";
import { hexToRGBA } from "../../utils/color-scheme/utils";
export const DefaultPlaceholder = ({ color }: { color: string }) => {
const { colors } = useThemeColors();
const colors = useThemeStore((state) => state.colors);
const message = useMessageStore((state) => state.message);
const annoucements = useMessageStore((state) => state.announcements);
const hasAnnoucements = annoucements.length > 0;
const shadeColor = color
? hexToRGBA(
ColorValues[color?.toLowerCase() as keyof typeof ColorValues],
COLORS_NOTE[color?.toLowerCase() as keyof typeof COLORS_NOTE],
0.15
)
: colors.primary.shade;
: colors.shade;
return (
<View
@@ -50,7 +50,7 @@ export const DefaultPlaceholder = ({ color }: { color: string }) => {
height: 100,
borderRadius: 10,
marginBottom: 20,
backgroundColor: colors.secondary.background,
backgroundColor: colors.nav,
padding: 12
}}
>
@@ -58,7 +58,7 @@ export const DefaultPlaceholder = ({ color }: { color: string }) => {
style={{
width: 150,
height: 20,
backgroundColor: colors.primary.hover,
backgroundColor: colors.transGray,
borderRadius: 5,
marginBottom: 10
}}
@@ -67,7 +67,7 @@ export const DefaultPlaceholder = ({ color }: { color: string }) => {
style={{
width: 250,
height: 14,
backgroundColor: colors.primary.hover,
backgroundColor: colors.transGray,
borderRadius: 5
}}
/>
@@ -110,7 +110,7 @@ export const DefaultPlaceholder = ({ color }: { color: string }) => {
style={{
width: 150,
height: 12,
backgroundColor: colors.secondary.background,
backgroundColor: colors.nav,
borderRadius: 5,
marginBottom: 10
}}
@@ -119,7 +119,7 @@ export const DefaultPlaceholder = ({ color }: { color: string }) => {
style={{
width: 250,
height: 16,
backgroundColor: colors.secondary.background,
backgroundColor: colors.nav,
borderRadius: 5
}}
/>
@@ -131,7 +131,7 @@ export const DefaultPlaceholder = ({ color }: { color: string }) => {
style={{
width: "100%",
height: 30,
backgroundColor: colors.secondary.background,
backgroundColor: colors.nav,
borderRadius: 10,
marginBottom: 20,
padding: 5,
@@ -158,7 +158,7 @@ export const DefaultPlaceholder = ({ color }: { color: string }) => {
style={{
width: 15,
height: 15,
backgroundColor: colors.primary.hover,
backgroundColor: colors.transGray,
borderRadius: 100,
marginRight: 10
}}
@@ -167,7 +167,7 @@ export const DefaultPlaceholder = ({ color }: { color: string }) => {
style={{
width: 60,
height: 15,
backgroundColor: colors.primary.hover,
backgroundColor: colors.transGray,
borderRadius: 3
}}
/>
@@ -178,7 +178,7 @@ export const DefaultPlaceholder = ({ color }: { color: string }) => {
style={{
width: 200,
height: 16,
backgroundColor: colors.secondary.background,
backgroundColor: colors.nav,
borderRadius: 5
}}
/>
@@ -186,7 +186,7 @@ export const DefaultPlaceholder = ({ color }: { color: string }) => {
style={{
width: "85%",
height: 13,
backgroundColor: colors.secondary.background,
backgroundColor: colors.nav,
borderRadius: 5,
marginTop: 10
}}
@@ -202,7 +202,7 @@ export const DefaultPlaceholder = ({ color }: { color: string }) => {
style={{
width: 50,
height: 10,
backgroundColor: colors.secondary.background,
backgroundColor: colors.nav,
borderRadius: 5
}}
/>
@@ -210,7 +210,7 @@ export const DefaultPlaceholder = ({ color }: { color: string }) => {
style={{
width: 60,
height: 10,
backgroundColor: colors.secondary.background,
backgroundColor: colors.nav,
borderRadius: 5,
marginLeft: 10
}}

View File

@@ -21,7 +21,7 @@ import React from "react";
import { ViewProps } from "react-native";
import Animated, { FadeOutUp } from "react-native-reanimated";
import { useDelayLayout } from "../../hooks/use-delay-layout";
import { useThemeColors } from "@notesnook/theme";
import { useThemeStore } from "../../stores/use-theme-store";
import { DefaultPlaceholder } from "./default-placeholder";
import { SettingsPlaceholder } from "./settings-placeholder";
@@ -42,7 +42,7 @@ export default function DelayLayout({
animated = true,
...props
}: IDelayLayoutProps) {
const { colors } = useThemeColors();
const colors = useThemeStore((state) => state.colors);
const loading = useDelayLayout(
!props.delay || props.delay < 300 ? 300 : props.delay
);
@@ -52,12 +52,12 @@ export default function DelayLayout({
<Animated.View
exiting={animated ? FadeOutUp : undefined}
style={{
backgroundColor: colors.primary.background,
backgroundColor: colors.bg,
flex: 1,
paddingTop: 20
}}
>
<Placeholder color={props.color || colors.primary.accent} />
<Placeholder color={props.color || colors.accent} />
</Animated.View>
) : (
<>{props.children}</>

View File

@@ -19,10 +19,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import React from "react";
import { View } from "react-native";
import { useThemeColors } from "@notesnook/theme";
import { useThemeStore } from "../../stores/use-theme-store";
export const SettingsPlaceholder = () => {
const { colors } = useThemeColors();
const colors = useThemeStore((state) => state.colors);
return (
<View>
@@ -30,7 +30,7 @@ export const SettingsPlaceholder = () => {
style={{
width: 100,
height: 12,
backgroundColor: colors.primary.shade,
backgroundColor: colors.shade,
borderRadius: 5,
marginLeft: 12,
marginBottom: 12
@@ -51,7 +51,7 @@ export const SettingsPlaceholder = () => {
style={{
width: 40,
height: 40,
backgroundColor: colors.primary.hover,
backgroundColor: colors.transGray,
borderRadius: 100,
marginRight: 20
}}
@@ -61,7 +61,7 @@ export const SettingsPlaceholder = () => {
style={{
width: 150,
height: 12,
backgroundColor: colors.secondary.background,
backgroundColor: colors.nav,
borderRadius: 5,
marginBottom: 10
}}
@@ -70,7 +70,7 @@ export const SettingsPlaceholder = () => {
style={{
width: 250,
height: 16,
backgroundColor: colors.secondary.background,
backgroundColor: colors.nav,
borderRadius: 5
}}
/>
@@ -93,7 +93,7 @@ export const SettingsPlaceholder = () => {
style={{
width: 40,
height: 40,
backgroundColor: colors.primary.shade,
backgroundColor: colors.shade,
borderRadius: 100,
marginRight: 20
}}
@@ -103,7 +103,7 @@ export const SettingsPlaceholder = () => {
style={{
width: 150,
height: 12,
backgroundColor: colors.secondary.background,
backgroundColor: colors.nav,
borderRadius: 5,
marginBottom: 10
}}
@@ -112,7 +112,7 @@ export const SettingsPlaceholder = () => {
style={{
width: 250,
height: 16,
backgroundColor: colors.secondary.background,
backgroundColor: colors.nav,
borderRadius: 5
}}
/>
@@ -122,7 +122,7 @@ export const SettingsPlaceholder = () => {
style={{
width: 40,
height: 20,
backgroundColor: colors.secondary.background,
backgroundColor: colors.nav,
borderRadius: 100,
marginLeft: 15,
alignItems: "flex-end",
@@ -134,7 +134,7 @@ export const SettingsPlaceholder = () => {
style={{
width: 15,
height: 15,
backgroundColor: colors.primary.shade,
backgroundColor: colors.shade,
borderRadius: 100,
marginLeft: 15
}}

View File

@@ -19,7 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import React from "react";
import { useNoteStore } from "../../stores/use-notes-store";
import { useThemeColors } from "@notesnook/theme";
import { useThemeStore } from "../../stores/use-theme-store";
import { AnnouncementDialog } from "../announcements";
import AuthModal from "../auth/auth-modal";
import { SessionExpired } from "../auth/session-expired";
@@ -39,7 +39,7 @@ import RestoreDataSheet from "../sheets/restore-data";
import PDFPreview from "../dialogs/pdf-preview";
const DialogProvider = () => {
const { colors } = useThemeColors();
const colors = useThemeStore((state) => state.colors);
const loading = useNoteStore((state) => state.loading);
return (

View File

@@ -30,7 +30,6 @@ import {
import useIsFloatingKeyboard from "../../hooks/use-is-floating-keyboard";
import { useSettingStore } from "../../stores/use-setting-store";
import { BouncingView } from "../ui/transitions/bouncing-view";
import { ScopedThemeProvider } from "@notesnook/theme";
const BaseDialog = ({
visible,
@@ -61,71 +60,69 @@ const BaseDialog = ({
const Wrapper = useSafeArea ? SafeAreaView : View;
return (
<ScopedThemeProvider value="dialog">
<Modal
visible={visible}
transparent={true}
animated
statusBarTranslucent={statusBarTranslucent}
supportedOrientations={[
"portrait",
"portrait-upside-down",
"landscape",
"landscape-left",
"landscape-right"
]}
onShow={() => {
if (onShow) {
onShow();
useSettingStore.getState().setSheetKeyboardHandler(false);
}
}}
animationType={animation}
onRequestClose={() => {
if (!closeOnTouch) return null;
useSettingStore.getState().setSheetKeyboardHandler(true);
onRequestClose && onRequestClose();
<Modal
visible={visible}
transparent={true}
animated
statusBarTranslucent={statusBarTranslucent}
supportedOrientations={[
"portrait",
"portrait-upside-down",
"landscape",
"landscape-left",
"landscape-right"
]}
onShow={() => {
if (onShow) {
onShow();
useSettingStore.getState().setSheetKeyboardHandler(false);
}
}}
animationType={animation}
onRequestClose={() => {
if (!closeOnTouch) return null;
useSettingStore.getState().setSheetKeyboardHandler(true);
onRequestClose && onRequestClose();
}}
>
<Wrapper
style={{
backgroundColor: background
? background
: transparent
? "transparent"
: "rgba(0,0,0,0.3)"
}}
>
<Wrapper
style={{
backgroundColor: background
? background
: transparent
? "transparent"
: "rgba(0,0,0,0.3)"
}}
<KeyboardAvoidingView
enabled={!floating && Platform.OS === "ios" && !avoidKeyboardResize}
behavior="padding"
>
<KeyboardAvoidingView
enabled={!floating && Platform.OS === "ios" && !avoidKeyboardResize}
behavior="padding"
<BouncingView
duration={400}
animated={animated}
initialScale={bounce ? 0.9 : 1}
style={[
styles.backdrop,
{
justifyContent: centered
? "center"
: bottom
? "flex-end"
: "flex-start"
}
]}
>
<BouncingView
duration={400}
animated={animated}
initialScale={bounce ? 0.9 : 1}
style={[
styles.backdrop,
{
justifyContent: centered
? "center"
: bottom
? "flex-end"
: "flex-start"
}
]}
>
<TouchableOpacity
onPress={closeOnTouch ? onRequestClose : null}
style={styles.overlayButton}
/>
{premium}
{children}
</BouncingView>
</KeyboardAvoidingView>
</Wrapper>
</Modal>
</ScopedThemeProvider>
<TouchableOpacity
onPress={closeOnTouch ? onRequestClose : null}
style={styles.overlayButton}
/>
{premium}
{children}
</BouncingView>
</KeyboardAvoidingView>
</Wrapper>
</Modal>
);
};

View File

@@ -21,7 +21,7 @@ import React from "react";
import { ActivityIndicator, StyleSheet, View } from "react-native";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { notesnook } from "../../../e2e/test.ids";
import { useThemeColors } from "@notesnook/theme";
import { useThemeStore } from "../../stores/use-theme-store";
import { SIZE } from "../../utils/size";
import { Button } from "../ui/button";
import Paragraph from "../ui/typography/paragraph";
@@ -35,14 +35,14 @@ const DialogButtons = ({
doneText,
positiveType
}) => {
const { colors } = useThemeColors();
const colors = useThemeStore((state) => state.colors);
return (
<View
style={[
styles.container,
{
backgroundColor: colors.secondary.background,
backgroundColor: colors.nav,
height: 60,
borderBottomRightRadius: 10,
borderBottomLeftRadius: 10,
@@ -51,7 +51,7 @@ const DialogButtons = ({
]}
>
{loading ? (
<ActivityIndicator color={colors.primary.accent} size={SIZE.lg} />
<ActivityIndicator color={colors.accent} size={SIZE.lg} />
) : doneText ? (
<View
style={{
@@ -60,11 +60,11 @@ const DialogButtons = ({
}}
>
<Icon
color={colors.primary.accent}
color={colors.accent}
name="check-circle-outline"
size={SIZE.md}
/>
<Paragraph color={colors.primary.accent}>{" " + doneText}</Paragraph>
<Paragraph color={colors.accent}>{" " + doneText}</Paragraph>
</View>
) : (
<View />

View File

@@ -20,21 +20,21 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import React from "react";
import { View } from "react-native";
import { DDS } from "../../services/device-detection";
import { useThemeColors } from "@notesnook/theme";
import { getElevationStyle } from "../../utils/elevation";
import { useThemeStore } from "../../stores/use-theme-store";
import { getElevation } from "../../utils";
const DialogContainer = ({ width, height, ...restProps }) => {
const { colors } = useThemeColors();
const colors = useThemeStore((state) => state.colors);
return (
<View
{...restProps}
style={{
...getElevationStyle(5),
...getElevation(5),
width: width || DDS.isTab ? 500 : "85%",
maxHeight: height || 450,
borderRadius: 10,
backgroundColor: colors.primary.background,
backgroundColor: colors.bg,
paddingTop: 12
}}
/>

View File

@@ -19,7 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import React from "react";
import { Text, View, ViewStyle } from "react-native";
import { useThemeColors } from "@notesnook/theme";
import { useThemeStore } from "../../stores/use-theme-store";
import { SIZE } from "../../utils/size";
import { Button } from "../ui/button";
import { PressableButtonProps } from "../ui/pressable";
@@ -54,7 +54,7 @@ const DialogHeader = ({
titlePart,
style
}: DialogHeaderProps) => {
const { colors } = useThemeColors();
const colors = useThemeStore((state) => state.colors);
return (
<>
@@ -86,7 +86,7 @@ const DialogHeader = ({
>
{title}{" "}
{titlePart ? (
<Text style={{ color: colors.primary.accent }}>{titlePart}</Text>
<Text style={{ color: colors.accent }}>{titlePart}</Text>
) : null}
</Heading>
@@ -114,7 +114,7 @@ const DialogHeader = ({
maxWidth: centered ? "90%" : "100%",
alignSelf: centered ? "center" : "flex-start"
}}
color={paragraphColor || colors.secondary.paragraph}
color={paragraphColor || colors.icon}
>
{paragraph}
</Paragraph>

View File

@@ -24,8 +24,8 @@ import {
eSubscribeEvent,
eUnSubscribeEvent
} from "../../services/event-manager";
import { useThemeColors } from "@notesnook/theme";
import { getElevationStyle } from "../../utils/elevation";
import { useThemeStore } from "../../stores/use-theme-store";
import { getElevation } from "../../utils";
import { eCloseSimpleDialog, eOpenSimpleDialog } from "../../utils/events";
import { sleep } from "../../utils/time";
import { Toast } from "../toast";
@@ -38,7 +38,7 @@ import { useCallback } from "react";
import { Button } from "../ui/button";
export const Dialog = ({ context = "global" }) => {
const { colors } = useThemeColors();
const colors = useThemeStore((state) => state.colors);
const [visible, setVisible] = useState(false);
const [inputValue, setInputValue] = useState(null);
const inputRef = useRef();
@@ -51,7 +51,7 @@ export const Dialog = ({ context = "global" }) => {
onClose: () => {},
positiveType: "transparent",
icon: null,
paragraphColor: colors.primary.paragraph,
paragraphColor: colors.pri,
input: false,
inputPlaceholder: "Enter some text",
defaultValue: "",
@@ -111,11 +111,11 @@ export const Dialog = ({ context = "global" }) => {
};
const style = {
...getElevationStyle(5),
...getElevation(5),
width: DDS.isTab ? 400 : "85%",
maxHeight: 450,
borderRadius: 5,
backgroundColor: colors.primary.background,
backgroundColor: colors.bg,
paddingTop: 12
};

View File

@@ -25,8 +25,8 @@ import {
eUnSubscribeEvent
} from "../../../services/event-manager";
import { useMessageStore } from "../../../stores/use-message-store";
import { useThemeColors } from "@notesnook/theme";
import { getElevationStyle } from "../../../utils/elevation";
import { useThemeStore } from "../../../stores/use-theme-store";
import { getElevation } from "../../../utils";
import {
eCloseJumpToDialog,
eOpenJumpToDialog,
@@ -41,10 +41,10 @@ import { useCallback } from "react";
const offsets = [];
let timeout = null;
const JumpToSectionDialog = ({ scrollRef, data, type }) => {
const { colors } = useThemeColors();
const colors = useThemeStore((state) => state.colors);
const notes = data;
const [visible, setVisible] = useState(false);
const [currentIndex, setCurrentIndex] = useState(0);
const [currentIndex, setCurrentIndex] = useState(null);
const onPress = (item) => {
let ind = notes.findIndex(
@@ -77,7 +77,7 @@ const JumpToSectionDialog = ({ scrollRef, data, type }) => {
}
timeout = setTimeout(() => {
let index = offsets.findIndex((o, i) => o <= y && offsets[i + 1] > y);
setCurrentIndex(index || 0);
setCurrentIndex(index);
}, 200);
};
@@ -113,6 +113,7 @@ const JumpToSectionDialog = ({ scrollRef, data, type }) => {
offsets.push(offset);
});
}, [notes]);
return !visible ? null : (
<BaseDialog
onShow={() => {
@@ -123,9 +124,9 @@ const JumpToSectionDialog = ({ scrollRef, data, type }) => {
>
<View
style={{
...getElevationStyle(5),
...getElevation(5),
width: DDS.isTab ? 500 : "85%",
backgroundColor: colors.primary.background,
backgroundColor: colors.bg,
zIndex: 100,
bottom: 20,
maxHeight: "65%",
@@ -156,7 +157,7 @@ const JumpToSectionDialog = ({ scrollRef, data, type }) => {
<PressableButton
key={item.title}
onPress={() => onPress(item, index)}
type={currentIndex === index ? "selected" : "transparent"}
type={currentIndex === index ? "accent" : "transparent"}
customStyle={{
minWidth: "20%",
width: null,
@@ -170,9 +171,7 @@ const JumpToSectionDialog = ({ scrollRef, data, type }) => {
<Paragraph
size={SIZE.sm}
color={
currentIndex === index
? colors.selected.accent
: colors.primary.accent
currentIndex === index ? colors.light : colors.accent
}
style={{
textAlign: "center"

View File

@@ -18,7 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React from "react";
import { View } from "react-native";
import { useThemeColors } from "@notesnook/theme";
import { useThemeStore } from "../../../stores/use-theme-store";
import BaseDialog from "../../dialog/base-dialog";
import { ProgressBarComponent } from "../../ui/svg/lazy";
import { useEffect } from "react";
@@ -30,7 +30,7 @@ import { useState } from "react";
import { eCloseLoading, eOpenLoading } from "../../../utils/events";
export const LoadingDialog = () => {
const { colors } = useThemeColors();
const colors = useThemeStore((state) => state.colors);
const [visible, setVisible] = useState(false);
useEffect(() => {
@@ -58,7 +58,7 @@ export const LoadingDialog = () => {
style={{
width: "100%",
height: "100%",
backgroundColor: colors.primary.background,
backgroundColor: colors.bg,
justifyContent: "center",
alignItems: "center"
}}
@@ -77,8 +77,8 @@ export const LoadingDialog = () => {
useNativeDriver
indeterminate
indeterminateAnimationDuration={2000}
unfilledColor={colors.secondary.background}
color={colors.primary.accent}
unfilledColor={colors.nav}
color={colors.accent}
borderWidth={0}
/>
</View>

View File

@@ -33,7 +33,7 @@ import {
eSubscribeEvent,
eUnSubscribeEvent
} from "../../../services/event-manager";
import { useThemeColors } from "@notesnook/theme";
import { useThemeStore } from "../../../stores/use-theme-store";
import { SIZE } from "../../../utils/size";
import { Dialog } from "../../dialog";
import BaseDialog from "../../dialog/base-dialog";
@@ -64,7 +64,7 @@ const usePDFSnapshot = (attachment) => {
};
const PDFPreview = () => {
const { colors } = useThemeColors();
const colors = useThemeStore((state) => state.colors);
const [visible, setVisible] = useState(false);
const [pdfSource, setPDFSource] = useState();
const [loading, setLoading] = useState(false);
@@ -172,7 +172,7 @@ const PDFPreview = () => {
>
<ProgressBarComponent
indeterminate={!progress}
color={colors.primary.accent}
color={colors.accent}
borderColor="transparent"
progress={parseInt(progress?.value || "100") / 100}
/>
@@ -180,7 +180,7 @@ const PDFPreview = () => {
style={{
marginTop: 10
}}
color={colors.static.white}
color={colors.light}
>
Loading {`${progress?.percent ? `(${progress?.percent})` : ""}`}
... Please wait
@@ -205,7 +205,7 @@ const PDFPreview = () => {
}}
>
<IconButton
color={colors.static.white}
color={colors.light}
name="arrow-left"
onPress={close}
customStyle={{
@@ -226,7 +226,7 @@ const PDFPreview = () => {
ref={inputRef}
defaultValue={currentPage + ""}
style={{
color: colors.primary.paragraph,
color: colors.pri,
padding: 0,
paddingTop: 0,
paddingBottom: 0,
@@ -234,7 +234,7 @@ const PDFPreview = () => {
marginBottom: 0,
paddingVertical: 0,
height: 25,
backgroundColor: colors.secondary.background,
backgroundColor: colors.nav,
width: 40,
textAlign: "center",
marginRight: 4,
@@ -249,7 +249,7 @@ const PDFPreview = () => {
}}
blurOnSubmit
/>
<Paragraph color={colors.static.white}>/{numPages}</Paragraph>
<Paragraph color={colors.light}>/{numPages}</Paragraph>
</View>
<View
@@ -258,7 +258,7 @@ const PDFPreview = () => {
}}
>
<IconButton
color={colors.static.white}
color={colors.light}
name="download"
onPress={() => {
downloadAttachment(attachment.metadata.hash, false);

View File

@@ -24,8 +24,8 @@ import {
eSubscribeEvent,
eUnSubscribeEvent
} from "../../../services/event-manager";
import { useThemeColors } from "@notesnook/theme";
import { getElevationStyle } from "../../../utils/elevation";
import { useThemeStore } from "../../../stores/use-theme-store";
import { getElevation } from "../../../utils";
import { eCloseResultDialog, eOpenResultDialog } from "../../../utils/events";
import { SIZE } from "../../../utils/size";
import BaseDialog from "../../dialog/base-dialog";
@@ -36,7 +36,7 @@ import Paragraph from "../../ui/typography/paragraph";
import { ProFeatures } from "./pro-features";
const ResultDialog = () => {
const { colors } = useThemeColors();
const colors = useThemeStore((state) => state.colors);
const [visible, setVisible] = useState(false);
const [dialogData, setDialogData] = useState({
title: "Thank you for signing up!",
@@ -68,11 +68,11 @@ const ResultDialog = () => {
<BaseDialog visible={true} onRequestClose={close}>
<View
style={{
...getElevationStyle(5),
...getElevation(5),
width: DDS.isTab ? 350 : "85%",
maxHeight: 500,
borderRadius: 10,
backgroundColor: colors.primary.background,
backgroundColor: colors.bg,
paddingTop: 20,
justifyContent: "center",
alignItems: "center"
@@ -94,7 +94,7 @@ const ResultDialog = () => {
</Heading>
<Paragraph
color={colors.secondary.paragraph}
color={colors.icon}
size={SIZE.md}
style={{
alignSelf: "center",
@@ -121,7 +121,7 @@ const ResultDialog = () => {
<Seperator />
<View
style={{
backgroundColor: colors.secondary.background,
backgroundColor: colors.nav,
width: "100%",
borderBottomRightRadius: 10,
borderBottomLeftRadius: 10,

View File

@@ -21,7 +21,7 @@ import React from "react";
import { View } from "react-native";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { eSendEvent } from "../../../services/event-manager";
import { useThemeColors } from "@notesnook/theme";
import { useThemeStore } from "../../../stores/use-theme-store";
import {
eCloseSheet,
eCloseResultDialog,
@@ -31,7 +31,7 @@ import { SIZE } from "../../../utils/size";
import { sleep } from "../../../utils/time";
import Paragraph from "../../ui/typography/paragraph";
export const ProFeatures = ({ count = 6 }) => {
const { colors } = useThemeColors();
const colors = useThemeStore((state) => state.colors);
return (
<>
@@ -73,7 +73,7 @@ export const ProFeatures = ({ count = 6 }) => {
justifyContent: "flex-start"
}}
>
<Icon size={SIZE.lg} color={colors.primary.accent} name="check" />
<Icon size={SIZE.lg} color={colors.accent} name="check" />
<Paragraph style={{ marginLeft: 5, flexShrink: 1 }}>
{item.content}
</Paragraph>
@@ -89,7 +89,7 @@ export const ProFeatures = ({ count = 6 }) => {
size={SIZE.xs}
style={{
textDecorationLine: "underline",
color: colors.secondary.paragraph
color: colors.icon
}}
>
See all features included in Notesnook Pro

View File

@@ -34,8 +34,7 @@ import {
} from "../../../services/event-manager";
import Navigation from "../../../services/navigation";
import SearchService from "../../../services/search";
import { convertNoteToText } from "../../../utils/note-to-text";
import { getElevationStyle } from "../../../utils/elevation";
import { getElevation, toTXT } from "../../../utils";
import {
eClearEditor,
eCloseActionSheet,
@@ -565,7 +564,7 @@ export class VaultDialog extends Component {
}
async _copyNote(note) {
Clipboard.setString(await convertNoteToText(note));
Clipboard.setString(await toTXT(note));
ToastEvent.show({
heading: "Note copied",
type: "success",
@@ -581,7 +580,7 @@ export class VaultDialog extends Component {
await Share.open({
heading: "Share note",
failOnCancel: false,
message: await convertNoteToText(note)
message: await toTXT(note)
});
} catch (e) {
console.error(e);
@@ -679,10 +678,10 @@ export class VaultDialog extends Component {
>
<View
style={{
...getElevationStyle(5),
...getElevation(5),
width: DDS.isTab ? 350 : "85%",
borderRadius: 10,
backgroundColor: colors.primary.background,
backgroundColor: colors.bg,
paddingTop: 12
}}
>
@@ -867,12 +866,7 @@ export class VaultDialog extends Component {
icon="fingerprint"
width="100%"
title="Biometric unlocking"
iconColor={
this.state.biometricUnlock
? colors.selected.icon
: colors.primary.icon
}
type={this.state.biometricUnlock ? "transparent" : "selected"}
type={this.state.biometricUnlock ? "transparent" : "gray"}
/>
) : null}
</View>

View File

@@ -27,14 +27,14 @@ import {
} from "../../services/event-manager";
import useNavigationStore from "../../stores/use-navigation-store";
import { useSelectionStore } from "../../stores/use-selection-store";
import { useThemeColors } from "@notesnook/theme";
import { useThemeStore } from "../../stores/use-theme-store";
import { eScrollEvent } from "../../utils/events";
import { LeftMenus } from "./left-menus";
import { RightMenus } from "./right-menus";
import { Title } from "./title";
const _Header = () => {
const { colors } = useThemeColors();
const colors = useThemeStore((state) => state.colors);
const insets = useGlobalSafeAreaInsets();
const [hide, setHide] = useState(true);
const selectionMode = useSelectionStore((state) => state.selectionMode);
@@ -69,12 +69,10 @@ const _Header = () => {
styles.container,
{
marginTop: Platform.OS === "android" ? insets.top : null,
backgroundColor: colors.primary.background,
backgroundColor: colors.bg,
overflow: "hidden",
borderBottomWidth: 1,
borderBottomColor: hide
? "transparent"
: colors.secondary.background,
borderBottomColor: hide ? "transparent" : colors.nav,
justifyContent: "space-between"
}
]}

View File

@@ -23,12 +23,12 @@ import { DDS } from "../../services/device-detection";
import Navigation from "../../services/navigation";
import useNavigationStore from "../../stores/use-navigation-store";
import { useSettingStore } from "../../stores/use-setting-store";
import { useThemeColors } from "@notesnook/theme";
import { useThemeStore } from "../../stores/use-theme-store";
import { tabBarRef } from "../../utils/global-refs";
import { IconButton } from "../ui/icon-button";
export const LeftMenus = () => {
const { colors } = useThemeColors();
const colors = useThemeStore((state) => state.colors);
const deviceMode = useSettingStore((state) => state.deviceMode);
const canGoBack = useNavigationStore((state) => state.canGoBack);
const isTablet = deviceMode === "tablet";
@@ -61,17 +61,17 @@ export const LeftMenus = () => {
width: 40,
borderRadius: 100,
marginLeft: -5,
marginRight: DDS.isLargeTablet() ? 10 : 7
marginRight: DDS.isLargeTablet() ? 10 : 25
}}
left={40}
top={40}
right={DDS.isLargeTablet() ? 10 : 10}
right={DDS.isLargeTablet() ? 10 : 25}
onPress={onLeftButtonPress}
onLongPress={() => {
Navigation.popToTop();
}}
name={canGoBack ? "arrow-left" : "menu"}
color={colors.primary.paragraph}
color={colors.pri}
iconStyle={{
marginLeft: canGoBack ? -5 : 0
}}

View File

@@ -25,15 +25,14 @@ import Navigation from "../../services/navigation";
import SearchService from "../../services/search";
import useNavigationStore from "../../stores/use-navigation-store";
import { useSettingStore } from "../../stores/use-setting-store";
import { useThemeColors } from "@notesnook/theme";
import { useThemeStore } from "../../stores/use-theme-store";
import { SIZE } from "../../utils/size";
import { sleep } from "../../utils/time";
import { Button } from "../ui/button";
import { IconButton } from "../ui/icon-button";
export const RightMenus = () => {
const { colors } = useThemeColors();
const { colors: contextMenuColors } = useThemeColors("contextMenu");
const colors = useThemeStore((state) => state.colors);
const deviceMode = useSettingStore((state) => state.deviceMode);
const rightButtons = useNavigationStore((state) => state.headerRightButtons);
const currentScreen = useNavigationStore((state) => state.currentScreen.name);
@@ -52,7 +51,7 @@ export const RightMenus = () => {
}}
testID="icon-search"
name="magnify"
color={colors.primary.paragraph}
color={colors.pri}
customStyle={styles.rightBtn}
/>
) : null}
@@ -77,7 +76,7 @@ export const RightMenus = () => {
borderRadius: 5,
paddingHorizontal: 0,
borderWidth: 1,
borderColor: colors.primary.accent
borderColor: colors.accent
}}
/>
) : null}
@@ -88,7 +87,7 @@ export const RightMenus = () => {
animationDuration={200}
style={{
borderRadius: 5,
backgroundColor: contextMenuColors.primary.background
backgroundColor: colors.bg
}}
onRequestClose={() => {
menuRef.current?.hide();
@@ -99,7 +98,7 @@ export const RightMenus = () => {
menuRef.current?.show();
}}
name="dots-vertical"
color={colors.primary.paragraph}
color={colors.pri}
customStyle={styles.rightBtn}
/>
}
@@ -113,7 +112,7 @@ export const RightMenus = () => {
}}
type="gray"
buttonType={{
text: contextMenuColors.primary.paragraph
text: colors.pri
}}
key={item.title}
title={item.title}

View File

@@ -26,7 +26,7 @@ import {
eUnSubscribeEvent
} from "../../services/event-manager";
import useNavigationStore from "../../stores/use-navigation-store";
import { useThemeColors } from "@notesnook/theme";
import { useThemeStore } from "../../stores/use-theme-store";
import { eScrollEvent } from "../../utils/events";
import { SIZE } from "../../utils/size";
import Heading from "../ui/typography/heading";
@@ -36,7 +36,7 @@ import Tag from "../ui/tag";
const titleState = {};
export const Title = () => {
const { colors } = useThemeColors();
const colors = useThemeStore((state) => state.colors);
const currentScreen = useNavigationStore((state) => state.currentScreen);
const isNotebook = currentScreen.name === "Notebook";
const isTopic = currentScreen?.name === "TopicNotes";
@@ -110,15 +110,15 @@ export const Title = () => {
<Heading
onPress={navigateToNotebook}
numberOfLines={1}
size={SIZE.lg}
size={SIZE.xl}
style={{
flexWrap: "wrap",
marginTop: Platform.OS === "ios" ? -1 : 0
}}
color={currentScreen.color || colors.primary.heading}
color={currentScreen.color || colors.heading}
>
{isTag ? (
<Heading size={SIZE.xl} color={colors.primary.accent}>
<Heading size={SIZE.xl} color={colors.accent}>
#
</Heading>
) : null}

View File

@@ -17,9 +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 Sodium from "@ammarahmed/react-native-sodium";
import dataurl from "@notesnook/core/utils/dataurl";
import { useThemeColors } from "@notesnook/theme";
import React, { useEffect, useState } from "react";
import { Platform, View } from "react-native";
import ImageViewer from "react-native-image-zoom-viewer";
@@ -29,13 +26,15 @@ import {
eSubscribeEvent,
eUnSubscribeEvent
} from "../../services/event-manager";
import { useThemeStore } from "../../stores/use-theme-store";
import BaseDialog from "../dialog/base-dialog";
import { IconButton } from "../ui/icon-button";
import { ProgressBarComponent } from "../ui/svg/lazy";
import Sodium from "@ammarahmed/react-native-sodium";
import dataurl from "@notesnook/core/utils/dataurl";
const ImagePreview = () => {
const { colors } = useThemeColors("dialog");
const colors = useThemeStore((state) => state.colors);
const [visible, setVisible] = useState(false);
const [image, setImage] = useState("");
const [loading, setLoading] = useState(false);
@@ -98,7 +97,7 @@ const ImagePreview = () => {
>
<ProgressBarComponent
indeterminate
color={colors.primary.accent}
color={colors.accent}
borderColor="transparent"
/>
</View>

View File

@@ -17,34 +17,32 @@ 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 { useThemeColors } from "@notesnook/theme";
import React from "react";
import {
Linking,
ScrollView,
TouchableOpacity,
useWindowDimensions,
View
} from "react-native";
import { SwiperFlatList } from "react-native-swiper-flatlist";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { getElevationStyle } from "../../utils/elevation";
import useGlobalSafeAreaInsets from "../../hooks/use-global-safe-area-insets";
import SettingsService from "../../services/settings";
import { useSettingStore } from "../../stores/use-setting-store";
import { useThemeStore } from "../../stores/use-theme-store";
import { getElevation } from "../../utils";
import { SIZE } from "../../utils/size";
import { Button } from "../ui/button";
import Heading from "../ui/typography/heading";
import Paragraph from "../ui/typography/paragraph";
const Intro = ({ navigation }) => {
const { colors } = useThemeColors();
const colors = useThemeStore((state) => state.colors);
const isTelemetryEnabled = useSettingStore(
(state) => state.settings.telemetry
);
const { width, height } = useWindowDimensions();
const { width } = useWindowDimensions();
const deviceMode = useSettingStore((state) => state.deviceMode);
const insets = useGlobalSafeAreaInsets();
const renderItem = React.useCallback(
({ item }) => (
<View
@@ -64,7 +62,7 @@ const Intro = ({ navigation }) => {
style={{
width: 100,
height: 5,
backgroundColor: colors.primary.accent,
backgroundColor: colors.accent,
borderRadius: 2,
marginRight: 7
}}
@@ -74,7 +72,7 @@ const Intro = ({ navigation }) => {
style={{
width: 20,
height: 5,
backgroundColor: colors.secondary.background,
backgroundColor: colors.nav,
borderRadius: 2
}}
/>
@@ -82,6 +80,7 @@ const Intro = ({ navigation }) => {
<View
style={{
marginTop: 10,
marginBottom: 20,
maxWidth: "90%",
width: "100%"
}}
@@ -117,31 +116,30 @@ const Intro = ({ navigation }) => {
</View>
</View>
),
[colors.primary.accent, colors.secondary.background, deviceMode, width]
[colors.accent, colors.nav, deviceMode, width]
);
return (
<ScrollView
<View
testID="notesnook.splashscreen"
style={{
width: "100%"
width: "100%",
height: "100%"
}}
>
<View
style={{
flex: 0.65,
width: deviceMode !== "mobile" ? width / 2 : "100%",
backgroundColor: colors.secondary.background,
backgroundColor: colors.nav,
marginBottom: 20,
borderBottomWidth: 1,
borderBottomColor: colors.primary.border,
borderBottomColor: colors.border,
alignSelf: deviceMode !== "mobile" ? "center" : undefined,
borderWidth: deviceMode !== "mobile" ? 1 : null,
borderColor: deviceMode !== "mobile" ? colors.primary.border : null,
borderColor: deviceMode !== "mobile" ? colors.border : null,
borderRadius: deviceMode !== "mobile" ? 20 : null,
marginTop: deviceMode !== "mobile" ? 50 : null,
paddingTop: insets.top + 10,
paddingBottom: insets.top + 10,
minHeight: height * 0.7
marginTop: deviceMode !== "mobile" ? 50 : null
}}
>
<SwiperFlatList
@@ -171,14 +169,14 @@ const Intro = ({ navigation }) => {
user: "@andrewsayer on Twitter"
}
]}
paginationActiveColor={colors.primary.accent}
paginationActiveColor={colors.accent}
paginationStyleItem={{
width: 10,
height: 5,
marginRight: 4,
marginLeft: 4
}}
paginationDefaultColor={colors.primary.border}
paginationDefaultColor={colors.border}
renderItem={renderItem}
/>
</View>
@@ -186,8 +184,8 @@ const Intro = ({ navigation }) => {
<View
style={{
width: "100%",
justifyContent: "center",
minHeight: height * 0.3
flex: 0.3,
justifyContent: "center"
}}
>
<Button
@@ -200,7 +198,7 @@ const Intro = ({ navigation }) => {
style={{
paddingHorizontal: 24,
alignSelf: "center",
...getElevationStyle(5),
...getElevation(5),
borderRadius: 100
}}
fontSize={SIZE.md}
@@ -229,9 +227,7 @@ const Intro = ({ navigation }) => {
name={
isTelemetryEnabled ? "checkbox-marked" : "checkbox-blank-outline"
}
color={
isTelemetryEnabled ? colors.primary.accent : colors.primary.icon
}
color={isTelemetryEnabled ? colors.accent : colors.icon}
/>
<Paragraph
@@ -246,7 +242,7 @@ const Intro = ({ navigation }) => {
</Paragraph>
</TouchableOpacity>
</View>
</ScrollView>
</View>
);
};

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,339 @@
/*
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 notifee from "@notifee/react-native";
import React, { useCallback, useEffect, useRef } from "react";
import { Platform, View } from "react-native";
import RNBootSplash from "react-native-bootsplash";
import { checkVersion } from "react-native-check-version";
import Config from "react-native-config";
import { enabled } from "react-native-privacy-snapshot";
import { DatabaseLogger, db } from "../../common/database";
import { useAppState } from "../../hooks/use-app-state";
import BiometricService from "../../services/biometrics";
import { eSendEvent, presentSheet } from "../../services/event-manager";
import { setRateAppMessage } from "../../services/message";
import PremiumService from "../../services/premium";
import SettingsService from "../../services/settings";
import { initialize } from "../../stores";
import { useMessageStore } from "../../stores/use-message-store";
import { useNoteStore } from "../../stores/use-notes-store";
import { useSettingStore } from "../../stores/use-setting-store";
import { useThemeStore } from "../../stores/use-theme-store";
import { useUserStore } from "../../stores/use-user-store";
import { AndroidModule } from "../../utils";
import { eOpenAnnouncementDialog } from "../../utils/events";
import { getGithubVersion } from "../../utils/github-version";
import { SIZE } from "../../utils/size";
import { sleep } from "../../utils/time";
import Migrate from "../sheets/migrate";
import NewFeature from "../sheets/new-feature/index";
import { Update } from "../sheets/update";
import { Button } from "../ui/button";
import { IconButton } from "../ui/icon-button";
import Input from "../ui/input";
import Seperator from "../ui/seperator";
import Heading from "../ui/typography/heading";
import Paragraph from "../ui/typography/paragraph";
import { Walkthrough } from "../walkthroughs";
const Launcher = React.memo(
function Launcher() {
const colors = useThemeStore((state) => state.colors);
const setLoading = useNoteStore((state) => state.setLoading);
const loading = useNoteStore((state) => state.loading);
const user = useUserStore((state) => state.user);
const verifyUser = useUserStore((state) => state.verifyUser);
const setVerifyUser = useUserStore((state) => state.setVerifyUser);
const deviceMode = useSettingStore((state) => state.deviceMode);
const appState = useAppState();
const passwordInputRef = useRef();
const password = useRef();
const introCompleted = useSettingStore(
(state) => state.settings.introCompleted
);
const verifying = useRef(false);
const loadNotes = useCallback(async () => {
if (verifyUser) {
return;
}
setImmediate(() => {
db.notes.init().then(() => {
Walkthrough.init();
initialize();
setImmediate(() => {
setLoading(false);
});
});
});
}, [setLoading, verifyUser]);
const init = useCallback(async () => {
if (!db.isInitialized) {
RNBootSplash.hide({ fade: true });
DatabaseLogger.info("Initializing database");
await db.init();
}
if (db.migrations.required() && !verifyUser) {
presentSheet({
component: <Migrate />,
onClose: async () => {
if (!db.isInitialized) {
await db.init();
}
loadNotes();
},
disableClosing: true
});
return;
}
if (!verifyUser) {
loadNotes();
} else {
useUserStore.getState().setUser(await db.user?.getUser());
}
}, [loadNotes, verifyUser]);
useEffect(() => {
if (!loading) {
doAppLoadActions();
}
}, [doAppLoadActions, loading]);
const doAppLoadActions = useCallback(async () => {
await sleep(500);
if (SettingsService.get().sessionExpired) {
eSendEvent("session_expired");
return;
}
notifee.setBadgeCount(0);
await useMessageStore.getState().setAnnouncement();
if (NewFeature.present()) return;
if (await checkAppUpdateAvailable()) return;
if (await checkForRateAppRequest()) return;
if (await PremiumService.getRemainingTrialDaysStatus()) return;
if (introCompleted) {
useMessageStore.subscribe((state) => {
let dialogs = state.dialogs;
if (dialogs.length > 0) {
eSendEvent(eOpenAnnouncementDialog, dialogs[0]);
}
});
}
}, [introCompleted]);
const checkAppUpdateAvailable = async () => {
if (__DEV__ || Config.isTesting === "true") return;
try {
const version =
Config.GITHUB_RELEASE === "true"
? await getGithubVersion()
: await checkVersion();
if (!version || !version?.needsUpdate) return false;
presentSheet({
component: (ref) => <Update version={version} fwdRef={ref} />
});
return true;
} catch (e) {
return false;
}
};
const checkForRateAppRequest = async () => {
let rateApp = SettingsService.get().rateApp;
if (
rateApp &&
rateApp < Date.now() &&
!useMessageStore.getState().message?.visible
) {
setRateAppMessage();
return false;
}
return false;
};
const onUnlockBiometrics = useCallback(async () => {
if (!(await BiometricService.isBiometryAvailable())) return;
if (Platform.OS === "android") {
const activityName = await AndroidModule.getActivityName();
if (activityName !== "MainActivity") return;
}
let verified = await BiometricService.validateUser(
"Unlock to access your notes",
""
);
if (verified) {
setVerifyUser(false);
enabled(false);
password.current = null;
setTimeout(() => {
verifying.current = false;
}, 1);
}
}, [setVerifyUser]);
useEffect(() => {
init();
}, [init, verifyUser]);
useEffect(() => {
if (verifying.current || useUserStore.getState().shouldBlockVerifyUser)
return;
if (verifyUser && appState === "active") {
verifying.current = true;
onUnlockBiometrics();
}
}, [appState, onUnlockBiometrics, verifyUser]);
const onSubmit = async () => {
if (!password.current) return;
try {
let verified = await db.user.verifyPassword(password.current);
if (verified) {
setVerifyUser(false);
enabled(false);
password.current = null;
}
} catch (e) {
console.error(e);
}
};
return verifyUser ? (
<View
style={{
backgroundColor: colors.bg,
width: "100%",
height: "100%",
position: "absolute",
zIndex: 999,
justifyContent: "center"
}}
>
<View
style={{
flex: 1,
justifyContent: "center",
width:
deviceMode !== "mobile"
? "50%"
: Platform.OS == "ios"
? "95%"
: "100%",
paddingHorizontal: 12,
marginBottom: 30,
marginTop: 15,
alignSelf: "center"
}}
>
<IconButton
name="fingerprint"
size={100}
customStyle={{
width: 100,
height: 100,
marginBottom: 20,
marginTop: user ? 0 : 50
}}
onPress={onUnlockBiometrics}
color={colors.border}
/>
<Heading
color={colors.heading}
style={{
alignSelf: "center",
textAlign: "center"
}}
>
Unlock your notes
</Heading>
<Paragraph
style={{
alignSelf: "center",
textAlign: "center",
maxWidth: "90%"
}}
>
{"Please verify it's you"}
</Paragraph>
<Seperator />
<View
style={{
width: "100%",
padding: 12,
backgroundColor: colors.bg
}}
>
{user ? (
<>
<Input
fwdRef={passwordInputRef}
secureTextEntry
placeholder="Enter account password"
onChangeText={(v) => (password.current = v)}
onSubmit={onSubmit}
/>
</>
) : null}
<View
style={{
marginTop: user ? 25 : 25
}}
>
{user ? (
<>
<Button
title="Continue"
type="accent"
onPress={onSubmit}
width={250}
height={45}
style={{
borderRadius: 150,
marginBottom: 10
}}
fontSize={SIZE.md}
/>
</>
) : null}
<Button
title="Unlock with Biometrics"
width={250}
onPress={onUnlockBiometrics}
icon={"fingerprint"}
type={user ? "grayAccent" : "accent"}
/>
</View>
</View>
</View>
</View>
) : null;
},
() => true
);
export default Launcher;

View File

@@ -19,9 +19,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import React from "react";
import { View } from "react-native";
import { useThemeColors } from "@notesnook/theme";
import { useThemeStore } from "../../../stores/use-theme-store";
import { useMessageStore } from "../../../stores/use-message-store";
import { ColorValues } from "../../../utils/colors";
import { COLORS_NOTE } from "../../../utils/color-scheme";
import { Announcement } from "../../announcements/announcement";
import { Card } from "../../list/card";
import Paragraph from "../../ui/typography/paragraph";
@@ -37,7 +37,7 @@ export const Header = React.memo(
noAnnouncement,
warning
}) => {
const { colors } = useThemeColors();
const colors = useThemeStore((state) => state.colors);
const announcements = useMessageStore((state) => state.announcements);
const selectionMode = useSelectionStore((state) => state.selectionMode);
@@ -47,7 +47,7 @@ export const Header = React.memo(
<View
style={{
padding: 12,
backgroundColor: colors.error.background,
backgroundColor: colors.errorBg,
width: "95%",
alignSelf: "center",
borderRadius: 5,
@@ -55,18 +55,13 @@ export const Header = React.memo(
alignItems: "center"
}}
>
<Icon
name="sync-alert"
size={SIZE.md}
color={colors.error.icon}
f
/>
<Paragraph style={{ marginLeft: 5 }} color={colors.error.icon}>
<Icon name="sync-alert" size={SIZE.md} color={colors.red} f />
<Paragraph style={{ marginLeft: 5 }} color={colors.red}>
{warning.title}
</Paragraph>
</View>
) : announcements.length !== 0 && !noAnnouncement ? (
<Announcement color={color || colors.primary.accent} />
<Announcement color={color || colors.accent} />
) : type === "search" ? null : !shouldShow ? (
<View
style={{
@@ -79,9 +74,7 @@ export const Header = React.memo(
>
{messageCard ? (
<Card
color={
ColorValues[color?.toLowerCase()] || colors.primary.accent
}
color={COLORS_NOTE[color?.toLowerCase()] || colors.accent}
/>
) : null}
</View>

View File

@@ -20,10 +20,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import { useRef, useState } from "react";
import React from "react";
import { View } from "react-native";
import { useThemeColors } from "@notesnook/theme";
import { useThemeStore } from "../../../stores/use-theme-store";
import { useMenuStore } from "../../../stores/use-menu-store";
import { ToastEvent } from "../../../services/event-manager";
import { getTotalNotes } from "@notesnook/common";
import { getTotalNotes } from "../../../utils";
import { db } from "../../../common/database";
import { SIZE } from "../../../utils/size";
import { IconButton } from "../../ui/icon-button";
@@ -31,7 +31,7 @@ import Heading from "../../ui/typography/heading";
import Paragraph from "../../ui/typography/paragraph";
export const NotebookHeader = ({ notebook, onEditNotebook }) => {
const { colors } = useThemeColors();
const colors = useThemeStore((state) => state.colors);
const [isPinnedToMenu, setIsPinnedToMenu] = useState(
db.shortcuts.exists(notebook.id)
);
@@ -75,7 +75,7 @@ export const NotebookHeader = ({ notebook, onEditNotebook }) => {
paddingTop: 25
}}
>
<Paragraph color={colors.secondary.paragraph} size={SIZE.xs}>
<Paragraph color={colors.icon} size={SIZE.xs}>
{new Date(notebook.dateEdited).toLocaleString()}
</Paragraph>
<View
@@ -110,7 +110,7 @@ export const NotebookHeader = ({ notebook, onEditNotebook }) => {
height: 40
}}
type={isPinnedToMenu ? "grayBg" : "grayBg"}
color={isPinnedToMenu ? colors.primary.accent : colors.primary.icon}
color={isPinnedToMenu ? colors.accent : colors.icon}
size={SIZE.lg}
/>
<IconButton
@@ -119,7 +119,7 @@ export const NotebookHeader = ({ notebook, onEditNotebook }) => {
tooltipText="Edit this notebook"
name="pencil"
type="grayBg"
color={colors.primary.icon}
color={colors.icon}
customStyle={{
width: 40,
height: 40
@@ -129,7 +129,7 @@ export const NotebookHeader = ({ notebook, onEditNotebook }) => {
</View>
{notebook.description ? (
<Paragraph size={SIZE.md} color={colors.primary.paragraph}>
<Paragraph size={SIZE.md} color={colors.pri}>
{notebook.description}
</Paragraph>
) : null}
@@ -141,7 +141,7 @@ export const NotebookHeader = ({ notebook, onEditNotebook }) => {
fontFamily: null
}}
size={SIZE.xs}
color={colors.secondary.paragraph}
color={colors.icon}
>
{notebook.topics.length === 1
? "1 topic"

View File

@@ -19,7 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import React, { useEffect, useRef, useState } from "react";
import { TouchableOpacity, useWindowDimensions, View } from "react-native";
import { useThemeColors } from "@notesnook/theme";
import { useThemeStore } from "../../../stores/use-theme-store";
import { useSettingStore } from "../../../stores/use-setting-store";
import {
eSendEvent,
@@ -29,7 +29,7 @@ import {
} from "../../../services/event-manager";
import SettingsService from "../../../services/settings";
import { GROUP } from "../../../utils/constants";
import { ColorValues } from "../../../utils/colors";
import { COLORS_NOTE } from "../../../utils/color-scheme";
import { db } from "../../../common/database";
import { eOpenJumpToDialog } from "../../../utils/events";
import { SIZE } from "../../../utils/size";
@@ -41,7 +41,7 @@ import { useCallback } from "react";
export const SectionHeader = React.memo(
function SectionHeader({ item, index, type, color, screen }) {
const { colors } = useThemeColors();
const colors = useThemeStore((state) => state.colors);
const { fontScale } = useWindowDimensions();
const [groupOptions, setGroupOptions] = useState(
db.settings?.getGroupOptions(type)
@@ -85,7 +85,7 @@ export const SectionHeader = React.memo(
justifyContent: "space-between",
paddingHorizontal: 12,
height: 35 * fontScale,
backgroundColor: colors.secondary.background,
backgroundColor: colors.nav,
alignSelf: "center",
borderRadius: 5,
marginVertical: 5
@@ -104,7 +104,7 @@ export const SectionHeader = React.memo(
}}
>
<Heading
color={ColorValues[color?.toLowerCase()] || colors.primary.accent}
color={COLORS_NOTE[color?.toLowerCase()] || colors.accent}
size={SIZE.sm}
style={{
minWidth: 60,
@@ -168,7 +168,7 @@ export const SectionHeader = React.memo(
: "Switch to compact mode"
}
fwdRef={compactModeRef}
color={colors.secondary.icon}
color={colors.icon}
name={listMode == "compact" ? "view-list" : "view-list-outline"}
onPress={() => {
let settings = {};

View File

@@ -29,8 +29,9 @@ import { TaggedNotes } from "../../../screens/notes/tagged";
import { TopicNotes } from "../../../screens/notes/topic-notes";
import useNavigationStore from "../../../stores/use-navigation-store";
import { useRelationStore } from "../../../stores/use-relation-store";
import { useThemeColors } from "@notesnook/theme";
import { ColorValues } from "../../../utils/colors";
import { useSettingStore } from "../../../stores/use-setting-store";
import { useThemeStore } from "../../../stores/use-theme-store";
import { COLORS_NOTE } from "../../../utils/color-scheme";
import { SIZE } from "../../../utils/size";
import { Properties } from "../../properties";
import { Button } from "../../ui/button";
@@ -39,7 +40,6 @@ import { ReminderTime } from "../../ui/reminder-time";
import { TimeSince } from "../../ui/time-since";
import Heading from "../../ui/typography/heading";
import Paragraph from "../../ui/typography/paragraph";
import { useIsCompactModeEnabled } from "../../../hooks/use-is-compact-mode-enabled";
function navigateToTag(item) {
const tag = db.tags.tag(item.id);
@@ -98,15 +98,18 @@ const NoteItem = ({
dateBy = "dateCreated",
noOpen = false
}) => {
const { colors } = useThemeColors();
const compactMode = useIsCompactModeEnabled(item);
const colors = useThemeStore((state) => state.colors);
const notesListMode = useSettingStore(
(state) => state.settings.notesListMode
);
const compactMode = notesListMode === "compact";
const attachmentCount = db.attachments?.ofNote(item.id, "all")?.length || 0;
const _update = useRelationStore((state) => state.updater);
// eslint-disable-next-line react-hooks/exhaustive-deps
const notebooks = React.useMemo(() => getNotebook(item), [item, _update]);
const reminders = db.relations.from(item, "reminder");
const reminder = getUpcomingReminder(reminders);
const noteColor = ColorValues[item.color?.toLowerCase()];
const noteColor = COLORS_NOTE[item.color?.toLowerCase()];
const tags = getTags(item);
return (
<>
@@ -148,7 +151,7 @@ const NoteItem = ({
borderRadius: 5,
marginRight: 5,
borderWidth: 0.5,
borderColor: colors.primary.border,
borderColor: colors.icon,
paddingHorizontal: 6,
marginBottom: 5
}}
@@ -178,9 +181,7 @@ const NoteItem = ({
{compactMode ? (
<Paragraph
numberOfLines={1}
color={
ColorValues[item.color?.toLowerCase()] || colors.primary.heading
}
color={COLORS_NOTE[item.color?.toLowerCase()] || colors.heading}
style={{
flexWrap: "wrap"
}}
@@ -191,9 +192,7 @@ const NoteItem = ({
) : (
<Heading
numberOfLines={1}
color={
ColorValues[item.color?.toLowerCase()] || colors.primary.heading
}
color={COLORS_NOTE[item.color?.toLowerCase()] || colors.heading}
style={{
flexWrap: "wrap"
}}
@@ -236,13 +235,13 @@ const NoteItem = ({
marginRight: 6
}}
size={SIZE.sm}
color={colors.error.accent}
color={colors.red}
/>
) : null}
<TimeSince
style={{
fontSize: SIZE.xs,
color: colors.secondary.paragraph,
color: colors.icon,
marginRight: 6
}}
time={item[dateBy]}
@@ -262,12 +261,9 @@ const NoteItem = ({
<Icon
name="attachment"
size={SIZE.md}
color={colors.primary.icon}
color={colors.icon}
/>
<Paragraph
color={colors.secondary.paragraph}
size={SIZE.xs}
>
<Paragraph color={colors.icon} size={SIZE.xs}>
{attachmentCount}
</Paragraph>
</View>
@@ -282,8 +278,7 @@ const NoteItem = ({
marginRight: 6
}}
color={
ColorValues[item.color?.toLowerCase()] ||
colors.primary.accent
COLORS_NOTE[item.color?.toLowerCase()] || colors.accent
}
/>
) : null}
@@ -296,7 +291,7 @@ const NoteItem = ({
style={{
marginRight: 6
}}
color={colors.primary.icon}
color={colors.icon}
/>
) : null}
@@ -341,7 +336,7 @@ const NoteItem = ({
) : (
<>
<Paragraph
color={colors.secondary.paragraph}
color={colors.icon}
size={SIZE.xs}
style={{
marginRight: 6
@@ -354,7 +349,7 @@ const NoteItem = ({
</Paragraph>
<Paragraph
color={colors.primary.accent}
color={colors.accent}
size={SIZE.xs}
style={{
marginRight: 6
@@ -382,7 +377,7 @@ const NoteItem = ({
marginRight: 6
}}
size={SIZE.sm}
color={colors.error.accent}
color={colors.red}
/>
) : null}
@@ -394,7 +389,7 @@ const NoteItem = ({
style={{
marginRight: 6
}}
color={colors.secondary.background}
color={colors.icon}
/>
) : null}
@@ -413,7 +408,7 @@ const NoteItem = ({
<TimeSince
style={{
fontSize: SIZE.xs,
color: colors.secondary.paragraph,
color: colors.icon,
marginRight: 6
}}
time={item[dateBy]}
@@ -424,7 +419,7 @@ const NoteItem = ({
<IconButton
testID={notesnook.listitem.menu}
color={colors.primary.paragraph}
color={colors.pri}
name="dots-horizontal"
size={SIZE.xl}
onPress={() => !noOpen && showActionSheet(item, isTrash)}

View File

@@ -30,6 +30,7 @@ import {
} from "../../../services/event-manager";
import { useEditorStore } from "../../../stores/use-editor-store";
import { useSelectionStore } from "../../../stores/use-selection-store";
import { history } from "../../../utils";
import { eOnLoadNote, eShowMergeDialog } from "../../../utils/events";
import { tabBarRef } from "../../../utils/global-refs";
import { presentDialog } from "../../dialog/functions";
@@ -58,14 +59,12 @@ export const openNote = async (item, isTrash, setSelectedItem, isSheet) => {
return;
}
}
const { selectedItemsList, selectionMode, clearSelection } =
useSelectionStore.getState();
if (selectedItemsList.length > 0 && selectionMode) {
if (history.selectedItemsList.length > 0 && history.selectionMode) {
setSelectedItem && setSelectedItem(_note);
return;
} else {
clearSelection();
history.selectedItemsList = [];
}
if (_note.conflicted) {

View File

@@ -22,23 +22,23 @@ import { View } from "react-native";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { notesnook } from "../../../../e2e/test.ids";
import { TopicNotes } from "../../../screens/notes/topic-notes";
import { useSelectionStore } from "../../../stores/use-selection-store";
import { useThemeColors } from "@notesnook/theme";
import { useSettingStore } from "../../../stores/use-setting-store";
import { useThemeStore } from "../../../stores/use-theme-store";
import { history } from "../../../utils";
import { SIZE } from "../../../utils/size";
import { Properties } from "../../properties";
import { Button } from "../../ui/button";
import { IconButton } from "../../ui/icon-button";
import Heading from "../../ui/typography/heading";
import Paragraph from "../../ui/typography/paragraph";
import { getFormattedDate } from "@notesnook/common";
import { useIsCompactModeEnabled } from "../../../hooks/use-is-compact-mode-enabled";
import { getFormattedDate } from "../../../utils/time";
const showActionSheet = (item) => {
Properties.present(item);
};
const navigateToTopic = (topic) => {
if (useSelectionStore.getState().selectedItemsList.length > 0) return;
if (history.selectedItemsList.length > 0) return;
TopicNotes.navigate(topic, true);
};
@@ -49,8 +49,11 @@ export const NotebookItem = ({
dateBy,
totalNotes
}) => {
const { colors } = useThemeColors();
const compactMode = useIsCompactModeEnabled(item);
const colors = useThemeStore((state) => state.colors);
const notebooksListMode = useSettingStore(
(state) => state.settings.notebooksListMode
);
const compactMode = notebooksListMode === "compact";
const topics = item.topics?.slice(0, 3) || [];
return (
@@ -109,6 +112,8 @@ export const NotebookItem = ({
key={topic.id}
height={null}
textStyle={{
fontWeight: "normal",
fontFamily: null,
marginRight: 0
}}
type="grayBg"
@@ -120,7 +125,7 @@ export const NotebookItem = ({
maxWidth: 120,
borderWidth: 0.5,
paddingVertical: 2.5,
borderColor: colors.primary.border,
borderColor: colors.icon,
paddingHorizontal: 6,
marginVertical: 5,
marginRight: 5
@@ -144,7 +149,7 @@ export const NotebookItem = ({
{isTrash ? (
<>
<Paragraph
color={colors.secondary.paragraph}
color={colors.icon}
size={SIZE.xs}
style={{
textAlignVertical: "center",
@@ -155,7 +160,7 @@ export const NotebookItem = ({
new Date(item.dateDeleted).toISOString().slice(0, 10)}
</Paragraph>
<Paragraph
color={colors.primary.accent}
color={colors.accent}
size={SIZE.xs}
style={{
textAlignVertical: "center",
@@ -167,7 +172,7 @@ export const NotebookItem = ({
</>
) : (
<Paragraph
color={colors.secondary.paragraph}
color={colors.icon}
size={SIZE.xs}
style={{
marginRight: 6
@@ -177,7 +182,7 @@ export const NotebookItem = ({
</Paragraph>
)}
<Paragraph
color={colors.secondary.paragraph}
color={colors.icon}
size={SIZE.xs}
style={{
marginRight: 6
@@ -198,7 +203,7 @@ export const NotebookItem = ({
marginRight: 10,
marginTop: 2
}}
color={colors.primary.accent}
color={colors.accent}
/>
) : null}
</View>
@@ -213,7 +218,7 @@ export const NotebookItem = ({
{compactMode ? (
<>
<Paragraph
color={colors.primary.icon}
color={colors.icon}
size={SIZE.xs}
style={{
marginRight: 6
@@ -229,7 +234,7 @@ export const NotebookItem = ({
) : null}
<IconButton
color={colors.primary.heading}
color={colors.heading}
name="dots-horizontal"
testID={notesnook.ids.notebook.menu}
size={SIZE.xl}

View File

@@ -24,6 +24,7 @@ import { ToastEvent } from "../../../services/event-manager";
import Navigation from "../../../services/navigation";
import { useSelectionStore } from "../../../stores/use-selection-store";
import { useTrashStore } from "../../../stores/use-trash-store";
import { history } from "../../../utils";
import { db } from "../../../common/database";
import { presentDialog } from "../../dialog/functions";
import SelectionWrapper from "../selection-wrapper";
@@ -48,13 +49,11 @@ const navigateToNotebook = (item, canGoBack) => {
export const openNotebookTopic = (item) => {
const isTrash = item.type === "trash";
const { selectedItemsList, setSelectedItem, selectionMode, clearSelection } =
useSelectionStore.getState();
if (selectedItemsList.length > 0 && selectionMode) {
setSelectedItem(item);
if (history.selectedItemsList.length > 0 && history.selectionMode) {
useSelectionStore.getState().setSelectedItem(item);
return;
} else {
clearSelection();
history.selectedItemsList = [];
}
if (isTrash) {

View File

@@ -20,7 +20,7 @@ import React from "react";
import { View } from "react-native";
import { notesnook } from "../../../../e2e/test.ids";
import type { Reminder } from "../../../services/notifications";
import { useThemeColors } from "@notesnook/theme";
import { useThemeStore } from "../../../stores/use-theme-store";
import { SIZE } from "../../../utils/size";
import { Properties } from "../../properties";
import { IconButton } from "../../ui/icon-button";
@@ -41,7 +41,7 @@ const ReminderItem = React.memo(
index: number;
isSheet: boolean;
}) => {
const { colors } = useThemeColors();
const colors = useThemeStore((state) => state.colors);
const openReminder = () => {
ReminderSheet.present(item, undefined, isSheet);
};
@@ -90,7 +90,7 @@ const ReminderItem = React.memo(
{item.disabled ? (
<View
style={{
backgroundColor: colors.secondary.background,
backgroundColor: colors.nav,
borderRadius: 5,
flexDirection: "row",
paddingHorizontal: 6,
@@ -105,11 +105,11 @@ const ReminderItem = React.memo(
<Icon
name="bell-off-outline"
size={SIZE.md}
color={colors.error.icon}
color={colors.errorText}
/>
<Paragraph
size={SIZE.xs}
color={colors.secondary.paragraph}
color={colors.icon}
style={{ marginLeft: 5 }}
>
Disabled
@@ -119,7 +119,7 @@ const ReminderItem = React.memo(
{item.mode === "repeat" && item.recurringMode ? (
<View
style={{
backgroundColor: colors.secondary.background,
backgroundColor: colors.nav,
borderRadius: 5,
flexDirection: "row",
paddingHorizontal: 6,
@@ -131,10 +131,10 @@ const ReminderItem = React.memo(
height: 30
}}
>
<Icon name="reload" size={SIZE.md} color={colors.primary.accent} />
<Icon name="reload" size={SIZE.md} color={colors.accent} />
<Paragraph
size={SIZE.xs}
color={colors.secondary.paragraph}
color={colors.icon}
style={{ marginLeft: 5 }}
>
{item.recurringMode.slice(0, 1).toUpperCase() +
@@ -160,7 +160,7 @@ const ReminderItem = React.memo(
</View>
<IconButton
testID={notesnook.listitem.menu}
color={colors.primary.paragraph}
color={colors.pri}
name="dots-horizontal"
size={SIZE.xl}
onPress={() => Properties.present(item, [], isSheet)}

View File

@@ -17,36 +17,37 @@ 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 { useThemeColors } from "@notesnook/theme";
import React from "react";
import { View } from "react-native";
import useIsSelected from "../../../hooks/use-selected";
import { useEditorStore } from "../../../stores/use-editor-store";
import { useThemeStore } from "../../../stores/use-theme-store";
import { hexToRGBA } from "../../../utils/color-scheme/utils";
export const Filler = ({ item }) => {
const { colors } = useThemeColors();
const colors = useThemeStore((state) => state.colors);
const currentEditingNote = useEditorStore(
(state) => state.currentEditingNote
);
const [selected] = useIsSelected(item);
const color = "gray";
return currentEditingNote === item.id || selected ? (
return currentEditingNote === item.id ? (
<View
style={{
position: "absolute",
width: "110%",
height: "150%",
backgroundColor: colors.selected.background,
backgroundColor:
currentEditingNote === item.id
? hexToRGBA(colors[color], 0.12)
: null,
borderLeftWidth: 5,
borderLeftColor:
currentEditingNote === item.id
? item.color
? colors.static[item.color]
: colors.selected.accent
? colors[item.color || "accent"]
: "transparent"
}}
collapsable={false}
/>
></View>
) : null;
};

View File

@@ -17,10 +17,10 @@ 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 { useThemeColors } from "@notesnook/theme";
import React, { useRef } from "react";
import { useIsCompactModeEnabled } from "../../../hooks/use-is-compact-mode-enabled";
import { useSelectionStore } from "../../../stores/use-selection-store";
import { useSettingStore } from "../../../stores/use-setting-store";
import { useThemeStore } from "../../../stores/use-theme-store";
import { PressableButton } from "../../ui/pressable";
import { Filler } from "./back-fill";
import { SelectionIcon } from "./selection";
@@ -29,33 +29,51 @@ const SelectionWrapper = ({
children,
item,
background,
onLongPress,
onPress,
testID,
isSheet
}) => {
const itemId = useRef(item.id);
const { colors, isDark } = useThemeColors();
const compactMode = useIsCompactModeEnabled(item);
const colors = useThemeStore((state) => state.colors);
const notebooksListMode = useSettingStore(
(state) => state.settings.notebooksListMode
);
const notesListMode = useSettingStore(
(state) => state.settings.notesListMode
);
const listMode =
item.type === "notebook" || item.itemType === "notebook"
? notebooksListMode
: notesListMode;
const compactMode =
(item.type === "notebook" ||
item.itemType === "notebook" ||
item.itemType === "note" ||
item.type === "note") &&
listMode === "compact";
if (item.id !== itemId.current) {
itemId.current = item.id;
}
const onLongPress = () => {
const _onLongPress = () => {
if (!useSelectionStore.getState().selectionMode) {
useSelectionStore.getState().setSelectionMode(true);
}
useSelectionStore.getState().setSelectedItem(item);
};
const _onPress = async () => {
await onPress();
};
return (
<PressableButton
customColor={isSheet ? colors.primary.hover : "transparent"}
customColor={isSheet ? colors.transGray : "transparent"}
testID={testID}
onLongPress={onLongPress}
onPress={onPress}
customSelectedColor={colors.primary.hover}
customAlpha={!isDark ? -0.02 : 0.02}
onLongPress={_onLongPress}
onPress={_onPress}
customSelectedColor={colors.transGray}
customAlpha={!colors.night ? -0.02 : 0.02}
customOpacity={1}
customStyle={{
flexDirection: "row",

View File

@@ -17,21 +17,51 @@ 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 { useThemeColors } from "@notesnook/theme";
import React from "react";
import React, { useEffect, useState } from "react";
import { View } from "react-native";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { useIsCompactModeEnabled } from "../../../hooks/use-is-compact-mode-enabled";
import useIsSelected from "../../../hooks/use-selected";
import { useSelectionStore } from "../../../stores/use-selection-store";
import { useThemeStore } from "../../../stores/use-theme-store";
import { SIZE } from "../../../utils/size";
import { useSettingStore } from "../../../stores/use-setting-store";
export const SelectionIcon = ({ item }) => {
const { colors } = useThemeColors();
const selectionMode = useSelectionStore((state) => state.selectionMode);
const [selected] = useIsSelected(item);
const colors = useThemeStore((state) => state.colors);
const compactMode = useIsCompactModeEnabled(item);
const selectionMode = useSelectionStore((state) => state.selectionMode);
const selectedItemsList = useSelectionStore(
(state) => state.selectedItemsList
);
const [selected, setSelected] = useState(false);
const notebooksListMode = useSettingStore(
(state) => state.settings.notebooksListMode
);
const notesListMode = useSettingStore(
(state) => state.settings.notesListMode
);
const listMode = item.type === "notebook" ? notebooksListMode : notesListMode;
const compactMode =
(item.type === "notebook" || item.type === "note") &&
listMode === "compact";
useEffect(() => {
if (selectionMode) {
let exists = selectedItemsList.filter(
(o) => o.dateCreated === item.dateCreated
);
if (exists[0]) {
if (!selected) {
setSelected(true);
}
} else {
if (selected) {
setSelected(false);
}
}
}
}, [selectedItemsList, item.id, selectionMode, item.dateCreated, selected]);
return selectionMode ? (
<View
@@ -43,14 +73,14 @@ export const SelectionIcon = ({ item }) => {
marginRight: 10,
borderWidth: 1,
borderRadius: 100,
borderColor: colors.primary.border
borderColor: colors.border
}}
pointerEvents="none"
>
{selected ? (
<Icon
size={compactMode ? SIZE.xl - 2 : SIZE.xl}
color={selected ? colors.selected.accent : colors.primary.icon}
color={selected ? colors.accent : colors.icon}
name={"check"}
/>
) : null}

View File

@@ -21,7 +21,7 @@ import React from "react";
import { View } from "react-native";
import { notesnook } from "../../../../e2e/test.ids";
import { TaggedNotes } from "../../../screens/notes/tagged";
import { useThemeColors } from "@notesnook/theme";
import { useThemeStore } from "../../../stores/use-theme-store";
import { SIZE } from "../../../utils/size";
import { Properties } from "../../properties";
import { IconButton } from "../../ui/icon-button";
@@ -31,7 +31,7 @@ import Paragraph from "../../ui/typography/paragraph";
const TagItem = React.memo(
({ item, index }) => {
const { colors, isDark } = useThemeColors();
const colors = useThemeStore((state) => state.colors);
const onPress = () => {
TaggedNotes.navigate(item, true);
};
@@ -39,9 +39,9 @@ const TagItem = React.memo(
return (
<PressableButton
onPress={onPress}
selectedColor={colors.secondary.background}
selectedColor={colors.nav}
testID={notesnook.ids.tag.get(index)}
alpha={!isDark ? -0.02 : 0.02}
alpha={!colors.night ? -0.02 : 0.02}
opacity={1}
customStyle={{
paddingHorizontal: 12,
@@ -61,7 +61,7 @@ const TagItem = React.memo(
<Heading
size={SIZE.md}
style={{
color: colors.primary.accent
color: colors.accent
}}
>
#
@@ -69,7 +69,7 @@ const TagItem = React.memo(
{item.alias}
</Heading>
<Paragraph
color={colors.secondary.paragraph}
color={colors.icon}
size={SIZE.xs}
style={{
marginTop: 5
@@ -84,7 +84,7 @@ const TagItem = React.memo(
</View>
<IconButton
color={colors.primary.heading}
color={colors.heading}
name="dots-horizontal"
size={SIZE.xl}
onPress={() => {

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