Compare commits

..
Author SHA1 Message Date
StandardNotes CI f02465346f chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].7
 - @standardnotes/[email protected].7
 - @standardnotes/[email protected].7
 - @standardnotes/[email protected].9
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].2
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
2022-09-29 15:10:20 +00:00
Aman Harwara 11dd39c126 feat: add custom note title format pref (#1678) 2022-09-29 20:10:05 +05:30
Mo d7a90c4d91 refactor: add pkc fields for registration endpoint (#1680) 2022-09-29 09:13:05 -05:00
StandardNotes CI 00075616e6 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].8
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected].3
2022-09-29 13:41:22 +00:00
Karol Sójko 5ffffbff20 feat(snjs): add e2e test for subsequent subscriptions settings persistance 2022-09-29 15:11:44 +02:00
StandardNotes CI ecd8d56171 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].7
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].2
 - @standardnotes/[email protected].2
2022-09-29 10:01:20 +00:00
Karol Sójko 33226000f5 fix(snjs): increase wait time in retrieving settings test for processing replaceable settings 2022-09-29 11:30:36 +02:00
Karol Sójko c841ac99d2 fix(snjs): instructions on running e2e locally 2022-09-29 11:07:12 +02:00
StandardNotes CI b0e708186c chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].6
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].1
2022-09-29 08:54:37 +00:00
Aman Harwara 20e420820d fix: ipad web view ui improvements (#1664) 2022-09-29 13:47:00 +05:30
StandardNotes CI c3d6a91730 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].5
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
2022-09-29 07:45:24 +00:00
Aman Harwara 0ed692ff9b feat: add panel settings section in quick settings (#1669) 2022-09-29 12:46:06 +05:30
StandardNotes CI c74fa272fb chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].4
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].4
2022-09-28 16:34:58 +00:00
Aman Harwara 3f9d3ceffa fix: improve biometrics input on mobile webview (#1658) 2022-09-28 21:26:20 +05:30
StandardNotes CI f6d0aa0f0a chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].6
 - @standardnotes/[email protected].6
 - @standardnotes/[email protected].6
 - @standardnotes/[email protected].3
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].3
2022-09-28 15:16:53 +00:00
Aman Harwara eafa65e934 fix: grey flash on textarea focus on safari/webkit (#1661) 2022-09-28 20:11:03 +05:30
Mo a83003ee69 feat(crypto): pkc algos for key generation, encrypt, and decrypt (#1663) 2022-09-28 09:15:34 -05:00
StandardNotes CI 554f59a3fe chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].2
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].2
2022-09-28 13:42:14 +00:00
Aman Harwara c0af596f2d fix: sticky header behavior on iOS (#1662) 2022-09-28 18:36:42 +05:30
StandardNotes CI 6e10911d02 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].1
2022-09-28 09:41:43 +00:00
Aman Harwara 9502a7fa32 fix: challenge modal 2022-09-28 14:30:31 +05:30
Aman Harwara 727d78cfe2 fix: webapp blanking because of mobileDevice check 2022-09-28 14:24:05 +05:30
StandardNotes CI 44bb4b7ca3 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
2022-09-28 07:19:59 +00:00
Aman Harwara 981d8a7497 feat: handle android back button on android (#1656) 2022-09-28 12:12:55 +05:30
StandardNotes CI 04245dfeeb chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
2022-09-27 14:51:15 +00:00
Vardan HakobyanandMo 5db47e83e8 feat: delete account (#1653)
* feat: delete account

* fix: copy adjustments

Co-authored-by: Mo
2022-09-27 18:13:54 +04:00
StandardNotes CI c08602b7b8 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
2022-09-27 13:28:41 +00:00
Aman Harwara ec52e5684d feat: upgrade cta (#1655) 2022-09-27 18:29:50 +05:30
StandardNotes CI f3f7f9d362 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].3
2022-09-27 12:52:54 +00:00
Mo b9a07d8b5a fix(web): incorrect native access 2022-09-27 07:23:21 -05:00
StandardNotes CI 31213bf268 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].2
2022-09-27 11:20:27 +00:00
Aman Harwara 70e57e32b3 fix: don't hide note tags container on desktop 2022-09-27 16:19:06 +05:30
StandardNotes CI 720215eea7 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].5
 - @standardnotes/[email protected].6
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].1
2022-09-27 07:23:11 +00:00
Aman Harwara 6d5ebdeaa1 fix: export/sharing notes on mobile webview (#1644) 2022-09-27 12:24:44 +05:30
StandardNotes CI c99693876f chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
2022-09-26 16:21:50 +00:00
Aman Harwara f8f6a5212b feat: sticky header on mobile if plaintext note is scrolled (#1645) 2022-09-26 21:15:11 +05:30
StandardNotes CI 58cd919267 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].1
2022-09-26 12:42:43 +00:00
Karol Sójko 507823dc4f fix(web): check for proper feature in the subscription sharing section 2022-09-26 14:12:01 +02:00
StandardNotes CI 6ea1def0cf chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
2022-09-25 22:06:15 +00:00
Aman Harwara fe2ce9f1e8 feat: note tags button for mobile (#1641) 2022-09-26 02:58:55 +05:30
StandardNotes CI 4985787c5d chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
2022-09-25 16:08:44 +00:00
Aman Harwara 8614a638a4 fix(mobile): hide drawer on new mobile experience (#1642) 2022-09-25 21:04:04 +05:30
StandardNotes CI 15957c71cb chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].9
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].3
2022-09-24 21:45:51 +00:00
Aman Harwara 59e814bcec fix: improve new note title format (#1640) 2022-09-24 16:18:06 -05:00
StandardNotes CI 4cf9ebf52a chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].8
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].2
2022-09-24 19:32:22 +00:00
Aman Harwara a3611c802f fix: move prefs button next to account menu button in footer (#1639) 2022-09-25 00:33:30 +05:30
StandardNotes CI 9be315730d chore(release): publish
- @standardnotes/[email protected].7
 - @standardnotes/[email protected]
2022-09-24 17:28:41 +00:00
Mo 789a78bda3 fix(mobile): accurate version number 2022-09-24 11:58:29 -05:00
StandardNotes CI 73e170dedd chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].6
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].1
2022-09-24 16:32:37 +00:00
Aman Harwara e4b1b64119 fix: responsiveness when resizing window on web/desktop (#1637) 2022-09-24 21:24:10 +05:30
StandardNotes CI c2a1918843 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].5
 - @standardnotes/[email protected].5
 - @standardnotes/[email protected].5
 - @standardnotes/[email protected].5
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].4
 - @standardnotes/[email protected].5
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
2022-09-24 11:03:09 +00:00
Aman Harwara d3621d70b1 feat: new note title format w/ prefs (#1629) 2022-09-24 16:04:31 +05:30
StandardNotes CI bf286f4854 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].4
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
2022-09-24 09:32:43 +00:00
Aman Harwara 97835e64ac feat: flatten quick settings menu and add separate prefs button (#1631) 2022-09-24 14:26:55 +05:30
StandardNotes CI 285df04a59 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].4
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected].4
 - @standardnotes/[email protected].4
 - @standardnotes/[email protected].3
 - @standardnotes/[email protected].4
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].3
 - @standardnotes/[email protected].3
 - @standardnotes/[email protected].4
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].2
2022-09-23 19:29:51 +00:00
Mo 4d5429cc89 fix(mobile): adjust status bar color to match current theme (#1624)
* feat: sync page theme color metadata with active theme bg

* fix: lint

* refactor: extract to method

* feat: recieve theme scheme change on mobile

* fix: handle issue where status bar color changes when keyboard appears on iOS

* fix: disable bouncing on web view
2022-09-23 13:48:51 -05:00
StandardNotes CI da6622dc95 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].2
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].1
2022-09-23 18:23:20 +00:00
Aman Harwara a548883863 fix: prefs view on desktop (#1628) 2022-09-23 23:22:01 +05:30
StandardNotes CI 1330201d2e chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
2022-09-23 17:16:32 +00:00
Aman Harwara 0af720146c feat: add prefs button to navigation panel on mobile (#1625) 2022-09-23 22:17:50 +05:30
StandardNotes CI 4d6992cf83 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].3
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].6
2022-09-23 15:54:05 +00:00
Aman Harwara 5de6f459c1 feat: sync page theme color metadata with active theme bg (#1623) 2022-09-23 20:53:00 +05:30
Mo 3c0d4fac76 fix: biometrics timing loading (#1622) 2022-09-23 09:59:16 -05:00
StandardNotes CI 4cdfcbfd95 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].5
2022-09-23 11:16:50 +00:00
Aman Harwara 51e50433d3 fix: protected overlay on mobile (#1621) 2022-09-23 16:16:04 +05:30
StandardNotes CI 696327ff03 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].4
2022-09-23 08:47:03 +00:00
Karol Sójko de64f1bfce fix(web): move email notification preferences to account pane (#1620) 2022-09-23 10:17:21 +02:00
StandardNotes CI 48d484675b chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].3
2022-09-22 20:08:00 +00:00
Aman Harwara 86251b49d3 fix: better safe area padding on iOS (#1618) 2022-09-23 01:03:36 +05:30
StandardNotes CI 5961bc491d chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].2
 - @standardnotes/[email protected].2
2022-09-22 18:54:43 +00:00
Karol Sójko e50f4eb92e Revert "Revert "feat(web): move emails notifications to one pane and enable opening settings via url (#1614)" (#1617)" (#1619)
This reverts commit 6824dd2d5f.
2022-09-22 20:18:19 +02:00
StandardNotes CI 4f8e75f36a chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected].1
2022-09-22 17:21:08 +00:00
Karol Sójko 6824dd2d5f Revert "feat(web): move emails notifications to one pane and enable opening settings via url (#1614)" (#1617)
This reverts commit 1fe833bc24.
2022-09-22 18:50:41 +02:00
Mo 76ec8b0f90 refactor: new mobile experience opt in flow (#1616)
* refactor: new mobile experience opt in flow

* chore: lint
2022-09-22 11:20:26 -05:00
StandardNotes CI 3eebdbb77d chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
2022-09-22 15:22:42 +00:00
Aman Harwara ce252def33 feat: show selected editor icon in change editor button (#1615) 2022-09-22 20:22:49 +05:30
StandardNotes CI cb7af03ce8 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected].0
2022-09-22 11:16:54 +00:00
Karol Sójko 1fe833bc24 feat(web): move emails notifications to one pane and enable opening settings via url (#1614)
* feat(web): move emails notifications to one pane and enable opening settings via url

* fix(web): rename notifications to email

* fix(snjs): add mute marketing emails to settings list options

* fix(web): linter issues
2022-09-22 12:40:08 +02:00
StandardNotes CI ac1f59cde7 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].9
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].1
2022-09-22 08:08:31 +00:00
Aman Harwara db4ceca10e fix: manage subscription button on mobile webview (#1613) 2022-09-22 13:10:15 +05:30
StandardNotes CI 0176f47fe7 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].8
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
2022-09-22 03:20:23 +00:00
Aman Harwara f281041221 feat: on mobile goto content tab after selecting revision (#1611) 2022-09-22 08:15:08 +05:30
StandardNotes CI ebd56cd5aa chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].7
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
2022-09-21 19:32:23 +00:00
Aman Harwara 8fa566336c fix: iOS safe area using CSS (#1610) 2022-09-22 00:22:11 +05:30
Aman Harwara 9dfeac7489 fix: disable focus mode and dynamic panel switches on mobile (#1607) 2022-09-21 22:09:02 +05:30
Aman Harwara d1b71861ec feat: add lock button to navigation panel on mobile (#1609) 2022-09-21 21:40:32 +05:30
StandardNotes CI 766548f12d chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].6
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].6
2022-09-21 15:42:20 +00:00
Aman Harwara 581a08cd09 fix: tag input auto-submitting when pressing space (#1608) 2022-09-21 20:39:29 +05:30
Aman Harwara ee0d44405d fix: revert webview alert changes (#1606) 2022-09-21 20:18:56 +05:30
Aman Harwara 1ae64dcac4 fix: iOS webview window size and padding (#1605) 2022-09-21 19:58:46 +05:30
StandardNotes CI 2be4fb4f83 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].5
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected].5
2022-09-21 13:19:58 +00:00
Mo 271a8d1d70 fix(web): subscription sharing copy 2022-09-21 07:50:17 -05:00
Karol Sójko e809328fa8 feat(snjs): add retrieving web sockets token for establishing connection (#1602)
* feat(snjs): add retrieving web sockets token for establishing connection

* fix(snjs): imports

* fix(snjs): use only web sockets connection token

* fix(snjs): linter issue
2022-09-21 14:39:43 +02:00
178 changed files with 3874 additions and 1115 deletions
Binary file not shown.
+16
View File
@@ -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.8.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-29)
**Note:** Version bump only for package @standardnotes/api
## [1.8.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
**Note:** Version bump only for package @standardnotes/api
## [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
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/api",
"version": "1.8.1",
"version": "1.8.5",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -24,7 +24,12 @@ describe('UserApiService', () => {
})
it('should register a user', async () => {
const response = await createService().register('[email protected]', 'testpasswd', keyParams, false)
const response = await createService().register({
email: '[email protected]',
serverPassword: 'testpasswd',
keyParams,
ephemeral: false,
})
expect(response).toEqual({
data: {
@@ -52,7 +57,7 @@ describe('UserApiService', () => {
let error = null
try {
await service.register('[email protected]', 'testpasswd', keyParams, false)
await service.register({ email: '[email protected]', serverPassword: 'testpasswd', keyParams, ephemeral: false })
} catch (caughtError) {
error = caughtError
}
@@ -67,7 +72,12 @@ describe('UserApiService', () => {
let error = null
try {
await createService().register('[email protected]', 'testpasswd', keyParams, false)
await createService().register({
email: '[email protected]',
serverPassword: 'testpasswd',
keyParams,
ephemeral: false,
})
} catch (caughtError) {
error = caughtError
}
@@ -15,12 +15,12 @@ export class UserApiService implements UserApiServiceInterface {
this.registering = false
}
async register(
email: string,
serverPassword: string,
keyParams: RootKeyParamsInterface,
ephemeral: boolean,
): Promise<UserRegistrationResponse> {
async register(registerDTO: {
email: string
serverPassword: string
keyParams: RootKeyParamsInterface
ephemeral: boolean
}): Promise<UserRegistrationResponse> {
if (this.registering) {
throw new ApiCallError(ErrorMessage.RegistrationInProgress)
}
@@ -29,10 +29,10 @@ export class UserApiService implements UserApiServiceInterface {
try {
const response = await this.userServer.register({
[ApiEndpointParam.ApiVersion]: ApiVersion.v0,
password: serverPassword,
email,
ephemeral,
...keyParams.getPortableValue(),
password: registerDTO.serverPassword,
email: registerDTO.email,
ephemeral: registerDTO.ephemeral,
...registerDTO.keyParams.getPortableValue(),
})
this.registering = false
@@ -2,10 +2,10 @@ import { RootKeyParamsInterface } from '@standardnotes/models'
import { UserRegistrationResponse } from '../../Response/User/UserRegistrationResponse'
export interface UserApiServiceInterface {
register(
email: string,
serverPassword: string,
keyParams: RootKeyParamsInterface,
ephemeral: boolean,
): Promise<UserRegistrationResponse>
register(registerDTO: {
email: string
serverPassword: string
keyParams: RootKeyParamsInterface
ephemeral: boolean
}): Promise<UserRegistrationResponse>
}
@@ -8,4 +8,6 @@ export type UserRegistrationRequestParams = AnyKeyParamsContent & {
email: string
ephemeral: boolean
[additionalParam: string]: unknown
pkcPublicKey?: string
pkcEncryptedPrivateKey?: string
}
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.7.14](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
**Note:** Version bump only for package @standardnotes/components-meta
## [2.7.13](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-16)
**Note:** Version bump only for package @standardnotes/components-meta
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/components-meta",
"version": "2.7.13",
"version": "2.7.14",
"private": true,
"author": "Standard Notes.",
"main": "dist",
+156
View File
@@ -3,6 +3,162 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.23.175](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-29)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.174](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-29)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.173](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-29)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.172](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-29)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.171](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-29)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.170](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.169](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.168](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.167](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.166](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.165](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-27)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.164](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-27)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.163](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-27)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.162](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-27)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.161](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-27)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.160](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-26)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.159](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-26)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.158](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-25)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.157](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.156](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.155](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.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
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@standardnotes/desktop",
"main": "./app/dist/index.js",
"version": "3.23.136",
"version": "3.23.175",
"license": "AGPL-3.0-or-later",
"author": "Standard Notes.",
"private": true,
+16
View File
@@ -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.15.7](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-29)
**Note:** Version bump only for package @standardnotes/encryption
## [1.15.6](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
**Note:** Version bump only for package @standardnotes/encryption
## [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 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/encryption",
"version": "1.15.3",
"version": "1.15.7",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
+6
View File
@@ -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 -1
View File
@@ -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',
+16
View File
@@ -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.23.7](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-29)
**Note:** Version bump only for package @standardnotes/filepicker
## [1.23.6](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
**Note:** Version bump only for package @standardnotes/filepicker
## [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 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/filepicker",
"version": "1.23.3",
"version": "1.23.7",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
+16
View File
@@ -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.10.7](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-29)
**Note:** Version bump only for package @standardnotes/files
## [1.10.6](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
**Note:** Version bump only for package @standardnotes/files
## [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 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/files",
"version": "1.10.3",
"version": "1.10.7",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
+180
View File
@@ -3,6 +3,186 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.37.9](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-29)
**Note:** Version bump only for package @standardnotes/mobile
## [3.37.8](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-29)
**Note:** Version bump only for package @standardnotes/mobile
## [3.37.7](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-29)
**Note:** Version bump only for package @standardnotes/mobile
## [3.37.6](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-29)
**Note:** Version bump only for package @standardnotes/mobile
## [3.37.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-29)
**Note:** Version bump only for package @standardnotes/mobile
## [3.37.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
**Note:** Version bump only for package @standardnotes/mobile
## [3.37.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
**Note:** Version bump only for package @standardnotes/mobile
## [3.37.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
**Note:** Version bump only for package @standardnotes/mobile
## [3.37.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
**Note:** Version bump only for package @standardnotes/mobile
# [3.37.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
### Features
* handle android back button on android ([#1656](https://github.com/standardnotes/app/issues/1656)) ([981d8a7](https://github.com/standardnotes/app/commit/981d8a7497ea2600e1535ad9170cb5559550ca4d))
## [3.36.18](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-27)
**Note:** Version bump only for package @standardnotes/mobile
## [3.36.17](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-27)
**Note:** Version bump only for package @standardnotes/mobile
## [3.36.16](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-27)
**Note:** Version bump only for package @standardnotes/mobile
## [3.36.15](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-27)
**Note:** Version bump only for package @standardnotes/mobile
## [3.36.14](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-27)
### Bug Fixes
* export/sharing notes on mobile webview ([#1644](https://github.com/standardnotes/app/issues/1644)) ([6d5ebde](https://github.com/standardnotes/app/commit/6d5ebdeaa1777f31878b6e7d4dfc33fe83abc9fc))
## [3.36.13](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-26)
**Note:** Version bump only for package @standardnotes/mobile
## [3.36.12](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-26)
**Note:** Version bump only for package @standardnotes/mobile
## [3.36.11](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-25)
**Note:** Version bump only for package @standardnotes/mobile
## [3.36.10](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-25)
### Bug Fixes
* **mobile:** hide drawer on new mobile experience ([#1642](https://github.com/standardnotes/app/issues/1642)) ([8614a63](https://github.com/standardnotes/app/commit/8614a638a4bfc8fdf97020bf1fc147c62998cf3b))
## [3.36.9](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.8](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.7](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-24)
### Bug Fixes
* **mobile:** accurate version number ([789a78b](https://github.com/standardnotes/app/commit/789a78bda33f12d214c12a63ae27d2ba0f39feab))
## [3.36.6](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.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
@@ -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>
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/mobile",
"version": "3.35.4",
"version": "3.37.9",
"author": "Standard Notes.",
"private": true,
"license": "AGPL-3.0-or-later",
@@ -69,7 +69,7 @@
"react-native-screens": "3.13.1",
"react-native-search-bar": "standardnotes/react-native-search-bar#7d2139daf9b7663b570403f21f520deceba9bb09",
"react-native-search-box": "standardnotes/react-native-search-box#8c46369912cba78dca718588aca9c16926953ff7",
"react-native-share": "^7.3.7",
"react-native-share": "^7.9.0",
"react-native-sodium-jsi": "1.2.0",
"react-native-static-server": "standardnotes/react-native-static-server#28ef0175dbee3db9aadfab57498497067556a836",
"react-native-store-review": "^0.2.0",
@@ -0,0 +1,21 @@
import { AbstractService, InternalEventBus, ReactNativeToWebEvent } from '@standardnotes/snjs'
import { BackHandler, NativeEventSubscription } from 'react-native'
export class AndroidBackHandlerService extends AbstractService<ReactNativeToWebEvent> {
private removeListener: NativeEventSubscription
constructor() {
const internalEventBus = new InternalEventBus()
super(internalEventBus)
this.removeListener = BackHandler.addEventListener('hardwareBackPress', () => {
void this.notifyEvent(ReactNativeToWebEvent.AndroidBackButtonPressed)
return true
})
}
deinit() {
this.removeListener.remove()
}
}
+4 -9
View File
@@ -18,7 +18,7 @@ import { ICON_MENU } from '@Style/Icons'
import { ThemeService } from '@Style/ThemeService'
import { getDefaultDrawerWidth } from '@Style/Utils'
import React, { useCallback, useContext, useEffect, useRef, useState } from 'react'
import { Dimensions, Keyboard, ScaledSize, StatusBar } from 'react-native'
import { Dimensions, Keyboard, ScaledSize } from 'react-native'
import DrawerLayout, { DrawerState } from 'react-native-gesture-handler/DrawerLayout'
import { HeaderButtons, Item } from 'react-navigation-header-buttons'
import { ThemeContext } from 'styled-components'
@@ -121,7 +121,9 @@ export const AppStackComponent = (props: ModalStackNavigationProp<'AppStack'>) =
[application],
)
if (IsMobileWeb) {
const shouldOpenWebApp = application?.getValue(AlwaysOpenWebAppOnLaunchKey, StorageValueModes.Nonwrapped) as boolean
if (IsMobileWeb || shouldOpenWebApp) {
return (
<AppStack.Navigator
screenOptions={() => ({
@@ -134,12 +136,6 @@ export const AppStackComponent = (props: ModalStackNavigationProp<'AppStack'>) =
)
}
if (!application) {
return null
}
const shouldOpenWebApp = application.getValue(AlwaysOpenWebAppOnLaunchKey, StorageValueModes.Nonwrapped) as boolean
return (
<DrawerLayout
ref={drawerRef}
@@ -150,7 +146,6 @@ export const AppStackComponent = (props: ModalStackNavigationProp<'AppStack'>) =
onDrawerStateChanged={handleDrawerStateChange}
renderNavigationView={() => !isLocked && <MainSideMenu drawerRef={drawerRef.current} />}
>
<StatusBar translucent={!shouldOpenWebApp} />
<DrawerLayout
ref={noteDrawerRef}
drawerWidth={getDefaultDrawerWidth(dimensions)}
+4 -1
View File
@@ -13,6 +13,7 @@ import {
platformFromString,
SNApplication,
SNComponentManager,
StorageValueModes,
} from '@standardnotes/snjs'
import { Platform } from 'react-native'
@@ -21,6 +22,7 @@ import { MobileAlertService } from './AlertService'
import { ApplicationState } from './ApplicationState'
import { BackupsService } from './BackupsService'
import { ComponentManager } from './ComponentManager'
import { AlwaysOpenWebAppOnLaunchKey } from './constants'
import { FilesService } from './FilesService'
import { InstallationService } from './InstallationService'
import { MobileDevice } from './Interface'
@@ -135,7 +137,8 @@ export class MobileApplication extends SNApplication {
}
promptForChallenge(challenge: Challenge) {
if (IsMobileWeb) {
const optedIntoWebPreview = this.getValue(AlwaysOpenWebAppOnLaunchKey, StorageValueModes.Nonwrapped) as boolean
if (IsMobileWeb || optedIntoWebPreview) {
return
}
+131 -2
View File
@@ -1,4 +1,5 @@
import AsyncStorage from '@react-native-community/async-storage'
import { AndroidBackHandlerService } from '@Root/AndroidBackHandlerService'
import SNReactNative from '@standardnotes/react-native-utils'
import {
ApplicationIdentifier,
@@ -7,16 +8,27 @@ import {
LegacyRawKeychainValue,
MobileDeviceInterface,
NamespacedRootKeyInKeychain,
Platform as SNPlatform,
RawKeychainValue,
removeFromArray,
TransferPayload,
} from '@standardnotes/snjs'
import { Alert, Linking, Platform } from 'react-native'
import { Alert, Linking, PermissionsAndroid, Platform, StatusBar } from 'react-native'
import FingerprintScanner from 'react-native-fingerprint-scanner'
import FlagSecure from 'react-native-flag-secure-android'
import {
CachesDirectoryPath,
DocumentDirectoryPath,
DownloadDirectoryPath,
exists,
unlink,
writeFile,
} from 'react-native-fs'
import { hide, show } from 'react-native-privacy-snapshot'
import Share from 'react-native-share'
import { AppStateObserverService } from './../AppStateObserverService'
import Keychain from './Keychain'
import { SNReactNativeCrypto } from './ReactNativeCrypto'
import { IsMobileWeb } from './Utils'
export type BiometricsType = 'Fingerprint' | 'Face ID' | 'Biometrics' | 'Touch ID'
@@ -64,13 +76,23 @@ const showLoadFailForItemIds = (failedItemIds: string[]) => {
export class MobileDevice implements MobileDeviceInterface {
environment: Environment.Mobile = Environment.Mobile
platform: SNPlatform.Ios | SNPlatform.Android = Platform.OS === 'ios' ? SNPlatform.Ios : SNPlatform.Android
private eventObservers: MobileDeviceEventHandler[] = []
public isDarkMode = false
private crypto: SNReactNativeCrypto
constructor(private stateObserverService?: AppStateObserverService) {}
constructor(
private stateObserverService?: AppStateObserverService,
private androidBackHandlerService?: AndroidBackHandlerService,
) {
this.crypto = new SNReactNativeCrypto()
}
deinit() {
this.stateObserverService?.deinit()
;(this.stateObserverService as unknown) = undefined
this.androidBackHandlerService?.deinit()
;(this.androidBackHandlerService as unknown) = undefined
}
consoleLog(...args: any[]): void {
@@ -432,6 +454,16 @@ export class MobileDevice implements MobileDeviceInterface {
}
}
handleThemeSchemeChange(isDark: boolean): void {
this.isDarkMode = isDark
this.reloadStatusBarStyle()
}
reloadStatusBarStyle(animated = true) {
StatusBar.setBarStyle(this.isDarkMode ? 'light-content' : 'dark-content', animated)
}
private notifyEvent(event: MobileDeviceEvent): void {
for (const handler of this.eventObservers) {
handler(event)
@@ -444,4 +476,101 @@ export class MobileDevice implements MobileDeviceInterface {
isDeviceDestroyed() {
return false
}
async deleteFileAtPathIfExists(path: string) {
if (await exists(path)) {
await unlink(path)
}
}
async shareBase64AsFile(base64: string, filename: string) {
let downloadedTempFilePath: string | undefined
try {
downloadedTempFilePath = await this.downloadBase64AsFile(base64, filename, true)
if (!downloadedTempFilePath) {
return
}
await Share.open({
url: `file://${downloadedTempFilePath}`,
failOnCancel: false,
})
} catch (error) {
this.consoleLog(`${error}`)
} finally {
if (downloadedTempFilePath) {
void this.deleteFileAtPathIfExists(downloadedTempFilePath)
}
}
}
getFileDestinationPath(filename: string, saveInTempLocation: boolean): string {
let directory = DocumentDirectoryPath
if (Platform.OS === 'android') {
directory = saveInTempLocation ? CachesDirectoryPath : DownloadDirectoryPath
}
return `${directory}/${filename}`
}
async hasStoragePermissionOnAndroid(): Promise<boolean> {
if (Platform.OS !== 'android') {
return true
}
const grantedStatus = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE)
if (grantedStatus === PermissionsAndroid.RESULTS.GRANTED) {
return true
}
Alert.alert(
'Storage permissions are required in order to download files. Please accept the permissions prompt and try again.',
)
return false
}
async downloadBase64AsFile(
base64: string,
filename: string,
saveInTempLocation = false,
): Promise<string | undefined> {
const isGrantedStoragePermissionOnAndroid = await this.hasStoragePermissionOnAndroid()
if (!isGrantedStoragePermissionOnAndroid) {
return
}
try {
const path = this.getFileDestinationPath(filename, saveInTempLocation)
void this.deleteFileAtPathIfExists(path)
const decodedContents = this.crypto.base64Decode(base64.replace(/data.*base64,/, ''))
await writeFile(path, decodedContents)
return path
} catch (error) {
this.consoleLog(`${error}`)
}
}
confirmAndExit() {
Alert.alert(
'Close app',
'Do you want to close the app?',
[
{
text: 'Cancel',
style: 'cancel',
// eslint-disable-next-line @typescript-eslint/no-empty-function
onPress: async () => {},
},
{
text: 'Close',
style: 'destructive',
onPress: async () => {
SNReactNative.exitApp()
},
},
],
{
cancelable: true,
},
)
}
}
+34 -8
View File
@@ -1,11 +1,15 @@
import { MobileDevice, MobileDeviceEvent } from '@Lib/Interface'
import { IsDev } from '@Lib/Utils'
import { ReactNativeToWebEvent } from '@standardnotes/snjs'
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { Platform } from 'react-native'
import { Keyboard, Platform } from 'react-native'
import VersionInfo from 'react-native-version-info'
import { WebView, WebViewMessageEvent } from 'react-native-webview'
import pjson from '../package.json'
import { AndroidBackHandlerService } from './AndroidBackHandlerService'
import { AppStateObserverService } from './AppStateObserverService'
const LoggingEnabled = false
const LoggingEnabled = IsDev
export const MobileWebAppContainer = () => {
const [identifier, setIdentifier] = useState(Math.random())
@@ -21,17 +25,38 @@ const MobileWebAppContents = ({ destroyAndReload }: { destroyAndReload: () => vo
const webViewRef = useRef<WebView>(null)
const sourceUri = (Platform.OS === 'android' ? 'file:///android_asset/' : '') + 'Web.bundle/src/index.html'
const stateService = useMemo(() => new AppStateObserverService(), [])
const device = useMemo(() => new MobileDevice(stateService), [stateService])
const androidBackHandlerService = useMemo(() => new AndroidBackHandlerService(), [])
const device = useMemo(
() => new MobileDevice(stateService, androidBackHandlerService),
[androidBackHandlerService, stateService],
)
useEffect(() => {
const removeListener = stateService.addEventObserver((event: ReactNativeToWebEvent) => {
const removeStateServiceListener = stateService.addEventObserver((event: ReactNativeToWebEvent) => {
webViewRef.current?.postMessage(JSON.stringify({ reactNativeEvent: event, messageType: 'event' }))
})
const removeBackHandlerServiceListener = androidBackHandlerService.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()
removeStateServiceListener()
removeBackHandlerServiceListener()
keyboardShowListener.remove()
keyboardHideListener.remove()
}
}, [webViewRef, stateService])
}, [webViewRef, stateService, device, androidBackHandlerService])
useEffect(() => {
const observer = device.addMobileWebEventReceiver((event) => {
@@ -73,8 +98,9 @@ const MobileWebAppContents = ({ destroyAndReload }: { destroyAndReload: () => vo
const WebProcessDeviceInterface = `
class WebProcessDeviceInterface {
constructor(messageSender) {
this.appVersion = '1.2.3'
this.appVersion = '${pjson.version} (${VersionInfo.buildVersion})'
this.environment = 4
this.platform = ${device.platform}
this.databases = []
this.messageSender = messageSender
}
@@ -175,7 +201,6 @@ const MobileWebAppContents = ({ destroyAndReload }: { destroyAndReload: () => vo
ref={webViewRef}
source={{ uri: sourceUri }}
originWhitelist={['*']}
contentInset={{ top: 30, bottom: 10 }}
onLoad={() => {}}
onError={(err) => console.error('An error has occurred', err)}
onHttpError={() => console.error('An HTTP error occurred')}
@@ -183,6 +208,7 @@ const MobileWebAppContents = ({ destroyAndReload }: { destroyAndReload: () => vo
allowFileAccess={true}
allowUniversalAccessFromFileURLs={true}
injectedJavaScriptBeforeContentLoaded={injectedJS}
bounces={false}
/>
)
/* eslint-enable @typescript-eslint/no-empty-function */
@@ -0,0 +1,69 @@
import { AlwaysOpenWebAppOnLaunchKey } from '@Lib/constants'
import { ApplicationContext } from '@Root/ApplicationContext'
import { ButtonCell } from '@Root/Components/ButtonCell'
import { SectionHeader } from '@Root/Components/SectionHeader'
import { TableSection } from '@Root/Components/TableSection'
import { ButtonType, StorageValueModes } from '@standardnotes/snjs'
import React, { useContext } from 'react'
import styled from 'styled-components/native'
import { Label } from './CompanySection.styled'
import { BaseView, StyledSectionedTableCell } from './EncryptionSection.styled'
const Title = styled.Text`
color: ${({ theme }) => theme.stylekitForegroundColor};
font-size: 16px;
font-weight: bold;
`
export const NewMobileSection = () => {
const application = useContext(ApplicationContext)
if (!application) {
return <></>
}
const optIn = async () => {
const confirmationText =
'This will close the app and switch to the new mobile experience next time you open it. You will be able to switch back to the soon-to-be removed classic experience from the settings.'
if (
await application.alertService.confirm(
confirmationText,
'Switch To New Mobile Experience?',
'Switch',
ButtonType.Info,
)
) {
application.setValue(AlwaysOpenWebAppOnLaunchKey, true, StorageValueModes.Nonwrapped)
setTimeout(() => application.deviceInterface.performSoftReset(), 1000)
}
}
return (
<TableSection>
<SectionHeader title={'New Mobile Experience'} />
<StyledSectionedTableCell last={true} first={true}>
<BaseView>
<Title>🎉 New Mobile Experience Preview</Title>
<Label>
The new mobile experience (MX) brings the desktop experience you've come to love right here on your mobile
device. This mode will replace the existing classic mobile experience soon. You can opt in below to begin
using the new MX now.
</Label>
</BaseView>
</StyledSectionedTableCell>
<ButtonCell leftAligned={true} title="Opt In to New Mobile Experience" onPress={optIn}></ButtonCell>
<ButtonCell
leftAligned={true}
title="Read Blog Post"
onPress={() => {
application?.deviceInterface!.openUrl(
'https://blog.standardnotes.com/38384/our-new-mobile-experience-is-launching-soon',
)
}}
></ButtonCell>
</TableSection>
)
}
@@ -1,4 +1,3 @@
import { AlwaysOpenWebAppOnLaunchKey } from '@Lib/constants'
import { useSignedIn } from '@Lib/SnjsHelperHooks'
import { useNavigation } from '@react-navigation/native'
import { ButtonCell } from '@Root/Components/ButtonCell'
@@ -9,7 +8,7 @@ import { TableSection } from '@Root/Components/TableSection'
import { useSafeApplicationContext } from '@Root/Hooks/useSafeApplicationContext'
import { ModalStackNavigationProp } from '@Root/ModalStack'
import { SCREEN_MANAGE_SESSIONS, SCREEN_SETTINGS } from '@Root/Screens/screens'
import { ButtonType, PrefKey, StorageValueModes } from '@standardnotes/snjs'
import { ButtonType, PrefKey } from '@standardnotes/snjs'
import moment from 'moment'
import React, { useCallback, useMemo, useState } from 'react'
import { Platform } from 'react-native'
@@ -222,21 +221,6 @@ export const OptionsSection = ({ title, encryptionAvailable }: Props) => {
onPress={onExportPress}
/>
<ButtonCell
onPress={async () => {
const confirmationText =
'This will close the app and fully switch to the web view next time you open it. You will be able to switch back from the settings.'
if (
await application.alertService.confirm(confirmationText, 'Switch To Web View?', 'Switch', ButtonType.Info)
) {
application.setValue(AlwaysOpenWebAppOnLaunchKey, true, StorageValueModes.Nonwrapped)
setTimeout(() => application.deviceInterface.performSoftReset(), 1000)
}
}}
title="Switch to Web View"
/>
{!signedIn && (
<SectionedAccessoryTableCell
testID="lastExportDate"
@@ -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 />}
+18
View File
@@ -3,6 +3,24 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [1.20.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-29)
### Features
* add custom note title format pref ([#1678](https://github.com/standardnotes/app/issues/1678)) ([11dd39c](https://github.com/standardnotes/app/commit/11dd39c126019c4295c03fb59b05ea5aa3adcd27))
# [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 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/models",
"version": "1.18.3",
"version": "1.20.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,15 @@ export enum PrefKey {
MobileDoNotShowAgainUnsupportedEditors = 'mobileDoNotShowAgainUnsupportedEditors',
MobileSelectedTagUuid = 'mobileSelectedTagUuid',
MobileNotesHideEditorIcon = 'mobileHideEditorIcon',
NewNoteTitleFormat = 'newNoteTitleFormat',
CustomNoteTitleFormat = 'customNoteTitleFormat',
}
export enum NewNoteTitleFormat {
CurrentDateAndTime = 'CurrentDateAndTime',
CurrentNoteCount = 'CurrentNoteCount',
CustomFormat = 'CustomFormat',
Empty = 'Empty',
}
export type PrefValue = {
@@ -65,4 +74,6 @@ export type PrefValue = {
[PrefKey.MobileDoNotShowAgainUnsupportedEditors]: boolean
[PrefKey.MobileSelectedTagUuid]: string | undefined
[PrefKey.MobileNotesHideEditorIcon]: boolean
[PrefKey.NewNoteTitleFormat]: NewNoteTitleFormat
[PrefKey.CustomNoteTitleFormat]: string
}
+164
View File
@@ -3,6 +3,170 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.3.100](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-29)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.99](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-29)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.98](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-29)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.97](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-29)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.96](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-29)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.95](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.94](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.93](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.92](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.91](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.90](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-27)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.89](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-27)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.88](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-27)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.87](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-27)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.86](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-27)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.85](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-26)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.84](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-26)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.83](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-25)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.82](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-25)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.81](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.80](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.79](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.78](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.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 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/releases",
"version": "1.3.59",
"version": "1.3.100",
"license": "AGPL-3.0-or-later",
"main": "dist/releases.json",
"types": "dist/index.d.ts",
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [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
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/responses",
"version": "1.10.2",
"version": "1.10.3",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
+30
View File
@@ -3,6 +3,36 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.22.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-29)
**Note:** Version bump only for package @standardnotes/services
## [1.22.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
**Note:** Version bump only for package @standardnotes/services
# [1.22.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
### Features
* handle android back button on android ([#1656](https://github.com/standardnotes/app/issues/1656)) ([981d8a7](https://github.com/standardnotes/app/commit/981d8a7497ea2600e1535ad9170cb5559550ca4d))
## [1.21.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-27)
### Bug Fixes
* export/sharing notes on mobile webview ([#1644](https://github.com/standardnotes/app/issues/1644)) ([6d5ebde](https://github.com/standardnotes/app/commit/6d5ebdeaa1777f31878b6e7d4dfc33fe83abc9fc))
## [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
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/services",
"version": "1.21.2",
"version": "1.22.2",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -1,3 +1,4 @@
import { MobileDeviceInterface } from './../Device/MobileDeviceInterface'
import { DesktopManagerInterface } from '../Device/DesktopManagerInterface'
import { WebAppEvent } from '../Event/WebAppEvent'
import { ApplicationInterface } from './ApplicationInterface'
@@ -9,4 +10,8 @@ export interface WebApplicationInterface extends ApplicationInterface {
handleMobileGainingFocusEvent(): Promise<void>
handleMobileLosingFocusEvent(): Promise<void>
handleMobileResumingFromBackgroundEvent(): Promise<void>
isNativeMobileWeb(): boolean
get mobileDevice(): MobileDeviceInterface
handleAndroidBackButtonPressed(): void
addAndroidBackHandlerEventListener(listener: () => boolean): (() => void) | undefined
}
@@ -1,8 +1,9 @@
import { DeviceInterface } from './DeviceInterface'
import { Environment, RawKeychainValue } from '@standardnotes/models'
import { Environment, Platform, RawKeychainValue } from '@standardnotes/models'
export interface MobileDeviceInterface extends DeviceInterface {
environment: Environment.Mobile
platform: Platform.Ios | Platform.Android
getRawKeychainValue(): Promise<RawKeychainValue | undefined>
getDeviceBiometricsAvailability(): Promise<boolean>
@@ -11,4 +12,8 @@ export interface MobileDeviceInterface extends DeviceInterface {
hideMobileInterfaceFromScreenshots(): void
stopHidingMobileInterfaceFromScreenshots(): void
consoleLog(...args: any[]): void
handleThemeSchemeChange(isDark: boolean): void
shareBase64AsFile(base64: string, filename: string): Promise<void>
downloadBase64AsFile(base64: string, filename: string, saveInTempLocation?: boolean): Promise<string | undefined>
confirmAndExit(): void
}
+6
View File
@@ -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.12.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
### Features
* **crypto:** pkc algos for key generation, encrypt, and decrypt ([#1663](https://github.com/standardnotes/app/issues/1663)) ([a83003e](https://github.com/standardnotes/app/commit/a83003ee69d144c8e80eaee20bc7be2533d92c63))
## [1.11.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-23)
**Note:** Version bump only for package @standardnotes/sncrypto-common
+3 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/sncrypto-common",
"version": "1.11.1",
"version": "1.12.0",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -26,7 +26,8 @@
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^5.30.0",
"@typescript-eslint/parser": "^5.12.1",
"eslint-plugin-prettier": "^4.2.1"
"eslint-plugin-prettier": "^4.2.1",
"typescript": "*"
},
"dependencies": {
"reflect-metadata": "^0.1.13"
@@ -0,0 +1,7 @@
import { HexString } from './HexString'
export type PkcKeyPair = {
keyType: 'curve25519' | 'ed25519' | 'x25519'
privateKey: HexString
publicKey: HexString
}
@@ -8,3 +8,4 @@ export * from './StreamDecryptorResult'
export * from './StreamEncryptor'
export * from './Unencrypted'
export * from './Utf8String'
export * from './PkcKeyPair'
+6
View File
@@ -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.13.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
### Features
* **crypto:** pkc algos for key generation, encrypt, and decrypt ([#1663](https://github.com/standardnotes/app/issues/1663)) ([a83003e](https://github.com/standardnotes/app/commit/a83003ee69d144c8e80eaee20bc7be2533d92c63))
## [1.12.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-23)
**Note:** Version bump only for package @standardnotes/sncrypto-web
+3 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/sncrypto-web",
"version": "1.12.3",
"version": "1.13.0",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -39,11 +39,13 @@
"babel-loader": "^8.2.3",
"chai": "^4.3.6",
"connect": "^3.7.0",
"eslint": "*",
"eslint-plugin-prettier": "*",
"regenerator-runtime": "^0.13.9",
"serve-static": "^1.14.2",
"ts-loader": "^9.2.6",
"typedarray-to-buffer": "^4.0.0",
"typescript": "*",
"uuid": "^8.3.2",
"webpack": "*",
"webpack-cli": "*"
+62 -17
View File
@@ -9,6 +9,7 @@ import {
PureCryptoInterface,
Utf8String,
timingSafeEqual,
PkcKeyPair,
} from '@standardnotes/sncrypto-common'
import * as Utils from './utils'
import * as sodium from './libsodium'
@@ -83,7 +84,7 @@ export class SNWebCrypto implements PureCryptoInterface {
iterations: number,
length: number,
): Promise<HexString | null> {
const keyData = await Utils.stringToArrayBuffer(password)
const keyData = Utils.stringToArrayBuffer(password)
const key = await this.webCryptoImportKey(keyData, WebCryptoAlgs.Pbkdf2, [WebCryptoActions.DeriveBits])
if (!key) {
console.error('Key is null, unable to continue')
@@ -99,21 +100,21 @@ export class SNWebCrypto implements PureCryptoInterface {
}
public async aes256CbcEncrypt(plaintext: Utf8String, iv: HexString, key: HexString): Promise<Base64String> {
const keyData = await Utils.hexStringToArrayBuffer(key)
const ivData = await Utils.hexStringToArrayBuffer(iv)
const keyData = Utils.hexStringToArrayBuffer(key)
const ivData = Utils.hexStringToArrayBuffer(iv)
const alg = { name: WebCryptoAlgs.AesCbc, iv: ivData }
const importedKeyData = await this.webCryptoImportKey(keyData, alg.name, [WebCryptoActions.Encrypt])
const textData = await Utils.stringToArrayBuffer(plaintext)
const textData = Utils.stringToArrayBuffer(plaintext)
const result = await crypto.subtle.encrypt(alg, importedKeyData, textData)
return Utils.arrayBufferToBase64(result)
}
public async aes256CbcDecrypt(ciphertext: Base64String, iv: HexString, key: HexString): Promise<Utf8String | null> {
const keyData = await Utils.hexStringToArrayBuffer(key)
const ivData = await Utils.hexStringToArrayBuffer(iv)
const keyData = Utils.hexStringToArrayBuffer(key)
const ivData = Utils.hexStringToArrayBuffer(iv)
const alg = { name: WebCryptoAlgs.AesCbc, iv: ivData }
const importedKeyData = await this.webCryptoImportKey(keyData, alg.name, [WebCryptoActions.Decrypt])
const textData = await Utils.base64ToArrayBuffer(ciphertext)
const textData = Utils.base64ToArrayBuffer(ciphertext)
try {
const result = await crypto.subtle.decrypt(alg, importedKeyData, textData)
@@ -150,11 +151,11 @@ export class SNWebCrypto implements PureCryptoInterface {
}
public async hmac1(message: Utf8String, key: HexString): Promise<HexString | null> {
const keyHexData = await Utils.hexStringToArrayBuffer(key)
const keyHexData = Utils.hexStringToArrayBuffer(key)
const keyData = await this.webCryptoImportKey(keyHexData, WebCryptoAlgs.Hmac, [WebCryptoActions.Sign], {
name: WebCryptoAlgs.Sha1,
})
const messageData = await Utils.stringToArrayBuffer(message)
const messageData = Utils.stringToArrayBuffer(message)
const funcParams = { name: WebCryptoAlgs.Hmac }
try {
@@ -169,15 +170,14 @@ export class SNWebCrypto implements PureCryptoInterface {
}
public async unsafeSha1(text: string): Promise<string> {
const textData = await Utils.stringToArrayBuffer(text)
const textData = Utils.stringToArrayBuffer(text)
const digest = await crypto.subtle.digest(WebCryptoAlgs.Sha1, textData)
return Utils.arrayBufferToHexString(digest)
}
/**
* Converts a raw string key to a WebCrypto CryptoKey object.
* @param rawKey
* A plain utf8 string or an array buffer
* @param keyData
* @param alg
* The name of the algorithm this key will be used for (i.e 'AES-CBC' or 'HMAC')
* @param actions
@@ -220,7 +220,7 @@ export class SNWebCrypto implements PureCryptoInterface {
): Promise<HexString> {
const params = {
name: WebCryptoAlgs.Pbkdf2,
salt: await Utils.stringToArrayBuffer(salt),
salt: Utils.stringToArrayBuffer(salt),
iterations: iterations,
hash: { name: WebCryptoAlgs.Sha512 },
}
@@ -298,13 +298,13 @@ export class SNWebCrypto implements PureCryptoInterface {
public xchacha20StreamEncryptorPush(
encryptor: StreamEncryptor,
plainBuffer: Uint8Array,
assocData: Utf8String,
assocData?: Utf8String,
tag: SodiumConstant = SodiumConstant.CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PUSH,
): Uint8Array {
const encryptedBuffer = sodium.crypto_secretstream_xchacha20poly1305_push(
encryptor.state as sodium.StateAddress,
plainBuffer,
assocData.length > 0 ? Utils.stringToArrayBuffer(assocData) : null,
assocData && assocData.length > 0 ? Utils.stringToArrayBuffer(assocData) : null,
tag,
)
return encryptedBuffer
@@ -325,7 +325,7 @@ export class SNWebCrypto implements PureCryptoInterface {
public xchacha20StreamDecryptorPush(
decryptor: StreamDecryptor,
encryptedBuffer: Uint8Array,
assocData: Utf8String,
assocData?: Utf8String,
): StreamDecryptorResult | false {
if (encryptedBuffer.length < SodiumConstant.CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES) {
throw new Error('Invalid ciphertext size')
@@ -334,7 +334,7 @@ export class SNWebCrypto implements PureCryptoInterface {
const result = sodium.crypto_secretstream_xchacha20poly1305_pull(
decryptor.state as sodium.StateAddress,
encryptedBuffer,
assocData.length > 0 ? Utils.stringToArrayBuffer(assocData) : null,
assocData && assocData.length > 0 ? Utils.stringToArrayBuffer(assocData) : null,
)
if ((result as unknown) === false) {
@@ -344,6 +344,51 @@ export class SNWebCrypto implements PureCryptoInterface {
return result
}
/**
* https://doc.libsodium.org/public-key_cryptography/authenticated_encryption
*/
public sodiumCryptoBoxEasyEncrypt(
message: Utf8String,
nonce: HexString,
senderSecretKey: HexString,
recipientPublicKey: HexString,
): Base64String {
const result = sodium.crypto_box_easy(
message,
Utils.hexStringToArrayBuffer(nonce),
Utils.hexStringToArrayBuffer(recipientPublicKey),
Utils.hexStringToArrayBuffer(senderSecretKey),
)
return Utils.arrayBufferToBase64(result)
}
public sodiumCryptoBoxEasyDecrypt(
ciphertext: Base64String,
nonce: HexString,
senderPublicKey: HexString,
recipientSecretKey: HexString,
): Base64String {
const result = sodium.crypto_box_open_easy(
Utils.base64ToArrayBuffer(ciphertext),
Utils.hexStringToArrayBuffer(nonce),
Utils.hexStringToArrayBuffer(senderPublicKey),
Utils.hexStringToArrayBuffer(recipientSecretKey),
'text',
)
return result
}
public sodiumCryptoBoxGenerateKeypair(): PkcKeyPair {
const result = sodium.crypto_box_keypair()
const publicKey = Utils.arrayBufferToHexString(result.publicKey)
const privateKey = Utils.arrayBufferToHexString(result.privateKey)
return { publicKey, privateKey, keyType: result.keyType }
}
/**
* Generates a random secret for TOTP authentication
*
+3 -16
View File
@@ -1,16 +1,3 @@
export { SNWebCrypto } from './crypto'
export {
arrayBufferToBase64,
arrayBufferToHexString,
arrayBufferToString,
base64Decode,
base64Encode,
base64ToArrayBuffer,
base64ToHex,
hexStringToArrayBuffer,
hexToBase64,
isWebCryptoAvailable,
stringToArrayBuffer,
base32Decode,
base32Encode,
} from './utils'
export * from './crypto'
export * from './utils'
export { SodiumConstant } from '@standardnotes/sncrypto-common'
+7 -4
View File
@@ -3,12 +3,15 @@ export {
base64_variants,
crypto_aead_xchacha20poly1305_ietf_decrypt,
crypto_aead_xchacha20poly1305_ietf_encrypt,
crypto_secretstream_xchacha20poly1305_push,
crypto_secretstream_xchacha20poly1305_pull,
crypto_secretstream_xchacha20poly1305_init_push,
crypto_secretstream_xchacha20poly1305_init_pull,
crypto_box_easy,
crypto_box_keypair,
crypto_box_open_easy,
crypto_pwhash_ALG_DEFAULT,
crypto_pwhash,
crypto_secretstream_xchacha20poly1305_init_pull,
crypto_secretstream_xchacha20poly1305_init_push,
crypto_secretstream_xchacha20poly1305_pull,
crypto_secretstream_xchacha20poly1305_push,
from_base64,
from_hex,
from_string,
+72 -143
View File
@@ -50,31 +50,18 @@ describe('crypto operations', async function () {
it('compares strings with timing safe comparison', async function () {
const crypto = new SNWebCrypto()
expect(crypto.timingSafeEqual('hello world 🌍', 'hello world 🌍')).to.equal(
true,
)
expect(crypto.timingSafeEqual('helo world 🌍', 'hello world 🌍')).to.equal(
false,
)
expect(crypto.timingSafeEqual('hello world 🌍', 'hello world 🌍')).to.equal(true)
expect(crypto.timingSafeEqual('helo world 🌍', 'hello world 🌍')).to.equal(false)
expect(crypto.timingSafeEqual('', 'a')).to.equal(false)
expect(crypto.timingSafeEqual('', '')).to.equal(true)
expect(
crypto.timingSafeEqual(
'2e1ee7920bb188a88f94bb912153befd83cc55cd',
'2e1ee7920bb188a88f94bb912153befd83cc55cd',
),
crypto.timingSafeEqual('2e1ee7920bb188a88f94bb912153befd83cc55cd', '2e1ee7920bb188a88f94bb912153befd83cc55cd'),
).to.equal(true)
expect(
crypto.timingSafeEqual(
'1e1ee7920bb188a88f94bb912153befd83cc55cd',
'2e1ee7920bb188a88f94bb912153befd83cc55cd',
),
crypto.timingSafeEqual('1e1ee7920bb188a88f94bb912153befd83cc55cd', '2e1ee7920bb188a88f94bb912153befd83cc55cd'),
).to.equal(false)
expect(
crypto.timingSafeEqual(
'2e1ee7920bb188a88f94bb912153befd83cc55cc',
'2e1ee7920bb188a88f94bb912153befd83cc55cd',
),
crypto.timingSafeEqual('2e1ee7920bb188a88f94bb912153befd83cc55cc', '2e1ee7920bb188a88f94bb912153befd83cc55cd'),
).to.equal(false)
})
@@ -85,22 +72,16 @@ describe('crypto operations', async function () {
it('pbkdf2 1', async function () {
const password = 'very_secure🔒'
const salt =
'c3feb78823adce65c4ab024dab9c5cdcda5a04cdbd98f65eac0311dfa432d67b'
const expected =
'bbb3d3af19dd1cbb901c958003faa55f193aad6a57fff30e51a62591bdc054d8'
const salt = 'c3feb78823adce65c4ab024dab9c5cdcda5a04cdbd98f65eac0311dfa432d67b'
const expected = 'bbb3d3af19dd1cbb901c958003faa55f193aad6a57fff30e51a62591bdc054d8'
const result = await webCrypto.pbkdf2(password, salt, 100000, 256)
expect(result).to.equal(expected)
})
it('pbkdf2 2', async function () {
const password = 'correct horse battery staple ✅'
const salt = Buffer.from(
'808182838485868788898a8b8c8d8e8f',
'hex',
).toString('utf8')
const expected =
'795d83b18e55d860d3799f85a20f66ee17eb9dcf041df1d7a13fac30af7103d9'
const salt = Buffer.from('808182838485868788898a8b8c8d8e8f', 'hex').toString('utf8')
const expected = '795d83b18e55d860d3799f85a20f66ee17eb9dcf041df1d7a13fac30af7103d9'
const result = await webCrypto.pbkdf2(password, salt, 100000, 256)
expect(result).to.equal(expected)
})
@@ -116,19 +97,16 @@ describe('crypto operations', async function () {
it('hmac 256', async function () {
const text = 'hello world 🌍'
const key =
'e802dc953f3f1f7b5db62409b74ac848559d4711c4e0047ecc5e312ad8ab8397'
const key = 'e802dc953f3f1f7b5db62409b74ac848559d4711c4e0047ecc5e312ad8ab8397'
const hash = await webCrypto.hmac256(text, key)
const expected =
'b63f94ee33a067ffac3ee97c7987dd3171dcdc747a322bb3f3ab890201c8e6f9'
const expected = 'b63f94ee33a067ffac3ee97c7987dd3171dcdc747a322bb3f3ab890201c8e6f9'
expect(hash).to.equal(expected)
})
it('sha256', async function () {
const text = 'hello world 🌍'
const hash = await webCrypto.sha256(text)
const expected =
'1e71fe32476da1ff115b44dfd74aed5c90d68a1d80a2033065e30cff4335211a'
const expected = '1e71fe32476da1ff115b44dfd74aed5c90d68a1d80a2033065e30cff4335211a'
expect(hash).to.equal(expected)
})
@@ -154,13 +132,7 @@ describe('crypto operations', async function () {
const bytes = 67108864
const length = 16
const iterations = 2
const result = await webCrypto.argon2(
password,
salt,
iterations,
bytes,
length,
)
const result = await webCrypto.argon2(password, salt, iterations, bytes, length)
const expectedResult = '18dfbc268f251701652c8e38b5273f73'
expect(result).to.equal(expectedResult)
})
@@ -172,15 +144,8 @@ describe('crypto operations', async function () {
const bytes = 67108864
const length = 32
const iterations = 5
const result = await webCrypto.argon2(
password,
truncatedSalt,
iterations,
bytes,
length,
)
const expected =
'bb6ec440708c271ce34decd7f997e2444d309b1105992779ccdb47f78a5fda6f'
const result = await webCrypto.argon2(password, truncatedSalt, iterations, bytes, length)
const expected = 'bb6ec440708c271ce34decd7f997e2444d309b1105992779ccdb47f78a5fda6f'
expect(result).to.equal(expected)
})
@@ -189,69 +154,38 @@ describe('crypto operations', async function () {
const nonce = await webCrypto.generateRandomKey(192)
const plaintext = 'hello world 🌍'
const aad = JSON.stringify({ uuid: '123🎤' })
const ciphertext = await webCrypto.xchacha20Encrypt(
plaintext,
nonce,
key,
aad,
)
const decrypted = await webCrypto.xchacha20Decrypt(
ciphertext,
nonce,
key,
aad,
)
const ciphertext = await webCrypto.xchacha20Encrypt(plaintext, nonce, key, aad)
const decrypted = await webCrypto.xchacha20Decrypt(ciphertext, nonce, key, aad)
expect(decrypted).to.equal(plaintext)
})
it('xchacha20 streaming encrypt/decrypt', async function () {
const key = await webCrypto.generateRandomKey(256)
const bigFile = await fetch(
'http://localhost:9003/test/resources/big_file.md',
)
const bigFile = await fetch('http://localhost:9003/test/resources/big_file.md')
const bigText = await bigFile.text()
const plaintext = bigText
const plainBuffer = stringToArrayBuffer(plaintext)
const encryptor = webCrypto.xchacha20StreamEncryptInitEncryptor(key)
const header = base64StringToArrayBuffer(encryptor.header)
const encryptor = webCrypto.xchacha20StreamInitEncryptor(key)
let encryptedBuffer = Buffer.concat([header])
const headerBase64 = encryptor.header
const headerBuffer = base64ToArrayBuffer(encryptor.header)
let encryptedBuffer = Buffer.concat([headerBuffer])
const pushChunkSize = plainBuffer.length / 200
const pullChunkSize =
pushChunkSize +
SodiumConstant.CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES
const pullChunkSize = pushChunkSize + SodiumConstant.CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES
for (let i = 0; i < plainBuffer.length; i += pushChunkSize) {
const readUntil =
i + pushChunkSize > plainBuffer.length
? plainBuffer.length
: i + pushChunkSize
const chunk = webCrypto.xchacha20StreamEncryptorPush(
encryptor,
plainBuffer.slice(i, readUntil),
)
const readUntil = i + pushChunkSize > plainBuffer.length ? plainBuffer.length : i + pushChunkSize
const chunk = webCrypto.xchacha20StreamEncryptorPush(encryptor, plainBuffer.slice(i, readUntil))
encryptedBuffer = Buffer.concat([encryptedBuffer, chunk])
}
const decryptor = webCrypto.xchacha20StreamEncryptInitDecryptor(
header,
key,
)
const decryptor = webCrypto.xchacha20StreamInitDecryptor(headerBase64, key)
let decryptedBuffer = Buffer.alloc(0)
for (
let i = header.length;
i < encryptedBuffer.length;
i += pullChunkSize
) {
const readUntil =
i + pullChunkSize > encryptedBuffer.length
? encryptedBuffer.length
: i + pullChunkSize
const chunk = webCrypto.xchacha20StreamDecryptorPush(
decryptor,
encryptedBuffer.slice(i, readUntil),
)
for (let i = headerBuffer.length; i < encryptedBuffer.length; i += pullChunkSize) {
const readUntil = i + pullChunkSize > encryptedBuffer.length ? encryptedBuffer.length : i + pullChunkSize
const chunk = webCrypto.xchacha20StreamDecryptorPush(decryptor, encryptedBuffer.slice(i, readUntil))
decryptedBuffer = Buffer.concat([decryptedBuffer, chunk.message])
}
@@ -263,18 +197,8 @@ describe('crypto operations', async function () {
const key = await webCrypto.generateRandomKey(256)
const nonce = await webCrypto.generateRandomKey(192)
const plaintext = 'hello world 🌍'
const ciphertext = await webCrypto.xchacha20Encrypt(
plaintext,
nonce,
key,
JSON.stringify({ uuid: 'foo🎲' }),
)
const result = await webCrypto.xchacha20Decrypt(
ciphertext,
nonce,
key,
JSON.stringify({ uuid: 'bar🎲' }),
)
const ciphertext = await webCrypto.xchacha20Encrypt(plaintext, nonce, key, JSON.stringify({ uuid: 'foo🎲' }))
const result = await webCrypto.xchacha20Decrypt(ciphertext, nonce, key, JSON.stringify({ uuid: 'bar🎲' }))
expect(result).to.not.be.ok
})
@@ -284,23 +208,12 @@ describe('crypto operations', async function () {
"Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it.🌞"
const assocData = await hexStringToArrayBuffer('50515253c0c1c2c3c4c5c6c7')
const nonce = '404142434445464748494a4b4c4d4e4f5051525354555657'
const key =
'808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f'
const ciphertext = await webCrypto.xchacha20Encrypt(
plaintext,
nonce,
key,
assocData,
)
const key = '808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f'
const ciphertext = await webCrypto.xchacha20Encrypt(plaintext, nonce, key, assocData)
const expected =
'vW0XnT6D1DuVdleUk8DpOVcqFwAlK/rMvtKQLCE5bLtzHH8bC0qmRAvzqC9O2n45rmTGcIxUwhbLlrcuEhO0Ui+Mm6QNtdlFsRtpuYLBu54/P6wrw2lIj3ayODVl0//5IflmTJdjfal2iBL2FcaLE7UuOqw6kdl7HV6PKzn0pIOeHH3rkwQ='
expect(ciphertext).to.equal(expected)
const decrypted = await webCrypto.xchacha20Decrypt(
ciphertext,
nonce,
key,
assocData,
)
const decrypted = await webCrypto.xchacha20Decrypt(ciphertext, nonce, key, assocData)
expect(decrypted).to.equal(plaintext)
})
@@ -315,16 +228,10 @@ describe('crypto operations', async function () {
).toString('utf8')
const assocData = Buffer.from('50515253c0c1c2c3c4c5c6c7', 'hex')
const nonce = '404142434445464748494a4b4c4d4e4f5051525354555657'
const key =
'808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f'
const key = '808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f'
/** Encrypt */
const ciphertextBase64 = await webCrypto.xchacha20Encrypt(
plaintext,
nonce,
key,
assocData,
)
const ciphertextBase64 = await webCrypto.xchacha20Encrypt(plaintext, nonce, key, assocData)
const ciphertextHex = await base64ToHex(ciphertextBase64)
const expected =
'bd6d179d3e83d43b9576579493c0e939572a1700252bfaccbed2902c21396cbb' +
@@ -335,12 +242,7 @@ describe('crypto operations', async function () {
expect(ciphertextHex).to.equal(expected)
/** Decrypt */
const decrypted = await webCrypto.xchacha20Decrypt(
ciphertextBase64,
nonce,
key,
assocData,
)
const decrypted = await webCrypto.xchacha20Decrypt(ciphertextBase64, nonce, key, assocData)
expect(decrypted).to.equal(plaintext)
})
@@ -351,17 +253,44 @@ describe('crypto operations', async function () {
const bytes = 67108864
const length = 16
const iterations = 2
const result = await webCrypto.argon2(
password,
salt,
iterations,
bytes,
length,
)
const result = await webCrypto.argon2(password, salt, iterations, bytes, length)
const expectedResult = '720f95400220748a811bca9b8cff5d6e'
expect(result).to.equal(expectedResult)
})
it('pkc crypto_box_easy keypair generation', async function () {
const keypair = await webCrypto.sodiumCryptoBoxGenerateKeypair()
expect(keypair.keyType).to.equal('x25519')
expect(keypair.publicKey.length).to.equal(64)
expect(keypair.privateKey.length).to.equal(64)
})
it('pkc crypto_box_easy encrypt/decrypt', async function () {
const senderKeypair = await webCrypto.sodiumCryptoBoxGenerateKeypair()
const recipientKeypair = await webCrypto.sodiumCryptoBoxGenerateKeypair()
const nonce = await webCrypto.generateRandomKey(192)
const plaintext = 'hello world 🌍'
const ciphertext = await webCrypto.sodiumCryptoBoxEasyEncrypt(
plaintext,
nonce,
senderKeypair.privateKey,
recipientKeypair.publicKey,
)
expect(ciphertext.length).to.equal(44)
const decrypted = await webCrypto.sodiumCryptoBoxEasyDecrypt(
ciphertext,
nonce,
senderKeypair.publicKey,
recipientKeypair.privateKey,
)
expect(decrypted).to.equal(plaintext)
})
it('generates random OTP secret 160 bits long', async function () {
const secret = await webCrypto.generateOtpSecret()
expect(secret).to.have.length(32)
+1 -1
View File
@@ -6,7 +6,7 @@
<link rel="stylesheet" href="https://unpkg.com/mocha/mocha.css" />
<script src="https://unpkg.com/chai/chai.js"></script>
<script src="https://unpkg.com/mocha/mocha.js"></script>
<script src="../../../node_modules/regenerator-runtime/runtime.js"></script>
<script src="https://unpkg.com/regenerator-runtime@0.13.9/runtime.js"></script>
<script src="../dist/sncrypto-web.js"></script>
<script>
Object.assign(window, SNCrypto);
+1 -1
View File
@@ -42,7 +42,7 @@ describe('utils', async function () {
it('base64URLEncode', async function () {
const str = 'hello world'
const b64 = await base64Encode(str)
const b64 = await base64URLEncode(str)
expect(b64).to.equal('aGVsbG8gd29ybGQ')
})
+69
View File
@@ -3,6 +3,75 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.134.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-29)
**Note:** Version bump only for package @standardnotes/snjs
# [2.134.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-29)
### Features
* **snjs:** add e2e test for subsequent subscriptions settings persistance ([5ffffbf](https://github.com/standardnotes/app/commit/5ffffbff202ab037b22a72c64fe34673fe49ecaf))
## [2.133.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-29)
### Bug Fixes
* **snjs:** increase wait time in retrieving settings test for processing replaceable settings ([3322600](https://github.com/standardnotes/app/commit/33226000f58f5b7f97882479e62de3b24a6b217d))
* **snjs:** instructions on running e2e locally ([c841ac9](https://github.com/standardnotes/app/commit/c841ac99d2e51ecca05f4a349efa1a0acb09a86d))
## [2.133.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
**Note:** Version bump only for package @standardnotes/snjs
# [2.133.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
### Features
* handle android back button on android ([#1656](https://github.com/standardnotes/app/issues/1656)) ([981d8a7](https://github.com/standardnotes/app/commit/981d8a7497ea2600e1535ad9170cb5559550ca4d))
## [2.132.6](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-27)
**Note:** Version bump only for package @standardnotes/snjs
## [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
+7 -1
View File
@@ -44,8 +44,9 @@ To run a stable server environment for E2E tests that is up to date with product
```
yarn install --immutable
yarn test:stable-server
yarn start:local-server
```
Wait for the `All services are up!` message.
Once the server infrastructure is ready, and you've built all packages, you can run the test suite in the browser via:
@@ -53,6 +54,11 @@ Once the server infrastructure is ready, and you've built all packages, you can
yarn start:server:e2e
```
Once you are finished you can close the running local server on E2E repo by typing:
```
yarn stop:local-server
```
### Unit Tests
From the root of the repository, run:
+20 -5
View File
@@ -10,6 +10,10 @@ import {
UserRegistrationResponseBody,
UserServer,
UserServerInterface,
WebSocketApiService,
WebSocketApiServiceInterface,
WebSocketServer,
WebSocketServerInterface,
} from '@standardnotes/api'
import * as Common from '@standardnotes/common'
import * as ExternalServices from '@standardnotes/services'
@@ -108,6 +112,8 @@ export class SNApplication
private declare subscriptionApiService: SubscriptionApiServiceInterface
private declare subscriptionServer: SubscriptionServerInterface
private declare subscriptionManager: SubscriptionClientInterface
private declare webSocketApiService: WebSocketApiServiceInterface
private declare webSocketServer: WebSocketServerInterface
private sessionManager!: InternalServices.SNSessionManager
private syncService!: InternalServices.SNSyncService
private challengeService!: InternalServices.ChallengeService
@@ -329,7 +335,7 @@ export class SNApplication
this.apiService.loadHost()
this.webSocketsService.loadWebSocketUrl()
this.sessionManager.initializeFromDisk()
await this.sessionManager.initializeFromDisk()
this.settingsService.initializeFromDisk()
@@ -954,10 +960,6 @@ export class SNApplication
| undefined
}
async loadMobileUnlockTiming() {
return this.protectionService.loadMobileUnlockTiming()
}
getBiometricsTimingOptions() {
return this.protectionService.getBiometricsTimingOptions()
}
@@ -1094,6 +1096,8 @@ export class SNApplication
this.createUserApiService()
this.createSubscriptionServer()
this.createSubscriptionApiService()
this.createWebSocketServer()
this.createWebSocketApiService()
this.createSubscriptionManager()
this.createWebSocketsService()
this.createSessionManager()
@@ -1135,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
@@ -1252,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)
@@ -1337,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)
}
@@ -3,4 +3,5 @@ export enum ReactNativeToWebEvent {
ResumingFromBackground = 'ResumingFromBackground',
GainingFocus = 'GainingFocus',
LosingFocus = 'LosingFocus',
AndroidBackButtonPressed = 'AndroidBackButtonPressed',
}
@@ -1,4 +1,6 @@
import { InternalEventBusInterface } from '@standardnotes/services'
import { WebSocketApiServiceInterface } from '@standardnotes/api'
import { StorageKey, DiskStorageService } from '@Lib/index'
import { SNWebSocketsService } from './WebsocketsService'
@@ -6,10 +8,11 @@ describe('webSocketsService', () => {
const webSocketUrl = ''
let storageService: DiskStorageService
let webSocketApiService: WebSocketApiServiceInterface
let internalEventBus: InternalEventBusInterface
const createService = () => {
return new SNWebSocketsService(storageService, webSocketUrl, internalEventBus)
return new SNWebSocketsService(storageService, webSocketUrl, webSocketApiService, internalEventBus)
}
beforeEach(() => {
@@ -18,6 +21,9 @@ describe('webSocketsService', () => {
internalEventBus = {} as jest.Mocked<InternalEventBusInterface>
internalEventBus.publish = jest.fn()
webSocketApiService = {} as jest.Mocked<WebSocketApiServiceInterface>
webSocketApiService.createConnectionToken = jest.fn().mockReturnValue({ token: 'foobar' })
})
describe('setWebSocketUrl()', () => {
@@ -1,6 +1,8 @@
import { UserRolesChangedEvent } from '@standardnotes/domain-events'
import { DiskStorageService } from '../Storage/DiskStorageService'
import { AbstractService, InternalEventBusInterface, StorageKey } from '@standardnotes/services'
import { WebSocketApiServiceInterface } from '@standardnotes/api'
import { DiskStorageService } from '../Storage/DiskStorageService'
export enum WebSocketsServiceEvent {
UserRoleMessageReceived = 'WebSocketMessageReceived',
@@ -12,6 +14,7 @@ export class SNWebSocketsService extends AbstractService<WebSocketsServiceEvent,
constructor(
private storageService: DiskStorageService,
private webSocketUrl: string | undefined,
private webSocketApiService: WebSocketApiServiceInterface,
protected override internalEventBus: InternalEventBusInterface,
) {
super(internalEventBus)
@@ -34,10 +37,15 @@ export class SNWebSocketsService extends AbstractService<WebSocketsServiceEvent,
)._websocket_url
}
public startWebSocketConnection(authToken: string): void {
async startWebSocketConnection(): Promise<void> {
const webSocketConectionToken = await this.createWebSocketConnectionToken()
if (webSocketConectionToken === undefined) {
return
}
if (this.webSocketUrl) {
try {
this.webSocket = new WebSocket(`${this.webSocketUrl}?authToken=Bearer+${authToken}`)
this.webSocket = new WebSocket(`${this.webSocketUrl}?authToken=${webSocketConectionToken}`)
this.webSocket.onmessage = this.onWebSocketMessage.bind(this)
this.webSocket.onclose = this.onWebSocketClose.bind(this)
} catch (e) {
@@ -59,9 +67,22 @@ export class SNWebSocketsService extends AbstractService<WebSocketsServiceEvent,
this.webSocket = undefined
}
private async createWebSocketConnectionToken(): Promise<string | undefined> {
try {
const response = await this.webSocketApiService.createConnectionToken()
return response.data.token
} catch (error) {
console.error((error as Error).message)
return undefined
}
}
override deinit(): void {
super.deinit()
;(this.storageService as unknown) = undefined
;(this.webSocketApiService as unknown) = undefined
this.closeWebSocketConnection()
}
}
@@ -87,6 +87,8 @@ export class SNProtectionService extends AbstractService<ProtectionEvent> implem
override handleApplicationStage(stage: ApplicationStage): Promise<void> {
if (stage === ApplicationStage.LoadedDatabase_12) {
this.updateSessionExpiryTimer(this.getSessionExpiryDate())
this.mobilePasscodeTiming = this.getPasscodeTiming()
this.mobileBiometricsTiming = this.getBiometricsTiming()
}
return Promise.resolve()
}
@@ -284,11 +286,6 @@ export class SNProtectionService extends AbstractService<ProtectionEvent> implem
return this.storageService.getValue(StorageKey.MobileScreenshotPrivacyEnabled, StorageValueModes.Default, false)
}
loadMobileUnlockTiming(): void {
this.mobilePasscodeTiming = this.getPasscodeTiming()
this.mobileBiometricsTiming = this.getBiometricsTiming()
}
private async validateOrRenewSession(
reason: ChallengeReason,
{ fallBackToAccountPassword = true, requireAccountPassword = false } = {},
@@ -107,7 +107,7 @@ export class SNSessionManager extends AbstractService<SessionEvent> implements S
this.apiService.setUser(user)
}
public initializeFromDisk() {
async initializeFromDisk() {
this.setUser(this.diskStorageService.getValue(StorageKey.User))
if (!this.user) {
@@ -121,7 +121,7 @@ export class SNSessionManager extends AbstractService<SessionEvent> implements S
if (rawSession) {
const session = SessionFromRawStorageValue(rawSession)
this.setSession(session, false)
this.webSocketsService.startWebSocketConnection(session.authorizationValue)
await this.webSocketsService.startWebSocketConnection()
}
}
@@ -286,7 +286,7 @@ export class SNSessionManager extends AbstractService<SessionEvent> implements S
const serverPassword = rootKey.serverPassword as string
const keyParams = rootKey.keyParams
const registerResponse = await this.userApiService.register(email, serverPassword, keyParams, ephemeral)
const registerResponse = await this.userApiService.register({ email, serverPassword, keyParams, ephemeral })
if ('error' in registerResponse.data) {
throw new ApiCallError((registerResponse.data as HttpErrorResponseBody).error.message)
@@ -623,9 +623,9 @@ export class SNSessionManager extends AbstractService<SessionEvent> implements S
this.httpService.setHost(host)
await this.setSession(session)
this.setSession(session)
this.webSocketsService.startWebSocketConnection(session.authorizationValue)
await this.webSocketsService.startWebSocketConnection()
}
private async handleAuthResponse(body: UserRegistrationResponseBody, rootKey: SNRootKey, wrappingKey?: SNRootKey) {
@@ -11,6 +11,7 @@ import {
ListedAuthorSecretsData,
LogSessionUserAgentOption,
SettingName,
MuteMarketingEmailsOption,
} from '@standardnotes/settings'
type SettingType =
@@ -23,6 +24,7 @@ type SettingType =
| MuteFailedBackupsEmailsOption
| MuteFailedCloudBackupsEmailsOption
| MuteSignInEmailsOption
| MuteMarketingEmailsOption
| OneDriveBackupFrequency
export class SettingsList {
+7 -37
View File
@@ -1,5 +1,7 @@
import * as Factory from './lib/factory.js'
import * as Utils from './lib/Utils.js'
import * as Files from './lib/Files.js'
chai.use(chaiAsPromised)
const expect = chai.expect
@@ -52,38 +54,6 @@ describe('files', function () {
localStorage.clear()
})
const uploadFile = async (fileService, buffer, name, ext, chunkSize) => {
const operation = await fileService.beginNewFileUpload(buffer.byteLength)
let chunkId = 1
for (let i = 0; i < buffer.length; i += chunkSize) {
const readUntil = i + chunkSize > buffer.length ? buffer.length : i + chunkSize
const chunk = buffer.slice(i, readUntil)
const isFinalChunk = readUntil === buffer.length
const error = await fileService.pushBytesForUpload(operation, chunk, chunkId++, isFinalChunk)
if (error) {
throw new Error('Could not upload file chunk')
}
}
const file = await fileService.finishUpload(operation, name, ext)
return file
}
const downloadFile = async (fileService, itemManager, remoteIdentifier) => {
const file = itemManager.getItems(ContentType.File).find((file) => file.remoteIdentifier === remoteIdentifier)
let receivedBytes = new Uint8Array()
await fileService.downloadFile(file, (decryptedBytes) => {
receivedBytes = new Uint8Array([...receivedBytes, ...decryptedBytes])
})
return receivedBytes
}
it('should create valet token from server', async function () {
await setup({ fakeCrypto: true, subscription: true })
const remoteIdentifier = Utils.generateUuid()
@@ -141,9 +111,9 @@ describe('files', function () {
const response = await fetch('/packages/snjs/mocha/assets/small_file.md')
const buffer = new Uint8Array(await response.arrayBuffer())
const file = await uploadFile(fileService, buffer, 'my-file', 'md', 1000)
const file = await Files.uploadFile(fileService, buffer, 'my-file', 'md', 1000)
const downloadedBytes = await downloadFile(fileService, itemManager, file.remoteIdentifier)
const downloadedBytes = await Files.downloadFile(fileService, itemManager, file.remoteIdentifier)
expect(downloadedBytes).to.eql(buffer)
})
@@ -154,9 +124,9 @@ describe('files', function () {
const response = await fetch('/packages/snjs/mocha/assets/two_mb_file.md')
const buffer = new Uint8Array(await response.arrayBuffer())
const file = await uploadFile(fileService, buffer, 'my-file', 'md', 100000)
const file = await Files.uploadFile(fileService, buffer, 'my-file', 'md', 100000)
const downloadedBytes = await downloadFile(fileService, itemManager, file.remoteIdentifier)
const downloadedBytes = await Files.downloadFile(fileService, itemManager, file.remoteIdentifier)
expect(downloadedBytes).to.eql(buffer)
})
@@ -167,7 +137,7 @@ describe('files', function () {
const response = await fetch('/packages/snjs/mocha/assets/small_file.md')
const buffer = new Uint8Array(await response.arrayBuffer())
const file = await uploadFile(fileService, buffer, 'my-file', 'md', 1000)
const file = await Files.uploadFile(fileService, buffer, 'my-file', 'md', 1000)
const error = await fileService.deleteFile(file)
+31
View File
@@ -0,0 +1,31 @@
export async function uploadFile(fileService, buffer, name, ext, chunkSize) {
const operation = await fileService.beginNewFileUpload(buffer.byteLength)
let chunkId = 1
for (let i = 0; i < buffer.length; i += chunkSize) {
const readUntil = i + chunkSize > buffer.length ? buffer.length : i + chunkSize
const chunk = buffer.slice(i, readUntil)
const isFinalChunk = readUntil === buffer.length
const error = await fileService.pushBytesForUpload(operation, chunk, chunkId++, isFinalChunk)
if (error) {
throw new Error('Could not upload file chunk')
}
}
const file = await fileService.finishUpload(operation, name, ext)
return file
}
export async function downloadFile(fileService, itemManager, remoteIdentifier) {
const file = itemManager.getItems(ContentType.File).find((file) => file.remoteIdentifier === remoteIdentifier)
let receivedBytes = new Uint8Array()
await fileService.downloadFile(file, (decryptedBytes) => {
receivedBytes = new Uint8Array([...receivedBytes, ...decryptedBytes])
})
return receivedBytes
}
+5 -1
View File
@@ -144,7 +144,11 @@ export async function registerOldUser({ application, email, password, version })
const operator = application.protocolService.operatorManager.operatorForVersion(version)
const accountKey = await operator.createRootKey(email, password, KeyParamsOrigination.Registration)
const response = await application.userApiService.register(email, accountKey.serverPassword, accountKey.keyParams)
const response = await application.userApiService.register({
email: email,
serverPassword: accountKey.serverPassword,
keyParams: accountKey.keyParams,
})
/** Mark all existing items as dirty. */
await application.itemManager.changeItems(application.itemManager.items, (m) => {
m.dirty = true
+84 -2
View File
@@ -1,14 +1,19 @@
import * as Factory from './lib/factory.js'
import * as Files from './lib/Files.js'
chai.use(chaiAsPromised)
const expect = chai.expect
describe('settings service', function () {
this.timeout(Factory.TwentySecondTimeout)
const validSetting = SettingName.GoogleDriveBackupFrequency
const fakePayload = 'Im so meta even this acronym'
const updatedFakePayload = 'is meta'
let application
let context
let user
beforeEach(async function () {
context = await Factory.createAppContextWithFakeCrypto()
@@ -17,13 +22,31 @@ describe('settings service', function () {
application = context.application
await Factory.registerUserToApplication({
const registerResponse = await Factory.registerUserToApplication({
application: context.application,
email: context.email,
password: context.password,
})
user = registerResponse.user
})
const reInitializeApplicationWithRealCrypto = async () => {
await Factory.safeDeinit(application)
context = await Factory.createAppContextWithRealCrypto()
await context.launch()
application = context.application
const registerResponse = await Factory.registerUserToApplication({
application: context.application,
email: context.email,
password: context.password,
})
user = registerResponse.user
}
afterEach(async function () {
await Factory.safeDeinit(application)
})
@@ -103,9 +126,68 @@ describe('settings service', function () {
offline: false,
})
await Factory.sleep(0.5)
await Factory.sleep(1)
const setting = await application.settings.getSubscriptionSetting('FILE_UPLOAD_BYTES_LIMIT')
expect(setting).to.be.a('string')
})
it('persist irreplaceable subscription settings between subsequent subscriptions', async () => {
await reInitializeApplicationWithRealCrypto()
await Factory.publishMockedEvent('SUBSCRIPTION_PURCHASED', {
userEmail: context.email,
subscriptionId: 1,
subscriptionName: 'PRO_PLAN',
subscriptionExpiresAt: (new Date().getTime() + 3_600_000) * 1_000,
timestamp: Date.now(),
offline: false,
})
await Factory.sleep(1)
const response = await fetch('/packages/snjs/mocha/assets/small_file.md')
const buffer = new Uint8Array(await response.arrayBuffer())
await Files.uploadFile(application.fileService, buffer, 'my-file', 'md', 1000)
await Factory.publishMockedEvent('FILE_UPLOADED', {
userUuid: user.uuid,
fileByteSize: 123,
filePath: 'foobar',
fileName: 'barbuzz',
})
await Factory.sleep(1)
const limitSettingBefore = await application.settings.getSubscriptionSetting('FILE_UPLOAD_BYTES_LIMIT')
expect(limitSettingBefore).to.equal('107374182400')
const usedSettingBefore = await application.settings.getSubscriptionSetting('FILE_UPLOAD_BYTES_USED')
expect(usedSettingBefore).to.equal('123')
await Factory.publishMockedEvent('SUBSCRIPTION_EXPIRED', {
userEmail: context.email,
subscriptionId: 1,
subscriptionName: 'PRO_PLAN',
timestamp: Date.now(),
offline: false,
})
await Factory.sleep(1)
await Factory.publishMockedEvent('SUBSCRIPTION_PURCHASED', {
userEmail: context.email,
subscriptionId: 2,
subscriptionName: 'PRO_PLAN',
subscriptionExpiresAt: (new Date().getTime() + 3_600_000) * 1_000,
timestamp: Date.now(),
offline: false,
})
await Factory.sleep(1)
const limitSettingAfter = await application.settings.getSubscriptionSetting('FILE_UPLOAD_BYTES_LIMIT')
expect(limitSettingAfter).to.equal(limitSettingBefore)
const usedSettingAfter = await application.settings.getSubscriptionSetting('FILE_UPLOAD_BYTES_USED')
expect(usedSettingAfter).to.equal(usedSettingBefore)
})
})
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/snjs",
"version": "2.130.2",
"version": "2.134.1",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
+40
View File
@@ -3,6 +3,46 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.3.7](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-29)
**Note:** Version bump only for package @standardnotes/ui-services
## [1.3.6](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
**Note:** Version bump only for package @standardnotes/ui-services
## [1.3.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
**Note:** Version bump only for package @standardnotes/ui-services
## [1.3.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-27)
### Bug Fixes
* **web:** incorrect native access ([b9a07d8](https://github.com/standardnotes/app/commit/b9a07d8b5abb9ae6e7fb00b0edc1fa87a2b209e0))
## [1.3.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-27)
### Bug Fixes
* export/sharing notes on mobile webview ([#1644](https://github.com/standardnotes/app/issues/1644)) ([6d5ebde](https://github.com/standardnotes/app/commit/6d5ebdeaa1777f31878b6e7d4dfc33fe83abc9fc))
## [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
+3 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/ui-services",
"version": "1.2.7",
"version": "1.3.7",
"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": "*"
}
}
@@ -8,7 +8,7 @@ import {
import { ContentType } from '@standardnotes/common'
import { ApplicationInterface } from '@standardnotes/services'
function sanitizeFileName(name: string): string {
export function sanitizeFileName(name: string): string {
return name.trim().replace(/[.\\/:"?*|<>]/g, '_')
}
@@ -52,13 +52,16 @@ export class ArchiveManager {
})
if (encrypted) {
this.downloadData(blobData, `Standard Notes Encrypted Backup and Import File - ${this.formattedDate()}.txt`)
this.downloadData(
blobData,
`Standard Notes Encrypted Backup and Import File - ${this.formattedDateForExports()}.txt`,
)
} else {
this.downloadZippedDecryptedItems(data).catch(console.error)
}
}
private formattedDate() {
formattedDateForExports() {
const string = `${new Date()}`
// Match up to the first parenthesis, i.e do not include '(Central Standard Time)'
const matches = string.match(/^(.*?) \(/)
@@ -108,7 +111,7 @@ export class ArchiveManager {
await nextFile()
} else {
const finalBlob = await zipWriter.close()
this.downloadData(finalBlob, `Standard Notes Backup - ${this.formattedDate()}.zip`)
this.downloadData(finalBlob, `Standard Notes Backup - ${this.formattedDateForExports()}.zip`)
}
}
@@ -143,7 +146,7 @@ export class ArchiveManager {
async downloadDataAsZip(data: ZippableData) {
const zipFileAsBlob = await this.zipData(data)
this.downloadData(zipFileAsBlob, `Standard Notes Export - ${this.formattedDate()}.zip`)
this.downloadData(zipFileAsBlob, `Standard Notes Export - ${this.formattedDateForExports()}.zip`)
}
private hrefForData(data: Blob) {
+29 -1
View File
@@ -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.isNativeMobileWeb()) {
this.application.mobileDevice.handleThemeSchemeChange(false)
}
}
private async cacheThemeState() {
+233
View File
@@ -3,6 +3,239 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [3.64.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-29)
### Features
* add custom note title format pref ([#1678](https://github.com/standardnotes/app/issues/1678)) ([11dd39c](https://github.com/standardnotes/app/commit/11dd39c126019c4295c03fb59b05ea5aa3adcd27))
## [3.63.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-29)
**Note:** Version bump only for package @standardnotes/web
## [3.63.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-29)
**Note:** Version bump only for package @standardnotes/web
## [3.63.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-29)
### Bug Fixes
* ipad web view ui improvements ([#1664](https://github.com/standardnotes/app/issues/1664)) ([20e4208](https://github.com/standardnotes/app/commit/20e420820d45e2556f60604de41a1bee96c98fe1))
# [3.63.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-29)
### Features
* add panel settings section in quick settings ([#1669](https://github.com/standardnotes/app/issues/1669)) ([0ed692f](https://github.com/standardnotes/app/commit/0ed692ff9b056d00dde73040482e6b1bdc404d04))
## [3.62.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
### Bug Fixes
* improve biometrics input on mobile webview ([#1658](https://github.com/standardnotes/app/issues/1658)) ([3f9d3ce](https://github.com/standardnotes/app/commit/3f9d3ceffac206645ff9e5b66e68bf2e7b9cd0e2))
## [3.62.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
### Bug Fixes
* grey flash on textarea focus on safari/webkit ([#1661](https://github.com/standardnotes/app/issues/1661)) ([eafa65e](https://github.com/standardnotes/app/commit/eafa65e93487e60a4b9ee37f8cc9932bbbd8917c))
## [3.62.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
### Bug Fixes
* sticky header behavior on iOS ([#1662](https://github.com/standardnotes/app/issues/1662)) ([c0af596](https://github.com/standardnotes/app/commit/c0af596f2d69654b50dffc36250137998dc629fb))
## [3.62.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
### Bug Fixes
* challenge modal ([9502a7f](https://github.com/standardnotes/app/commit/9502a7fa32f2cca26b6964788a44acc9778bf721))
* webapp blanking because of mobileDevice check ([727d78c](https://github.com/standardnotes/app/commit/727d78cfe23c268dcd97566f355584a23c8b9d45))
# [3.62.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
### Features
* handle android back button on android ([#1656](https://github.com/standardnotes/app/issues/1656)) ([981d8a7](https://github.com/standardnotes/app/commit/981d8a7497ea2600e1535ad9170cb5559550ca4d))
# [3.61.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-27)
### Features
* delete account ([#1653](https://github.com/standardnotes/app/issues/1653)) ([5db47e8](https://github.com/standardnotes/app/commit/5db47e83e82993bb9d210cb264d05f59ea1db5f3))
# [3.60.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-27)
### Features
* upgrade cta ([#1655](https://github.com/standardnotes/app/issues/1655)) ([ec52e56](https://github.com/standardnotes/app/commit/ec52e5684da2c7caaa24929275727cdbc23c28e1))
## [3.59.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-27)
**Note:** Version bump only for package @standardnotes/web
## [3.59.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-27)
### Bug Fixes
* don't hide note tags container on desktop ([70e57e3](https://github.com/standardnotes/app/commit/70e57e32b3bd6e3943d6fc1af2ae0ad9618e1812))
## [3.59.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-27)
### Bug Fixes
* export/sharing notes on mobile webview ([#1644](https://github.com/standardnotes/app/issues/1644)) ([6d5ebde](https://github.com/standardnotes/app/commit/6d5ebdeaa1777f31878b6e7d4dfc33fe83abc9fc))
# [3.59.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-26)
### Features
* sticky header on mobile if plaintext note is scrolled ([#1645](https://github.com/standardnotes/app/issues/1645)) ([f8f6a52](https://github.com/standardnotes/app/commit/f8f6a5212b608c7a43957449d42b1d462134773c))
## [3.58.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-26)
### Bug Fixes
* **web:** check for proper feature in the subscription sharing section ([507823d](https://github.com/standardnotes/app/commit/507823dc4f1a2c1db47635ac26a686d4d8f2f4e8))
# [3.58.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-25)
### Features
* note tags button for mobile ([#1641](https://github.com/standardnotes/app/issues/1641)) ([fe2ce9f](https://github.com/standardnotes/app/commit/fe2ce9f1e8b0c027c30bcd892606e914f71d4634))
## [3.57.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-24)
### Bug Fixes
* improve new note title format ([#1640](https://github.com/standardnotes/app/issues/1640)) ([59e814b](https://github.com/standardnotes/app/commit/59e814bcec8c3633b1b2baeae3e435fa2a19777d))
## [3.57.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-24)
### Bug Fixes
* move prefs button next to account menu button in footer ([#1639](https://github.com/standardnotes/app/issues/1639)) ([a3611c8](https://github.com/standardnotes/app/commit/a3611c802f08817d2ba73adf6b9d48465738b1b6))
## [3.57.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-24)
### Bug Fixes
* responsiveness when resizing window on web/desktop ([#1637](https://github.com/standardnotes/app/issues/1637)) ([e4b1b64](https://github.com/standardnotes/app/commit/e4b1b641194cede65b8f0413bb1c805a84585dfe))
# [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
+2 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/web",
"version": "3.50.4",
"version": "3.64.0",
"license": "AGPL-3.0-or-later",
"main": "dist/app.js",
"author": "Standard Notes.",
@@ -85,6 +85,7 @@
"@standardnotes/toast": "workspace:*",
"@standardnotes/ui-services": "workspace:^",
"@zip.js/zip.js": "^2.6.26",
"dayjs": "^1.11.5",
"mobx": "^6.6.2",
"mobx-react-lite": "^3.4.0",
"qrcode.react": "^3.1.0",
+1 -1
View File
@@ -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" />
+10 -4
View File
@@ -41,6 +41,13 @@ const getKey = () => {
return keyCount++
}
const setViewportHeight = () => {
document.documentElement.style.setProperty(
'--viewport-height',
`${visualViewport ? visualViewport.height : window.innerHeight}px`,
)
}
const startApplication: StartApplication = async function startApplication(
defaultSyncServerHost: string,
device: WebOrDesktopDevice,
@@ -53,6 +60,7 @@ const startApplication: StartApplication = async function startApplication(
let root: Root
const onDestroy = () => {
window.removeEventListener('orientationchange', setViewportHeight)
const rootElement = document.getElementById(ElementIds.RootId) as HTMLElement
root.unmount()
rootElement.remove()
@@ -66,10 +74,8 @@ const startApplication: StartApplication = async function startApplication(
root = createRoot(appendedRootNode)
disableIosTextFieldZoom()
document.documentElement.style.setProperty(
'--viewport-height',
`${visualViewport ? visualViewport.height : window.innerHeight}px`,
)
setViewportHeight()
window.addEventListener('orientationchange', setViewportHeight)
root.render(
<ApplicationGroupView
@@ -26,6 +26,8 @@ import { isDesktopApplication } from '@/Utils'
import { DesktopManager } from './Device/DesktopManager'
import { ArchiveManager, AutolockService, IOService, WebAlertService, ThemeManager } from '@standardnotes/ui-services'
import { MobileWebReceiver } from './MobileWebReceiver'
import { AndroidBackHandler } from '@/NativeMobileWeb/AndroidBackHandler'
import { PrefDefaults } from '@/Constants/PrefDefaults'
type WebServices = {
viewControllerManager: ViewControllerManager
@@ -45,6 +47,7 @@ export class WebApplication extends SNApplication implements WebApplicationInter
public iconsController: IconsController
private onVisibilityChange: () => void
private mobileWebReceiver?: MobileWebReceiver
private androidBackHandler?: AndroidBackHandler
constructor(
deviceInterface: WebOrDesktopDevice,
@@ -76,6 +79,7 @@ export class WebApplication extends SNApplication implements WebApplicationInter
if (this.isNativeMobileWeb()) {
this.mobileWebReceiver = new MobileWebReceiver(this)
this.androidBackHandler = new AndroidBackHandler()
// eslint-disable-next-line no-console
console.log = (...args) => {
@@ -207,7 +211,7 @@ export class WebApplication extends SNApplication implements WebApplicationInter
}
isGlobalSpellcheckEnabled(): boolean {
return this.getPreference(PrefKey.EditorSpellcheck, true)
return this.getPreference(PrefKey.EditorSpellcheck, PrefDefaults[PrefKey.EditorSpellcheck])
}
public getItemTags(item: DecryptedItemInterface) {
@@ -264,4 +268,17 @@ export class WebApplication extends SNApplication implements WebApplicationInter
await this.lock()
}
}
handleAndroidBackButtonPressed(): void {
if (typeof this.androidBackHandler !== 'undefined') {
this.androidBackHandler.notifyEvent()
}
}
addAndroidBackHandlerEventListener(listener: () => boolean) {
if (typeof this.androidBackHandler !== 'undefined') {
return this.androidBackHandler.addEventListener(listener)
}
return
}
}
@@ -20,7 +20,7 @@ const createApplication = (
device: WebOrDesktopDevice,
webSocketUrl: string,
) => {
const platform = getPlatform()
const platform = getPlatform(device)
const application = new WebApplication(
deviceInterface,
@@ -53,6 +53,9 @@ export class MobileWebReceiver {
case ReactNativeToWebEvent.ResumingFromBackground:
void this.application.handleMobileResumingFromBackgroundEvent()
break
case ReactNativeToWebEvent.AndroidBackButtonPressed:
void this.application.handleAndroidBackButtonPressed()
break
default:
break
@@ -45,9 +45,7 @@ const WorkspaceSwitcherMenu: FunctionComponent<Props> = ({
const signoutAll = useCallback(async () => {
const confirmed = await viewControllerManager.application.alertService.confirm(
`Are you sure you want to sign out of all workspaces on this device?${
viewControllerManager.application.isNativeMobileWeb() && '<b> Your app will quit after sign out completes.</b>'
}`,
'Are you sure you want to sign out of all workspaces on this device?',
undefined,
'Sign out all',
ButtonType.Danger,
@@ -64,44 +62,14 @@ const WorkspaceSwitcherMenu: FunctionComponent<Props> = ({
const activateWorkspace = useCallback(
async (descriptor: ApplicationDescriptor) => {
if (viewControllerManager.application.isNativeMobileWeb()) {
const confirmed = await viewControllerManager.application.alertService.confirm(
'<b>The app needs to be restarted to activate the workspace</b>',
undefined,
'Quit app and activate workspace',
ButtonType.Danger,
)
if (confirmed) {
void mainApplicationGroup.unloadCurrentAndActivateDescriptor(descriptor)
}
return
}
void mainApplicationGroup.unloadCurrentAndActivateDescriptor(descriptor)
},
[mainApplicationGroup, viewControllerManager.application],
[mainApplicationGroup],
)
const addAnotherWorkspace = useCallback(async () => {
if (viewControllerManager.application.isNativeMobileWeb()) {
const confirmed = await viewControllerManager.application.alertService.confirm(
'<b>The app needs to be restarted to add another workspace</b>',
undefined,
'Quit app and add new workspace',
ButtonType.Danger,
)
if (confirmed) {
void mainApplicationGroup.unloadCurrentAndCreateNewDescriptor()
}
return
}
void mainApplicationGroup.unloadCurrentAndCreateNewDescriptor()
}, [mainApplicationGroup, viewControllerManager.application])
}, [mainApplicationGroup])
return (
<Menu a11yLabel="Workspace switcher menu" className="px-0 focus:shadow-none" isOpen={isOpen}>
@@ -12,7 +12,7 @@ import PreferencesViewWrapper from '@/Components/Preferences/PreferencesViewWrap
import ChallengeModal from '@/Components/ChallengeModal/ChallengeModal'
import NotesContextMenu from '@/Components/NotesContextMenu/NotesContextMenu'
import PurchaseFlowWrapper from '@/Components/PurchaseFlow/PurchaseFlowWrapper'
import { FunctionComponent, useCallback, useEffect, useMemo, useState } from 'react'
import { FunctionComponent, useCallback, useEffect, useMemo, useRef, useState } from 'react'
import RevisionHistoryModal from '@/Components/RevisionHistoryModal/RevisionHistoryModal'
import PremiumModalProvider from '@/Hooks/usePremiumModal'
import ConfirmSignoutContainer from '@/Components/ConfirmSignoutModal/ConfirmSignoutModal'
@@ -25,6 +25,8 @@ import { PanelResizedData } from '@/Types/PanelResizedData'
import TagContextMenuWrapper from '@/Components/Tags/TagContextMenuWrapper'
import FileDragNDropProvider from '../FileDragNDropProvider/FileDragNDropProvider'
import ResponsivePaneProvider from '../ResponsivePane/ResponsivePaneProvider'
import AndroidBackHandlerProvider from '@/NativeMobileWeb/useAndroidBackHandler'
import ConfirmDeleteAccountContainer from '@/Components/ConfirmDeleteAccountModal/ConfirmDeleteAccountModal'
type Props = {
application: WebApplication
@@ -33,13 +35,14 @@ type Props = {
const ApplicationView: FunctionComponent<Props> = ({ application, mainApplicationGroup }) => {
const platformString = getPlatformString()
const [appClass, setAppClass] = useState('')
const [launched, setLaunched] = useState(false)
const [needsUnlock, setNeedsUnlock] = useState(true)
const [challenges, setChallenges] = useState<Challenge[]>([])
const viewControllerManager = application.getViewControllerManager()
const appColumnContainerRef = useRef<HTMLDivElement>(null)
useEffect(() => {
const desktopService = application.getDesktopService()
@@ -123,15 +126,27 @@ const ApplicationView: FunctionComponent<Props> = ({ application, mainApplicatio
useEffect(() => {
const removeObserver = application.addWebEventObserver(async (eventName, data) => {
if (eventName === WebAppEvent.PanelResized) {
if (!appColumnContainerRef.current) {
return
}
const { panel, collapsed } = data as PanelResizedData
let appClass = ''
if (panel === PANEL_NAME_NOTES && collapsed) {
appClass += 'collapsed-notes'
if (panel === PANEL_NAME_NOTES) {
if (collapsed) {
appColumnContainerRef.current.classList.add('collapsed-notes')
} else {
appColumnContainerRef.current.classList.remove('collapsed-notes')
}
}
if (panel === PANEL_NAME_NAVIGATION && collapsed) {
appClass += ' collapsed-navigation'
if (panel === PANEL_NAME_NAVIGATION) {
if (collapsed) {
appColumnContainerRef.current.classList.add('collapsed-navigation')
} else {
appColumnContainerRef.current.classList.remove('collapsed-navigation')
}
}
setAppClass(appClass)
} else if (eventName === WebAppEvent.WindowDidFocus) {
if (!(await application.isLocked())) {
application.sync.sync().catch(console.error)
@@ -150,7 +165,7 @@ const ApplicationView: FunctionComponent<Props> = ({ application, mainApplicatio
const renderChallenges = useCallback(() => {
return (
<>
<AndroidBackHandlerProvider application={application}>
{challenges.map((challenge) => {
return (
<div className="sk-modal" key={`${challenge.id}${application.ephemeralIdentifier}`}>
@@ -165,7 +180,7 @@ const ApplicationView: FunctionComponent<Props> = ({ application, mainApplicatio
</div>
)
})}
</>
</AndroidBackHandlerProvider>
)
}, [viewControllerManager, challenges, mainApplicationGroup, removeChallenge, application])
@@ -174,76 +189,79 @@ const ApplicationView: FunctionComponent<Props> = ({ application, mainApplicatio
}
return (
<PremiumModalProvider application={application} viewControllerManager={viewControllerManager}>
<AndroidBackHandlerProvider application={application}>
<ResponsivePaneProvider>
<div className={platformString + ' main-ui-view sn-component'}>
<div id="app" className={appClass + ' app app-column-container'}>
<FileDragNDropProvider
application={application}
featuresController={viewControllerManager.featuresController}
filesController={viewControllerManager.filesController}
>
<Navigation application={application} />
<ContentListView
<PremiumModalProvider application={application} viewControllerManager={viewControllerManager}>
<div className={platformString + ' main-ui-view sn-component'}>
<div id="app" className="app app-column-container" ref={appColumnContainerRef}>
<FileDragNDropProvider
application={application}
accountMenuController={viewControllerManager.accountMenuController}
featuresController={viewControllerManager.featuresController}
filesController={viewControllerManager.filesController}
itemListController={viewControllerManager.itemListController}
navigationController={viewControllerManager.navigationController}
noAccountWarningController={viewControllerManager.noAccountWarningController}
noteTagsController={viewControllerManager.noteTagsController}
>
<Navigation application={application} />
<ContentListView
application={application}
accountMenuController={viewControllerManager.accountMenuController}
filesController={viewControllerManager.filesController}
itemListController={viewControllerManager.itemListController}
navigationController={viewControllerManager.navigationController}
noAccountWarningController={viewControllerManager.noAccountWarningController}
noteTagsController={viewControllerManager.noteTagsController}
notesController={viewControllerManager.notesController}
selectionController={viewControllerManager.selectionController}
searchOptionsController={viewControllerManager.searchOptionsController}
/>
<NoteGroupView application={application} />
</FileDragNDropProvider>
</div>
<>
<Footer application={application} applicationGroup={mainApplicationGroup} />
<SessionsModal application={application} viewControllerManager={viewControllerManager} />
<PreferencesViewWrapper viewControllerManager={viewControllerManager} application={application} />
<RevisionHistoryModal
application={application}
historyModalController={viewControllerManager.historyModalController}
notesController={viewControllerManager.notesController}
selectionController={viewControllerManager.selectionController}
searchOptionsController={viewControllerManager.searchOptionsController}
subscriptionController={viewControllerManager.subscriptionController}
/>
<NoteGroupView application={application} />
</FileDragNDropProvider>
</>
{renderChallenges()}
<>
<NotesContextMenu
application={application}
navigationController={viewControllerManager.navigationController}
notesController={viewControllerManager.notesController}
noteTagsController={viewControllerManager.noteTagsController}
historyModalController={viewControllerManager.historyModalController}
/>
<TagContextMenuWrapper
navigationController={viewControllerManager.navigationController}
featuresController={viewControllerManager.featuresController}
/>
<FileContextMenuWrapper
filesController={viewControllerManager.filesController}
selectionController={viewControllerManager.selectionController}
/>
<PurchaseFlowWrapper application={application} viewControllerManager={viewControllerManager} />
<ConfirmSignoutContainer
applicationGroup={mainApplicationGroup}
viewControllerManager={viewControllerManager}
application={application}
/>
<ToastContainer />
<FilePreviewModalWrapper application={application} viewControllerManager={viewControllerManager} />
<PermissionsModalWrapper application={application} />
<ConfirmDeleteAccountContainer application={application} viewControllerManager={viewControllerManager} />
</>
</div>
<>
<Footer application={application} applicationGroup={mainApplicationGroup} />
<SessionsModal application={application} viewControllerManager={viewControllerManager} />
<PreferencesViewWrapper viewControllerManager={viewControllerManager} application={application} />
<RevisionHistoryModal
application={application}
historyModalController={viewControllerManager.historyModalController}
notesController={viewControllerManager.notesController}
selectionController={viewControllerManager.selectionController}
subscriptionController={viewControllerManager.subscriptionController}
/>
</>
{renderChallenges()}
<>
<NotesContextMenu
application={application}
navigationController={viewControllerManager.navigationController}
notesController={viewControllerManager.notesController}
noteTagsController={viewControllerManager.noteTagsController}
historyModalController={viewControllerManager.historyModalController}
/>
<TagContextMenuWrapper
navigationController={viewControllerManager.navigationController}
featuresController={viewControllerManager.featuresController}
/>
<FileContextMenuWrapper
filesController={viewControllerManager.filesController}
selectionController={viewControllerManager.selectionController}
/>
<PurchaseFlowWrapper application={application} viewControllerManager={viewControllerManager} />
<ConfirmSignoutContainer
applicationGroup={mainApplicationGroup}
viewControllerManager={viewControllerManager}
application={application}
/>
<ToastContainer />
<FilePreviewModalWrapper application={application} viewControllerManager={viewControllerManager} />
<PermissionsModalWrapper application={application} />
</>
</div>
</PremiumModalProvider>
</ResponsivePaneProvider>
</PremiumModalProvider>
</AndroidBackHandlerProvider>
)
}
@@ -0,0 +1,44 @@
import { WebApplication } from '@/Application/Application'
import { ChallengePrompt } from '@standardnotes/services'
import { RefObject, useState } from 'react'
import Button from '../Button/Button'
import Icon from '../Icon/Icon'
import { InputValue } from './InputValue'
type Props = {
application: WebApplication
onValueChange: (value: InputValue['value'], prompt: ChallengePrompt) => void
prompt: ChallengePrompt
buttonRef: RefObject<HTMLButtonElement>
}
const BiometricsPrompt = ({ application, onValueChange, prompt, buttonRef }: Props) => {
const [authenticated, setAuthenticated] = useState(false)
return (
<div className="min-w-76">
<Button
primary
fullWidth
colorStyle={authenticated ? 'success' : 'info'}
onClick={async () => {
const authenticated = await application.mobileDevice.authenticateWithBiometrics()
setAuthenticated(authenticated)
onValueChange(authenticated, prompt)
}}
ref={buttonRef}
>
{authenticated ? (
<span className="flex items-center justify-center gap-3">
<Icon type="check-circle" />
Biometrics successful
</span>
) : (
'Tap to use biometrics'
)}
</Button>
</div>
)
}
export default BiometricsPrompt
@@ -184,6 +184,20 @@ const ChallengeModal: FunctionComponent<Props> = ({
}
}, [hasBiometricPromptValue, hasOnlyBiometricPrompt, submit])
useEffect(() => {
const removeListener = application.addAndroidBackHandlerEventListener(() => {
if (challenge.cancelable) {
cancelChallenge()
}
return true
})
return () => {
if (removeListener) {
removeListener()
}
}
}, [application, cancelChallenge, challenge.cancelable])
if (!challenge.prompts) {
return null
}
@@ -1,16 +1,11 @@
import {
ChallengePrompt,
ChallengeValidation,
MobileDeviceInterface,
ProtectionSessionDurations,
} from '@standardnotes/snjs'
import { ChallengePrompt, ChallengeValidation, ProtectionSessionDurations } from '@standardnotes/snjs'
import { FunctionComponent, useEffect, useRef } from 'react'
import DecoratedInput from '@/Components/Input/DecoratedInput'
import DecoratedPasswordInput from '@/Components/Input/DecoratedPasswordInput'
import { ChallengeModalValues } from './ChallengeModalValues'
import Button from '../Button/Button'
import { WebApplication } from '@/Application/Application'
import { InputValue } from './InputValue'
import BiometricsPrompt from './BiometricsPrompt'
type Props = {
application: WebApplication
@@ -87,21 +82,12 @@ const ChallengeModalPrompt: FunctionComponent<Props> = ({
</div>
</div>
) : prompt.validation === ChallengeValidation.Biometric ? (
<div className="min-w-76">
<Button
primary
fullWidth
onClick={async () => {
const authenticated = await (
application.deviceInterface as MobileDeviceInterface
).authenticateWithBiometrics()
onValueChange(authenticated, prompt)
}}
ref={biometricsButtonRef}
>
Tap to use biometrics
</Button>
</div>
<BiometricsPrompt
application={application}
onValueChange={onValueChange}
prompt={prompt}
buttonRef={biometricsButtonRef}
/>
) : prompt.secureTextEntry ? (
<DecoratedPasswordInput
ref={inputRef}
@@ -5,6 +5,7 @@ import { FunctionComponent, useCallback, useRef, useState } from 'react'
import Icon from '@/Components/Icon/Icon'
import ChangeEditorMenu from './ChangeEditorMenu'
import Popover from '../Popover/Popover'
import { classNames } from '@/Utils/ConcatenateClassNames'
type Props = {
application: WebApplication
@@ -21,6 +22,12 @@ const ChangeEditorButton: FunctionComponent<Props> = ({
const [isOpen, setIsOpen] = useState(false)
const buttonRef = useRef<HTMLButtonElement>(null)
const containerRef = useRef<HTMLDivElement>(null)
const [selectedEditor, setSelectedEditor] = useState(() => {
return note ? application.componentManager.editorForNote(note) : undefined
})
const [selectedEditorIcon, selectedEditorIconTint] = application.iconsController.getIconAndTintForNoteType(
selectedEditor?.package_info.note_type,
)
const toggleMenu = useCallback(async () => {
const willMenuOpen = !isOpen
@@ -33,13 +40,16 @@ const ChangeEditorButton: FunctionComponent<Props> = ({
return (
<div ref={containerRef}>
<button
className="bg-text-padding flex h-8 min-w-8 cursor-pointer items-center justify-center rounded-full border border-solid border-border text-neutral hover:bg-contrast focus:bg-contrast"
className={classNames(
'bg-text-padding flex h-8 min-w-8 cursor-pointer items-center justify-center rounded-full border border-solid text-neutral hover:bg-contrast focus:bg-contrast',
`border-accessory-tint-${selectedEditorIconTint}`,
)}
title="Change note type"
aria-label="Change note type"
onClick={toggleMenu}
ref={buttonRef}
>
<Icon type="dashboard" />
<Icon type={selectedEditorIcon} className={`text-accessory-tint-${selectedEditorIconTint}`} />
</button>
<Popover togglePopover={toggleMenu} anchorElement={buttonRef.current} open={isOpen} className="pt-2 md:pt-0">
<ChangeEditorMenu
@@ -49,6 +59,9 @@ const ChangeEditorButton: FunctionComponent<Props> = ({
closeMenu={() => {
setIsOpen(false)
}}
onSelect={(component) => {
setSelectedEditor(component)
}}
/>
</Popover>
</div>
@@ -31,11 +31,18 @@ type ChangeEditorMenuProps = {
closeMenu: () => void
isVisible: boolean
note: SNNote | undefined
onSelect?: (component: SNComponent | undefined) => void
}
const getGroupId = (group: EditorMenuGroup) => group.title.toLowerCase().replace(/\s/, '-')
const ChangeEditorMenu: FunctionComponent<ChangeEditorMenuProps> = ({ application, closeMenu, isVisible, note }) => {
const ChangeEditorMenu: FunctionComponent<ChangeEditorMenuProps> = ({
application,
closeMenu,
isVisible,
note,
onSelect,
}) => {
const editors = useMemo(
() =>
application.componentManager.componentsForArea(ComponentArea.Editor).sort((a, b) => {
@@ -162,8 +169,12 @@ const ChangeEditorMenu: FunctionComponent<ChangeEditorMenuProps> = ({ applicatio
}
closeMenu()
if (onSelect) {
onSelect(itemToBeSelected.component)
}
},
[application.componentManager, closeMenu, currentEditor, note, premiumModal, selectComponent],
[application.componentManager, closeMenu, currentEditor, note, onSelect, premiumModal, selectComponent],
)
return (
@@ -0,0 +1,70 @@
import { observer } from 'mobx-react-lite'
import { ViewControllerManager } from '@Controllers/ViewControllerManager'
import { AlertDialog, AlertDialogDescription, AlertDialogLabel } from '@reach/alert-dialog'
import { useRef } from 'react'
import { STRING_DELETE_ACCOUNT_CONFIRMATION } from '@/Constants/Strings'
import Button from '@/Components/Button/Button'
import { WebApplication } from '@/Application/Application'
type Props = {
viewControllerManager: ViewControllerManager
application: WebApplication
}
const ConfirmDeleteAccountModal = ({ application, viewControllerManager }: Props) => {
function closeDialog() {
viewControllerManager.accountMenuController.setDeletingAccount(false)
}
const cancelRef = useRef<HTMLButtonElement>(null)
return (
<AlertDialog onDismiss={closeDialog} leastDestructiveRef={cancelRef} className="max-w-[600px] p-0">
<div className="sk-modal-content">
<div className="sn-component">
<div className="sk-panel">
<div className="sk-panel-content">
<div className="sk-panel-section">
<AlertDialogLabel className="sk-h3 sk-panel-section-title">Delete account?</AlertDialogLabel>
<AlertDialogDescription className="sk-panel-row">
<div>
<p className="text-foreground">{STRING_DELETE_ACCOUNT_CONFIRMATION}</p>
</div>
</AlertDialogDescription>
<div className="my-1 mt-4 flex gap-2">
<Button primary small colorStyle="neutral" rounded={false} ref={cancelRef} onClick={closeDialog}>
Cancel
</Button>
<Button
primary
small
colorStyle="danger"
rounded={false}
onClick={() => {
application.user.deleteAccount().catch(console.error)
closeDialog()
}}
>
Delete my account for good
</Button>
</div>
</div>
</div>
</div>
</div>
</div>
</AlertDialog>
)
}
ConfirmDeleteAccountModal.displayName = 'ConfirmDeleteAccountModal'
const ConfirmDeleteAccountContainer = (props: Props) => {
if (!props.viewControllerManager.accountMenuController.deletingAccount) {
return null
}
return <ConfirmDeleteAccountModal {...props} />
}
export default observer(ConfirmDeleteAccountContainer)
@@ -41,15 +41,7 @@ const ConfirmSignoutModal: FunctionComponent<Props> = ({ application, viewContro
<AlertDialogLabel className="sk-h3 sk-panel-section-title">Sign out workspace?</AlertDialogLabel>
<AlertDialogDescription className="sk-panel-row">
<div>
<p className="text-foreground">
{STRING_SIGN_OUT_CONFIRMATION}
{application.isNativeMobileWeb() && (
<div className="font-bold">
<br />
Your app will quit after sign out completes.
</div>
)}
</p>
<p className="text-foreground">{STRING_SIGN_OUT_CONFIRMATION}</p>
{showWorkspaceWarning && (
<>
<br />
@@ -69,7 +69,7 @@ const ContentList: FunctionComponent<Props> = ({
<div
className={classNames(
'infinite-scroll overflow-y-auto overflow-x-hidden focus:shadow-none focus:outline-none',
'md:max-h-full md:overflow-y-hidden md:hover:overflow-y-auto',
'md:max-h-full md:overflow-y-hidden md:hover:overflow-y-auto pointer-coarse:md:overflow-y-auto',
'md:hover:[overflow-y:_overlay]',
)}
id={ElementIds.ContentList}
@@ -24,6 +24,7 @@ import { StreamingFileReader } from '@standardnotes/filepicker'
import SearchBar from '../SearchBar/SearchBar'
import { SearchOptionsController } from '@/Controllers/SearchOptionsController'
import { classNames } from '@/Utils/ConcatenateClassNames'
import { MediaQueryBreakpoints, useMediaQuery } from '@/Hooks/useMediaQuery'
type Props = {
accountMenuController: AccountMenuController
@@ -50,7 +51,7 @@ const ContentListView: FunctionComponent<Props> = ({
selectionController,
searchOptionsController,
}) => {
const { toggleAppPane } = useResponsiveAppPane()
const { isNotesListVisibleOnTablets, toggleAppPane } = useResponsiveAppPane()
const fileInputRef = useRef<HTMLInputElement>(null)
const itemsViewPanelRef = useRef<HTMLDivElement>(null)
@@ -181,17 +182,24 @@ const ContentListView: FunctionComponent<Props> = ({
[isFilesSmartView],
)
const matchesMediumBreakpoint = useMediaQuery(MediaQueryBreakpoints.md)
const matchesXLBreakpoint = useMediaQuery(MediaQueryBreakpoints.xl)
const isTabletScreenSize = matchesMediumBreakpoint && !matchesXLBreakpoint
return (
<div
id="items-column"
className={classNames(
'sn-component section app-column flex h-screen flex-col md:h-full',
'xl:w-87.5 xsm-only:!w-full sm-only:!w-full pointer-coarse:md-only:!w-52 pointer-coarse:lg-only:!w-52',
'sn-component section app-column flex h-screen flex-col pt-safe-top md:h-full',
'xl:w-87.5 xsm-only:!w-full sm-only:!w-full',
isTabletScreenSize && !isNotesListVisibleOnTablets
? 'pointer-coarse:md-only:!w-0 pointer-coarse:lg-only:!w-0'
: 'pointer-coarse:md-only:!w-60 pointer-coarse:lg-only:!w-60',
)}
aria-label={'Notes & Files'}
ref={itemsViewPanelRef}
>
<ResponsivePaneContent paneId={AppPaneId.Items} className="min-h-[85vh]">
<ResponsivePaneContent paneId={AppPaneId.Items}>
<div id="items-title-bar" className="section-title-bar border-b border-solid border-border">
<div id="items-title-bar-container">
<input
@@ -7,6 +7,7 @@ import MenuItem from '@/Components/Menu/MenuItem'
import MenuItemSeparator from '@/Components/Menu/MenuItemSeparator'
import { MenuItemType } from '@/Components/Menu/MenuItemType'
import { DisplayOptionsMenuProps } from './DisplayOptionsMenuProps'
import { PrefDefaults } from '@/Constants/PrefDefaults'
const DisplayOptionsMenu: FunctionComponent<DisplayOptionsMenuProps> = ({
closeDisplayOptionsMenu,
@@ -14,17 +15,35 @@ const DisplayOptionsMenu: FunctionComponent<DisplayOptionsMenuProps> = ({
isOpen,
isFilesSmartView,
}) => {
const [sortBy, setSortBy] = useState(() => application.getPreference(PrefKey.SortNotesBy, CollectionSort.CreatedAt))
const [sortReverse, setSortReverse] = useState(() => application.getPreference(PrefKey.SortNotesReverse, false))
const [hidePreview, setHidePreview] = useState(() => application.getPreference(PrefKey.NotesHideNotePreview, false))
const [hideDate, setHideDate] = useState(() => application.getPreference(PrefKey.NotesHideDate, false))
const [hideTags, setHideTags] = useState(() => application.getPreference(PrefKey.NotesHideTags, true))
const [hidePinned, setHidePinned] = useState(() => application.getPreference(PrefKey.NotesHidePinned, false))
const [showArchived, setShowArchived] = useState(() => application.getPreference(PrefKey.NotesShowArchived, false))
const [showTrashed, setShowTrashed] = useState(() => application.getPreference(PrefKey.NotesShowTrashed, false))
const [hideProtected, setHideProtected] = useState(() => application.getPreference(PrefKey.NotesHideProtected, false))
const [sortBy, setSortBy] = useState(() =>
application.getPreference(PrefKey.SortNotesBy, PrefDefaults[PrefKey.SortNotesBy]),
)
const [sortReverse, setSortReverse] = useState(() =>
application.getPreference(PrefKey.SortNotesReverse, PrefDefaults[PrefKey.SortNotesReverse]),
)
const [hidePreview, setHidePreview] = useState(() =>
application.getPreference(PrefKey.NotesHideNotePreview, PrefDefaults[PrefKey.NotesHideNotePreview]),
)
const [hideDate, setHideDate] = useState(() =>
application.getPreference(PrefKey.NotesHideDate, PrefDefaults[PrefKey.NotesHideDate]),
)
const [hideTags, setHideTags] = useState(() =>
application.getPreference(PrefKey.NotesHideTags, PrefDefaults[PrefKey.NotesHideTags]),
)
const [hidePinned, setHidePinned] = useState(() =>
application.getPreference(PrefKey.NotesHidePinned, PrefDefaults[PrefKey.NotesHidePinned]),
)
const [showArchived, setShowArchived] = useState(() =>
application.getPreference(PrefKey.NotesShowArchived, PrefDefaults[PrefKey.NotesShowArchived]),
)
const [showTrashed, setShowTrashed] = useState(() =>
application.getPreference(PrefKey.NotesShowTrashed, PrefDefaults[PrefKey.NotesShowTrashed]),
)
const [hideProtected, setHideProtected] = useState(() =>
application.getPreference(PrefKey.NotesHideProtected, PrefDefaults[PrefKey.NotesHideProtected]),
)
const [hideEditorIcon, setHideEditorIcon] = useState(() =>
application.getPreference(PrefKey.NotesHideEditorIcon, false),
application.getPreference(PrefKey.NotesHideEditorIcon, PrefDefaults[PrefKey.NotesHideEditorIcon]),
)
const toggleSortReverse = useCallback(() => {
@@ -28,16 +28,12 @@ const FileView = ({ application, viewControllerManager, file }: FileViewProps) =
}, [application, file])
return shouldShowProtectedOverlay ? (
<div aria-label="Note" className="section editor sn-component">
<div className="flex h-full items-center justify-center">
<ProtectedItemOverlay
viewControllerManager={viewControllerManager}
hasProtectionSources={application.hasProtectionSources()}
onViewItem={dismissProtectedOverlay}
itemType={'note'}
/>
</div>
</div>
<ProtectedItemOverlay
viewControllerManager={viewControllerManager}
hasProtectionSources={application.hasProtectionSources()}
onViewItem={dismissProtectedOverlay}
itemType={'file'}
/>
) : (
<FileViewWithoutProtection application={application} viewControllerManager={viewControllerManager} file={file} />
)
@@ -3,6 +3,7 @@ import { useRef } from 'react'
import AccountMenu, { AccountMenuProps } from '../AccountMenu/AccountMenu'
import Icon from '../Icon/Icon'
import Popover from '../Popover/Popover'
import StyledTooltip from '../StyledTooltip/StyledTooltip'
type Props = AccountMenuProps & {
isOpen: boolean
@@ -25,18 +26,20 @@ const AccountMenuButton = ({
return (
<>
<button
ref={buttonRef}
onClick={toggleMenu}
className={classNames(
isOpen ? 'bg-border' : '',
'flex h-full w-8 cursor-pointer items-center justify-center rounded-full',
)}
>
<div className={hasError ? 'text-danger' : user ? 'text-info' : 'text-neutral'}>
<Icon type="account-circle" className="h-5 w-5 hover:text-info" />
</div>
</button>
<StyledTooltip label="Open account menu">
<button
ref={buttonRef}
onClick={toggleMenu}
className={classNames(
isOpen ? 'bg-border' : '',
'flex h-full w-8 cursor-pointer items-center justify-center rounded-full',
)}
>
<div className={hasError ? 'text-danger' : user ? 'text-info' : 'text-neutral'}>
<Icon type="account-circle" className="h-5 w-5 hover:text-info" />
</div>
</button>
</StyledTooltip>
<Popover anchorElement={buttonRef.current} open={isOpen} togglePopover={toggleMenu} side="top" className="py-2">
<AccountMenu
onClickOutside={onClickOutside}
@@ -18,6 +18,8 @@ import { AccountMenuPane } from '../AccountMenu/AccountMenuPane'
import { EditorEventSource } from '@/Types/EditorEventSource'
import QuickSettingsButton from './QuickSettingsButton'
import AccountMenuButton from './AccountMenuButton'
import StyledTooltip from '../StyledTooltip/StyledTooltip'
import UpgradeNow from './UpgradeNow'
type Props = {
application: WebApplication
@@ -336,6 +338,11 @@ class Footer extends PureComponent<Props, State> {
this.viewControllerManager.quickSettingsMenuController.closeQuickSettingsMenu()
}
openPreferences = () => {
this.clickOutsideQuickSettingsMenu()
this.viewControllerManager.preferencesController.openPreferences()
}
override render() {
return (
<div className="sn-component">
@@ -356,15 +363,30 @@ class Footer extends PureComponent<Props, State> {
viewControllerManager={this.viewControllerManager}
/>
</div>
<div className="relative z-footer-bar-item select-none">
<StyledTooltip label="Open preferences">
<button
onClick={this.openPreferences}
className="flex h-full w-8 cursor-pointer items-center justify-center"
>
<div className="h-5">
<Icon type="tune" className="rounded hover:text-info" />
</div>
</button>
</StyledTooltip>
</div>
<div className="relative z-footer-bar-item select-none">
<QuickSettingsButton
isOpen={this.state.showQuickSettingsMenu}
toggleMenu={this.quickSettingsClickHandler}
application={this.application}
preferencesController={this.viewControllerManager.preferencesController}
quickSettingsMenuController={this.viewControllerManager.quickSettingsMenuController}
/>
</div>
<UpgradeNow
application={this.application}
featuresController={this.viewControllerManager.featuresController}
/>
{this.state.showBetaWarning && (
<Fragment>
<div className="relative z-footer-bar-item ml-3 flex select-none items-center border-l border-solid border-border pl-3">
@@ -417,14 +439,16 @@ class Footer extends PureComponent<Props, State> {
</div>
)}
{this.state.hasPasscode && (
<div
id="lock-item"
onClick={this.lockClickHandler}
title="Locks application and wipes unencrypted data from memory."
className="relative z-footer-bar-item ml-3 flex cursor-pointer select-none items-center border-l border-solid border-border pl-2 hover:text-info"
>
<Icon type="lock-filled" size="custom" className="h-4.5 w-4.5" />
</div>
<StyledTooltip label="Lock application">
<div
id="lock-item"
onClick={this.lockClickHandler}
title="Locks application and wipes unencrypted data from memory."
className="relative z-footer-bar-item ml-3 flex cursor-pointer select-none items-center border-l border-solid border-border pl-2 hover:text-info"
>
<Icon type="lock-filled" size="custom" className="h-4.5 w-4.5" />
</div>
</StyledTooltip>
)}
</div>
</footer>
@@ -1,40 +1,35 @@
import { WebApplication } from '@/Application/Application'
import { PreferencesController } from '@/Controllers/PreferencesController'
import { QuickSettingsController } from '@/Controllers/QuickSettingsController'
import { classNames } from '@/Utils/ConcatenateClassNames'
import { useRef } from 'react'
import Icon from '../Icon/Icon'
import Popover from '../Popover/Popover'
import QuickSettingsMenu from '../QuickSettingsMenu/QuickSettingsMenu'
import StyledTooltip from '../StyledTooltip/StyledTooltip'
type Props = {
isOpen: boolean
toggleMenu: () => void
application: WebApplication
preferencesController: PreferencesController
quickSettingsMenuController: QuickSettingsController
}
const QuickSettingsButton = ({
application,
isOpen,
toggleMenu,
preferencesController,
quickSettingsMenuController,
}: Props) => {
const QuickSettingsButton = ({ application, isOpen, toggleMenu, quickSettingsMenuController }: Props) => {
const buttonRef = useRef<HTMLButtonElement>(null)
return (
<>
<button
onClick={toggleMenu}
className="flex h-full w-8 cursor-pointer items-center justify-center"
ref={buttonRef}
>
<div className="h-5">
<Icon type="tune" className={classNames(isOpen && 'text-info', 'rounded hover:text-info')} />
</div>
</button>
<StyledTooltip label="Open quick settings menu">
<button
onClick={toggleMenu}
className="flex h-full w-8 cursor-pointer items-center justify-center"
ref={buttonRef}
>
<div className="h-5">
<Icon type="themes" className={classNames(isOpen && 'text-info', 'rounded hover:text-info')} />
</div>
</button>
</StyledTooltip>
<Popover
togglePopover={toggleMenu}
anchorElement={buttonRef.current}
@@ -43,11 +38,7 @@ const QuickSettingsButton = ({
align="start"
className="py-2"
>
<QuickSettingsMenu
preferencesController={preferencesController}
quickSettingsMenuController={quickSettingsMenuController}
application={application}
/>
<QuickSettingsMenu quickSettingsMenuController={quickSettingsMenuController} application={application} />
</Popover>
</>
)
@@ -0,0 +1,46 @@
import { WebApplication } from '@/Application/Application'
import { FeaturesController } from '@/Controllers/FeaturesController'
import { observer } from 'mobx-react-lite'
import { loadPurchaseFlowUrl } from '../PurchaseFlow/PurchaseFlowFunctions'
type Props = {
application: WebApplication
featuresController: FeaturesController
}
const UpgradeNow = ({ application, featuresController }: Props) => {
const shouldShowCTA = !featuresController.hasFolders
const hasAccount = application.hasAccount()
const openPlansPage = () => {
if (!window.plansUrl) {
return
}
if (application.isNativeMobileWeb()) {
application.mobileDevice.openUrl(window.plansUrl)
} else {
window.location.assign(window.plansUrl)
}
}
return shouldShowCTA ? (
<div className="flex h-full items-center px-2">
<button
className="rounded bg-info py-0.5 px-1.5 text-xs font-bold uppercase text-info-contrast hover:brightness-125"
onClick={() => {
if (hasAccount) {
void loadPurchaseFlowUrl(application)
return
}
openPlansPage()
}}
>
Upgrade now
</button>
</div>
) : null
}
export default observer(UpgradeNow)

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