mirror of
https://github.com/standardnotes/app
synced 2026-09-14 03:46:01 -04:00
Compare commits
71
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c2a1918843 | ||
|
|
d3621d70b1 | ||
|
|
bf286f4854 | ||
|
|
97835e64ac | ||
|
|
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 | ||
|
|
023d1665b6 | ||
|
|
4a773fa537 | ||
|
|
dd5ca0c28c | ||
|
|
9aa7bc018e | ||
|
|
571919c969 | ||
|
|
66a25c7556 | ||
|
|
e3be17c7f8 | ||
|
|
c4d7761496 | ||
|
|
f80cc5b822 | ||
|
|
ecaa2a629f | ||
|
|
46f3e873a5 | ||
|
|
038320b2fd | ||
|
|
ee4a1acb9c | ||
|
|
efe0c38462 | ||
|
|
4336c9ed66 | ||
|
|
85c90e07fc | ||
|
|
146b3329e0 | ||
|
|
0c3c98d7af | ||
|
|
5a8752b95a | ||
|
|
7807fa34f3 | ||
|
|
ddf4c97477 | ||
|
|
3a15142940 | ||
|
|
79518b6a5d | ||
|
|
2d0ee10226 |
+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,26 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.8.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api
|
||||
|
||||
## [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
|
||||
|
||||
* **api:** add websocket api definitions ([4a773fa](https://github.com/standardnotes/app/commit/4a773fa53796e17ce5df325ed7d40ba2cb686476))
|
||||
|
||||
## [1.7.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api
|
||||
|
||||
@@ -10,10 +10,10 @@ module.exports = {
|
||||
},
|
||||
coverageThreshold: {
|
||||
global: {
|
||||
branches: 17,
|
||||
functions: 43,
|
||||
lines: 46,
|
||||
statements: 46
|
||||
branches: 20,
|
||||
functions: 66,
|
||||
lines: 63,
|
||||
statements: 63
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/api",
|
||||
"version": "1.7.2",
|
||||
"version": "1.8.3",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
@@ -32,7 +32,8 @@
|
||||
"eslint": "^8.23.0",
|
||||
"eslint-plugin-prettier": "*",
|
||||
"jest": "^28.1.2",
|
||||
"ts-jest": "^28.0.5"
|
||||
"ts-jest": "^28.0.5",
|
||||
"typescript": "*"
|
||||
},
|
||||
"dependencies": {
|
||||
"@standardnotes/common": "^1.32.0",
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
export enum WebSocketApiOperations {
|
||||
CreatingConnectionToken,
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
import { WebSocketConnectionTokenResponse } from '../../Response'
|
||||
|
||||
import { WebSocketServerInterface } from '../../Server/WebSocket/WebSocketServerInterface'
|
||||
import { WebSocketApiOperations } from './WebSocketApiOperations'
|
||||
|
||||
import { WebSocketApiService } from './WebSocketApiService'
|
||||
|
||||
describe('WebSocketApiService', () => {
|
||||
let webSocketServer: WebSocketServerInterface
|
||||
|
||||
const createService = () => new WebSocketApiService(webSocketServer)
|
||||
|
||||
beforeEach(() => {
|
||||
webSocketServer = {} as jest.Mocked<WebSocketServerInterface>
|
||||
webSocketServer.createConnectionToken = jest.fn().mockReturnValue({
|
||||
data: { token: 'foobar' },
|
||||
} as jest.Mocked<WebSocketConnectionTokenResponse>)
|
||||
})
|
||||
|
||||
it('should create a websocket connection token', async () => {
|
||||
const response = await createService().createConnectionToken()
|
||||
|
||||
expect(response).toEqual({
|
||||
data: {
|
||||
token: 'foobar',
|
||||
},
|
||||
})
|
||||
expect(webSocketServer.createConnectionToken).toHaveBeenCalledWith({})
|
||||
})
|
||||
|
||||
it('should not create a token if it is already creating', async () => {
|
||||
const service = createService()
|
||||
Object.defineProperty(service, 'operationsInProgress', {
|
||||
get: () => new Map([[WebSocketApiOperations.CreatingConnectionToken, true]]),
|
||||
})
|
||||
|
||||
let error = null
|
||||
try {
|
||||
await service.createConnectionToken()
|
||||
} catch (caughtError) {
|
||||
error = caughtError
|
||||
}
|
||||
|
||||
expect(error).not.toBeNull()
|
||||
})
|
||||
|
||||
it('should not create a token if the server fails', async () => {
|
||||
webSocketServer.createConnectionToken = jest.fn().mockImplementation(() => {
|
||||
throw new Error('Oops')
|
||||
})
|
||||
|
||||
let error = null
|
||||
try {
|
||||
await createService().createConnectionToken()
|
||||
} catch (caughtError) {
|
||||
error = caughtError
|
||||
}
|
||||
|
||||
expect(error).not.toBeNull()
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,33 @@
|
||||
import { ErrorMessage } from '../../Error/ErrorMessage'
|
||||
import { ApiCallError } from '../../Error/ApiCallError'
|
||||
|
||||
import { WebSocketApiServiceInterface } from './WebSocketApiServiceInterface'
|
||||
import { WebSocketApiOperations } from './WebSocketApiOperations'
|
||||
import { WebSocketServerInterface } from '../../Server'
|
||||
import { WebSocketConnectionTokenResponse } from '../../Response'
|
||||
|
||||
export class WebSocketApiService implements WebSocketApiServiceInterface {
|
||||
private operationsInProgress: Map<WebSocketApiOperations, boolean>
|
||||
|
||||
constructor(private webSocketServer: WebSocketServerInterface) {
|
||||
this.operationsInProgress = new Map()
|
||||
}
|
||||
|
||||
async createConnectionToken(): Promise<WebSocketConnectionTokenResponse> {
|
||||
if (this.operationsInProgress.get(WebSocketApiOperations.CreatingConnectionToken)) {
|
||||
throw new ApiCallError(ErrorMessage.GenericInProgress)
|
||||
}
|
||||
|
||||
this.operationsInProgress.set(WebSocketApiOperations.CreatingConnectionToken, true)
|
||||
|
||||
try {
|
||||
const response = await this.webSocketServer.createConnectionToken({})
|
||||
|
||||
this.operationsInProgress.set(WebSocketApiOperations.CreatingConnectionToken, false)
|
||||
|
||||
return response
|
||||
} catch (error) {
|
||||
throw new ApiCallError(ErrorMessage.GenericFail)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import { WebSocketConnectionTokenResponse } from '../../Response'
|
||||
|
||||
export interface WebSocketApiServiceInterface {
|
||||
createConnectionToken(): Promise<WebSocketConnectionTokenResponse>
|
||||
}
|
||||
@@ -3,3 +3,5 @@ export * from './Subscription/SubscriptionApiService'
|
||||
export * from './Subscription/SubscriptionApiServiceInterface'
|
||||
export * from './User/UserApiService'
|
||||
export * from './User/UserApiServiceInterface'
|
||||
export * from './WebSocket/WebSocketApiService'
|
||||
export * from './WebSocket/WebSocketApiServiceInterface'
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
export type WebSocketConnectionTokenRequestParams = {
|
||||
[additionalParam: string]: unknown
|
||||
}
|
||||
@@ -5,3 +5,4 @@ export * from './Subscription/SubscriptionInviteDeclineRequestParams'
|
||||
export * from './Subscription/SubscriptionInviteListRequestParams'
|
||||
export * from './Subscription/SubscriptionInviteRequestParams'
|
||||
export * from './User/UserRegistrationRequestParams'
|
||||
export * from './WebSocket/WebSocketConnectionTokenRequestParams'
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import { Either } from '@standardnotes/common'
|
||||
|
||||
import { HttpErrorResponseBody } from '../../Http/HttpErrorResponseBody'
|
||||
import { HttpResponse } from '../../Http/HttpResponse'
|
||||
import { WebSocketConnectionTokenResponseBody } from './WebSocketConnectionTokenResponseBody'
|
||||
|
||||
export interface WebSocketConnectionTokenResponse extends HttpResponse {
|
||||
data: Either<WebSocketConnectionTokenResponseBody, HttpErrorResponseBody>
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export type WebSocketConnectionTokenResponseBody = {
|
||||
token: string
|
||||
}
|
||||
@@ -10,3 +10,5 @@ export * from './Subscription/SubscriptionInviteResponse'
|
||||
export * from './Subscription/SubscriptionInviteResponseBody'
|
||||
export * from './User/UserRegistrationResponse'
|
||||
export * from './User/UserRegistrationResponseBody'
|
||||
export * from './WebSocket/WebSocketConnectionTokenResponse'
|
||||
export * from './WebSocket/WebSocketConnectionTokenResponseBody'
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
const TokenPaths = {
|
||||
createConnectionToken: '/v1/sockets/tokens',
|
||||
}
|
||||
|
||||
export const Paths = {
|
||||
v1: {
|
||||
...TokenPaths,
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { HttpServiceInterface } from '../../Http'
|
||||
import { WebSocketConnectionTokenResponse } from '../../Response'
|
||||
|
||||
import { WebSocketServer } from './WebSocketServer'
|
||||
|
||||
describe('WebSocketServer', () => {
|
||||
let httpService: HttpServiceInterface
|
||||
|
||||
const createServer = () => new WebSocketServer(httpService)
|
||||
|
||||
beforeEach(() => {
|
||||
httpService = {} as jest.Mocked<HttpServiceInterface>
|
||||
httpService.post = jest.fn().mockReturnValue({
|
||||
data: { token: 'foobar' },
|
||||
} as jest.Mocked<WebSocketConnectionTokenResponse>)
|
||||
})
|
||||
|
||||
it('should create a websocket connection token', async () => {
|
||||
const response = await createServer().createConnectionToken({})
|
||||
|
||||
expect(response).toEqual({
|
||||
data: {
|
||||
token: 'foobar',
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,17 @@
|
||||
import { HttpServiceInterface } from '../../Http/HttpServiceInterface'
|
||||
import { WebSocketConnectionTokenRequestParams } from '../../Request/WebSocket/WebSocketConnectionTokenRequestParams'
|
||||
import { WebSocketConnectionTokenResponse } from '../../Response/WebSocket/WebSocketConnectionTokenResponse'
|
||||
import { Paths } from './Paths'
|
||||
import { WebSocketServerInterface } from './WebSocketServerInterface'
|
||||
|
||||
export class WebSocketServer implements WebSocketServerInterface {
|
||||
constructor(private httpService: HttpServiceInterface) {}
|
||||
|
||||
async createConnectionToken(
|
||||
params: WebSocketConnectionTokenRequestParams,
|
||||
): Promise<WebSocketConnectionTokenResponse> {
|
||||
const response = await this.httpService.post(Paths.v1.createConnectionToken, params)
|
||||
|
||||
return response as WebSocketConnectionTokenResponse
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import { WebSocketConnectionTokenRequestParams } from '../../Request/WebSocket/WebSocketConnectionTokenRequestParams'
|
||||
import { WebSocketConnectionTokenResponse } from '../../Response/WebSocket/WebSocketConnectionTokenResponse'
|
||||
|
||||
export interface WebSocketServerInterface {
|
||||
createConnectionToken(params: WebSocketConnectionTokenRequestParams): Promise<WebSocketConnectionTokenResponse>
|
||||
}
|
||||
@@ -2,3 +2,5 @@ export * from './Subscription/SubscriptionServer'
|
||||
export * from './Subscription/SubscriptionServerInterface'
|
||||
export * from './User/UserServer'
|
||||
export * from './User/UserServerInterface'
|
||||
export * from './WebSocket/WebSocketServer'
|
||||
export * from './WebSocket/WebSocketServerInterface'
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
dist
|
||||
@@ -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.
|
||||
|
||||
## [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
|
||||
|
||||
## [2.7.12](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-13)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/components-meta
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/components-meta",
|
||||
"version": "2.7.12",
|
||||
"version": "2.7.14",
|
||||
"private": true,
|
||||
"author": "Standard Notes.",
|
||||
"main": "dist",
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
node_modules
|
||||
dist
|
||||
jsign
|
||||
@@ -3,6 +3,132 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [3.23.154](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.153](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [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
|
||||
|
||||
## [3.23.133](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.132](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-19)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.131](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-19)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.130](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-19)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.129](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-18)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.128](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-16)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.127](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-16)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.126](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-16)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.125](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.124](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.123](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@standardnotes/desktop",
|
||||
"main": "./app/dist/index.js",
|
||||
"version": "3.23.123",
|
||||
"version": "3.23.154",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"author": "Standard Notes.",
|
||||
"private": true,
|
||||
|
||||
@@ -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.15.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/encryption
|
||||
|
||||
## [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.5",
|
||||
"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,18 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.23.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/filepicker
|
||||
|
||||
## [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.5",
|
||||
"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.10.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files
|
||||
|
||||
## [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.5",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
metro.config.js
|
||||
packages/mobile/html/Web.bundle/src/components
|
||||
packages/mobile/html/Web.bundle/src/web-src
|
||||
html/**/*
|
||||
node_modules
|
||||
ios
|
||||
e2e
|
||||
android
|
||||
fastlane
|
||||
WebFrame
|
||||
__tests__
|
||||
@@ -3,6 +3,146 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [3.36.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.36.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [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
|
||||
|
||||
## [3.35.1](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.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-19)
|
||||
|
||||
### Features
|
||||
|
||||
* mobile web bridge ([#1597](https://github.com/standardnotes/app/issues/1597)) ([c4d7761](https://github.com/standardnotes/app/commit/c4d776149677269bc766f24da6adc5ec816dbcfb))
|
||||
|
||||
## [3.34.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-19)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.34.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-19)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.34.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-18)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
# [3.34.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-16)
|
||||
|
||||
### Features
|
||||
|
||||
* add settings to fully switch between native/webview ([#1587](https://github.com/standardnotes/app/issues/1587)) ([85c90e0](https://github.com/standardnotes/app/commit/85c90e07fc8b1ce66eaa88df09f2728ac0fecf1c))
|
||||
|
||||
## [3.33.7](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-16)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.33.6](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-16)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.33.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-15)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* biometrics input on mobile webview challenge modal ([#1572](https://github.com/standardnotes/app/issues/1572)) ([3a15142](https://github.com/standardnotes/app/commit/3a15142940ef9391868442e1997c3d9d5eec33be))
|
||||
|
||||
## [3.33.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.33.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-15)
|
||||
|
||||
**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,10 +1,12 @@
|
||||
import { IsMobileWeb } from '@Lib/Utils'
|
||||
import { MobileWebApp } from '@Root/MobileWebApp'
|
||||
import { SNLog } from '@standardnotes/snjs'
|
||||
import { AppRegistry } from 'react-native'
|
||||
import 'react-native-gesture-handler'
|
||||
import { enableScreens } from 'react-native-screens'
|
||||
import 'react-native-url-polyfill/auto'
|
||||
import { name as appName } from './app.json'
|
||||
import { App } from './src/App'
|
||||
import { NativeApp } from './src/NativeApp'
|
||||
import { enableAndroidFontFix } from './src/Style/android_text_fix'
|
||||
|
||||
enableScreens()
|
||||
@@ -28,11 +30,11 @@ console.warn = function filterWarnings(msg) {
|
||||
"[react-native-gesture-handler] Seems like you're using an old API with gesture components",
|
||||
]
|
||||
|
||||
if (!supressedWarnings.some(entry => msg.includes(entry))) {
|
||||
if (!supressedWarnings.some((entry) => msg.includes(entry))) {
|
||||
originalWarn.apply(console, arguments)
|
||||
}
|
||||
}
|
||||
|
||||
enableAndroidFontFix()
|
||||
|
||||
AppRegistry.registerComponent(appName, () => App)
|
||||
AppRegistry.registerComponent(appName, () => (IsMobileWeb ? MobileWebApp : NativeApp))
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/mobile",
|
||||
"version": "3.33.3",
|
||||
"version": "3.36.5",
|
||||
"author": "Standard Notes.",
|
||||
"private": true,
|
||||
"license": "AGPL-3.0-or-later",
|
||||
|
||||
@@ -2,18 +2,18 @@ import { AppStateEventType, AppStateType, TabletModeChangeData } from '@Lib/Appl
|
||||
import { AlwaysOpenWebAppOnLaunchKey } from '@Lib/constants'
|
||||
import { useHasEditor, useIsLocked } from '@Lib/SnjsHelperHooks'
|
||||
import { ScreenStatus } from '@Lib/StatusManager'
|
||||
import { IsDev } from '@Lib/Utils'
|
||||
import { CompositeNavigationProp, RouteProp, useNavigation } from '@react-navigation/native'
|
||||
import { IsMobileWeb } from '@Lib/Utils'
|
||||
import { CompositeNavigationProp, RouteProp } from '@react-navigation/native'
|
||||
import { createStackNavigator, StackNavigationProp } from '@react-navigation/stack'
|
||||
import { HeaderTitleView } from '@Root/Components/HeaderTitleView'
|
||||
import { IoniconsHeaderButton } from '@Root/Components/IoniconsHeaderButton'
|
||||
import { Compose } from '@Root/Screens/Compose/Compose'
|
||||
import { SCREEN_COMPOSE, SCREEN_NOTES, SCREEN_VIEW_PROTECTED_NOTE, SCREEN_WEB_APP } from '@Root/Screens/screens'
|
||||
import { SCREEN_COMPOSE, SCREEN_NOTES, SCREEN_VIEW_PROTECTED_NOTE } from '@Root/Screens/screens'
|
||||
import { MainSideMenu } from '@Root/Screens/SideMenu/MainSideMenu'
|
||||
import { NoteSideMenu } from '@Root/Screens/SideMenu/NoteSideMenu'
|
||||
import { ViewProtectedNote } from '@Root/Screens/ViewProtectedNote/ViewProtectedNote'
|
||||
import { Root } from '@Screens/Root'
|
||||
import { ApplicationEvent, StorageValueModes, UuidString } from '@standardnotes/snjs'
|
||||
import { StorageValueModes, UuidString } from '@standardnotes/snjs'
|
||||
import { ICON_MENU } from '@Style/Icons'
|
||||
import { ThemeService } from '@Style/ThemeService'
|
||||
import { getDefaultDrawerWidth } from '@Style/Utils'
|
||||
@@ -22,13 +22,10 @@ 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'
|
||||
import { HeaderTitleParams } from './App'
|
||||
import { ApplicationContext } from './ApplicationContext'
|
||||
import { MobileWebAppContainer } from './MobileWebAppContainer'
|
||||
import { ModalStackNavigationProp } from './ModalStack'
|
||||
|
||||
const IS_DEBUGGING_WEB_APP = false
|
||||
const DEFAULT_TO_WEB_APP = IsDev && IS_DEBUGGING_WEB_APP
|
||||
import { HeaderTitleParams } from './NativeApp'
|
||||
|
||||
export type AppStackNavigatorParamList = {
|
||||
[SCREEN_NOTES]: HeaderTitleParams
|
||||
@@ -124,27 +121,24 @@ export const AppStackComponent = (props: ModalStackNavigationProp<'AppStack'>) =
|
||||
[application],
|
||||
)
|
||||
|
||||
const navigation = useNavigation<ModalStackNavigationProp<'AppStack'>['navigation']>()
|
||||
if (IsMobileWeb) {
|
||||
return (
|
||||
<AppStack.Navigator
|
||||
screenOptions={() => ({
|
||||
headerShown: false,
|
||||
})}
|
||||
initialRouteName={SCREEN_NOTES}
|
||||
>
|
||||
<AppStack.Screen name={SCREEN_NOTES} component={MobileWebAppContainer} />
|
||||
</AppStack.Navigator>
|
||||
)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!application) {
|
||||
return
|
||||
}
|
||||
if (!application) {
|
||||
return null
|
||||
}
|
||||
|
||||
const removeObserver = application.addEventObserver(async (event) => {
|
||||
if (event === ApplicationEvent.Launched) {
|
||||
const value = (await application.getValue(AlwaysOpenWebAppOnLaunchKey, StorageValueModes.Nonwrapped)) as
|
||||
| boolean
|
||||
| undefined
|
||||
const shouldAlwaysOpenWebAppOnLaunch = value ?? false
|
||||
if (shouldAlwaysOpenWebAppOnLaunch) {
|
||||
navigation.push(SCREEN_WEB_APP)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return removeObserver
|
||||
}, [application, navigation])
|
||||
const shouldOpenWebApp = application.getValue(AlwaysOpenWebAppOnLaunchKey, StorageValueModes.Nonwrapped) as boolean
|
||||
|
||||
return (
|
||||
<DrawerLayout
|
||||
@@ -185,6 +179,7 @@ export const AppStackComponent = (props: ModalStackNavigationProp<'AppStack'>) =
|
||||
name={SCREEN_NOTES}
|
||||
options={({ route }) => ({
|
||||
title: 'All notes',
|
||||
headerShown: !shouldOpenWebApp,
|
||||
headerTitle: ({ children }) => {
|
||||
const screenStatus = isInTabletMode ? composeStatus || notesStatus : notesStatus
|
||||
|
||||
@@ -224,7 +219,7 @@ export const AppStackComponent = (props: ModalStackNavigationProp<'AppStack'>) =
|
||||
</HeaderButtons>
|
||||
),
|
||||
})}
|
||||
component={DEFAULT_TO_WEB_APP ? MobileWebAppContainer : Root}
|
||||
component={shouldOpenWebApp ? MobileWebAppContainer : Root}
|
||||
/>
|
||||
<AppStack.Screen
|
||||
name={SCREEN_COMPOSE}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
import { AbstractService, InternalEventBus, ReactNativeToWebEvent } from '@standardnotes/snjs'
|
||||
import { AppState, AppStateStatus, NativeEventSubscription } from 'react-native'
|
||||
|
||||
export class AppStateObserverService extends AbstractService<ReactNativeToWebEvent> {
|
||||
private mostRecentState?: ReactNativeToWebEvent
|
||||
private removeListener: NativeEventSubscription
|
||||
private ignoringStateChanges = false
|
||||
|
||||
constructor() {
|
||||
const bus = new InternalEventBus()
|
||||
super(bus)
|
||||
|
||||
this.removeListener = AppState.addEventListener('change', async (nextAppState: AppStateStatus) => {
|
||||
if (this.ignoringStateChanges) {
|
||||
return
|
||||
}
|
||||
|
||||
// if the most recent state is not 'background' ('inactive'), then we're going
|
||||
// from inactive to active, which doesn't really happen unless you, say, swipe
|
||||
// notification center in iOS down then back up. We don't want to lock on this state change.
|
||||
const isResuming = nextAppState === 'active'
|
||||
const isResumingFromBackground = isResuming && this.mostRecentState === ReactNativeToWebEvent.EnteringBackground
|
||||
const isEnteringBackground = nextAppState === 'background'
|
||||
const isLosingFocus = nextAppState === 'inactive'
|
||||
|
||||
if (isEnteringBackground) {
|
||||
this.notifyStateChange(ReactNativeToWebEvent.EnteringBackground)
|
||||
}
|
||||
|
||||
if (isResumingFromBackground || isResuming) {
|
||||
if (isResumingFromBackground) {
|
||||
this.notifyStateChange(ReactNativeToWebEvent.ResumingFromBackground)
|
||||
}
|
||||
|
||||
// Notify of GainingFocus even if resuming from background
|
||||
this.notifyStateChange(ReactNativeToWebEvent.GainingFocus)
|
||||
return
|
||||
}
|
||||
|
||||
if (isLosingFocus) {
|
||||
this.notifyStateChange(ReactNativeToWebEvent.LosingFocus)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
beginIgnoringStateChanges() {
|
||||
this.ignoringStateChanges = true
|
||||
}
|
||||
|
||||
stopIgnoringStateChanges() {
|
||||
this.ignoringStateChanges = false
|
||||
}
|
||||
|
||||
deinit() {
|
||||
this.removeListener.remove()
|
||||
}
|
||||
|
||||
private notifyStateChange(state: ReactNativeToWebEvent): void {
|
||||
this.mostRecentState = state
|
||||
void this.notifyEvent(state)
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ import React, { useContext } from 'react'
|
||||
import { Platform } from 'react-native'
|
||||
import { HeaderButtons, Item } from 'react-navigation-header-buttons'
|
||||
import { ThemeContext } from 'styled-components'
|
||||
import { HeaderTitleParams } from './App'
|
||||
import { HeaderTitleParams } from './NativeApp'
|
||||
|
||||
type HistoryStackNavigatorParamList = {
|
||||
[SCREEN_NOTE_HISTORY]: (HeaderTitleParams & { noteUuid: string }) | (undefined & { noteUuid: string })
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
platformFromString,
|
||||
SNApplication,
|
||||
SNComponentManager,
|
||||
StorageValueModes,
|
||||
} from '@standardnotes/snjs'
|
||||
import { Platform } from 'react-native'
|
||||
|
||||
@@ -21,15 +22,16 @@ 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 { MobileDeviceInterface } from './Interface'
|
||||
import { MobileDevice } from './Interface'
|
||||
import { push } from './NavigationService'
|
||||
import { PreferencesManager } from './PreferencesManager'
|
||||
import { SNReactNativeCrypto } from './ReactNativeCrypto'
|
||||
import { ReviewService } from './ReviewService'
|
||||
import { StatusManager } from './StatusManager'
|
||||
import { IsDev } from './Utils'
|
||||
import { IsDev, IsMobileWeb } from './Utils'
|
||||
|
||||
type MobileServices = {
|
||||
applicationState: ApplicationState
|
||||
@@ -52,7 +54,7 @@ export class MobileApplication extends SNApplication {
|
||||
|
||||
static previouslyLaunched = false
|
||||
|
||||
constructor(deviceInterface: MobileDeviceInterface, identifier: string) {
|
||||
constructor(deviceInterface: MobileDevice, identifier: string) {
|
||||
super({
|
||||
environment: Environment.Mobile,
|
||||
platform: platformFromString(Platform.OS),
|
||||
@@ -135,6 +137,11 @@ export class MobileApplication extends SNApplication {
|
||||
}
|
||||
|
||||
promptForChallenge(challenge: Challenge) {
|
||||
const optedIntoWebPreview = this.getValue(AlwaysOpenWebAppOnLaunchKey, StorageValueModes.Nonwrapped) as boolean
|
||||
if (IsMobileWeb || optedIntoWebPreview) {
|
||||
return
|
||||
}
|
||||
|
||||
push(SCREEN_AUTHENTICATE, { challenge, title: challenge.modalTitle })
|
||||
}
|
||||
|
||||
|
||||
@@ -4,14 +4,14 @@ import { ApplicationState } from './ApplicationState'
|
||||
import { BackupsService } from './BackupsService'
|
||||
import { FilesService } from './FilesService'
|
||||
import { InstallationService } from './InstallationService'
|
||||
import { MobileDeviceInterface } from './Interface'
|
||||
import { MobileDevice } from './Interface'
|
||||
import { PreferencesManager } from './PreferencesManager'
|
||||
import { ReviewService } from './ReviewService'
|
||||
import { StatusManager } from './StatusManager'
|
||||
|
||||
export class ApplicationGroup extends SNApplicationGroup {
|
||||
constructor() {
|
||||
super(new MobileDeviceInterface())
|
||||
super(new MobileDevice())
|
||||
}
|
||||
|
||||
override async initialize(_callback?: any): Promise<void> {
|
||||
@@ -21,7 +21,7 @@ export class ApplicationGroup extends SNApplicationGroup {
|
||||
}
|
||||
|
||||
private createApplication = async (descriptor: ApplicationDescriptor, deviceInterface: DeviceInterface) => {
|
||||
const application = new MobileApplication(deviceInterface as MobileDeviceInterface, descriptor.identifier)
|
||||
const application = new MobileApplication(deviceInterface as MobileDevice, descriptor.identifier)
|
||||
const internalEventBus = new InternalEventBus()
|
||||
const applicationState = new ApplicationState(application)
|
||||
const reviewService = new ReviewService(application, internalEventBus)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { MobileDeviceInterface } from '@Lib/Interface'
|
||||
import { MobileDevice } from '@Lib/Interface'
|
||||
import {
|
||||
ApplicationEvent,
|
||||
ApplicationService,
|
||||
@@ -169,9 +169,7 @@ export class ApplicationState extends ApplicationService {
|
||||
override async onAppLaunch() {
|
||||
MobileApplication.setPreviouslyLaunched()
|
||||
this.screenshotPrivacyEnabled = (await this.getScreenshotPrivacyEnabled()) ?? true
|
||||
await (this.application.deviceInterface as MobileDeviceInterface).setAndroidScreenshotPrivacy(
|
||||
this.screenshotPrivacyEnabled,
|
||||
)
|
||||
await (this.application.deviceInterface as MobileDevice).setAndroidScreenshotPrivacy(this.screenshotPrivacyEnabled)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -480,28 +478,35 @@ export class ApplicationState extends ApplicationService {
|
||||
|
||||
private async checkAndLockApplication() {
|
||||
const isLocked = await this.application.isLocked()
|
||||
if (!isLocked) {
|
||||
const hasBiometrics = await this.application.hasBiometrics()
|
||||
const hasPasscode = this.application.hasPasscode()
|
||||
if (hasPasscode && this.passcodeTiming === MobileUnlockTiming.Immediately) {
|
||||
await this.application.lock()
|
||||
} else if (hasBiometrics && this.biometricsTiming === MobileUnlockTiming.Immediately && !this.locked) {
|
||||
const challenge = new Challenge(
|
||||
[new ChallengePrompt(ChallengeValidation.Biometric)],
|
||||
ChallengeReason.ApplicationUnlock,
|
||||
false,
|
||||
)
|
||||
void this.application.promptForCustomChallenge(challenge)
|
||||
|
||||
this.locked = true
|
||||
this.notifyLockStateObservers(LockStateType.Locked)
|
||||
this.application.addChallengeObserver(challenge, {
|
||||
onComplete: () => {
|
||||
this.locked = false
|
||||
this.notifyLockStateObservers(LockStateType.Unlocked)
|
||||
},
|
||||
})
|
||||
}
|
||||
if (isLocked) {
|
||||
return
|
||||
}
|
||||
|
||||
const hasBiometrics = this.application.hasBiometrics()
|
||||
const hasPasscode = this.application.hasPasscode()
|
||||
const passcodeLockImmediately = hasPasscode && this.passcodeTiming === MobileUnlockTiming.Immediately
|
||||
const biometricsLockImmediately =
|
||||
hasBiometrics && this.biometricsTiming === MobileUnlockTiming.Immediately && !this.locked
|
||||
|
||||
if (passcodeLockImmediately) {
|
||||
await this.application.lock()
|
||||
} else if (biometricsLockImmediately) {
|
||||
const challenge = new Challenge(
|
||||
[new ChallengePrompt(ChallengeValidation.Biometric)],
|
||||
ChallengeReason.ApplicationUnlock,
|
||||
false,
|
||||
)
|
||||
void this.application.promptForCustomChallenge(challenge)
|
||||
|
||||
this.locked = true
|
||||
this.notifyLockStateObservers(LockStateType.Locked)
|
||||
this.application.addChallengeObserver(challenge, {
|
||||
onComplete: () => {
|
||||
this.locked = false
|
||||
this.notifyLockStateObservers(LockStateType.Unlocked)
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -565,35 +570,31 @@ export class ApplicationState extends ApplicationService {
|
||||
).includes(state)
|
||||
}
|
||||
|
||||
private async getScreenshotPrivacyEnabled(): Promise<boolean | undefined> {
|
||||
private async getScreenshotPrivacyEnabled(): Promise<boolean> {
|
||||
return this.application.getMobileScreenshotPrivacyEnabled()
|
||||
}
|
||||
|
||||
private async getPasscodeTiming(): Promise<MobileUnlockTiming | undefined> {
|
||||
return this.application.getValue(StorageKey.MobilePasscodeTiming, StorageValueModes.Nonwrapped) as Promise<
|
||||
MobileUnlockTiming | undefined
|
||||
>
|
||||
return this.application.getMobilePasscodeTiming()
|
||||
}
|
||||
|
||||
private async getBiometricsTiming(): Promise<MobileUnlockTiming | undefined> {
|
||||
return this.application.getValue(StorageKey.MobileBiometricsTiming, StorageValueModes.Nonwrapped) as Promise<
|
||||
MobileUnlockTiming | undefined
|
||||
>
|
||||
return this.application.getMobileBiometricsTiming()
|
||||
}
|
||||
|
||||
public async setScreenshotPrivacyEnabled(enabled: boolean) {
|
||||
await this.application.setMobileScreenshotPrivacyEnabled(enabled)
|
||||
this.screenshotPrivacyEnabled = enabled
|
||||
await (this.application.deviceInterface as MobileDeviceInterface).setAndroidScreenshotPrivacy(enabled)
|
||||
await (this.application.deviceInterface as MobileDevice).setAndroidScreenshotPrivacy(enabled)
|
||||
}
|
||||
|
||||
public async setPasscodeTiming(timing: MobileUnlockTiming) {
|
||||
await this.application.setValue(StorageKey.MobilePasscodeTiming, timing, StorageValueModes.Nonwrapped)
|
||||
this.application.setValue(StorageKey.MobilePasscodeTiming, timing, StorageValueModes.Nonwrapped)
|
||||
this.passcodeTiming = timing
|
||||
}
|
||||
|
||||
public async setBiometricsTiming(timing: MobileUnlockTiming) {
|
||||
await this.application.setValue(StorageKey.MobileBiometricsTiming, timing, StorageValueModes.Nonwrapped)
|
||||
this.application.setValue(StorageKey.MobileBiometricsTiming, timing, StorageValueModes.Nonwrapped)
|
||||
this.biometricsTiming = timing
|
||||
}
|
||||
|
||||
@@ -605,7 +606,7 @@ export class ApplicationState extends ApplicationService {
|
||||
}
|
||||
|
||||
public async setPasscodeKeyboardType(type: PasscodeKeyboardType) {
|
||||
await this.application.setValue(MobileStorageKey.PasscodeKeyboardTypeKey, type, StorageValueModes.Nonwrapped)
|
||||
this.application.setValue(MobileStorageKey.PasscodeKeyboardTypeKey, type, StorageValueModes.Nonwrapped)
|
||||
}
|
||||
|
||||
public onDrawerOpen() {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import SNReactNative from '@standardnotes/react-native-utils'
|
||||
import { ApplicationService, ButtonType, StorageValueModes } from '@standardnotes/snjs'
|
||||
import { MobileDeviceInterface } from './Interface'
|
||||
import { MobileDevice } from './Interface'
|
||||
|
||||
const FIRST_RUN_KEY = 'first_run'
|
||||
|
||||
@@ -23,7 +23,7 @@ export class InstallationService extends ApplicationService {
|
||||
*/
|
||||
async needsWipe() {
|
||||
const hasAccountOrPasscode = this.application.hasAccount() || this.application?.hasPasscode()
|
||||
const deviceInterface = this.application.deviceInterface as MobileDeviceInterface
|
||||
const deviceInterface = this.application.deviceInterface as MobileDevice
|
||||
const keychainKey = await deviceInterface.getNamespacedKeychainValue(this.application.identifier)
|
||||
|
||||
const hasKeychainValue = keychainKey != undefined
|
||||
|
||||
@@ -2,21 +2,31 @@ import AsyncStorage from '@react-native-community/async-storage'
|
||||
import SNReactNative from '@standardnotes/react-native-utils'
|
||||
import {
|
||||
ApplicationIdentifier,
|
||||
DeviceInterface,
|
||||
Environment,
|
||||
LegacyMobileKeychainStructure,
|
||||
LegacyRawKeychainValue,
|
||||
MobileDeviceInterface,
|
||||
NamespacedRootKeyInKeychain,
|
||||
RawKeychainValue,
|
||||
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'
|
||||
import { AppStateObserverService } from './../AppStateObserverService'
|
||||
import Keychain from './Keychain'
|
||||
import { IsMobileWeb } from './Utils'
|
||||
|
||||
export type BiometricsType = 'Fingerprint' | 'Face ID' | 'Biometrics' | 'Touch ID'
|
||||
|
||||
export enum MobileDeviceEvent {
|
||||
RequestsWebViewReload = 0,
|
||||
}
|
||||
|
||||
type MobileDeviceEventHandler = (event: MobileDeviceEvent) => void
|
||||
|
||||
/**
|
||||
* This identifier was the database name used in Standard Notes web/desktop.
|
||||
*/
|
||||
@@ -52,11 +62,22 @@ const showLoadFailForItemIds = (failedItemIds: string[]) => {
|
||||
Alert.alert('Unable to load item(s)', text)
|
||||
}
|
||||
|
||||
export class MobileDeviceInterface implements DeviceInterface {
|
||||
export class MobileDevice implements MobileDeviceInterface {
|
||||
environment: Environment.Mobile = Environment.Mobile
|
||||
private eventObservers: MobileDeviceEventHandler[] = []
|
||||
public isDarkMode = false
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
deinit() {}
|
||||
constructor(private stateObserverService?: AppStateObserverService) {}
|
||||
|
||||
deinit() {
|
||||
this.stateObserverService?.deinit()
|
||||
;(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)
|
||||
@@ -177,6 +198,14 @@ export class MobileDeviceInterface implements DeviceInterface {
|
||||
}
|
||||
}
|
||||
|
||||
hideMobileInterfaceFromScreenshots(): void {
|
||||
hide()
|
||||
}
|
||||
|
||||
stopHidingMobileInterfaceFromScreenshots(): void {
|
||||
show()
|
||||
}
|
||||
|
||||
async getAllRawStorageKeyValues() {
|
||||
const keys = await AsyncStorage.getAllKeys()
|
||||
return this.getRawStorageKeyValues(keys)
|
||||
@@ -288,15 +317,74 @@ export class MobileDeviceInterface implements DeviceInterface {
|
||||
}
|
||||
}
|
||||
|
||||
getRawKeychainValue(): Promise<RawKeychainValue | null | undefined> {
|
||||
return Keychain.getKeys()
|
||||
async authenticateWithBiometrics() {
|
||||
this.stateObserverService?.beginIgnoringStateChanges()
|
||||
|
||||
const result = await new Promise<boolean>((resolve) => {
|
||||
if (Platform.OS === 'android') {
|
||||
FingerprintScanner.authenticate({
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore ts type does not exist for deviceCredentialAllowed
|
||||
deviceCredentialAllowed: true,
|
||||
description: 'Biometrics are required to access your notes.',
|
||||
})
|
||||
.then(() => {
|
||||
FingerprintScanner.release()
|
||||
resolve(true)
|
||||
})
|
||||
.catch((error) => {
|
||||
FingerprintScanner.release()
|
||||
if (error.name === 'DeviceLocked') {
|
||||
Alert.alert('Unsuccessful', 'Authentication failed. Wait 30 seconds to try again.')
|
||||
} else {
|
||||
Alert.alert('Unsuccessful', 'Authentication failed. Tap to try again.')
|
||||
}
|
||||
resolve(false)
|
||||
})
|
||||
} else {
|
||||
// iOS
|
||||
FingerprintScanner.authenticate({
|
||||
fallbackEnabled: true,
|
||||
description: 'This is required to access your notes.',
|
||||
})
|
||||
.then(() => {
|
||||
FingerprintScanner.release()
|
||||
resolve(true)
|
||||
})
|
||||
.catch((error_1) => {
|
||||
FingerprintScanner.release()
|
||||
if (error_1.name !== 'SystemCancel') {
|
||||
if (error_1.name !== 'UserCancel') {
|
||||
Alert.alert('Unsuccessful')
|
||||
} else {
|
||||
Alert.alert('Unsuccessful', 'Authentication failed. Tap to try again.')
|
||||
}
|
||||
}
|
||||
resolve(false)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
this.stateObserverService?.stopIgnoringStateChanges()
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
async getRawKeychainValue(): Promise<RawKeychainValue | undefined> {
|
||||
const result = await Keychain.getKeys()
|
||||
|
||||
if (result === null) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
async clearRawKeychainValue(): Promise<void> {
|
||||
await Keychain.clearKeys()
|
||||
}
|
||||
|
||||
async setAndroidScreenshotPrivacy(enable: boolean): Promise<void> {
|
||||
setAndroidScreenshotPrivacy(enable: boolean): void {
|
||||
if (Platform.OS === 'android') {
|
||||
enable ? FlagSecure.activate() : FlagSecure.deactivate()
|
||||
}
|
||||
@@ -328,7 +416,37 @@ export class MobileDeviceInterface implements DeviceInterface {
|
||||
}
|
||||
|
||||
performSoftReset() {
|
||||
SNReactNative.exitApp()
|
||||
if (IsMobileWeb) {
|
||||
this.notifyEvent(MobileDeviceEvent.RequestsWebViewReload)
|
||||
} else {
|
||||
SNReactNative.exitApp()
|
||||
}
|
||||
}
|
||||
|
||||
addMobileWebEventReceiver(handler: MobileDeviceEventHandler): () => void {
|
||||
this.eventObservers.push(handler)
|
||||
|
||||
const thislessObservers = this.eventObservers
|
||||
|
||||
return () => {
|
||||
removeFromArray(thislessObservers, handler)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { TEnvironment } from '@Root/App'
|
||||
import { TEnvironment } from '@Root/NativeApp'
|
||||
import VersionInfo from 'react-native-version-info'
|
||||
|
||||
export const IsDev = VersionInfo.bundleIdentifier?.includes('dev')
|
||||
export const IsMobileWeb = IsDev
|
||||
|
||||
export function isNullOrUndefined(value: unknown) {
|
||||
return value === null || value === undefined
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import { navigationRef } from '@Lib/NavigationService'
|
||||
import { NavigationContainer } from '@react-navigation/native'
|
||||
import React from 'react'
|
||||
import { MobileWebMainStackComponent } from './ModalStack'
|
||||
|
||||
const AppComponent: React.FC = () => {
|
||||
return (
|
||||
<NavigationContainer ref={navigationRef}>
|
||||
<MobileWebMainStackComponent />
|
||||
</NavigationContainer>
|
||||
)
|
||||
}
|
||||
|
||||
export const MobileWebApp = () => {
|
||||
return <AppComponent />
|
||||
}
|
||||
@@ -1,13 +1,61 @@
|
||||
import { MobileDeviceInterface } from '@Lib/Interface'
|
||||
import React, { useMemo, useRef } from 'react'
|
||||
import { Platform } from 'react-native'
|
||||
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 { Keyboard, Platform } from 'react-native'
|
||||
import { WebView, WebViewMessageEvent } from 'react-native-webview'
|
||||
import { AppStateObserverService } from './AppStateObserverService'
|
||||
|
||||
const LoggingEnabled = IsDev
|
||||
|
||||
export const MobileWebAppContainer = () => {
|
||||
const [identifier, setIdentifier] = useState(Math.random())
|
||||
|
||||
const destroyAndReload = useCallback(() => {
|
||||
setIdentifier(Math.random())
|
||||
}, [])
|
||||
|
||||
return <MobileWebAppContents key={`${identifier}`} destroyAndReload={destroyAndReload} />
|
||||
}
|
||||
|
||||
const MobileWebAppContents = ({ destroyAndReload }: { destroyAndReload: () => void }) => {
|
||||
const webViewRef = useRef<WebView>(null)
|
||||
const sourceUri = (Platform.OS === 'android' ? 'file:///android_asset/' : '') + 'Web.bundle/src/index.html'
|
||||
const webViewRef = useRef<WebView>(null)
|
||||
const stateService = useMemo(() => new AppStateObserverService(), [])
|
||||
const device = useMemo(() => new MobileDevice(stateService), [stateService])
|
||||
|
||||
useEffect(() => {
|
||||
const removeListener = stateService.addEventObserver((event: ReactNativeToWebEvent) => {
|
||||
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])
|
||||
|
||||
useEffect(() => {
|
||||
const observer = device.addMobileWebEventReceiver((event) => {
|
||||
if (event === MobileDeviceEvent.RequestsWebViewReload) {
|
||||
destroyAndReload()
|
||||
}
|
||||
})
|
||||
|
||||
return () => {
|
||||
observer()
|
||||
}
|
||||
}, [device, destroyAndReload])
|
||||
|
||||
const device = useMemo(() => new MobileDeviceInterface(), [])
|
||||
const functions = Object.getOwnPropertyNames(Object.getPrototypeOf(device))
|
||||
|
||||
const baselineFunctions: Record<string, any> = {
|
||||
@@ -28,7 +76,7 @@ export const MobileWebAppContainer = () => {
|
||||
|
||||
stringFunctions += `
|
||||
${functionName}(...args) {
|
||||
return this.sendMessage('${functionName}', args);
|
||||
return this.askReactNativeToInvokeInterfaceMethod('${functionName}', args);
|
||||
}
|
||||
`
|
||||
}
|
||||
@@ -44,8 +92,8 @@ export const MobileWebAppContainer = () => {
|
||||
|
||||
setApplication() {}
|
||||
|
||||
sendMessage(functionName, args) {
|
||||
return this.messageSender.sendMessage(functionName, args)
|
||||
askReactNativeToInvokeInterfaceMethod(functionName, args) {
|
||||
return this.messageSender.askReactNativeToInvokeInterfaceMethod(functionName, args)
|
||||
}
|
||||
|
||||
${stringFunctions}
|
||||
@@ -56,26 +104,18 @@ export const MobileWebAppContainer = () => {
|
||||
class WebProcessMessageSender {
|
||||
constructor() {
|
||||
this.pendingMessages = []
|
||||
window.addEventListener('message', this.handleMessageFromReactNative.bind(this))
|
||||
document.addEventListener('message', this.handleMessageFromReactNative.bind(this))
|
||||
}
|
||||
|
||||
handleMessageFromReactNative(event) {
|
||||
const message = event.data
|
||||
try {
|
||||
const parsed = JSON.parse(message)
|
||||
const { messageId, returnValue } = parsed
|
||||
const pendingMessage = this.pendingMessages.find((m) => m.messageId === messageId)
|
||||
pendingMessage.resolve(returnValue)
|
||||
this.pendingMessages.splice(this.pendingMessages.indexOf(pendingMessage), 1)
|
||||
} catch (error) {
|
||||
console.log('Error parsing message from React Native', message, error)
|
||||
}
|
||||
handleReplyFromReactNative( messageId, returnValue) {
|
||||
const pendingMessage = this.pendingMessages.find((m) => m.messageId === messageId)
|
||||
pendingMessage.resolve(returnValue)
|
||||
this.pendingMessages.splice(this.pendingMessages.indexOf(pendingMessage), 1)
|
||||
}
|
||||
|
||||
sendMessage(functionName, args) {
|
||||
askReactNativeToInvokeInterfaceMethod(functionName, args) {
|
||||
const messageId = Math.random()
|
||||
window.ReactNativeWebView.postMessage(JSON.stringify({ functionName: functionName, args: args, messageId }))
|
||||
|
||||
return new Promise((resolve) => {
|
||||
this.pendingMessages.push({
|
||||
messageId,
|
||||
@@ -98,6 +138,25 @@ export const MobileWebAppContainer = () => {
|
||||
const messageSender = new WebProcessMessageSender();
|
||||
window.reactNativeDevice = new WebProcessDeviceInterface(messageSender);
|
||||
|
||||
const handleMessageFromReactNative = (event) => {
|
||||
const message = event.data
|
||||
|
||||
try {
|
||||
const parsed = JSON.parse(message)
|
||||
const { messageId, returnValue, messageType } = parsed
|
||||
|
||||
if (messageType === 'reply') {
|
||||
messageSender.handleReplyFromReactNative(messageId, returnValue)
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.log('Error parsing message from React Native', message, error)
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('message', handleMessageFromReactNative)
|
||||
document.addEventListener('message', handleMessageFromReactNative)
|
||||
|
||||
true;
|
||||
`
|
||||
|
||||
@@ -107,14 +166,18 @@ export const MobileWebAppContainer = () => {
|
||||
const functionData = JSON.parse(message)
|
||||
void onFunctionMessage(functionData.functionName, functionData.messageId, functionData.args)
|
||||
} catch (error) {
|
||||
console.log('onGeneralMessage', JSON.stringify(message))
|
||||
if (LoggingEnabled) {
|
||||
console.log('onGeneralMessage', JSON.stringify(message))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const onFunctionMessage = async (functionName: string, messageId: string, args: any) => {
|
||||
const returnValue = await (device as any)[functionName](...args)
|
||||
console.log(`Native device function ${functionName} called`)
|
||||
webViewRef.current?.postMessage(JSON.stringify({ messageId, returnValue }))
|
||||
if (LoggingEnabled) {
|
||||
console.log(`Native device function ${functionName} called`)
|
||||
}
|
||||
webViewRef.current?.postMessage(JSON.stringify({ messageId, returnValue, messageType: 'reply' }))
|
||||
}
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-empty-function */
|
||||
@@ -130,6 +193,7 @@ export const MobileWebAppContainer = () => {
|
||||
allowFileAccess={true}
|
||||
allowUniversalAccessFromFileURLs={true}
|
||||
injectedJavaScriptBeforeContentLoaded={injectedJS}
|
||||
bounces={false}
|
||||
/>
|
||||
)
|
||||
/* eslint-enable @typescript-eslint/no-empty-function */
|
||||
|
||||
@@ -30,11 +30,11 @@ import React, { memo, useContext } from 'react'
|
||||
import { Platform } from 'react-native'
|
||||
import { HeaderButtons, Item } from 'react-navigation-header-buttons'
|
||||
import { ThemeContext } from 'styled-components'
|
||||
import { HeaderTitleParams, TEnvironment } from './App'
|
||||
import { ApplicationContext } from './ApplicationContext'
|
||||
import { AppStackComponent } from './AppStack'
|
||||
import { HistoryStack } from './HistoryStack'
|
||||
import { MobileWebAppContainer } from './MobileWebAppContainer'
|
||||
import { HeaderTitleParams, TEnvironment } from './NativeApp'
|
||||
|
||||
export type ModalStackNavigatorParamList = {
|
||||
AppStack: undefined
|
||||
@@ -75,7 +75,31 @@ export type ModalStackNavigationProp<T extends keyof ModalStackNavigatorParamLis
|
||||
|
||||
const MainStack = createStackNavigator<ModalStackNavigatorParamList>()
|
||||
|
||||
export const MainStackComponent = ({ env }: { env: TEnvironment }) => {
|
||||
export const MobileWebMainStackComponent = () => {
|
||||
const MemoizedAppStackComponent = memo((props: ModalStackNavigationProp<'AppStack'>) => (
|
||||
<AppStackComponent {...props} />
|
||||
))
|
||||
|
||||
return (
|
||||
<MainStack.Navigator
|
||||
screenOptions={{
|
||||
gestureEnabled: false,
|
||||
presentation: 'modal',
|
||||
}}
|
||||
initialRouteName="AppStack"
|
||||
>
|
||||
<MainStack.Screen
|
||||
name={'AppStack'}
|
||||
options={{
|
||||
headerShown: false,
|
||||
}}
|
||||
component={MemoizedAppStackComponent}
|
||||
/>
|
||||
</MainStack.Navigator>
|
||||
)
|
||||
}
|
||||
|
||||
export const NativeMainStackComponent = ({ env }: { env: TEnvironment }) => {
|
||||
const application = useContext(ApplicationContext)
|
||||
const theme = useContext(ThemeContext)
|
||||
|
||||
|
||||
@@ -9,10 +9,9 @@ import { MobileThemeVariables } from '@Root/Style/Themes/styled-components'
|
||||
import { ApplicationGroupEvent, DeinitMode, DeinitSource } from '@standardnotes/snjs'
|
||||
import { ThemeService, ThemeServiceContext } from '@Style/ThemeService'
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { StatusBar } from 'react-native'
|
||||
import { ThemeProvider } from 'styled-components/native'
|
||||
import { ApplicationContext } from './ApplicationContext'
|
||||
import { MainStackComponent } from './ModalStack'
|
||||
import { NativeMainStackComponent } from './ModalStack'
|
||||
|
||||
export type HeaderTitleParams = {
|
||||
title?: string
|
||||
@@ -107,13 +106,12 @@ const AppComponent: React.FC<{
|
||||
}}
|
||||
ref={navigationRef}
|
||||
>
|
||||
<StatusBar translucent />
|
||||
{themeService.current && (
|
||||
<>
|
||||
<ThemeProvider theme={activeTheme}>
|
||||
<ActionSheetProvider>
|
||||
<ThemeServiceContext.Provider value={themeService.current}>
|
||||
<MainStackComponent env={env} />
|
||||
<NativeMainStackComponent env={env} />
|
||||
</ThemeServiceContext.Provider>
|
||||
</ActionSheetProvider>
|
||||
<ToastWrapper />
|
||||
@@ -124,7 +122,7 @@ const AppComponent: React.FC<{
|
||||
)
|
||||
}
|
||||
|
||||
export const App = (props: { env: TEnvironment }) => {
|
||||
export const NativeApp = (props: { env: TEnvironment }) => {
|
||||
const [application, setApplication] = useState<MobileApplication | undefined>()
|
||||
|
||||
const createNewAppGroup = useCallback(() => {
|
||||
@@ -1,5 +1,5 @@
|
||||
import { AppStateType, PasscodeKeyboardType } from '@Lib/ApplicationState'
|
||||
import { MobileDeviceInterface } from '@Lib/Interface'
|
||||
import { MobileDevice } from '@Lib/Interface'
|
||||
import { HeaderHeightContext } from '@react-navigation/elements'
|
||||
import { useFocusEffect } from '@react-navigation/native'
|
||||
import { ApplicationContext } from '@Root/ApplicationContext'
|
||||
@@ -164,7 +164,7 @@ export const Authenticate = ({
|
||||
}, [])
|
||||
|
||||
const checkForBiometrics = useCallback(
|
||||
async () => (application?.deviceInterface as MobileDeviceInterface).getDeviceBiometricsAvailability(),
|
||||
async () => (application?.deviceInterface as MobileDevice).getDeviceBiometricsAvailability(),
|
||||
[application],
|
||||
)
|
||||
|
||||
|
||||
@@ -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'
|
||||
@@ -8,10 +7,10 @@ import { SectionHeader } from '@Root/Components/SectionHeader'
|
||||
import { TableSection } from '@Root/Components/TableSection'
|
||||
import { useSafeApplicationContext } from '@Root/Hooks/useSafeApplicationContext'
|
||||
import { ModalStackNavigationProp } from '@Root/ModalStack'
|
||||
import { SCREEN_MANAGE_SESSIONS, SCREEN_SETTINGS, SCREEN_WEB_APP } from '@Root/Screens/screens'
|
||||
import { ButtonType, PrefKey, StorageValueModes } from '@standardnotes/snjs'
|
||||
import { SCREEN_MANAGE_SESSIONS, SCREEN_SETTINGS } from '@Root/Screens/screens'
|
||||
import { ButtonType, PrefKey } from '@standardnotes/snjs'
|
||||
import moment from 'moment'
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import React, { useCallback, useMemo, useState } from 'react'
|
||||
import { Platform } from 'react-native'
|
||||
import DocumentPicker from 'react-native-document-picker'
|
||||
import RNFS from 'react-native-fs'
|
||||
@@ -183,22 +182,6 @@ export const OptionsSection = ({ title, encryptionAvailable }: Props) => {
|
||||
)
|
||||
}, [application.alertService])
|
||||
|
||||
const [shouldAlwaysOpenWebAppOnLaunch, setShouldAlwaysOpenWebAppOnLaunch] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
const getSetting = async () => {
|
||||
const value = (await application.getValue(AlwaysOpenWebAppOnLaunchKey, StorageValueModes.Nonwrapped)) as
|
||||
| boolean
|
||||
| undefined
|
||||
setShouldAlwaysOpenWebAppOnLaunch(value ?? false)
|
||||
}
|
||||
void getSetting()
|
||||
}, [application])
|
||||
|
||||
const openWebApp = useCallback(() => {
|
||||
navigation.push(SCREEN_WEB_APP)
|
||||
}, [navigation])
|
||||
|
||||
return (
|
||||
<TableSection>
|
||||
<SectionHeader title={title} />
|
||||
@@ -238,17 +221,6 @@ export const OptionsSection = ({ title, encryptionAvailable }: Props) => {
|
||||
onPress={onExportPress}
|
||||
/>
|
||||
|
||||
<ButtonCell testID="openWebApp" leftAligned title="Open Web App" onPress={() => openWebApp()} />
|
||||
<SectionedAccessoryTableCell
|
||||
onPress={() => {
|
||||
const newValue = !shouldAlwaysOpenWebAppOnLaunch
|
||||
setShouldAlwaysOpenWebAppOnLaunch(newValue)
|
||||
void application.setValue(AlwaysOpenWebAppOnLaunchKey, newValue, StorageValueModes.Nonwrapped)
|
||||
}}
|
||||
text="Always Open Web App On Launch"
|
||||
selected={() => shouldAlwaysOpenWebAppOnLaunch}
|
||||
/>
|
||||
|
||||
{!signedIn && (
|
||||
<SectionedAccessoryTableCell
|
||||
testID="lastExportDate"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { MobileDeviceInterface } from '@Lib/Interface'
|
||||
import { MobileDevice } from '@Lib/Interface'
|
||||
import { useFocusEffect, useNavigation } from '@react-navigation/native'
|
||||
import { ApplicationContext } from '@Root/ApplicationContext'
|
||||
import { ButtonCell } from '@Root/Components/ButtonCell'
|
||||
@@ -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)
|
||||
}
|
||||
@@ -53,7 +53,7 @@ export const SecuritySection = (props: Props) => {
|
||||
void getHasBiometrics()
|
||||
const hasBiometricsSupport = async () => {
|
||||
const hasBiometricsAvailable = await (
|
||||
application?.deviceInterface as MobileDeviceInterface
|
||||
application?.deviceInterface as MobileDevice
|
||||
).getDeviceBiometricsAvailability()
|
||||
if (mounted) {
|
||||
setSupportsBiometrics(hasBiometricsAvailable)
|
||||
|
||||
@@ -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,22 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [1.19.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-24)
|
||||
|
||||
### Features
|
||||
|
||||
* new note title format w/ prefs ([#1629](https://github.com/standardnotes/app/issues/1629)) ([d3621d7](https://github.com/standardnotes/app/commit/d3621d70b1a34537417b06830275467055b753cb))
|
||||
|
||||
## [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.19.0",
|
||||
"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)
|
||||
|
||||
@@ -32,6 +32,13 @@ export enum PrefKey {
|
||||
MobileDoNotShowAgainUnsupportedEditors = 'mobileDoNotShowAgainUnsupportedEditors',
|
||||
MobileSelectedTagUuid = 'mobileSelectedTagUuid',
|
||||
MobileNotesHideEditorIcon = 'mobileHideEditorIcon',
|
||||
NewNoteTitleFormat = 'newNoteTitleFormat',
|
||||
}
|
||||
|
||||
export enum NewNoteTitleFormat {
|
||||
CurrentDateAndTime = 'CurrentDateAndTime',
|
||||
CurrentNoteCount = 'CurrentNoteCount',
|
||||
Empty = 'Empty',
|
||||
}
|
||||
|
||||
export type PrefValue = {
|
||||
@@ -65,4 +72,5 @@ export type PrefValue = {
|
||||
[PrefKey.MobileDoNotShowAgainUnsupportedEditors]: boolean
|
||||
[PrefKey.MobileSelectedTagUuid]: string | undefined
|
||||
[PrefKey.MobileNotesHideEditorIcon]: boolean
|
||||
[PrefKey.NewNoteTitleFormat]: NewNoteTitleFormat
|
||||
}
|
||||
|
||||
@@ -3,6 +3,130 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.3.77](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.76](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [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.3.56](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.55](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-19)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.54](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-19)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.53](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-19)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.52](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-18)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.51](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-16)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.50](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-16)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.49](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-16)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.48](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.47](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.46](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/releases",
|
||||
"version": "1.3.46",
|
||||
"version": "1.3.77",
|
||||
"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,38 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.21.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/services
|
||||
|
||||
## [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.21.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-19)
|
||||
|
||||
### Features
|
||||
|
||||
* mobile web bridge ([#1597](https://github.com/standardnotes/app/issues/1597)) ([c4d7761](https://github.com/standardnotes/app/commit/c4d776149677269bc766f24da6adc5ec816dbcfb))
|
||||
|
||||
## [1.20.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-15)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* biometrics input on mobile webview challenge modal ([#1572](https://github.com/standardnotes/app/issues/1572)) ([3a15142](https://github.com/standardnotes/app/commit/3a15142940ef9391868442e1997c3d9d5eec33be))
|
||||
|
||||
## [1.20.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/services
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/services",
|
||||
"version": "1.20.1",
|
||||
"version": "1.21.4",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
@@ -42,6 +42,7 @@
|
||||
"eslint": "^8.23.1",
|
||||
"eslint-plugin-prettier": "*",
|
||||
"jest": "^28.1.2",
|
||||
"ts-jest": "^28.0.5"
|
||||
"ts-jest": "^28.0.5",
|
||||
"typescript": "*"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { MobileDeviceInterface } from './../Device/MobileDeviceInterface'
|
||||
import { DesktopManagerInterface } from '../Device/DesktopManagerInterface'
|
||||
import { WebAppEvent } from '../Event/WebAppEvent'
|
||||
import { ApplicationInterface } from './ApplicationInterface'
|
||||
@@ -5,4 +6,10 @@ import { ApplicationInterface } from './ApplicationInterface'
|
||||
export interface WebApplicationInterface extends ApplicationInterface {
|
||||
notifyWebEvent(event: WebAppEvent, data?: unknown): void
|
||||
getDesktopService(): DesktopManagerInterface | undefined
|
||||
handleMobileEnteringBackgroundEvent(): Promise<void>
|
||||
handleMobileGainingFocusEvent(): Promise<void>
|
||||
handleMobileLosingFocusEvent(): Promise<void>
|
||||
handleMobileResumingFromBackgroundEvent(): Promise<void>
|
||||
isNativeMobileWeb(): boolean
|
||||
get mobileDevice(): MobileDeviceInterface
|
||||
}
|
||||
|
||||
@@ -6,7 +6,10 @@ export interface MobileDeviceInterface extends DeviceInterface {
|
||||
|
||||
getRawKeychainValue(): Promise<RawKeychainValue | undefined>
|
||||
getDeviceBiometricsAvailability(): Promise<boolean>
|
||||
setAndroidScreenshotPrivacy(enable: boolean): Promise<void>
|
||||
getMobileScreenshotPrivacyEnabled(): Promise<boolean | undefined>
|
||||
setMobileScreenshotPrivacyEnabled(isEnabled: 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,76 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [2.132.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/snjs
|
||||
|
||||
## [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
|
||||
|
||||
# [2.130.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-19)
|
||||
|
||||
### Features
|
||||
|
||||
* mobile web bridge ([#1597](https://github.com/standardnotes/app/issues/1597)) ([c4d7761](https://github.com/standardnotes/app/commit/c4d776149677269bc766f24da6adc5ec816dbcfb))
|
||||
|
||||
## [2.129.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-19)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **snjs:** pass unencrypted file size to comply with file service interface ([#1595](https://github.com/standardnotes/app/issues/1595)) ([038320b](https://github.com/standardnotes/app/commit/038320b2fda8348810db586c70b0998647519fd6))
|
||||
|
||||
## [2.129.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/snjs
|
||||
|
||||
# [2.129.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-15)
|
||||
|
||||
### Features
|
||||
|
||||
* sharing subscriptions UI ([#1567](https://github.com/standardnotes/app/issues/1567)) ([2d0ee10](https://github.com/standardnotes/app/commit/2d0ee10226687df1d24926b9408ce270557a5b57))
|
||||
|
||||
## [2.128.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-15)
|
||||
|
||||
**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'
|
||||
@@ -41,6 +45,7 @@ import {
|
||||
FileService,
|
||||
SubscriptionClientInterface,
|
||||
SubscriptionManager,
|
||||
StorageValueModes,
|
||||
} from '@standardnotes/services'
|
||||
import { FilesClientInterface } from '@standardnotes/files'
|
||||
import { ComputePrivateWorkspaceIdentifier } from '@standardnotes/encryption'
|
||||
@@ -60,6 +65,7 @@ import { SNLog } from '../Log'
|
||||
import { Challenge, ChallengeResponse } from '../Services'
|
||||
import { ApplicationConstructorOptions, FullyResolvedApplicationOptions } from './Options/ApplicationOptions'
|
||||
import { ApplicationOptionsDefaults } from './Options/Defaults'
|
||||
import { MobileUnlockTiming } from '@Lib/Services/Protection/MobileUnlockTiming'
|
||||
|
||||
/** How often to automatically sync, in milliseconds */
|
||||
const DEFAULT_AUTO_SYNC_INTERVAL = 30_000
|
||||
@@ -106,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
|
||||
@@ -322,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()
|
||||
|
||||
@@ -927,20 +936,28 @@ export class SNApplication
|
||||
return this.deinit(this.getDeinitMode(), DeinitSource.Lock)
|
||||
}
|
||||
|
||||
async setBiometricsTiming(timing: InternalServices.MobileUnlockTiming) {
|
||||
setBiometricsTiming(timing: MobileUnlockTiming) {
|
||||
return this.protectionService.setBiometricsTiming(timing)
|
||||
}
|
||||
|
||||
async getMobileScreenshotPrivacyEnabled(): Promise<boolean | undefined> {
|
||||
getMobileScreenshotPrivacyEnabled(): boolean {
|
||||
return this.protectionService.getMobileScreenshotPrivacyEnabled()
|
||||
}
|
||||
|
||||
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() {
|
||||
@@ -1079,6 +1096,8 @@ export class SNApplication
|
||||
this.createUserApiService()
|
||||
this.createSubscriptionServer()
|
||||
this.createSubscriptionApiService()
|
||||
this.createWebSocketServer()
|
||||
this.createWebSocketApiService()
|
||||
this.createSubscriptionManager()
|
||||
this.createWebSocketsService()
|
||||
this.createSessionManager()
|
||||
@@ -1120,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
|
||||
@@ -1237,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)
|
||||
@@ -1322,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)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
export enum ReactNativeToWebEvent {
|
||||
EnteringBackground = 'EnteringBackground',
|
||||
ResumingFromBackground = 'ResumingFromBackground',
|
||||
GainingFocus = 'GainingFocus',
|
||||
LosingFocus = 'LosingFocus',
|
||||
}
|
||||
@@ -2,3 +2,4 @@ export * from './IconsController'
|
||||
export * from './NoteViewController'
|
||||
export * from './FileViewController'
|
||||
export * from './ItemGroupController'
|
||||
export * from './ReactNativeToWebEvent'
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
export enum MobileUnlockTiming {
|
||||
Immediately = 'immediately',
|
||||
OnQuit = 'on-quit',
|
||||
}
|
||||
@@ -18,17 +18,13 @@ import {
|
||||
} from '@standardnotes/services'
|
||||
import { ProtectionsClientInterface } from './ClientInterface'
|
||||
import { ContentType } from '@standardnotes/common'
|
||||
import { MobileUnlockTiming } from './MobileUnlockTiming'
|
||||
|
||||
export enum ProtectionEvent {
|
||||
UnprotectedSessionBegan = 'UnprotectedSessionBegan',
|
||||
UnprotectedSessionExpired = 'UnprotectedSessionExpired',
|
||||
}
|
||||
|
||||
export enum MobileUnlockTiming {
|
||||
Immediately = 'immediately',
|
||||
OnQuit = 'on-quit',
|
||||
}
|
||||
|
||||
export const ProposedSecondsToDeferUILevelSessionExpirationDuringActiveInteraction = 30
|
||||
|
||||
export enum UnprotectedAccessSecondsDuration {
|
||||
@@ -91,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()
|
||||
}
|
||||
@@ -261,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(
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
export * from './ClientInterface'
|
||||
export * from './ProtectionService'
|
||||
export * from './MobileUnlockTiming'
|
||||
|
||||
@@ -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,11 +121,13 @@ 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()
|
||||
}
|
||||
}
|
||||
|
||||
private setSession(session: Session, persist = true): void {
|
||||
this.httpService.setAuthorizationToken(session.authorizationValue)
|
||||
|
||||
this.apiService.setSession(session, persist)
|
||||
}
|
||||
|
||||
@@ -621,11 +623,9 @@ export class SNSessionManager extends AbstractService<SessionEvent> implements S
|
||||
|
||||
this.httpService.setHost(host)
|
||||
|
||||
this.httpService.setAuthorizationToken(session.authorizationValue)
|
||||
this.setSession(session)
|
||||
|
||||
await 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,
|
||||
|
||||
@@ -53,7 +53,7 @@ describe('files', function () {
|
||||
})
|
||||
|
||||
const uploadFile = async (fileService, buffer, name, ext, chunkSize) => {
|
||||
const operation = await fileService.beginNewFileUpload()
|
||||
const operation = await fileService.beginNewFileUpload(buffer.byteLength)
|
||||
|
||||
let chunkId = 1
|
||||
for (let i = 0; i < buffer.length; i += chunkSize) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/snjs",
|
||||
"version": "2.128.1",
|
||||
"version": "2.132.5",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,38 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.3.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/ui-services
|
||||
|
||||
## [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.2.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-19)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/ui-services
|
||||
|
||||
## [1.2.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/ui-services
|
||||
|
||||
## [1.2.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/ui-services
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/ui-services",
|
||||
"version": "1.2.3",
|
||||
"version": "1.3.2",
|
||||
"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,196 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [3.57.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-24)
|
||||
|
||||
### Features
|
||||
|
||||
* new note title format w/ prefs ([#1629](https://github.com/standardnotes/app/issues/1629)) ([d3621d7](https://github.com/standardnotes/app/commit/d3621d70b1a34537417b06830275467055b753cb))
|
||||
|
||||
# [3.56.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-24)
|
||||
|
||||
### Features
|
||||
|
||||
* flatten quick settings menu and add separate prefs button ([#1631](https://github.com/standardnotes/app/issues/1631)) ([97835e6](https://github.com/standardnotes/app/commit/97835e64ac0ebea829a923af082880b269a2965e))
|
||||
|
||||
## [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
|
||||
|
||||
* window size on mobile ([#1600](https://github.com/standardnotes/app/issues/1600)) ([dd5ca0c](https://github.com/standardnotes/app/commit/dd5ca0c28c683252fa3cc5eee3c27b981fbd7977))
|
||||
|
||||
## [3.50.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* default to notes list on launch on mobile ([#1599](https://github.com/standardnotes/app/issues/1599)) ([571919c](https://github.com/standardnotes/app/commit/571919c9696212d4389692ccdf53e60a2bc06e16))
|
||||
|
||||
# [3.50.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-19)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* show warning on mobile webview before app quits ([#1598](https://github.com/standardnotes/app/issues/1598)) ([e3be17c](https://github.com/standardnotes/app/commit/e3be17c7f8345c1eed5b2cc6f98b38e24647b212))
|
||||
|
||||
### Features
|
||||
|
||||
* mobile web bridge ([#1597](https://github.com/standardnotes/app/issues/1597)) ([c4d7761](https://github.com/standardnotes/app/commit/c4d776149677269bc766f24da6adc5ec816dbcfb))
|
||||
|
||||
## [3.49.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-19)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* preferences dropdown contrast and color ([#1591](https://github.com/standardnotes/app/issues/1591)) ([ecaa2a6](https://github.com/standardnotes/app/commit/ecaa2a629f7c7bac58c26d7258469711b7c05785))
|
||||
|
||||
## [3.49.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-19)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.49.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-18)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* move save status next to note actions on mobile ([#1590](https://github.com/standardnotes/app/issues/1590)) ([efe0c38](https://github.com/standardnotes/app/commit/efe0c38462bb5d75fc94a6ba966bc26a6973890f))
|
||||
|
||||
# [3.49.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-16)
|
||||
|
||||
### Features
|
||||
|
||||
* add settings to fully switch between native/webview ([#1587](https://github.com/standardnotes/app/issues/1587)) ([85c90e0](https://github.com/standardnotes/app/commit/85c90e07fc8b1ce66eaa88df09f2728ac0fecf1c))
|
||||
|
||||
## [3.48.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-16)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.48.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-16)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* long titles on non-mobile view ([#1575](https://github.com/standardnotes/app/issues/1575)) ([7807fa3](https://github.com/standardnotes/app/commit/7807fa34f30f47ef3d7025bc4c804dbb9079c15a))
|
||||
|
||||
## [3.48.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-15)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* biometrics input on mobile webview challenge modal ([#1572](https://github.com/standardnotes/app/issues/1572)) ([3a15142](https://github.com/standardnotes/app/commit/3a15142940ef9391868442e1997c3d9d5eec33be))
|
||||
|
||||
# [3.48.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-15)
|
||||
|
||||
### Features
|
||||
|
||||
* sharing subscriptions UI ([#1567](https://github.com/standardnotes/app/issues/1567)) ([2d0ee10](https://github.com/standardnotes/app/commit/2d0ee10226687df1d24926b9408ce270557a5b57))
|
||||
|
||||
## [3.47.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/web",
|
||||
"version": "3.47.3",
|
||||
"version": "3.57.0",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"main": "dist/app.js",
|
||||
"author": "Standard Notes.",
|
||||
@@ -13,6 +13,7 @@
|
||||
"clean": "rm -fr dist && rm -rf src/components",
|
||||
"format": "prettier --write src/javascripts",
|
||||
"lint": "NODE_OPTIONS=\"--max-old-space-size=4096\" eslint src/javascripts",
|
||||
"lint:fix": "NODE_OPTIONS=\"--max-old-space-size=4096\" eslint src/javascripts --fix",
|
||||
"start": "webpack-dev-server --config web.webpack.dev.js",
|
||||
"start-secure": "yarn start --server-type https",
|
||||
"test": "jest --config jest.config.js --coverage",
|
||||
|
||||
@@ -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" />
|
||||
|
||||
|
||||
@@ -66,7 +66,10 @@ const startApplication: StartApplication = async function startApplication(
|
||||
root = createRoot(appendedRootNode)
|
||||
|
||||
disableIosTextFieldZoom()
|
||||
document.documentElement.style.setProperty('--viewport-height', `${window.innerHeight}px`)
|
||||
document.documentElement.style.setProperty(
|
||||
'--viewport-height',
|
||||
`${visualViewport ? visualViewport.height : window.innerHeight}px`,
|
||||
)
|
||||
|
||||
root.render(
|
||||
<ApplicationGroupView
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user