fix: dark mode not working in editors (#1773)
This commit is contained in:
@@ -21,7 +21,7 @@ export enum FeatureIdentifier {
|
||||
|
||||
AutobiographyTheme = 'org.standardnotes.theme-autobiography',
|
||||
DynamicTheme = 'org.standardnotes.theme-dynamic',
|
||||
FocusedTheme = 'org.standardnotes.theme-focus',
|
||||
DarkTheme = 'org.standardnotes.theme-focus',
|
||||
FocusMode = 'org.standardnotes.focus-mode',
|
||||
FuturaTheme = 'org.standardnotes.theme-futura',
|
||||
MidnightTheme = 'org.standardnotes.theme-midnight',
|
||||
|
||||
@@ -68,10 +68,10 @@ export function themes(): ThemeFeatureDescription[] {
|
||||
},
|
||||
})
|
||||
|
||||
const focus: ThemeFeatureDescription = FillThemeComponentDefaults({
|
||||
const dark: ThemeFeatureDescription = FillThemeComponentDefaults({
|
||||
availableInSubscriptions: [SubscriptionName.PlusPlan, SubscriptionName.ProPlan],
|
||||
name: 'Focus',
|
||||
identifier: FeatureIdentifier.FocusedTheme,
|
||||
name: 'Dark',
|
||||
identifier: FeatureIdentifier.DarkTheme,
|
||||
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',
|
||||
@@ -109,5 +109,5 @@ export function themes(): ThemeFeatureDescription[] {
|
||||
description: 'A smart theme that minimizes the tags and notes panels when they are not in use.',
|
||||
})
|
||||
|
||||
return [midnight, futura, solarizedDark, autobiography, focus, titanium, dynamic]
|
||||
return [midnight, futura, solarizedDark, autobiography, dark, titanium, dynamic]
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ describe('fileService', () => {
|
||||
crypto.xchacha20StreamEncryptorPush = jest.fn().mockReturnValue(new Uint8Array())
|
||||
})
|
||||
|
||||
it.only('should cache file after download', async () => {
|
||||
it('should cache file after download', async () => {
|
||||
const file = {
|
||||
uuid: '1',
|
||||
decryptedSize: 100_000,
|
||||
|
||||
@@ -1497,7 +1497,10 @@ export class SNApplication
|
||||
const syncEventCallback = async (eventName: ExternalServices.SyncEvent) => {
|
||||
const appEvent = applicationEventForSyncEvent(eventName)
|
||||
if (appEvent) {
|
||||
await this.protocolService.onSyncEvent(eventName)
|
||||
|
||||
await this.notifyEvent(appEvent)
|
||||
|
||||
if (appEvent === ApplicationEvent.CompletedFullSync) {
|
||||
if (!this.handledFullSyncStage) {
|
||||
this.handledFullSyncStage = true
|
||||
@@ -1505,7 +1508,6 @@ export class SNApplication
|
||||
}
|
||||
}
|
||||
}
|
||||
await this.protocolService.onSyncEvent(eventName)
|
||||
}
|
||||
const uninstall = this.syncService.addEventObserver(syncEventCallback)
|
||||
this.serviceObservers.push(uninstall)
|
||||
|
||||
@@ -44,6 +44,7 @@ import {
|
||||
SetOfflineFeaturesFunctionResponse,
|
||||
StorageKey,
|
||||
} from '@standardnotes/services'
|
||||
import { FeatureIdentifier } from '@standardnotes/features'
|
||||
|
||||
type GetOfflineSubscriptionDetailsResponse = OfflineSubscriptionEntitlements | ClientDisplayableError
|
||||
|
||||
@@ -145,7 +146,10 @@ export class SNFeaturesService
|
||||
|
||||
override async handleApplicationStage(stage: ApplicationStage): Promise<void> {
|
||||
await super.handleApplicationStage(stage)
|
||||
|
||||
if (stage === ApplicationStage.FullSyncCompleted_13) {
|
||||
void this.addDarkTheme()
|
||||
|
||||
if (!this.hasOnlineSubscription()) {
|
||||
const offlineRepo = this.getOfflineRepo()
|
||||
if (offlineRepo) {
|
||||
@@ -155,6 +159,14 @@ export class SNFeaturesService
|
||||
}
|
||||
}
|
||||
|
||||
private async addDarkTheme() {
|
||||
const darkThemeFeature = FeaturesImports.FindNativeFeature(FeatureIdentifier.DarkTheme)
|
||||
|
||||
if (darkThemeFeature) {
|
||||
await this.mapRemoteNativeFeaturesToItems([darkThemeFeature])
|
||||
}
|
||||
}
|
||||
|
||||
public enableExperimentalFeature(identifier: FeaturesImports.FeatureIdentifier): void {
|
||||
const feature = this.getUserFeature(identifier)
|
||||
if (!feature) {
|
||||
@@ -366,7 +378,7 @@ export class SNFeaturesService
|
||||
if (!arraysEqual(this.roles, roles)) {
|
||||
void this.notifyEvent(FeaturesEvent.UserRolesChanged)
|
||||
}
|
||||
await this.storageService.setValue(StorageKey.UserRoles, this.roles)
|
||||
this.storageService.setValue(StorageKey.UserRoles, this.roles)
|
||||
}
|
||||
|
||||
public async didDownloadFeatures(features: FeaturesImports.FeatureDescription[]): Promise<void> {
|
||||
@@ -448,7 +460,15 @@ export class SNFeaturesService
|
||||
return FeaturesImports.FindNativeFeature(featureId)?.deprecated === true
|
||||
}
|
||||
|
||||
public isFreeFeature(featureId: FeaturesImports.FeatureIdentifier) {
|
||||
return [FeatureIdentifier.DarkTheme].includes(featureId)
|
||||
}
|
||||
|
||||
public getFeatureStatus(featureId: FeaturesImports.FeatureIdentifier): FeatureStatus {
|
||||
if (this.isFreeFeature(featureId)) {
|
||||
return FeatureStatus.Entitled
|
||||
}
|
||||
|
||||
const isDeprecated = this.isFeatureDeprecated(featureId)
|
||||
if (isDeprecated) {
|
||||
if (this.hasPaidOnlineOrOfflineSubscription()) {
|
||||
@@ -548,7 +568,9 @@ export class SNFeaturesService
|
||||
|
||||
let hasChanges = false
|
||||
const now = new Date()
|
||||
const expired = new Date(feature.expires_at || 0).getTime() < now.getTime()
|
||||
const expired = this.isFreeFeature(feature.identifier)
|
||||
? false
|
||||
: new Date(feature.expires_at || 0).getTime() < now.getTime()
|
||||
|
||||
const existingItem = currentItems.find((item) => {
|
||||
if (item.content.package_info) {
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
/* eslint-disable no-unused-expressions */
|
||||
/* eslint-disable no-undef */
|
||||
import { BaseItemCounts } from './lib/Applications.js'
|
||||
import * as Factory from './lib/factory.js'
|
||||
chai.use(chaiAsPromised)
|
||||
const expect = chai.expect
|
||||
|
||||
describe('application instances', () => {
|
||||
const BASE_ITEM_COUNT = 2 /** Default items key, user preferences */
|
||||
|
||||
const syncOptions = {
|
||||
checkIntegrity: true,
|
||||
awaitAll: true,
|
||||
@@ -27,8 +26,8 @@ describe('application instances', () => {
|
||||
expect(app1.payloadManager).to.not.equal(app2.payloadManager)
|
||||
|
||||
await Factory.createMappedNote(app1)
|
||||
expect(app1.itemManager.items.length).length.to.equal(BASE_ITEM_COUNT + 1)
|
||||
expect(app2.itemManager.items.length).to.equal(BASE_ITEM_COUNT)
|
||||
expect(app1.itemManager.items.length).length.to.equal(BaseItemCounts.DefaultItems + 1)
|
||||
expect(app2.itemManager.items.length).to.equal(BaseItemCounts.DefaultItems)
|
||||
await Factory.safeDeinit(app1)
|
||||
await Factory.safeDeinit(app2)
|
||||
})
|
||||
@@ -40,14 +39,14 @@ describe('application instances', () => {
|
||||
await Factory.createMappedNote(app1)
|
||||
await app1.syncService.sync(syncOptions)
|
||||
|
||||
expect((await app1.diskStorageService.getAllRawPayloads()).length).length.to.equal(BASE_ITEM_COUNT + 1)
|
||||
expect((await app2.diskStorageService.getAllRawPayloads()).length).length.to.equal(BASE_ITEM_COUNT)
|
||||
expect((await app1.diskStorageService.getAllRawPayloads()).length).length.to.equal(BaseItemCounts.DefaultItems + 1)
|
||||
expect((await app2.diskStorageService.getAllRawPayloads()).length).length.to.equal(BaseItemCounts.DefaultItems)
|
||||
|
||||
await Factory.createMappedNote(app2)
|
||||
await app2.syncService.sync(syncOptions)
|
||||
|
||||
expect((await app1.diskStorageService.getAllRawPayloads()).length).length.to.equal(BASE_ITEM_COUNT + 1)
|
||||
expect((await app2.diskStorageService.getAllRawPayloads()).length).length.to.equal(BASE_ITEM_COUNT + 1)
|
||||
expect((await app1.diskStorageService.getAllRawPayloads()).length).length.to.equal(BaseItemCounts.DefaultItems + 1)
|
||||
expect((await app2.diskStorageService.getAllRawPayloads()).length).length.to.equal(BaseItemCounts.DefaultItems + 1)
|
||||
await Factory.safeDeinit(app1)
|
||||
await Factory.safeDeinit(app2)
|
||||
})
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
/* eslint-disable no-unused-expressions */
|
||||
/* eslint-disable no-undef */
|
||||
import { BaseItemCounts } from './lib/Applications.js'
|
||||
import * as Factory from './lib/factory.js'
|
||||
chai.use(chaiAsPromised)
|
||||
const expect = chai.expect
|
||||
|
||||
describe('auth fringe cases', () => {
|
||||
const BASE_ITEM_COUNT = ['default items key', 'user prefs'].length
|
||||
|
||||
const createContext = async () => {
|
||||
const application = await Factory.createInitAppWithFakeCrypto()
|
||||
return {
|
||||
expectedItemCount: BASE_ITEM_COUNT,
|
||||
expectedItemCount: BaseItemCounts.DefaultItems,
|
||||
application: application,
|
||||
email: UuidGenerator.GenerateUuid(),
|
||||
password: UuidGenerator.GenerateUuid(),
|
||||
@@ -100,9 +99,13 @@ describe('auth fringe cases', () => {
|
||||
|
||||
expect(newApplication.itemManager.getDisplayableNotes().length).to.equal(2)
|
||||
|
||||
expect(newApplication.itemManager.getDisplayableNotes().find((n) => n.uuid === firstVersionOfNote.uuid).text).to.equal(staleText)
|
||||
expect(
|
||||
newApplication.itemManager.getDisplayableNotes().find((n) => n.uuid === firstVersionOfNote.uuid).text,
|
||||
).to.equal(staleText)
|
||||
|
||||
const conflictedCopy = newApplication.itemManager.getDisplayableNotes().find((n) => n.uuid !== firstVersionOfNote.uuid)
|
||||
const conflictedCopy = newApplication.itemManager
|
||||
.getDisplayableNotes()
|
||||
.find((n) => n.uuid !== firstVersionOfNote.uuid)
|
||||
expect(conflictedCopy.text).to.equal(serverText)
|
||||
expect(conflictedCopy.duplicate_of).to.equal(firstVersionOfNote.uuid)
|
||||
await Factory.safeDeinit(newApplication)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/* eslint-disable no-unused-expressions */
|
||||
/* eslint-disable no-undef */
|
||||
import { BaseItemCounts } from './lib/Applications.js'
|
||||
import * as Factory from './lib/factory.js'
|
||||
chai.use(chaiAsPromised)
|
||||
const expect = chai.expect
|
||||
@@ -7,8 +8,6 @@ const expect = chai.expect
|
||||
describe('basic auth', function () {
|
||||
this.timeout(Factory.TenSecondTimeout)
|
||||
|
||||
const BASE_ITEM_COUNT = 2 /** Default items key, user preferences */
|
||||
|
||||
const syncOptions = {
|
||||
checkIntegrity: true,
|
||||
awaitAll: true,
|
||||
@@ -16,7 +15,7 @@ describe('basic auth', function () {
|
||||
|
||||
beforeEach(async function () {
|
||||
localStorage.clear()
|
||||
this.expectedItemCount = BASE_ITEM_COUNT
|
||||
this.expectedItemCount = BaseItemCounts.DefaultItems
|
||||
this.application = await Factory.createInitAppWithFakeCrypto()
|
||||
this.email = UuidGenerator.GenerateUuid()
|
||||
this.password = UuidGenerator.GenerateUuid()
|
||||
@@ -62,7 +61,7 @@ describe('basic auth', function () {
|
||||
expect(this.application.protocolService.rootKeyEncryption.keyMode).to.equal(KeyMode.RootKeyNone)
|
||||
|
||||
const rawPayloads = await this.application.diskStorageService.getAllRawPayloads()
|
||||
expect(rawPayloads.length).to.equal(BASE_ITEM_COUNT)
|
||||
expect(rawPayloads.length).to.equal(BaseItemCounts.DefaultItems)
|
||||
})
|
||||
|
||||
it('successfully signs in to registered account', async function () {
|
||||
@@ -408,7 +407,7 @@ describe('basic auth', function () {
|
||||
|
||||
this.application = await Factory.signOutApplicationAndReturnNew(this.application)
|
||||
|
||||
expect(this.application.itemManager.items.length).to.equal(BASE_ITEM_COUNT)
|
||||
expect(this.application.itemManager.items.length).to.equal(BaseItemCounts.DefaultItems)
|
||||
expect(this.application.payloadManager.invalidPayloads.length).to.equal(0)
|
||||
|
||||
/** Should login with new password */
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/* eslint-disable no-unused-expressions */
|
||||
/* eslint-disable no-undef */
|
||||
import { BaseItemCounts } from './lib/Applications.js'
|
||||
import * as Factory from './lib/factory.js'
|
||||
chai.use(chaiAsPromised)
|
||||
const expect = chai.expect
|
||||
@@ -24,8 +25,8 @@ describe('backups', function () {
|
||||
this.application = null
|
||||
})
|
||||
|
||||
const BASE_ITEM_COUNT_ENCRYPTED = ['ItemsKey', 'UserPreferences'].length
|
||||
const BASE_ITEM_COUNT_DECRYPTED = ['UserPreferences'].length
|
||||
const BASE_ITEM_COUNT_ENCRYPTED = BaseItemCounts.DefaultItems
|
||||
const BASE_ITEM_COUNT_DECRYPTED = ['UserPreferences', 'DarkTheme'].length
|
||||
|
||||
it('backup file should have a version number', async function () {
|
||||
let data = await this.application.createDecryptedBackupFile()
|
||||
|
||||
@@ -83,11 +83,11 @@ describe('features', () => {
|
||||
it('should fetch user features and create items for features with content type', async () => {
|
||||
expect(application.apiService.getUserFeatures.callCount).to.equal(1)
|
||||
expect(application.itemManager.createItem.callCount).to.equal(2)
|
||||
|
||||
const themeItems = application.items.getItems(ContentType.Theme)
|
||||
const editorItems = application.items.getItems(ContentType.Component)
|
||||
expect(themeItems).to.have.lengthOf(1)
|
||||
expect(editorItems).to.have.lengthOf(1)
|
||||
expect(themeItems[0].content).to.containSubset(
|
||||
const systemThemeCount = 1
|
||||
expect(themeItems).to.have.lengthOf(1 + systemThemeCount)
|
||||
expect(themeItems[1].content).to.containSubset(
|
||||
JSON.parse(
|
||||
JSON.stringify({
|
||||
name: midnightThemeFeature.name,
|
||||
@@ -96,6 +96,9 @@ describe('features', () => {
|
||||
}),
|
||||
),
|
||||
)
|
||||
|
||||
const editorItems = application.items.getItems(ContentType.Component)
|
||||
expect(editorItems).to.have.lengthOf(1)
|
||||
expect(editorItems[0].content).to.containSubset(
|
||||
JSON.parse(
|
||||
JSON.stringify({
|
||||
@@ -157,7 +160,9 @@ describe('features', () => {
|
||||
})
|
||||
})
|
||||
|
||||
const themeItem = application.items.getItems(ContentType.Theme)[0]
|
||||
const themeItem = application.items
|
||||
.getItems(ContentType.Theme)
|
||||
.find((theme) => theme.identifier === midnightThemeFeature.identifier)
|
||||
|
||||
// Wipe roles from initial sync
|
||||
await application.featuresService.setRoles([])
|
||||
@@ -171,7 +176,9 @@ describe('features', () => {
|
||||
true,
|
||||
)
|
||||
|
||||
const noTheme = application.items.getItems(ContentType.Theme)[0]
|
||||
const noTheme = application.items
|
||||
.getItems(ContentType.Theme)
|
||||
.find((theme) => theme.identifier === midnightThemeFeature.identifier)
|
||||
expect(noTheme).to.not.be.ok
|
||||
})
|
||||
})
|
||||
|
||||
@@ -2,6 +2,10 @@ import WebDeviceInterface from './web_device_interface.js'
|
||||
import FakeWebCrypto from './fake_web_crypto.js'
|
||||
import * as Defaults from './Defaults.js'
|
||||
|
||||
export const BaseItemCounts = {
|
||||
DefaultItems: ['ItemsKey', 'UserPreferences', 'DarkTheme'].length,
|
||||
}
|
||||
|
||||
export function createApplicationWithOptions({ identifier, environment, platform, host, crypto, device }) {
|
||||
if (!device) {
|
||||
device = new WebDeviceInterface()
|
||||
|
||||
@@ -161,14 +161,15 @@ describe('migrations', () => {
|
||||
await application.mutator.insertItem(noDistractionItem)
|
||||
await application.sync.sync()
|
||||
|
||||
expect(application.items.getItems(ContentType.Theme).length).to.equal(1)
|
||||
const systemThemeCount = 1
|
||||
expect(application.items.getItems(ContentType.Theme).length).to.equal(1 + systemThemeCount)
|
||||
|
||||
/** Run migration */
|
||||
const migration = new Migration2_42_0(application.migrationService.services)
|
||||
await migration.handleStage(ApplicationStage.FullSyncCompleted_13)
|
||||
await application.sync.sync()
|
||||
|
||||
expect(application.items.getItems(ContentType.Theme).length).to.equal(0)
|
||||
expect(application.items.getItems(ContentType.Theme).length).to.equal(systemThemeCount)
|
||||
|
||||
await Factory.safeDeinit(application)
|
||||
})
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/* eslint-disable camelcase */
|
||||
/* eslint-disable no-unused-expressions */
|
||||
/* eslint-disable no-undef */
|
||||
import { BaseItemCounts } from '../lib/Applications.js'
|
||||
import * as Factory from '../lib/factory.js'
|
||||
chai.use(chaiAsPromised)
|
||||
const expect = chai.expect
|
||||
|
||||
describe('app models', () => {
|
||||
const BASE_ITEM_COUNT = 2 /** Default items key, user preferences */
|
||||
const sharedApplication = Factory.createApplicationWithFakeCrypto()
|
||||
|
||||
before(async function () {
|
||||
@@ -20,7 +20,7 @@ describe('app models', () => {
|
||||
})
|
||||
|
||||
beforeEach(async function () {
|
||||
this.expectedItemCount = BASE_ITEM_COUNT
|
||||
this.expectedItemCount = BaseItemCounts.DefaultItems
|
||||
this.application = await Factory.createInitAppWithFakeCrypto()
|
||||
})
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/* eslint-disable no-unused-expressions */
|
||||
/* eslint-disable no-undef */
|
||||
import { BaseItemCounts } from '../lib/Applications.js'
|
||||
import * as Factory from '../lib/factory.js'
|
||||
import { createRelatedNoteTagPairPayload } from '../lib/Items.js'
|
||||
chai.use(chaiAsPromised)
|
||||
@@ -7,7 +8,6 @@ const expect = chai.expect
|
||||
|
||||
describe('importing', function () {
|
||||
this.timeout(Factory.TenSecondTimeout)
|
||||
const BASE_ITEM_COUNT = 2 /** Default items key, user preferences */
|
||||
|
||||
let expectedItemCount
|
||||
let application
|
||||
@@ -19,7 +19,7 @@ describe('importing', function () {
|
||||
})
|
||||
|
||||
const setup = async ({ fakeCrypto }) => {
|
||||
expectedItemCount = BASE_ITEM_COUNT
|
||||
expectedItemCount = BaseItemCounts.DefaultItems
|
||||
if (fakeCrypto) {
|
||||
application = await Factory.createInitAppWithFakeCrypto()
|
||||
} else {
|
||||
@@ -599,12 +599,11 @@ describe('importing', function () {
|
||||
application = await Factory.createInitAppWithFakeCrypto()
|
||||
application.setLaunchCallback({
|
||||
receiveChallenge: (challenge) => {
|
||||
const values = challenge.prompts.map(
|
||||
(prompt) =>
|
||||
CreateChallengeValue(
|
||||
prompt,
|
||||
prompt.validation === ChallengeValidation.None ? 'incorrect password' : password,
|
||||
),
|
||||
const values = challenge.prompts.map((prompt) =>
|
||||
CreateChallengeValue(
|
||||
prompt,
|
||||
prompt.validation === ChallengeValidation.None ? 'incorrect password' : password,
|
||||
),
|
||||
)
|
||||
application.submitValuesForChallenge(challenge, values)
|
||||
},
|
||||
@@ -782,14 +781,13 @@ describe('importing', function () {
|
||||
if (challenge.prompts.length === 2) {
|
||||
application.submitValuesForChallenge(
|
||||
challenge,
|
||||
challenge.prompts.map(
|
||||
(prompt) =>
|
||||
CreateChallengeValue(
|
||||
prompt,
|
||||
prompt.validation !== ChallengeValidation.ProtectionSessionDuration
|
||||
? password
|
||||
: UnprotectedAccessSecondsDuration.OneMinute,
|
||||
),
|
||||
challenge.prompts.map((prompt) =>
|
||||
CreateChallengeValue(
|
||||
prompt,
|
||||
prompt.validation !== ChallengeValidation.ProtectionSessionDuration
|
||||
? password
|
||||
: UnprotectedAccessSecondsDuration.OneMinute,
|
||||
),
|
||||
),
|
||||
)
|
||||
} else {
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
/* eslint-disable no-unused-expressions */
|
||||
/* eslint-disable no-undef */
|
||||
import { BaseItemCounts } from '../lib/Applications.js'
|
||||
import * as Factory from '../lib/factory.js'
|
||||
chai.use(chaiAsPromised)
|
||||
const expect = chai.expect
|
||||
|
||||
describe('items', () => {
|
||||
const BASE_ITEM_COUNT = 2 /** Default items key, user preferences */
|
||||
|
||||
const syncOptions = {
|
||||
checkIntegrity: true,
|
||||
awaitAll: true,
|
||||
}
|
||||
|
||||
beforeEach(async function () {
|
||||
this.expectedItemCount = BASE_ITEM_COUNT
|
||||
this.expectedItemCount = BaseItemCounts.DefaultItems
|
||||
this.application = await Factory.createInitAppWithFakeCrypto()
|
||||
})
|
||||
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
/* eslint-disable no-unused-expressions */
|
||||
/* eslint-disable no-undef */
|
||||
import { BaseItemCounts } from '../lib/Applications.js'
|
||||
import * as Factory from '../lib/factory.js'
|
||||
import { createNoteParams } from '../lib/Items.js'
|
||||
chai.use(chaiAsPromised)
|
||||
const expect = chai.expect
|
||||
|
||||
describe('model manager mapping', () => {
|
||||
const BASE_ITEM_COUNT = 2 /** Default items key, user preferences */
|
||||
|
||||
beforeEach(async function () {
|
||||
this.expectedItemCount = BASE_ITEM_COUNT
|
||||
this.expectedItemCount = BaseItemCounts.DefaultItems
|
||||
this.application = await Factory.createInitAppWithFakeCrypto()
|
||||
})
|
||||
|
||||
|
||||
@@ -2,19 +2,18 @@
|
||||
import * as Factory from '../lib/factory.js'
|
||||
import * as Utils from '../lib/Utils.js'
|
||||
import { createRelatedNoteTagPairPayload } from '../lib/Items.js'
|
||||
import { BaseItemCounts } from '../lib/Applications.js'
|
||||
chai.use(chaiAsPromised)
|
||||
const expect = chai.expect
|
||||
|
||||
describe('notes and tags', () => {
|
||||
const BASE_ITEM_COUNT = 2 /** Default items key, user preferences */
|
||||
|
||||
const syncOptions = {
|
||||
checkIntegrity: true,
|
||||
awaitAll: true,
|
||||
}
|
||||
|
||||
beforeEach(async function () {
|
||||
this.expectedItemCount = BASE_ITEM_COUNT
|
||||
this.expectedItemCount = BaseItemCounts.DefaultItems
|
||||
this.application = await Factory.createInitAppWithFakeCrypto()
|
||||
})
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/* eslint-disable no-unused-expressions */
|
||||
/* eslint-disable no-undef */
|
||||
import { BaseItemCounts } from './lib/Applications.js'
|
||||
import * as Factory from './lib/factory.js'
|
||||
import WebDeviceInterface from './lib/web_device_interface.js'
|
||||
chai.use(chaiAsPromised)
|
||||
@@ -8,8 +9,6 @@ const expect = chai.expect
|
||||
describe('server session', function () {
|
||||
this.timeout(Factory.TenSecondTimeout)
|
||||
|
||||
const BASE_ITEM_COUNT = 2 /** Default items key, user preferences */
|
||||
|
||||
const syncOptions = {
|
||||
checkIntegrity: true,
|
||||
awaitAll: true,
|
||||
@@ -17,7 +16,7 @@ describe('server session', function () {
|
||||
|
||||
beforeEach(async function () {
|
||||
localStorage.clear()
|
||||
this.expectedItemCount = BASE_ITEM_COUNT
|
||||
this.expectedItemCount = BaseItemCounts.DefaultItems
|
||||
this.application = await Factory.createInitAppWithFakeCrypto()
|
||||
this.email = UuidGenerator.GenerateUuid()
|
||||
this.password = UuidGenerator.GenerateUuid()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/* eslint-disable no-unused-expressions */
|
||||
/* eslint-disable no-undef */
|
||||
import { BaseItemCounts } from './lib/Applications.js'
|
||||
import * as Factory from './lib/factory.js'
|
||||
import WebDeviceInterface from './lib/web_device_interface.js'
|
||||
chai.use(chaiAsPromised)
|
||||
@@ -11,7 +12,6 @@ describe('singletons', function () {
|
||||
const syncOptions = {
|
||||
checkIntegrity: true,
|
||||
}
|
||||
const BASE_ITEM_COUNT = 2 /** Default items key, user preferences */
|
||||
|
||||
function createPrefsPayload() {
|
||||
const params = {
|
||||
@@ -30,7 +30,7 @@ describe('singletons', function () {
|
||||
|
||||
beforeEach(async function () {
|
||||
localStorage.clear()
|
||||
this.expectedItemCount = BASE_ITEM_COUNT
|
||||
this.expectedItemCount = BaseItemCounts.DefaultItems
|
||||
this.application = await Factory.createInitAppWithFakeCrypto()
|
||||
this.email = UuidGenerator.GenerateUuid()
|
||||
this.password = UuidGenerator.GenerateUuid()
|
||||
@@ -83,7 +83,7 @@ describe('singletons', function () {
|
||||
localStorage.clear()
|
||||
})
|
||||
|
||||
it(`only resolves to ${BASE_ITEM_COUNT} items`, async function () {
|
||||
it(`only resolves to ${BaseItemCounts.DefaultItems} items`, async function () {
|
||||
/** Preferences are an item we know to always return true for isSingleton */
|
||||
const prefs1 = createPrefsPayload()
|
||||
const prefs2 = createPrefsPayload()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/* eslint-disable no-unused-expressions */
|
||||
/* eslint-disable no-undef */
|
||||
import { BaseItemCounts } from './lib/Applications.js'
|
||||
import * as Factory from './lib/factory.js'
|
||||
chai.use(chaiAsPromised)
|
||||
const expect = chai.expect
|
||||
@@ -11,7 +12,6 @@ describe('storage manager', function () {
|
||||
* Base keys are `storage`, `snjs_version`, and `keychain`
|
||||
*/
|
||||
const BASE_KEY_COUNT = 3
|
||||
const BASE_ITEM_COUNT = 2 /** Default items key, user preferences */
|
||||
|
||||
beforeEach(async function () {
|
||||
localStorage.clear()
|
||||
@@ -37,7 +37,7 @@ describe('storage manager', function () {
|
||||
const payload = Factory.createNotePayload()
|
||||
await this.application.diskStorageService.savePayload(payload)
|
||||
const payloads = await this.application.diskStorageService.getAllRawPayloads()
|
||||
expect(payloads.length).to.equal(BASE_ITEM_COUNT + 1)
|
||||
expect(payloads.length).to.equal(BaseItemCounts.DefaultItems + 1)
|
||||
})
|
||||
|
||||
it('should clear values', async function () {
|
||||
@@ -71,7 +71,7 @@ describe('storage manager', function () {
|
||||
const value = 'bar'
|
||||
await this.application.diskStorageService.setValue(key, value)
|
||||
/** Items are stored in local storage */
|
||||
expect(Object.keys(localStorage).length).to.equal(this.expectedKeyCount + BASE_ITEM_COUNT)
|
||||
expect(Object.keys(localStorage).length).to.equal(this.expectedKeyCount + BaseItemCounts.DefaultItems)
|
||||
const retrievedValue = await this.application.diskStorageService.getValue(key)
|
||||
expect(retrievedValue).to.equal(value)
|
||||
})
|
||||
@@ -297,8 +297,8 @@ describe('storage manager', function () {
|
||||
})
|
||||
|
||||
await Factory.createSyncedNote(this.application)
|
||||
expect(await Factory.storagePayloadCount(this.application)).to.equal(BASE_ITEM_COUNT + 1)
|
||||
expect(await Factory.storagePayloadCount(this.application)).to.equal(BaseItemCounts.DefaultItems + 1)
|
||||
this.application = await Factory.signOutApplicationAndReturnNew(this.application)
|
||||
expect(await Factory.storagePayloadCount(this.application)).to.equal(BASE_ITEM_COUNT)
|
||||
expect(await Factory.storagePayloadCount(this.application)).to.equal(BaseItemCounts.DefaultItems)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
/* eslint-disable no-undef */
|
||||
import { BaseItemCounts } from '../lib/Applications.js'
|
||||
import * as Factory from '../lib/factory.js'
|
||||
import { createItemParams, createSyncedNoteWithTag } from '../lib/Items.js'
|
||||
import { createSyncedNoteWithTag } from '../lib/Items.js'
|
||||
import * as Utils from '../lib/Utils.js'
|
||||
chai.use(chaiAsPromised)
|
||||
const expect = chai.expect
|
||||
|
||||
describe('online conflict handling', function () {
|
||||
this.timeout(Factory.TenSecondTimeout)
|
||||
const BASE_ITEM_COUNT = 2 /** Default items key, user preferences */
|
||||
|
||||
const syncOptions = {
|
||||
checkIntegrity: true,
|
||||
@@ -16,7 +16,7 @@ describe('online conflict handling', function () {
|
||||
|
||||
beforeEach(async function () {
|
||||
localStorage.clear()
|
||||
this.expectedItemCount = BASE_ITEM_COUNT
|
||||
this.expectedItemCount = BaseItemCounts.DefaultItems
|
||||
|
||||
this.context = await Factory.createAppContextWithFakeCrypto('AppA')
|
||||
await this.context.launch()
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
/* eslint-disable no-unused-expressions */
|
||||
/* eslint-disable no-undef */
|
||||
import { BaseItemCounts } from '../lib/Applications.js'
|
||||
import * as Factory from '../lib/factory.js'
|
||||
chai.use(chaiAsPromised)
|
||||
const expect = chai.expect
|
||||
|
||||
describe('sync integrity', () => {
|
||||
const BASE_ITEM_COUNT = 2 /** Default items key, user preferences */
|
||||
|
||||
before(function () {
|
||||
localStorage.clear()
|
||||
})
|
||||
@@ -16,7 +15,7 @@ describe('sync integrity', () => {
|
||||
})
|
||||
|
||||
beforeEach(async function () {
|
||||
this.expectedItemCount = BASE_ITEM_COUNT
|
||||
this.expectedItemCount = BaseItemCounts.DefaultItems
|
||||
this.application = await Factory.createInitAppWithFakeCrypto()
|
||||
this.email = UuidGenerator.GenerateUuid()
|
||||
this.password = UuidGenerator.GenerateUuid()
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
/* eslint-disable no-unused-expressions */
|
||||
/* eslint-disable no-undef */
|
||||
import { BaseItemCounts } from '../lib/Applications.js'
|
||||
import * as Factory from '../lib/factory.js'
|
||||
chai.use(chaiAsPromised)
|
||||
const expect = chai.expect
|
||||
|
||||
describe('offline syncing', () => {
|
||||
const BASE_ITEM_COUNT = 2 /** Default items key, user preferences */
|
||||
|
||||
const syncOptions = {
|
||||
checkIntegrity: true,
|
||||
awaitAll: true,
|
||||
}
|
||||
|
||||
beforeEach(async function () {
|
||||
this.expectedItemCount = BASE_ITEM_COUNT
|
||||
this.expectedItemCount = BaseItemCounts.DefaultItems
|
||||
this.application = await Factory.createInitAppWithFakeCrypto()
|
||||
})
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/* eslint-disable no-undef */
|
||||
import { BaseItemCounts } from '../lib/Applications.js'
|
||||
import * as Factory from '../lib/factory.js'
|
||||
import * as Utils from '../lib/Utils.js'
|
||||
chai.use(chaiAsPromised)
|
||||
@@ -6,7 +7,6 @@ const expect = chai.expect
|
||||
|
||||
describe('online syncing', function () {
|
||||
this.timeout(Factory.TenSecondTimeout)
|
||||
const BASE_ITEM_COUNT = 2 /** Default items key, user preferences */
|
||||
|
||||
const syncOptions = {
|
||||
checkIntegrity: true,
|
||||
@@ -15,7 +15,7 @@ describe('online syncing', function () {
|
||||
|
||||
beforeEach(async function () {
|
||||
localStorage.clear()
|
||||
this.expectedItemCount = BASE_ITEM_COUNT
|
||||
this.expectedItemCount = BaseItemCounts.DefaultItems
|
||||
|
||||
this.context = await Factory.createAppContext()
|
||||
await this.context.launch()
|
||||
@@ -97,7 +97,7 @@ describe('online syncing', function () {
|
||||
|
||||
this.application = await Factory.signOutApplicationAndReturnNew(this.application)
|
||||
|
||||
expect(this.application.itemManager.items.length).to.equal(BASE_ITEM_COUNT)
|
||||
expect(this.application.itemManager.items.length).to.equal(BaseItemCounts.DefaultItems)
|
||||
|
||||
const promise = Factory.loginToApplication({
|
||||
application: this.application,
|
||||
@@ -244,7 +244,7 @@ describe('online syncing', function () {
|
||||
// set item to be merged for when sign in occurs
|
||||
await this.application.syncService.markAllItemsAsNeedingSyncAndPersist()
|
||||
expect(this.application.syncService.isOutOfSync()).to.equal(false)
|
||||
expect(this.application.itemManager.getDirtyItems().length).to.equal(BASE_ITEM_COUNT + 1)
|
||||
expect(this.application.itemManager.getDirtyItems().length).to.equal(BaseItemCounts.DefaultItems + 1)
|
||||
|
||||
// Sign back in for next tests
|
||||
await Factory.loginToApplication({
|
||||
@@ -686,7 +686,7 @@ describe('online syncing', function () {
|
||||
|
||||
this.application = await Factory.signOutApplicationAndReturnNew(this.application)
|
||||
const rawPayloads = await this.application.diskStorageService.getAllRawPayloads()
|
||||
expect(rawPayloads.length).to.equal(BASE_ITEM_COUNT)
|
||||
expect(rawPayloads.length).to.equal(BaseItemCounts.DefaultItems)
|
||||
|
||||
await this.application.signIn(this.email, this.password, undefined, undefined, undefined, true)
|
||||
|
||||
|
||||
@@ -16,11 +16,11 @@ import {
|
||||
StorageValueModes,
|
||||
FeatureStatus,
|
||||
} from '@standardnotes/services'
|
||||
import { FeatureIdentifier } from '@standardnotes/snjs'
|
||||
|
||||
const CachedThemesKey = 'cachedThemes'
|
||||
const TimeBeforeApplyingColorScheme = 5
|
||||
const DefaultThemeIdentifier = 'Default'
|
||||
const DarkThemeIdentifier = 'Dark'
|
||||
|
||||
export class ThemeManager extends AbstractService {
|
||||
private activeThemes: Uuid[] = []
|
||||
@@ -200,18 +200,14 @@ export class ThemeManager extends AbstractService {
|
||||
private setThemeAsPerColorScheme(prefersDarkColorScheme: boolean) {
|
||||
const preference = prefersDarkColorScheme ? PrefKey.AutoDarkThemeIdentifier : PrefKey.AutoLightThemeIdentifier
|
||||
const preferenceDefault =
|
||||
preference === PrefKey.AutoDarkThemeIdentifier ? DarkThemeIdentifier : DefaultThemeIdentifier
|
||||
preference === PrefKey.AutoDarkThemeIdentifier ? FeatureIdentifier.DarkTheme : DefaultThemeIdentifier
|
||||
|
||||
const themes = this.application.items
|
||||
.getDisplayableComponents()
|
||||
.filter((component) => component.isTheme()) as SNTheme[]
|
||||
|
||||
const activeTheme = themes.find((theme) => theme.active && !theme.isLayerable())
|
||||
const activeThemeIdentifier = activeTheme
|
||||
? activeTheme.identifier
|
||||
: this.application.getPreference(PrefKey.DarkMode, false)
|
||||
? DarkThemeIdentifier
|
||||
: DefaultThemeIdentifier
|
||||
const activeThemeIdentifier = activeTheme ? activeTheme.identifier : DefaultThemeIdentifier
|
||||
|
||||
const themeIdentifier = this.application.getPreference(preference, preferenceDefault) as string
|
||||
|
||||
@@ -225,9 +221,6 @@ export class ThemeManager extends AbstractService {
|
||||
if (themeIdentifier === DefaultThemeIdentifier) {
|
||||
toggleActiveTheme()
|
||||
void this.application.setPreference(PrefKey.DarkMode, false)
|
||||
} else if (themeIdentifier === DarkThemeIdentifier) {
|
||||
toggleActiveTheme()
|
||||
void this.application.setPreference(PrefKey.DarkMode, true)
|
||||
} else {
|
||||
const theme = themes.find((theme) => theme.package_info.identifier === themeIdentifier)
|
||||
if (theme && !theme.active) {
|
||||
|
||||
@@ -58,11 +58,6 @@ const Appearance: FunctionComponent<Props> = ({ application }) => {
|
||||
}
|
||||
})
|
||||
|
||||
themesAsItems.unshift({
|
||||
label: 'Dark',
|
||||
value: 'Dark',
|
||||
})
|
||||
|
||||
themesAsItems.unshift({
|
||||
label: 'Default',
|
||||
value: 'Default',
|
||||
|
||||
@@ -166,13 +166,6 @@ const QuickSettingsMenu: FunctionComponent<MenuProps> = ({ application, quickSet
|
||||
application.setPreference(PrefKey.DarkMode, false)
|
||||
}, [application, deactivateAnyNonLayerableTheme])
|
||||
|
||||
const toggleDarkMode = useCallback(() => {
|
||||
if (!isDarkModeOn) {
|
||||
deactivateAnyNonLayerableTheme()
|
||||
application.setPreference(PrefKey.DarkMode, true)
|
||||
}
|
||||
}, [application, isDarkModeOn, deactivateAnyNonLayerableTheme])
|
||||
|
||||
return (
|
||||
<div>
|
||||
{toggleableComponents.length > 0 && (
|
||||
@@ -205,13 +198,6 @@ const QuickSettingsMenu: FunctionComponent<MenuProps> = ({ application, quickSet
|
||||
<RadioIndicator checked={defaultThemeOn} className="mr-2" />
|
||||
Default
|
||||
</button>
|
||||
<button
|
||||
className="flex w-full cursor-pointer items-center border-0 bg-transparent px-3 py-1.5 text-left text-mobile-menu-item text-text hover:bg-contrast hover:text-foreground focus:bg-info-backdrop focus:shadow-none md:text-sm"
|
||||
onClick={toggleDarkMode}
|
||||
>
|
||||
<RadioIndicator checked={isDarkModeOn} className="mr-2" />
|
||||
Dark
|
||||
</button>
|
||||
{themes.map((theme) => (
|
||||
<ThemesMenuButton item={theme} application={application} key={theme.component?.uuid ?? theme.identifier} />
|
||||
))}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { ThemeItem } from '@/Components/QuickSettingsMenu/ThemeItem'
|
||||
import { FeatureIdentifier } from '@standardnotes/snjs'
|
||||
|
||||
const isDarkModeTheme = (theme: ThemeItem) => theme.identifier === FeatureIdentifier.DarkTheme
|
||||
|
||||
export const sortThemes = (a: ThemeItem, b: ThemeItem) => {
|
||||
const aIsLayerable = a.component?.isLayerable()
|
||||
@@ -8,6 +11,8 @@ export const sortThemes = (a: ThemeItem, b: ThemeItem) => {
|
||||
return 1
|
||||
} else if (!aIsLayerable && bIsLayerable) {
|
||||
return -1
|
||||
} else if (!isDarkModeTheme(a) && isDarkModeTheme(b)) {
|
||||
return 1
|
||||
} else {
|
||||
return a.name.toLowerCase() < b.name.toLowerCase() ? -1 : 1
|
||||
}
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
.dark-mode {
|
||||
--foreground-color: #eeeeee;
|
||||
--background-color: #0f1011;
|
||||
--highlight-color: #a464c2;
|
||||
--border-color: #0f1011;
|
||||
|
||||
--sn-component-foreground-color: var(--foreground-color);
|
||||
--sn-component-background-color: transparent;
|
||||
--sn-component-foreground-highlight-color: var(--highlight-color);
|
||||
--sn-component-outer-border-color: transparent;
|
||||
--sn-component-inner-border-color: var(--foreground-color);
|
||||
|
||||
// StyleKit Vars
|
||||
|
||||
--sn-stylekit-passive-color-0: #999999;
|
||||
--sn-stylekit-passive-color-3: #28292b;
|
||||
--sn-stylekit-passive-color-4: #1c1d1e;
|
||||
--sn-stylekit-passive-color-5: #1d1f20;
|
||||
|
||||
--sn-stylekit-shadow-color: #000000;
|
||||
|
||||
--sn-stylekit-info-color: var(--highlight-color);
|
||||
--sn-stylekit-info-contrast-color: var(--foreground-color);
|
||||
|
||||
--sn-stylekit-neutral-color: #7c7c7c;
|
||||
--sn-stylekit-neutral-contrast-color: #ffffff;
|
||||
|
||||
--sn-stylekit-success-color: #2b9612;
|
||||
--sn-stylekit-success-contrast-color: #ffffff;
|
||||
|
||||
--sn-stylekit-warning-color: #f6a200;
|
||||
--sn-stylekit-warning-contrast-color: #ffffff;
|
||||
|
||||
--sn-stylekit-danger-color: #f80324;
|
||||
--sn-stylekit-danger-contrast-color: #ffffff;
|
||||
|
||||
--sn-stylekit-editor-background-color: var(--sn-stylekit-background-color);
|
||||
--sn-stylekit-editor-foreground-color: var(--sn-stylekit-foreground-color);
|
||||
|
||||
--sn-stylekit-background-color: var(--background-color);
|
||||
--sn-stylekit-foreground-color: var(--foreground-color);
|
||||
--sn-stylekit-border-color: #000000;
|
||||
|
||||
--sn-stylekit-contrast-background-color: #000000;
|
||||
--sn-stylekit-contrast-foreground-color: #ffffff;
|
||||
--sn-stylekit-contrast-border-color: #000000;
|
||||
|
||||
--sn-stylekit-secondary-background-color: var(--sn-stylekit-passive-color-4);
|
||||
--sn-stylekit-secondary-foreground-color: #ffffff;
|
||||
--sn-stylekit-secondary-border-color: #000000;
|
||||
|
||||
--sn-stylekit-secondary-contrast-background-color: #000000;
|
||||
--sn-stylekit-secondary-contrast-foreground-color: #ffffff;
|
||||
--sn-stylekit-secondary-contrast-border-color: #ffffff;
|
||||
|
||||
--sn-stylekit-paragraph-text-color: #ffffff;
|
||||
|
||||
--sn-desktop-titlebar-bg-color: var(--background-color);
|
||||
--sn-desktop-titlebar-border-color: var(--border-color);
|
||||
--sn-desktop-titlebar-ui-color: var(--foreground-color);
|
||||
--sn-desktop-titlebar-ui-hover-color: var(--highlight-color);
|
||||
|
||||
--sn-stylekit-scrollbar-track-border-color: var(--border-color);
|
||||
--sn-stylekit-scrollbar-thumb-color: var(--sn-stylekit-info-color);
|
||||
|
||||
--sn-stylekit-menu-border: 1px solid #424242;
|
||||
|
||||
// Theme
|
||||
|
||||
--navigation-item-selected-background-color: var(--background-color);
|
||||
}
|
||||
@@ -3,7 +3,6 @@
|
||||
@import '../../../styles/src/Styles/_scrollbar.scss';
|
||||
@import '../../../styles/src/Styles/utils/_animation.scss';
|
||||
@import 'theme';
|
||||
@import 'dark-mode';
|
||||
@import 'main';
|
||||
@import 'ui';
|
||||
@import 'footer';
|
||||
|
||||
Reference in New Issue
Block a user