Compare commits

...

8 Commits

Author SHA1 Message Date
Georges Basile Stavracas Neto
47a2e58d45 Introduce updates indicator
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/466
2019-03-19 12:18:54 +00:00
Georges Basile Stavracas Neto
20d73be57d Introduce Automatic Updates component
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/466
2019-03-19 12:18:47 +00:00
Carlos Garnacho
62233a4db4 dnd: Multiply drag threshold by output scale
So it comes out right on hidpi, and consistent with clients.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/455
2019-03-13 17:22:35 +00:00
Carlos Garnacho
4a7e2ddff5 dnd: Make startDrag() fail if there is a current grab
This call just went through stomping over previous drag operations if any,
_maybeStartDrag() accounted for this, but other callers (well, WindowClone
in workspace.js) don't. This must bail out early even if a drag operation is
requested, luckily all callers account for it already.

This broke shell state by preserving connected captured-event handlers if
one tried to drag multiple windows simultaneously through multitouch. We
of course don't support that, now more elegantly.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/455
2019-03-13 17:22:35 +00:00
Victor Ibragimov
fb737ebde0 Update Tajik Translation 2019-03-13 21:45:05 +05:00
Victor Ibragimov
bf77cb44e7 Merge branch 'master' of gitlab.gnome.org:GNOME/gnome-shell 2019-03-13 21:40:31 +05:00
Victor Ibragimov
c72e2bb4a9 Update Tajik Translation 2019-03-13 21:39:34 +05:00
Victor Ibragimov
68c182b1df Update Tajik Translation 2019-03-13 21:18:10 +05:00
13 changed files with 717 additions and 75 deletions

View File

@@ -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>

View 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

View 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

View 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

View File

@@ -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
View 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
View 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;

View File

@@ -306,6 +306,9 @@ var _Draggable = class _Draggable {
* for the draggable.
*/
startDrag(stageX, stageY, time, sequence, device) {
if (currentDraggable)
return;
if (device == undefined) {
let event = Clutter.get_current_event();
@@ -447,7 +450,8 @@ var _Draggable = class _Draggable {
let [stageX, stageY] = event.get_coords();
// See if the user has moved the mouse enough to trigger a drag
let threshold = St.Settings.get().drag_threshold;
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
let threshold = St.Settings.get().drag_threshold * scaleFactor;
if (!currentDraggable &&
(Math.abs(stageX - this._dragStartX) > threshold ||
Math.abs(stageY - this._dragStartY) > threshold)) {

View File

@@ -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);
}

View File

@@ -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'],

View 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);
}
};

View File

@@ -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

144
po/tg.po
View File

@@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: Tajik Gnome\n"
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/gnome-shell/issues\n"
"POT-Creation-Date: 2019-03-02 10:57+0000\n"
"PO-Revision-Date: 2019-03-06 20:14+0500\n"
"PO-Revision-Date: 2019-03-13 21:44+0500\n"
"Last-Translator: Victor Ibragimov <victor.ibragimov@gmail.com>\n"
"Language-Team: \n"
"Language: tg\n"
@@ -32,7 +32,7 @@ msgstr "Марказонидани огоҳии фаъол"
#: data/50-gnome-shell-system.xml:15
msgid "Show the overview"
msgstr "Намоиш додани хулоса"
msgstr "Намоиш додани ҷамъбаст"
#: data/50-gnome-shell-system.xml:18
msgid "Show all applications"
@@ -82,7 +82,7 @@ msgstr "Ғайрифаъол кардани васеъшавиҳои корба
#: data/org.gnome.shell.gschema.xml.in:27
msgid "Disable all extensions the user has enabled without affecting the “enabled-extension” setting."
msgstr ""
msgstr "Ҳамаи васеъшавиҳое, ки корбар фаъол кард, бе расонидани таъсир ба танзими “васеъшавиии-фаъол” ғайрифаъол карда мешаванд."
#: data/org.gnome.shell.gschema.xml.in:34
msgid "Disables the validation of extension version compatibility"
@@ -188,11 +188,11 @@ msgstr "Тугмабандӣ барои иваз кардани намоёнии
#: data/org.gnome.shell.gschema.xml.in:138
msgid "Keybinding to focus the active notification"
msgstr "Тугмабандӣ барои гузоштани фокус ба огоҳии фаъол"
msgstr "Тугмабандӣ барои марказонидани огоҳии фаъол"
#: data/org.gnome.shell.gschema.xml.in:139
msgid "Keybinding to focus the active notification."
msgstr "Тугмабандӣ барои гузоштани фокус ба огоҳии фаъол."
msgstr "Тугмабандӣ барои марказонидани огоҳии фаъол."
#: data/org.gnome.shell.gschema.xml.in:145
msgid "Keybinding that pauses and resumes all running tweens, for debugging purposes"
@@ -245,11 +245,11 @@ msgstr "Гузариш ба барномаи 9"
#: data/org.gnome.shell.gschema.xml.in:190
msgid "Which keyboard to use"
msgstr "Клавиатураро интихоб кунед"
msgstr "Клавиатураро интихоб намоед"
#: data/org.gnome.shell.gschema.xml.in:191
msgid "The type of keyboard to use."
msgstr "Намуди клавиатура барои истифода."
msgstr "Навъи клавиатурае, ки истифода мешавад."
#: data/org.gnome.shell.gschema.xml.in:202
#: data/org.gnome.shell.gschema.xml.in:229
@@ -308,15 +308,15 @@ msgstr "Воридшавии шабакавӣ"
#. Translators: Do NOT translate or transliterate this text (this is an icon file name)!
#: data/org.gnome.Shell.PortalHelper.desktop.in.in:9
msgid "network-workgroup"
msgstr ""
msgstr "шабака-гурӯҳи корӣ"
#: js/extensionPrefs/main.js:116
msgid "Somethings gone wrong"
msgstr ""
msgstr "Чизе нодуруст ба миён омад"
#: js/extensionPrefs/main.js:123
msgid "Were very sorry, but theres been a problem: the settings for this extension cant be displayed. We recommend that you report the issue to the extension authors."
msgstr ""
msgstr "Мутаассифона, хатое ба вуҷуд омад: танзимот барои ин васеъшавӣ нишон дода намешавад. Тавсия дода мешавад, ки шумо дар бораи хато ба муаллифони васеъшавӣ гузориш диҳед."
#: js/extensionPrefs/main.js:130
#| msgid "Show Details"
@@ -330,7 +330,7 @@ msgstr "Намоиш додани хатоҳо"
#: js/extensionPrefs/main.js:185
msgid "Homepage"
msgstr ""
msgstr "Саҳифаи асосӣ"
#: js/extensionPrefs/main.js:186
#| msgid "UUIDs of extensions to enable"
@@ -340,15 +340,15 @@ msgstr "Рамзҳои UUID барои пасвандҳои фаъолшаван
#: js/extensionPrefs/main.js:449
#| msgid "No extensions installed"
msgid "No Extensions Installed"
msgstr "Ягон пасванд насб нашудааст"
msgstr "Ягон васеъшавӣ насб нашудааст"
#: js/extensionPrefs/main.js:459
msgid "Extensions can be installed through Software or <a href=\"https://extensions.gnome.org\">extensions.gnome.org</a>."
msgstr ""
msgstr "Васеъшавиҳо ба воситаи низоми нармафзор ё <a href=\"https://extensions.gnome.org\">extensions.gnome.org</a> ҷорӣ карда мешаванд."
#: js/extensionPrefs/main.js:474
msgid "Browse in Software"
msgstr ""
msgstr "Намоиш дар низоми нармафзор"
#: js/gdm/authPrompt.js:140 js/ui/audioDeviceSelection.js:55
#: js/ui/components/networkAgent.js:117 js/ui/components/polkitAgent.js:136
@@ -430,7 +430,7 @@ msgstr ""
#: js/misc/systemActions.js:95
msgctxt "search-result"
msgid "Lock Screen"
msgstr ""
msgstr "Қулф кардани экран"
#. Translators: A list of keywords that match the lock screen action, separated by semicolons
#: js/misc/systemActions.js:98
@@ -454,13 +454,13 @@ msgstr ""
#| msgid "Suspend"
msgctxt "search-result"
msgid "Suspend"
msgstr "Таваққуф кардан"
msgstr "Таваққуф кардани низом"
#. Translators: A list of keywords that match the suspend action, separated by semicolons
#: js/misc/systemActions.js:112
#| msgid "Suspend"
msgid "suspend;sleep"
msgstr "Таваққуф"
msgstr "таваққуф;хоб"
#. Translators: The name of the switch user action in search
#: js/misc/systemActions.js:116
@@ -473,14 +473,14 @@ msgstr "Иваз кардани корбар"
#: js/misc/systemActions.js:119
#| msgid "Switch User"
msgid "switch user"
msgstr "Таъвизи корбар"
msgstr "ивази корбар"
#. Translators: The name of the lock orientation action in search
#: js/misc/systemActions.js:123
#| msgid "Orientation Lock"
msgctxt "search-result"
msgid "Lock Orientation"
msgstr "Қулфи самт"
msgstr "Қулфи самти экран"
#. Translators: A list of keywords that match the lock orientation action, separated by semicolons
#: js/misc/systemActions.js:126
@@ -504,7 +504,7 @@ msgstr "Иҷрокунии “%s” қатъ шудааст:"
#: js/misc/util.js:175
msgid "Just now"
msgstr ""
msgstr "Ҳоли ҳозир"
#: js/misc/util.js:177
#, javascript-format
@@ -533,29 +533,29 @@ msgstr "Дирӯз"
#, javascript-format
msgid "%d day ago"
msgid_plural "%d days ago"
msgstr[0] ""
msgstr[1] ""
msgstr[0] "%d рӯз пеш"
msgstr[1] "%d рӯз пеш"
#: js/misc/util.js:188
#, javascript-format
msgid "%d week ago"
msgid_plural "%d weeks ago"
msgstr[0] ""
msgstr[1] ""
msgstr[0] "%d ҳафта пеш"
msgstr[1] "%d ҳафта пеш"
#: js/misc/util.js:191
#, javascript-format
msgid "%d month ago"
msgid_plural "%d months ago"
msgstr[0] ""
msgstr[1] ""
msgstr[0] "%d моҳ пеш"
msgstr[1] "%d моҳ пеш"
#: js/misc/util.js:193
#, javascript-format
msgid "%d year ago"
msgid_plural "%d years ago"
msgstr[0] ""
msgstr[1] ""
msgstr[0] "%d сол пеш"
msgstr[1] "%d сол пеш"
#. Translators: Time in 24h format
#: js/misc/util.js:223
@@ -635,22 +635,22 @@ msgstr "%B %d %Y, %l%M %p"
#: js/portalHelper/main.js:40
#| msgid "Hotspot Active"
msgid "Hotspot Login"
msgstr "Hotspot фаъол аст"
msgstr "Воридшавӣ ба нуқтаи пайваст"
#: js/portalHelper/main.js:86
msgid "Your connection to this hotspot login is not secure. Passwords or other information you enter on this page can be viewed by people nearby."
msgstr ""
msgstr "Пайвасти воридшавии шумо ба нуқтаи пайвасти ҷорӣ бехатар намебошад. Ниҳонвожаҳо ё маълумоти дигаре, ки дар ин саҳифа ворид карда мешавад, метавонанд бо одамони дар гидру атроф ошкор карда шаванд."
#. No support for non-modal system dialogs, so ignore the option
#. let modal = options['modal'] || true;
#: js/ui/accessDialog.js:37 js/ui/status/location.js:360
msgid "Deny Access"
msgstr ""
msgstr "Манъ кардани дастрасӣ"
#: js/ui/accessDialog.js:38 js/ui/status/location.js:363
#| msgid "Always grant access"
msgid "Grant Access"
msgstr "Ҳамеша иҷозат додан"
msgstr "Иҷозат додани дастрасӣ"
#: js/ui/appDisplay.js:660
msgid "Frequently used applications will appear here"
@@ -697,7 +697,7 @@ msgstr "%s аз баргузидаҳои шумо тоза шудааст."
#: js/ui/audioDeviceSelection.js:42
#| msgid "Send Files to Device…"
msgid "Select Audio Device"
msgstr "Фиристодани файлҳо ба дастгоҳ..."
msgstr "Интихоби дастгоҳи аудиоӣ"
#: js/ui/audioDeviceSelection.js:53
msgid "Sound Settings"
@@ -705,11 +705,11 @@ msgstr "Танзимоти садо"
#: js/ui/audioDeviceSelection.js:62
msgid "Headphones"
msgstr ""
msgstr "Гӯшмонакҳо"
#: js/ui/audioDeviceSelection.js:64
msgid "Headset"
msgstr ""
msgstr "Гӯшмонак бо микрофон"
#: js/ui/audioDeviceSelection.js:66 js/ui/status/volume.js:247
msgid "Microphone"
@@ -717,7 +717,7 @@ msgstr "Микрофон"
#: js/ui/backgroundMenu.js:13
msgid "Change Background…"
msgstr "Тағйир додани пазсамина..."
msgstr "Тағйир додани пазсамина"
#: js/ui/backgroundMenu.js:15 js/ui/status/nightLight.js:43
msgid "Display Settings"
@@ -800,7 +800,7 @@ msgstr "%OB"
#.
#: js/ui/calendar.js:342
msgid "%OB %Y"
msgstr ""
msgstr "%OB %Y"
#: js/ui/calendar.js:399
msgid "Previous month"
@@ -854,14 +854,14 @@ msgstr "Ягон рӯйдод нест"
#: js/ui/calendar.js:1075
msgid "Clear"
msgstr ""
msgstr "Пок кардан"
#. Translators: %s is an application name
#: js/ui/closeDialog.js:42
#, javascript-format
#| msgid "“%s” is ready"
msgid "“%s” is not responding."
msgstr "“%s” омода аст"
msgstr "“%s” ҷавоб намедиҳад."
#: js/ui/closeDialog.js:43
msgid "You may choose to wait a short while for it to continue or force the application to quit entirely."
@@ -869,11 +869,11 @@ msgstr ""
#: js/ui/closeDialog.js:59
msgid "Force Quit"
msgstr ""
msgstr "Маҷбуран пӯшида шавад"
#: js/ui/closeDialog.js:62
msgid "Wait"
msgstr ""
msgstr "Интизор шавед"
#: js/ui/components/automountManager.js:86
msgid "External drive connected"
@@ -910,24 +910,24 @@ msgstr "Пайваст шудан"
#: js/ui/components/networkAgent.js:246 js/ui/components/networkAgent.js:265
#: js/ui/components/networkAgent.js:285 js/ui/components/networkAgent.js:295
msgid "Password: "
msgstr "Ниҳонвожа:"
msgstr "Ниҳонвожа: "
#. static WEP
#: js/ui/components/networkAgent.js:216
msgid "Key: "
msgstr "Калид:"
msgstr "Калид: "
#: js/ui/components/networkAgent.js:249 js/ui/components/networkAgent.js:271
msgid "Private key password: "
msgstr "Пароли калиди шахсӣ:"
msgstr "Ниҳонвожаи калиди шахсӣ: "
#: js/ui/components/networkAgent.js:269
msgid "Identity: "
msgstr "Шахсият:"
msgstr "Шахсият: "
#: js/ui/components/networkAgent.js:283
msgid "Service: "
msgstr "Хидмат:"
msgstr "Хидмат: "
#: js/ui/components/networkAgent.js:312 js/ui/components/networkAgent.js:685
msgid "Authentication required by wireless network"
@@ -944,7 +944,7 @@ msgstr "Санҷиши ҳаққонияти 802.1X-и симдор"
#: js/ui/components/networkAgent.js:319
msgid "Network name: "
msgstr "Номи шабака:"
msgstr "Номи шабака: "
#: js/ui/components/networkAgent.js:324 js/ui/components/networkAgent.js:693
msgid "DSL authentication"
@@ -960,7 +960,7 @@ msgstr "Барои дастгоҳи паҳннавори мобилӣ рамзи
#: js/ui/components/networkAgent.js:333
msgid "PIN: "
msgstr "PIN:"
msgstr "PIN: "
#: js/ui/components/networkAgent.js:340 js/ui/components/networkAgent.js:706
msgid "Mobile broadband network password"
@@ -1051,12 +1051,12 @@ msgstr "Обу ҳаво"
#: js/ui/dateMenu.js:305
#| msgid "Select a network"
msgid "Select a location…"
msgstr "Интихоб кардани шабака"
msgstr "Интихоби ҷойгиршавӣ…"
#: js/ui/dateMenu.js:313
#| msgid "Searching…"
msgid "Loading…"
msgstr "Ҷустуҷӯ рафта истодааст..."
msgstr "Бор шуда истодааст"
#: js/ui/dateMenu.js:323
msgid "Go online for weather information"
@@ -1274,7 +1274,7 @@ msgstr ""
#: js/ui/kbdA11yDialog.js:57
msgid "Leave On"
msgstr ""
msgstr "Ҳамеша фаъол"
#: js/ui/kbdA11yDialog.js:57 js/ui/status/bluetooth.js:133
#: js/ui/status/network.js:1264
@@ -1287,11 +1287,11 @@ msgstr "Фаъол кардан"
#: js/ui/status/nightLight.js:39 js/ui/status/rfkill.js:79
#: js/ui/status/rfkill.js:106
msgid "Turn Off"
msgstr "Хомӯш кардан"
msgstr "Ғайрифаъол кардан"
#: js/ui/kbdA11yDialog.js:65
msgid "Leave Off"
msgstr ""
msgstr "Ҳамеша ғайрифаъол"
#: js/ui/keyboard.js:203
msgid "Region & Language Settings"
@@ -1327,7 +1327,7 @@ msgstr "Ғайрифаъол"
#: js/ui/lookingGlass.js:693
msgid "Error"
msgstr "Хатогӣ"
msgstr "Хато"
#: js/ui/lookingGlass.js:695
msgid "Out of date"
@@ -1372,7 +1372,7 @@ msgstr "Ботил сохтан"
#. activities. See also note for "Activities" string.
#: js/ui/overview.js:100
msgid "Overview"
msgstr "Хулоса"
msgstr "Ҷамъбаст"
#. Translators: this is the text displayed
#. in the search entry when no search is
@@ -1380,20 +1380,20 @@ msgstr "Хулоса"
#. characters.
#: js/ui/overview.js:226
msgid "Type to search…"
msgstr "Ҷустуҷӯ кардан..."
msgstr "Барои ҷустуҷӯ чизеро чоп намоед…"
#: js/ui/padOsd.js:92
msgid "New shortcut…"
msgstr ""
msgstr "Миёнбури нав…"
#: js/ui/padOsd.js:141
#| msgid "Applications"
msgid "Application defined"
msgstr "Барномаҳо"
msgstr "Барномаи муайяншуда"
#: js/ui/padOsd.js:142
msgid "Show on-screen help"
msgstr ""
msgstr "Намоиш додани кумаки экранӣ"
#: js/ui/padOsd.js:143
#| msgid "Switch User"
@@ -1406,7 +1406,7 @@ msgstr ""
#: js/ui/padOsd.js:209
msgid "Done"
msgstr ""
msgstr "Тайёр"
#: js/ui/padOsd.js:721
msgid "Edit…"
@@ -1414,19 +1414,19 @@ msgstr "Таҳрир кардан…"
#: js/ui/padOsd.js:763 js/ui/padOsd.js:868
msgid "None"
msgstr ""
msgstr "Ҳеҷ"
#: js/ui/padOsd.js:822
msgid "Press a button to configure"
msgstr ""
msgstr "Барои идома тугмаеро пахш намоед"
#: js/ui/padOsd.js:823
msgid "Press Esc to exit"
msgstr ""
msgstr "Барои баромад тугмаи Esc-ро пахш намоед"
#: js/ui/padOsd.js:826
msgid "Press any key to exit"
msgstr ""
msgstr "Барои баромад тугмаи дилхоҳро пахш намоед"
#: js/ui/panel.js:108
msgid "Quit"
@@ -1446,7 +1446,7 @@ msgstr "Низом"
#: js/ui/panel.js:861
msgid "Top Bar"
msgstr "Панели боло"
msgstr "Лавҳаии болоӣ"
#. Translators: this MUST be either "toggle-switch-us"
#. (for toggle switches containing the English words
@@ -1519,7 +1519,7 @@ msgstr "Қулф аз тарави барнома баста шудааст"
#: js/ui/search.js:635
msgid "Searching…"
msgstr "Ҷустуҷӯ рафта истодааст..."
msgstr "Дар ҳоли ҷустуҷӯ…"
#: js/ui/search.js:637
msgid "No results."
@@ -1836,7 +1836,7 @@ msgstr "%s пайваст нашудааст"
#: js/ui/status/network.js:1393
#| msgid "Connecting"
msgid "connecting…"
msgstr "Пайвастшавӣ"
msgstr "пайваст шуда истодааст…"
#. Translators: this is for network connections that require some kind of key or password
#: js/ui/status/network.js:1396
@@ -1894,7 +1894,7 @@ msgstr "Пайваст қатъ шудааст"
#: js/ui/status/network.js:1703
msgid "Activation of network connection failed"
msgstr "Фаъолсозии пайвасти шабака қатъ шудааст."
msgstr "Фаъолсозии пайвасти шабака қатъ шуд"
#: js/ui/status/nightLight.js:60
#| msgid "Networking is disabled"
@@ -1929,7 +1929,7 @@ msgstr ""
#. to estimate battery life
#: js/ui/status/power.js:70 js/ui/status/power.js:76
msgid "Estimating…"
msgstr "Ҳисоб шуда истодааст..."
msgstr "Ҳисоб шуда истодааст"
#. Translators: this is <hours>:<minutes> Remaining (<percentage>)
#: js/ui/status/power.js:84
@@ -1948,7 +1948,7 @@ msgstr "%d%02d то пур шудан (%d%%)"
#: js/ui/status/power.js:117 js/ui/status/power.js:119
#, javascript-format
msgid "%d%%"
msgstr ""
msgstr "%d%%"
#: js/ui/status/remoteAccess.js:42
msgid "Screen is Being Shared"
@@ -1978,11 +1978,11 @@ msgstr "Баромад аз мизи корӣ"
#: js/ui/status/system.js:227
#| msgid "Sound Settings"
msgid "Account Settings"
msgstr "Танзимоти садо"
msgstr "Танзимоти ҳисоб"
#: js/ui/status/system.js:255
msgid "Orientation Lock"
msgstr "Қулфи самт"
msgstr "Қулфи самти экран"
#: js/ui/status/system.js:281
msgid "Suspend"