Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
feat(App): Add option to enable dark mode for supported services
- Loading branch information
|
@@ -304,6 +304,7 @@ export default @observer class EditServiceForm extends Component { |
|
|
|
|
|
<div className="settings__settings-group"> |
|
|
<h3>{intl.formatMessage(messages.headlineGeneral)}</h3> |
|
|
<Toggle field={form.$('isDarkModeEnabled')} /> |
|
|
<Toggle field={form.$('isEnabled')} /> |
|
|
</div> |
|
|
</div> |
|
|
|
@@ -6,6 +6,7 @@ import { defineMessages, intlShape } from 'react-intl'; |
|
|
import UserStore from '../../stores/UserStore'; |
|
|
import RecipesStore from '../../stores/RecipesStore'; |
|
|
import ServicesStore from '../../stores/ServicesStore'; |
|
|
import SettingsStore from '../../stores/SettingsStore'; |
|
|
import Form from '../../lib/Form'; |
|
|
import { gaPage } from '../../lib/analytics'; |
|
|
|
|
@@ -50,6 +51,10 @@ const messages = defineMessages({ |
|
|
id: 'settings.service.form.icon', |
|
|
defaultMessage: '!!!Custom icon', |
|
|
}, |
|
|
enableDarkMode: { |
|
|
id: 'settings.service.form.enableDarkMode', |
|
|
defaultMessage: '!!!Enable Dark Mode', |
|
|
}, |
|
|
}); |
|
|
|
|
|
export default @inject('stores', 'actions') @observer class EditServiceScreen extends Component { |
|
@@ -111,6 +116,11 @@ export default @inject('stores', 'actions') @observer class EditServiceScreen ex |
|
|
default: null, |
|
|
type: 'file', |
|
|
}, |
|
|
isDarkModeEnabled: { |
|
|
label: intl.formatMessage(messages.enableDarkMode), |
|
|
value: service.isDarkModeEnabled, |
|
|
default: this.props.stores.settings.all.app.darkMode, |
|
|
}, |
|
|
}, |
|
|
}; |
|
|
|
|
@@ -238,6 +248,7 @@ EditServiceScreen.wrappedComponent.propTypes = { |
|
|
user: PropTypes.instanceOf(UserStore).isRequired, |
|
|
recipes: PropTypes.instanceOf(RecipesStore).isRequired, |
|
|
services: PropTypes.instanceOf(ServicesStore).isRequired, |
|
|
settings: PropTypes.instanceOf(SettingsStore).isRequired, |
|
|
}).isRequired, |
|
|
router: PropTypes.shape({ |
|
|
params: PropTypes.shape({ |
|
|
|
@@ -130,6 +130,7 @@ |
|
|
"settings.service.form.icon": "Custom icon", |
|
|
"settings.service.form.iconDelete": "Delete", |
|
|
"settings.service.form.iconUpload": "Drop your image, or click here", |
|
|
"settings.service.form.enableDarkMode": "Enable Dark Mode", |
|
|
"settings.service.error.headline": "Error", |
|
|
"settings.service.error.goBack": "Back to services", |
|
|
"settings.service.error.message": "Could not load service recipe.", |
|
|
|
|
@@ -1,5 +1,7 @@ |
|
|
import emailParser from 'address-rfc2822'; |
|
|
import semver from 'semver'; |
|
|
import fs from 'fs-extra'; |
|
|
import path from 'path'; |
|
|
|
|
|
export default class Recipe { |
|
|
id = ''; |
|
@@ -73,4 +75,8 @@ export default class Recipe { |
|
|
|
|
|
return []; |
|
|
} |
|
|
|
|
|
get hasDarkMode() { |
|
|
return fs.pathExistsSync(path.join(this.path, 'darkmode.css')); |
|
|
} |
|
|
} |
|
@@ -28,6 +28,7 @@ export default class Service { |
|
|
@observable iconUrl = ''; |
|
|
@observable hasCustomUploadedIcon = false; |
|
|
@observable hasCrashed = false; |
|
|
@observable isDarkModeEnabled = false; |
|
|
|
|
|
constructor(data, recipe) { |
|
|
if (!data) { |
|
@@ -64,6 +65,8 @@ export default class Service { |
|
|
|
|
|
this.isMuted = data.isMuted !== undefined ? data.isMuted : this.isMuted; |
|
|
|
|
|
this.isDarkModeEnabled = data.isDarkModeEnabled !== undefined ? data.isDarkModeEnabled : this.isDarkModeEnabled; |
|
|
|
|
|
this.hasCustomUploadedIcon = data.hasCustomIcon !== undefined ? data.hasCustomIcon : this.hasCustomUploadedIcon; |
|
|
|
|
|
this.recipe = recipe; |
|
|
|
@@ -214,6 +214,14 @@ export default class ServicesStore extends Store { |
|
|
await request._promise; |
|
|
this.actionStatus = request.result.status; |
|
|
|
|
|
if (service.isEnabled) { |
|
|
this._sendIPCMessage({ |
|
|
serviceId, |
|
|
channel: 'service-settings-update', |
|
|
args: newData, |
|
|
}); |
|
|
} |
|
|
|
|
|
if (redirect) { |
|
|
this.stores.router.push('/settings/services'); |
|
|
gaEvent('Service', 'update', service.recipe.id); |
|
|
|
|
@@ -0,0 +1,28 @@ |
|
|
import path from 'path'; |
|
|
import fs from 'fs-extra'; |
|
|
|
|
|
const ID = 'franz-theme-dark-mode'; |
|
|
|
|
|
export function injectDarkModeStyle(recipePath) { |
|
|
const darkModeStyle = path.join(recipePath, 'darkmode.css'); |
|
|
if (fs.pathExistsSync(darkModeStyle)) { |
|
|
const data = fs.readFileSync(darkModeStyle); |
|
|
const styles = document.createElement('style'); |
|
|
styles.id = ID; |
|
|
styles.innerHTML = data.toString(); |
|
|
|
|
|
document.querySelector('head').appendChild(styles); |
|
|
} |
|
|
} |
|
|
|
|
|
export function removeDarkModeStyle() { |
|
|
const style = document.querySelector(`#${ID}`); |
|
|
|
|
|
if (style) { |
|
|
style.remove(); |
|
|
} |
|
|
} |
|
|
|
|
|
export function isDarkModeStyleInjected() { |
|
|
return !!document.querySelector(`#${ID}`); |
|
|
} |
|
@@ -6,18 +6,29 @@ import { isDevMode } from '../environment'; |
|
|
import RecipeWebview from './lib/RecipeWebview'; |
|
|
|
|
|
import Spellchecker from './spellchecker'; |
|
|
import { injectDarkModeStyle, isDarkModeStyleInjected, removeDarkModeStyle } from './darkmode'; |
|
|
import './notifications'; |
|
|
|
|
|
const debug = require('debug')('Franz:Plugin'); |
|
|
|
|
|
window.franzSettings = {}; |
|
|
let serviceData; |
|
|
|
|
|
ipcRenderer.on('initializeRecipe', (e, data) => { |
|
|
const modulePath = path.join(data.recipe.path, 'webview.js'); |
|
|
// Delete module from cache |
|
|
delete require.cache[require.resolve(modulePath)]; |
|
|
try { |
|
|
// eslint-disable-next-line |
|
|
require(modulePath)(new RecipeWebview(), data); |
|
|
debug('Initialize Recipe'); |
|
|
debug('Initialize Recipe', data); |
|
|
|
|
|
serviceData = data; |
|
|
|
|
|
if (data.isDarkModeEnabled) { |
|
|
injectDarkModeStyle(data.recipe.path); |
|
|
debug('Add dark theme styles'); |
|
|
} |
|
|
} catch (err) { |
|
|
debug('Recipe initialization failed', err); |
|
|
} |
|
@@ -33,11 +44,27 @@ new ContextMenuListener((info) => { // eslint-disable-line |
|
|
}); |
|
|
|
|
|
ipcRenderer.on('settings-update', (e, data) => { |
|
|
spellchecker.toggleSpellchecker(data.enableSpellchecking); |
|
|
debug('Settings update received', data); |
|
|
|
|
|
spellchecker.toggleSpellchecker(data.enableSpellchecking); |
|
|
window.franzSettings = data; |
|
|
}); |
|
|
|
|
|
ipcRenderer.on('service-settings-update', (e, data) => { |
|
|
debug('Service settings update received', data); |
|
|
|
|
|
if (data.isDarkModeEnabled && !isDarkModeStyleInjected()) { |
|
|
injectDarkModeStyle(serviceData.recipe.path); |
|
|
|
|
|
debug('Enable service dark mode'); |
|
|
} else if (!data.isDarkModeEnabled && isDarkModeStyleInjected()) { |
|
|
removeDarkModeStyle(); |
|
|
|
|
|
debug('Disable service dark mode'); |
|
|
} |
|
|
}); |
|
|
|
|
|
// initSpellche |
|
|
// initSpellchecker |
|
|
|
|
|
document.addEventListener('DOMContentLoaded', () => { |
|
|
ipcRenderer.sendToHost('hello'); |
|
|