mirror of
https://github.com/standardnotes/app
synced 2026-09-16 00:46:00 -04:00
Compare commits
39
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
285df04a59 | ||
|
|
4d5429cc89 | ||
|
|
da6622dc95 | ||
|
|
a548883863 | ||
|
|
1330201d2e | ||
|
|
0af720146c | ||
|
|
4d6992cf83 | ||
|
|
5de6f459c1 | ||
|
|
3c0d4fac76 | ||
|
|
4cdfcbfd95 | ||
|
|
51e50433d3 | ||
|
|
696327ff03 | ||
|
|
de64f1bfce | ||
|
|
48d484675b | ||
|
|
86251b49d3 | ||
|
|
5961bc491d | ||
|
|
e50f4eb92e | ||
|
|
4f8e75f36a | ||
|
|
6824dd2d5f | ||
|
|
76ec8b0f90 | ||
|
|
3eebdbb77d | ||
|
|
ce252def33 | ||
|
|
cb7af03ce8 | ||
|
|
1fe833bc24 | ||
|
|
ac1f59cde7 | ||
|
|
db4ceca10e | ||
|
|
0176f47fe7 | ||
|
|
f281041221 | ||
|
|
ebd56cd5aa | ||
|
|
8fa566336c | ||
|
|
9dfeac7489 | ||
|
|
d1b71861ec | ||
|
|
766548f12d | ||
|
|
581a08cd09 | ||
|
|
ee0d44405d | ||
|
|
1ae64dcac4 | ||
|
|
2be4fb4f83 | ||
|
|
271a8d1d70 | ||
|
|
e809328fa8 |
@@ -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.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,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/api",
|
||||
"version": "1.8.1",
|
||||
"version": "1.8.2",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [2.7.14](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/components-meta
|
||||
|
||||
## [2.7.13](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-16)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/components-meta
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/components-meta",
|
||||
"version": "2.7.13",
|
||||
"version": "2.7.14",
|
||||
"private": true,
|
||||
"author": "Standard Notes.",
|
||||
"main": "dist",
|
||||
|
||||
@@ -3,6 +3,70 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [3.23.152](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.151](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.150](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.149](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.148](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.147](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.146](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.145](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.144](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.143](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.142](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.141](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.140](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.139](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.138](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.137](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.23.136](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@standardnotes/desktop",
|
||||
"main": "./app/dist/index.js",
|
||||
"version": "3.23.136",
|
||||
"version": "3.23.152",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"author": "Standard Notes.",
|
||||
"private": true,
|
||||
|
||||
@@ -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.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,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/encryption",
|
||||
"version": "1.15.3",
|
||||
"version": "1.15.4",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,12 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.52.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **mobile:** adjust status bar color to match current theme ([#1624](https://github.com/standardnotes/app/issues/1624)) ([4d5429c](https://github.com/standardnotes/app/commit/4d5429cc89c15f870825f20e97844825102c6aec))
|
||||
|
||||
# [1.52.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-13)
|
||||
|
||||
### Features
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/features",
|
||||
"version": "1.52.0",
|
||||
"version": "1.52.1",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -72,6 +72,7 @@ export type ThemeFeatureDescription = ComponentFeatureDescription & {
|
||||
/** Some themes can be layered on top of other themes */
|
||||
layerable?: boolean
|
||||
dock_icon?: ThemeDockIcon
|
||||
isDark?: boolean
|
||||
}
|
||||
|
||||
export type FeatureDescription = BaseFeatureDescription &
|
||||
|
||||
@@ -12,6 +12,7 @@ export function themes(): ThemeFeatureDescription[] {
|
||||
permission_name: PermissionName.MidnightTheme,
|
||||
description: 'Elegant utilitarianism.',
|
||||
thumbnail_url: 'https://s3.amazonaws.com/standard-notes/screenshots/models/themes/midnight-with-mobile.jpg',
|
||||
isDark: true,
|
||||
dock_icon: {
|
||||
type: 'circle',
|
||||
background_color: '#086DD6',
|
||||
@@ -27,6 +28,7 @@ export function themes(): ThemeFeatureDescription[] {
|
||||
permission_name: PermissionName.FuturaTheme,
|
||||
description: 'Calm and relaxed. Take some time off.',
|
||||
thumbnail_url: 'https://s3.amazonaws.com/standard-notes/screenshots/models/themes/futura-with-mobile.jpg',
|
||||
isDark: true,
|
||||
dock_icon: {
|
||||
type: 'circle',
|
||||
background_color: '#fca429',
|
||||
@@ -42,6 +44,7 @@ export function themes(): ThemeFeatureDescription[] {
|
||||
permission_name: PermissionName.SolarizedDarkTheme,
|
||||
description: 'The perfect theme for any time.',
|
||||
thumbnail_url: 'https://s3.amazonaws.com/standard-notes/screenshots/models/themes/solarized-dark.jpg',
|
||||
isDark: true,
|
||||
dock_icon: {
|
||||
type: 'circle',
|
||||
background_color: '#2AA198',
|
||||
@@ -72,6 +75,7 @@ export function themes(): ThemeFeatureDescription[] {
|
||||
permission_name: PermissionName.FocusedTheme,
|
||||
description: 'For when you need to go in.',
|
||||
thumbnail_url: 'https://s3.amazonaws.com/standard-notes/screenshots/models/themes/focus-with-mobile.jpg',
|
||||
isDark: true,
|
||||
dock_icon: {
|
||||
type: 'circle',
|
||||
background_color: '#a464c2',
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.23.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/filepicker
|
||||
|
||||
## [1.23.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/filepicker
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/filepicker",
|
||||
"version": "1.23.3",
|
||||
"version": "1.23.4",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [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,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/files",
|
||||
"version": "1.10.3",
|
||||
"version": "1.10.4",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,78 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [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>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/mobile",
|
||||
"version": "3.35.4",
|
||||
"version": "3.36.3",
|
||||
"author": "Standard Notes.",
|
||||
"private": true,
|
||||
"license": "AGPL-3.0-or-later",
|
||||
|
||||
@@ -18,7 +18,7 @@ import { ICON_MENU } from '@Style/Icons'
|
||||
import { ThemeService } from '@Style/ThemeService'
|
||||
import { getDefaultDrawerWidth } from '@Style/Utils'
|
||||
import React, { useCallback, useContext, useEffect, useRef, useState } from 'react'
|
||||
import { Dimensions, Keyboard, ScaledSize, StatusBar } from 'react-native'
|
||||
import { Dimensions, Keyboard, ScaledSize } from 'react-native'
|
||||
import DrawerLayout, { DrawerState } from 'react-native-gesture-handler/DrawerLayout'
|
||||
import { HeaderButtons, Item } from 'react-navigation-header-buttons'
|
||||
import { ThemeContext } from 'styled-components'
|
||||
@@ -150,7 +150,6 @@ export const AppStackComponent = (props: ModalStackNavigationProp<'AppStack'>) =
|
||||
onDrawerStateChanged={handleDrawerStateChange}
|
||||
renderNavigationView={() => !isLocked && <MainSideMenu drawerRef={drawerRef.current} />}
|
||||
>
|
||||
<StatusBar translucent={!shouldOpenWebApp} />
|
||||
<DrawerLayout
|
||||
ref={noteDrawerRef}
|
||||
drawerWidth={getDefaultDrawerWidth(dimensions)}
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
platformFromString,
|
||||
SNApplication,
|
||||
SNComponentManager,
|
||||
StorageValueModes,
|
||||
} from '@standardnotes/snjs'
|
||||
import { Platform } from 'react-native'
|
||||
|
||||
@@ -21,6 +22,7 @@ import { MobileAlertService } from './AlertService'
|
||||
import { ApplicationState } from './ApplicationState'
|
||||
import { BackupsService } from './BackupsService'
|
||||
import { ComponentManager } from './ComponentManager'
|
||||
import { AlwaysOpenWebAppOnLaunchKey } from './constants'
|
||||
import { FilesService } from './FilesService'
|
||||
import { InstallationService } from './InstallationService'
|
||||
import { MobileDevice } from './Interface'
|
||||
@@ -135,7 +137,8 @@ export class MobileApplication extends SNApplication {
|
||||
}
|
||||
|
||||
promptForChallenge(challenge: Challenge) {
|
||||
if (IsMobileWeb) {
|
||||
const optedIntoWebPreview = this.getValue(AlwaysOpenWebAppOnLaunchKey, StorageValueModes.Nonwrapped) as boolean
|
||||
if (IsMobileWeb || optedIntoWebPreview) {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
removeFromArray,
|
||||
TransferPayload,
|
||||
} from '@standardnotes/snjs'
|
||||
import { Alert, Linking, Platform } from 'react-native'
|
||||
import { Alert, Linking, Platform, StatusBar } from 'react-native'
|
||||
import FingerprintScanner from 'react-native-fingerprint-scanner'
|
||||
import FlagSecure from 'react-native-flag-secure-android'
|
||||
import { hide, show } from 'react-native-privacy-snapshot'
|
||||
@@ -65,6 +65,7 @@ const showLoadFailForItemIds = (failedItemIds: string[]) => {
|
||||
export class MobileDevice implements MobileDeviceInterface {
|
||||
environment: Environment.Mobile = Environment.Mobile
|
||||
private eventObservers: MobileDeviceEventHandler[] = []
|
||||
public isDarkMode = false
|
||||
|
||||
constructor(private stateObserverService?: AppStateObserverService) {}
|
||||
|
||||
@@ -432,6 +433,16 @@ export class MobileDevice implements MobileDeviceInterface {
|
||||
}
|
||||
}
|
||||
|
||||
handleThemeSchemeChange(isDark: boolean): void {
|
||||
this.isDarkMode = isDark
|
||||
|
||||
this.reloadStatusBarStyle()
|
||||
}
|
||||
|
||||
reloadStatusBarStyle(animated = true) {
|
||||
StatusBar.setBarStyle(this.isDarkMode ? 'light-content' : 'dark-content', animated)
|
||||
}
|
||||
|
||||
private notifyEvent(event: MobileDeviceEvent): void {
|
||||
for (const handler of this.eventObservers) {
|
||||
handler(event)
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { MobileDevice, MobileDeviceEvent } from '@Lib/Interface'
|
||||
import { IsDev } from '@Lib/Utils'
|
||||
import { ReactNativeToWebEvent } from '@standardnotes/snjs'
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { Platform } from 'react-native'
|
||||
import { Keyboard, Platform } from 'react-native'
|
||||
import { WebView, WebViewMessageEvent } from 'react-native-webview'
|
||||
import { AppStateObserverService } from './AppStateObserverService'
|
||||
|
||||
const LoggingEnabled = false
|
||||
const LoggingEnabled = IsDev
|
||||
|
||||
export const MobileWebAppContainer = () => {
|
||||
const [identifier, setIdentifier] = useState(Math.random())
|
||||
@@ -28,8 +29,18 @@ const MobileWebAppContents = ({ destroyAndReload }: { destroyAndReload: () => vo
|
||||
webViewRef.current?.postMessage(JSON.stringify({ reactNativeEvent: event, messageType: 'event' }))
|
||||
})
|
||||
|
||||
const keyboardShowListener = Keyboard.addListener('keyboardWillShow', () => {
|
||||
device.reloadStatusBarStyle(false)
|
||||
})
|
||||
|
||||
const keyboardHideListener = Keyboard.addListener('keyboardDidHide', () => {
|
||||
device.reloadStatusBarStyle(false)
|
||||
})
|
||||
|
||||
return () => {
|
||||
removeListener()
|
||||
keyboardShowListener.remove()
|
||||
keyboardHideListener.remove()
|
||||
}
|
||||
}, [webViewRef, stateService])
|
||||
|
||||
@@ -175,7 +186,6 @@ const MobileWebAppContents = ({ destroyAndReload }: { destroyAndReload: () => vo
|
||||
ref={webViewRef}
|
||||
source={{ uri: sourceUri }}
|
||||
originWhitelist={['*']}
|
||||
contentInset={{ top: 30, bottom: 10 }}
|
||||
onLoad={() => {}}
|
||||
onError={(err) => console.error('An error has occurred', err)}
|
||||
onHttpError={() => console.error('An HTTP error occurred')}
|
||||
@@ -183,6 +193,7 @@ const MobileWebAppContents = ({ destroyAndReload }: { destroyAndReload: () => vo
|
||||
allowFileAccess={true}
|
||||
allowUniversalAccessFromFileURLs={true}
|
||||
injectedJavaScriptBeforeContentLoaded={injectedJS}
|
||||
bounces={false}
|
||||
/>
|
||||
)
|
||||
/* eslint-enable @typescript-eslint/no-empty-function */
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
import { AlwaysOpenWebAppOnLaunchKey } from '@Lib/constants'
|
||||
import { ApplicationContext } from '@Root/ApplicationContext'
|
||||
import { ButtonCell } from '@Root/Components/ButtonCell'
|
||||
import { SectionHeader } from '@Root/Components/SectionHeader'
|
||||
import { TableSection } from '@Root/Components/TableSection'
|
||||
import { ButtonType, StorageValueModes } from '@standardnotes/snjs'
|
||||
import React, { useContext } from 'react'
|
||||
import styled from 'styled-components/native'
|
||||
import { Label } from './CompanySection.styled'
|
||||
import { BaseView, StyledSectionedTableCell } from './EncryptionSection.styled'
|
||||
|
||||
const Title = styled.Text`
|
||||
color: ${({ theme }) => theme.stylekitForegroundColor};
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
`
|
||||
|
||||
export const NewMobileSection = () => {
|
||||
const application = useContext(ApplicationContext)
|
||||
|
||||
if (!application) {
|
||||
return <></>
|
||||
}
|
||||
|
||||
const optIn = async () => {
|
||||
const confirmationText =
|
||||
'This will close the app and switch to the new mobile experience next time you open it. You will be able to switch back to the soon-to-be removed classic experience from the settings.'
|
||||
|
||||
if (
|
||||
await application.alertService.confirm(
|
||||
confirmationText,
|
||||
'Switch To New Mobile Experience?',
|
||||
'Switch',
|
||||
ButtonType.Info,
|
||||
)
|
||||
) {
|
||||
application.setValue(AlwaysOpenWebAppOnLaunchKey, true, StorageValueModes.Nonwrapped)
|
||||
setTimeout(() => application.deviceInterface.performSoftReset(), 1000)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<TableSection>
|
||||
<SectionHeader title={'New Mobile Experience'} />
|
||||
|
||||
<StyledSectionedTableCell last={true} first={true}>
|
||||
<BaseView>
|
||||
<Title>🎉 New Mobile Experience Preview</Title>
|
||||
<Label>
|
||||
The new mobile experience (MX) brings the desktop experience you've come to love right here on your mobile
|
||||
device. This mode will replace the existing classic mobile experience soon. You can opt in below to begin
|
||||
using the new MX now.
|
||||
</Label>
|
||||
</BaseView>
|
||||
</StyledSectionedTableCell>
|
||||
|
||||
<ButtonCell leftAligned={true} title="Opt In to New Mobile Experience" onPress={optIn}></ButtonCell>
|
||||
<ButtonCell
|
||||
leftAligned={true}
|
||||
title="Read Blog Post"
|
||||
onPress={() => {
|
||||
application?.deviceInterface!.openUrl(
|
||||
'https://blog.standardnotes.com/38384/our-new-mobile-experience-is-launching-soon',
|
||||
)
|
||||
}}
|
||||
></ButtonCell>
|
||||
</TableSection>
|
||||
)
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
import { AlwaysOpenWebAppOnLaunchKey } from '@Lib/constants'
|
||||
import { useSignedIn } from '@Lib/SnjsHelperHooks'
|
||||
import { useNavigation } from '@react-navigation/native'
|
||||
import { ButtonCell } from '@Root/Components/ButtonCell'
|
||||
@@ -9,7 +8,7 @@ import { TableSection } from '@Root/Components/TableSection'
|
||||
import { useSafeApplicationContext } from '@Root/Hooks/useSafeApplicationContext'
|
||||
import { ModalStackNavigationProp } from '@Root/ModalStack'
|
||||
import { SCREEN_MANAGE_SESSIONS, SCREEN_SETTINGS } from '@Root/Screens/screens'
|
||||
import { ButtonType, PrefKey, StorageValueModes } from '@standardnotes/snjs'
|
||||
import { ButtonType, PrefKey } from '@standardnotes/snjs'
|
||||
import moment from 'moment'
|
||||
import React, { useCallback, useMemo, useState } from 'react'
|
||||
import { Platform } from 'react-native'
|
||||
@@ -222,21 +221,6 @@ export const OptionsSection = ({ title, encryptionAvailable }: Props) => {
|
||||
onPress={onExportPress}
|
||||
/>
|
||||
|
||||
<ButtonCell
|
||||
onPress={async () => {
|
||||
const confirmationText =
|
||||
'This will close the app and fully switch to the web view next time you open it. You will be able to switch back from the settings.'
|
||||
|
||||
if (
|
||||
await application.alertService.confirm(confirmationText, 'Switch To Web View?', 'Switch', ButtonType.Info)
|
||||
) {
|
||||
application.setValue(AlwaysOpenWebAppOnLaunchKey, true, StorageValueModes.Nonwrapped)
|
||||
setTimeout(() => application.deviceInterface.performSoftReset(), 1000)
|
||||
}
|
||||
}}
|
||||
title="Switch to Web View"
|
||||
/>
|
||||
|
||||
{!signedIn && (
|
||||
<SectionedAccessoryTableCell
|
||||
testID="lastExportDate"
|
||||
|
||||
@@ -9,6 +9,7 @@ import React, { useCallback, useEffect, useState } from 'react'
|
||||
import { AuthSection } from './Sections/AuthSection'
|
||||
import { CompanySection } from './Sections/CompanySection'
|
||||
import { EncryptionSection } from './Sections/EncryptionSection'
|
||||
import { NewMobileSection } from './Sections/NewMobilePreview'
|
||||
import { OptionsSection } from './Sections/OptionsSection'
|
||||
import { PreferencesSection } from './Sections/PreferencesSection'
|
||||
import { ProtectionsSection } from './Sections/ProtectionsSection'
|
||||
@@ -54,6 +55,7 @@ export const Settings = (props: Props) => {
|
||||
<Container keyboardShouldPersistTaps={'always'} keyboardDismissMode={'interactive'}>
|
||||
<AuthSection title="Account" signedIn={signedIn} />
|
||||
<OptionsSection encryptionAvailable={!!encryptionAvailable} title="Options" />
|
||||
<NewMobileSection />
|
||||
<WorkspacesSection />
|
||||
<PreferencesSection />
|
||||
{application.hasAccount() && isEntitledToFiles && <FilesSection />}
|
||||
|
||||
@@ -3,6 +3,12 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.18.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **mobile:** adjust status bar color to match current theme ([#1624](https://github.com/standardnotes/app/issues/1624)) ([4d5429c](https://github.com/standardnotes/app/commit/4d5429cc89c15f870825f20e97844825102c6aec))
|
||||
|
||||
## [1.18.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/models
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/models",
|
||||
"version": "1.18.3",
|
||||
"version": "1.18.4",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { FeatureDescription } from '@standardnotes/features'
|
||||
import { FeatureDescription, ThemeFeatureDescription } from '@standardnotes/features'
|
||||
|
||||
type ThirdPartyPackageInfo = {
|
||||
version: string
|
||||
@@ -6,3 +6,4 @@ type ThirdPartyPackageInfo = {
|
||||
}
|
||||
|
||||
export type ComponentPackageInfo = FeatureDescription & Partial<ThirdPartyPackageInfo>
|
||||
export type ThemePackageInfo = FeatureDescription & Partial<ThirdPartyPackageInfo> & ThemeFeatureDescription
|
||||
|
||||
@@ -6,11 +6,13 @@ import { HistoryEntryInterface } from '../../Runtime/History'
|
||||
import { DecryptedItemInterface, ItemInterface } from '../../Abstract/Item'
|
||||
import { ContentType } from '@standardnotes/common'
|
||||
import { useBoolean } from '@standardnotes/utils'
|
||||
import { ThemePackageInfo } from '../Component/PackageInfo'
|
||||
|
||||
export const isTheme = (x: ItemInterface): x is SNTheme => x.content_type === ContentType.Theme
|
||||
|
||||
export class SNTheme extends SNComponent {
|
||||
public override area: ComponentArea = ComponentArea.Themes
|
||||
public override readonly package_info!: ThemePackageInfo
|
||||
|
||||
isLayerable(): boolean {
|
||||
return useBoolean(this.package_info && this.package_info.layerable, false)
|
||||
|
||||
@@ -3,6 +3,70 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.3.75](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.74](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.73](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.72](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.71](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.70](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.69](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.68](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.67](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.66](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.65](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.64](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.63](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.62](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.61](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.60](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.3.59](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/releases",
|
||||
"version": "1.3.59",
|
||||
"version": "1.3.75",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"main": "dist/releases.json",
|
||||
"types": "dist/index.d.ts",
|
||||
|
||||
@@ -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,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/responses",
|
||||
"version": "1.10.2",
|
||||
"version": "1.10.3",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,12 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.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,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/services",
|
||||
"version": "1.21.2",
|
||||
"version": "1.21.3",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { MobileDeviceInterface } from './../Device/MobileDeviceInterface'
|
||||
import { DesktopManagerInterface } from '../Device/DesktopManagerInterface'
|
||||
import { WebAppEvent } from '../Event/WebAppEvent'
|
||||
import { ApplicationInterface } from './ApplicationInterface'
|
||||
@@ -9,4 +10,6 @@ export interface WebApplicationInterface extends ApplicationInterface {
|
||||
handleMobileGainingFocusEvent(): Promise<void>
|
||||
handleMobileLosingFocusEvent(): Promise<void>
|
||||
handleMobileResumingFromBackgroundEvent(): Promise<void>
|
||||
isNativeMobileWeb(): boolean
|
||||
get mobileDevice(): MobileDeviceInterface
|
||||
}
|
||||
|
||||
@@ -11,4 +11,5 @@ export interface MobileDeviceInterface extends DeviceInterface {
|
||||
hideMobileInterfaceFromScreenshots(): void
|
||||
stopHidingMobileInterfaceFromScreenshots(): void
|
||||
consoleLog(...args: any[]): void
|
||||
handleThemeSchemeChange(isDark: boolean): void
|
||||
}
|
||||
|
||||
@@ -3,6 +3,40 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [2.132.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/snjs
|
||||
|
||||
## [2.132.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* biometrics timing loading ([#1622](https://github.com/standardnotes/app/issues/1622)) ([3c0d4fa](https://github.com/standardnotes/app/commit/3c0d4fac766c3a31bdbebe4f7e88f83ba1ea58da))
|
||||
|
||||
## [2.132.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
### Reverts
|
||||
|
||||
* Revert "Revert "feat(web): move emails notifications to one pane and enable opening settings via url (#1614)" (#1617)" (#1619) ([e50f4eb](https://github.com/standardnotes/app/commit/e50f4eb92efd65b0b8fa3a5001b8dfb611f60180)), closes [#1614](https://github.com/standardnotes/app/issues/1614) [#1617](https://github.com/standardnotes/app/issues/1617) [#1619](https://github.com/standardnotes/app/issues/1619)
|
||||
|
||||
## [2.132.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
### Reverts
|
||||
|
||||
* Revert "feat(web): move emails notifications to one pane and enable opening settings via url (#1614)" (#1617) ([6824dd2](https://github.com/standardnotes/app/commit/6824dd2d5fe4a6d427ff5465540f3b7865933e98)), closes [#1614](https://github.com/standardnotes/app/issues/1614) [#1617](https://github.com/standardnotes/app/issues/1617)
|
||||
|
||||
# [2.132.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
### Features
|
||||
|
||||
* **web:** move emails notifications to one pane and enable opening settings via url ([#1614](https://github.com/standardnotes/app/issues/1614)) ([1fe833b](https://github.com/standardnotes/app/commit/1fe833bc24a3a426a7230381704d418624cc2b82))
|
||||
|
||||
# [2.131.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-21)
|
||||
|
||||
### Features
|
||||
|
||||
* **snjs:** add retrieving web sockets token for establishing connection ([#1602](https://github.com/standardnotes/app/issues/1602)) ([e809328](https://github.com/standardnotes/app/commit/e809328fa86d49f76d24bc0d95db010e483c1853))
|
||||
|
||||
## [2.130.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/snjs",
|
||||
"version": "2.130.2",
|
||||
"version": "2.132.4",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,18 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.3.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **mobile:** adjust status bar color to match current theme ([#1624](https://github.com/standardnotes/app/issues/1624)) ([4d5429c](https://github.com/standardnotes/app/commit/4d5429cc89c15f870825f20e97844825102c6aec))
|
||||
|
||||
# [1.3.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
### Features
|
||||
|
||||
* sync page theme color metadata with active theme bg ([#1623](https://github.com/standardnotes/app/issues/1623)) ([5de6f45](https://github.com/standardnotes/app/commit/5de6f459c106127f294693389f62fa1c3ed57798))
|
||||
|
||||
## [1.2.7](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/ui-services
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/ui-services",
|
||||
"version": "1.2.7",
|
||||
"version": "1.3.1",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
@@ -36,6 +36,7 @@
|
||||
"@typescript-eslint/parser": "^5.12.1",
|
||||
"eslint-plugin-prettier": "*",
|
||||
"jest": "^28.1.2",
|
||||
"ts-jest": "^28.0.5"
|
||||
"ts-jest": "^28.0.5",
|
||||
"typescript": "*"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,13 +248,14 @@ export class ThemeManager extends AbstractService {
|
||||
this.deactivateTheme(theme.uuid)
|
||||
}
|
||||
}
|
||||
|
||||
if (source !== PayloadEmitSource.LocalRetrieved) {
|
||||
this.cacheThemeState().catch(console.error)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
public deactivateAllThemes() {
|
||||
private deactivateAllThemes() {
|
||||
const activeThemes = this.activeThemes.slice()
|
||||
|
||||
for (const uuid of activeThemes) {
|
||||
@@ -287,10 +288,33 @@ export class ThemeManager extends AbstractService {
|
||||
link.rel = 'stylesheet'
|
||||
link.media = 'screen,print'
|
||||
link.id = theme.uuid
|
||||
link.onload = this.syncThemeColorMetadata
|
||||
document.getElementsByTagName('head')[0].appendChild(link)
|
||||
|
||||
if (this.application.isNativeMobileWeb()) {
|
||||
this.application.mobileDevice.handleThemeSchemeChange(theme.package_info.isDark ?? false)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Syncs the active theme's background color to the 'theme-color' meta tag
|
||||
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta/name/theme-color
|
||||
*/
|
||||
private syncThemeColorMetadata() {
|
||||
const themeColorMetaElement = document.querySelector('meta[name="theme-color"]')
|
||||
if (!themeColorMetaElement) {
|
||||
return
|
||||
}
|
||||
|
||||
const bgColor = getComputedStyle(document.documentElement).getPropertyValue('--sn-stylekit-background-color')
|
||||
themeColorMetaElement.setAttribute('content', bgColor ? bgColor.trim() : '#ffffff')
|
||||
}
|
||||
|
||||
private deactivateTheme(uuid: string) {
|
||||
if (!this.activeThemes.includes(uuid)) {
|
||||
return
|
||||
}
|
||||
|
||||
const element = document.getElementById(uuid) as HTMLLinkElement
|
||||
if (element) {
|
||||
element.disabled = true
|
||||
@@ -298,6 +322,10 @@ export class ThemeManager extends AbstractService {
|
||||
}
|
||||
|
||||
removeFromArray(this.activeThemes, uuid)
|
||||
|
||||
if (this.activeThemes.length === 0) {
|
||||
this.application.mobileDevice.handleThemeSchemeChange(false)
|
||||
}
|
||||
}
|
||||
|
||||
private async cacheThemeState() {
|
||||
|
||||
@@ -3,6 +3,106 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [3.55.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/web
|
||||
|
||||
## [3.55.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* prefs view on desktop ([#1628](https://github.com/standardnotes/app/issues/1628)) ([a548883](https://github.com/standardnotes/app/commit/a548883863b4e0ec949fa63a8581cc2984614993))
|
||||
|
||||
# [3.55.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
### Features
|
||||
|
||||
* add prefs button to navigation panel on mobile ([#1625](https://github.com/standardnotes/app/issues/1625)) ([0af7201](https://github.com/standardnotes/app/commit/0af720146c412316fcb24999ff73c91337f19fb9))
|
||||
|
||||
## [3.54.6](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* biometrics timing loading ([#1622](https://github.com/standardnotes/app/issues/1622)) ([3c0d4fa](https://github.com/standardnotes/app/commit/3c0d4fac766c3a31bdbebe4f7e88f83ba1ea58da))
|
||||
|
||||
## [3.54.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* protected overlay on mobile ([#1621](https://github.com/standardnotes/app/issues/1621)) ([51e5043](https://github.com/standardnotes/app/commit/51e50433d3e1a3a682bcb7a774129a904a39b12e))
|
||||
|
||||
## [3.54.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **web:** move email notification preferences to account pane ([#1620](https://github.com/standardnotes/app/issues/1620)) ([de64f1b](https://github.com/standardnotes/app/commit/de64f1bfce6d343fe698c55d6eaf307d200df3ee))
|
||||
|
||||
## [3.54.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* better safe area padding on iOS ([#1618](https://github.com/standardnotes/app/issues/1618)) ([86251b4](https://github.com/standardnotes/app/commit/86251b49d3b4965571da1a3c039ec4c6043f733c))
|
||||
|
||||
## [3.54.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
### Reverts
|
||||
|
||||
* Revert "Revert "feat(web): move emails notifications to one pane and enable opening settings via url (#1614)" (#1617)" (#1619) ([e50f4eb](https://github.com/standardnotes/app/commit/e50f4eb92efd65b0b8fa3a5001b8dfb611f60180)), closes [#1614](https://github.com/standardnotes/app/issues/1614) [#1617](https://github.com/standardnotes/app/issues/1617) [#1619](https://github.com/standardnotes/app/issues/1619)
|
||||
|
||||
## [3.54.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
### Reverts
|
||||
|
||||
* Revert "feat(web): move emails notifications to one pane and enable opening settings via url (#1614)" (#1617) ([6824dd2](https://github.com/standardnotes/app/commit/6824dd2d5fe4a6d427ff5465540f3b7865933e98)), closes [#1614](https://github.com/standardnotes/app/issues/1614) [#1617](https://github.com/standardnotes/app/issues/1617)
|
||||
|
||||
# [3.54.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
### Features
|
||||
|
||||
* show selected editor icon in change editor button ([#1615](https://github.com/standardnotes/app/issues/1615)) ([ce252de](https://github.com/standardnotes/app/commit/ce252def332c99d8d8be6a3ce5d76b66e2ea325f))
|
||||
|
||||
# [3.53.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
### Features
|
||||
|
||||
* **web:** move emails notifications to one pane and enable opening settings via url ([#1614](https://github.com/standardnotes/app/issues/1614)) ([1fe833b](https://github.com/standardnotes/app/commit/1fe833bc24a3a426a7230381704d418624cc2b82))
|
||||
|
||||
## [3.52.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* manage subscription button on mobile webview ([#1613](https://github.com/standardnotes/app/issues/1613)) ([db4ceca](https://github.com/standardnotes/app/commit/db4ceca10e4b41707cae2a4daa9718646d808c19))
|
||||
|
||||
# [3.52.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
|
||||
|
||||
### Features
|
||||
|
||||
* on mobile goto content tab after selecting revision ([#1611](https://github.com/standardnotes/app/issues/1611)) ([f281041](https://github.com/standardnotes/app/commit/f2810412217afdaa05d5012db37276c843d360b4))
|
||||
|
||||
# [3.51.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-21)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* disable focus mode and dynamic panel switches on mobile ([#1607](https://github.com/standardnotes/app/issues/1607)) ([9dfeac7](https://github.com/standardnotes/app/commit/9dfeac74897594628c0bf657226f3e5e586267dc))
|
||||
* iOS safe area using CSS ([#1610](https://github.com/standardnotes/app/issues/1610)) ([8fa5663](https://github.com/standardnotes/app/commit/8fa566336ceef8a3d7b559b1aaf342f7c51f21cd))
|
||||
|
||||
### Features
|
||||
|
||||
* add lock button to navigation panel on mobile ([#1609](https://github.com/standardnotes/app/issues/1609)) ([d1b7186](https://github.com/standardnotes/app/commit/d1b71861ecf5c8093cbf3d37813ad7ab514edc42))
|
||||
|
||||
## [3.50.6](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-21)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* revert webview alert changes ([#1606](https://github.com/standardnotes/app/issues/1606)) ([ee0d444](https://github.com/standardnotes/app/commit/ee0d44405d14505e043aae2c63848bae1c14f1c3))
|
||||
* tag input auto-submitting when pressing space ([#1608](https://github.com/standardnotes/app/issues/1608)) ([581a08c](https://github.com/standardnotes/app/commit/581a08cd09e02354676d9c14058475e71be05175))
|
||||
|
||||
## [3.50.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-21)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **web:** subscription sharing copy ([271a8d1](https://github.com/standardnotes/app/commit/271a8d1d70d25e4d5bdc7e3ad5cfffb2a5cb4f01))
|
||||
|
||||
## [3.50.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/web",
|
||||
"version": "3.50.4",
|
||||
"version": "3.55.2",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"main": "dist/app.js",
|
||||
"author": "Standard Notes.",
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta content="IE=edge" http-equiv="X-UA-Compatible"/>
|
||||
<meta content="width=device-width, initial-scale=1" name="viewport"/>
|
||||
<meta content="viewport-fit=cover, width=device-width, initial-scale=1" name="viewport"/>
|
||||
|
||||
<link rel="canonical" href="https://app.standardnotes.com" />
|
||||
|
||||
|
||||
+3
-35
@@ -45,9 +45,7 @@ const WorkspaceSwitcherMenu: FunctionComponent<Props> = ({
|
||||
|
||||
const signoutAll = useCallback(async () => {
|
||||
const confirmed = await viewControllerManager.application.alertService.confirm(
|
||||
`Are you sure you want to sign out of all workspaces on this device?${
|
||||
viewControllerManager.application.isNativeMobileWeb() && '<b> Your app will quit after sign out completes.</b>'
|
||||
}`,
|
||||
'Are you sure you want to sign out of all workspaces on this device?',
|
||||
undefined,
|
||||
'Sign out all',
|
||||
ButtonType.Danger,
|
||||
@@ -64,44 +62,14 @@ const WorkspaceSwitcherMenu: FunctionComponent<Props> = ({
|
||||
|
||||
const activateWorkspace = useCallback(
|
||||
async (descriptor: ApplicationDescriptor) => {
|
||||
if (viewControllerManager.application.isNativeMobileWeb()) {
|
||||
const confirmed = await viewControllerManager.application.alertService.confirm(
|
||||
'<b>The app needs to be restarted to activate the workspace</b>',
|
||||
undefined,
|
||||
'Quit app and activate workspace',
|
||||
ButtonType.Danger,
|
||||
)
|
||||
|
||||
if (confirmed) {
|
||||
void mainApplicationGroup.unloadCurrentAndActivateDescriptor(descriptor)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
void mainApplicationGroup.unloadCurrentAndActivateDescriptor(descriptor)
|
||||
},
|
||||
[mainApplicationGroup, viewControllerManager.application],
|
||||
[mainApplicationGroup],
|
||||
)
|
||||
|
||||
const addAnotherWorkspace = useCallback(async () => {
|
||||
if (viewControllerManager.application.isNativeMobileWeb()) {
|
||||
const confirmed = await viewControllerManager.application.alertService.confirm(
|
||||
'<b>The app needs to be restarted to add another workspace</b>',
|
||||
undefined,
|
||||
'Quit app and add new workspace',
|
||||
ButtonType.Danger,
|
||||
)
|
||||
|
||||
if (confirmed) {
|
||||
void mainApplicationGroup.unloadCurrentAndCreateNewDescriptor()
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
void mainApplicationGroup.unloadCurrentAndCreateNewDescriptor()
|
||||
}, [mainApplicationGroup, viewControllerManager.application])
|
||||
}, [mainApplicationGroup])
|
||||
|
||||
return (
|
||||
<Menu a11yLabel="Workspace switcher menu" className="px-0 focus:shadow-none" isOpen={isOpen}>
|
||||
|
||||
@@ -5,6 +5,7 @@ import { FunctionComponent, useCallback, useRef, useState } from 'react'
|
||||
import Icon from '@/Components/Icon/Icon'
|
||||
import ChangeEditorMenu from './ChangeEditorMenu'
|
||||
import Popover from '../Popover/Popover'
|
||||
import { classNames } from '@/Utils/ConcatenateClassNames'
|
||||
|
||||
type Props = {
|
||||
application: WebApplication
|
||||
@@ -21,6 +22,12 @@ const ChangeEditorButton: FunctionComponent<Props> = ({
|
||||
const [isOpen, setIsOpen] = useState(false)
|
||||
const buttonRef = useRef<HTMLButtonElement>(null)
|
||||
const containerRef = useRef<HTMLDivElement>(null)
|
||||
const [selectedEditor, setSelectedEditor] = useState(() => {
|
||||
return note ? application.componentManager.editorForNote(note) : undefined
|
||||
})
|
||||
const [selectedEditorIcon, selectedEditorIconTint] = application.iconsController.getIconAndTintForNoteType(
|
||||
selectedEditor?.package_info.note_type,
|
||||
)
|
||||
|
||||
const toggleMenu = useCallback(async () => {
|
||||
const willMenuOpen = !isOpen
|
||||
@@ -33,13 +40,16 @@ const ChangeEditorButton: FunctionComponent<Props> = ({
|
||||
return (
|
||||
<div ref={containerRef}>
|
||||
<button
|
||||
className="bg-text-padding flex h-8 min-w-8 cursor-pointer items-center justify-center rounded-full border border-solid border-border text-neutral hover:bg-contrast focus:bg-contrast"
|
||||
className={classNames(
|
||||
'bg-text-padding flex h-8 min-w-8 cursor-pointer items-center justify-center rounded-full border border-solid text-neutral hover:bg-contrast focus:bg-contrast',
|
||||
`border-accessory-tint-${selectedEditorIconTint}`,
|
||||
)}
|
||||
title="Change note type"
|
||||
aria-label="Change note type"
|
||||
onClick={toggleMenu}
|
||||
ref={buttonRef}
|
||||
>
|
||||
<Icon type="dashboard" />
|
||||
<Icon type={selectedEditorIcon} className={`text-accessory-tint-${selectedEditorIconTint}`} />
|
||||
</button>
|
||||
<Popover togglePopover={toggleMenu} anchorElement={buttonRef.current} open={isOpen} className="pt-2 md:pt-0">
|
||||
<ChangeEditorMenu
|
||||
@@ -49,6 +59,9 @@ const ChangeEditorButton: FunctionComponent<Props> = ({
|
||||
closeMenu={() => {
|
||||
setIsOpen(false)
|
||||
}}
|
||||
onSelect={(component) => {
|
||||
setSelectedEditor(component)
|
||||
}}
|
||||
/>
|
||||
</Popover>
|
||||
</div>
|
||||
|
||||
@@ -31,11 +31,18 @@ type ChangeEditorMenuProps = {
|
||||
closeMenu: () => void
|
||||
isVisible: boolean
|
||||
note: SNNote | undefined
|
||||
onSelect?: (component: SNComponent | undefined) => void
|
||||
}
|
||||
|
||||
const getGroupId = (group: EditorMenuGroup) => group.title.toLowerCase().replace(/\s/, '-')
|
||||
|
||||
const ChangeEditorMenu: FunctionComponent<ChangeEditorMenuProps> = ({ application, closeMenu, isVisible, note }) => {
|
||||
const ChangeEditorMenu: FunctionComponent<ChangeEditorMenuProps> = ({
|
||||
application,
|
||||
closeMenu,
|
||||
isVisible,
|
||||
note,
|
||||
onSelect,
|
||||
}) => {
|
||||
const editors = useMemo(
|
||||
() =>
|
||||
application.componentManager.componentsForArea(ComponentArea.Editor).sort((a, b) => {
|
||||
@@ -162,8 +169,12 @@ const ChangeEditorMenu: FunctionComponent<ChangeEditorMenuProps> = ({ applicatio
|
||||
}
|
||||
|
||||
closeMenu()
|
||||
|
||||
if (onSelect) {
|
||||
onSelect(itemToBeSelected.component)
|
||||
}
|
||||
},
|
||||
[application.componentManager, closeMenu, currentEditor, note, premiumModal, selectComponent],
|
||||
[application.componentManager, closeMenu, currentEditor, note, onSelect, premiumModal, selectComponent],
|
||||
)
|
||||
|
||||
return (
|
||||
|
||||
@@ -41,15 +41,7 @@ const ConfirmSignoutModal: FunctionComponent<Props> = ({ application, viewContro
|
||||
<AlertDialogLabel className="sk-h3 sk-panel-section-title">Sign out workspace?</AlertDialogLabel>
|
||||
<AlertDialogDescription className="sk-panel-row">
|
||||
<div>
|
||||
<p className="text-foreground">
|
||||
{STRING_SIGN_OUT_CONFIRMATION}
|
||||
{application.isNativeMobileWeb() && (
|
||||
<div className="font-bold">
|
||||
<br />
|
||||
Your app will quit after sign out completes.
|
||||
</div>
|
||||
)}
|
||||
</p>
|
||||
<p className="text-foreground">{STRING_SIGN_OUT_CONFIRMATION}</p>
|
||||
{showWorkspaceWarning && (
|
||||
<>
|
||||
<br />
|
||||
|
||||
@@ -185,13 +185,13 @@ const ContentListView: FunctionComponent<Props> = ({
|
||||
<div
|
||||
id="items-column"
|
||||
className={classNames(
|
||||
'sn-component section app-column flex h-screen flex-col md:h-full',
|
||||
'sn-component section app-column flex h-screen flex-col pt-safe-top md:h-full',
|
||||
'xl:w-87.5 xsm-only:!w-full sm-only:!w-full pointer-coarse:md-only:!w-52 pointer-coarse:lg-only:!w-52',
|
||||
)}
|
||||
aria-label={'Notes & Files'}
|
||||
ref={itemsViewPanelRef}
|
||||
>
|
||||
<ResponsivePaneContent paneId={AppPaneId.Items} className="min-h-[85vh]">
|
||||
<ResponsivePaneContent paneId={AppPaneId.Items}>
|
||||
<div id="items-title-bar" className="section-title-bar border-b border-solid border-border">
|
||||
<div id="items-title-bar-container">
|
||||
<input
|
||||
|
||||
@@ -28,16 +28,12 @@ const FileView = ({ application, viewControllerManager, file }: FileViewProps) =
|
||||
}, [application, file])
|
||||
|
||||
return shouldShowProtectedOverlay ? (
|
||||
<div aria-label="Note" className="section editor sn-component">
|
||||
<div className="flex h-full items-center justify-center">
|
||||
<ProtectedItemOverlay
|
||||
viewControllerManager={viewControllerManager}
|
||||
hasProtectionSources={application.hasProtectionSources()}
|
||||
onViewItem={dismissProtectedOverlay}
|
||||
itemType={'note'}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<ProtectedItemOverlay
|
||||
viewControllerManager={viewControllerManager}
|
||||
hasProtectionSources={application.hasProtectionSources()}
|
||||
onViewItem={dismissProtectedOverlay}
|
||||
itemType={'file'}
|
||||
/>
|
||||
) : (
|
||||
<FileViewWithoutProtection application={application} viewControllerManager={viewControllerManager} file={file} />
|
||||
)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { IconType } from '@standardnotes/snjs'
|
||||
|
||||
export const PremiumFeatureIconName: IconType = 'asterisk'
|
||||
export const PremiumFeatureIconClass = 'text-info'
|
||||
export const PremiumFeatureIconClass = 'text-info group-disabled:text-passive-2'
|
||||
|
||||
@@ -11,6 +11,7 @@ import { AppPaneId } from '@/Components/ResponsivePane/AppPaneMetadata'
|
||||
import { classNames } from '@/Utils/ConcatenateClassNames'
|
||||
import Icon from '../Icon/Icon'
|
||||
import { useResponsiveAppPane } from '../ResponsivePane/ResponsivePaneProvider'
|
||||
import { isIOS } from '@/Utils'
|
||||
|
||||
type Props = {
|
||||
application: WebApplication
|
||||
@@ -22,6 +23,15 @@ const Navigation: FunctionComponent<Props> = ({ application }) => {
|
||||
const [panelWidth, setPanelWidth] = useState<number>(0)
|
||||
const { toggleAppPane } = useResponsiveAppPane()
|
||||
|
||||
const [hasPasscode, setHasPasscode] = useState(() => application.hasPasscode())
|
||||
useEffect(() => {
|
||||
const removeObserver = application.addEventObserver(async () => {
|
||||
setHasPasscode(application.hasPasscode())
|
||||
}, ApplicationEvent.KeyStatusChanged)
|
||||
|
||||
return removeObserver
|
||||
}, [application])
|
||||
|
||||
useEffect(() => {
|
||||
const removeObserver = application.addEventObserver(async () => {
|
||||
const width = application.getPreference(PrefKey.TagsPanelWidth)
|
||||
@@ -51,7 +61,10 @@ const Navigation: FunctionComponent<Props> = ({ application }) => {
|
||||
return (
|
||||
<div
|
||||
id="navigation"
|
||||
className="sn-component section app-column h-screen max-h-screen w-[220px] overflow-hidden pb-8 md:h-full md:min-h-0 md:py-0 xsm-only:!w-full sm-only:!w-full"
|
||||
className={classNames(
|
||||
'sn-component section app-column h-screen max-h-screen w-[220px] overflow-hidden pt-safe-top md:h-full md:min-h-0 md:py-0 xsm-only:!w-full sm-only:!w-full',
|
||||
isIOS() ? 'pb-safe-bottom' : 'pb-2.5',
|
||||
)}
|
||||
ref={ref}
|
||||
>
|
||||
<ResponsivePaneContent paneId={AppPaneId.Navigation} contentElementId="navigation-content">
|
||||
@@ -87,20 +100,41 @@ const Navigation: FunctionComponent<Props> = ({ application }) => {
|
||||
onClick={() => {
|
||||
viewControllerManager.accountMenuController.toggleShow()
|
||||
}}
|
||||
title="Go to items list"
|
||||
aria-label="Go to items list"
|
||||
title="Go to account menu"
|
||||
aria-label="Go to account menu"
|
||||
>
|
||||
<Icon type="account-circle" />
|
||||
</button>
|
||||
{hasPasscode && (
|
||||
<button
|
||||
id="lock-item"
|
||||
onClick={() => application.lock()}
|
||||
title="Locks application and wipes unencrypted data from memory."
|
||||
aria-label="Locks application and wipes unencrypted data from memory."
|
||||
className="ml-2.5 flex h-8 min-w-8 cursor-pointer items-center justify-center rounded-full border border-solid border-border bg-default text-neutral hover:bg-contrast focus:bg-contrast"
|
||||
>
|
||||
<Icon type="lock-filled" size="custom" className="h-4.5 w-4.5" />
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
className="ml-2.5 flex h-8 min-w-8 cursor-pointer items-center justify-center rounded-full border border-solid border-border bg-default text-neutral hover:bg-contrast focus:bg-contrast"
|
||||
onClick={() => {
|
||||
viewControllerManager.preferencesController.openPreferences()
|
||||
}}
|
||||
title="Go to preferences"
|
||||
aria-label="Go to preferences"
|
||||
>
|
||||
<Icon type="tune" />
|
||||
</button>
|
||||
<button
|
||||
className="ml-2.5 flex h-8 min-w-8 cursor-pointer items-center justify-center rounded-full border border-solid border-border bg-default text-neutral hover:bg-contrast focus:bg-contrast"
|
||||
onClick={() => {
|
||||
viewControllerManager.quickSettingsMenuController.toggle()
|
||||
}}
|
||||
title="Go to items list"
|
||||
aria-label="Go to items list"
|
||||
title="Go to quick settings menu"
|
||||
aria-label="Go to quick settings menu"
|
||||
>
|
||||
<Icon type="tune" />
|
||||
<Icon type="themes" />
|
||||
</button>
|
||||
</div>
|
||||
</ResponsivePaneContent>
|
||||
|
||||
@@ -91,7 +91,7 @@ class NoteGroupView extends PureComponent<Props, State> {
|
||||
return (
|
||||
<div
|
||||
id={ElementIds.EditorColumn}
|
||||
className="app-column app-column-third flex min-h-screen flex-col md:h-full md:min-h-0"
|
||||
className="app-column app-column-third flex min-h-screen flex-col pt-safe-top md:h-full md:min-h-0"
|
||||
>
|
||||
<ResponsivePaneContent paneId={AppPaneId.Editor} className="flex-grow">
|
||||
{this.state.showMultipleSelectedNotes && (
|
||||
|
||||
@@ -874,18 +874,12 @@ class NoteView extends PureComponent<NoteViewProps, State> {
|
||||
override render() {
|
||||
if (this.state.showProtectedWarning) {
|
||||
return (
|
||||
<div aria-label="Note" className="section editor sn-component">
|
||||
{this.state.showProtectedWarning && (
|
||||
<div className="flex h-full items-center justify-center">
|
||||
<ProtectedItemOverlay
|
||||
viewControllerManager={this.viewControllerManager}
|
||||
hasProtectionSources={this.application.hasProtectionSources()}
|
||||
onViewItem={this.dismissProtectedWarning}
|
||||
itemType={'note'}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<ProtectedItemOverlay
|
||||
viewControllerManager={this.viewControllerManager}
|
||||
hasProtectionSources={this.application.hasProtectionSources()}
|
||||
onViewItem={this.dismissProtectedWarning}
|
||||
itemType={'note'}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -57,9 +57,8 @@ const PositionedPopoverContent = ({
|
||||
<Portal>
|
||||
<div
|
||||
className={classNames(
|
||||
'absolute top-0 left-0 flex h-full w-full min-w-80 cursor-auto flex-col overflow-y-auto rounded bg-default shadow-main md:h-auto md:max-w-xs',
|
||||
'safe-area-padding absolute top-0 left-0 flex h-full w-full min-w-80 cursor-auto flex-col overflow-y-auto rounded bg-default shadow-main md:h-auto md:max-w-xs',
|
||||
overrideZIndex ? overrideZIndex : 'z-dropdown-menu',
|
||||
className,
|
||||
)}
|
||||
style={{
|
||||
...styles,
|
||||
@@ -71,15 +70,17 @@ const PositionedPopoverContent = ({
|
||||
}}
|
||||
data-popover={id}
|
||||
>
|
||||
<div className="md:hidden">
|
||||
<div className="flex items-center justify-end px-3">
|
||||
<button className="rounded-full border border-border p-1" onClick={togglePopover}>
|
||||
<Icon type="close" className="h-4 w-4" />
|
||||
</button>
|
||||
<div className={className}>
|
||||
<div className="md:hidden">
|
||||
<div className="flex items-center justify-end px-3">
|
||||
<button className="rounded-full border border-border p-1" onClick={togglePopover}>
|
||||
<Icon type="close" className="h-4 w-4" />
|
||||
</button>
|
||||
</div>
|
||||
<HorizontalSeparator classes="my-2" />
|
||||
</div>
|
||||
<HorizontalSeparator classes="my-2" />
|
||||
{children}
|
||||
</div>
|
||||
{children}
|
||||
</div>
|
||||
</Portal>
|
||||
)
|
||||
|
||||
+2
@@ -9,6 +9,7 @@ import SignOutWrapper from './SignOutView'
|
||||
import FilesSection from './Files'
|
||||
import PreferencesPane from '../../PreferencesComponents/PreferencesPane'
|
||||
import SubscriptionSharing from './SubscriptionSharing/SubscriptionSharing'
|
||||
import Email from './Email'
|
||||
|
||||
type Props = {
|
||||
application: WebApplication
|
||||
@@ -30,6 +31,7 @@ const AccountPreferences = ({ application, viewControllerManager }: Props) => (
|
||||
{application.hasAccount() && viewControllerManager.featuresController.hasFiles && (
|
||||
<FilesSection application={application} />
|
||||
)}
|
||||
<Email application={application} />
|
||||
<SignOutWrapper application={application} viewControllerManager={viewControllerManager} />
|
||||
</PreferencesPane>
|
||||
)
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
import { MuteMarketingEmailsOption, MuteSignInEmailsOption, SettingName } from '@standardnotes/snjs'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { FunctionComponent, useCallback, useEffect, useState } from 'react'
|
||||
|
||||
import HorizontalSeparator from '@/Components/Shared/HorizontalSeparator'
|
||||
import Switch from '@/Components/Switch/Switch'
|
||||
import { Subtitle, Text, Title } from '@/Components/Preferences/PreferencesComponents/Content'
|
||||
import { WebApplication } from '@/Application/Application'
|
||||
import { STRING_FAILED_TO_UPDATE_USER_SETTING } from '@/Constants/Strings'
|
||||
import PreferencesGroup from '@/Components/Preferences/PreferencesComponents/PreferencesGroup'
|
||||
import PreferencesSegment from '@/Components/Preferences/PreferencesComponents/PreferencesSegment'
|
||||
import Spinner from '@/Components/Spinner/Spinner'
|
||||
|
||||
type Props = {
|
||||
application: WebApplication
|
||||
}
|
||||
|
||||
const Email: FunctionComponent<Props> = ({ application }: Props) => {
|
||||
const [signInEmailsMutedValue, setSignInEmailsMutedValue] = useState(MuteSignInEmailsOption.NotMuted)
|
||||
const [marketingEmailsMutedValue, setMarketingEmailsMutedValue] = useState(MuteMarketingEmailsOption.NotMuted)
|
||||
const [isLoading, setIsLoading] = useState(true)
|
||||
|
||||
const updateSetting = async (settingName: SettingName, payload: string): Promise<boolean> => {
|
||||
try {
|
||||
await application.settings.updateSetting(settingName, payload, false)
|
||||
return true
|
||||
} catch (e) {
|
||||
application.alertService.alert(STRING_FAILED_TO_UPDATE_USER_SETTING).catch(console.error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
const loadSettings = useCallback(async () => {
|
||||
if (!application.getUser()) {
|
||||
return
|
||||
}
|
||||
setIsLoading(true)
|
||||
|
||||
try {
|
||||
const userSettings = await application.settings.listSettings()
|
||||
setSignInEmailsMutedValue(
|
||||
userSettings.getSettingValue<MuteSignInEmailsOption>(
|
||||
SettingName.MuteSignInEmails,
|
||||
MuteSignInEmailsOption.NotMuted,
|
||||
),
|
||||
),
|
||||
setMarketingEmailsMutedValue(
|
||||
userSettings.getSettingValue<MuteMarketingEmailsOption>(
|
||||
SettingName.MuteMarketingEmails,
|
||||
MuteMarketingEmailsOption.NotMuted,
|
||||
),
|
||||
)
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
} finally {
|
||||
setIsLoading(false)
|
||||
}
|
||||
}, [application])
|
||||
|
||||
useEffect(() => {
|
||||
loadSettings().catch(console.error)
|
||||
}, [loadSettings])
|
||||
|
||||
const toggleMuteSignInEmails = async () => {
|
||||
const previousValue = signInEmailsMutedValue
|
||||
const newValue =
|
||||
previousValue === MuteSignInEmailsOption.Muted ? MuteSignInEmailsOption.NotMuted : MuteSignInEmailsOption.Muted
|
||||
setSignInEmailsMutedValue(newValue)
|
||||
|
||||
const updateResult = await updateSetting(SettingName.MuteSignInEmails, newValue)
|
||||
|
||||
if (!updateResult) {
|
||||
setSignInEmailsMutedValue(previousValue)
|
||||
}
|
||||
}
|
||||
|
||||
const toggleMuteMarketingEmails = async () => {
|
||||
const previousValue = marketingEmailsMutedValue
|
||||
const newValue =
|
||||
previousValue === MuteMarketingEmailsOption.Muted
|
||||
? MuteMarketingEmailsOption.NotMuted
|
||||
: MuteMarketingEmailsOption.Muted
|
||||
setMarketingEmailsMutedValue(newValue)
|
||||
|
||||
const updateResult = await updateSetting(SettingName.MuteMarketingEmails, newValue)
|
||||
|
||||
if (!updateResult) {
|
||||
setMarketingEmailsMutedValue(previousValue)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<PreferencesGroup>
|
||||
<PreferencesSegment>
|
||||
<Title>Email</Title>
|
||||
<div>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex flex-col">
|
||||
<Subtitle>Disable sign-in notification emails</Subtitle>
|
||||
<Text>
|
||||
Disables email notifications when a new sign-in occurs on your account. (Email notifications are
|
||||
available to paid subscribers).
|
||||
</Text>
|
||||
</div>
|
||||
{isLoading ? (
|
||||
<Spinner className="ml-2 flex-shrink-0" />
|
||||
) : (
|
||||
<Switch
|
||||
onChange={toggleMuteSignInEmails}
|
||||
checked={signInEmailsMutedValue === MuteSignInEmailsOption.Muted}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<HorizontalSeparator classes="my-4" />
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex flex-col">
|
||||
<Subtitle>Disable marketing notification emails</Subtitle>
|
||||
<Text>Disables email notifications with special deals and promotions.</Text>
|
||||
</div>
|
||||
{isLoading ? (
|
||||
<Spinner className="ml-2 flex-shrink-0" />
|
||||
) : (
|
||||
<Switch
|
||||
onChange={toggleMuteMarketingEmails}
|
||||
checked={marketingEmailsMutedValue === MuteMarketingEmailsOption.Muted}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</PreferencesSegment>
|
||||
</PreferencesGroup>
|
||||
)
|
||||
}
|
||||
|
||||
export default observer(Email)
|
||||
+2
-2
@@ -51,7 +51,7 @@ const InvitationsList = ({ subscriptionState, application }: Props) => {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<SubtitleLight className="mb-2 text-info">Active Invitations:</SubtitleLight>
|
||||
<SubtitleLight className="mb-2 text-info">Active Invites:</SubtitleLight>
|
||||
{activeSubscriptions?.map((invitation) => (
|
||||
<div key={invitation.uuid} className="mt-1 mb-4">
|
||||
<Text>
|
||||
@@ -64,7 +64,7 @@ const InvitationsList = ({ subscriptionState, application }: Props) => {
|
||||
))}
|
||||
{!!inActiveSubscriptions?.length && (
|
||||
<>
|
||||
<SubtitleLight className="mb-2 text-info">Inactive Invitations:</SubtitleLight>
|
||||
<SubtitleLight className="mb-2 text-info">Inactive Invites:</SubtitleLight>
|
||||
<div>
|
||||
{inActiveSubscriptions?.map((invitation) => (
|
||||
<div key={invitation.uuid} className="mb-3 first:mt-2">
|
||||
|
||||
+3
-3
@@ -13,7 +13,7 @@ import InviteForm from './InviteForm'
|
||||
import InviteSuccess from './InviteSuccess'
|
||||
|
||||
enum SubmitButtonTitles {
|
||||
Default = 'Send Invitation',
|
||||
Default = 'Send Invite',
|
||||
Sending = 'Sending...',
|
||||
Finish = 'Finish',
|
||||
}
|
||||
@@ -96,7 +96,7 @@ const Invite: FunctionComponent<Props> = ({ onCloseDialog, application, subscrip
|
||||
const success = await processInvite()
|
||||
if (!success) {
|
||||
application.alertService
|
||||
.alert('We could not send the invitation. Please try again or contact support if the issue persists.')
|
||||
.alert('An error occurred while sending the invite. Please try again or contact support if the issue persists.')
|
||||
.catch(console.error)
|
||||
|
||||
resetProgressState()
|
||||
@@ -112,7 +112,7 @@ const Invite: FunctionComponent<Props> = ({ onCloseDialog, application, subscrip
|
||||
return (
|
||||
<div>
|
||||
<ModalDialog>
|
||||
<ModalDialogLabel closeDialog={handleDialogClose}>Invite</ModalDialogLabel>
|
||||
<ModalDialogLabel closeDialog={handleDialogClose}>Share your Subscription</ModalDialogLabel>
|
||||
<ModalDialogDescription className="flex flex-row items-center px-4.5">
|
||||
{currentStep === Steps.InitialStep && <InviteForm setInviteeEmail={setInviteeEmail} />}
|
||||
{currentStep === Steps.FinishStep && <InviteSuccess />}
|
||||
|
||||
+2
-2
@@ -9,8 +9,8 @@ const SharingStatusText = ({ subscriptionState }: Props) => {
|
||||
|
||||
return (
|
||||
<Text className="mt-1">
|
||||
You have have used <span className="font-bold">{usedInvitationsCount}</span> out of {allowedInvitationsCount}{' '}
|
||||
subscription invitations.
|
||||
You've used <span className="font-bold">{usedInvitationsCount}</span> out of {allowedInvitationsCount}{' '}
|
||||
subscription invites.
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -126,10 +126,10 @@ const Defaults: FunctionComponent<Props> = ({ application }) => {
|
||||
{application.isNativeMobileWeb() && (
|
||||
<>
|
||||
<div className="flex flex-col">
|
||||
<Subtitle>Switch to Native View</Subtitle>
|
||||
<Subtitle>Switch to Classic Mobile Experience</Subtitle>
|
||||
<Text>
|
||||
This will close the app and fully switch to the native view next time you open it. You will be able to
|
||||
switch back from the settings.
|
||||
This will close the app and switch back to the soon-to-be removed classic mobile experience. You can opt
|
||||
back in to new experience from the app settings.
|
||||
</Text>
|
||||
<Button className="mt-3 min-w-20" label="Switch" onClick={switchToNativeView} />
|
||||
</div>
|
||||
|
||||
+2
-5
@@ -19,10 +19,8 @@ const BiometricsLock = ({ application }: Props) => {
|
||||
const [biometricsTimingOptions, setBiometricsTimingOptions] = useState(() => application.getBiometricsTimingOptions())
|
||||
|
||||
useEffect(() => {
|
||||
const getHasBiometrics = async () => {
|
||||
const appHasBiometrics = application.hasBiometrics()
|
||||
setHasBiometrics(appHasBiometrics)
|
||||
}
|
||||
const appHasBiometrics = application.hasBiometrics()
|
||||
setHasBiometrics(appHasBiometrics)
|
||||
|
||||
const hasBiometricsSupport = async () => {
|
||||
const hasBiometricsAvailable = await (
|
||||
@@ -30,7 +28,6 @@ const BiometricsLock = ({ application }: Props) => {
|
||||
).getDeviceBiometricsAvailability?.()
|
||||
setSupportsBiometrics(hasBiometricsAvailable)
|
||||
}
|
||||
void getHasBiometrics()
|
||||
void hasBiometricsSupport()
|
||||
}, [application])
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import HorizontalSeparator from '@/Components/Shared/HorizontalSeparator'
|
||||
import Switch from '@/Components/Switch/Switch'
|
||||
import { Subtitle, Text, Title } from '@/Components/Preferences/PreferencesComponents/Content'
|
||||
import { WebApplication } from '@/Application/Application'
|
||||
import { MuteSignInEmailsOption, LogSessionUserAgentOption, SettingName } from '@standardnotes/snjs'
|
||||
import { LogSessionUserAgentOption, SettingName } from '@standardnotes/snjs'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { FunctionComponent, useCallback, useEffect, useState } from 'react'
|
||||
import { STRING_FAILED_TO_UPDATE_USER_SETTING } from '@/Constants/Strings'
|
||||
@@ -15,9 +15,6 @@ type Props = {
|
||||
}
|
||||
|
||||
const Privacy: FunctionComponent<Props> = ({ application }: Props) => {
|
||||
const [signInEmailsMutedValue, setSignInEmailsMutedValue] = useState<MuteSignInEmailsOption>(
|
||||
MuteSignInEmailsOption.NotMuted,
|
||||
)
|
||||
const [sessionUaLoggingValue, setSessionUaLoggingValue] = useState<LogSessionUserAgentOption>(
|
||||
LogSessionUserAgentOption.Enabled,
|
||||
)
|
||||
@@ -41,12 +38,6 @@ const Privacy: FunctionComponent<Props> = ({ application }: Props) => {
|
||||
|
||||
try {
|
||||
const userSettings = await application.settings.listSettings()
|
||||
setSignInEmailsMutedValue(
|
||||
userSettings.getSettingValue<MuteSignInEmailsOption>(
|
||||
SettingName.MuteSignInEmails,
|
||||
MuteSignInEmailsOption.NotMuted,
|
||||
),
|
||||
)
|
||||
setSessionUaLoggingValue(
|
||||
userSettings.getSettingValue<LogSessionUserAgentOption>(
|
||||
SettingName.LogSessionUserAgent,
|
||||
@@ -64,19 +55,6 @@ const Privacy: FunctionComponent<Props> = ({ application }: Props) => {
|
||||
loadSettings().catch(console.error)
|
||||
}, [loadSettings])
|
||||
|
||||
const toggleMuteSignInEmails = async () => {
|
||||
const previousValue = signInEmailsMutedValue
|
||||
const newValue =
|
||||
previousValue === MuteSignInEmailsOption.Muted ? MuteSignInEmailsOption.NotMuted : MuteSignInEmailsOption.Muted
|
||||
setSignInEmailsMutedValue(newValue)
|
||||
|
||||
const updateResult = await updateSetting(SettingName.MuteSignInEmails, newValue)
|
||||
|
||||
if (!updateResult) {
|
||||
setSignInEmailsMutedValue(previousValue)
|
||||
}
|
||||
}
|
||||
|
||||
const toggleSessionLogging = async () => {
|
||||
const previousValue = sessionUaLoggingValue
|
||||
const newValue =
|
||||
@@ -97,23 +75,6 @@ const Privacy: FunctionComponent<Props> = ({ application }: Props) => {
|
||||
<PreferencesSegment>
|
||||
<Title>Privacy</Title>
|
||||
<div>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex flex-col">
|
||||
<Subtitle>Disable sign-in notification emails</Subtitle>
|
||||
<Text>
|
||||
Disables email notifications when a new sign-in occurs on your account. (Email notifications are
|
||||
available to paid subscribers).
|
||||
</Text>
|
||||
</div>
|
||||
{isLoading ? (
|
||||
<Spinner className="ml-2 flex-shrink-0" />
|
||||
) : (
|
||||
<Switch
|
||||
onChange={toggleMuteSignInEmails}
|
||||
checked={signInEmailsMutedValue === MuteSignInEmailsOption.Muted}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<HorizontalSeparator classes="my-4" />
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex flex-col">
|
||||
|
||||
@@ -8,7 +8,9 @@ import { PreferencesProps } from './PreferencesProps'
|
||||
const PreferencesCanvas: FunctionComponent<PreferencesProps & { menu: PreferencesMenu }> = (props) => (
|
||||
<div className="flex min-h-0 flex-grow flex-col-reverse md:flex-row md:justify-between">
|
||||
<PreferencesMenuView menu={props.menu} />
|
||||
<PaneSelector {...props} />
|
||||
<div className="min-h-0 flex-grow overflow-auto bg-contrast">
|
||||
<PaneSelector {...props} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ const PreferencesPane: FunctionComponent<{ children?: ReactNode }> = ({ children
|
||||
{children != undefined && Array.isArray(children) ? children.filter((child) => child != undefined) : children}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex-shrink basis-[13.75rem]" />
|
||||
<div className="hidden flex-shrink basis-[13.75rem] md:block" />
|
||||
</div>
|
||||
)
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ const PreferencesMenuView: FunctionComponent<Props> = ({ menu }) => {
|
||||
)
|
||||
|
||||
return (
|
||||
<div className="border-t border-border bg-default px-5 pt-2 pb-6 md:border-0 md:bg-transparent md:px-0 md:py-0">
|
||||
<div className="border-t border-border bg-default px-5 pt-2 md:border-0 md:bg-contrast md:px-0 md:py-0">
|
||||
<div className="hidden min-w-55 flex-col overflow-y-auto px-3 py-6 md:flex">
|
||||
{menuItems.map((pref) => (
|
||||
<PreferencesMenuItem
|
||||
|
||||
@@ -4,8 +4,9 @@ import { observer } from 'mobx-react-lite'
|
||||
import { PreferencesMenu } from './PreferencesMenu'
|
||||
import PreferencesCanvas from './PreferencesCanvas'
|
||||
import { PreferencesProps } from './PreferencesProps'
|
||||
import { fitNodeToMobileScreen } from '@/Utils'
|
||||
import { fitNodeToMobileScreen, isIOS } from '@/Utils'
|
||||
import { useDisableBodyScrollOnMobile } from '@/Hooks/useDisableBodyScrollOnMobile'
|
||||
import { classNames } from '@/Utils/ConcatenateClassNames'
|
||||
|
||||
const PreferencesView: FunctionComponent<PreferencesProps> = (props) => {
|
||||
const menu = useMemo(
|
||||
@@ -31,7 +32,10 @@ const PreferencesView: FunctionComponent<PreferencesProps> = (props) => {
|
||||
|
||||
return (
|
||||
<div
|
||||
className="absolute top-0 left-0 z-preferences flex h-full max-h-screen w-full flex-col bg-contrast"
|
||||
className={classNames(
|
||||
'absolute top-0 left-0 z-preferences flex h-full max-h-screen w-full flex-col bg-default pt-safe-top',
|
||||
isIOS() ? 'pb-safe-bottom' : 'pb-2 md:pb-0',
|
||||
)}
|
||||
ref={fitNodeToMobileScreen}
|
||||
>
|
||||
<div className="flex w-full flex-row items-center justify-between border-b border-solid border-border bg-default px-3 py-2 md:p-3">
|
||||
|
||||
+26
-18
@@ -1,5 +1,6 @@
|
||||
import { ViewControllerManager } from '@/Controllers/ViewControllerManager'
|
||||
import Button from '@/Components/Button/Button'
|
||||
import MobileItemsListButton from '../NoteGroupView/MobileItemsListButton'
|
||||
|
||||
type Props = {
|
||||
viewControllerManager: ViewControllerManager
|
||||
@@ -14,24 +15,31 @@ const ProtectedItemOverlay = ({ viewControllerManager, onViewItem, hasProtection
|
||||
: `Add a passcode or create an account to require authentication to view this ${itemType}.`
|
||||
|
||||
return (
|
||||
<div className="flex max-w-md flex-col items-center justify-center text-center">
|
||||
<h1 className="m-0 w-full text-2xl font-bold">This {itemType} is protected</h1>
|
||||
<p className="mt-2 w-full text-lg">{instructionText}</p>
|
||||
<div className="mt-4 flex gap-3">
|
||||
{!hasProtectionSources && (
|
||||
<Button
|
||||
primary
|
||||
small
|
||||
onClick={() => {
|
||||
viewControllerManager.accountMenuController.setShow(true)
|
||||
}}
|
||||
>
|
||||
Open account menu
|
||||
</Button>
|
||||
)}
|
||||
<Button small onClick={onViewItem}>
|
||||
{hasProtectionSources ? 'Authenticate' : `View ${itemType}`}
|
||||
</Button>
|
||||
<div aria-label="Protected overlay" className="section editor sn-component">
|
||||
<div className="flex h-full flex-grow flex-col justify-center md:flex-row md:items-center">
|
||||
<div className="mb-auto p-4 md:hidden">
|
||||
<MobileItemsListButton />
|
||||
</div>
|
||||
<div className="mb-auto flex max-w-md flex-col items-center justify-center text-center md:mb-0">
|
||||
<h1 className="m-0 w-full text-2xl font-bold">This {itemType} is protected</h1>
|
||||
<p className="mt-2 w-full text-lg">{instructionText}</p>
|
||||
<div className="mt-4 flex gap-3">
|
||||
{!hasProtectionSources && (
|
||||
<Button
|
||||
primary
|
||||
small
|
||||
onClick={() => {
|
||||
viewControllerManager.accountMenuController.setShow(true)
|
||||
}}
|
||||
>
|
||||
Open account menu
|
||||
</Button>
|
||||
)}
|
||||
<Button small onClick={onViewItem}>
|
||||
{hasProtectionSources ? 'Authenticate' : `View ${itemType}`}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -5,6 +5,7 @@ import Icon from '@/Components/Icon/Icon'
|
||||
import { usePremiumModal } from '@/Hooks/usePremiumModal'
|
||||
import Switch from '@/Components/Switch/Switch'
|
||||
import { PremiumFeatureIconClass, PremiumFeatureIconName } from '../Icon/PremiumFeatureIcon'
|
||||
import { isMobileScreen } from '@/Utils'
|
||||
|
||||
type Props = {
|
||||
application: WebApplication
|
||||
@@ -34,11 +35,12 @@ const FocusModeSwitch: FunctionComponent<Props> = ({ application, onToggle, onCl
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
className="flex w-full cursor-pointer items-center justify-between border-0 bg-transparent px-3 py-1.5 text-left text-sm text-text hover:bg-contrast hover:text-foreground focus:bg-info-backdrop focus:shadow-none"
|
||||
className="group flex w-full cursor-pointer items-center justify-between border-0 bg-transparent px-3 py-1.5 text-left text-sm text-text hover:bg-contrast hover:text-foreground focus:bg-info-backdrop focus:shadow-none disabled:bg-default disabled:text-passive-2"
|
||||
onClick={toggle}
|
||||
disabled={application.isNativeMobileWeb() || isMobileScreen()}
|
||||
>
|
||||
<div className="flex items-center">
|
||||
<Icon type="menu-close" className="mr-2 text-neutral" />
|
||||
<Icon type="menu-close" className="mr-2 text-neutral group-disabled:text-passive-2" />
|
||||
Focused Writing
|
||||
</div>
|
||||
{isEntitled ? (
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { WebApplication } from '@/Application/Application'
|
||||
import { FeatureStatus } from '@standardnotes/snjs'
|
||||
import { FeatureIdentifier, FeatureStatus } from '@standardnotes/snjs'
|
||||
import { FunctionComponent, MouseEventHandler, useCallback, useMemo } from 'react'
|
||||
import Icon from '@/Components/Icon/Icon'
|
||||
import { usePremiumModal } from '@/Hooks/usePremiumModal'
|
||||
@@ -7,6 +7,7 @@ import Switch from '@/Components/Switch/Switch'
|
||||
import { ThemeItem } from './ThemeItem'
|
||||
import RadioIndicator from '../RadioIndicator/RadioIndicator'
|
||||
import { PremiumFeatureIconClass, PremiumFeatureIconName } from '../Icon/PremiumFeatureIcon'
|
||||
import { isMobileScreen } from '@/Utils'
|
||||
|
||||
type Props = {
|
||||
item: ThemeItem
|
||||
@@ -43,11 +44,14 @@ const ThemesMenuButton: FunctionComponent<Props> = ({ application, item }) => {
|
||||
[application, canActivateTheme, item, premiumModal],
|
||||
)
|
||||
|
||||
const isMobile = application.isNativeMobileWeb() || isMobileScreen()
|
||||
|
||||
return (
|
||||
<button
|
||||
className={
|
||||
'flex w-full cursor-pointer items-center justify-between border-0 bg-transparent px-3 py-1.5 text-left text-sm text-text hover:bg-contrast hover:text-foreground focus:bg-info-backdrop focus:bg-info-backdrop focus:shadow-none focus:shadow-none'
|
||||
'group flex w-full cursor-pointer items-center justify-between border-0 bg-transparent px-3 py-1.5 text-left text-sm text-text hover:bg-contrast hover:text-foreground focus:bg-info-backdrop focus:shadow-none disabled:bg-default disabled:text-passive-2'
|
||||
}
|
||||
disabled={item.identifier === FeatureIdentifier.DynamicTheme && isMobile}
|
||||
onClick={toggleTheme}
|
||||
>
|
||||
{item.component?.isLayerable() ? (
|
||||
|
||||
+23
-5
@@ -1,18 +1,20 @@
|
||||
import { NoteHistoryController } from '@/Controllers/NoteHistory/NoteHistoryController'
|
||||
import { FeaturesClientInterface } from '@standardnotes/snjs'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { FunctionComponent } from 'react'
|
||||
import { FunctionComponent, useCallback } from 'react'
|
||||
import LegacyHistoryList from './LegacyHistoryList'
|
||||
import RemoteHistoryList from './RemoteHistoryList'
|
||||
import { RevisionType } from './RevisionType'
|
||||
import SessionHistoryList from './SessionHistoryList'
|
||||
import { HistoryModalMobileTab } from './utils'
|
||||
|
||||
type Props = {
|
||||
features: FeaturesClientInterface
|
||||
noteHistoryController: NoteHistoryController
|
||||
selectMobileModalTab: (tab: HistoryModalMobileTab) => void
|
||||
}
|
||||
|
||||
const HistoryListContainer: FunctionComponent<Props> = ({ features, noteHistoryController }) => {
|
||||
const HistoryListContainer: FunctionComponent<Props> = ({ features, noteHistoryController, selectMobileModalTab }) => {
|
||||
const { legacyHistory, currentTab, selectTab } = noteHistoryController
|
||||
|
||||
const TabButton: FunctionComponent<{
|
||||
@@ -34,14 +36,30 @@ const HistoryListContainer: FunctionComponent<Props> = ({ features, noteHistoryC
|
||||
)
|
||||
}
|
||||
|
||||
const onSelectRevision = useCallback(() => {
|
||||
selectMobileModalTab('Content')
|
||||
}, [selectMobileModalTab])
|
||||
|
||||
const CurrentTabList = () => {
|
||||
switch (currentTab) {
|
||||
case RevisionType.Remote:
|
||||
return <RemoteHistoryList features={features} noteHistoryController={noteHistoryController} />
|
||||
return (
|
||||
<RemoteHistoryList
|
||||
onSelectRevision={onSelectRevision}
|
||||
features={features}
|
||||
noteHistoryController={noteHistoryController}
|
||||
/>
|
||||
)
|
||||
case RevisionType.Session:
|
||||
return <SessionHistoryList noteHistoryController={noteHistoryController} />
|
||||
return <SessionHistoryList onSelectRevision={onSelectRevision} noteHistoryController={noteHistoryController} />
|
||||
case RevisionType.Legacy:
|
||||
return <LegacyHistoryList legacyHistory={legacyHistory} noteHistoryController={noteHistoryController} />
|
||||
return (
|
||||
<LegacyHistoryList
|
||||
onSelectRevision={onSelectRevision}
|
||||
legacyHistory={legacyHistory}
|
||||
noteHistoryController={noteHistoryController}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ const HistoryModalDialog = ({ children, onDismiss }: Props) => {
|
||||
>
|
||||
<DialogContent
|
||||
aria-label="Note revision history"
|
||||
className="my-0 flex h-full w-full flex-col rounded-md bg-[color:var(--modal-background-color)] p-0 shadow-lg md:max-h-[90%] md:w-[90%] md:max-w-[90%]"
|
||||
className="my-0 flex h-screen w-full flex-col rounded-md bg-[color:var(--modal-background-color)] p-0 pt-safe-top pb-safe-bottom shadow-lg md:max-h-[90%] md:w-[90%] md:max-w-[90%]"
|
||||
>
|
||||
<div className="flex h-full flex-col overflow-hidden bg-default">{children}</div>
|
||||
</DialogContent>
|
||||
|
||||
+7
-2
@@ -7,6 +7,7 @@ import HistoryModalContentPane from './HistoryModalContentPane'
|
||||
import { NoteHistoryController } from '@/Controllers/NoteHistory/NoteHistoryController'
|
||||
import Icon from '../Icon/Icon'
|
||||
import { classNames } from '@/Utils/ConcatenateClassNames'
|
||||
import { HistoryModalMobileTab } from './utils'
|
||||
|
||||
const HistoryModalDialogContent = ({
|
||||
application,
|
||||
@@ -18,7 +19,7 @@ const HistoryModalDialogContent = ({
|
||||
}: RevisionHistoryModalContentProps) => {
|
||||
const [noteHistoryController] = useState(() => new NoteHistoryController(application, note, selectionController))
|
||||
|
||||
const [selectedMobileTab, setSelectedMobileTab] = useState<'List' | 'Content'>('Content')
|
||||
const [selectedMobileTab, setSelectedMobileTab] = useState<HistoryModalMobileTab>('Content')
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -56,7 +57,11 @@ const HistoryModalDialogContent = ({
|
||||
selectedMobileTab === 'List' ? 'flex' : 'hidden',
|
||||
)}
|
||||
>
|
||||
<HistoryListContainer features={application.features} noteHistoryController={noteHistoryController} />
|
||||
<HistoryListContainer
|
||||
features={application.features}
|
||||
noteHistoryController={noteHistoryController}
|
||||
selectMobileModalTab={setSelectedMobileTab}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className={classNames(
|
||||
|
||||
@@ -7,9 +7,10 @@ import { NoteHistoryController } from '@/Controllers/NoteHistory/NoteHistoryCont
|
||||
type Props = {
|
||||
legacyHistory: Action[] | undefined
|
||||
noteHistoryController: NoteHistoryController
|
||||
onSelectRevision: () => void
|
||||
}
|
||||
|
||||
const LegacyHistoryList: FunctionComponent<Props> = ({ legacyHistory, noteHistoryController }) => {
|
||||
const LegacyHistoryList: FunctionComponent<Props> = ({ legacyHistory, noteHistoryController, onSelectRevision }) => {
|
||||
const { selectLegacyRevision, selectedEntry } = noteHistoryController
|
||||
|
||||
const legacyHistoryListRef = useRef<HTMLDivElement>(null)
|
||||
@@ -33,6 +34,7 @@ const LegacyHistoryList: FunctionComponent<Props> = ({ legacyHistory, noteHistor
|
||||
isSelected={selectedEntryUrl === url}
|
||||
onClick={() => {
|
||||
selectLegacyRevision(entry)
|
||||
onSelectRevision()
|
||||
}}
|
||||
>
|
||||
{entry.label}
|
||||
|
||||
@@ -12,9 +12,14 @@ import { PremiumFeatureIconClass, PremiumFeatureIconName } from '../Icon/Premium
|
||||
type RemoteHistoryListProps = {
|
||||
features: FeaturesClientInterface
|
||||
noteHistoryController: NoteHistoryController
|
||||
onSelectRevision: () => void
|
||||
}
|
||||
|
||||
const RemoteHistoryList: FunctionComponent<RemoteHistoryListProps> = ({ features, noteHistoryController }) => {
|
||||
const RemoteHistoryList: FunctionComponent<RemoteHistoryListProps> = ({
|
||||
features,
|
||||
noteHistoryController,
|
||||
onSelectRevision,
|
||||
}) => {
|
||||
const { remoteHistory, isFetchingRemoteHistory, selectRemoteRevision, selectedEntry } = noteHistoryController
|
||||
|
||||
const remoteHistoryListRef = useRef<HTMLDivElement>(null)
|
||||
@@ -44,6 +49,7 @@ const RemoteHistoryList: FunctionComponent<RemoteHistoryListProps> = ({ features
|
||||
isSelected={(selectedEntry as RevisionListEntry)?.uuid === entry.uuid}
|
||||
onClick={() => {
|
||||
selectRemoteRevision(entry)
|
||||
onSelectRevision()
|
||||
}}
|
||||
>
|
||||
<div className="flex flex-grow items-center justify-between">
|
||||
|
||||
@@ -6,9 +6,10 @@ import { NoteHistoryController } from '@/Controllers/NoteHistory/NoteHistoryCont
|
||||
|
||||
type Props = {
|
||||
noteHistoryController: NoteHistoryController
|
||||
onSelectRevision: () => void
|
||||
}
|
||||
|
||||
const SessionHistoryList: FunctionComponent<Props> = ({ noteHistoryController }) => {
|
||||
const SessionHistoryList: FunctionComponent<Props> = ({ noteHistoryController, onSelectRevision }) => {
|
||||
const { sessionHistory, selectedRevision, selectSessionRevision } = noteHistoryController
|
||||
|
||||
const sessionHistoryListRef = useRef<HTMLDivElement>(null)
|
||||
@@ -40,6 +41,7 @@ const SessionHistoryList: FunctionComponent<Props> = ({ noteHistoryController })
|
||||
isSelected={selectedRevision?.payload.updated_at === entry.payload.updated_at}
|
||||
onClick={() => {
|
||||
selectSessionRevision(entry)
|
||||
onSelectRevision()
|
||||
}}
|
||||
>
|
||||
{entry.previewTitle()}
|
||||
|
||||
@@ -2,6 +2,8 @@ import { DAYS_IN_A_WEEK, DAYS_IN_A_YEAR } from '@/Constants/Constants'
|
||||
import { HistoryEntry, NoteHistoryEntry, RevisionListEntry } from '@standardnotes/snjs'
|
||||
import { calculateDifferenceBetweenDatesInDays } from '../../Utils/CalculateDifferenceBetweenDatesInDays'
|
||||
|
||||
export type HistoryModalMobileTab = 'Content' | 'List'
|
||||
|
||||
export type LegacyHistoryEntry = {
|
||||
payload: HistoryEntry['payload']
|
||||
created_at: string
|
||||
|
||||
@@ -112,6 +112,8 @@ const SmartViewsListItem: FunctionComponent<Props> = ({ view, tagsState }) => {
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
className={classNames('tag py-2 px-3.5 md:py-1', isSelected && 'selected', isFaded && 'opacity-50')}
|
||||
onClick={selectCurrentTag}
|
||||
style={{
|
||||
|
||||
@@ -202,7 +202,9 @@ export const TagsListItem: FunctionComponent<Props> = observer(({ tag, features,
|
||||
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
<div
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
className={classNames(
|
||||
'tag py-2 px-3.5 focus:shadow-inner md:py-1',
|
||||
isSelected && 'selected',
|
||||
@@ -272,7 +274,7 @@ export const TagsListItem: FunctionComponent<Props> = observer(({ tag, features,
|
||||
<div className={`meta ${hasAtLeastOneFolder ? 'with-folders' : ''}`}>
|
||||
{tag.conflictOf && <div className="danger text-[0.625rem] font-bold">Conflicted Copy {tag.conflictOf}</div>}
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
{isAddingSubtag && (
|
||||
<div
|
||||
className="tag overflow-hidden"
|
||||
|
||||
@@ -116,7 +116,7 @@ export class NotesController extends AbstractViewController {
|
||||
return this.application.items.trashedItems.length
|
||||
}
|
||||
|
||||
setContextMenuOpen(open: boolean): void {
|
||||
setContextMenuOpen = (open: boolean) => {
|
||||
this.contextMenuOpen = open
|
||||
}
|
||||
|
||||
|
||||
@@ -29,9 +29,18 @@ export class PreferencesController {
|
||||
closePreferences = (): void => {
|
||||
this._open = false
|
||||
this.currentPane = DEFAULT_PANE
|
||||
this.removePreferencesToggleFromURLQueryParameters()
|
||||
}
|
||||
|
||||
get isOpen(): boolean {
|
||||
return this._open
|
||||
}
|
||||
|
||||
private removePreferencesToggleFromURLQueryParameters() {
|
||||
const urlSearchParams = new URLSearchParams(window.location.search)
|
||||
urlSearchParams.delete('settings')
|
||||
|
||||
const newUrl = `${window.location.origin}${window.location.pathname}${urlSearchParams.toString()}`
|
||||
window.history.replaceState(null, document.title, newUrl)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@ import { NavigationController } from './Navigation/NavigationController'
|
||||
import { FilePreviewModalController } from './FilePreviewModalController'
|
||||
import { SelectedItemsController } from './SelectedItemsController'
|
||||
import { HistoryModalController } from './NoteHistory/HistoryModalController'
|
||||
import { PreferenceId } from '@/Components/Preferences/PreferencesMenu'
|
||||
import { AccountMenuPane } from '@/Components/AccountMenu/AccountMenuPane'
|
||||
|
||||
export class ViewControllerManager {
|
||||
readonly enableUnfinishedFeatures: boolean = window?.enabledUnfinishedFeatures
|
||||
@@ -209,11 +211,31 @@ export class ViewControllerManager {
|
||||
|
||||
addAppEventObserver() {
|
||||
this.unsubAppEventObserver = this.application.addEventObserver(async (eventName) => {
|
||||
const urlSearchParams = new URLSearchParams(window.location.search)
|
||||
|
||||
switch (eventName) {
|
||||
case ApplicationEvent.Launched:
|
||||
if (window.location.search.includes('purchase=true')) {
|
||||
if (urlSearchParams.get('purchase')) {
|
||||
this.purchaseFlowController.openPurchaseFlow()
|
||||
}
|
||||
if (urlSearchParams.get('settings')) {
|
||||
const user = this.application.getUser()
|
||||
if (user === undefined) {
|
||||
this.accountMenuController.setShow(true)
|
||||
this.accountMenuController.setCurrentPane(AccountMenuPane.SignIn)
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
this.preferencesController.openPreferences()
|
||||
this.preferencesController.setCurrentPane(urlSearchParams.get('settings') as PreferenceId)
|
||||
}
|
||||
break
|
||||
case ApplicationEvent.SignedIn:
|
||||
if (urlSearchParams.get('settings')) {
|
||||
this.preferencesController.openPreferences()
|
||||
this.preferencesController.setCurrentPane(urlSearchParams.get('settings') as PreferenceId)
|
||||
}
|
||||
break
|
||||
case ApplicationEvent.SyncStatusChanged:
|
||||
this.syncStatusController.update(this.application.sync.getSyncStatus())
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
import { SNApplication } from '@standardnotes/snjs'
|
||||
import { Environment, SNApplication } from '@standardnotes/snjs'
|
||||
|
||||
export async function openSubscriptionDashboard(application: SNApplication) {
|
||||
const token = await application.getNewSubscriptionToken()
|
||||
if (!token) {
|
||||
return
|
||||
}
|
||||
|
||||
const url = `${window.dashboardUrl}?subscription_token=${token}`
|
||||
|
||||
if (application.deviceInterface.environment === Environment.NativeMobileWeb) {
|
||||
application.deviceInterface.openUrl(url)
|
||||
return
|
||||
}
|
||||
|
||||
export function openSubscriptionDashboard(application: SNApplication): void {
|
||||
const windowProxy = window.open('', '_blank')
|
||||
application
|
||||
.getNewSubscriptionToken()
|
||||
.then((token) => {
|
||||
if (!token) {
|
||||
return
|
||||
}
|
||||
;(windowProxy as WindowProxy).location = `${window.dashboardUrl}?subscription_token=${token}`
|
||||
})
|
||||
.catch(console.error)
|
||||
;(windowProxy as WindowProxy).location = url
|
||||
}
|
||||
|
||||
@@ -23,6 +23,11 @@
|
||||
--sn-stylekit-editor-font-family: var(--sn-stylekit-sans-serif-font);
|
||||
|
||||
--reach-checkbox: 1;
|
||||
|
||||
--safe-area-inset-top: env(safe-area-inset-top, 0);
|
||||
--safe-area-inset-bottom: env(safe-area-inset-bottom, 0);
|
||||
--safe-area-inset-left: env(safe-area-inset-left, 0);
|
||||
--safe-area-inset-right: env(safe-area-inset-right, 0);
|
||||
}
|
||||
|
||||
html {
|
||||
@@ -31,9 +36,15 @@ html {
|
||||
|
||||
body {
|
||||
font-size: var(--sn-stylekit-base-font-size);
|
||||
background-color: var(--sn-stylekit-background-color);
|
||||
color: var(--sn-stylekit-foreground-color);
|
||||
}
|
||||
|
||||
.safe-area-padding {
|
||||
padding: var(--safe-area-inset-top) var(--safe-area-inset-right) var(--safe-area-inset-bottom)
|
||||
var(--safe-area-inset-left);
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans',
|
||||
|
||||
@@ -15,6 +15,10 @@ module.exports = {
|
||||
87.5: '21.875rem',
|
||||
125: '31.25rem',
|
||||
160: '40rem',
|
||||
'safe-top': 'var(--safe-area-inset-top)',
|
||||
'safe-bottom': 'var(--safe-area-inset-bottom)',
|
||||
'safe-left': 'var(--safe-area-inset-left)',
|
||||
'safe-right': 'var(--safe-area-inset-right)',
|
||||
},
|
||||
minWidth: {
|
||||
1: '0.25rem',
|
||||
@@ -135,6 +139,12 @@ module.exports = {
|
||||
'text-accessory-tint-4',
|
||||
'text-accessory-tint-5',
|
||||
'text-accessory-tint-6',
|
||||
'border-accessory-tint-1',
|
||||
'border-accessory-tint-2',
|
||||
'border-accessory-tint-3',
|
||||
'border-accessory-tint-4',
|
||||
'border-accessory-tint-5',
|
||||
'border-accessory-tint-6',
|
||||
],
|
||||
plugins: [
|
||||
plugin(function ({ addVariant }) {
|
||||
|
||||
Reference in New Issue
Block a user