From 2ae6d00c564f5c56e6e57b8bfbb80284aef5af73 Mon Sep 17 00:00:00 2001 From: Romain Vigier Date: Fri, 16 Feb 2024 22:37:54 +0100 Subject: [PATCH] Extension: Add settings for day and night color scheme --- README.md | 11 +++ ....extensions.nightthemeswitcher.gschema.xml | 13 +++ src/enums/ColorScheme.js | 14 ++++ src/extension.js | 8 +- src/meson.build | 2 + src/modules/ColorSchemeSwitcher.js | 83 +++++++++++++++++++ src/modules/Switcher.js | 15 ++-- src/modules/SwitcherCommands.js | 1 + src/modules/SwitcherTheme.js | 1 + src/modules/Timer.js | 29 ++++--- src/po/POTFILES | 2 + 11 files changed, 160 insertions(+), 19 deletions(-) create mode 100644 src/enums/ColorScheme.js create mode 100644 src/modules/ColorSchemeSwitcher.js diff --git a/README.md b/README.md index 4c3c758..2344b59 100644 --- a/README.md +++ b/README.md @@ -88,3 +88,14 @@ If you know your coordinates, you can enter them in a hidden setting, and the ex ``` gsettings --schemadir ~/.local/share/gnome-shell/extensions/nightthemeswitcher@romainvigier.fr/schemas/ set org.gnome.shell.extensions.nightthemeswitcher.time location '($LATITUDE,$LONGITUDE)' ``` + +### I want to use the `prefer-light` color scheme or change the color scheme used during the day/night + +There are two hidden settings to change the color scheme used during the day or night: + +``` +gsettings --schemadir ~/.local/share/gnome-shell/extensions/nightthemeswitcher@romainvigier.fr/schemas/ set org.gnome.shell.extensions.nightthemeswitcher.color-scheme day $DESIRED_COLORSCHEME +gsettings --schemadir ~/.local/share/gnome-shell/extensions/nightthemeswitcher@romainvigier.fr/schemas/ set org.gnome.shell.extensions.nightthemeswitcher.color-scheme night $DESIRED_COLORSCHEME +``` + +With `$DESIRED_COLORSCHEME` one of `default`, `prefer-dark` or `prefer-light`. diff --git a/src/data/org.gnome.shell.extensions.nightthemeswitcher.gschema.xml b/src/data/org.gnome.shell.extensions.nightthemeswitcher.gschema.xml index b861f68..61c808b 100644 --- a/src/data/org.gnome.shell.extensions.nightthemeswitcher.gschema.xml +++ b/src/data/org.gnome.shell.extensions.nightthemeswitcher.gschema.xml @@ -4,6 +4,11 @@ SPDX-FileCopyrightText: Night Theme Switcher Contributors SPDX-License-Identifier: GPL-3.0-or-later --> + + + + + 0 @@ -87,4 +92,12 @@ SPDX-License-Identifier: GPL-3.0-or-later 0.4 + + + "default" + + + "prefer-dark" + + diff --git a/src/enums/ColorScheme.js b/src/enums/ColorScheme.js new file mode 100644 index 0000000..8459d05 --- /dev/null +++ b/src/enums/ColorScheme.js @@ -0,0 +1,14 @@ +// SPDX-FileCopyrightText: Night Theme Switcher Contributors +// SPDX-License-Identifier: GPL-3.0-or-later + +/** + * Color Schemes. + * + * @readonly + * @enum {string} + */ +export const ColorScheme = { + DEFAULT: 'default', + PREFER_DARK: 'prefer-dark', + PREFER_LIGHT: 'prefer-night', +}; diff --git a/src/extension.js b/src/extension.js index dfee068..5ee5df0 100644 --- a/src/extension.js +++ b/src/extension.js @@ -7,6 +7,7 @@ import { Extension } from 'resource:///org/gnome/shell/extensions/extension.js'; import * as debug from './debug.js'; +import { ColorSchemeSwitcher } from './modules/ColorSchemeSwitcher.js'; import { SwitcherCommands } from './modules/SwitcherCommands.js'; import { SwitcherThemeCursor, SwitcherThemeGtk, SwitcherThemeIcon, SwitcherThemeShell } from './modules/SwitcherTheme.js'; import { Timer } from './modules/Timer.js'; @@ -20,10 +21,15 @@ export default class NightThemeSwitcher extends Extension { debug.message('Enabling extension...'); - const timer = new Timer({ settings: this.getSettings(`${this.metadata['settings-schema']}.time`), openPrefs: this.openPrefs }); + const timer = new Timer({ + settings: this.getSettings(`${this.metadata['settings-schema']}.time`), + colorSchemeSettings: this.getSettings(`${this.metadata['settings-schema']}.color-scheme`), + openPrefs: this.openPrefs, + }); this.#modules.push(timer); [ + new ColorSchemeSwitcher({ timer, settings: this.getSettings(`${this.metadata['settings-schema']}.color-scheme`) }), new SwitcherThemeGtk({ timer, settings: this.getSettings(`${this.metadata['settings-schema']}.gtk-variants`) }), new SwitcherThemeIcon({ timer, settings: this.getSettings(`${this.metadata['settings-schema']}.icon-variants`) }), new SwitcherThemeShell({ timer, settings: this.getSettings(`${this.metadata['settings-schema']}.shell-variants`) }), diff --git a/src/meson.build b/src/meson.build index fd965c3..1d75acd 100644 --- a/src/meson.build +++ b/src/meson.build @@ -20,12 +20,14 @@ main = [ 'utils.js', ] enums = [ + 'enums/ColorScheme.js', 'enums/Time.js', ] icons = [ 'data/icons/nightthemeswitcher-symbolic.svg', ] modules = [ + 'modules/ColorSchemeSwitcher.js', 'modules/Switcher.js', 'modules/SwitcherCommands.js', 'modules/SwitcherTheme.js', diff --git a/src/modules/ColorSchemeSwitcher.js b/src/modules/ColorSchemeSwitcher.js new file mode 100644 index 0000000..f3a7567 --- /dev/null +++ b/src/modules/ColorSchemeSwitcher.js @@ -0,0 +1,83 @@ +// SPDX-FileCopyrightText: Night Theme Switcher Contributors +// SPDX-License-Identifier: GPL-3.0-or-later + +import Gio from 'gi://Gio'; + +import * as debug from '../debug.js'; + +import { Time } from '../enums/Time.js'; + +import { Switcher } from './Switcher.js'; + +/** + * The Color Scheme Switcher changes the system color scheme according to the time. + */ +export class ColorSchemeSwitcher extends Switcher { + #settings; + #interfaceSettings; + #timer; + + #settingsConnections = []; + + constructor({ timer, settings }) { + super({ + name: 'Color Scheme', + timer, + settings, + callback: time => this.#onTimeChanged(time), + }); + this.#timer = timer; + this.#settings = settings; + this.#interfaceSettings = new Gio.Settings({ schema: 'org.gnome.desktop.interface' }); + } + + enable() { + super.enable(); + this.#connectSettings(); + } + + disable() { + super.disable(); + this.#disconnectSettings(); + } + + #connectSettings() { + debug.message('Connecting Color Scheme Switcher to settings...'); + this.#settingsConnections.push({ + settings: this.#settings, + id: this.#settings.connect('changed::day', this.#onColorSchemeChanged.bind(this)), + }); + this.#settingsConnections.push({ + settings: this.#settings, + id: this.#settings.connect('changed::night', this.#onColorSchemeChanged.bind(this)), + }); + this.#settingsConnections.push({ + settings: this.#interfaceSettings, + id: this.#interfaceSettings.connect('changed::color-scheme', this.#onSystemColorSchemeChanged.bind(this)), + }); + } + + #disconnectSettings() { + this.#settingsConnections.forEach(({ settings, id }) => settings.disconnect(id)); + this.#settingsConnections = []; + debug.message('Disconnected Color Scheme Switcher from settings.'); + } + + #onTimeChanged(time) { + const colorScheme = time === Time.NIGHT ? this.#settings.get_string('night') : this.#settings.get_string('day'); + this.#interfaceSettings.set_string('color-scheme', colorScheme); + } + + #onColorSchemeChanged(_settings, time) { + const colorScheme = this.#settings.get_string(time); + debug.message(`${time} color scheme changed to ${colorScheme}.`); + if (time === this.#timer.time) + this.#interfaceSettings.set_string('color-scheme', colorScheme); + } + + #onSystemColorSchemeChanged() { + const colorScheme = this.#interfaceSettings.get_string('color-scheme'); + debug.message(`System color scheme changed to ${colorScheme}.`); + this.#timer.syncTimeToColorScheme(colorScheme); + } +} diff --git a/src/modules/Switcher.js b/src/modules/Switcher.js index a3686cf..7f4cef6 100644 --- a/src/modules/Switcher.js +++ b/src/modules/Switcher.js @@ -21,6 +21,7 @@ export class Switcher { #timer; #settings; #callback; + #disableable; #statusConnection = null; #timerConnection = null; @@ -29,20 +30,23 @@ export class Switcher { * @param {object} params Params object. * @param {string} params.name Name of the switcher. * @param {Timer} params.timer Timer to listen to. - * @param {Gio.Settings} params.settings Settings with the `enabled` key. + * @param {Gio.Settings} params.settings Settings. * @param {TimeChangedCallback} params.callback Callback function. + * @param {boolean} params.disableable If the switcher can be disabled using an `enabled` key in the settings. */ - constructor({ name, timer, settings, callback }) { + constructor({ name, timer, settings, callback, disableable = false }) { this.#name = name; this.#timer = timer; this.#settings = settings; this.#callback = callback; + this.#disableable = disableable; } enable() { debug.message(`Enabling ${this.#name} switcher...`); - this.#watchStatus(); - if (this.#settings.get_boolean('enabled')) { + if (this.#disableable) + this.#watchStatus(); + if (!this.#disableable || this.#settings.get_boolean('enabled')) { this.#connectTimer(); this.#onTimeChanged(); } @@ -52,7 +56,8 @@ export class Switcher { disable() { debug.message(`Disabling ${this.#name} switcher...`); this.#disconnectTimer(); - this.#unwatchStatus(); + if (this.#disableable) + this.#unwatchStatus(); debug.message(`${this.#name} switcher disabled.`); } diff --git a/src/modules/SwitcherCommands.js b/src/modules/SwitcherCommands.js index aad1251..404bd81 100644 --- a/src/modules/SwitcherCommands.js +++ b/src/modules/SwitcherCommands.js @@ -27,6 +27,7 @@ export class SwitcherCommands extends Switcher { timer, settings, callback: time => this.#onTimeChanged(time), + disableable: true, }); this.#settings = settings; } diff --git a/src/modules/SwitcherTheme.js b/src/modules/SwitcherTheme.js index 2ab66bc..c1db38c 100644 --- a/src/modules/SwitcherTheme.js +++ b/src/modules/SwitcherTheme.js @@ -54,6 +54,7 @@ export class SwitcherTheme extends Switcher { timer, settings, callback: time => this.#onTimeChanged(time), + disableable: true, }); this.#name = name; this.#timer = timer; diff --git a/src/modules/Timer.js b/src/modules/Timer.js index 75c5fec..4ee721e 100644 --- a/src/modules/Timer.js +++ b/src/modules/Timer.js @@ -14,6 +14,7 @@ import * as MessageTray from 'resource:///org/gnome/shell/ui/messageTray.js'; import * as debug from '../debug.js'; +import { ColorScheme } from '../enums/ColorScheme.js'; // eslint-disable-line no-unused-vars import { Time } from '../enums/Time.js'; @@ -28,6 +29,7 @@ import { Time } from '../enums/Time.js'; */ export class Timer extends GObject.Object { #settings; + #colorSchemeSettings; #interfaceSettings; #locationSettings; #openPrefs; @@ -54,11 +56,13 @@ export class Timer extends GObject.Object { /** * @param {object} params Params object. * @param {Gio.Settings} params.settings Timer settings. + * @param {Gio.Settings} params.colorSchemeSettings Color Scheme settings. * @param {Function} params.openPrefs Function opening the extension preferences. */ - constructor({ settings, openPrefs }) { + constructor({ settings, colorSchemeSettings, openPrefs }) { super(); this.#settings = settings; + this.#colorSchemeSettings = colorSchemeSettings; this.#interfaceSettings = new Gio.Settings({ schema: 'org.gnome.desktop.interface' }); this.#locationSettings = new Gio.Settings({ schema: 'org.gnome.system.location' }); this.#openPrefs = openPrefs; @@ -92,6 +96,13 @@ export class Timer extends GObject.Object { debug.message('Timer disabled.'); } + /** + * @param {ColorScheme} colorScheme Color scheme to sync the time to. + */ + syncTimeToColorScheme(colorScheme) { + this.#changeTime(this.#colorSchemeToTime(colorScheme), true); + } + get time() { return this.#time || Time.UNKNOWN; @@ -113,7 +124,7 @@ export class Timer extends GObject.Object { debug.message(manual ? `Time manually set to ${time}.` : `Time changed to ${time}.`); layoutManager.screenTransition.run(); - this.#interfaceSettings.set_string('color-scheme', time === Time.NIGHT ? 'prefer-dark' : 'default'); + this.notify('time'); } @@ -132,10 +143,6 @@ export class Timer extends GObject.Object { settings: this.#settings, id: this.#settings.connect('changed::nightthemeswitcher-ondemand-keybinding', this.#onOndemandKeybindingChanged.bind(this)), }); - this.#settingsConnections.push({ - settings: this.#interfaceSettings, - id: this.#interfaceSettings.connect('changed::color-scheme', this.#onColorSchemeChanged.bind(this)), - }); // Only listen to the offset setting when not using a manual schedule if (!this.#settings.get_boolean('manual-schedule')) { this.#settingsConnections.push({ @@ -234,8 +241,8 @@ export class Timer extends GObject.Object { } - #colorSchemeToTime() { - return this.#interfaceSettings.get_string('color-scheme') === 'prefer-dark' ? Time.NIGHT : Time.DAY; + #colorSchemeToTime(colorScheme) { + return colorScheme === this.#colorSchemeSettings.get_string('night') ? Time.NIGHT : Time.DAY; } @@ -258,10 +265,6 @@ export class Timer extends GObject.Object { this.#addKeybinding(); } - #onColorSchemeChanged() { - this.#changeTime(this.#colorSchemeToTime(), true); - } - #onGeoclueReady(_geoclue, result) { try { this.#geoclue = Geoclue.Simple.new_finish(result); @@ -325,7 +328,7 @@ export class Timer extends GObject.Object { return hour >= sunrise || hour < sunset ? Time.DAY : Time.NIGHT; // Sunset and Sunrise times are identical; preserve current theme else - return this.#time || this.#colorSchemeToTime(); + return this.#time || this.#colorSchemeToTime(this.#interfaceSettings.get_string('color-scheme')); } #updateSuntimes() { diff --git a/src/po/POTFILES b/src/po/POTFILES index 224ee9e..bd1b7e0 100644 --- a/src/po/POTFILES +++ b/src/po/POTFILES @@ -17,8 +17,10 @@ src/data/ui/ShortcutButton.ui src/data/ui/ThemesPage.ui src/data/ui/TimeChooser.ui +src/enums/ColorScheme.js src/enums/Time.js +src/modules/ColorSchemeSwitcher.js src/modules/Switcher.js src/modules/SwitcherCommands.js src/modules/SwitcherTheme.js