Skip to content

Commit

Permalink
Finalise work on the appearance provider
Browse files Browse the repository at this point in the history
  • Loading branch information
nathanlesage committed Apr 12, 2019
1 parent 591d010 commit 60163bf
Show file tree
Hide file tree
Showing 10 changed files with 131 additions and 22 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# (no version assigned)
# 1.3.0

## GUI and Functionality

- **New Feature**: Zettlr can now automatically switch between light and dark mode either based on a fixed schedule or, if you are using macOS, based on the appearance of the operating system.
- **New Feature**: Add words to the user defined dictionary.
- Display contributors tab on the about dialog containing the names of all authors of the translation files.
- The dictionary loading mechanism works far more reliably now.
Expand All @@ -10,6 +11,7 @@

- Re-throw errors during command run in Zettlr main class.
- Moved the dictionary to its own dedicated provider for more versatility and improved upon its functionality.
- Created an appearance provider which takes care of switching the Zettlr theming based upon user choices.

# 1.2.3

Expand Down
12 changes: 12 additions & 0 deletions resources/less/geometry/modal.less
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,18 @@
font-size: inherit;
outline:none;
margin-bottom:1em;

&.inline {
width: auto;
display: inline-block;
margin-bottom: 0;
}

&.time {
// Time fields can be extra narrow
width: 70px;
text-align: center;
}
}

select {
Expand Down
36 changes: 35 additions & 1 deletion resources/templates/dialog/preferences.handlebars
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,41 @@
</label>
<label for="pref-sorting-ascii">{{i18n "dialog.preferences.sorting_ascii"}}</label>
</div>
</div>
<hr>
<!-- Now the auto dark mode settings -->
<p>
{{i18n "dialog.preferences.auto_dark_mode_explanation"}}
</p>
<div class="cb-group">
<label class="radio-toggle">
<input type="radio" name="autoDarkMode" value="off" id="auto-dark-mode-off" {{#ifCond autoDarkMode '=' 'off'}}checked="checked"{{/ifCond}}>
<div class="toggle"></div>
</label>
<label for="auto-dark-mode-off">{{i18n "dialog.preferences.auto_dark_mode_off"}}</label>
</div>
<div class="cb-group">
<label class="radio-toggle">
<input type="radio" name="autoDarkMode" value="schedule" id="auto-dark-mode-schedule" {{#ifCond autoDarkMode '=' 'schedule'}}checked="checked"{{/ifCond}}>
<div class="toggle"></div>
</label>
<label for="auto-dark-mode-schedule">
{{i18n "dialog.preferences.auto_dark_mode_schedule"}}
<input type="text" class="inline time" pattern="\d{2}:\d{2}" title="{{i18n "dialog.preferences.auto_dark_mode_schedule_format"}}" value="{{ autoDarkModeStart }}" name="autoDarkModeStart">
&mdash;
<input type="text" class="inline time" pattern="\d{2}:\d{2}" title="{{i18n "dialog.preferences.auto_dark_mode_schedule_format"}}" value="{{ autoDarkModeEnd }}" name="autoDarkModeEnd">
</label>
</div>
{{#if hasOSDarkMode}}
<!-- Only for macOS: Enable system switching -->
<div class="cb-group">
<label class="radio-toggle">
<input type="radio" name="autoDarkMode" value="system" id="auto-dark-mode-system" {{#ifCond autoDarkMode '=' 'system'}}checked="checked"{{/ifCond}}>
<div class="toggle"></div>
</label>
<label for="auto-dark-mode-system">{{i18n "dialog.preferences.auto_dark_mode_system"}}</label>
</div>
{{/if}}
</div> <!-- End box right -->
</div>
<!-- Editor related options -->
<div id="prefs-tabs-editor">
Expand Down
5 changes: 5 additions & 0 deletions source/common/lang/de-DE.json
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,11 @@
"pandoc_default": "Standard: pandoc",
"xelatex_default": "Standard: xelatex",
"nightmode": "Dunkles Thema",
"auto_dark_mode_explanation": "Automatisch ins dunkle Thema wechseln",
"auto_dark_mode_off": "Aus",
"auto_dark_mode_system": "Folge Betriebssystem",
"auto_dark_mode_schedule": "Zeit",
"auto_dark_mode_schedule_format": "HH:MM",
"snippets": "Textfragmente anzeigen",
"hide_dirs": "Verstecke Verzeichnisse während globaler Suchen",
"combiner_explanation": "Modus der Seitenleiste",
Expand Down
5 changes: 5 additions & 0 deletions source/common/lang/en-GB.json
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,11 @@
"pandoc_default": "Default: pandoc",
"xelatex_default": "Default: xelatex",
"nightmode": "Night mode",
"auto_dark_mode_explanation": "Automatically switch to dark mode",
"auto_dark_mode_off": "Off",
"auto_dark_mode_system": "Follow Operating System",
"auto_dark_mode_schedule": "Schedule",
"auto_dark_mode_schedule_format": "HH:MM (24h format)",
"snippets": "Text snippets",
"hide_dirs": "Hide directories during global search",
"combiner_explanation": "Side pane mode",
Expand Down
5 changes: 5 additions & 0 deletions source/common/lang/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,11 @@
"pandoc_default": "Default: pandoc",
"xelatex_default": "Default: xelatex",
"nightmode": "Night mode",
"auto_dark_mode_explanation": "Automatically switch to dark mode",
"auto_dark_mode_off": "Off",
"auto_dark_mode_system": "Follow Operating System",
"auto_dark_mode_schedule": "Schedule",
"auto_dark_mode_schedule_format": "HH:MM (24h format)",
"snippets": "Text snippets",
"hide_dirs": "Hide directories during global search",
"combiner_explanation": "Side pane mode",
Expand Down
5 changes: 5 additions & 0 deletions source/common/lang/fr-FR.json
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,11 @@
},
"attachments_info": "Entrez toutes les extension de fichiers que vous voulez voir dans la liste d'annexes. S\u00e9parez les par des virgules. Les modification prendront effet au prochain red\u00e9marrage.",
"autoCloseBrackets": "Fermer les pairs du caract\u00e8res suivants: ()[]{}'\"\"\u00bb\u00ab\u201e\u201c\u201c\u201d\u2018\u2019__``",
"auto_dark_mode_explanation": "Basculer automatiquement en mode sombre",
"auto_dark_mode_off": "Non",
"auto_dark_mode_schedule": "Programme",
"auto_dark_mode_schedule_format": "HH:MM",
"auto_dark_mode_system": "Suivre le syst\u00e8me d'exploitation",
"checkForBeta": "Notifier-moi \u00e0 propos des versions b\u00eata.",
"choose_file": "Choisier le fichier \u2026",
"combiner_collapsed": "\u00c9troit &mdash; Remontrer Preview ou Tree View",
Expand Down
1 change: 1 addition & 0 deletions source/common/validation.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"darkTheme": "required|boolean|default:false",
"autoDarkMode": "required|string|in:off,system,schedule,auto|default:off",
"snippets": "required|boolean|default:false",
"appLang": "required|string|min:5|max:7|default:en_US",
"combinerState": "required|string|in:collapsed,expanded|default:collapsed",
Expand Down
77 changes: 57 additions & 20 deletions source/main/providers/appearance-provider.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@ const EventEmitter = require('events')
const { systemPreferences } = require('electron')

/**
* This class manages the coloured tags of the app. It reads the tags on each
* start of the app and writes them after they have been changed.
* This class manages automatic changes in the appearance of the app. It won't
* do anything, if the scheduler is set to off, listen to changes in the
* operating system's appearance if set to system, and switch the mode on a given
* time if set to schedule.
*/
class AppearanceProvider extends EventEmitter {
/**
Expand All @@ -31,42 +33,63 @@ class AppearanceProvider extends EventEmitter {
// - off: Do nothing in here
// - schedule: Ask the clock when to switch
// - system: Only on macOS (probably Windows as well): Listen to mode changes
// - sunrise/sunset: Basically schedule, only calculated based on timezone
// - auto: Basically schedule, only calculated based on timezone (to be implemented)

this._mode = 'system' // global.config.get('autoDarkMode')
// Initiate everything
this._mode = global.config.get('autoDarkMode')
this._scheduleWasDark = this._isItDark() // Preset where we currently are
this._isDarkMode = global.config.get('darkTheme')
this.calculateSchedule()
this._recalculateSchedule() // Parse the start and end times

/**
* On macOS, subscribe to AppleInterfaceThemeChangedNotifications to be notified
* whenever the system's theme changes. The actual theme change is only applied,
* if the config setting is set to "system", i.e.: follow system appearance.
*/
if (process.platform === 'darwin') {
systemPreferences.subscribeNotification('AppleInterfaceThemeChangedNotification', (event, userInfo) => {
// Only react to these notifications if the schedule is set to 'system'
if (this._mode !== 'system') return
// Set the var accordingly
global.config.set('darkTheme', systemPreferences.isDarkMode())
})
}

// Subscribe to configuration updates
global.config.on('update', (option) => {
// Set internal vars accordingly
if (option === 'autoDarkMode') this._mode = global.config.get('autoDarkMode')
if (option === 'darkTheme') this._isDarkMode = global.config.get('darkTheme')
if (option === 'autoDarkModeStart') this._recalculateSchedule()
if (option === 'autoDarkModeEnd') this._recalculateSchedule()
})

// new Date().getTimezoneOffset() <-- This returns the LOCAL timezone offset in minutes, so divide by 60 then you have the hours
this.tick() // Begin the tick
}

tick () {
if (this._mode === 'system' && process.platform === 'darwin') {
if (systemPreferences.isDarkMode() && !this._isDarkMode) {
global.config.set('darkTheme', true)
}

if (!systemPreferences.isDarkMode() && this._isDarkMode) {
global.config.set('darkTheme', false)
if (this._mode === 'schedule') {
// By tracking the status of the time, we avoid annoying people by forcing
// the dark or light theme even if they decide to change it later on. This
// time Zettlr will only trigger a theme change if we traversed from
// daytime to nighttime, and leave out the question of whether or not dark
// mode has been active or not.
if (this._scheduleWasDark !== this._isItDark()) {
// The schedule just changed -> change the theme
global.config.set('darkTheme', this._isItDark())
this._scheduleWasDark = this._isItDark()
}
} else if (this._mode === 'schedule') {
// First get the current time index
// 2. If now between start and end and not in dark mode, enter it
// 3. Else if dark mode true: Leave it
// let now = new Date()
}
// Have a tick every two seconds
setTimeout(() => { this.tick() }, 2000)
// Have a tick (tac)
setTimeout(() => { this.tick() }, 1000)
}

calculateSchedule () {
/**
* Parses the current auto dark mode start and end times for quick access.
* @return {void} No return.
*/
_recalculateSchedule () {
let start = global.config.get('autoDarkModeStart').split(':')
let end = global.config.get('autoDarkModeEnd').split(':')

Expand All @@ -76,6 +99,20 @@ class AppearanceProvider extends EventEmitter {
this._endMin = parseInt(end[1], 10)
}

/**
* Returns true if, according to the schedule, Zettlr should now be in dark
* mode.
* @return {Boolean} Whether or not time indicates it should be dark now.
*/
_isItDark () {
let now = new Date()
let nowMin = now.getMinutes()
let nowHours = now.getHours()

return (nowHours >= this._startHour && nowMin >= this._startMin &&
nowHours <= this._endHour && nowMin <= this._endMin)
}

/**
* Shuts down the provider
* @return {Boolean} Always returns true
Expand Down
3 changes: 3 additions & 0 deletions source/renderer/dialog/preferences.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ class PreferencesDialog extends ZettlrDialog {
}
// The template expects a simple string
data.attachmentExtensions = data.attachmentExtensions.join(', ')

// Determine the ability of the OS to switch to dark mode
data.hasOSDarkMode = (process.platform === 'darwin')
return data
}

Expand Down

0 comments on commit 60163bf

Please sign in to comment.