Add Location Services and manual schedule support
This commit is contained in:
@@ -74,7 +74,7 @@ pot:
|
|||||||
--package-name="$(NAME)" \
|
--package-name="$(NAME)" \
|
||||||
--package-version="$(VERSION)" \
|
--package-version="$(VERSION)" \
|
||||||
--output=./src/po/$(UUID).pot \
|
--output=./src/po/$(UUID).pot \
|
||||||
./src/**/*.js ./src/**/*.xml
|
./src/*.js ./src/**/*.js ./src/**/*.xml
|
||||||
sed -i '1,4s/SOME DESCRIPTIVE TITLE./$(NAME)/g' ./src/po/$(UUID).pot
|
sed -i '1,4s/SOME DESCRIPTIVE TITLE./$(NAME)/g' ./src/po/$(UUID).pot
|
||||||
sed -i '1,4s/YEAR/$(COPYRIGHT_YEAR)/' ./src/po/$(UUID).pot
|
sed -i '1,4s/YEAR/$(COPYRIGHT_YEAR)/' ./src/po/$(UUID).pot
|
||||||
sed -i "1,4s/THE PACKAGE'S COPYRIGHT HOLDER/$(AUTHOR_NAME)/" ./src/po/$(UUID).pot
|
sed -i "1,4s/THE PACKAGE'S COPYRIGHT HOLDER/$(AUTHOR_NAME)/" ./src/po/$(UUID).pot
|
||||||
|
|||||||
@@ -2,7 +2,9 @@
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
Automatically toggle between your light and dark GTK theme variants when Night Light activates.
|
Automatically toggle between your light and dark GTK theme variants.
|
||||||
|
|
||||||
|
Supports Night Light, Location Services and manual schedule.
|
||||||
|
|
||||||
_Do you need to change your GNOME shell theme as well? Try [Night Shell Switcher](https://gitlab.com/rmnvgr/nightshellswitcher-gnome-shell-extension/)!_
|
_Do you need to change your GNOME shell theme as well? Try [Night Shell Switcher](https://gitlab.com/rmnvgr/nightshellswitcher-gnome-shell-extension/)!_
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -1,4 +1,6 @@
|
|||||||
Night mode for GNOME apps! Automatically toggle between your light and dark GTK theme variants when Night Light activates.
|
Night mode for GNOME apps! Automatically toggle between your light and dark GTK theme variants.
|
||||||
|
|
||||||
|
Supports Night Light, Location Services and manual schedule.
|
||||||
|
|
||||||
These themes have been tested and work:
|
These themes have been tested and work:
|
||||||
- Adapta
|
- Adapta
|
||||||
|
|||||||
+58
-3
@@ -16,13 +16,68 @@ You should have received a copy of the GNU General Public License along with
|
|||||||
this program. If not, see <http s ://www.gnu.org/licenses/>.
|
this program. If not, see <http s ://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var EXT_NAME = 'Night Theme Switcher';
|
|
||||||
var EXT_UUID = 'nightthemeswitcher@romainvigier.fr';
|
|
||||||
|
|
||||||
var THEME_GSETTINGS_SCHEMA = 'org.gnome.desktop.interface';
|
var THEME_GSETTINGS_SCHEMA = 'org.gnome.desktop.interface';
|
||||||
var THEME_GSETTINGS_PROPERTY = 'gtk-theme';
|
var THEME_GSETTINGS_PROPERTY = 'gtk-theme';
|
||||||
|
|
||||||
var NIGHTLIGHT_GSETTINGS_SCHEMA = 'org.gnome.settings-daemon.plugins.color';
|
var NIGHTLIGHT_GSETTINGS_SCHEMA = 'org.gnome.settings-daemon.plugins.color';
|
||||||
var NIGHTLIGHT_GSETTINGS_PROPERTY = 'night-light-enabled';
|
var NIGHTLIGHT_GSETTINGS_PROPERTY = 'night-light-enabled';
|
||||||
|
|
||||||
|
var LOCATION_GSETTINGS_SCHEMA = 'org.gnome.system.location';
|
||||||
|
var LOCATION_GSETTINGS_PROPERTY = 'enabled';
|
||||||
|
|
||||||
|
// GeoClue2 interfaces from https://gitlab.freedesktop.org/geoclue/geoclue/
|
||||||
|
var GEOCLUE_MANAGER_INTERFACE = `
|
||||||
|
<node>
|
||||||
|
<interface name="org.freedesktop.GeoClue2.Manager">
|
||||||
|
<property name="InUse" type="b" access="read"/>
|
||||||
|
<property name="AvailableAccuracyLevel" type="u" access="read"/>
|
||||||
|
<method name="GetClient">
|
||||||
|
<arg name="client" type="o" direction="out"/>
|
||||||
|
</method>
|
||||||
|
<method name="CreateClient">
|
||||||
|
<arg name="client" type="o" direction="out"/>
|
||||||
|
</method>
|
||||||
|
<method name="DeleteClient">
|
||||||
|
<arg name="client" type="o" direction="in"/>
|
||||||
|
</method>
|
||||||
|
<method name="AddAgent">
|
||||||
|
<arg name="id" type="s" direction="in"/>
|
||||||
|
</method>
|
||||||
|
</interface>
|
||||||
|
</node>`;
|
||||||
|
var GEOCLUE_CLIENT_INTERFACE = `
|
||||||
|
<node>
|
||||||
|
<interface name="org.freedesktop.GeoClue2.Client">
|
||||||
|
<property name="Location" type="o" access="read"/>
|
||||||
|
<property name="DistanceThreshold" type="u" access="readwrite">
|
||||||
|
<annotation name="org.freedesktop.Accounts.DefaultValue" value="0"/>
|
||||||
|
</property>
|
||||||
|
<property name="TimeThreshold" type="u" access="readwrite">
|
||||||
|
<annotation name="org.freedesktop.Accounts.DefaultValue" value="0"/>
|
||||||
|
</property>
|
||||||
|
<property name="DesktopId" type="s" access="readwrite"/>
|
||||||
|
<property name="RequestedAccuracyLevel" type="u" access="readwrite"/>
|
||||||
|
<property name="Active" type="b" access="read"/>
|
||||||
|
<method name="Start"/>
|
||||||
|
<method name="Stop"/>
|
||||||
|
<signal name="LocationUpdated">
|
||||||
|
<arg name="old" type="o"/>
|
||||||
|
<arg name="new" type="o"/>
|
||||||
|
</signal>
|
||||||
|
</interface>
|
||||||
|
</node>`;
|
||||||
|
var GEOCLUE_LOCATION_INTERFACE = `
|
||||||
|
<node>
|
||||||
|
<interface name="org.freedesktop.GeoClue2.Location">
|
||||||
|
<property name="Latitude" type="d" access="read"/>
|
||||||
|
<property name="Longitude" type="d" access="read"/>
|
||||||
|
<property name="Accuracy" type="d" access="read"/>
|
||||||
|
<property name="Altitude" type="d" access="read"/>
|
||||||
|
<property name="Speed" type="d" access="read"/>
|
||||||
|
<property name="Heading" type="d" access="read"/>
|
||||||
|
<property name="Description" type="s" access="read"/>
|
||||||
|
<property name="Timestamp" type="(tt)" access="read"/>
|
||||||
|
</interface>
|
||||||
|
</node>`;
|
||||||
|
|
||||||
var debug = false;
|
var debug = false;
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "Night Theme Switcher",
|
"name": "Night Theme Switcher",
|
||||||
"description": "Automatically toggle between your light and dark GTK theme variants when Night Light activates.",
|
"description": "Automatically toggle between your light and dark GTK theme variants.",
|
||||||
"uuid": "nightthemeswitcher@romainvigier.fr",
|
"uuid": "nightthemeswitcher@romainvigier.fr",
|
||||||
"gettext-domain": "nightthemeswitcher@romainvigier.fr",
|
"gettext-domain": "nightthemeswitcher@romainvigier.fr",
|
||||||
"settings-schema": "org.gnome.shell.extensions.nightthemeswitcher",
|
"settings-schema": "org.gnome.shell.extensions.nightthemeswitcher",
|
||||||
|
|||||||
@@ -1,186 +0,0 @@
|
|||||||
/*
|
|
||||||
Night Theme Switcher Gnome Shell extension
|
|
||||||
|
|
||||||
Copyright (C) 2020 Romain Vigier
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify it under
|
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
|
||||||
Foundation, either version 3 of the License, or (at your option) any later
|
|
||||||
version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with
|
|
||||||
this program. If not, see <http s ://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const { extensionUtils, fileUtils } = imports.misc;
|
|
||||||
const { Gio } = imports.gi;
|
|
||||||
const { main } = imports.ui;
|
|
||||||
|
|
||||||
const Me = extensionUtils.getCurrentExtension();
|
|
||||||
const config = Me.imports.config;
|
|
||||||
|
|
||||||
const { log_debug } = Me.imports.utils;
|
|
||||||
|
|
||||||
const Gettext = imports.gettext.domain(config.EXT_UUID);
|
|
||||||
const _ = Gettext.gettext;
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
The Nightlighter establishes a connection with the session bus to get the
|
|
||||||
current Night Light status. It listens to changes and reports them.
|
|
||||||
|
|
||||||
As Night Light is essential for the extension to work, it continuously checks
|
|
||||||
if it is enabled and warns the user if that's not the case. To not overwhelm
|
|
||||||
the user with notifications, it only warns once and then only listens to Night
|
|
||||||
Light changes to reactivate itself automatically.
|
|
||||||
*/
|
|
||||||
|
|
||||||
var Nightlighter = class {
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
log_debug('Initializing Nightlighter...');
|
|
||||||
this.first_nightlight_not_enabled_warning = true;
|
|
||||||
this.nightlight_gsettings = new Gio.Settings({ schema: config.NIGHTLIGHT_GSETTINGS_SCHEMA });
|
|
||||||
log_debug('Nightlighter initialized.');
|
|
||||||
}
|
|
||||||
|
|
||||||
enable() {
|
|
||||||
log_debug('Enabling NightLighter...');
|
|
||||||
try {
|
|
||||||
this._listen_to_nightlight_status();
|
|
||||||
this._check_nightlight_status();
|
|
||||||
this._connect_to_dbus();
|
|
||||||
this._listen_to_nightlight_changes();
|
|
||||||
this.emit();
|
|
||||||
log_debug('Nightlighter enabled.');
|
|
||||||
}
|
|
||||||
catch(e) {
|
|
||||||
if ( e.message ) {
|
|
||||||
main.notifyError(config.EXT_NAME, e.message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
disable() {
|
|
||||||
log_debug('Disabling Nightlighter...');
|
|
||||||
this._stop_listening_to_nightlight_status();
|
|
||||||
this._stop_listening_to_nightlight_changes();
|
|
||||||
this._disconnect_from_dbus();
|
|
||||||
log_debug('Nightlighter disabled.');
|
|
||||||
}
|
|
||||||
|
|
||||||
get time() {
|
|
||||||
return this._get_nightlight_active() ? 'night' : 'day';
|
|
||||||
}
|
|
||||||
|
|
||||||
subscribe(callback) {
|
|
||||||
this.nightlight_change_callback = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
emit() {
|
|
||||||
if ( this.nightlight_change_callback ) {
|
|
||||||
this.nightlight_change_callback();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_is_nightlight_enabled() {
|
|
||||||
return this.nightlight_gsettings.get_boolean(config.NIGHTLIGHT_GSETTINGS_PROPERTY);
|
|
||||||
}
|
|
||||||
|
|
||||||
_check_nightlight_status() {
|
|
||||||
if ( !this._is_nightlight_enabled() ) {
|
|
||||||
if ( this.first_nightlight_not_enabled_warning ) {
|
|
||||||
this.first_nightlight_not_enabled_warning = false;
|
|
||||||
const message = _('Night Light must be enabled to use this extension. Please enable it in your system settings.');
|
|
||||||
throw new Error(message);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new Error();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_listen_to_nightlight_status() {
|
|
||||||
if ( !this.nightlight_status_connect ) {
|
|
||||||
this.nightlight_status_connect = this.nightlight_gsettings.connect(
|
|
||||||
'changed::' + config.NIGHTLIGHT_GSETTINGS_PROPERTY,
|
|
||||||
this._on_nightlight_status_change.bind(this)
|
|
||||||
);
|
|
||||||
log_debug('Listening to Night Light status changes...');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_stop_listening_to_nightlight_status() {
|
|
||||||
if ( this.nightlight_gsettings && this.nightlight_status_connect ) {
|
|
||||||
this.nightlight_gsettings.disconnect(this.nightlight_status_connect);
|
|
||||||
this.nightlight_status_connect = null;
|
|
||||||
log_debug('Stopped listening to Night Light status changes.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_on_nightlight_status_change() {
|
|
||||||
log_debug('Night Light status has changed.');
|
|
||||||
this.enable();
|
|
||||||
}
|
|
||||||
|
|
||||||
_connect_to_dbus() {
|
|
||||||
if ( !this.dbus_proxy ) {
|
|
||||||
log_debug('Connecting to DBus...');
|
|
||||||
const color_interface = fileUtils.loadInterfaceXML('org.gnome.SettingsDaemon.Color');
|
|
||||||
const ColorProxy = Gio.DBusProxy.makeProxyWrapper(color_interface);
|
|
||||||
this.dbus_proxy = new ColorProxy(
|
|
||||||
Gio.DBus.session,
|
|
||||||
'org.gnome.SettingsDaemon.Color',
|
|
||||||
'/org/gnome/SettingsDaemon/Color'
|
|
||||||
);
|
|
||||||
if ( !this.dbus_proxy ) {
|
|
||||||
const message = _('Unable to create proxy to the session bus.');
|
|
||||||
throw new Error(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_disconnect_from_dbus() {
|
|
||||||
if ( this.dbus_proxy ) {
|
|
||||||
this.dbus_proxy = null;
|
|
||||||
log_debug('Disconnected from DBus.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_listen_to_nightlight_changes() {
|
|
||||||
if ( !this.nightlight_changes_connect ) {
|
|
||||||
this.nightlight_changes_connect = this.dbus_proxy.connect(
|
|
||||||
'g-properties-changed',
|
|
||||||
this._on_nightlight_change.bind(this)
|
|
||||||
);
|
|
||||||
log_debug('Listening to Night Light changes...');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_stop_listening_to_nightlight_changes() {
|
|
||||||
if ( this.dbus_proxy && this.nightlight_changes_connect ) {
|
|
||||||
this.dbus_proxy.disconnect(this.nightlight_changes_connect);
|
|
||||||
this.nightlight_changes_connect = null;
|
|
||||||
log_debug('Stopped listening to Night Light changes.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_on_nightlight_change(dbus_properties, dbus_signals) {
|
|
||||||
const signals = dbus_signals.deep_unpack();
|
|
||||||
if ( signals.NightLightActive ) {
|
|
||||||
log_debug('Night Light has become ' + (signals.NightLightActive.unpack() ? '' : 'in') + 'active.');
|
|
||||||
this.emit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_get_nightlight_active() {
|
|
||||||
if ( this.dbus_proxy ) {
|
|
||||||
return this.dbus_proxy.NightLightActive;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
+19
-21
@@ -24,31 +24,30 @@ const config = Me.imports.config;
|
|||||||
|
|
||||||
const { log_debug } = Me.imports.utils;
|
const { log_debug } = Me.imports.utils;
|
||||||
|
|
||||||
const { Nightlighter } = Me.imports.modules.Nightlighter;
|
|
||||||
const { Themer } = Me.imports.modules.Themer;
|
const { Themer } = Me.imports.modules.Themer;
|
||||||
|
const { Timer } = Me.imports.modules.Timer;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The Switcher is the orchestrator of the extension.
|
The Switcher is the orchestrator of the extension.
|
||||||
|
|
||||||
When the extension is enabled, it asks the Themer to listen to theme changes
|
When the extension is enabled, it asks the Themer to listen to theme changes
|
||||||
from the user and the Nightlighter to listen to changes in the Night Light
|
from the user and the Timer to listen to changes in the current time:
|
||||||
status:
|
|
||||||
- On theme change, it asks the Themer to guess the new day and night
|
- On theme change, it asks the Themer to guess the new day and night
|
||||||
variants for that theme, and to apply the relevant variant depending on the
|
variants for that theme, and to apply the relevant variant depending on the
|
||||||
Night Light status.
|
time of the day.
|
||||||
- On Night Light activation or deactivation, it asks the Themer to apply
|
- On time of the day change, it asks the Themer to apply the relevant
|
||||||
the relevant variant.
|
variant.
|
||||||
|
|
||||||
When the extension is disabled, it asks the Themer and the Nightlighter to
|
When the extension is disabled, it asks the Themer and the Timer to disable
|
||||||
disable themselves.
|
themselves.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var Switcher = class {
|
var Switcher = class {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
log_debug('Initializing extension...');
|
log_debug('Initializing extension...');
|
||||||
extensionUtils.initTranslations(config.EXT_UUID);
|
extensionUtils.initTranslations(Me.metadata.uuid);
|
||||||
log_debug('Extension initialized.');
|
log_debug('Extension initialized.');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,17 +56,16 @@ var Switcher = class {
|
|||||||
try {
|
try {
|
||||||
this.theme = new Themer();
|
this.theme = new Themer();
|
||||||
this.theme.enable();
|
this.theme.enable();
|
||||||
this.theme.subscribe(this._on_theme_change.bind(this));
|
this.theme.subscribe(this._on_theme_changed.bind(this));
|
||||||
|
|
||||||
this.nightlight = new Nightlighter();
|
this.time = new Timer();
|
||||||
this.nightlight.enable();
|
this.time.enable();
|
||||||
this.nightlight.subscribe(this._on_nightlight_change.bind(this));
|
this.time.subscribe(this._on_time_changed.bind(this));
|
||||||
|
|
||||||
this.theme.set_variant(this.nightlight.time);
|
|
||||||
log_debug('Extension enabled.');
|
log_debug('Extension enabled.');
|
||||||
}
|
}
|
||||||
catch(e) {
|
catch(e) {
|
||||||
main.notifyError(config.EXT_NAME, e.message);
|
main.notifyError(Me.metadata.name, e.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,23 +73,23 @@ var Switcher = class {
|
|||||||
log_debug('Disabling extension...');
|
log_debug('Disabling extension...');
|
||||||
try {
|
try {
|
||||||
this.theme.disable();
|
this.theme.disable();
|
||||||
this.nightlight.disable();
|
this.time.disable();
|
||||||
}
|
}
|
||||||
catch(e) {} // Since we're disabling, we'll just ignore errors.
|
catch(e) {} // Since we're disabling, we'll just ignore errors.
|
||||||
finally {
|
finally {
|
||||||
this.theme = null;
|
this.theme = null;
|
||||||
this.nightlight = null;
|
this.time = null;
|
||||||
}
|
}
|
||||||
log_debug('Extension disabled.');
|
log_debug('Extension disabled.');
|
||||||
}
|
}
|
||||||
|
|
||||||
_on_theme_change() {
|
_on_theme_changed() {
|
||||||
this.theme.update_variants();
|
this.theme.update_variants();
|
||||||
this.theme.set_variant(this.nightlight.time);
|
this.theme.set_variant(this.time.current);
|
||||||
}
|
}
|
||||||
|
|
||||||
_on_nightlight_change() {
|
_on_time_changed() {
|
||||||
this.theme.set_variant(this.nightlight.time);
|
this.theme.set_variant(this.time.current);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ var Themer = class {
|
|||||||
if ( !this.theme_change_connect ) {
|
if ( !this.theme_change_connect ) {
|
||||||
this.theme_change_connect = this.theme_gsettings.connect(
|
this.theme_change_connect = this.theme_gsettings.connect(
|
||||||
'changed::' + config.THEME_GSETTINGS_PROPERTY,
|
'changed::' + config.THEME_GSETTINGS_PROPERTY,
|
||||||
this._on_theme_change.bind(this)
|
this._on_theme_changed.bind(this)
|
||||||
);
|
);
|
||||||
log_debug('Listening for theme changes...');
|
log_debug('Listening for theme changes...');
|
||||||
}
|
}
|
||||||
@@ -134,7 +134,7 @@ var Themer = class {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_on_theme_change() {
|
_on_theme_changed() {
|
||||||
log_debug(`Theme has changed to "${this.current_theme}".`);
|
log_debug(`Theme has changed to "${this.current_theme}".`);
|
||||||
this.emit();
|
this.emit();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,545 @@
|
|||||||
|
/*
|
||||||
|
Night Theme Switcher Gnome Shell extension
|
||||||
|
|
||||||
|
Copyright (C) 2020 Romain Vigier
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify it under
|
||||||
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
|
Foundation, either version 3 of the License, or (at your option) any later
|
||||||
|
version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with
|
||||||
|
this program. If not, see <http s ://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const MainLoop = imports.mainloop;
|
||||||
|
const { Gio, GLib } = imports.gi;
|
||||||
|
const { extensionUtils, fileUtils } = imports.misc;
|
||||||
|
const { main } = imports.ui;
|
||||||
|
|
||||||
|
const Me = extensionUtils.getCurrentExtension();
|
||||||
|
const config = Me.imports.config;
|
||||||
|
|
||||||
|
const { log_debug } = Me.imports.utils;
|
||||||
|
|
||||||
|
const Gettext = imports.gettext.domain(Me.metadata.uuid);
|
||||||
|
const _ = Gettext.gettext;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
The Timer checks for changes in the time of day and reports them.
|
||||||
|
|
||||||
|
I can either use Night Light or Location Services as a source.
|
||||||
|
|
||||||
|
As Night Light or Location Services are essential for the extension to work,
|
||||||
|
it continuously checks if one of them is enabled and warns the user if that's
|
||||||
|
not the case. To not overwhelm the user with notifications, it only warns once
|
||||||
|
and then only listens to Night Light or Location Services changes to reactivate
|
||||||
|
itself automatically.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var Timer = class {
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
log_debug('Initializing Timer...');
|
||||||
|
this.settings = extensionUtils.getSettings();
|
||||||
|
this.nightlight_gsettings = new Gio.Settings({ schema: config.NIGHTLIGHT_GSETTINGS_SCHEMA });
|
||||||
|
this.location_gsettings = new Gio.Settings({ schema: config.LOCATION_GSETTINGS_SCHEMA });
|
||||||
|
log_debug('Nightlighter initialized.');
|
||||||
|
}
|
||||||
|
|
||||||
|
enable() {
|
||||||
|
log_debug('Enabling Timer...');
|
||||||
|
try {
|
||||||
|
this.ready = false;
|
||||||
|
this.settings.set_string('time-source', this._get_source());
|
||||||
|
this._listen_to_nightlight_status();
|
||||||
|
this._listen_to_location_status();
|
||||||
|
this._listen_to_force_manual_status();
|
||||||
|
switch (this.settings.get_string('time-source')) {
|
||||||
|
case 'nightlight':
|
||||||
|
log_debug('Using Night Light as a source.');
|
||||||
|
this._connect_to_color_dbus_proxy();
|
||||||
|
this._listen_to_nightlight_changes();
|
||||||
|
break;
|
||||||
|
case 'location':
|
||||||
|
log_debug('Using Location Services as a source.');
|
||||||
|
this._connect_to_geoclue_dbus_proxy();
|
||||||
|
this._listen_to_location_changes();
|
||||||
|
this._connect_to_geoclue_location_dbus_proxy();
|
||||||
|
this._update_location();
|
||||||
|
this._update_location_suntimes();
|
||||||
|
this._watch_for_location_time_change();
|
||||||
|
this._regularly_update_location_suntimes();
|
||||||
|
break;
|
||||||
|
case 'manual':
|
||||||
|
log_debug('Using manual schedule as a source.');
|
||||||
|
this._watch_for_location_time_change();
|
||||||
|
}
|
||||||
|
this.ready = true;
|
||||||
|
this.emit();
|
||||||
|
log_debug('Timer enabled.');
|
||||||
|
}
|
||||||
|
catch(e) {
|
||||||
|
if ( e.message ) {
|
||||||
|
main.notifyError(Me.metadata.name, e.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
disable() {
|
||||||
|
log_debug('Disabling Timer...');
|
||||||
|
this._stop_listening_to_nightlight_status();
|
||||||
|
this._stop_listening_to_location_status();
|
||||||
|
this._stop_listening_to_force_manual_status();
|
||||||
|
switch (this.settings.get_string('time-source')) {
|
||||||
|
case 'nightlight':
|
||||||
|
this._stop_listening_to_nightlight_changes();
|
||||||
|
this._disconnect_from_color_dbus_proxy();
|
||||||
|
break;
|
||||||
|
case 'location':
|
||||||
|
this._stop_regularly_updating_location_suntimes();
|
||||||
|
this._stop_watching_for_location_time_change();
|
||||||
|
this._stop_listening_to_location_changes();
|
||||||
|
this._disconnect_from_geoclue_location_dbus_proxy();
|
||||||
|
this._disconnect_from_geoclue_dbus_proxy();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
log_debug('Timer disabled.');
|
||||||
|
}
|
||||||
|
|
||||||
|
get current() {
|
||||||
|
if ( this.ready ) {
|
||||||
|
switch (this.settings.get_string('time-source')) {
|
||||||
|
case 'nightlight':
|
||||||
|
return this._is_nightlight_active() ? 'night' : 'day';
|
||||||
|
case 'location':
|
||||||
|
case 'manual':
|
||||||
|
return this._is_location_daytime() ? 'day' : 'night';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return 'day';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
subscribe(callback) {
|
||||||
|
this.time_change_callback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit() {
|
||||||
|
if ( this.time_change_callback ) {
|
||||||
|
this.time_change_callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_get_source() {
|
||||||
|
if ( this._is_force_manual_enabled() ) {
|
||||||
|
return 'manual';
|
||||||
|
}
|
||||||
|
else if ( this._is_nightlight_enabled() ) {
|
||||||
|
return 'nightlight';
|
||||||
|
}
|
||||||
|
else if ( this._is_location_enabled() ) {
|
||||||
|
return 'location';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return 'manual';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Check if Night Light is enabled and restart the Timer on changes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
_is_nightlight_enabled() {
|
||||||
|
return this.nightlight_gsettings.get_boolean(config.NIGHTLIGHT_GSETTINGS_PROPERTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
_listen_to_nightlight_status() {
|
||||||
|
if ( !this.nightlight_status_connect ) {
|
||||||
|
this.nightlight_status_connect = this.nightlight_gsettings.connect(
|
||||||
|
'changed::' + config.NIGHTLIGHT_GSETTINGS_PROPERTY,
|
||||||
|
this._on_nightlight_status_changed.bind(this)
|
||||||
|
);
|
||||||
|
log_debug('Listening to Night Light status changes...');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_stop_listening_to_nightlight_status() {
|
||||||
|
if ( this.nightlight_gsettings && this.nightlight_status_connect ) {
|
||||||
|
this.nightlight_gsettings.disconnect(this.nightlight_status_connect);
|
||||||
|
this.nightlight_status_connect = null;
|
||||||
|
log_debug('Stopped listening to Night Light status changes.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_on_nightlight_status_changed() {
|
||||||
|
log_debug('Night Light status has changed.');
|
||||||
|
this.enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Check if Location Services are enabled and restart the Timer on changes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
_is_location_enabled() {
|
||||||
|
return this.location_gsettings.get_boolean(config.LOCATION_GSETTINGS_PROPERTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
_listen_to_location_status() {
|
||||||
|
if ( !this.location_status_connect ) {
|
||||||
|
this.location_status_connect = this.location_gsettings.connect(
|
||||||
|
'changed::' + config.LOCATION_GSETTINGS_PROPERTY,
|
||||||
|
this._on_location_status_changed.bind(this)
|
||||||
|
);
|
||||||
|
log_debug('Listening to Location Services status changes...');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_stop_listening_to_location_status() {
|
||||||
|
if ( this.location_gsettings && this.location_status_connect ) {
|
||||||
|
this.location_gsettings.disconnect(this.location_status_connect);
|
||||||
|
this.location_status_connect = null;
|
||||||
|
log_debug('Stopped listening to Location Services status changes.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_on_location_status_changed() {
|
||||||
|
log_debug('Location Services status has changed.');
|
||||||
|
this.enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Check if the user wants to force a manual schedule and restart the Timer on
|
||||||
|
changes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
_is_force_manual_enabled() {
|
||||||
|
return this.settings.get_boolean('time-force-manual');
|
||||||
|
}
|
||||||
|
|
||||||
|
_listen_to_force_manual_status() {
|
||||||
|
if ( !this.force_manual_status_connect ) {
|
||||||
|
this.force_manual_status_connect = this.settings.connect(
|
||||||
|
'changed::time-force-manual',
|
||||||
|
this._on_force_manual_status_changed.bind(this)
|
||||||
|
);
|
||||||
|
log_debug('Listening to manual schedule status changes...');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_stop_listening_to_force_manual_status() {
|
||||||
|
if ( this.settings && this.force_manual_status_connect ) {
|
||||||
|
this.settings.disconnect(this.force_manual_status_connect);
|
||||||
|
this.force_manual_status_connect = null;
|
||||||
|
log_debug('Stopped listening to manual schedule status changes.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_on_force_manual_status_changed() {
|
||||||
|
log_debug('Manual schedule status has changed.');
|
||||||
|
this.enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Use Night Light as a time source.
|
||||||
|
*/
|
||||||
|
|
||||||
|
_connect_to_color_dbus_proxy() {
|
||||||
|
try {
|
||||||
|
log_debug('Connecting to Color DBus proxy...');
|
||||||
|
const color_interface = fileUtils.loadInterfaceXML('org.gnome.SettingsDaemon.Color');
|
||||||
|
const ColorProxy = Gio.DBusProxy.makeProxyWrapper(color_interface);
|
||||||
|
this.color_dbus_proxy = new ColorProxy(
|
||||||
|
Gio.DBus.session,
|
||||||
|
'org.gnome.SettingsDaemon.Color',
|
||||||
|
'/org/gnome/SettingsDaemon/Color'
|
||||||
|
);
|
||||||
|
log_debug('Connected to Color DBus proxy.');
|
||||||
|
}
|
||||||
|
catch(e) {
|
||||||
|
const message = _('Unable to connect to Color DBus proxy.');
|
||||||
|
throw new Error(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_disconnect_from_color_dbus_proxy() {
|
||||||
|
if ( this.color_dbus_proxy ) {
|
||||||
|
log_debug('Disconnecting from Color DBus Proxy...');
|
||||||
|
this.color_dbus_proxy = null;
|
||||||
|
log_debug('Disconnected from Color DBus Proxy.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_listen_to_nightlight_changes() {
|
||||||
|
if ( !this.nightlight_changes_connect ) {
|
||||||
|
this.nightlight_changes_connect = this.color_dbus_proxy.connect(
|
||||||
|
'g-properties-changed',
|
||||||
|
this._on_nightlight_changed.bind(this)
|
||||||
|
);
|
||||||
|
log_debug('Listening to Night Light changes...');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_stop_listening_to_nightlight_changes() {
|
||||||
|
if ( this.color_dbus_proxy && this.nightlight_changes_connect ) {
|
||||||
|
this.color_dbus_proxy.disconnect(this.nightlight_changes_connect);
|
||||||
|
this.nightlight_changes_connect = null;
|
||||||
|
log_debug('Stopped listening to Night Light changes.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_on_nightlight_changed(sender, dbus_properties) {
|
||||||
|
const properties = dbus_properties.deep_unpack();
|
||||||
|
if ( properties.NightLightActive ) {
|
||||||
|
log_debug('Night Light has become ' + (properties.NightLightActive.unpack() ? '' : 'in') + 'active.');
|
||||||
|
this.emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_is_nightlight_active() {
|
||||||
|
if ( this.color_dbus_proxy ) {
|
||||||
|
return this.color_dbus_proxy.NightLightActive;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Use location as a time source.
|
||||||
|
*/
|
||||||
|
|
||||||
|
_connect_to_geoclue_dbus_proxy() {
|
||||||
|
try {
|
||||||
|
log_debug('Connecting to GeoClue Manager DBus proxy...');
|
||||||
|
const GeoClueManagerProxy = Gio.DBusProxy.makeProxyWrapper(config.GEOCLUE_MANAGER_INTERFACE);
|
||||||
|
this.geoclue_manager_dbus_proxy = new GeoClueManagerProxy(
|
||||||
|
Gio.DBus.system,
|
||||||
|
'org.freedesktop.GeoClue2',
|
||||||
|
'/org/freedesktop/GeoClue2/Manager'
|
||||||
|
);
|
||||||
|
log_debug('Connected to GeoClue Manager DBus proxy.');
|
||||||
|
}
|
||||||
|
catch(e) {
|
||||||
|
const message = _('Unable to connect to GeoClue Manager DBus proxy.');
|
||||||
|
throw new Error(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
log_debug('Requesting new GeoClue Client...');
|
||||||
|
this.geoclue_client = this.geoclue_manager_dbus_proxy.GetClientSync()[0];
|
||||||
|
log_debug(`Got a GeoClue Client at ${this.geoclue_client}`);
|
||||||
|
}
|
||||||
|
catch(e) {
|
||||||
|
const message = _('Unable to get a GeoClue Client.');
|
||||||
|
throw new Error(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
log_debug('Connecting to GeoClue Client DBus proxy...');
|
||||||
|
const GeoClueClientProxy = Gio.DBusProxy.makeProxyWrapper(config.GEOCLUE_CLIENT_INTERFACE);
|
||||||
|
this.geoclue_client_dbus_proxy = new GeoClueClientProxy(
|
||||||
|
Gio.DBus.system,
|
||||||
|
'org.freedesktop.GeoClue2',
|
||||||
|
this.geoclue_client
|
||||||
|
);
|
||||||
|
this.geoclue_client_dbus_proxy.DesktopId = Me.metadata.uuid;
|
||||||
|
this.geoclue_client_dbus_proxy.DistanceThreshold = 10000;
|
||||||
|
this.geoclue_client_dbus_proxy.RequestedAccuracyLevel = 4;
|
||||||
|
log_debug('Connected to GeoClue Client DBus proxy.');
|
||||||
|
}
|
||||||
|
catch(e) {
|
||||||
|
const message = _('Unable to connect to GeoClue Client DBus proxy.');
|
||||||
|
throw new Error(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_disconnect_from_geoclue_dbus_proxy() {
|
||||||
|
if ( this.geoclue_client_dbus_proxy ) {
|
||||||
|
log_debug('Disconnecting from GeoClue Client DBus proxy...');
|
||||||
|
if ( this.geoclue_manager_dbus_proxy && this.geoclue_client ) {
|
||||||
|
this.geoclue_manager_dbus_proxy.DeleteClientSync(this.geoclue_client);
|
||||||
|
this.geoclue_client = null;
|
||||||
|
}
|
||||||
|
this.geoclue_client_dbus_proxy = null;
|
||||||
|
log_debug('Disconnected from GeoClue Client DBus Proxy.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( this.geoclue_manager_dbus_proxy ) {
|
||||||
|
log_debug('Disconnecting from GeoClue Manager DBus proxy...');
|
||||||
|
this.geoclue_manager_dbus_proxy = null;
|
||||||
|
log_debug('Disconnected from GeoClue Manager DBus proxy.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_listen_to_location_changes() {
|
||||||
|
if ( !this.location_changes_connect ) {
|
||||||
|
this.location_changes_connect = this.geoclue_client_dbus_proxy.connectSignal('LocationUpdated', this._on_location_changed.bind(this));
|
||||||
|
this.geoclue_client_dbus_proxy.StartSync();
|
||||||
|
log_debug('Listening to location changes...');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_stop_listening_to_location_changes() {
|
||||||
|
if ( this.geoclue_client_dbus_proxy && this.location_changes_connect ) {
|
||||||
|
this.geoclue_client_dbus_proxy.disconnectSignal(this.location_changes_connect);
|
||||||
|
this.location_changes_connect = null;
|
||||||
|
this.geoclue_client_dbus_proxy.StopSync();
|
||||||
|
log_debug('Stopped listening to location changes.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_on_location_changed(proxy, sender, [old_location_path, new_location_path]) {
|
||||||
|
log_debug('Location has changed.');
|
||||||
|
this._connect_to_geoclue_location_dbus_proxy(new_location_path);
|
||||||
|
this._update_location();
|
||||||
|
this._update_location_suntimes();
|
||||||
|
}
|
||||||
|
|
||||||
|
_connect_to_geoclue_location_dbus_proxy(path) {
|
||||||
|
if ( !path && this.geoclue_client_dbus_proxy ) {
|
||||||
|
path = this.geoclue_client_dbus_proxy.Location;
|
||||||
|
}
|
||||||
|
if ( path !== '/' ) {
|
||||||
|
try {
|
||||||
|
log_debug('Connecting to GeoClue Location DBus proxy...');
|
||||||
|
const GeoClueLocationProxy = Gio.DBusProxy.makeProxyWrapper(config.GEOCLUE_LOCATION_INTERFACE);
|
||||||
|
this.geoclue_location_dbus_proxy = new GeoClueLocationProxy(
|
||||||
|
Gio.DBus.system,
|
||||||
|
'org.freedesktop.GeoClue2',
|
||||||
|
path
|
||||||
|
);
|
||||||
|
log_debug('Connected to GeoClue Location DBus proxy.');
|
||||||
|
}
|
||||||
|
catch(e) {
|
||||||
|
const message = _('Unable to connect to GeoClue Location DBus proxy.');
|
||||||
|
throw new Error(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_disconnect_from_geoclue_location_dbus_proxy() {
|
||||||
|
if ( this.geoclue_location_dbus_proxy ) {
|
||||||
|
log_debug('Disconnecting from GeoClue Location DBus proxy...');
|
||||||
|
this.geoclue_location_dbus_proxy = null;
|
||||||
|
log_debug('Disconnected from GeoClue Location DBus proxy.')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_update_location() {
|
||||||
|
if ( this.geoclue_location_dbus_proxy ) {
|
||||||
|
try {
|
||||||
|
log_debug('Updating location...');
|
||||||
|
const latitude = this.geoclue_location_dbus_proxy.Latitude;
|
||||||
|
const longitude = this.geoclue_location_dbus_proxy.Longitude;
|
||||||
|
|
||||||
|
this.location = new Map([
|
||||||
|
['latitude', latitude],
|
||||||
|
['longitude', longitude]
|
||||||
|
]);
|
||||||
|
log_debug(`Current location: (${latitude};${longitude})`);
|
||||||
|
}
|
||||||
|
catch(e) {
|
||||||
|
const message = _('Unable to get current location.');
|
||||||
|
throw new Error(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_update_location_suntimes() {
|
||||||
|
if ( !this.location ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_debug('Updating sun times...');
|
||||||
|
|
||||||
|
Math.rad = degrees => degrees * Math.PI / 180;
|
||||||
|
Math.deg = radians => radians * 180 / Math.PI;
|
||||||
|
|
||||||
|
// Calculations from https://www.esrl.noaa.gov/gmd/grad/solcalc/calcdetails.html
|
||||||
|
const latitude = this.location.get('latitude');
|
||||||
|
const longitude = this.location.get('longitude');
|
||||||
|
|
||||||
|
const dt_now = GLib.DateTime.new_now_local();
|
||||||
|
const dt_zero = GLib.DateTime.new_utc(1900, 1, 1, 0, 0, 0);
|
||||||
|
|
||||||
|
const time_span = dt_now.difference(dt_zero);
|
||||||
|
|
||||||
|
const date = time_span / 1000 / 1000 / 60 / 60 / 24 + 2;
|
||||||
|
const tz_offset = dt_now.get_utc_offset() / 1000 / 1000 / 60 / 60;
|
||||||
|
const time_past_local_midnight = 0;
|
||||||
|
|
||||||
|
const julian_day = date + 2415018.5 + time_past_local_midnight - tz_offset / 24;
|
||||||
|
const julian_century = (julian_day - 2451545) / 36525;
|
||||||
|
const geom_mean_long_sun = (280.46646 + julian_century * (36000.76983 + julian_century * 0.0003032)) % 360;
|
||||||
|
const geom_mean_anom_sun = 357.52911 + julian_century * (35999.05029 - 0.0001537 * julian_century);
|
||||||
|
const eccent_earth_orbit = 0.016708634 - julian_century * (0.000042037 + 0.0000001267 * julian_century);
|
||||||
|
const sun_eq_of_ctr = Math.sin(Math.rad(geom_mean_anom_sun)) * (1.914602 - julian_century * (0.004817 + 0.000014 * julian_century)) + Math.sin(Math.rad(2 * geom_mean_anom_sun)) * (0.019993 - 0.000101 * julian_century) + Math.sin(Math.rad(3 * geom_mean_anom_sun)) * 0.000289;
|
||||||
|
const sun_true_long = geom_mean_long_sun + sun_eq_of_ctr;
|
||||||
|
const sun_app_long = sun_true_long - 0.00569 - 0.00478 * Math.sin(Math.rad(125.04 - 1934.136 * julian_century));
|
||||||
|
const mean_obliq_ecliptic = 23 + (26 + ((21.448 - julian_century * (46.815 + julian_century * (0.00059 - julian_century * 0.001813)))) / 60) / 60;
|
||||||
|
const obliq_corr = mean_obliq_ecliptic + 0.00256 * Math.cos(Math.rad(125.04 - 1934.136 * julian_century));
|
||||||
|
const sun_declin = Math.deg(Math.asin(Math.sin(Math.rad(obliq_corr)) * Math.sin(Math.rad(sun_app_long))));
|
||||||
|
const var_y = Math.tan(Math.rad(obliq_corr / 2)) * Math.tan(Math.rad(obliq_corr / 2));
|
||||||
|
const eq_of_time = 4 * Math.deg(var_y * Math.sin(2 * Math.rad(geom_mean_long_sun)) - 2 * eccent_earth_orbit * Math.sin(Math.rad(geom_mean_anom_sun)) + 4 * eccent_earth_orbit * var_y * Math.sin(Math.rad(geom_mean_anom_sun)) * Math.cos(2 * Math.rad(geom_mean_long_sun)) - 0.5 * var_y * var_y * Math.sin(4 * Math.rad(geom_mean_long_sun)) - 1.25 * eccent_earth_orbit * eccent_earth_orbit * Math.sin(2 * Math.rad(geom_mean_anom_sun)));
|
||||||
|
const ha_sunrise = Math.deg(Math.acos(Math.cos(Math.rad(90.833)) / (Math.cos(Math.rad(latitude)) * Math.cos(Math.rad(sun_declin))) - Math.tan(Math.rad(latitude)) * Math.tan(Math.rad(sun_declin))));
|
||||||
|
const solar_noon = (720 - 4 * longitude - eq_of_time + tz_offset * 60) / 1440;
|
||||||
|
|
||||||
|
const sunrise_time = solar_noon - ha_sunrise * 4 / 1440;
|
||||||
|
const sunset_time = solar_noon + ha_sunrise * 4 / 1440;
|
||||||
|
|
||||||
|
const sunrise = sunrise_time * 24;
|
||||||
|
const sunset = sunset_time * 24;
|
||||||
|
|
||||||
|
this.settings.set_double('time-sunrise', sunrise);
|
||||||
|
this.settings.set_double('time-sunset', sunset);
|
||||||
|
log_debug(`New sun times: (sunrise: ${sunrise}; sunset: ${sunset})`);
|
||||||
|
}
|
||||||
|
|
||||||
|
_regularly_update_location_suntimes() {
|
||||||
|
this.regularly_update_suntimes_timer = MainLoop.timeout_add_seconds(3600, () => {
|
||||||
|
this._update_location_suntimes();
|
||||||
|
return true; // Repeat the loop
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_stop_regularly_updating_location_suntimes() {
|
||||||
|
if ( this.regularly_update_suntimes_timer ) {
|
||||||
|
MainLoop.source_remove(this.regularly_update_suntimes_timer);
|
||||||
|
this.regularly_update_suntimes_timer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_is_location_daytime() {
|
||||||
|
const time = GLib.DateTime.new_now_local();
|
||||||
|
const hour = time.get_hour() + time.get_minute() / 60 + time.get_second() / 3600;
|
||||||
|
return ( hour >= this.settings.get_double('time-sunrise') && hour <= this.settings.get_double('time-sunset') );
|
||||||
|
}
|
||||||
|
|
||||||
|
_watch_for_location_time_change() {
|
||||||
|
this.location_time_change_timer = MainLoop.timeout_add_seconds(1, () => {
|
||||||
|
const previous_time = this.location_daytime;
|
||||||
|
if ( previous_time !== this._is_location_daytime() ) {
|
||||||
|
log_debug('Time of the day has changed.');
|
||||||
|
this.location_daytime = this._is_location_daytime();
|
||||||
|
this.emit();
|
||||||
|
}
|
||||||
|
return true; // Repeat the loop
|
||||||
|
}, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
_stop_watching_for_location_time_change() {
|
||||||
|
if ( this.location_time_change_timer ) {
|
||||||
|
MainLoop.source_remove(this.location_time_change_timer);
|
||||||
|
this.location_time_change_timer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+101
-15
@@ -1,34 +1,70 @@
|
|||||||
# Night Theme Switcher
|
# Night Theme Switcher
|
||||||
# Copyright (C) 2019 Romain Vigier
|
# Copyright (C) 2019 Romain Vigier
|
||||||
# This file is distributed under the same license as the Night Theme Switcher package.
|
# This file is distributed under the same license as the Night Theme Switcher package.
|
||||||
# Romain Vigier <>, 2019-2020.
|
# Romain Vigier <romain@romainvigier.fr>, 2019-2020.
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: Night Theme Switcher 7\n"
|
"Project-Id-Version: Night Theme Switcher 7\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2020-04-12 14:18+0200\n"
|
"POT-Creation-Date: 2020-05-06 16:40+0200\n"
|
||||||
"PO-Revision-Date: 2020-04-12 14:21+0200\n"
|
"PO-Revision-Date: 2020-05-06 16:40+0200\n"
|
||||||
"Last-Translator: Romain Vigier <>\n"
|
"Last-Translator: Romain Vigier <romain@romainvigier.fr>\n"
|
||||||
"Language-Team: French <none>\n"
|
"Language-Team: French - France <romain@romainvigier.fr>\n"
|
||||||
"Language: fr\n"
|
"Language: fr_FR\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=2; plural=(n > 1)\n"
|
"Plural-Forms: nplurals=2; plural=(n > 1)\n"
|
||||||
"X-Generator: Gtranslator 3.34.0\n"
|
"X-Generator: Gtranslator 3.36.0\n"
|
||||||
|
|
||||||
#: src/modules/Nightlighter.js:101
|
#: src/prefs.js:58
|
||||||
msgid ""
|
msgid ""
|
||||||
"Night Light must be enabled to use this extension. Please enable it in your "
|
"The extension will try to use Night Light or Location Services to "
|
||||||
"system settings."
|
"automatically set your current sunrise and sunset times if they are "
|
||||||
|
"enabled.\n"
|
||||||
|
"If you prefer, you can set a manual schedule."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Le mode nuit doit être activé pour utiliser l’extension. Veuillez l’activer "
|
"S’ils sont activés, l’extension essayera d’utiliser le mode nuit ou les "
|
||||||
"dans les réglages du système."
|
"services de localisation pour définir automatiquement les heures de lever et "
|
||||||
|
"de coucher du soleil.\n"
|
||||||
|
"Si vous préférez, vous pouvez définir manuellement un horaire."
|
||||||
|
|
||||||
#: src/modules/Nightlighter.js:144
|
#: src/prefs.js:93
|
||||||
msgid "Unable to create proxy to the session bus."
|
msgid "Manual schedule:"
|
||||||
msgstr "Impossible de créer une passerelle vers le bus de la session."
|
msgstr "Horaire manuel :"
|
||||||
|
|
||||||
|
#: src/prefs.js:138
|
||||||
|
msgid "Sunrise: "
|
||||||
|
msgstr "Lever du soleil :"
|
||||||
|
|
||||||
|
#: src/prefs.js:139
|
||||||
|
msgid "Sunset: "
|
||||||
|
msgstr "Coucher du soleil :"
|
||||||
|
|
||||||
|
#: src/modules/Timer.js:268
|
||||||
|
msgid "Unable to connect to Color DBus proxy."
|
||||||
|
msgstr "Impossible de se connecter à la passerelle DBus Color."
|
||||||
|
|
||||||
|
#: src/modules/Timer.js:330
|
||||||
|
msgid "Unable to connect to GeoClue Manager DBus proxy."
|
||||||
|
msgstr "Impossible de se connecter à la passerelle DBus GeoClue Manager."
|
||||||
|
|
||||||
|
#: src/modules/Timer.js:340
|
||||||
|
msgid "Unable to get a GeoClue Client."
|
||||||
|
msgstr "Impossible d’obtenir un client GeoClue."
|
||||||
|
|
||||||
|
#: src/modules/Timer.js:358
|
||||||
|
msgid "Unable to connect to GeoClue Client DBus proxy."
|
||||||
|
msgstr "Impossible de se connecter à la passerelle DBus GeoClue Client."
|
||||||
|
|
||||||
|
#: src/modules/Timer.js:417
|
||||||
|
msgid "Unable to connect to GeoClue Location DBus proxy."
|
||||||
|
msgstr "Impossible de se connecter à la passerelle DBus GeoClue Location."
|
||||||
|
|
||||||
|
#: src/modules/Timer.js:447
|
||||||
|
msgid "Unable to get current location."
|
||||||
|
msgstr "Impossible d’obtenir l’emplacement actuel."
|
||||||
|
|
||||||
#: src/schemas/org.gnome.shell.extensions.nightthemeswitcher.gschema.xml:6
|
#: src/schemas/org.gnome.shell.extensions.nightthemeswitcher.gschema.xml:6
|
||||||
msgid "Original theme"
|
msgid "Original theme"
|
||||||
@@ -54,6 +90,56 @@ msgstr "Thème nocturne"
|
|||||||
msgid "The theme to use during nighttime"
|
msgid "The theme to use during nighttime"
|
||||||
msgstr "Thème à utiliser pendant la nuit"
|
msgstr "Thème à utiliser pendant la nuit"
|
||||||
|
|
||||||
|
#: src/schemas/org.gnome.shell.extensions.nightthemeswitcher.gschema.xml:21
|
||||||
|
msgid "Use manual schedule"
|
||||||
|
msgstr "Utiliser un horaire manuel"
|
||||||
|
|
||||||
|
#: src/schemas/org.gnome.shell.extensions.nightthemeswitcher.gschema.xml:22
|
||||||
|
msgid "Disable automatic times detection"
|
||||||
|
msgstr "Désactive la détection automatique des horaires"
|
||||||
|
|
||||||
|
#: src/schemas/org.gnome.shell.extensions.nightthemeswitcher.gschema.xml:31
|
||||||
|
msgid "Time source"
|
||||||
|
msgstr "Source des horaires"
|
||||||
|
|
||||||
|
#: src/schemas/org.gnome.shell.extensions.nightthemeswitcher.gschema.xml:32
|
||||||
|
msgid "The source used to check current time"
|
||||||
|
msgstr "Source utilisée pour vérifier les horaires"
|
||||||
|
|
||||||
|
#: src/schemas/org.gnome.shell.extensions.nightthemeswitcher.gschema.xml:36
|
||||||
|
msgid "Sunrise time"
|
||||||
|
msgstr "Heure du lever"
|
||||||
|
|
||||||
|
#: src/schemas/org.gnome.shell.extensions.nightthemeswitcher.gschema.xml:37
|
||||||
|
msgid "When the day starts"
|
||||||
|
msgstr "Quand le jour se lève"
|
||||||
|
|
||||||
|
#: src/schemas/org.gnome.shell.extensions.nightthemeswitcher.gschema.xml:41
|
||||||
|
msgid "Sunset time"
|
||||||
|
msgstr "Heure du coucher"
|
||||||
|
|
||||||
|
#: src/schemas/org.gnome.shell.extensions.nightthemeswitcher.gschema.xml:42
|
||||||
|
msgid "When the day ends"
|
||||||
|
msgstr "Quand le jour se couche"
|
||||||
|
|
||||||
|
#~ msgid ""
|
||||||
|
#~ "Night Light or Location Services must be enabled to use this extension. "
|
||||||
|
#~ "Please enable it in your system settings."
|
||||||
|
#~ msgstr ""
|
||||||
|
#~ "Le mode nuit ou les services de localisation doivent être activés pour "
|
||||||
|
#~ "utiliser cette extension. Veuillez les activer dans vos paramètres du "
|
||||||
|
#~ "système."
|
||||||
|
|
||||||
|
#~ msgid ""
|
||||||
|
#~ "Night Light must be enabled to use this extension. Please enable it in "
|
||||||
|
#~ "your system settings."
|
||||||
|
#~ msgstr ""
|
||||||
|
#~ "Le mode nuit doit être activé pour utiliser l’extension. Veuillez "
|
||||||
|
#~ "l’activer dans les réglages du système."
|
||||||
|
|
||||||
|
#~ msgid "Unable to create proxy to the session bus."
|
||||||
|
#~ msgstr "Impossible de créer une passerelle vers le bus de la session."
|
||||||
|
|
||||||
#~ msgid "Unable to connect to the session bus."
|
#~ msgid "Unable to connect to the session bus."
|
||||||
#~ msgstr "Impossible de se connecter au bus de la session."
|
#~ msgstr "Impossible de se connecter au bus de la session."
|
||||||
|
|
||||||
|
|||||||
@@ -6,9 +6,9 @@
|
|||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: Night Theme Switcher 22\n"
|
"Project-Id-Version: Night Theme Switcher 25\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2020-04-12 14:18+0200\n"
|
"POT-Creation-Date: 2020-05-06 16:40+0200\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
@@ -17,14 +17,48 @@ msgstr ""
|
|||||||
"Content-Type: text/plain; charset=CHARSET\n"
|
"Content-Type: text/plain; charset=CHARSET\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
|
||||||
#: src/modules/Nightlighter.js:101
|
#: src/prefs.js:58
|
||||||
msgid ""
|
msgid ""
|
||||||
"Night Light must be enabled to use this extension. Please enable it in your "
|
"The extension will try to use Night Light or Location Services to "
|
||||||
"system settings."
|
"automatically set your current sunrise and sunset times if they are "
|
||||||
|
"enabled.\n"
|
||||||
|
"If you prefer, you can set a manual schedule."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/modules/Nightlighter.js:144
|
#: src/prefs.js:93
|
||||||
msgid "Unable to create proxy to the session bus."
|
msgid "Manual schedule:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/prefs.js:138
|
||||||
|
msgid "Sunrise: "
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/prefs.js:139
|
||||||
|
msgid "Sunset: "
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/modules/Timer.js:268
|
||||||
|
msgid "Unable to connect to Color DBus proxy."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/modules/Timer.js:330
|
||||||
|
msgid "Unable to connect to GeoClue Manager DBus proxy."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/modules/Timer.js:340
|
||||||
|
msgid "Unable to get a GeoClue Client."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/modules/Timer.js:358
|
||||||
|
msgid "Unable to connect to GeoClue Client DBus proxy."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/modules/Timer.js:417
|
||||||
|
msgid "Unable to connect to GeoClue Location DBus proxy."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/modules/Timer.js:447
|
||||||
|
msgid "Unable to get current location."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/schemas/org.gnome.shell.extensions.nightthemeswitcher.gschema.xml:6
|
#: src/schemas/org.gnome.shell.extensions.nightthemeswitcher.gschema.xml:6
|
||||||
@@ -50,3 +84,35 @@ msgstr ""
|
|||||||
#: src/schemas/org.gnome.shell.extensions.nightthemeswitcher.gschema.xml:17
|
#: src/schemas/org.gnome.shell.extensions.nightthemeswitcher.gschema.xml:17
|
||||||
msgid "The theme to use during nighttime"
|
msgid "The theme to use during nighttime"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/schemas/org.gnome.shell.extensions.nightthemeswitcher.gschema.xml:21
|
||||||
|
msgid "Use manual schedule"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/schemas/org.gnome.shell.extensions.nightthemeswitcher.gschema.xml:22
|
||||||
|
msgid "Disable automatic times detection"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/schemas/org.gnome.shell.extensions.nightthemeswitcher.gschema.xml:31
|
||||||
|
msgid "Time source"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/schemas/org.gnome.shell.extensions.nightthemeswitcher.gschema.xml:32
|
||||||
|
msgid "The source used to check current time"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/schemas/org.gnome.shell.extensions.nightthemeswitcher.gschema.xml:36
|
||||||
|
msgid "Sunrise time"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/schemas/org.gnome.shell.extensions.nightthemeswitcher.gschema.xml:37
|
||||||
|
msgid "When the day starts"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/schemas/org.gnome.shell.extensions.nightthemeswitcher.gschema.xml:41
|
||||||
|
msgid "Sunset time"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/schemas/org.gnome.shell.extensions.nightthemeswitcher.gschema.xml:42
|
||||||
|
msgid "When the day ends"
|
||||||
|
msgstr ""
|
||||||
|
|||||||
+239
@@ -0,0 +1,239 @@
|
|||||||
|
/*
|
||||||
|
Night Theme Switcher Gnome Shell extension
|
||||||
|
|
||||||
|
Copyright (C) 2020 Romain Vigier
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify it under
|
||||||
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
|
Foundation, either version 3 of the License, or (at your option) any later
|
||||||
|
version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with
|
||||||
|
this program. If not, see <http s ://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const { Gio, GLib, Gtk } = imports.gi;
|
||||||
|
const { extensionUtils } = imports.misc;
|
||||||
|
|
||||||
|
const Me = extensionUtils.getCurrentExtension();
|
||||||
|
const config = Me.imports.config;
|
||||||
|
|
||||||
|
const { log_debug } = Me.imports.utils;
|
||||||
|
|
||||||
|
const Gettext = imports.gettext.domain(Me.metadata.uuid);
|
||||||
|
const _ = Gettext.gettext;
|
||||||
|
|
||||||
|
|
||||||
|
let settings;
|
||||||
|
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
log_debug('Initializing preferences...');
|
||||||
|
settings = extensionUtils.getSettings();
|
||||||
|
extensionUtils.initTranslations(Me.metadata.uuid);
|
||||||
|
log_debug('Preferences initialized.');
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildPrefsWidget() {
|
||||||
|
const prefs_widget = new Gtk.Box({
|
||||||
|
orientation: Gtk.Orientation.VERTICAL,
|
||||||
|
spacing: 30,
|
||||||
|
margin_top: 30,
|
||||||
|
margin_end: 36,
|
||||||
|
margin_start: 36,
|
||||||
|
valign: Gtk.Align.START,
|
||||||
|
halign: Gtk.Align.CENTER,
|
||||||
|
width_request: 450,
|
||||||
|
margin_bottom: 36,
|
||||||
|
visible: true
|
||||||
|
})
|
||||||
|
|
||||||
|
const prefs_info = new Gtk.Label({
|
||||||
|
label: _('The extension will try to use Night Light or Location Services to automatically set your current sunrise and sunset times if they are enabled.\nIf you prefer, you can set a manual schedule.'),
|
||||||
|
wrap: true,
|
||||||
|
max_width_chars: 60,
|
||||||
|
halign: Gtk.Align.FILL,
|
||||||
|
opacity: 0.7,
|
||||||
|
visible: true
|
||||||
|
});
|
||||||
|
prefs_widget.pack_start(prefs_info, true, true, 0);
|
||||||
|
|
||||||
|
const prefs_frame = new Gtk.Frame({
|
||||||
|
can_focus: false,
|
||||||
|
visible: true
|
||||||
|
});
|
||||||
|
prefs_widget.pack_start(prefs_frame, true, true, 0);
|
||||||
|
|
||||||
|
const prefs_list = new Gtk.ListBox({
|
||||||
|
border_width: 0,
|
||||||
|
margin: 0,
|
||||||
|
can_focus: false,
|
||||||
|
selection_mode: Gtk.SelectionMode.NONE,
|
||||||
|
visible: true
|
||||||
|
});
|
||||||
|
prefs_frame.add(prefs_list);
|
||||||
|
|
||||||
|
// Force manual toggle
|
||||||
|
const force_manual_box = new Gtk.Box({
|
||||||
|
margin: 16,
|
||||||
|
spacing: 12,
|
||||||
|
orientation: Gtk.Orientation.HORIZONTAL,
|
||||||
|
can_focus: false,
|
||||||
|
visible: true
|
||||||
|
});
|
||||||
|
prefs_list.add(force_manual_box);
|
||||||
|
|
||||||
|
const force_manual_label = new Gtk.Label({
|
||||||
|
label: _('Manual schedule:'),
|
||||||
|
halign: Gtk.Align.START,
|
||||||
|
visible: true
|
||||||
|
});
|
||||||
|
force_manual_box.pack_start(force_manual_label, true, true, 0);
|
||||||
|
|
||||||
|
const force_manual_toggle = new Gtk.Switch({
|
||||||
|
active: this.settings.get_boolean('time-force-manual'),
|
||||||
|
halign: Gtk.Align.END,
|
||||||
|
visible: true
|
||||||
|
});
|
||||||
|
settings.bind(
|
||||||
|
'time-force-manual',
|
||||||
|
force_manual_toggle,
|
||||||
|
'active',
|
||||||
|
Gio.SettingsBindFlags.DEFAULT
|
||||||
|
);
|
||||||
|
force_manual_box.pack_start(force_manual_toggle, false, false, 0);
|
||||||
|
|
||||||
|
prefs_list.add(new Gtk.Separator({
|
||||||
|
orientation: Gtk.Orientation.VERTICAL,
|
||||||
|
can_focus: false,
|
||||||
|
visible: true
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Times schedule
|
||||||
|
['sunrise', 'sunset'].forEach((suntime, i, suntimes) => {
|
||||||
|
const time_box = new Gtk.Box({
|
||||||
|
margin: 16,
|
||||||
|
spacing: 12,
|
||||||
|
orientation: Gtk.Orientation.HORIZONTAL,
|
||||||
|
can_focus: false,
|
||||||
|
visible: true
|
||||||
|
});
|
||||||
|
prefs_list.add(time_box);
|
||||||
|
|
||||||
|
if ( i < suntimes.length - 1 ) {
|
||||||
|
prefs_list.add(new Gtk.Separator({
|
||||||
|
orientation: Gtk.Orientation.VERTICAL,
|
||||||
|
can_focus: false,
|
||||||
|
visible: true
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
const time_labels = new Map([
|
||||||
|
['sunrise', _('Sunrise: ')],
|
||||||
|
['sunset', _('Sunset: ')]
|
||||||
|
]);
|
||||||
|
const time_label = new Gtk.Label({
|
||||||
|
label: time_labels.get(suntime),
|
||||||
|
halign: Gtk.Align.START,
|
||||||
|
visible: true
|
||||||
|
})
|
||||||
|
time_box.pack_start(time_label, true, true, 0);
|
||||||
|
|
||||||
|
const time = settings.get_double(`time-${suntime}`);
|
||||||
|
const hour = Math.trunc(time);
|
||||||
|
const minutes = Math.round((time - hour) * 60);
|
||||||
|
|
||||||
|
const time_hour_spin = new Gtk.SpinButton({
|
||||||
|
adjustment: new Gtk.Adjustment({
|
||||||
|
value: hour,
|
||||||
|
lower: 0,
|
||||||
|
upper: 23,
|
||||||
|
step_increment: 1,
|
||||||
|
page_increment: 0,
|
||||||
|
page_size: 0
|
||||||
|
}),
|
||||||
|
value: hour,
|
||||||
|
numeric: true,
|
||||||
|
wrap: true,
|
||||||
|
orientation: Gtk.Orientation.VERTICAL,
|
||||||
|
visible: true
|
||||||
|
});
|
||||||
|
settings.bind(
|
||||||
|
'time-force-manual',
|
||||||
|
time_hour_spin,
|
||||||
|
'sensitive',
|
||||||
|
Gio.SettingsBindFlags.DEFAULT
|
||||||
|
);
|
||||||
|
settings.connect(`changed::time-${suntime}`, () => {
|
||||||
|
const hour = Math.trunc(settings.get_double(`time-${suntime}`));
|
||||||
|
time_hour_spin.value = hour;
|
||||||
|
});
|
||||||
|
time_hour_spin.connect('output', () => {
|
||||||
|
const text = time_hour_spin.adjustment.value.toString().padStart(2, '0');
|
||||||
|
time_hour_spin.set_text(text);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
time_hour_spin.connect('value-changed', () => {
|
||||||
|
const old_time = settings.get_double(`time-${suntime}`);
|
||||||
|
const old_hour = Math.trunc(old_time);
|
||||||
|
const minutes = old_time - old_hour;
|
||||||
|
const new_time = time_hour_spin.value + minutes;
|
||||||
|
settings.set_double(`time-${suntime}`, new_time);
|
||||||
|
});
|
||||||
|
time_box.pack_start(time_hour_spin, false, false, 0);
|
||||||
|
|
||||||
|
const time_separator = new Gtk.Label({
|
||||||
|
label: ':',
|
||||||
|
visible: true
|
||||||
|
})
|
||||||
|
time_box.pack_start(time_separator, false, false, 0);
|
||||||
|
|
||||||
|
const time_minutes_spin = new Gtk.SpinButton({
|
||||||
|
adjustment: new Gtk.Adjustment({
|
||||||
|
value: minutes,
|
||||||
|
lower: 0,
|
||||||
|
upper: 59,
|
||||||
|
step_increment: 1,
|
||||||
|
page_increment: 0,
|
||||||
|
page_size: 0
|
||||||
|
}),
|
||||||
|
value: minutes,
|
||||||
|
numeric: true,
|
||||||
|
wrap: true,
|
||||||
|
orientation: Gtk.Orientation.VERTICAL,
|
||||||
|
visible: true
|
||||||
|
});
|
||||||
|
settings.bind(
|
||||||
|
'time-force-manual',
|
||||||
|
time_minutes_spin,
|
||||||
|
'sensitive',
|
||||||
|
Gio.SettingsBindFlags.DEFAULT
|
||||||
|
);
|
||||||
|
settings.connect(`changed::time-${suntime}`, () => {
|
||||||
|
const time = settings.get_double(`time-${suntime}`);
|
||||||
|
const hour = Math.trunc(time);
|
||||||
|
const minutes = Math.round((time - hour) * 60);
|
||||||
|
time_minutes_spin.value = minutes;
|
||||||
|
});
|
||||||
|
time_minutes_spin.connect('output', () => {
|
||||||
|
const text = time_minutes_spin.adjustment.value.toString().padStart(2, '0');
|
||||||
|
time_minutes_spin.set_text(text);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
time_minutes_spin.connect('value-changed', () => {
|
||||||
|
const hour = Math.trunc(settings.get_double(`time-${suntime}`));
|
||||||
|
const minutes = time_minutes_spin.value / 60;
|
||||||
|
const new_time = hour + minutes;
|
||||||
|
settings.set_double(`time-${suntime}`, new_time);
|
||||||
|
});
|
||||||
|
time_box.pack_start(time_minutes_spin, false, false, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
return prefs_widget;
|
||||||
|
}
|
||||||
@@ -16,5 +16,30 @@
|
|||||||
<summary>Night theme</summary>
|
<summary>Night theme</summary>
|
||||||
<description>The theme to use during nighttime</description>
|
<description>The theme to use during nighttime</description>
|
||||||
</key>
|
</key>
|
||||||
|
<key name="time-force-manual" type="b">
|
||||||
|
<default>false</default>
|
||||||
|
<summary>Use manual schedule</summary>
|
||||||
|
<description>Disable automatic times detection</description>
|
||||||
|
</key>
|
||||||
|
<key name="time-source" type="s">
|
||||||
|
<choices>
|
||||||
|
<choice value="nightlight"/>
|
||||||
|
<choice value="location"/>
|
||||||
|
<choice value="manual"/>
|
||||||
|
</choices>
|
||||||
|
<default>"manual"</default>
|
||||||
|
<summary>Time source</summary>
|
||||||
|
<description>The source used to check current time</description>
|
||||||
|
</key>
|
||||||
|
<key name="time-sunrise" type="d">
|
||||||
|
<default>6</default>
|
||||||
|
<summary>Sunrise time</summary>
|
||||||
|
<description>When the day starts</description>
|
||||||
|
</key>
|
||||||
|
<key name="time-sunset" type="d">
|
||||||
|
<default>20</default>
|
||||||
|
<summary>Sunset time</summary>
|
||||||
|
<description>When the day ends</description>
|
||||||
|
</key>
|
||||||
</schema>
|
</schema>
|
||||||
</schemalist>
|
</schemalist>
|
||||||
|
|||||||
+1
-1
@@ -23,6 +23,6 @@ const config = Me.imports.config;
|
|||||||
|
|
||||||
var log_debug = function(message) {
|
var log_debug = function(message) {
|
||||||
if ( config.debug ) {
|
if ( config.debug ) {
|
||||||
log(`[DEBUG] ${config.EXT_NAME}: ${message}`);
|
log(`[DEBUG] ${Me.metadata.name}: ${message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user