Compare commits
	
		
			2 Commits
		
	
	
		
			3.33.1
			...
			gbsneto/au
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					47a2e58d45 | ||
| 
						 | 
					20d73be57d | 
@@ -1,6 +1,9 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<gresources>
 | 
			
		||||
  <gresource prefix="/org/gnome/shell/theme">
 | 
			
		||||
    <file>automatic-updates-off-symbolic.svg</file>
 | 
			
		||||
    <file>automatic-updates-on-symbolic.svg</file>
 | 
			
		||||
    <file>automatic-updates-scheduled-symbolic.svg</file>
 | 
			
		||||
    <file>calendar-today.svg</file>
 | 
			
		||||
    <file>checkbox-focused.svg</file>
 | 
			
		||||
    <file>checkbox-off-focused.svg</file>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1
									
								
								data/theme/automatic-updates-off-symbolic.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								data/theme/automatic-updates-off-symbolic.svg
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><title>EOS_symbolic-icons_v0.1auto-updates_OFF</title><path d="M11.03,10.074a.125.125,0,0,0-.086.213l1.347,1.35a5.733,5.733,0,0,1-4.238,1.9,5.6,5.6,0,0,1-2.282-.484l-1.11,1.11a7.024,7.024,0,0,0,3.392.875,7.3,7.3,0,0,0,5.3-2.339l1.357,1.36a.125.125,0,0,0,.213-.086L15,10Z" style="fill:#999"/><path d="M12.921,5.9a6.354,6.354,0,0,1,.326,1.863.248.248,0,0,0,.244.244h1a.261.261,0,0,0,.257-.265,7.543,7.543,0,0,0-.677-2.991Z" style="fill:#999"/><path d="M6.286,9.707a.994.994,0,0,0,.715.3H9a1,1,0,0,0,1-1v-2A.994.994,0,0,0,9.7,6.3l2.175-2.175,0,0L12.93,3.067l0,0,1.4-1.4a.25.25,0,0,0,0-.354L13.617.608a.25.25,0,0,0-.354,0L11.772,2.1A6.97,6.97,0,0,0,7.948.961,7.3,7.3,0,0,0,2.651,3.3L1.293,1.94a.125.125,0,0,0-.214.086L1,6l3.971-.074a.125.125,0,0,0,.086-.213L3.71,4.363a5.733,5.733,0,0,1,4.238-1.9,5.523,5.523,0,0,1,2.723.739L7.86,6.011H7a1,1,0,0,0-1,1V7.87L3.291,10.58a6,6,0,0,1-.537-2.346.248.248,0,0,0-.244-.245h-1a.261.261,0,0,0-.257.265A7.329,7.329,0,0,0,2.172,11.7L.608,13.263a.25.25,0,0,0,0,.354l.707.707a.25.25,0,0,0,.354,0l1.4-1.4,0,0,1.056-1.056,0,0Z" style="fill:#999"/></svg>
 | 
			
		||||
| 
		 After Width: | Height: | Size: 1.1 KiB  | 
							
								
								
									
										1
									
								
								data/theme/automatic-updates-on-symbolic.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								data/theme/automatic-updates-on-symbolic.svg
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><title>EOS_symbolic-icons_v0.1auto-updates_ON</title><rect x="6.001" y="6.011" width="4" height="4" rx="1" ry="1" style="fill:#999"/><path d="M5.057,5.713,3.71,4.362a5.733,5.733,0,0,1,4.238-1.9,5.173,5.173,0,0,1,5.3,5.305.248.248,0,0,0,.244.244h1a.261.261,0,0,0,.257-.265A6.684,6.684,0,0,0,7.948.961,7.3,7.3,0,0,0,2.65,3.3L1.293,1.94a.125.125,0,0,0-.213.086L1,6l3.971-.074A.125.125,0,0,0,5.057,5.713Z" style="fill:#999"/><path d="M11.03,10.074a.125.125,0,0,0-.086.213l1.347,1.35a5.733,5.733,0,0,1-4.238,1.9,5.173,5.173,0,0,1-5.3-5.305.248.248,0,0,0-.244-.245h-1a.261.261,0,0,0-.257.265,6.684,6.684,0,0,0,6.8,6.785,7.3,7.3,0,0,0,5.3-2.339l1.357,1.36a.125.125,0,0,0,.214-.086L15,10Z" style="fill:#999"/></svg>
 | 
			
		||||
| 
		 After Width: | Height: | Size: 767 B  | 
							
								
								
									
										1
									
								
								data/theme/automatic-updates-scheduled-symbolic.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								data/theme/automatic-updates-scheduled-symbolic.svg
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><title>EOS_symbolic-icons_v0.1update-scheduled_OUTLINE</title><path d="M7.99,15.054A6.7,6.7,0,0,1,1.06,8,6.7,6.7,0,0,1,7.99.954,6.71,6.71,0,0,1,14.948,8,6.71,6.71,0,0,1,7.99,15.054Zm0-12.6A5.2,5.2,0,0,0,2.56,8a5.2,5.2,0,0,0,5.43,5.55A5.215,5.215,0,0,0,13.448,8,5.216,5.216,0,0,0,7.99,2.454Z" style="fill:#999"/><path d="M9.209,10.443,7.2,8.437a.25.25,0,0,1-.073-.177l0-4.01A.25.25,0,0,1,7.379,4h1.25a.25.25,0,0,1,.25.25l0,3.283a.25.25,0,0,0,.073.177l1.5,1.494a.25.25,0,0,1,0,.354l-.883.884A.25.25,0,0,1,9.209,10.443Z" style="fill:#999"/></svg>
 | 
			
		||||
| 
		 After Width: | Height: | Size: 603 B  | 
@@ -9,6 +9,7 @@
 | 
			
		||||
    <file>gdm/realmd.js</file>
 | 
			
		||||
    <file>gdm/util.js</file>
 | 
			
		||||
 | 
			
		||||
    <file>misc/updateManager.js</file>
 | 
			
		||||
    <file>misc/config.js</file>
 | 
			
		||||
    <file>misc/extensionUtils.js</file>
 | 
			
		||||
    <file>misc/fileUtils.js</file>
 | 
			
		||||
@@ -116,9 +117,11 @@
 | 
			
		||||
    <file>ui/components/networkAgent.js</file>
 | 
			
		||||
    <file>ui/components/polkitAgent.js</file>
 | 
			
		||||
    <file>ui/components/telepathyClient.js</file>
 | 
			
		||||
    <file>ui/components/updates.js</file>
 | 
			
		||||
    <file>ui/components/keyring.js</file>
 | 
			
		||||
 | 
			
		||||
    <file>ui/status/accessibility.js</file>
 | 
			
		||||
    <file>ui/status/automaticUpdates.js</file>
 | 
			
		||||
    <file>ui/status/brightness.js</file>
 | 
			
		||||
    <file>ui/status/location.js</file>
 | 
			
		||||
    <file>ui/status/keyboard.js</file>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										338
									
								
								js/misc/updateManager.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										338
									
								
								js/misc/updateManager.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,338 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
//
 | 
			
		||||
// Copyright (C) 2019 Endless Mobile, Inc.
 | 
			
		||||
//
 | 
			
		||||
// This is a GNOME Shell component to wrap the interactions over
 | 
			
		||||
// D-Bus with the Mogwai system daemon.
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the GNU General Public License Version 2
 | 
			
		||||
//
 | 
			
		||||
// 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 2
 | 
			
		||||
// 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, write to the Free Software
 | 
			
		||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 | 
			
		||||
 | 
			
		||||
const { Clutter, Gio, GLib,
 | 
			
		||||
        GObject, Gtk, NM, Shell, St } = imports.gi;
 | 
			
		||||
 | 
			
		||||
const NM_SETTING_AUTOMATIC_UPDATES_NOTIFICATION_TIME = "connection.automatic-updates-notification-time";
 | 
			
		||||
const NM_SETTING_ALLOW_DOWNLOADS = 'connection.allow-downloads';
 | 
			
		||||
const NM_SETTING_TARIFF_ENABLED = "connection.tariff-enabled";
 | 
			
		||||
 | 
			
		||||
const SchedulerInterface = '\
 | 
			
		||||
<node> \
 | 
			
		||||
  <interface name="com.endlessm.DownloadManager1.Scheduler"> \
 | 
			
		||||
    <property name="ActiveEntryCount" type="u" access="read" /> \
 | 
			
		||||
    <property name="EntryCount" type="u" access="read" /> \
 | 
			
		||||
  </interface> \
 | 
			
		||||
</node>';
 | 
			
		||||
 | 
			
		||||
const SchedulerProxy = Gio.DBusProxy.makeProxyWrapper(SchedulerInterface);
 | 
			
		||||
 | 
			
		||||
let _updateManager = null;
 | 
			
		||||
 | 
			
		||||
function getUpdateManager() {
 | 
			
		||||
    if (_updateManager == null)
 | 
			
		||||
        _updateManager = new UpdateManager();
 | 
			
		||||
    return _updateManager;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var State = {
 | 
			
		||||
    UNKNOWN: 0,
 | 
			
		||||
    DISCONNECTED: 1,
 | 
			
		||||
    DISABLED: 2,
 | 
			
		||||
    IDLE: 3,
 | 
			
		||||
    SCHEDULED: 4,
 | 
			
		||||
    DOWNLOADING: 5
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function stateToIconName(state) {
 | 
			
		||||
    switch (state) {
 | 
			
		||||
    case State.UNKNOWN:
 | 
			
		||||
    case State.DISCONNECTED:
 | 
			
		||||
        return null;
 | 
			
		||||
 | 
			
		||||
    case State.DISABLED:
 | 
			
		||||
        return 'resource:///org/gnome/shell/theme/automatic-updates-off-symbolic.svg';
 | 
			
		||||
 | 
			
		||||
    case State.IDLE:
 | 
			
		||||
    case State.DOWNLOADING:
 | 
			
		||||
        return 'resource:///org/gnome/shell/theme/automatic-updates-on-symbolic.svg';
 | 
			
		||||
 | 
			
		||||
    case State.SCHEDULED:
 | 
			
		||||
        return 'resource:///org/gnome/shell/theme/automatic-updates-scheduled-symbolic.svg';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return null;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var UpdateManager = GObject.registerClass ({
 | 
			
		||||
    Properties: {
 | 
			
		||||
        'last-notification-time': GObject.ParamSpec.int('last-notification-time',
 | 
			
		||||
                                                        'last-notification-time',
 | 
			
		||||
                                                        'last-notification-time',
 | 
			
		||||
                                                        GObject.ParamFlags.READWRITE,
 | 
			
		||||
                                                        null),
 | 
			
		||||
        'icon': GObject.ParamSpec.object('icon', 'icon', 'icon',
 | 
			
		||||
                                         GObject.ParamFlags.READABLE,
 | 
			
		||||
                                         Gio.Icon.$gtype),
 | 
			
		||||
        'state': GObject.ParamSpec.uint('state', 'state', 'state',
 | 
			
		||||
                                        GObject.ParamFlags.READABLE,
 | 
			
		||||
                                        null),
 | 
			
		||||
    },
 | 
			
		||||
}, class UpdateManager extends GObject.Object {
 | 
			
		||||
    _init() {
 | 
			
		||||
        super._init();
 | 
			
		||||
 | 
			
		||||
        this._activeConnection = null;
 | 
			
		||||
        this._settingChangedSignalId = 0;
 | 
			
		||||
        this._updateTimeoutId = 0;
 | 
			
		||||
 | 
			
		||||
        this._state = State.UNKNOWN;
 | 
			
		||||
 | 
			
		||||
        NM.Client.new_async(null, this._clientGot.bind(this));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _clientGot(obj, result) {
 | 
			
		||||
        this._client = NM.Client.new_finish(result);
 | 
			
		||||
 | 
			
		||||
        this._client.connect('notify::primary-connection', this._sync.bind(this));
 | 
			
		||||
        this._client.connect('notify::state', this._sync.bind(this));
 | 
			
		||||
 | 
			
		||||
        // Start retrieving the Mogwai proxy
 | 
			
		||||
        this._proxy = new SchedulerProxy(Gio.DBus.system,
 | 
			
		||||
                                         'com.endlessm.MogwaiSchedule1',
 | 
			
		||||
                                         '/com/endlessm/DownloadManager1',
 | 
			
		||||
                                          (proxy, error) => {
 | 
			
		||||
                                              if (error) {
 | 
			
		||||
                                                  log(error.message);
 | 
			
		||||
                                                  return;
 | 
			
		||||
                                              }
 | 
			
		||||
                                              this._proxy.connect('g-properties-changed',
 | 
			
		||||
                                                                  this._sync.bind(this));
 | 
			
		||||
                                              this._updateStatus();
 | 
			
		||||
                                          });
 | 
			
		||||
 | 
			
		||||
        this._sync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _sync() {
 | 
			
		||||
        if (!this._client || !this._proxy)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (this._updateTimeoutId > 0) {
 | 
			
		||||
            GLib.source_remove(this._updateTimeoutId);
 | 
			
		||||
            this._updateTimeoutId = 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Intermediate states (connecting or disconnecting) must not trigger
 | 
			
		||||
        // any kind of state change.
 | 
			
		||||
        if (this._client.state == NM.State.CONNECTING || this._client.state == NM.State.DISCONNECTING)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        // Use a timeout to avoid instantly throwing the notification at
 | 
			
		||||
        // the user's face, and to avoid a series of unecessary updates
 | 
			
		||||
        // that happen when NetworkManager is still figuring out details.
 | 
			
		||||
        this._updateTimeoutId = GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT,
 | 
			
		||||
                                                         2,
 | 
			
		||||
                                                         () => {
 | 
			
		||||
                                                            this._updateStatus();
 | 
			
		||||
                                                            this._updateTimeoutId = 0;
 | 
			
		||||
                                                            return GLib.SOURCE_REMOVE;
 | 
			
		||||
                                                         });
 | 
			
		||||
        GLib.Source.set_name_by_id(this._updateTimeoutId, '[update] updateStatus');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _updateStatus() {
 | 
			
		||||
        // Update the current active connection. This will connect to the
 | 
			
		||||
        // NM.SettingUser signal to sync every time someone updates the
 | 
			
		||||
        // NM_SETTING_ALLOW_DOWNLOADS setting.
 | 
			
		||||
        this._updateActiveConnection();
 | 
			
		||||
 | 
			
		||||
        let state = this._getState();
 | 
			
		||||
        if (state != this._state) {
 | 
			
		||||
            this._state = state;
 | 
			
		||||
            this.notify('state');
 | 
			
		||||
 | 
			
		||||
            this._updateIcon();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _updateActiveConnection() {
 | 
			
		||||
        let currentActiveConnection = this._getActiveConnection();
 | 
			
		||||
 | 
			
		||||
        if (this._activeConnection == currentActiveConnection)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        // Disconnect from the previous active connection
 | 
			
		||||
        if (this._settingChangedSignalId > 0) {
 | 
			
		||||
            this._activeConnection.disconnect(this._settingChangedSignalId);
 | 
			
		||||
            this._settingChangedSignalId = 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._activeConnection = currentActiveConnection;
 | 
			
		||||
 | 
			
		||||
        // Connect from the current active connection
 | 
			
		||||
        if (currentActiveConnection)
 | 
			
		||||
            this._settingChangedSignalId = currentActiveConnection.connect('changed', this._updateStatus.bind(this));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _ensureUserSetting(connection) {
 | 
			
		||||
        let userSetting = connection.get_setting(NM.SettingUser.$gtype);
 | 
			
		||||
        if (!userSetting) {
 | 
			
		||||
            userSetting = new NM.SettingUser();
 | 
			
		||||
            connection.add_setting(userSetting);
 | 
			
		||||
        }
 | 
			
		||||
        return userSetting;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _getState() {
 | 
			
		||||
        if (!this._activeConnection)
 | 
			
		||||
            return State.DISCONNECTED;
 | 
			
		||||
 | 
			
		||||
        let userSetting = this._ensureUserSetting(this._activeConnection);
 | 
			
		||||
 | 
			
		||||
        // We only return true when:
 | 
			
		||||
        //  * Automatic Updates are on
 | 
			
		||||
        //  * A schedule was set
 | 
			
		||||
        //  * Something is being downloaded
 | 
			
		||||
 | 
			
		||||
        let allowDownloadsValue = userSetting.get_data(NM_SETTING_ALLOW_DOWNLOADS);
 | 
			
		||||
        if (allowDownloadsValue) {
 | 
			
		||||
            let allowDownloads = (allowDownloadsValue === '1');
 | 
			
		||||
 | 
			
		||||
            if (!allowDownloads)
 | 
			
		||||
                return State.DISABLED;
 | 
			
		||||
        } else {
 | 
			
		||||
            // Guess the default value from the metered state. Only return
 | 
			
		||||
            // if it's disabled - if it's not, we want to follow the regular
 | 
			
		||||
            // code paths and fetch the correct state
 | 
			
		||||
            let connectionSetting = this._activeConnection.get_setting_connection();
 | 
			
		||||
 | 
			
		||||
            if (!connectionSetting)
 | 
			
		||||
                return State.DISABLED;
 | 
			
		||||
 | 
			
		||||
            let metered = connectionSetting.get_metered();
 | 
			
		||||
            if (metered == NM.Metered.YES || metered == NM.Metered.GUESS_YES)
 | 
			
		||||
                return State.DISABLED;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Without the proxy, we can't really know the state
 | 
			
		||||
        if (!this._proxy)
 | 
			
		||||
            return State.UNKNOWN;
 | 
			
		||||
 | 
			
		||||
        let scheduleSet = userSetting.get_data(NM_SETTING_TARIFF_ENABLED) === '1';
 | 
			
		||||
        if (!scheduleSet)
 | 
			
		||||
            return State.IDLE;
 | 
			
		||||
 | 
			
		||||
        let downloading = this._proxy.ActiveEntryCount > 0;
 | 
			
		||||
        if (downloading)
 | 
			
		||||
            return State.DOWNLOADING;
 | 
			
		||||
 | 
			
		||||
        // At this point we're not downloading anything, but something
 | 
			
		||||
        // might be queued
 | 
			
		||||
        let downloadsQueued = this._proxy.EntryCount > 0;
 | 
			
		||||
        if (downloadsQueued)
 | 
			
		||||
            return State.SCHEDULED;
 | 
			
		||||
        else
 | 
			
		||||
            return State.IDLE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _getActiveConnection() {
 | 
			
		||||
        let activeConnection = this._client.get_primary_connection();
 | 
			
		||||
        return activeConnection ? activeConnection.get_connection() : null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _updateIcon() {
 | 
			
		||||
        let state = this._state;
 | 
			
		||||
        let iconName = stateToIconName(state);
 | 
			
		||||
 | 
			
		||||
        if (iconName) {
 | 
			
		||||
            let iconFile = Gio.File.new_for_uri(iconName);
 | 
			
		||||
            this._icon = new Gio.FileIcon({ file: iconFile });
 | 
			
		||||
        } else {
 | 
			
		||||
            this._icon = null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.notify('icon');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    get state() {
 | 
			
		||||
        return this._state;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    get lastNotificationTime() {
 | 
			
		||||
        let connection = this._getActiveConnection();
 | 
			
		||||
        if (!connection)
 | 
			
		||||
            return -1;
 | 
			
		||||
 | 
			
		||||
        let userSetting = connection.get_setting(NM.SettingUser.$gtype);
 | 
			
		||||
        if (!userSetting)
 | 
			
		||||
            return -1;
 | 
			
		||||
 | 
			
		||||
        let time = userSetting.get_data(NM_SETTING_AUTOMATIC_UPDATES_NOTIFICATION_TIME);
 | 
			
		||||
        return time ? parseInt(time) : -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    set lastNotificationTime(time) {
 | 
			
		||||
        if (!this._activeConnection)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let userSetting = this._ensureUserSetting(this._activeConnection);
 | 
			
		||||
        userSetting.set_data(NM_SETTING_AUTOMATIC_UPDATES_NOTIFICATION_TIME,
 | 
			
		||||
                             '%s'.format(time));
 | 
			
		||||
 | 
			
		||||
        this._activeConnection.commit_changes(true, null);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    get active() {
 | 
			
		||||
        return this._active;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    set active(_active) {
 | 
			
		||||
        if (this._active == _active)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._active = _active;
 | 
			
		||||
        this.notify('active');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    get icon() {
 | 
			
		||||
        return this._icon;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    toggleAutomaticUpdates() {
 | 
			
		||||
        if (!this._activeConnection)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let userSetting = this._ensureUserSetting(this._activeConnection);
 | 
			
		||||
 | 
			
		||||
        let state = this._getState();
 | 
			
		||||
        let value;
 | 
			
		||||
 | 
			
		||||
        if (state == State.IDLE ||
 | 
			
		||||
            state == State.SCHEDULED ||
 | 
			
		||||
            state == State.DOWNLOADING) {
 | 
			
		||||
            value = '0';
 | 
			
		||||
        } else {
 | 
			
		||||
            value = '1';
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        userSetting.set_data(NM_SETTING_ALLOW_DOWNLOADS, value);
 | 
			
		||||
 | 
			
		||||
        this._activeConnection.commit_changes_async(true, null, (con, res, data) => {
 | 
			
		||||
            this._activeConnection.commit_changes_finish(res);
 | 
			
		||||
            this._updateStatus();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										135
									
								
								js/ui/components/updates.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								js/ui/components/updates.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,135 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
//
 | 
			
		||||
// Copyright (C) 2018 Endless Mobile, Inc.
 | 
			
		||||
//
 | 
			
		||||
// This is a GNOME Shell component to wrap the interactions over
 | 
			
		||||
// D-Bus with the Mogwai system daemon.
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the GNU General Public License Version 2
 | 
			
		||||
//
 | 
			
		||||
// 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 2
 | 
			
		||||
// 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, write to the Free Software
 | 
			
		||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 | 
			
		||||
 | 
			
		||||
const { Gio, GLib, Shell } = imports.gi;
 | 
			
		||||
 | 
			
		||||
const UpdateManager = imports.misc.updateManager;
 | 
			
		||||
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const MessageTray = imports.ui.messageTray;
 | 
			
		||||
 | 
			
		||||
var UpdateComponent = class {
 | 
			
		||||
    constructor() {
 | 
			
		||||
        this._notification = null;
 | 
			
		||||
        this._state = UpdateManager.State.UNKNOWN;
 | 
			
		||||
 | 
			
		||||
        this._manager = UpdateManager.getUpdateManager();
 | 
			
		||||
        this._manager.connect('notify::state', this._updateState.bind(this));
 | 
			
		||||
 | 
			
		||||
        this._updateState();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    enable() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    disable() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _updateState() {
 | 
			
		||||
        let newState = this._manager.state;
 | 
			
		||||
 | 
			
		||||
        if (this._state == newState)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._updateNotification(newState);
 | 
			
		||||
        this._state = newState;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _updateNotification(newState) {
 | 
			
		||||
        // Don't notify when starting up
 | 
			
		||||
        if (this._manager.state == UpdateManager.State.UNKNOWN)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let alreadySentNotification = this._manager.lastNotificationTime != -1;
 | 
			
		||||
 | 
			
		||||
        let wasDisconnected = this._state == UpdateManager.State.DISCONNECTED;
 | 
			
		||||
        let wasActive = this._state >= UpdateManager.State.IDLE;
 | 
			
		||||
        let isActive = newState >= UpdateManager.State.IDLE;
 | 
			
		||||
 | 
			
		||||
        // The criteria to notify about the Automatic Updates setting is:
 | 
			
		||||
        //   1. If the user was disconnected and connects to a new network; or
 | 
			
		||||
        //   2. If the user was connected and connects to a network with different status;
 | 
			
		||||
        if ((wasDisconnected && alreadySentNotification) || (!wasDisconnected && isActive == wasActive))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (this._notification)
 | 
			
		||||
            this._notification.destroy();
 | 
			
		||||
 | 
			
		||||
        if (newState == UpdateManager.State.DISCONNECTED)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let source = new MessageTray.SystemNotificationSource();
 | 
			
		||||
        Main.messageTray.add(source);
 | 
			
		||||
 | 
			
		||||
        // Figure out the title, subtitle and icon
 | 
			
		||||
        let title, subtitle, iconFile;
 | 
			
		||||
 | 
			
		||||
        if (isActive) {
 | 
			
		||||
            title = _("Automatic updates on");
 | 
			
		||||
            subtitle = _("Your connection has unlimited data so automatic updates have been turned on.");
 | 
			
		||||
            iconFile = UpdateManager.stateToIconName(UpdateManager.State.IDLE);
 | 
			
		||||
        } else {
 | 
			
		||||
            title = _("Automatic updates are turned off to save your data");
 | 
			
		||||
            subtitle = _("You will need to choose which updates to apply when on this connection.");
 | 
			
		||||
            iconFile = UpdateManager.stateToIconName(UpdateManager.State.DISABLED);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let gicon = new Gio.FileIcon({ file: Gio.File.new_for_uri(iconFile) });
 | 
			
		||||
 | 
			
		||||
        // Create the notification.
 | 
			
		||||
        // The first time we notify the user for a given connection,
 | 
			
		||||
        // we set the urgency to critical so that we make sure the
 | 
			
		||||
        // user understands how we may be changing their settings.
 | 
			
		||||
        // On subsequent notifications for the given connection,
 | 
			
		||||
        // for instance if the user regularly switches between
 | 
			
		||||
        // metered and unmetered connections, we set the urgency
 | 
			
		||||
        // to normal so as not to be too obtrusive.
 | 
			
		||||
        this._notification = new MessageTray.Notification(source, title, subtitle, { gicon: gicon });
 | 
			
		||||
        this._notification.setUrgency(alreadySentNotification ?
 | 
			
		||||
                                      MessageTray.Urgency.NORMAL : MessageTray.Urgency.CRITICAL);
 | 
			
		||||
        this._notification.setTransient(false);
 | 
			
		||||
 | 
			
		||||
        this._notification.addAction(_("Close"), () => {
 | 
			
		||||
            this._notification.destroy();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this._notification.addAction(_("Change Settings…"), () => {
 | 
			
		||||
            // FIXME: this requires the Automatic Updates panel in GNOME
 | 
			
		||||
            // Settings. Going with the Network panel for now…
 | 
			
		||||
            let app = Shell.AppSystem.get_default().lookup_app('gnome-network-panel.desktop');
 | 
			
		||||
            Main.overview.hide();
 | 
			
		||||
            app.activate();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        source.notify(this._notification);
 | 
			
		||||
 | 
			
		||||
        this._notification.connect('destroy', () => {
 | 
			
		||||
            this._notification = null;
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Now that we first detected this connection, mark it as such
 | 
			
		||||
        this._manager.lastNotificationTime = GLib.get_real_time();
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
var Component = UpdateComponent;
 | 
			
		||||
@@ -774,10 +774,17 @@ class AggregateMenu extends PanelMenu.Button {
 | 
			
		||||
        this._nightLight = new imports.ui.status.nightLight.Indicator();
 | 
			
		||||
        this._thunderbolt = new imports.ui.status.thunderbolt.Indicator();
 | 
			
		||||
 | 
			
		||||
        if (Main.sessionMode.components.includes('updates'))
 | 
			
		||||
            this._automaticUpdates = new imports.ui.status.automaticUpdates.Indicator();
 | 
			
		||||
        else
 | 
			
		||||
            this._automaticUpdates = null;
 | 
			
		||||
 | 
			
		||||
        this._indicators.add_child(this._thunderbolt.indicators);
 | 
			
		||||
        this._indicators.add_child(this._screencast.indicators);
 | 
			
		||||
        this._indicators.add_child(this._location.indicators);
 | 
			
		||||
        this._indicators.add_child(this._nightLight.indicators);
 | 
			
		||||
        if (this._automaticUpdates)
 | 
			
		||||
            this._indicators.add_child(this._automaticUpdates.indicators);
 | 
			
		||||
        if (this._network) {
 | 
			
		||||
            this._indicators.add_child(this._network.indicators);
 | 
			
		||||
        }
 | 
			
		||||
@@ -796,6 +803,8 @@ class AggregateMenu extends PanelMenu.Button {
 | 
			
		||||
        if (this._network) {
 | 
			
		||||
            this.menu.addMenuItem(this._network.menu);
 | 
			
		||||
        }
 | 
			
		||||
        if (this._automaticUpdates)
 | 
			
		||||
            this.menu.addMenuItem(this._automaticUpdates.menu);
 | 
			
		||||
        if (this._bluetooth) {
 | 
			
		||||
            this.menu.addMenuItem(this._bluetooth.menu);
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -92,9 +92,11 @@ const _modes = {
 | 
			
		||||
        unlockDialog: imports.ui.unlockDialog.UnlockDialog,
 | 
			
		||||
        components: Config.HAVE_NETWORKMANAGER ?
 | 
			
		||||
                    ['networkAgent', 'polkitAgent', 'telepathyClient',
 | 
			
		||||
                     'keyring', 'autorunManager', 'automountManager'] :
 | 
			
		||||
                     'keyring', 'autorunManager', 'automountManager',
 | 
			
		||||
                     'updates'] :
 | 
			
		||||
                    ['polkitAgent', 'telepathyClient',
 | 
			
		||||
                     'keyring', 'autorunManager', 'automountManager'],
 | 
			
		||||
                     'keyring', 'autorunManager', 'automountManager',
 | 
			
		||||
                     'updates'],
 | 
			
		||||
 | 
			
		||||
        panel: {
 | 
			
		||||
            left: ['activities', 'appMenu'],
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										144
									
								
								js/ui/status/automaticUpdates.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										144
									
								
								js/ui/status/automaticUpdates.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,144 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
//
 | 
			
		||||
// Copyright (C) 2018 Endless Mobile, Inc.
 | 
			
		||||
//
 | 
			
		||||
// This is a GNOME Shell component to wrap the interactions over
 | 
			
		||||
// D-Bus with the Mogwai system daemon.
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the GNU General Public License Version 2
 | 
			
		||||
//
 | 
			
		||||
// 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 2
 | 
			
		||||
// 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, write to the Free Software
 | 
			
		||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 | 
			
		||||
 | 
			
		||||
const { Gio, GLib, Shell, St } = imports.gi;
 | 
			
		||||
 | 
			
		||||
const UpdateManager = imports.misc.updateManager;
 | 
			
		||||
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const MessageTray = imports.ui.messageTray;
 | 
			
		||||
const PanelMenu = imports.ui.panelMenu;
 | 
			
		||||
const PopupMenu = imports.ui.popupMenu;
 | 
			
		||||
 | 
			
		||||
const NM_SETTING_AUTOMATIC_UPDATES_NOTIFICATION_TIME = "connection.automatic-updates-notification-time";
 | 
			
		||||
const NM_SETTING_ALLOW_DOWNLOADS = 'connection.allow-downloads';
 | 
			
		||||
const NM_SETTING_TARIFF_ENABLED = "connection.tariff-enabled";
 | 
			
		||||
 | 
			
		||||
const SchedulerInterface = '\
 | 
			
		||||
<node> \
 | 
			
		||||
  <interface name="com.endlessm.DownloadManager1.Scheduler"> \
 | 
			
		||||
    <property name="ActiveEntryCount" type="u" access="read" /> \
 | 
			
		||||
    <property name="EntryCount" type="u" access="read" /> \
 | 
			
		||||
  </interface> \
 | 
			
		||||
</node>';
 | 
			
		||||
 | 
			
		||||
const SchedulerProxy = Gio.DBusProxy.makeProxyWrapper(SchedulerInterface);
 | 
			
		||||
 | 
			
		||||
var Indicator = class extends PanelMenu.SystemIndicator {
 | 
			
		||||
    constructor() {
 | 
			
		||||
        super();
 | 
			
		||||
 | 
			
		||||
        this._indicator = this._addIndicator();
 | 
			
		||||
        this._indicator.visible = false;
 | 
			
		||||
 | 
			
		||||
        this._item = new PopupMenu.PopupSubMenuMenuItem("", true);
 | 
			
		||||
        this._toggleItem = this._item.menu.addAction("", this._toggleAutomaticUpdates.bind(this));
 | 
			
		||||
        this._item.menu.addAction(_("Updates Queue"), () => {
 | 
			
		||||
            let params = new GLib.Variant('(sava{sv})', [ 'set-mode', [ new GLib.Variant('s', 'updates') ], {} ]);
 | 
			
		||||
            Gio.DBus.session.call('org.gnome.Software',
 | 
			
		||||
                                  '/org/gnome/Software',
 | 
			
		||||
                                  'org.gtk.Actions',
 | 
			
		||||
                                  'Activate',
 | 
			
		||||
                                  params,
 | 
			
		||||
                                  null,
 | 
			
		||||
                                  Gio.DBusCallFlags.NONE,
 | 
			
		||||
                                  5000,
 | 
			
		||||
                                  null,
 | 
			
		||||
                                  (conn, result) => {
 | 
			
		||||
                                      try {
 | 
			
		||||
                                          conn.call_finish(result);
 | 
			
		||||
                                      } catch (e) {
 | 
			
		||||
                                          logError(e, 'Failed to start gnome-software');
 | 
			
		||||
                                      }
 | 
			
		||||
                                  });
 | 
			
		||||
 | 
			
		||||
        });
 | 
			
		||||
        this._item.menu.addSettingsAction(_("Set a Schedule"), 'gnome-updates-panel.desktop');
 | 
			
		||||
        this.menu.addMenuItem(this._item);
 | 
			
		||||
 | 
			
		||||
        this._manager = UpdateManager.getUpdateManager();
 | 
			
		||||
        this._manager.connect('notify::state', this._updateState.bind(this));
 | 
			
		||||
 | 
			
		||||
        this._updateState();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _updateState() {
 | 
			
		||||
        this._updateStatus();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _sessionUpdated() {
 | 
			
		||||
        let sensitive = !Main.sessionMode.isLocked && !Main.sessionMode.isGreeter;
 | 
			
		||||
        this.menu.setSensitive(sensitive);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _updateStatus() {
 | 
			
		||||
        // Toggle item name
 | 
			
		||||
        this._updateItem();
 | 
			
		||||
 | 
			
		||||
        // Icons
 | 
			
		||||
        let icon = this._getIcon()
 | 
			
		||||
 | 
			
		||||
        this._item.icon.gicon = icon;
 | 
			
		||||
        this._indicator.gicon = icon;
 | 
			
		||||
 | 
			
		||||
        // Only show the Automatic Updates icon at the bottom bar when it is
 | 
			
		||||
        // both enabled, and there are updates being downloaded or installed.
 | 
			
		||||
        this._updateVisibility();
 | 
			
		||||
 | 
			
		||||
        // The status label
 | 
			
		||||
        this._item.label.text = _("Automatic Updates");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _updateItem() {
 | 
			
		||||
        let state = this._manager.state;
 | 
			
		||||
 | 
			
		||||
        if (state == UpdateManager.State.DISABLED)
 | 
			
		||||
            this._toggleItem.label.text = _("Turn On");
 | 
			
		||||
        else
 | 
			
		||||
            this._toggleItem.label.text = _("Turn Off");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _toggleAutomaticUpdates() {
 | 
			
		||||
        this._manager.toggleAutomaticUpdates();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _getIcon() {
 | 
			
		||||
        let state = this._manager.state;
 | 
			
		||||
        let iconName = UpdateManager.stateToIconName(state);
 | 
			
		||||
 | 
			
		||||
        if (!iconName)
 | 
			
		||||
            return null;
 | 
			
		||||
 | 
			
		||||
        let iconFile = Gio.File.new_for_uri(iconName);
 | 
			
		||||
        let gicon = new Gio.FileIcon({ file: iconFile });
 | 
			
		||||
 | 
			
		||||
        return gicon;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _updateVisibility() {
 | 
			
		||||
        let state = this._manager.state;
 | 
			
		||||
 | 
			
		||||
        this._item.actor.visible = (state != UpdateManager.State.DISCONNECTED);
 | 
			
		||||
        this._indicator.visible = (state == UpdateManager.State.DOWNLOADING);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
@@ -52,6 +52,7 @@ js/ui/search.js
 | 
			
		||||
js/ui/shellEntry.js
 | 
			
		||||
js/ui/shellMountOperation.js
 | 
			
		||||
js/ui/status/accessibility.js
 | 
			
		||||
js/ui/status/automaticUpdates.js
 | 
			
		||||
js/ui/status/bluetooth.js
 | 
			
		||||
js/ui/status/brightness.js
 | 
			
		||||
js/ui/status/keyboard.js
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user