mirror of
https://github.com/standardnotes/app
synced 2026-09-15 15:46:05 -04:00
Compare commits
43
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
285df04a59 | ||
|
|
4d5429cc89 | ||
|
|
da6622dc95 | ||
|
|
a548883863 | ||
|
|
1330201d2e | ||
|
|
0af720146c | ||
|
|
4d6992cf83 | ||
|
|
5de6f459c1 | ||
|
|
3c0d4fac76 | ||
|
|
4cdfcbfd95 | ||
|
|
51e50433d3 | ||
|
|
696327ff03 | ||
|
|
de64f1bfce | ||
|
|
48d484675b | ||
|
|
86251b49d3 | ||
|
|
5961bc491d | ||
|
|
e50f4eb92e | ||
|
|
4f8e75f36a | ||
|
|
6824dd2d5f | ||
|
|
76ec8b0f90 | ||
|
|
3eebdbb77d | ||
|
|
ce252def33 | ||
|
|
cb7af03ce8 | ||
|
|
1fe833bc24 | ||
|
|
ac1f59cde7 | ||
|
|
db4ceca10e | ||
|
|
0176f47fe7 | ||
|
|
f281041221 | ||
|
|
ebd56cd5aa | ||
|
|
8fa566336c | ||
|
|
9dfeac7489 | ||
|
|
d1b71861ec | ||
|
|
766548f12d | ||
|
|
581a08cd09 | ||
|
|
ee0d44405d | ||
|
|
1ae64dcac4 | ||
|
|
2be4fb4f83 | ||
|
|
271a8d1d70 | ||
|
|
e809328fa8 | ||
|
|
784cefa26f | ||
|
|
c5e225d335 | ||
|
|
cb4c0f1b5c | ||
|
|
91d9364e95 |
+18
-1
@@ -1,2 +1,19 @@
|
||||
node_modules
|
||||
scripts
|
||||
scripts
|
||||
actions
|
||||
.yarn
|
||||
.vscode
|
||||
.sass-cache
|
||||
.husky
|
||||
.github
|
||||
.git
|
||||
**/dist
|
||||
**/coverage
|
||||
**/node_modules
|
||||
packages/components
|
||||
packages/docs
|
||||
packages/mobile/android
|
||||
packages/mobile/ios
|
||||
packages/mobile/html
|
||||
packages/snjs/mocha
|
||||
*.d.ts
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"extends": ["./node_modules/@standardnotes/config/src/.eslintrc"],
|
||||
"ignorePatterns": [".eslintrc.js", "*.webpack.*.js", "webpack-defaults.js", "jest.config.js", "__mocks__"]
|
||||
"ignorePatterns": [".eslintrc.js", "*.webpack.*.js", "webpack-defaults.js", "jest.config.js", "__mocks__", "**/**/coverage"]
|
||||
}
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
node_modules
|
||||
dist
|
||||
coverage
|
||||
@@ -3,6 +3,16 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.8.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api
|
||||
|
||||
## [1.8.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* move wrapped storage to unwrapped if not encrypted ([#1603](https://github.com/standardnotes/app/issues/1603)) ([c5e225d](https://github.com/standardnotes/app/commit/c5e225d335537257f44168b8ad05222afccb508a))
|
||||
|
||||
# [1.8.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
|
||||
|
||||
### Features
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/api",
|
||||
"version": "1.8.0",
|
||||
"version": "1.8.2",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [2.7.14](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/components-meta
|
||||
|
||||
## [2.7.13](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-16)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/components-meta
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/components-meta",
|
||||
"version": "2.7.13",
|
||||
"version": "2.7.14",
|
||||
"private": true,
|
||||
"author": "Standard Notes.",
|
||||
"main": "dist",
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
node_modules
|
||||
dist
|
||||
jsign
|
||||
@@ -3,6 +3,80 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [3.23.152](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.151](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.150](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.149](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.148](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.147](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.146](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.145](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.144](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.143](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.142](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.141](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.140](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.139](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.138](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.137](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.136](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* move wrapped storage to unwrapped if not encrypted ([#1603](https://github.com/standardnotes/app/issues/1603)) ([c5e225d](https://github.com/standardnotes/app/commit/c5e225d335537257f44168b8ad05222afccb508a))
|
||||
|
||||
## [3.23.135](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.134](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@standardnotes/desktop",
|
||||
"main": "./app/dist/index.js",
|
||||
"version": "3.23.134",
|
||||
"version": "3.23.152",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"author": "Standard Notes.",
|
||||
"private": true,
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.15.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/encryption
|
||||
|
||||
## [1.15.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/encryption
|
||||
|
||||
## [1.15.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/encryption
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/encryption",
|
||||
"version": "1.15.2",
|
||||
"version": "1.15.4",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,12 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.52.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **mobile:** adjust status bar color to match current theme ([#1624](https://github.com/standardnotes/app/issues/1624)) ([4d5429c](https://github.com/standardnotes/app/commit/4d5429cc89c15f870825f20e97844825102c6aec))
|
||||
|
||||
# [1.52.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-13)
|
||||
|
||||
### Features
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/features",
|
||||
"version": "1.52.0",
|
||||
"version": "1.52.1",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -72,6 +72,7 @@ export type ThemeFeatureDescription = ComponentFeatureDescription & {
|
||||
/** Some themes can be layered on top of other themes */
|
||||
layerable?: boolean
|
||||
dock_icon?: ThemeDockIcon
|
||||
isDark?: boolean
|
||||
}
|
||||
|
||||
export type FeatureDescription = BaseFeatureDescription &
|
||||
|
||||
@@ -12,6 +12,7 @@ export function themes(): ThemeFeatureDescription[] {
|
||||
permission_name: PermissionName.MidnightTheme,
|
||||
description: 'Elegant utilitarianism.',
|
||||
thumbnail_url: 'https://s3.amazonaws.com/standard-notes/screenshots/models/themes/midnight-with-mobile.jpg',
|
||||
isDark: true,
|
||||
dock_icon: {
|
||||
type: 'circle',
|
||||
background_color: '#086DD6',
|
||||
@@ -27,6 +28,7 @@ export function themes(): ThemeFeatureDescription[] {
|
||||
permission_name: PermissionName.FuturaTheme,
|
||||
description: 'Calm and relaxed. Take some time off.',
|
||||
thumbnail_url: 'https://s3.amazonaws.com/standard-notes/screenshots/models/themes/futura-with-mobile.jpg',
|
||||
isDark: true,
|
||||
dock_icon: {
|
||||
type: 'circle',
|
||||
background_color: '#fca429',
|
||||
@@ -42,6 +44,7 @@ export function themes(): ThemeFeatureDescription[] {
|
||||
permission_name: PermissionName.SolarizedDarkTheme,
|
||||
description: 'The perfect theme for any time.',
|
||||
thumbnail_url: 'https://s3.amazonaws.com/standard-notes/screenshots/models/themes/solarized-dark.jpg',
|
||||
isDark: true,
|
||||
dock_icon: {
|
||||
type: 'circle',
|
||||
background_color: '#2AA198',
|
||||
@@ -72,6 +75,7 @@ export function themes(): ThemeFeatureDescription[] {
|
||||
permission_name: PermissionName.FocusedTheme,
|
||||
description: 'For when you need to go in.',
|
||||
thumbnail_url: 'https://s3.amazonaws.com/standard-notes/screenshots/models/themes/focus-with-mobile.jpg',
|
||||
isDark: true,
|
||||
dock_icon: {
|
||||
type: 'circle',
|
||||
background_color: '#a464c2',
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.23.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/filepicker
|
||||
|
||||
## [1.23.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/filepicker
|
||||
|
||||
## [1.23.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/filepicker
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/filepicker",
|
||||
"version": "1.23.2",
|
||||
"version": "1.23.4",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.10.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files
|
||||
|
||||
## [1.10.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files
|
||||
|
||||
## [1.10.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/files",
|
||||
"version": "1.10.2",
|
||||
"version": "1.10.4",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -5,4 +5,5 @@ ios
|
||||
e2e
|
||||
android
|
||||
fastlane
|
||||
WebFrame
|
||||
WebFrame
|
||||
__tests__
|
||||
@@ -3,6 +3,88 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [3.36.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **mobile:** adjust status bar color to match current theme ([#1624](https://github.com/standardnotes/app/issues/1624)) ([4d5429c](https://github.com/standardnotes/app/commit/4d5429cc89c15f870825f20e97844825102c6aec))
|
||||
|
||||
## [3.36.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.36.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
# [3.36.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
### Features
|
||||
|
||||
* sync page theme color metadata with active theme bg ([#1623](https://github.com/standardnotes/app/issues/1623)) ([5de6f45](https://github.com/standardnotes/app/commit/5de6f459c106127f294693389f62fa1c3ed57798))
|
||||
|
||||
## [3.35.16](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.35.15](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.35.14](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.35.13](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.35.12](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.35.11](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.35.10](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.35.9](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.35.8](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.35.7](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-21)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* iOS safe area using CSS ([#1610](https://github.com/standardnotes/app/issues/1610)) ([8fa5663](https://github.com/standardnotes/app/commit/8fa566336ceef8a3d7b559b1aaf342f7c51f21cd))
|
||||
|
||||
## [3.35.6](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-21)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* iOS webview window size and padding ([#1605](https://github.com/standardnotes/app/issues/1605)) ([1ae64dc](https://github.com/standardnotes/app/commit/1ae64dcac4cc714f8931b2301fce1cb802570862))
|
||||
|
||||
## [3.35.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.35.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* move wrapped storage to unwrapped if not encrypted ([#1603](https://github.com/standardnotes/app/issues/1603)) ([c5e225d](https://github.com/standardnotes/app/commit/c5e225d335537257f44168b8ad05222afccb508a))
|
||||
|
||||
## [3.35.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.35.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta content="IE=edge" http-equiv="X-UA-Compatible" />
|
||||
<meta content="width=device-width, initial-scale=1" name="viewport" />
|
||||
<meta content="viewport-fit=cover, width=device-width, initial-scale=1" name="viewport" />
|
||||
<meta content="#ffffff" name="theme-color" />
|
||||
<link rel="stylesheet" href="web-src/app.css" />
|
||||
<script>
|
||||
window.defaultSyncServer = "https://api.standardnotes.com";
|
||||
@@ -22,4 +23,4 @@
|
||||
<body>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/mobile",
|
||||
"version": "3.35.2",
|
||||
"version": "3.36.3",
|
||||
"author": "Standard Notes.",
|
||||
"private": true,
|
||||
"license": "AGPL-3.0-or-later",
|
||||
|
||||
@@ -18,7 +18,7 @@ import { ICON_MENU } from '@Style/Icons'
|
||||
import { ThemeService } from '@Style/ThemeService'
|
||||
import { getDefaultDrawerWidth } from '@Style/Utils'
|
||||
import React, { useCallback, useContext, useEffect, useRef, useState } from 'react'
|
||||
import { Dimensions, Keyboard, ScaledSize, StatusBar } from 'react-native'
|
||||
import { Dimensions, Keyboard, ScaledSize } from 'react-native'
|
||||
import DrawerLayout, { DrawerState } from 'react-native-gesture-handler/DrawerLayout'
|
||||
import { HeaderButtons, Item } from 'react-navigation-header-buttons'
|
||||
import { ThemeContext } from 'styled-components'
|
||||
@@ -150,7 +150,6 @@ export const AppStackComponent = (props: ModalStackNavigationProp<'AppStack'>) =
|
||||
onDrawerStateChanged={handleDrawerStateChange}
|
||||
renderNavigationView={() => !isLocked && <MainSideMenu drawerRef={drawerRef.current} />}
|
||||
>
|
||||
<StatusBar translucent={!shouldOpenWebApp} />
|
||||
<DrawerLayout
|
||||
ref={noteDrawerRef}
|
||||
drawerWidth={getDefaultDrawerWidth(dimensions)}
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
platformFromString,
|
||||
SNApplication,
|
||||
SNComponentManager,
|
||||
StorageValueModes,
|
||||
} from '@standardnotes/snjs'
|
||||
import { Platform } from 'react-native'
|
||||
|
||||
@@ -21,6 +22,7 @@ import { MobileAlertService } from './AlertService'
|
||||
import { ApplicationState } from './ApplicationState'
|
||||
import { BackupsService } from './BackupsService'
|
||||
import { ComponentManager } from './ComponentManager'
|
||||
import { AlwaysOpenWebAppOnLaunchKey } from './constants'
|
||||
import { FilesService } from './FilesService'
|
||||
import { InstallationService } from './InstallationService'
|
||||
import { MobileDevice } from './Interface'
|
||||
@@ -135,7 +137,8 @@ export class MobileApplication extends SNApplication {
|
||||
}
|
||||
|
||||
promptForChallenge(challenge: Challenge) {
|
||||
if (IsMobileWeb) {
|
||||
const optedIntoWebPreview = this.getValue(AlwaysOpenWebAppOnLaunchKey, StorageValueModes.Nonwrapped) as boolean
|
||||
if (IsMobileWeb || optedIntoWebPreview) {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -570,7 +570,7 @@ export class ApplicationState extends ApplicationService {
|
||||
).includes(state)
|
||||
}
|
||||
|
||||
private async getScreenshotPrivacyEnabled(): Promise<boolean | undefined> {
|
||||
private async getScreenshotPrivacyEnabled(): Promise<boolean> {
|
||||
return this.application.getMobileScreenshotPrivacyEnabled()
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
removeFromArray,
|
||||
TransferPayload,
|
||||
} from '@standardnotes/snjs'
|
||||
import { Alert, Linking, Platform } from 'react-native'
|
||||
import { Alert, Linking, Platform, StatusBar } from 'react-native'
|
||||
import FingerprintScanner from 'react-native-fingerprint-scanner'
|
||||
import FlagSecure from 'react-native-flag-secure-android'
|
||||
import { hide, show } from 'react-native-privacy-snapshot'
|
||||
@@ -65,6 +65,7 @@ const showLoadFailForItemIds = (failedItemIds: string[]) => {
|
||||
export class MobileDevice implements MobileDeviceInterface {
|
||||
environment: Environment.Mobile = Environment.Mobile
|
||||
private eventObservers: MobileDeviceEventHandler[] = []
|
||||
public isDarkMode = false
|
||||
|
||||
constructor(private stateObserverService?: AppStateObserverService) {}
|
||||
|
||||
@@ -73,6 +74,11 @@ export class MobileDevice implements MobileDeviceInterface {
|
||||
;(this.stateObserverService as unknown) = undefined
|
||||
}
|
||||
|
||||
consoleLog(...args: any[]): void {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(args)
|
||||
}
|
||||
|
||||
async setLegacyRawKeychainValue(value: LegacyRawKeychainValue): Promise<void> {
|
||||
await Keychain.setKeys(value)
|
||||
}
|
||||
@@ -378,7 +384,7 @@ export class MobileDevice implements MobileDeviceInterface {
|
||||
await Keychain.clearKeys()
|
||||
}
|
||||
|
||||
async setAndroidScreenshotPrivacy(enable: boolean): Promise<void> {
|
||||
setAndroidScreenshotPrivacy(enable: boolean): void {
|
||||
if (Platform.OS === 'android') {
|
||||
enable ? FlagSecure.activate() : FlagSecure.deactivate()
|
||||
}
|
||||
@@ -427,6 +433,16 @@ export class MobileDevice implements MobileDeviceInterface {
|
||||
}
|
||||
}
|
||||
|
||||
handleThemeSchemeChange(isDark: boolean): void {
|
||||
this.isDarkMode = isDark
|
||||
|
||||
this.reloadStatusBarStyle()
|
||||
}
|
||||
|
||||
reloadStatusBarStyle(animated = true) {
|
||||
StatusBar.setBarStyle(this.isDarkMode ? 'light-content' : 'dark-content', animated)
|
||||
}
|
||||
|
||||
private notifyEvent(event: MobileDeviceEvent): void {
|
||||
for (const handler of this.eventObservers) {
|
||||
handler(event)
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { MobileDevice, MobileDeviceEvent } from '@Lib/Interface'
|
||||
import { IsDev } from '@Lib/Utils'
|
||||
import { ReactNativeToWebEvent } from '@standardnotes/snjs'
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { Platform } from 'react-native'
|
||||
import { Keyboard, Platform } from 'react-native'
|
||||
import { WebView, WebViewMessageEvent } from 'react-native-webview'
|
||||
import { AppStateObserverService } from './AppStateObserverService'
|
||||
|
||||
const LoggingEnabled = false
|
||||
const LoggingEnabled = IsDev
|
||||
|
||||
export const MobileWebAppContainer = () => {
|
||||
const [identifier, setIdentifier] = useState(Math.random())
|
||||
@@ -28,8 +29,18 @@ const MobileWebAppContents = ({ destroyAndReload }: { destroyAndReload: () => vo
|
||||
webViewRef.current?.postMessage(JSON.stringify({ reactNativeEvent: event, messageType: 'event' }))
|
||||
})
|
||||
|
||||
const keyboardShowListener = Keyboard.addListener('keyboardWillShow', () => {
|
||||
device.reloadStatusBarStyle(false)
|
||||
})
|
||||
|
||||
const keyboardHideListener = Keyboard.addListener('keyboardDidHide', () => {
|
||||
device.reloadStatusBarStyle(false)
|
||||
})
|
||||
|
||||
return () => {
|
||||
removeListener()
|
||||
keyboardShowListener.remove()
|
||||
keyboardHideListener.remove()
|
||||
}
|
||||
}, [webViewRef, stateService])
|
||||
|
||||
@@ -175,7 +186,6 @@ const MobileWebAppContents = ({ destroyAndReload }: { destroyAndReload: () => vo
|
||||
ref={webViewRef}
|
||||
source={{ uri: sourceUri }}
|
||||
originWhitelist={['*']}
|
||||
contentInset={{ top: 30, bottom: 10 }}
|
||||
onLoad={() => {}}
|
||||
onError={(err) => console.error('An error has occurred', err)}
|
||||
onHttpError={() => console.error('An HTTP error occurred')}
|
||||
@@ -183,6 +193,7 @@ const MobileWebAppContents = ({ destroyAndReload }: { destroyAndReload: () => vo
|
||||
allowFileAccess={true}
|
||||
allowUniversalAccessFromFileURLs={true}
|
||||
injectedJavaScriptBeforeContentLoaded={injectedJS}
|
||||
bounces={false}
|
||||
/>
|
||||
)
|
||||
/* eslint-enable @typescript-eslint/no-empty-function */
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
import { AlwaysOpenWebAppOnLaunchKey } from '@Lib/constants'
|
||||
import { ApplicationContext } from '@Root/ApplicationContext'
|
||||
import { ButtonCell } from '@Root/Components/ButtonCell'
|
||||
import { SectionHeader } from '@Root/Components/SectionHeader'
|
||||
import { TableSection } from '@Root/Components/TableSection'
|
||||
import { ButtonType, StorageValueModes } from '@standardnotes/snjs'
|
||||
import React, { useContext } from 'react'
|
||||
import styled from 'styled-components/native'
|
||||
import { Label } from './CompanySection.styled'
|
||||
import { BaseView, StyledSectionedTableCell } from './EncryptionSection.styled'
|
||||
|
||||
const Title = styled.Text`
|
||||
color: ${({ theme }) => theme.stylekitForegroundColor};
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
`
|
||||
|
||||
export const NewMobileSection = () => {
|
||||
const application = useContext(ApplicationContext)
|
||||
|
||||
if (!application) {
|
||||
return <></>
|
||||
}
|
||||
|
||||
const optIn = async () => {
|
||||
const confirmationText =
|
||||
'This will close the app and switch to the new mobile experience next time you open it. You will be able to switch back to the soon-to-be removed classic experience from the settings.'
|
||||
|
||||
if (
|
||||
await application.alertService.confirm(
|
||||
confirmationText,
|
||||
'Switch To New Mobile Experience?',
|
||||
'Switch',
|
||||
ButtonType.Info,
|
||||
)
|
||||
) {
|
||||
application.setValue(AlwaysOpenWebAppOnLaunchKey, true, StorageValueModes.Nonwrapped)
|
||||
setTimeout(() => application.deviceInterface.performSoftReset(), 1000)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<TableSection>
|
||||
<SectionHeader title={'New Mobile Experience'} />
|
||||
|
||||
<StyledSectionedTableCell last={true} first={true}>
|
||||
<BaseView>
|
||||
<Title>🎉 New Mobile Experience Preview</Title>
|
||||
<Label>
|
||||
The new mobile experience (MX) brings the desktop experience you've come to love right here on your mobile
|
||||
device. This mode will replace the existing classic mobile experience soon. You can opt in below to begin
|
||||
using the new MX now.
|
||||
</Label>
|
||||
</BaseView>
|
||||
</StyledSectionedTableCell>
|
||||
|
||||
<ButtonCell leftAligned={true} title="Opt In to New Mobile Experience" onPress={optIn}></ButtonCell>
|
||||
<ButtonCell
|
||||
leftAligned={true}
|
||||
title="Read Blog Post"
|
||||
onPress={() => {
|
||||
application?.deviceInterface!.openUrl(
|
||||
'https://blog.standardnotes.com/38384/our-new-mobile-experience-is-launching-soon',
|
||||
)
|
||||
}}
|
||||
></ButtonCell>
|
||||
</TableSection>
|
||||
)
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
import { AlwaysOpenWebAppOnLaunchKey } from '@Lib/constants'
|
||||
import { useSignedIn } from '@Lib/SnjsHelperHooks'
|
||||
import { useNavigation } from '@react-navigation/native'
|
||||
import { ButtonCell } from '@Root/Components/ButtonCell'
|
||||
@@ -9,7 +8,7 @@ import { TableSection } from '@Root/Components/TableSection'
|
||||
import { useSafeApplicationContext } from '@Root/Hooks/useSafeApplicationContext'
|
||||
import { ModalStackNavigationProp } from '@Root/ModalStack'
|
||||
import { SCREEN_MANAGE_SESSIONS, SCREEN_SETTINGS } from '@Root/Screens/screens'
|
||||
import { ButtonType, PrefKey, StorageValueModes } from '@standardnotes/snjs'
|
||||
import { ButtonType, PrefKey } from '@standardnotes/snjs'
|
||||
import moment from 'moment'
|
||||
import React, { useCallback, useMemo, useState } from 'react'
|
||||
import { Platform } from 'react-native'
|
||||
@@ -222,21 +221,6 @@ export const OptionsSection = ({ title, encryptionAvailable }: Props) => {
|
||||
onPress={onExportPress}
|
||||
/>
|
||||
|
||||
<ButtonCell
|
||||
onPress={async () => {
|
||||
const confirmationText =
|
||||
'This will close the app and fully switch to the web view next time you open it. You will be able to switch back from the settings.'
|
||||
|
||||
if (
|
||||
await application.alertService.confirm(confirmationText, 'Switch To Web View?', 'Switch', ButtonType.Info)
|
||||
) {
|
||||
application.setValue(AlwaysOpenWebAppOnLaunchKey, true, StorageValueModes.Nonwrapped)
|
||||
setTimeout(() => application.deviceInterface.performSoftReset(), 1000)
|
||||
}
|
||||
}}
|
||||
title="Switch to Web View"
|
||||
/>
|
||||
|
||||
{!signedIn && (
|
||||
<SectionedAccessoryTableCell
|
||||
testID="lastExportDate"
|
||||
|
||||
@@ -38,14 +38,14 @@ export const SecuritySection = (props: Props) => {
|
||||
useEffect(() => {
|
||||
let mounted = true
|
||||
const getHasScreenshotPrivacy = async () => {
|
||||
const hasScreenshotPrivacyEnabled = (await application?.getMobileScreenshotPrivacyEnabled()) ?? true
|
||||
const hasScreenshotPrivacyEnabled = application?.getMobileScreenshotPrivacyEnabled()
|
||||
if (mounted) {
|
||||
setHasScreenshotPrivacy(hasScreenshotPrivacyEnabled)
|
||||
}
|
||||
}
|
||||
void getHasScreenshotPrivacy()
|
||||
const getHasBiometrics = async () => {
|
||||
const appHasBiometrics = await application!.hasBiometrics()
|
||||
const appHasBiometrics = application!.hasBiometrics()
|
||||
if (mounted) {
|
||||
setHasBiometrics(appHasBiometrics)
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import React, { useCallback, useEffect, useState } from 'react'
|
||||
import { AuthSection } from './Sections/AuthSection'
|
||||
import { CompanySection } from './Sections/CompanySection'
|
||||
import { EncryptionSection } from './Sections/EncryptionSection'
|
||||
import { NewMobileSection } from './Sections/NewMobilePreview'
|
||||
import { OptionsSection } from './Sections/OptionsSection'
|
||||
import { PreferencesSection } from './Sections/PreferencesSection'
|
||||
import { ProtectionsSection } from './Sections/ProtectionsSection'
|
||||
@@ -54,6 +55,7 @@ export const Settings = (props: Props) => {
|
||||
<Container keyboardShouldPersistTaps={'always'} keyboardDismissMode={'interactive'}>
|
||||
<AuthSection title="Account" signedIn={signedIn} />
|
||||
<OptionsSection encryptionAvailable={!!encryptionAvailable} title="Options" />
|
||||
<NewMobileSection />
|
||||
<WorkspacesSection />
|
||||
<PreferencesSection />
|
||||
{application.hasAccount() && isEntitledToFiles && <FilesSection />}
|
||||
|
||||
@@ -3,6 +3,16 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.18.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **mobile:** adjust status bar color to match current theme ([#1624](https://github.com/standardnotes/app/issues/1624)) ([4d5429c](https://github.com/standardnotes/app/commit/4d5429cc89c15f870825f20e97844825102c6aec))
|
||||
|
||||
## [1.18.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/models
|
||||
|
||||
## [1.18.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-15)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/models",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.4",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { FeatureDescription } from '@standardnotes/features'
|
||||
import { FeatureDescription, ThemeFeatureDescription } from '@standardnotes/features'
|
||||
|
||||
type ThirdPartyPackageInfo = {
|
||||
version: string
|
||||
@@ -6,3 +6,4 @@ type ThirdPartyPackageInfo = {
|
||||
}
|
||||
|
||||
export type ComponentPackageInfo = FeatureDescription & Partial<ThirdPartyPackageInfo>
|
||||
export type ThemePackageInfo = FeatureDescription & Partial<ThirdPartyPackageInfo> & ThemeFeatureDescription
|
||||
|
||||
@@ -6,11 +6,13 @@ import { HistoryEntryInterface } from '../../Runtime/History'
|
||||
import { DecryptedItemInterface, ItemInterface } from '../../Abstract/Item'
|
||||
import { ContentType } from '@standardnotes/common'
|
||||
import { useBoolean } from '@standardnotes/utils'
|
||||
import { ThemePackageInfo } from '../Component/PackageInfo'
|
||||
|
||||
export const isTheme = (x: ItemInterface): x is SNTheme => x.content_type === ContentType.Theme
|
||||
|
||||
export class SNTheme extends SNComponent {
|
||||
public override area: ComponentArea = ComponentArea.Themes
|
||||
public override readonly package_info!: ThemePackageInfo
|
||||
|
||||
isLayerable(): boolean {
|
||||
return useBoolean(this.package_info && this.package_info.layerable, false)
|
||||
|
||||
@@ -3,6 +3,78 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.3.75](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.74](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.73](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.72](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.71](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.70](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.69](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.68](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.67](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.66](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.65](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.64](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.63](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.62](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.61](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.60](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.59](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.58](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.57](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/releases",
|
||||
"version": "1.3.57",
|
||||
"version": "1.3.75",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"main": "dist/releases.json",
|
||||
"types": "dist/index.d.ts",
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
node_modules
|
||||
dist
|
||||
coverage
|
||||
@@ -3,6 +3,16 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.10.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/responses
|
||||
|
||||
## [1.10.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* move wrapped storage to unwrapped if not encrypted ([#1603](https://github.com/standardnotes/app/issues/1603)) ([c5e225d](https://github.com/standardnotes/app/commit/c5e225d335537257f44168b8ad05222afccb508a))
|
||||
|
||||
## [1.10.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-13)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/responses
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/responses",
|
||||
"version": "1.10.1",
|
||||
"version": "1.10.3",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,18 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.21.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **mobile:** adjust status bar color to match current theme ([#1624](https://github.com/standardnotes/app/issues/1624)) ([4d5429c](https://github.com/standardnotes/app/commit/4d5429cc89c15f870825f20e97844825102c6aec))
|
||||
|
||||
## [1.21.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* move wrapped storage to unwrapped if not encrypted ([#1603](https://github.com/standardnotes/app/issues/1603)) ([c5e225d](https://github.com/standardnotes/app/commit/c5e225d335537257f44168b8ad05222afccb508a))
|
||||
|
||||
## [1.21.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/services
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/services",
|
||||
"version": "1.21.1",
|
||||
"version": "1.21.3",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { MobileDeviceInterface } from './../Device/MobileDeviceInterface'
|
||||
import { DesktopManagerInterface } from '../Device/DesktopManagerInterface'
|
||||
import { WebAppEvent } from '../Event/WebAppEvent'
|
||||
import { ApplicationInterface } from './ApplicationInterface'
|
||||
@@ -9,4 +10,6 @@ export interface WebApplicationInterface extends ApplicationInterface {
|
||||
handleMobileGainingFocusEvent(): Promise<void>
|
||||
handleMobileLosingFocusEvent(): Promise<void>
|
||||
handleMobileResumingFromBackgroundEvent(): Promise<void>
|
||||
isNativeMobileWeb(): boolean
|
||||
get mobileDevice(): MobileDeviceInterface
|
||||
}
|
||||
|
||||
@@ -6,8 +6,10 @@ export interface MobileDeviceInterface extends DeviceInterface {
|
||||
|
||||
getRawKeychainValue(): Promise<RawKeychainValue | undefined>
|
||||
getDeviceBiometricsAvailability(): Promise<boolean>
|
||||
setAndroidScreenshotPrivacy(enable: boolean): Promise<void>
|
||||
setAndroidScreenshotPrivacy(enable: boolean): void
|
||||
authenticateWithBiometrics(): Promise<boolean>
|
||||
hideMobileInterfaceFromScreenshots(): void
|
||||
stopHidingMobileInterfaceFromScreenshots(): void
|
||||
consoleLog(...args: any[]): void
|
||||
handleThemeSchemeChange(isDark: boolean): void
|
||||
}
|
||||
|
||||
@@ -2,4 +2,8 @@ node_modules
|
||||
dist
|
||||
test
|
||||
*.config.js
|
||||
mocha/**/*
|
||||
mocha/**/*
|
||||
coverage
|
||||
e2e-server.js
|
||||
jest-global.ts
|
||||
webpack.*.js
|
||||
@@ -3,6 +3,46 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [2.132.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/snjs
|
||||
|
||||
## [2.132.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* biometrics timing loading ([#1622](https://github.com/standardnotes/app/issues/1622)) ([3c0d4fa](https://github.com/standardnotes/app/commit/3c0d4fac766c3a31bdbebe4f7e88f83ba1ea58da))
|
||||
|
||||
## [2.132.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
### Reverts
|
||||
|
||||
* Revert "Revert "feat(web): move emails notifications to one pane and enable opening settings via url (#1614)" (#1617)" (#1619) ([e50f4eb](https://github.com/standardnotes/app/commit/e50f4eb92efd65b0b8fa3a5001b8dfb611f60180)), closes [#1614](https://github.com/standardnotes/app/issues/1614) [#1617](https://github.com/standardnotes/app/issues/1617) [#1619](https://github.com/standardnotes/app/issues/1619)
|
||||
|
||||
## [2.132.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
### Reverts
|
||||
|
||||
* Revert "feat(web): move emails notifications to one pane and enable opening settings via url (#1614)" (#1617) ([6824dd2](https://github.com/standardnotes/app/commit/6824dd2d5fe4a6d427ff5465540f3b7865933e98)), closes [#1614](https://github.com/standardnotes/app/issues/1614) [#1617](https://github.com/standardnotes/app/issues/1617)
|
||||
|
||||
# [2.132.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
### Features
|
||||
|
||||
* **web:** move emails notifications to one pane and enable opening settings via url ([#1614](https://github.com/standardnotes/app/issues/1614)) ([1fe833b](https://github.com/standardnotes/app/commit/1fe833bc24a3a426a7230381704d418624cc2b82))
|
||||
|
||||
# [2.131.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-21)
|
||||
|
||||
### Features
|
||||
|
||||
* **snjs:** add retrieving web sockets token for establishing connection ([#1602](https://github.com/standardnotes/app/issues/1602)) ([e809328](https://github.com/standardnotes/app/commit/e809328fa86d49f76d24bc0d95db010e483c1853))
|
||||
|
||||
## [2.130.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* move wrapped storage to unwrapped if not encrypted ([#1603](https://github.com/standardnotes/app/issues/1603)) ([c5e225d](https://github.com/standardnotes/app/commit/c5e225d335537257f44168b8ad05222afccb508a))
|
||||
|
||||
## [2.130.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/snjs
|
||||
|
||||
@@ -10,6 +10,10 @@ import {
|
||||
UserRegistrationResponseBody,
|
||||
UserServer,
|
||||
UserServerInterface,
|
||||
WebSocketApiService,
|
||||
WebSocketApiServiceInterface,
|
||||
WebSocketServer,
|
||||
WebSocketServerInterface,
|
||||
} from '@standardnotes/api'
|
||||
import * as Common from '@standardnotes/common'
|
||||
import * as ExternalServices from '@standardnotes/services'
|
||||
@@ -108,6 +112,8 @@ export class SNApplication
|
||||
private declare subscriptionApiService: SubscriptionApiServiceInterface
|
||||
private declare subscriptionServer: SubscriptionServerInterface
|
||||
private declare subscriptionManager: SubscriptionClientInterface
|
||||
private declare webSocketApiService: WebSocketApiServiceInterface
|
||||
private declare webSocketServer: WebSocketServerInterface
|
||||
private sessionManager!: InternalServices.SNSessionManager
|
||||
private syncService!: InternalServices.SNSyncService
|
||||
private challengeService!: InternalServices.ChallengeService
|
||||
@@ -324,11 +330,12 @@ export class SNApplication
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
await this.handleStage(ExternalServices.ApplicationStage.StorageDecrypted_09)
|
||||
|
||||
this.apiService.loadHost()
|
||||
this.webSocketsService.loadWebSocketUrl()
|
||||
this.sessionManager.initializeFromDisk()
|
||||
await this.sessionManager.initializeFromDisk()
|
||||
|
||||
this.settingsService.initializeFromDisk()
|
||||
|
||||
@@ -929,32 +936,28 @@ export class SNApplication
|
||||
return this.deinit(this.getDeinitMode(), DeinitSource.Lock)
|
||||
}
|
||||
|
||||
async setBiometricsTiming(timing: MobileUnlockTiming) {
|
||||
setBiometricsTiming(timing: MobileUnlockTiming) {
|
||||
return this.protectionService.setBiometricsTiming(timing)
|
||||
}
|
||||
|
||||
async getMobileScreenshotPrivacyEnabled(): Promise<boolean | undefined> {
|
||||
getMobileScreenshotPrivacyEnabled(): boolean {
|
||||
return this.protectionService.getMobileScreenshotPrivacyEnabled()
|
||||
}
|
||||
|
||||
async getMobilePasscodeTiming(): Promise<MobileUnlockTiming | undefined> {
|
||||
return this.getValue(StorageKey.MobilePasscodeTiming, StorageValueModes.Nonwrapped) as Promise<
|
||||
MobileUnlockTiming | undefined
|
||||
>
|
||||
}
|
||||
|
||||
async getMobileBiometricsTiming(): Promise<MobileUnlockTiming | undefined> {
|
||||
return this.getValue(StorageKey.MobileBiometricsTiming, StorageValueModes.Nonwrapped) as Promise<
|
||||
MobileUnlockTiming | undefined
|
||||
>
|
||||
}
|
||||
|
||||
async setMobileScreenshotPrivacyEnabled(isEnabled: boolean) {
|
||||
setMobileScreenshotPrivacyEnabled(isEnabled: boolean) {
|
||||
return this.protectionService.setMobileScreenshotPrivacyEnabled(isEnabled)
|
||||
}
|
||||
|
||||
async loadMobileUnlockTiming() {
|
||||
return this.protectionService.loadMobileUnlockTiming()
|
||||
getMobilePasscodeTiming(): MobileUnlockTiming | undefined {
|
||||
return this.getValue(StorageKey.MobilePasscodeTiming, StorageValueModes.Nonwrapped) as
|
||||
| MobileUnlockTiming
|
||||
| undefined
|
||||
}
|
||||
|
||||
getMobileBiometricsTiming(): MobileUnlockTiming | undefined {
|
||||
return this.getValue(StorageKey.MobileBiometricsTiming, StorageValueModes.Nonwrapped) as
|
||||
| MobileUnlockTiming
|
||||
| undefined
|
||||
}
|
||||
|
||||
getBiometricsTimingOptions() {
|
||||
@@ -1093,6 +1096,8 @@ export class SNApplication
|
||||
this.createUserApiService()
|
||||
this.createSubscriptionServer()
|
||||
this.createSubscriptionApiService()
|
||||
this.createWebSocketServer()
|
||||
this.createWebSocketApiService()
|
||||
this.createSubscriptionManager()
|
||||
this.createWebSocketsService()
|
||||
this.createSessionManager()
|
||||
@@ -1134,6 +1139,8 @@ export class SNApplication
|
||||
;(this.userServer as unknown) = undefined
|
||||
;(this.subscriptionApiService as unknown) = undefined
|
||||
;(this.subscriptionServer as unknown) = undefined
|
||||
;(this.webSocketApiService as unknown) = undefined
|
||||
;(this.webSocketServer as unknown) = undefined
|
||||
;(this.subscriptionManager as unknown) = undefined
|
||||
;(this.sessionManager as unknown) = undefined
|
||||
;(this.syncService as unknown) = undefined
|
||||
@@ -1251,6 +1258,7 @@ export class SNApplication
|
||||
this.webSocketsService = new InternalServices.SNWebSocketsService(
|
||||
this.diskStorageService,
|
||||
this.options.webSocketUrl,
|
||||
this.webSocketApiService,
|
||||
this.internalEventBus,
|
||||
)
|
||||
this.services.push(this.webSocketsService)
|
||||
@@ -1336,6 +1344,14 @@ export class SNApplication
|
||||
this.subscriptionServer = new SubscriptionServer(this.httpService)
|
||||
}
|
||||
|
||||
private createWebSocketApiService() {
|
||||
this.webSocketApiService = new WebSocketApiService(this.webSocketServer)
|
||||
}
|
||||
|
||||
private createWebSocketServer() {
|
||||
this.webSocketServer = new WebSocketServer(this.httpService)
|
||||
}
|
||||
|
||||
private createSubscriptionManager() {
|
||||
this.subscriptionManager = new SubscriptionManager(this.subscriptionApiService, this.internalEventBus)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { InternalEventBusInterface } from '@standardnotes/services'
|
||||
import { WebSocketApiServiceInterface } from '@standardnotes/api'
|
||||
|
||||
import { StorageKey, DiskStorageService } from '@Lib/index'
|
||||
import { SNWebSocketsService } from './WebsocketsService'
|
||||
|
||||
@@ -6,10 +8,11 @@ describe('webSocketsService', () => {
|
||||
const webSocketUrl = ''
|
||||
|
||||
let storageService: DiskStorageService
|
||||
let webSocketApiService: WebSocketApiServiceInterface
|
||||
let internalEventBus: InternalEventBusInterface
|
||||
|
||||
const createService = () => {
|
||||
return new SNWebSocketsService(storageService, webSocketUrl, internalEventBus)
|
||||
return new SNWebSocketsService(storageService, webSocketUrl, webSocketApiService, internalEventBus)
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -18,6 +21,9 @@ describe('webSocketsService', () => {
|
||||
|
||||
internalEventBus = {} as jest.Mocked<InternalEventBusInterface>
|
||||
internalEventBus.publish = jest.fn()
|
||||
|
||||
webSocketApiService = {} as jest.Mocked<WebSocketApiServiceInterface>
|
||||
webSocketApiService.createConnectionToken = jest.fn().mockReturnValue({ token: 'foobar' })
|
||||
})
|
||||
|
||||
describe('setWebSocketUrl()', () => {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { UserRolesChangedEvent } from '@standardnotes/domain-events'
|
||||
import { DiskStorageService } from '../Storage/DiskStorageService'
|
||||
import { AbstractService, InternalEventBusInterface, StorageKey } from '@standardnotes/services'
|
||||
import { WebSocketApiServiceInterface } from '@standardnotes/api'
|
||||
|
||||
import { DiskStorageService } from '../Storage/DiskStorageService'
|
||||
|
||||
export enum WebSocketsServiceEvent {
|
||||
UserRoleMessageReceived = 'WebSocketMessageReceived',
|
||||
@@ -12,6 +14,7 @@ export class SNWebSocketsService extends AbstractService<WebSocketsServiceEvent,
|
||||
constructor(
|
||||
private storageService: DiskStorageService,
|
||||
private webSocketUrl: string | undefined,
|
||||
private webSocketApiService: WebSocketApiServiceInterface,
|
||||
protected override internalEventBus: InternalEventBusInterface,
|
||||
) {
|
||||
super(internalEventBus)
|
||||
@@ -34,10 +37,15 @@ export class SNWebSocketsService extends AbstractService<WebSocketsServiceEvent,
|
||||
)._websocket_url
|
||||
}
|
||||
|
||||
public startWebSocketConnection(authToken: string): void {
|
||||
async startWebSocketConnection(): Promise<void> {
|
||||
const webSocketConectionToken = await this.createWebSocketConnectionToken()
|
||||
if (webSocketConectionToken === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
if (this.webSocketUrl) {
|
||||
try {
|
||||
this.webSocket = new WebSocket(`${this.webSocketUrl}?authToken=Bearer+${authToken}`)
|
||||
this.webSocket = new WebSocket(`${this.webSocketUrl}?authToken=${webSocketConectionToken}`)
|
||||
this.webSocket.onmessage = this.onWebSocketMessage.bind(this)
|
||||
this.webSocket.onclose = this.onWebSocketClose.bind(this)
|
||||
} catch (e) {
|
||||
@@ -59,9 +67,22 @@ export class SNWebSocketsService extends AbstractService<WebSocketsServiceEvent,
|
||||
this.webSocket = undefined
|
||||
}
|
||||
|
||||
private async createWebSocketConnectionToken(): Promise<string | undefined> {
|
||||
try {
|
||||
const response = await this.webSocketApiService.createConnectionToken()
|
||||
|
||||
return response.data.token
|
||||
} catch (error) {
|
||||
console.error((error as Error).message)
|
||||
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
override deinit(): void {
|
||||
super.deinit()
|
||||
;(this.storageService as unknown) = undefined
|
||||
;(this.webSocketApiService as unknown) = undefined
|
||||
this.closeWebSocketConnection()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,6 +87,8 @@ export class SNProtectionService extends AbstractService<ProtectionEvent> implem
|
||||
override handleApplicationStage(stage: ApplicationStage): Promise<void> {
|
||||
if (stage === ApplicationStage.LoadedDatabase_12) {
|
||||
this.updateSessionExpiryTimer(this.getSessionExpiryDate())
|
||||
this.mobilePasscodeTiming = this.getPasscodeTiming()
|
||||
this.mobileBiometricsTiming = this.getBiometricsTiming()
|
||||
}
|
||||
return Promise.resolve()
|
||||
}
|
||||
@@ -257,36 +259,31 @@ export class SNProtectionService extends AbstractService<ProtectionEvent> implem
|
||||
]
|
||||
}
|
||||
|
||||
private async getBiometricsTiming(): Promise<MobileUnlockTiming | undefined> {
|
||||
return this.storageService.getValue<Promise<MobileUnlockTiming | undefined>>(
|
||||
private getBiometricsTiming(): MobileUnlockTiming | undefined {
|
||||
return this.storageService.getValue<MobileUnlockTiming | undefined>(
|
||||
StorageKey.MobileBiometricsTiming,
|
||||
StorageValueModes.Nonwrapped,
|
||||
)
|
||||
}
|
||||
|
||||
private async getPasscodeTiming(): Promise<MobileUnlockTiming | undefined> {
|
||||
return this.storageService.getValue<Promise<MobileUnlockTiming | undefined>>(
|
||||
private getPasscodeTiming(): MobileUnlockTiming | undefined {
|
||||
return this.storageService.getValue<MobileUnlockTiming | undefined>(
|
||||
StorageKey.MobilePasscodeTiming,
|
||||
StorageValueModes.Nonwrapped,
|
||||
)
|
||||
}
|
||||
|
||||
async setBiometricsTiming(timing: MobileUnlockTiming) {
|
||||
await this.storageService.setValue(StorageKey.MobileBiometricsTiming, timing, StorageValueModes.Nonwrapped)
|
||||
this.storageService.setValue(StorageKey.MobileBiometricsTiming, timing, StorageValueModes.Nonwrapped)
|
||||
this.mobileBiometricsTiming = timing
|
||||
}
|
||||
|
||||
async setMobileScreenshotPrivacyEnabled(isEnabled: boolean) {
|
||||
setMobileScreenshotPrivacyEnabled(isEnabled: boolean) {
|
||||
return this.storageService.setValue(StorageKey.MobileScreenshotPrivacyEnabled, isEnabled, StorageValueModes.Default)
|
||||
}
|
||||
|
||||
async getMobileScreenshotPrivacyEnabled(): Promise<boolean | undefined> {
|
||||
return this.storageService.getValue(StorageKey.MobileScreenshotPrivacyEnabled, StorageValueModes.Default)
|
||||
}
|
||||
|
||||
async loadMobileUnlockTiming() {
|
||||
this.mobilePasscodeTiming = await this.getPasscodeTiming()
|
||||
this.mobileBiometricsTiming = await this.getBiometricsTiming()
|
||||
getMobileScreenshotPrivacyEnabled(): boolean {
|
||||
return this.storageService.getValue(StorageKey.MobileScreenshotPrivacyEnabled, StorageValueModes.Default, false)
|
||||
}
|
||||
|
||||
private async validateOrRenewSession(
|
||||
|
||||
@@ -107,7 +107,7 @@ export class SNSessionManager extends AbstractService<SessionEvent> implements S
|
||||
this.apiService.setUser(user)
|
||||
}
|
||||
|
||||
public initializeFromDisk() {
|
||||
async initializeFromDisk() {
|
||||
this.setUser(this.diskStorageService.getValue(StorageKey.User))
|
||||
|
||||
if (!this.user) {
|
||||
@@ -121,7 +121,7 @@ export class SNSessionManager extends AbstractService<SessionEvent> implements S
|
||||
if (rawSession) {
|
||||
const session = SessionFromRawStorageValue(rawSession)
|
||||
this.setSession(session, false)
|
||||
this.webSocketsService.startWebSocketConnection(session.authorizationValue)
|
||||
await this.webSocketsService.startWebSocketConnection()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -623,9 +623,9 @@ export class SNSessionManager extends AbstractService<SessionEvent> implements S
|
||||
|
||||
this.httpService.setHost(host)
|
||||
|
||||
await this.setSession(session)
|
||||
this.setSession(session)
|
||||
|
||||
this.webSocketsService.startWebSocketConnection(session.authorizationValue)
|
||||
await this.webSocketsService.startWebSocketConnection()
|
||||
}
|
||||
|
||||
private async handleAuthResponse(body: UserRegistrationResponseBody, rootKey: SNRootKey, wrappingKey?: SNRootKey) {
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
ListedAuthorSecretsData,
|
||||
LogSessionUserAgentOption,
|
||||
SettingName,
|
||||
MuteMarketingEmailsOption,
|
||||
} from '@standardnotes/settings'
|
||||
|
||||
type SettingType =
|
||||
@@ -23,6 +24,7 @@ type SettingType =
|
||||
| MuteFailedBackupsEmailsOption
|
||||
| MuteFailedCloudBackupsEmailsOption
|
||||
| MuteSignInEmailsOption
|
||||
| MuteMarketingEmailsOption
|
||||
| OneDriveBackupFrequency
|
||||
|
||||
export class SettingsList {
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import { DiskStorageService } from './DiskStorageService'
|
||||
|
||||
import { InternalEventBus, DeviceInterface, InternalEventBusInterface } from '@standardnotes/services'
|
||||
import { Environment } from '@standardnotes/models'
|
||||
|
||||
describe('diskStorageService', () => {
|
||||
let storageService: DiskStorageService
|
||||
let internalEventBus: InternalEventBusInterface
|
||||
let device: DeviceInterface
|
||||
|
||||
beforeEach(() => {
|
||||
internalEventBus = {} as jest.Mocked<InternalEventBus>
|
||||
device = {} as jest.Mocked<DeviceInterface>
|
||||
|
||||
storageService = new DiskStorageService(device, 'test', Environment.Desktop, internalEventBus)
|
||||
})
|
||||
|
||||
it('setInitialValues should set unwrapped values as wrapped value if wrapped value is not encrypted', async () => {
|
||||
storageService.isStorageWrapped = jest.fn().mockReturnValue(false)
|
||||
|
||||
await storageService['setInitialValues']({
|
||||
wrapped: { content: { foo: 'bar' } } as never,
|
||||
nonwrapped: {},
|
||||
unwrapped: { bar: 'zoo' },
|
||||
})
|
||||
|
||||
expect(storageService['values']).toEqual({
|
||||
wrapped: { content: { foo: 'bar' } } as never,
|
||||
nonwrapped: {},
|
||||
unwrapped: { bar: 'zoo', foo: 'bar' },
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -112,14 +112,10 @@ export class DiskStorageService extends Services.AbstractService implements Serv
|
||||
const value = await this.deviceInterface.getRawStorageValue(this.getPersistenceKey())
|
||||
const values = value ? JSON.parse(value as string) : undefined
|
||||
|
||||
this.setInitialValues(values)
|
||||
await this.setInitialValues(values)
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by platforms with the value they load from disk,
|
||||
* after they handle initializeFromDisk
|
||||
*/
|
||||
private setInitialValues(values?: Services.StorageValuesObject) {
|
||||
private async setInitialValues(values?: Services.StorageValuesObject) {
|
||||
const sureValues = values || this.defaultValuesObject()
|
||||
|
||||
if (!sureValues[Services.ValueModesKeys.Unwrapped]) {
|
||||
@@ -127,6 +123,13 @@ export class DiskStorageService extends Services.AbstractService implements Serv
|
||||
}
|
||||
|
||||
this.values = sureValues
|
||||
|
||||
if (!this.isStorageWrapped()) {
|
||||
this.values[Services.ValueModesKeys.Unwrapped] = {
|
||||
...(this.values[Services.ValueModesKeys.Wrapped].content as object),
|
||||
...this.values[Services.ValueModesKeys.Unwrapped],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public isStorageWrapped(): boolean {
|
||||
@@ -370,7 +373,7 @@ export class DiskStorageService extends Services.AbstractService implements Serv
|
||||
* Clears simple values from storage only. Does not affect payloads.
|
||||
*/
|
||||
async clearValues() {
|
||||
this.setInitialValues()
|
||||
await this.setInitialValues()
|
||||
await this.immediatelyPersistValuesToDisk()
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
module.exports = {
|
||||
extends: ['../.eslintrc.js'],
|
||||
extends: ['../.eslintrc'],
|
||||
globals: {
|
||||
chai: true,
|
||||
chaiAsPromised: true,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/snjs",
|
||||
"version": "2.130.1",
|
||||
"version": "2.132.4",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,22 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.3.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **mobile:** adjust status bar color to match current theme ([#1624](https://github.com/standardnotes/app/issues/1624)) ([4d5429c](https://github.com/standardnotes/app/commit/4d5429cc89c15f870825f20e97844825102c6aec))
|
||||
|
||||
# [1.3.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
### Features
|
||||
|
||||
* sync page theme color metadata with active theme bg ([#1623](https://github.com/standardnotes/app/issues/1623)) ([5de6f45](https://github.com/standardnotes/app/commit/5de6f459c106127f294693389f62fa1c3ed57798))
|
||||
|
||||
## [1.2.7](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/ui-services
|
||||
|
||||
## [1.2.6](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/ui-services
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/ui-services",
|
||||
"version": "1.2.6",
|
||||
"version": "1.3.1",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
@@ -36,6 +36,7 @@
|
||||
"@typescript-eslint/parser": "^5.12.1",
|
||||
"eslint-plugin-prettier": "*",
|
||||
"jest": "^28.1.2",
|
||||
"ts-jest": "^28.0.5"
|
||||
"ts-jest": "^28.0.5",
|
||||
"typescript": "*"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,13 +248,14 @@ export class ThemeManager extends AbstractService {
|
||||
this.deactivateTheme(theme.uuid)
|
||||
}
|
||||
}
|
||||
|
||||
if (source !== PayloadEmitSource.LocalRetrieved) {
|
||||
this.cacheThemeState().catch(console.error)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
public deactivateAllThemes() {
|
||||
private deactivateAllThemes() {
|
||||
const activeThemes = this.activeThemes.slice()
|
||||
|
||||
for (const uuid of activeThemes) {
|
||||
@@ -287,10 +288,33 @@ export class ThemeManager extends AbstractService {
|
||||
link.rel = 'stylesheet'
|
||||
link.media = 'screen,print'
|
||||
link.id = theme.uuid
|
||||
link.onload = this.syncThemeColorMetadata
|
||||
document.getElementsByTagName('head')[0].appendChild(link)
|
||||
|
||||
if (this.application.isNativeMobileWeb()) {
|
||||
this.application.mobileDevice.handleThemeSchemeChange(theme.package_info.isDark ?? false)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Syncs the active theme's background color to the 'theme-color' meta tag
|
||||
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta/name/theme-color
|
||||
*/
|
||||
private syncThemeColorMetadata() {
|
||||
const themeColorMetaElement = document.querySelector('meta[name="theme-color"]')
|
||||
if (!themeColorMetaElement) {
|
||||
return
|
||||
}
|
||||
|
||||
const bgColor = getComputedStyle(document.documentElement).getPropertyValue('--sn-stylekit-background-color')
|
||||
themeColorMetaElement.setAttribute('content', bgColor ? bgColor.trim() : '#ffffff')
|
||||
}
|
||||
|
||||
private deactivateTheme(uuid: string) {
|
||||
if (!this.activeThemes.includes(uuid)) {
|
||||
return
|
||||
}
|
||||
|
||||
const element = document.getElementById(uuid) as HTMLLinkElement
|
||||
if (element) {
|
||||
element.disabled = true
|
||||
@@ -298,6 +322,10 @@ export class ThemeManager extends AbstractService {
|
||||
}
|
||||
|
||||
removeFromArray(this.activeThemes, uuid)
|
||||
|
||||
if (this.activeThemes.length === 0) {
|
||||
this.application.mobileDevice.handleThemeSchemeChange(false)
|
||||
}
|
||||
}
|
||||
|
||||
private async cacheThemeState() {
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
dist
|
||||
node_modules
|
||||
web.webpack-defaults.js
|
||||
coverage
|
||||
@@ -19,7 +19,9 @@
|
||||
"__mocks__",
|
||||
"src/components",
|
||||
"src/favicon",
|
||||
"src/vendor"
|
||||
"src/vendor",
|
||||
"coverage",
|
||||
"*.config.js"
|
||||
],
|
||||
"rules": {
|
||||
"standard/no-callback-literal": 0, // Disable this as we have too many callbacks relying on literals
|
||||
|
||||
@@ -3,6 +3,118 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [3.55.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.55.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* prefs view on desktop ([#1628](https://github.com/standardnotes/app/issues/1628)) ([a548883](https://github.com/standardnotes/app/commit/a548883863b4e0ec949fa63a8581cc2984614993))
|
||||
|
||||
# [3.55.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
### Features
|
||||
|
||||
* add prefs button to navigation panel on mobile ([#1625](https://github.com/standardnotes/app/issues/1625)) ([0af7201](https://github.com/standardnotes/app/commit/0af720146c412316fcb24999ff73c91337f19fb9))
|
||||
|
||||
## [3.54.6](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* biometrics timing loading ([#1622](https://github.com/standardnotes/app/issues/1622)) ([3c0d4fa](https://github.com/standardnotes/app/commit/3c0d4fac766c3a31bdbebe4f7e88f83ba1ea58da))
|
||||
|
||||
## [3.54.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* protected overlay on mobile ([#1621](https://github.com/standardnotes/app/issues/1621)) ([51e5043](https://github.com/standardnotes/app/commit/51e50433d3e1a3a682bcb7a774129a904a39b12e))
|
||||
|
||||
## [3.54.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **web:** move email notification preferences to account pane ([#1620](https://github.com/standardnotes/app/issues/1620)) ([de64f1b](https://github.com/standardnotes/app/commit/de64f1bfce6d343fe698c55d6eaf307d200df3ee))
|
||||
|
||||
## [3.54.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* better safe area padding on iOS ([#1618](https://github.com/standardnotes/app/issues/1618)) ([86251b4](https://github.com/standardnotes/app/commit/86251b49d3b4965571da1a3c039ec4c6043f733c))
|
||||
|
||||
## [3.54.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
### Reverts
|
||||
|
||||
* Revert "Revert "feat(web): move emails notifications to one pane and enable opening settings via url (#1614)" (#1617)" (#1619) ([e50f4eb](https://github.com/standardnotes/app/commit/e50f4eb92efd65b0b8fa3a5001b8dfb611f60180)), closes [#1614](https://github.com/standardnotes/app/issues/1614) [#1617](https://github.com/standardnotes/app/issues/1617) [#1619](https://github.com/standardnotes/app/issues/1619)
|
||||
|
||||
## [3.54.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
### Reverts
|
||||
|
||||
* Revert "feat(web): move emails notifications to one pane and enable opening settings via url (#1614)" (#1617) ([6824dd2](https://github.com/standardnotes/app/commit/6824dd2d5fe4a6d427ff5465540f3b7865933e98)), closes [#1614](https://github.com/standardnotes/app/issues/1614) [#1617](https://github.com/standardnotes/app/issues/1617)
|
||||
|
||||
# [3.54.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
### Features
|
||||
|
||||
* show selected editor icon in change editor button ([#1615](https://github.com/standardnotes/app/issues/1615)) ([ce252de](https://github.com/standardnotes/app/commit/ce252def332c99d8d8be6a3ce5d76b66e2ea325f))
|
||||
|
||||
# [3.53.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
### Features
|
||||
|
||||
* **web:** move emails notifications to one pane and enable opening settings via url ([#1614](https://github.com/standardnotes/app/issues/1614)) ([1fe833b](https://github.com/standardnotes/app/commit/1fe833bc24a3a426a7230381704d418624cc2b82))
|
||||
|
||||
## [3.52.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* manage subscription button on mobile webview ([#1613](https://github.com/standardnotes/app/issues/1613)) ([db4ceca](https://github.com/standardnotes/app/commit/db4ceca10e4b41707cae2a4daa9718646d808c19))
|
||||
|
||||
# [3.52.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
### Features
|
||||
|
||||
* on mobile goto content tab after selecting revision ([#1611](https://github.com/standardnotes/app/issues/1611)) ([f281041](https://github.com/standardnotes/app/commit/f2810412217afdaa05d5012db37276c843d360b4))
|
||||
|
||||
# [3.51.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-21)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* disable focus mode and dynamic panel switches on mobile ([#1607](https://github.com/standardnotes/app/issues/1607)) ([9dfeac7](https://github.com/standardnotes/app/commit/9dfeac74897594628c0bf657226f3e5e586267dc))
|
||||
* iOS safe area using CSS ([#1610](https://github.com/standardnotes/app/issues/1610)) ([8fa5663](https://github.com/standardnotes/app/commit/8fa566336ceef8a3d7b559b1aaf342f7c51f21cd))
|
||||
|
||||
### Features
|
||||
|
||||
* add lock button to navigation panel on mobile ([#1609](https://github.com/standardnotes/app/issues/1609)) ([d1b7186](https://github.com/standardnotes/app/commit/d1b71861ecf5c8093cbf3d37813ad7ab514edc42))
|
||||
|
||||
## [3.50.6](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-21)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* revert webview alert changes ([#1606](https://github.com/standardnotes/app/issues/1606)) ([ee0d444](https://github.com/standardnotes/app/commit/ee0d44405d14505e043aae2c63848bae1c14f1c3))
|
||||
* tag input auto-submitting when pressing space ([#1608](https://github.com/standardnotes/app/issues/1608)) ([581a08c](https://github.com/standardnotes/app/commit/581a08cd09e02354676d9c14058475e71be05175))
|
||||
|
||||
## [3.50.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-21)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **web:** subscription sharing copy ([271a8d1](https://github.com/standardnotes/app/commit/271a8d1d70d25e4d5bdc7e3ad5cfffb2a5cb4f01))
|
||||
|
||||
## [3.50.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* move wrapped storage to unwrapped if not encrypted ([#1603](https://github.com/standardnotes/app/issues/1603)) ([c5e225d](https://github.com/standardnotes/app/commit/c5e225d335537257f44168b8ad05222afccb508a))
|
||||
|
||||
## [3.50.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* close menu & toggle notes list when note action occurs ([#1601](https://github.com/standardnotes/app/issues/1601)) ([91d9364](https://github.com/standardnotes/app/commit/91d9364e950bc5e613b449427fa32761feb30365))
|
||||
|
||||
## [3.50.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/web",
|
||||
"version": "3.50.2",
|
||||
"version": "3.55.2",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"main": "dist/app.js",
|
||||
"author": "Standard Notes.",
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta content="IE=edge" http-equiv="X-UA-Compatible"/>
|
||||
<meta content="width=device-width, initial-scale=1" name="viewport"/>
|
||||
<meta content="viewport-fit=cover, width=device-width, initial-scale=1" name="viewport"/>
|
||||
|
||||
<link rel="canonical" href="https://app.standardnotes.com" />
|
||||
|
||||
|
||||
@@ -76,6 +76,11 @@ export class WebApplication extends SNApplication implements WebApplicationInter
|
||||
|
||||
if (this.isNativeMobileWeb()) {
|
||||
this.mobileWebReceiver = new MobileWebReceiver(this)
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
console.log = (...args) => {
|
||||
this.mobileDevice.consoleLog(...args)
|
||||
}
|
||||
}
|
||||
|
||||
this.onVisibilityChange = () => {
|
||||
@@ -228,7 +233,7 @@ export class WebApplication extends SNApplication implements WebApplicationInter
|
||||
async handleMobileGainingFocusEvent(): Promise<void> {}
|
||||
|
||||
async handleMobileLosingFocusEvent(): Promise<void> {
|
||||
if (await this.getMobileScreenshotPrivacyEnabled()) {
|
||||
if (this.getMobileScreenshotPrivacyEnabled()) {
|
||||
this.mobileDevice.stopHidingMobileInterfaceFromScreenshots()
|
||||
}
|
||||
|
||||
@@ -236,7 +241,7 @@ export class WebApplication extends SNApplication implements WebApplicationInter
|
||||
}
|
||||
|
||||
async handleMobileResumingFromBackgroundEvent(): Promise<void> {
|
||||
if (await this.getMobileScreenshotPrivacyEnabled()) {
|
||||
if (this.getMobileScreenshotPrivacyEnabled()) {
|
||||
this.mobileDevice.hideMobileInterfaceFromScreenshots()
|
||||
}
|
||||
}
|
||||
|
||||
+3
-35
@@ -45,9 +45,7 @@ const WorkspaceSwitcherMenu: FunctionComponent<Props> = ({
|
||||
|
||||
const signoutAll = useCallback(async () => {
|
||||
const confirmed = await viewControllerManager.application.alertService.confirm(
|
||||
`Are you sure you want to sign out of all workspaces on this device?${
|
||||
viewControllerManager.application.isNativeMobileWeb() && '<b> Your app will quit after sign out completes.</b>'
|
||||
}`,
|
||||
'Are you sure you want to sign out of all workspaces on this device?',
|
||||
undefined,
|
||||
'Sign out all',
|
||||
ButtonType.Danger,
|
||||
@@ -64,44 +62,14 @@ const WorkspaceSwitcherMenu: FunctionComponent<Props> = ({
|
||||
|
||||
const activateWorkspace = useCallback(
|
||||
async (descriptor: ApplicationDescriptor) => {
|
||||
if (viewControllerManager.application.isNativeMobileWeb()) {
|
||||
const confirmed = await viewControllerManager.application.alertService.confirm(
|
||||
'<b>The app needs to be restarted to activate the workspace</b>',
|
||||
undefined,
|
||||
'Quit app and activate workspace',
|
||||
ButtonType.Danger,
|
||||
)
|
||||
|
||||
if (confirmed) {
|
||||
void mainApplicationGroup.unloadCurrentAndActivateDescriptor(descriptor)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
void mainApplicationGroup.unloadCurrentAndActivateDescriptor(descriptor)
|
||||
},
|
||||
[mainApplicationGroup, viewControllerManager.application],
|
||||
[mainApplicationGroup],
|
||||
)
|
||||
|
||||
const addAnotherWorkspace = useCallback(async () => {
|
||||
if (viewControllerManager.application.isNativeMobileWeb()) {
|
||||
const confirmed = await viewControllerManager.application.alertService.confirm(
|
||||
'<b>The app needs to be restarted to add another workspace</b>',
|
||||
undefined,
|
||||
'Quit app and add new workspace',
|
||||
ButtonType.Danger,
|
||||
)
|
||||
|
||||
if (confirmed) {
|
||||
void mainApplicationGroup.unloadCurrentAndCreateNewDescriptor()
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
void mainApplicationGroup.unloadCurrentAndCreateNewDescriptor()
|
||||
}, [mainApplicationGroup, viewControllerManager.application])
|
||||
}, [mainApplicationGroup])
|
||||
|
||||
return (
|
||||
<Menu a11yLabel="Workspace switcher menu" className="px-0 focus:shadow-none" isOpen={isOpen}>
|
||||
|
||||
@@ -175,14 +175,14 @@ const ApplicationView: FunctionComponent<Props> = ({ application, mainApplicatio
|
||||
|
||||
return (
|
||||
<PremiumModalProvider application={application} viewControllerManager={viewControllerManager}>
|
||||
<div className={platformString + ' main-ui-view sn-component'}>
|
||||
<div id="app" className={appClass + ' app app-column-container'}>
|
||||
<FileDragNDropProvider
|
||||
application={application}
|
||||
featuresController={viewControllerManager.featuresController}
|
||||
filesController={viewControllerManager.filesController}
|
||||
>
|
||||
<ResponsivePaneProvider>
|
||||
<ResponsivePaneProvider>
|
||||
<div className={platformString + ' main-ui-view sn-component'}>
|
||||
<div id="app" className={appClass + ' app app-column-container'}>
|
||||
<FileDragNDropProvider
|
||||
application={application}
|
||||
featuresController={viewControllerManager.featuresController}
|
||||
filesController={viewControllerManager.filesController}
|
||||
>
|
||||
<Navigation application={application} />
|
||||
<ContentListView
|
||||
application={application}
|
||||
@@ -197,52 +197,52 @@ const ApplicationView: FunctionComponent<Props> = ({ application, mainApplicatio
|
||||
searchOptionsController={viewControllerManager.searchOptionsController}
|
||||
/>
|
||||
<NoteGroupView application={application} />
|
||||
</ResponsivePaneProvider>
|
||||
</FileDragNDropProvider>
|
||||
</FileDragNDropProvider>
|
||||
</div>
|
||||
|
||||
<>
|
||||
<Footer application={application} applicationGroup={mainApplicationGroup} />
|
||||
<SessionsModal application={application} viewControllerManager={viewControllerManager} />
|
||||
<PreferencesViewWrapper viewControllerManager={viewControllerManager} application={application} />
|
||||
<RevisionHistoryModal
|
||||
application={application}
|
||||
historyModalController={viewControllerManager.historyModalController}
|
||||
notesController={viewControllerManager.notesController}
|
||||
selectionController={viewControllerManager.selectionController}
|
||||
subscriptionController={viewControllerManager.subscriptionController}
|
||||
/>
|
||||
</>
|
||||
|
||||
{renderChallenges()}
|
||||
|
||||
<>
|
||||
<NotesContextMenu
|
||||
application={application}
|
||||
navigationController={viewControllerManager.navigationController}
|
||||
notesController={viewControllerManager.notesController}
|
||||
noteTagsController={viewControllerManager.noteTagsController}
|
||||
historyModalController={viewControllerManager.historyModalController}
|
||||
/>
|
||||
<TagContextMenuWrapper
|
||||
navigationController={viewControllerManager.navigationController}
|
||||
featuresController={viewControllerManager.featuresController}
|
||||
/>
|
||||
<FileContextMenuWrapper
|
||||
filesController={viewControllerManager.filesController}
|
||||
selectionController={viewControllerManager.selectionController}
|
||||
/>
|
||||
<PurchaseFlowWrapper application={application} viewControllerManager={viewControllerManager} />
|
||||
<ConfirmSignoutContainer
|
||||
applicationGroup={mainApplicationGroup}
|
||||
viewControllerManager={viewControllerManager}
|
||||
application={application}
|
||||
/>
|
||||
<ToastContainer />
|
||||
<FilePreviewModalWrapper application={application} viewControllerManager={viewControllerManager} />
|
||||
<PermissionsModalWrapper application={application} />
|
||||
</>
|
||||
</div>
|
||||
|
||||
<>
|
||||
<Footer application={application} applicationGroup={mainApplicationGroup} />
|
||||
<SessionsModal application={application} viewControllerManager={viewControllerManager} />
|
||||
<PreferencesViewWrapper viewControllerManager={viewControllerManager} application={application} />
|
||||
<RevisionHistoryModal
|
||||
application={application}
|
||||
historyModalController={viewControllerManager.historyModalController}
|
||||
notesController={viewControllerManager.notesController}
|
||||
selectionController={viewControllerManager.selectionController}
|
||||
subscriptionController={viewControllerManager.subscriptionController}
|
||||
/>
|
||||
</>
|
||||
|
||||
{renderChallenges()}
|
||||
|
||||
<>
|
||||
<NotesContextMenu
|
||||
application={application}
|
||||
navigationController={viewControllerManager.navigationController}
|
||||
notesController={viewControllerManager.notesController}
|
||||
noteTagsController={viewControllerManager.noteTagsController}
|
||||
historyModalController={viewControllerManager.historyModalController}
|
||||
/>
|
||||
<TagContextMenuWrapper
|
||||
navigationController={viewControllerManager.navigationController}
|
||||
featuresController={viewControllerManager.featuresController}
|
||||
/>
|
||||
<FileContextMenuWrapper
|
||||
filesController={viewControllerManager.filesController}
|
||||
selectionController={viewControllerManager.selectionController}
|
||||
/>
|
||||
<PurchaseFlowWrapper application={application} viewControllerManager={viewControllerManager} />
|
||||
<ConfirmSignoutContainer
|
||||
applicationGroup={mainApplicationGroup}
|
||||
viewControllerManager={viewControllerManager}
|
||||
application={application}
|
||||
/>
|
||||
<ToastContainer />
|
||||
<FilePreviewModalWrapper application={application} viewControllerManager={viewControllerManager} />
|
||||
<PermissionsModalWrapper application={application} />
|
||||
</>
|
||||
</div>
|
||||
</ResponsivePaneProvider>
|
||||
</PremiumModalProvider>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { FunctionComponent, useCallback, useRef, useState } from 'react'
|
||||
import Icon from '@/Components/Icon/Icon'
|
||||
import ChangeEditorMenu from './ChangeEditorMenu'
|
||||
import Popover from '../Popover/Popover'
|
||||
import { classNames } from '@/Utils/ConcatenateClassNames'
|
||||
|
||||
type Props = {
|
||||
application: WebApplication
|
||||
@@ -21,6 +22,12 @@ const ChangeEditorButton: FunctionComponent<Props> = ({
|
||||
const [isOpen, setIsOpen] = useState(false)
|
||||
const buttonRef = useRef<HTMLButtonElement>(null)
|
||||
const containerRef = useRef<HTMLDivElement>(null)
|
||||
const [selectedEditor, setSelectedEditor] = useState(() => {
|
||||
return note ? application.componentManager.editorForNote(note) : undefined
|
||||
})
|
||||
const [selectedEditorIcon, selectedEditorIconTint] = application.iconsController.getIconAndTintForNoteType(
|
||||
selectedEditor?.package_info.note_type,
|
||||
)
|
||||
|
||||
const toggleMenu = useCallback(async () => {
|
||||
const willMenuOpen = !isOpen
|
||||
@@ -33,13 +40,16 @@ const ChangeEditorButton: FunctionComponent<Props> = ({
|
||||
return (
|
||||
<div ref={containerRef}>
|
||||
<button
|
||||
className="bg-text-padding flex h-8 min-w-8 cursor-pointer items-center justify-center rounded-full border border-solid border-border text-neutral hover:bg-contrast focus:bg-contrast"
|
||||
className={classNames(
|
||||
'bg-text-padding flex h-8 min-w-8 cursor-pointer items-center justify-center rounded-full border border-solid text-neutral hover:bg-contrast focus:bg-contrast',
|
||||
`border-accessory-tint-${selectedEditorIconTint}`,
|
||||
)}
|
||||
title="Change note type"
|
||||
aria-label="Change note type"
|
||||
onClick={toggleMenu}
|
||||
ref={buttonRef}
|
||||
>
|
||||
<Icon type="dashboard" />
|
||||
<Icon type={selectedEditorIcon} className={`text-accessory-tint-${selectedEditorIconTint}`} />
|
||||
</button>
|
||||
<Popover togglePopover={toggleMenu} anchorElement={buttonRef.current} open={isOpen} className="pt-2 md:pt-0">
|
||||
<ChangeEditorMenu
|
||||
@@ -49,6 +59,9 @@ const ChangeEditorButton: FunctionComponent<Props> = ({
|
||||
closeMenu={() => {
|
||||
setIsOpen(false)
|
||||
}}
|
||||
onSelect={(component) => {
|
||||
setSelectedEditor(component)
|
||||
}}
|
||||
/>
|
||||
</Popover>
|
||||
</div>
|
||||
|
||||
@@ -31,11 +31,18 @@ type ChangeEditorMenuProps = {
|
||||
closeMenu: () => void
|
||||
isVisible: boolean
|
||||
note: SNNote | undefined
|
||||
onSelect?: (component: SNComponent | undefined) => void
|
||||
}
|
||||
|
||||
const getGroupId = (group: EditorMenuGroup) => group.title.toLowerCase().replace(/\s/, '-')
|
||||
|
||||
const ChangeEditorMenu: FunctionComponent<ChangeEditorMenuProps> = ({ application, closeMenu, isVisible, note }) => {
|
||||
const ChangeEditorMenu: FunctionComponent<ChangeEditorMenuProps> = ({
|
||||
application,
|
||||
closeMenu,
|
||||
isVisible,
|
||||
note,
|
||||
onSelect,
|
||||
}) => {
|
||||
const editors = useMemo(
|
||||
() =>
|
||||
application.componentManager.componentsForArea(ComponentArea.Editor).sort((a, b) => {
|
||||
@@ -162,8 +169,12 @@ const ChangeEditorMenu: FunctionComponent<ChangeEditorMenuProps> = ({ applicatio
|
||||
}
|
||||
|
||||
closeMenu()
|
||||
|
||||
if (onSelect) {
|
||||
onSelect(itemToBeSelected.component)
|
||||
}
|
||||
},
|
||||
[application.componentManager, closeMenu, currentEditor, note, premiumModal, selectComponent],
|
||||
[application.componentManager, closeMenu, currentEditor, note, onSelect, premiumModal, selectComponent],
|
||||
)
|
||||
|
||||
return (
|
||||
|
||||
@@ -41,15 +41,7 @@ const ConfirmSignoutModal: FunctionComponent<Props> = ({ application, viewContro
|
||||
<AlertDialogLabel className="sk-h3 sk-panel-section-title">Sign out workspace?</AlertDialogLabel>
|
||||
<AlertDialogDescription className="sk-panel-row">
|
||||
<div>
|
||||
<p className="text-foreground">
|
||||
{STRING_SIGN_OUT_CONFIRMATION}
|
||||
{application.isNativeMobileWeb() && (
|
||||
<div className="font-bold">
|
||||
<br />
|
||||
Your app will quit after sign out completes.
|
||||
</div>
|
||||
)}
|
||||
</p>
|
||||
<p className="text-foreground">{STRING_SIGN_OUT_CONFIRMATION}</p>
|
||||
{showWorkspaceWarning && (
|
||||
<>
|
||||
<br />
|
||||
|
||||
@@ -185,13 +185,13 @@ const ContentListView: FunctionComponent<Props> = ({
|
||||
<div
|
||||
id="items-column"
|
||||
className={classNames(
|
||||
'sn-component section app-column flex h-screen flex-col md:h-full',
|
||||
'sn-component section app-column flex h-screen flex-col pt-safe-top md:h-full',
|
||||
'xl:w-87.5 xsm-only:!w-full sm-only:!w-full pointer-coarse:md-only:!w-52 pointer-coarse:lg-only:!w-52',
|
||||
)}
|
||||
aria-label={'Notes & Files'}
|
||||
ref={itemsViewPanelRef}
|
||||
>
|
||||
<ResponsivePaneContent paneId={AppPaneId.Items} className="min-h-[85vh]">
|
||||
<ResponsivePaneContent paneId={AppPaneId.Items}>
|
||||
<div id="items-title-bar" className="section-title-bar border-b border-solid border-border">
|
||||
<div id="items-title-bar-container">
|
||||
<input
|
||||
|
||||
@@ -8,6 +8,8 @@ import { FilesController } from '@/Controllers/FilesController'
|
||||
import { SelectedItemsController } from '@/Controllers/SelectedItemsController'
|
||||
import HorizontalSeparator from '../Shared/HorizontalSeparator'
|
||||
import { formatSizeToReadableString } from '@standardnotes/filepicker'
|
||||
import { useResponsiveAppPane } from '../ResponsivePane/ResponsivePaneProvider'
|
||||
import { AppPaneId } from '../ResponsivePane/AppPaneMetadata'
|
||||
|
||||
type Props = {
|
||||
closeMenu: () => void
|
||||
@@ -30,6 +32,7 @@ const FileMenuOptions: FunctionComponent<Props> = ({
|
||||
}) => {
|
||||
const { selectedFiles } = selectionController
|
||||
const { handleFileAction } = filesController
|
||||
const { toggleAppPane } = useResponsiveAppPane()
|
||||
|
||||
const hasProtectedFiles = useMemo(() => selectedFiles.some((file) => file.protected), [selectedFiles])
|
||||
const hasSelectedMultipleFiles = useMemo(() => selectedFiles.length > 1, [selectedFiles.length])
|
||||
@@ -68,6 +71,11 @@ const FileMenuOptions: FunctionComponent<Props> = ({
|
||||
closeMenu()
|
||||
}, [closeMenu, handleFileAction, selectedFiles])
|
||||
|
||||
const closeMenuAndToggleFilesList = useCallback(() => {
|
||||
toggleAppPane(AppPaneId.Items)
|
||||
closeMenu()
|
||||
}, [closeMenu, toggleAppPane])
|
||||
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
@@ -139,6 +147,7 @@ const FileMenuOptions: FunctionComponent<Props> = ({
|
||||
<button
|
||||
className="flex w-full cursor-pointer items-center border-0 bg-transparent px-3 py-1.5 text-left text-sm text-text hover:bg-contrast hover:text-foreground focus:bg-info-backdrop focus:shadow-none"
|
||||
onClick={() => {
|
||||
closeMenuAndToggleFilesList()
|
||||
void filesController.deleteFilesPermanently(selectionController.selectedFiles)
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -28,16 +28,12 @@ const FileView = ({ application, viewControllerManager, file }: FileViewProps) =
|
||||
}, [application, file])
|
||||
|
||||
return shouldShowProtectedOverlay ? (
|
||||
<div aria-label="Note" className="section editor sn-component">
|
||||
<div className="flex h-full items-center justify-center">
|
||||
<ProtectedItemOverlay
|
||||
viewControllerManager={viewControllerManager}
|
||||
hasProtectionSources={application.hasProtectionSources()}
|
||||
onViewItem={dismissProtectedOverlay}
|
||||
itemType={'note'}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<ProtectedItemOverlay
|
||||
viewControllerManager={viewControllerManager}
|
||||
hasProtectionSources={application.hasProtectionSources()}
|
||||
onViewItem={dismissProtectedOverlay}
|
||||
itemType={'file'}
|
||||
/>
|
||||
) : (
|
||||
<FileViewWithoutProtection application={application} viewControllerManager={viewControllerManager} file={file} />
|
||||
)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { IconType } from '@standardnotes/snjs'
|
||||
|
||||
export const PremiumFeatureIconName: IconType = 'asterisk'
|
||||
export const PremiumFeatureIconClass = 'text-info'
|
||||
export const PremiumFeatureIconClass = 'text-info group-disabled:text-passive-2'
|
||||
|
||||
@@ -11,6 +11,7 @@ import { AppPaneId } from '@/Components/ResponsivePane/AppPaneMetadata'
|
||||
import { classNames } from '@/Utils/ConcatenateClassNames'
|
||||
import Icon from '../Icon/Icon'
|
||||
import { useResponsiveAppPane } from '../ResponsivePane/ResponsivePaneProvider'
|
||||
import { isIOS } from '@/Utils'
|
||||
|
||||
type Props = {
|
||||
application: WebApplication
|
||||
@@ -22,6 +23,15 @@ const Navigation: FunctionComponent<Props> = ({ application }) => {
|
||||
const [panelWidth, setPanelWidth] = useState<number>(0)
|
||||
const { toggleAppPane } = useResponsiveAppPane()
|
||||
|
||||
const [hasPasscode, setHasPasscode] = useState(() => application.hasPasscode())
|
||||
useEffect(() => {
|
||||
const removeObserver = application.addEventObserver(async () => {
|
||||
setHasPasscode(application.hasPasscode())
|
||||
}, ApplicationEvent.KeyStatusChanged)
|
||||
|
||||
return removeObserver
|
||||
}, [application])
|
||||
|
||||
useEffect(() => {
|
||||
const removeObserver = application.addEventObserver(async () => {
|
||||
const width = application.getPreference(PrefKey.TagsPanelWidth)
|
||||
@@ -51,7 +61,10 @@ const Navigation: FunctionComponent<Props> = ({ application }) => {
|
||||
return (
|
||||
<div
|
||||
id="navigation"
|
||||
className="sn-component section app-column h-screen max-h-screen w-[220px] overflow-hidden pb-8 md:h-full md:min-h-0 md:py-0 xsm-only:!w-full sm-only:!w-full"
|
||||
className={classNames(
|
||||
'sn-component section app-column h-screen max-h-screen w-[220px] overflow-hidden pt-safe-top md:h-full md:min-h-0 md:py-0 xsm-only:!w-full sm-only:!w-full',
|
||||
isIOS() ? 'pb-safe-bottom' : 'pb-2.5',
|
||||
)}
|
||||
ref={ref}
|
||||
>
|
||||
<ResponsivePaneContent paneId={AppPaneId.Navigation} contentElementId="navigation-content">
|
||||
@@ -87,20 +100,41 @@ const Navigation: FunctionComponent<Props> = ({ application }) => {
|
||||
onClick={() => {
|
||||
viewControllerManager.accountMenuController.toggleShow()
|
||||
}}
|
||||
title="Go to items list"
|
||||
aria-label="Go to items list"
|
||||
title="Go to account menu"
|
||||
aria-label="Go to account menu"
|
||||
>
|
||||
<Icon type="account-circle" />
|
||||
</button>
|
||||
{hasPasscode && (
|
||||
<button
|
||||
id="lock-item"
|
||||
onClick={() => application.lock()}
|
||||
title="Locks application and wipes unencrypted data from memory."
|
||||
aria-label="Locks application and wipes unencrypted data from memory."
|
||||
className="ml-2.5 flex h-8 min-w-8 cursor-pointer items-center justify-center rounded-full border border-solid border-border bg-default text-neutral hover:bg-contrast focus:bg-contrast"
|
||||
>
|
||||
<Icon type="lock-filled" size="custom" className="h-4.5 w-4.5" />
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
className="ml-2.5 flex h-8 min-w-8 cursor-pointer items-center justify-center rounded-full border border-solid border-border bg-default text-neutral hover:bg-contrast focus:bg-contrast"
|
||||
onClick={() => {
|
||||
viewControllerManager.preferencesController.openPreferences()
|
||||
}}
|
||||
title="Go to preferences"
|
||||
aria-label="Go to preferences"
|
||||
>
|
||||
<Icon type="tune" />
|
||||
</button>
|
||||
<button
|
||||
className="ml-2.5 flex h-8 min-w-8 cursor-pointer items-center justify-center rounded-full border border-solid border-border bg-default text-neutral hover:bg-contrast focus:bg-contrast"
|
||||
onClick={() => {
|
||||
viewControllerManager.quickSettingsMenuController.toggle()
|
||||
}}
|
||||
title="Go to items list"
|
||||
aria-label="Go to items list"
|
||||
title="Go to quick settings menu"
|
||||
aria-label="Go to quick settings menu"
|
||||
>
|
||||
<Icon type="tune" />
|
||||
<Icon type="themes" />
|
||||
</button>
|
||||
</div>
|
||||
</ResponsivePaneContent>
|
||||
|
||||
@@ -91,7 +91,7 @@ class NoteGroupView extends PureComponent<Props, State> {
|
||||
return (
|
||||
<div
|
||||
id={ElementIds.EditorColumn}
|
||||
className="app-column app-column-third flex min-h-screen flex-col md:h-full md:min-h-0"
|
||||
className="app-column app-column-third flex min-h-screen flex-col pt-safe-top md:h-full md:min-h-0"
|
||||
>
|
||||
<ResponsivePaneContent paneId={AppPaneId.Editor} className="flex-grow">
|
||||
{this.state.showMultipleSelectedNotes && (
|
||||
|
||||
@@ -874,18 +874,12 @@ class NoteView extends PureComponent<NoteViewProps, State> {
|
||||
override render() {
|
||||
if (this.state.showProtectedWarning) {
|
||||
return (
|
||||
<div aria-label="Note" className="section editor sn-component">
|
||||
{this.state.showProtectedWarning && (
|
||||
<div className="flex h-full items-center justify-center">
|
||||
<ProtectedItemOverlay
|
||||
viewControllerManager={this.viewControllerManager}
|
||||
hasProtectionSources={this.application.hasProtectionSources()}
|
||||
onViewItem={this.dismissProtectedWarning}
|
||||
itemType={'note'}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<ProtectedItemOverlay
|
||||
viewControllerManager={this.viewControllerManager}
|
||||
hasProtectionSources={this.application.hasProtectionSources()}
|
||||
onViewItem={this.dismissProtectedWarning}
|
||||
itemType={'note'}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -23,10 +23,12 @@ const NotesContextMenu = ({
|
||||
noteTagsController,
|
||||
historyModalController,
|
||||
}: Props) => {
|
||||
const { contextMenuOpen, contextMenuClickLocation } = notesController
|
||||
const { contextMenuOpen, contextMenuClickLocation, setContextMenuOpen } = notesController
|
||||
|
||||
const contextMenuRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
const closeMenu = () => setContextMenuOpen(!contextMenuOpen)
|
||||
|
||||
return (
|
||||
<Popover
|
||||
align="start"
|
||||
@@ -37,7 +39,7 @@ const NotesContextMenu = ({
|
||||
className="py-2"
|
||||
open={contextMenuOpen}
|
||||
side="right"
|
||||
togglePopover={() => notesController.setContextMenuOpen(!contextMenuOpen)}
|
||||
togglePopover={closeMenu}
|
||||
>
|
||||
<div ref={contextMenuRef}>
|
||||
<NotesOptions
|
||||
@@ -46,6 +48,7 @@ const NotesContextMenu = ({
|
||||
notesController={notesController}
|
||||
noteTagsController={noteTagsController}
|
||||
historyModalController={historyModalController}
|
||||
closeMenu={closeMenu}
|
||||
/>
|
||||
</div>
|
||||
</Popover>
|
||||
|
||||
@@ -13,6 +13,8 @@ import { NotesOptionsProps } from './NotesOptionsProps'
|
||||
import { NotesController } from '@/Controllers/NotesController'
|
||||
import HorizontalSeparator from '../Shared/HorizontalSeparator'
|
||||
import { formatDateForContextMenu } from '@/Utils/DateUtils'
|
||||
import { useResponsiveAppPane } from '../ResponsivePane/ResponsivePaneProvider'
|
||||
import { AppPaneId } from '../ResponsivePane/AppPaneMetadata'
|
||||
|
||||
type DeletePermanentlyButtonProps = {
|
||||
onClick: () => void
|
||||
@@ -175,8 +177,10 @@ const NotesOptions = ({
|
||||
notesController,
|
||||
noteTagsController,
|
||||
historyModalController,
|
||||
closeMenu,
|
||||
}: NotesOptionsProps) => {
|
||||
const [altKeyDown, setAltKeyDown] = useState(false)
|
||||
const { toggleAppPane } = useResponsiveAppPane()
|
||||
|
||||
const toggleOn = (condition: (note: SNNote) => boolean) => {
|
||||
const notesMatchingAttribute = notes.filter(condition)
|
||||
@@ -252,11 +256,15 @@ const NotesOptions = ({
|
||||
}
|
||||
}, [application, getNoteFileName, notes])
|
||||
|
||||
const duplicateSelectedItems = useCallback(() => {
|
||||
notes.forEach((note) => {
|
||||
application.mutator.duplicateItem(note).catch(console.error)
|
||||
})
|
||||
}, [application, notes])
|
||||
const closeMenuAndToggleNotesList = useCallback(() => {
|
||||
toggleAppPane(AppPaneId.Items)
|
||||
closeMenu()
|
||||
}, [closeMenu, toggleAppPane])
|
||||
|
||||
const duplicateSelectedItems = useCallback(async () => {
|
||||
await Promise.all(notes.map((note) => application.mutator.duplicateItem(note).catch(console.error)))
|
||||
closeMenuAndToggleNotesList()
|
||||
}, [application.mutator, closeMenuAndToggleNotesList, notes])
|
||||
|
||||
const openRevisionHistoryModal = useCallback(() => {
|
||||
historyModalController.openModal(notesController.firstSelectedNote)
|
||||
@@ -365,8 +373,9 @@ const NotesOptions = ({
|
||||
{unarchived && (
|
||||
<button
|
||||
className="flex w-full cursor-pointer items-center border-0 bg-transparent px-3 py-1.5 text-left text-menu-item text-text hover:bg-contrast hover:text-foreground focus:bg-info-backdrop focus:shadow-none"
|
||||
onClick={() => {
|
||||
notesController.setArchiveSelectedNotes(true).catch(console.error)
|
||||
onClick={async () => {
|
||||
await notesController.setArchiveSelectedNotes(true).catch(console.error)
|
||||
closeMenuAndToggleNotesList()
|
||||
}}
|
||||
>
|
||||
<Icon type="archive" className={iconClassWarning} />
|
||||
@@ -376,8 +385,9 @@ const NotesOptions = ({
|
||||
{archived && (
|
||||
<button
|
||||
className="flex w-full cursor-pointer items-center border-0 bg-transparent px-3 py-1.5 text-left text-menu-item text-text hover:bg-contrast hover:text-foreground focus:bg-info-backdrop focus:shadow-none"
|
||||
onClick={() => {
|
||||
notesController.setArchiveSelectedNotes(false).catch(console.error)
|
||||
onClick={async () => {
|
||||
await notesController.setArchiveSelectedNotes(false).catch(console.error)
|
||||
closeMenuAndToggleNotesList()
|
||||
}}
|
||||
>
|
||||
<Icon type="unarchive" className={iconClassWarning} />
|
||||
@@ -389,6 +399,7 @@ const NotesOptions = ({
|
||||
<DeletePermanentlyButton
|
||||
onClick={async () => {
|
||||
await notesController.deleteNotesPermanently()
|
||||
closeMenuAndToggleNotesList()
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
@@ -396,6 +407,7 @@ const NotesOptions = ({
|
||||
className="flex w-full cursor-pointer items-center border-0 bg-transparent px-3 py-1.5 text-left text-menu-item text-text hover:bg-contrast hover:text-foreground focus:bg-info-backdrop focus:shadow-none"
|
||||
onClick={async () => {
|
||||
await notesController.setTrashSelectedNotes(true)
|
||||
closeMenuAndToggleNotesList()
|
||||
}}
|
||||
>
|
||||
<Icon type="trash" className={iconClassDanger} />
|
||||
@@ -408,6 +420,7 @@ const NotesOptions = ({
|
||||
className="flex w-full cursor-pointer items-center border-0 bg-transparent px-3 py-1.5 text-left text-menu-item text-text hover:bg-contrast hover:text-foreground focus:bg-info-backdrop focus:shadow-none"
|
||||
onClick={async () => {
|
||||
await notesController.setTrashSelectedNotes(false)
|
||||
closeMenuAndToggleNotesList()
|
||||
}}
|
||||
>
|
||||
<Icon type="restore" className={iconClassSuccess} />
|
||||
@@ -416,12 +429,14 @@ const NotesOptions = ({
|
||||
<DeletePermanentlyButton
|
||||
onClick={async () => {
|
||||
await notesController.deleteNotesPermanently()
|
||||
closeMenuAndToggleNotesList()
|
||||
}}
|
||||
/>
|
||||
<button
|
||||
className="flex w-full cursor-pointer items-center border-0 bg-transparent px-3 py-1.5 text-left text-menu-item text-text hover:bg-contrast hover:text-foreground focus:bg-info-backdrop focus:shadow-none"
|
||||
onClick={async () => {
|
||||
await notesController.emptyTrash()
|
||||
closeMenuAndToggleNotesList()
|
||||
}}
|
||||
>
|
||||
<div className="flex items-start">
|
||||
|
||||
@@ -55,6 +55,7 @@ const NotesOptionsPanel = ({
|
||||
notesController={notesController}
|
||||
noteTagsController={noteTagsController}
|
||||
historyModalController={historyModalController}
|
||||
closeMenu={toggleMenu}
|
||||
/>
|
||||
</Popover>
|
||||
</>
|
||||
|
||||
@@ -10,4 +10,5 @@ export type NotesOptionsProps = {
|
||||
notesController: NotesController
|
||||
noteTagsController: NoteTagsController
|
||||
historyModalController: HistoryModalController
|
||||
closeMenu: () => void
|
||||
}
|
||||
|
||||
@@ -57,9 +57,8 @@ const PositionedPopoverContent = ({
|
||||
<Portal>
|
||||
<div
|
||||
className={classNames(
|
||||
'absolute top-0 left-0 flex h-full w-full min-w-80 cursor-auto flex-col overflow-y-auto rounded bg-default shadow-main md:h-auto md:max-w-xs',
|
||||
'safe-area-padding absolute top-0 left-0 flex h-full w-full min-w-80 cursor-auto flex-col overflow-y-auto rounded bg-default shadow-main md:h-auto md:max-w-xs',
|
||||
overrideZIndex ? overrideZIndex : 'z-dropdown-menu',
|
||||
className,
|
||||
)}
|
||||
style={{
|
||||
...styles,
|
||||
@@ -71,15 +70,17 @@ const PositionedPopoverContent = ({
|
||||
}}
|
||||
data-popover={id}
|
||||
>
|
||||
<div className="md:hidden">
|
||||
<div className="flex items-center justify-end px-3">
|
||||
<button className="rounded-full border border-border p-1" onClick={togglePopover}>
|
||||
<Icon type="close" className="h-4 w-4" />
|
||||
</button>
|
||||
<div className={className}>
|
||||
<div className="md:hidden">
|
||||
<div className="flex items-center justify-end px-3">
|
||||
<button className="rounded-full border border-border p-1" onClick={togglePopover}>
|
||||
<Icon type="close" className="h-4 w-4" />
|
||||
</button>
|
||||
</div>
|
||||
<HorizontalSeparator classes="my-2" />
|
||||
</div>
|
||||
<HorizontalSeparator classes="my-2" />
|
||||
{children}
|
||||
</div>
|
||||
{children}
|
||||
</div>
|
||||
</Portal>
|
||||
)
|
||||
|
||||
+2
@@ -9,6 +9,7 @@ import SignOutWrapper from './SignOutView'
|
||||
import FilesSection from './Files'
|
||||
import PreferencesPane from '../../PreferencesComponents/PreferencesPane'
|
||||
import SubscriptionSharing from './SubscriptionSharing/SubscriptionSharing'
|
||||
import Email from './Email'
|
||||
|
||||
type Props = {
|
||||
application: WebApplication
|
||||
@@ -30,6 +31,7 @@ const AccountPreferences = ({ application, viewControllerManager }: Props) => (
|
||||
{application.hasAccount() && viewControllerManager.featuresController.hasFiles && (
|
||||
<FilesSection application={application} />
|
||||
)}
|
||||
<Email application={application} />
|
||||
<SignOutWrapper application={application} viewControllerManager={viewControllerManager} />
|
||||
</PreferencesPane>
|
||||
)
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
import { MuteMarketingEmailsOption, MuteSignInEmailsOption, SettingName } from '@standardnotes/snjs'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { FunctionComponent, useCallback, useEffect, useState } from 'react'
|
||||
|
||||
import HorizontalSeparator from '@/Components/Shared/HorizontalSeparator'
|
||||
import Switch from '@/Components/Switch/Switch'
|
||||
import { Subtitle, Text, Title } from '@/Components/Preferences/PreferencesComponents/Content'
|
||||
import { WebApplication } from '@/Application/Application'
|
||||
import { STRING_FAILED_TO_UPDATE_USER_SETTING } from '@/Constants/Strings'
|
||||
import PreferencesGroup from '@/Components/Preferences/PreferencesComponents/PreferencesGroup'
|
||||
import PreferencesSegment from '@/Components/Preferences/PreferencesComponents/PreferencesSegment'
|
||||
import Spinner from '@/Components/Spinner/Spinner'
|
||||
|
||||
type Props = {
|
||||
application: WebApplication
|
||||
}
|
||||
|
||||
const Email: FunctionComponent<Props> = ({ application }: Props) => {
|
||||
const [signInEmailsMutedValue, setSignInEmailsMutedValue] = useState(MuteSignInEmailsOption.NotMuted)
|
||||
const [marketingEmailsMutedValue, setMarketingEmailsMutedValue] = useState(MuteMarketingEmailsOption.NotMuted)
|
||||
const [isLoading, setIsLoading] = useState(true)
|
||||
|
||||
const updateSetting = async (settingName: SettingName, payload: string): Promise<boolean> => {
|
||||
try {
|
||||
await application.settings.updateSetting(settingName, payload, false)
|
||||
return true
|
||||
} catch (e) {
|
||||
application.alertService.alert(STRING_FAILED_TO_UPDATE_USER_SETTING).catch(console.error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
const loadSettings = useCallback(async () => {
|
||||
if (!application.getUser()) {
|
||||
return
|
||||
}
|
||||
setIsLoading(true)
|
||||
|
||||
try {
|
||||
const userSettings = await application.settings.listSettings()
|
||||
setSignInEmailsMutedValue(
|
||||
userSettings.getSettingValue<MuteSignInEmailsOption>(
|
||||
SettingName.MuteSignInEmails,
|
||||
MuteSignInEmailsOption.NotMuted,
|
||||
),
|
||||
),
|
||||
setMarketingEmailsMutedValue(
|
||||
userSettings.getSettingValue<MuteMarketingEmailsOption>(
|
||||
SettingName.MuteMarketingEmails,
|
||||
MuteMarketingEmailsOption.NotMuted,
|
||||
),
|
||||
)
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
} finally {
|
||||
setIsLoading(false)
|
||||
}
|
||||
}, [application])
|
||||
|
||||
useEffect(() => {
|
||||
loadSettings().catch(console.error)
|
||||
}, [loadSettings])
|
||||
|
||||
const toggleMuteSignInEmails = async () => {
|
||||
const previousValue = signInEmailsMutedValue
|
||||
const newValue =
|
||||
previousValue === MuteSignInEmailsOption.Muted ? MuteSignInEmailsOption.NotMuted : MuteSignInEmailsOption.Muted
|
||||
setSignInEmailsMutedValue(newValue)
|
||||
|
||||
const updateResult = await updateSetting(SettingName.MuteSignInEmails, newValue)
|
||||
|
||||
if (!updateResult) {
|
||||
setSignInEmailsMutedValue(previousValue)
|
||||
}
|
||||
}
|
||||
|
||||
const toggleMuteMarketingEmails = async () => {
|
||||
const previousValue = marketingEmailsMutedValue
|
||||
const newValue =
|
||||
previousValue === MuteMarketingEmailsOption.Muted
|
||||
? MuteMarketingEmailsOption.NotMuted
|
||||
: MuteMarketingEmailsOption.Muted
|
||||
setMarketingEmailsMutedValue(newValue)
|
||||
|
||||
const updateResult = await updateSetting(SettingName.MuteMarketingEmails, newValue)
|
||||
|
||||
if (!updateResult) {
|
||||
setMarketingEmailsMutedValue(previousValue)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<PreferencesGroup>
|
||||
<PreferencesSegment>
|
||||
<Title>Email</Title>
|
||||
<div>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex flex-col">
|
||||
<Subtitle>Disable sign-in notification emails</Subtitle>
|
||||
<Text>
|
||||
Disables email notifications when a new sign-in occurs on your account. (Email notifications are
|
||||
available to paid subscribers).
|
||||
</Text>
|
||||
</div>
|
||||
{isLoading ? (
|
||||
<Spinner className="ml-2 flex-shrink-0" />
|
||||
) : (
|
||||
<Switch
|
||||
onChange={toggleMuteSignInEmails}
|
||||
checked={signInEmailsMutedValue === MuteSignInEmailsOption.Muted}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<HorizontalSeparator classes="my-4" />
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex flex-col">
|
||||
<Subtitle>Disable marketing notification emails</Subtitle>
|
||||
<Text>Disables email notifications with special deals and promotions.</Text>
|
||||
</div>
|
||||
{isLoading ? (
|
||||
<Spinner className="ml-2 flex-shrink-0" />
|
||||
) : (
|
||||
<Switch
|
||||
onChange={toggleMuteMarketingEmails}
|
||||
checked={marketingEmailsMutedValue === MuteMarketingEmailsOption.Muted}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</PreferencesSegment>
|
||||
</PreferencesGroup>
|
||||
)
|
||||
}
|
||||
|
||||
export default observer(Email)
|
||||
+2
-2
@@ -51,7 +51,7 @@ const InvitationsList = ({ subscriptionState, application }: Props) => {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<SubtitleLight className="mb-2 text-info">Active Invitations:</SubtitleLight>
|
||||
<SubtitleLight className="mb-2 text-info">Active Invites:</SubtitleLight>
|
||||
{activeSubscriptions?.map((invitation) => (
|
||||
<div key={invitation.uuid} className="mt-1 mb-4">
|
||||
<Text>
|
||||
@@ -64,7 +64,7 @@ const InvitationsList = ({ subscriptionState, application }: Props) => {
|
||||
))}
|
||||
{!!inActiveSubscriptions?.length && (
|
||||
<>
|
||||
<SubtitleLight className="mb-2 text-info">Inactive Invitations:</SubtitleLight>
|
||||
<SubtitleLight className="mb-2 text-info">Inactive Invites:</SubtitleLight>
|
||||
<div>
|
||||
{inActiveSubscriptions?.map((invitation) => (
|
||||
<div key={invitation.uuid} className="mb-3 first:mt-2">
|
||||
|
||||
+3
-3
@@ -13,7 +13,7 @@ import InviteForm from './InviteForm'
|
||||
import InviteSuccess from './InviteSuccess'
|
||||
|
||||
enum SubmitButtonTitles {
|
||||
Default = 'Send Invitation',
|
||||
Default = 'Send Invite',
|
||||
Sending = 'Sending...',
|
||||
Finish = 'Finish',
|
||||
}
|
||||
@@ -96,7 +96,7 @@ const Invite: FunctionComponent<Props> = ({ onCloseDialog, application, subscrip
|
||||
const success = await processInvite()
|
||||
if (!success) {
|
||||
application.alertService
|
||||
.alert('We could not send the invitation. Please try again or contact support if the issue persists.')
|
||||
.alert('An error occurred while sending the invite. Please try again or contact support if the issue persists.')
|
||||
.catch(console.error)
|
||||
|
||||
resetProgressState()
|
||||
@@ -112,7 +112,7 @@ const Invite: FunctionComponent<Props> = ({ onCloseDialog, application, subscrip
|
||||
return (
|
||||
<div>
|
||||
<ModalDialog>
|
||||
<ModalDialogLabel closeDialog={handleDialogClose}>Invite</ModalDialogLabel>
|
||||
<ModalDialogLabel closeDialog={handleDialogClose}>Share your Subscription</ModalDialogLabel>
|
||||
<ModalDialogDescription className="flex flex-row items-center px-4.5">
|
||||
{currentStep === Steps.InitialStep && <InviteForm setInviteeEmail={setInviteeEmail} />}
|
||||
{currentStep === Steps.FinishStep && <InviteSuccess />}
|
||||
|
||||
+2
-2
@@ -9,8 +9,8 @@ const SharingStatusText = ({ subscriptionState }: Props) => {
|
||||
|
||||
return (
|
||||
<Text className="mt-1">
|
||||
You have have used <span className="font-bold">{usedInvitationsCount}</span> out of {allowedInvitationsCount}{' '}
|
||||
subscription invitations.
|
||||
You've used <span className="font-bold">{usedInvitationsCount}</span> out of {allowedInvitationsCount}{' '}
|
||||
subscription invites.
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -126,10 +126,10 @@ const Defaults: FunctionComponent<Props> = ({ application }) => {
|
||||
{application.isNativeMobileWeb() && (
|
||||
<>
|
||||
<div className="flex flex-col">
|
||||
<Subtitle>Switch to Native View</Subtitle>
|
||||
<Subtitle>Switch to Classic Mobile Experience</Subtitle>
|
||||
<Text>
|
||||
This will close the app and fully switch to the native view next time you open it. You will be able to
|
||||
switch back from the settings.
|
||||
This will close the app and switch back to the soon-to-be removed classic mobile experience. You can opt
|
||||
back in to new experience from the app settings.
|
||||
</Text>
|
||||
<Button className="mt-3 min-w-20" label="Switch" onClick={switchToNativeView} />
|
||||
</div>
|
||||
|
||||
+3
-6
@@ -19,10 +19,8 @@ const BiometricsLock = ({ application }: Props) => {
|
||||
const [biometricsTimingOptions, setBiometricsTimingOptions] = useState(() => application.getBiometricsTimingOptions())
|
||||
|
||||
useEffect(() => {
|
||||
const getHasBiometrics = async () => {
|
||||
const appHasBiometrics = await application.hasBiometrics()
|
||||
setHasBiometrics(appHasBiometrics)
|
||||
}
|
||||
const appHasBiometrics = application.hasBiometrics()
|
||||
setHasBiometrics(appHasBiometrics)
|
||||
|
||||
const hasBiometricsSupport = async () => {
|
||||
const hasBiometricsAvailable = await (
|
||||
@@ -30,7 +28,6 @@ const BiometricsLock = ({ application }: Props) => {
|
||||
).getDeviceBiometricsAvailability?.()
|
||||
setSupportsBiometrics(hasBiometricsAvailable)
|
||||
}
|
||||
void getHasBiometrics()
|
||||
void hasBiometricsSupport()
|
||||
}, [application])
|
||||
|
||||
@@ -50,7 +47,7 @@ const BiometricsLock = ({ application }: Props) => {
|
||||
await disableBiometrics()
|
||||
} else {
|
||||
setHasBiometrics(true)
|
||||
await application.enableBiometrics()
|
||||
application.enableBiometrics()
|
||||
await setBiometricsTimingValue(MobileUnlockTiming.OnQuit)
|
||||
}
|
||||
}
|
||||
|
||||
+5
-8
@@ -13,22 +13,19 @@ type Props = {
|
||||
}
|
||||
|
||||
const MultitaskingPrivacy = ({ application }: Props) => {
|
||||
const [hasScreenshotPrivacy, setHasScreenshotPrivacy] = useState<boolean | undefined>(false)
|
||||
const [hasScreenshotPrivacy, setHasScreenshotPrivacy] = useState<boolean>(false)
|
||||
|
||||
useEffect(() => {
|
||||
const getHasScreenshotPrivacy = async () => {
|
||||
const hasScreenshotPrivacyEnabled = (await application.getMobileScreenshotPrivacyEnabled()) ?? true
|
||||
setHasScreenshotPrivacy(hasScreenshotPrivacyEnabled)
|
||||
}
|
||||
void getHasScreenshotPrivacy()
|
||||
const hasScreenshotPrivacyEnabled = application.getMobileScreenshotPrivacyEnabled()
|
||||
setHasScreenshotPrivacy(hasScreenshotPrivacyEnabled)
|
||||
}, [application])
|
||||
|
||||
const onScreenshotPrivacyPress = async () => {
|
||||
const enable = !hasScreenshotPrivacy
|
||||
setHasScreenshotPrivacy(enable)
|
||||
|
||||
await application.setMobileScreenshotPrivacyEnabled(enable)
|
||||
await (application.deviceInterface as MobileDeviceInterface).setAndroidScreenshotPrivacy(enable)
|
||||
application.setMobileScreenshotPrivacyEnabled(enable)
|
||||
;(application.deviceInterface as MobileDeviceInterface).setAndroidScreenshotPrivacy(enable)
|
||||
}
|
||||
|
||||
const screenshotPrivacyFeatureText = isIOS() ? 'Multitasking Privacy' : 'Multitasking/Screenshot Privacy'
|
||||
|
||||
@@ -2,7 +2,7 @@ import HorizontalSeparator from '@/Components/Shared/HorizontalSeparator'
|
||||
import Switch from '@/Components/Switch/Switch'
|
||||
import { Subtitle, Text, Title } from '@/Components/Preferences/PreferencesComponents/Content'
|
||||
import { WebApplication } from '@/Application/Application'
|
||||
import { MuteSignInEmailsOption, LogSessionUserAgentOption, SettingName } from '@standardnotes/snjs'
|
||||
import { LogSessionUserAgentOption, SettingName } from '@standardnotes/snjs'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { FunctionComponent, useCallback, useEffect, useState } from 'react'
|
||||
import { STRING_FAILED_TO_UPDATE_USER_SETTING } from '@/Constants/Strings'
|
||||
@@ -15,9 +15,6 @@ type Props = {
|
||||
}
|
||||
|
||||
const Privacy: FunctionComponent<Props> = ({ application }: Props) => {
|
||||
const [signInEmailsMutedValue, setSignInEmailsMutedValue] = useState<MuteSignInEmailsOption>(
|
||||
MuteSignInEmailsOption.NotMuted,
|
||||
)
|
||||
const [sessionUaLoggingValue, setSessionUaLoggingValue] = useState<LogSessionUserAgentOption>(
|
||||
LogSessionUserAgentOption.Enabled,
|
||||
)
|
||||
@@ -41,12 +38,6 @@ const Privacy: FunctionComponent<Props> = ({ application }: Props) => {
|
||||
|
||||
try {
|
||||
const userSettings = await application.settings.listSettings()
|
||||
setSignInEmailsMutedValue(
|
||||
userSettings.getSettingValue<MuteSignInEmailsOption>(
|
||||
SettingName.MuteSignInEmails,
|
||||
MuteSignInEmailsOption.NotMuted,
|
||||
),
|
||||
)
|
||||
setSessionUaLoggingValue(
|
||||
userSettings.getSettingValue<LogSessionUserAgentOption>(
|
||||
SettingName.LogSessionUserAgent,
|
||||
@@ -64,19 +55,6 @@ const Privacy: FunctionComponent<Props> = ({ application }: Props) => {
|
||||
loadSettings().catch(console.error)
|
||||
}, [loadSettings])
|
||||
|
||||
const toggleMuteSignInEmails = async () => {
|
||||
const previousValue = signInEmailsMutedValue
|
||||
const newValue =
|
||||
previousValue === MuteSignInEmailsOption.Muted ? MuteSignInEmailsOption.NotMuted : MuteSignInEmailsOption.Muted
|
||||
setSignInEmailsMutedValue(newValue)
|
||||
|
||||
const updateResult = await updateSetting(SettingName.MuteSignInEmails, newValue)
|
||||
|
||||
if (!updateResult) {
|
||||
setSignInEmailsMutedValue(previousValue)
|
||||
}
|
||||
}
|
||||
|
||||
const toggleSessionLogging = async () => {
|
||||
const previousValue = sessionUaLoggingValue
|
||||
const newValue =
|
||||
@@ -97,23 +75,6 @@ const Privacy: FunctionComponent<Props> = ({ application }: Props) => {
|
||||
<PreferencesSegment>
|
||||
<Title>Privacy</Title>
|
||||
<div>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex flex-col">
|
||||
<Subtitle>Disable sign-in notification emails</Subtitle>
|
||||
<Text>
|
||||
Disables email notifications when a new sign-in occurs on your account. (Email notifications are
|
||||
available to paid subscribers).
|
||||
</Text>
|
||||
</div>
|
||||
{isLoading ? (
|
||||
<Spinner className="ml-2 flex-shrink-0" />
|
||||
) : (
|
||||
<Switch
|
||||
onChange={toggleMuteSignInEmails}
|
||||
checked={signInEmailsMutedValue === MuteSignInEmailsOption.Muted}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<HorizontalSeparator classes="my-4" />
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex flex-col">
|
||||
|
||||
@@ -8,7 +8,9 @@ import { PreferencesProps } from './PreferencesProps'
|
||||
const PreferencesCanvas: FunctionComponent<PreferencesProps & { menu: PreferencesMenu }> = (props) => (
|
||||
<div className="flex min-h-0 flex-grow flex-col-reverse md:flex-row md:justify-between">
|
||||
<PreferencesMenuView menu={props.menu} />
|
||||
<PaneSelector {...props} />
|
||||
<div className="min-h-0 flex-grow overflow-auto bg-contrast">
|
||||
<PaneSelector {...props} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ const PreferencesPane: FunctionComponent<{ children?: ReactNode }> = ({ children
|
||||
{children != undefined && Array.isArray(children) ? children.filter((child) => child != undefined) : children}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex-shrink basis-[13.75rem]" />
|
||||
<div className="hidden flex-shrink basis-[13.75rem] md:block" />
|
||||
</div>
|
||||
)
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ const PreferencesMenuView: FunctionComponent<Props> = ({ menu }) => {
|
||||
)
|
||||
|
||||
return (
|
||||
<div className="border-t border-border bg-default px-5 pt-2 pb-6 md:border-0 md:bg-transparent md:px-0 md:py-0">
|
||||
<div className="border-t border-border bg-default px-5 pt-2 md:border-0 md:bg-contrast md:px-0 md:py-0">
|
||||
<div className="hidden min-w-55 flex-col overflow-y-auto px-3 py-6 md:flex">
|
||||
{menuItems.map((pref) => (
|
||||
<PreferencesMenuItem
|
||||
|
||||
@@ -4,8 +4,9 @@ import { observer } from 'mobx-react-lite'
|
||||
import { PreferencesMenu } from './PreferencesMenu'
|
||||
import PreferencesCanvas from './PreferencesCanvas'
|
||||
import { PreferencesProps } from './PreferencesProps'
|
||||
import { fitNodeToMobileScreen } from '@/Utils'
|
||||
import { fitNodeToMobileScreen, isIOS } from '@/Utils'
|
||||
import { useDisableBodyScrollOnMobile } from '@/Hooks/useDisableBodyScrollOnMobile'
|
||||
import { classNames } from '@/Utils/ConcatenateClassNames'
|
||||
|
||||
const PreferencesView: FunctionComponent<PreferencesProps> = (props) => {
|
||||
const menu = useMemo(
|
||||
@@ -31,7 +32,10 @@ const PreferencesView: FunctionComponent<PreferencesProps> = (props) => {
|
||||
|
||||
return (
|
||||
<div
|
||||
className="absolute top-0 left-0 z-preferences flex h-full max-h-screen w-full flex-col bg-contrast"
|
||||
className={classNames(
|
||||
'absolute top-0 left-0 z-preferences flex h-full max-h-screen w-full flex-col bg-default pt-safe-top',
|
||||
isIOS() ? 'pb-safe-bottom' : 'pb-2 md:pb-0',
|
||||
)}
|
||||
ref={fitNodeToMobileScreen}
|
||||
>
|
||||
<div className="flex w-full flex-row items-center justify-between border-b border-solid border-border bg-default px-3 py-2 md:p-3">
|
||||
|
||||
+26
-18
@@ -1,5 +1,6 @@
|
||||
import { ViewControllerManager } from '@/Controllers/ViewControllerManager'
|
||||
import Button from '@/Components/Button/Button'
|
||||
import MobileItemsListButton from '../NoteGroupView/MobileItemsListButton'
|
||||
|
||||
type Props = {
|
||||
viewControllerManager: ViewControllerManager
|
||||
@@ -14,24 +15,31 @@ const ProtectedItemOverlay = ({ viewControllerManager, onViewItem, hasProtection
|
||||
: `Add a passcode or create an account to require authentication to view this ${itemType}.`
|
||||
|
||||
return (
|
||||
<div className="flex max-w-md flex-col items-center justify-center text-center">
|
||||
<h1 className="m-0 w-full text-2xl font-bold">This {itemType} is protected</h1>
|
||||
<p className="mt-2 w-full text-lg">{instructionText}</p>
|
||||
<div className="mt-4 flex gap-3">
|
||||
{!hasProtectionSources && (
|
||||
<Button
|
||||
primary
|
||||
small
|
||||
onClick={() => {
|
||||
viewControllerManager.accountMenuController.setShow(true)
|
||||
}}
|
||||
>
|
||||
Open account menu
|
||||
</Button>
|
||||
)}
|
||||
<Button small onClick={onViewItem}>
|
||||
{hasProtectionSources ? 'Authenticate' : `View ${itemType}`}
|
||||
</Button>
|
||||
<div aria-label="Protected overlay" className="section editor sn-component">
|
||||
<div className="flex h-full flex-grow flex-col justify-center md:flex-row md:items-center">
|
||||
<div className="mb-auto p-4 md:hidden">
|
||||
<MobileItemsListButton />
|
||||
</div>
|
||||
<div className="mb-auto flex max-w-md flex-col items-center justify-center text-center md:mb-0">
|
||||
<h1 className="m-0 w-full text-2xl font-bold">This {itemType} is protected</h1>
|
||||
<p className="mt-2 w-full text-lg">{instructionText}</p>
|
||||
<div className="mt-4 flex gap-3">
|
||||
{!hasProtectionSources && (
|
||||
<Button
|
||||
primary
|
||||
small
|
||||
onClick={() => {
|
||||
viewControllerManager.accountMenuController.setShow(true)
|
||||
}}
|
||||
>
|
||||
Open account menu
|
||||
</Button>
|
||||
)}
|
||||
<Button small onClick={onViewItem}>
|
||||
{hasProtectionSources ? 'Authenticate' : `View ${itemType}`}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -5,6 +5,7 @@ import Icon from '@/Components/Icon/Icon'
|
||||
import { usePremiumModal } from '@/Hooks/usePremiumModal'
|
||||
import Switch from '@/Components/Switch/Switch'
|
||||
import { PremiumFeatureIconClass, PremiumFeatureIconName } from '../Icon/PremiumFeatureIcon'
|
||||
import { isMobileScreen } from '@/Utils'
|
||||
|
||||
type Props = {
|
||||
application: WebApplication
|
||||
@@ -34,11 +35,12 @@ const FocusModeSwitch: FunctionComponent<Props> = ({ application, onToggle, onCl
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
className="flex w-full cursor-pointer items-center justify-between border-0 bg-transparent px-3 py-1.5 text-left text-sm text-text hover:bg-contrast hover:text-foreground focus:bg-info-backdrop focus:shadow-none"
|
||||
className="group flex w-full cursor-pointer items-center justify-between border-0 bg-transparent px-3 py-1.5 text-left text-sm text-text hover:bg-contrast hover:text-foreground focus:bg-info-backdrop focus:shadow-none disabled:bg-default disabled:text-passive-2"
|
||||
onClick={toggle}
|
||||
disabled={application.isNativeMobileWeb() || isMobileScreen()}
|
||||
>
|
||||
<div className="flex items-center">
|
||||
<Icon type="menu-close" className="mr-2 text-neutral" />
|
||||
<Icon type="menu-close" className="mr-2 text-neutral group-disabled:text-passive-2" />
|
||||
Focused Writing
|
||||
</div>
|
||||
{isEntitled ? (
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { WebApplication } from '@/Application/Application'
|
||||
import { FeatureStatus } from '@standardnotes/snjs'
|
||||
import { FeatureIdentifier, FeatureStatus } from '@standardnotes/snjs'
|
||||
import { FunctionComponent, MouseEventHandler, useCallback, useMemo } from 'react'
|
||||
import Icon from '@/Components/Icon/Icon'
|
||||
import { usePremiumModal } from '@/Hooks/usePremiumModal'
|
||||
@@ -7,6 +7,7 @@ import Switch from '@/Components/Switch/Switch'
|
||||
import { ThemeItem } from './ThemeItem'
|
||||
import RadioIndicator from '../RadioIndicator/RadioIndicator'
|
||||
import { PremiumFeatureIconClass, PremiumFeatureIconName } from '../Icon/PremiumFeatureIcon'
|
||||
import { isMobileScreen } from '@/Utils'
|
||||
|
||||
type Props = {
|
||||
item: ThemeItem
|
||||
@@ -43,11 +44,14 @@ const ThemesMenuButton: FunctionComponent<Props> = ({ application, item }) => {
|
||||
[application, canActivateTheme, item, premiumModal],
|
||||
)
|
||||
|
||||
const isMobile = application.isNativeMobileWeb() || isMobileScreen()
|
||||
|
||||
return (
|
||||
<button
|
||||
className={
|
||||
'flex w-full cursor-pointer items-center justify-between border-0 bg-transparent px-3 py-1.5 text-left text-sm text-text hover:bg-contrast hover:text-foreground focus:bg-info-backdrop focus:bg-info-backdrop focus:shadow-none focus:shadow-none'
|
||||
'group flex w-full cursor-pointer items-center justify-between border-0 bg-transparent px-3 py-1.5 text-left text-sm text-text hover:bg-contrast hover:text-foreground focus:bg-info-backdrop focus:shadow-none disabled:bg-default disabled:text-passive-2'
|
||||
}
|
||||
disabled={item.identifier === FeatureIdentifier.DynamicTheme && isMobile}
|
||||
onClick={toggleTheme}
|
||||
>
|
||||
{item.component?.isLayerable() ? (
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user