mirror of
https://github.com/marktext/marktext.git
synced 2025-05-02 20:12:23 +08:00
159 lines
4.4 KiB
JavaScript
159 lines
4.4 KiB
JavaScript
import fs from 'fs'
|
|
import path from 'path'
|
|
import EventEmitter from 'events'
|
|
import Store from 'electron-store'
|
|
import { BrowserWindow, ipcMain, nativeTheme } from 'electron'
|
|
import log from 'electron-log'
|
|
import { isWindows } from '../config'
|
|
import { hasSameKeys } from '../utils'
|
|
import schema from './schema'
|
|
|
|
const PREFERENCES_FILE_NAME = 'preferences'
|
|
|
|
class Preference extends EventEmitter {
|
|
/**
|
|
* @param {AppPaths} userDataPath The path instance.
|
|
*
|
|
* NOTE: This throws an exception when validation fails.
|
|
*
|
|
*/
|
|
constructor (paths) {
|
|
// TODO: Preferences should not loaded if global.MARKTEXT_SAFE_MODE is set.
|
|
super()
|
|
|
|
const { preferencesPath } = paths
|
|
this.preferencesPath = preferencesPath
|
|
this.hasPreferencesFile = fs.existsSync(path.join(this.preferencesPath, `./${PREFERENCES_FILE_NAME}.json`))
|
|
this.store = new Store({
|
|
schema,
|
|
name: PREFERENCES_FILE_NAME
|
|
})
|
|
|
|
this.staticPath = path.join(__static, 'preference.json')
|
|
this.init()
|
|
}
|
|
|
|
init = () => {
|
|
let defaultSettings = null
|
|
try {
|
|
defaultSettings = JSON.parse(fs.readFileSync(this.staticPath, { encoding: 'utf8' }) || '{}')
|
|
|
|
// Set best theme on first application start.
|
|
if (nativeTheme.shouldUseDarkColors) {
|
|
defaultSettings.theme = 'dark'
|
|
}
|
|
} catch (err) {
|
|
log.error(err)
|
|
}
|
|
|
|
if (!defaultSettings) {
|
|
throw new Error('Can not load static preference.json file')
|
|
}
|
|
|
|
// I don't know why `this.store.size` is 3 when first load, so I just check file existed.
|
|
if (!this.hasPreferencesFile) {
|
|
this.store.set(defaultSettings)
|
|
} else {
|
|
// Because `this.getAll()` will return a plainObject, so we can not use `hasOwnProperty` method
|
|
// const plainObject = () => Object.create(null)
|
|
const userSetting = this.getAll()
|
|
// Update outdated settings
|
|
const requiresUpdate = !hasSameKeys(defaultSettings, userSetting)
|
|
const userSettingKeys = Object.keys(userSetting)
|
|
const defaultSettingKeys = Object.keys(defaultSettings)
|
|
|
|
if (requiresUpdate) {
|
|
// TODO(fxha): For performance reasons, we should try to replace 'electron-store' because
|
|
// it does multiple blocking I/O calls when changing entries. There is no transaction or
|
|
// async I/O available. The core reason we changed to it was JSON scheme validation.
|
|
|
|
// Remove outdated settings
|
|
for (const key of userSettingKeys) {
|
|
if (!defaultSettingKeys.includes(key)) {
|
|
delete userSetting[key]
|
|
this.store.delete(key)
|
|
}
|
|
}
|
|
|
|
// Add new setting options
|
|
let addedNewEntries = false
|
|
for (const key in defaultSettings) {
|
|
if (!userSettingKeys.includes(key)) {
|
|
addedNewEntries = true
|
|
userSetting[key] = defaultSettings[key]
|
|
}
|
|
}
|
|
if (addedNewEntries) {
|
|
this.store.set(userSetting)
|
|
}
|
|
}
|
|
}
|
|
|
|
this._listenForIpcMain()
|
|
}
|
|
|
|
getAll () {
|
|
return this.store.store
|
|
}
|
|
|
|
setItem (key, value) {
|
|
ipcMain.emit('broadcast-preferences-changed', { [key]: value })
|
|
return this.store.set(key, value)
|
|
}
|
|
|
|
getItem (key) {
|
|
return this.store.get(key)
|
|
}
|
|
|
|
/**
|
|
* Change multiple setting entries.
|
|
*
|
|
* @param {Object.<string, *>} settings A settings object or subset object with key/value entries.
|
|
*/
|
|
setItems (settings) {
|
|
if (!settings) {
|
|
log.error('Cannot change settings without entires: object is undefined or null.')
|
|
return
|
|
}
|
|
|
|
Object.keys(settings).forEach(key => {
|
|
this.setItem(key, settings[key])
|
|
})
|
|
}
|
|
|
|
getPreferredEol () {
|
|
const endOfLine = this.getItem('endOfLine')
|
|
if (endOfLine === 'lf') {
|
|
return 'lf'
|
|
}
|
|
return endOfLine === 'crlf' || isWindows ? 'crlf' : 'lf'
|
|
}
|
|
|
|
exportJSON () {
|
|
// todo
|
|
}
|
|
|
|
importJSON () {
|
|
// todo
|
|
}
|
|
|
|
_listenForIpcMain () {
|
|
ipcMain.on('mt::ask-for-user-preference', e => {
|
|
const win = BrowserWindow.fromWebContents(e.sender)
|
|
win.webContents.send('mt::user-preference', this.getAll())
|
|
})
|
|
ipcMain.on('mt::set-user-preference', (e, settings) => {
|
|
this.setItems(settings)
|
|
})
|
|
ipcMain.on('mt::cmd-toggle-autosave', e => {
|
|
this.setItem('autoSave', !!this.getItem('autoSave'))
|
|
})
|
|
|
|
ipcMain.on('set-user-preference', settings => {
|
|
this.setItems(settings)
|
|
})
|
|
}
|
|
}
|
|
|
|
export default Preference
|