From 73eaf0df9fe954bf0e6a2d45f42333b8fc00793f Mon Sep 17 00:00:00 2001 From: Georges Basile Stavracas Neto Date: Thu, 28 Nov 2019 18:35:13 -0300 Subject: [PATCH] screenShield: Move notifications to Unlock Dialog Also adjust the CSS style classes names to match the new owner. https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/872 --- .../widgets/_screen-shield.scss | 16 +- js/ui/screenShield.js | 274 +---------------- js/ui/unlockDialog.js | 276 ++++++++++++++++++ 3 files changed, 286 insertions(+), 280 deletions(-) diff --git a/data/theme/gnome-shell-sass/widgets/_screen-shield.scss b/data/theme/gnome-shell-sass/widgets/_screen-shield.scss index 8401da193..f08c1bebc 100644 --- a/data/theme/gnome-shell-sass/widgets/_screen-shield.scss +++ b/data/theme/gnome-shell-sass/widgets/_screen-shield.scss @@ -1,10 +1,10 @@ /* Screen Shield */ -$_screenshield_shadow: 0px 0px 6px rgba(0, 0, 0, 0.726); +$_unlockdialog_shadow: 0px 0px 6px rgba(0, 0, 0, 0.726); .unlock-dialog-clock { color: white; - text-shadow: $_screenshield_shadow; + text-shadow: $_unlockdialog_shadow; font-weight: bold; text-align: center; padding-bottom: 1.5em; @@ -12,7 +12,7 @@ $_screenshield_shadow: 0px 0px 6px rgba(0, 0, 0, 0.726); .unlock-dialog-clock-time { font-size: 72pt; - text-shadow: $_screenshield_shadow; + text-shadow: $_unlockdialog_shadow; font-feature-settings: "tnum"; } @@ -21,7 +21,7 @@ $_screenshield_shadow: 0px 0px 6px rgba(0, 0, 0, 0.726); font-weight: normal; } -.screen-shield-notifications-container { +.unlock-dialog-notifications-container { spacing: 6px; width: 30em; background-color: transparent; @@ -32,7 +32,7 @@ $_screenshield_shadow: 0px 0px 6px rgba(0, 0, 0, 0.726); } .notification, - .screen-shield-notification-source { + .unlock-dialog-notification-source { padding: 12px 6px; border: 1px solid $osd_outer_borders_color; background-color: transparentize($osd_bg_color,0.5); @@ -43,12 +43,12 @@ $_screenshield_shadow: 0px 0px 6px rgba(0, 0, 0, 0.726); } -.screen-shield-notification-label { +.unlock-dialog-notification-label { font-weight: bold; padding: 0px 0px 0px 12px; } -.screen-shield-notification-count-text { padding: 0px 0px 0px 12px; } +.unlock-dialog-notification-count-text { padding: 0px 0px 0px 12px; } #panel.lock-screen { background-color: transparentize($osd_bg_color, 0.5); } @@ -62,7 +62,7 @@ $_screenshield_shadow: 0px 0px 6px rgba(0, 0, 0, 0.726); background-repeat: repeat; } -#screenShieldNotifications { +#unlockDialogNotifications { StButton#vhandle, StButton#hhandle { background-color: transparentize($bg_color,0.7); &:hover, &:focus { background-color: transparentize($bg_color,0.5); } diff --git a/js/ui/screenShield.js b/js/ui/screenShield.js index 94e399bbb..7cbf26059 100644 --- a/js/ui/screenShield.js +++ b/js/ui/screenShield.js @@ -1,7 +1,7 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- -const { AccountsService, Clutter, Gio, GLib, - GObject, Graphene, Meta, Shell, St } = imports.gi; +const { AccountsService, Clutter, Gio, + GLib, Graphene, Meta, Shell, St } = imports.gi; const Signals = imports.signals; const Background = imports.ui.background; @@ -30,8 +30,6 @@ const LOCKED_STATE_STR = 'screenShield.locked'; // the slide up automatically var ARROW_DRAG_THRESHOLD = 0.1; -var SUMMARY_ICON_SIZE = 48; - // ScreenShield animation time // - STANDARD_FADE_TIME is used when the session goes idle // - MANUAL_FADE_TIME is used for lowering the shield when asked by the user, @@ -41,264 +39,6 @@ var STANDARD_FADE_TIME = 10000; var MANUAL_FADE_TIME = 300; var CURTAIN_SLIDE_TIME = 300; -var NotificationsBox = GObject.registerClass({ - Signals: { 'wake-up-screen': {} }, -}, class NotificationsBox extends St.BoxLayout { - _init() { - super._init({ - vertical: true, - name: 'screenShieldNotifications', - style_class: 'screen-shield-notifications-container', - }); - - this._scrollView = new St.ScrollView({ hscrollbar_policy: St.PolicyType.NEVER }); - this._notificationBox = new St.BoxLayout({ vertical: true, - style_class: 'screen-shield-notifications-container' }); - this._scrollView.add_actor(this._notificationBox); - - this.add_child(this._scrollView); - - this._sources = new Map(); - Main.messageTray.getSources().forEach(source => { - this._sourceAdded(Main.messageTray, source, true); - }); - this._updateVisibility(); - - this._sourceAddedId = Main.messageTray.connect('source-added', this._sourceAdded.bind(this)); - - this.connect('destroy', this._onDestroy.bind(this)); - } - - _onDestroy() { - if (this._sourceAddedId) { - Main.messageTray.disconnect(this._sourceAddedId); - this._sourceAddedId = 0; - } - - let items = this._sources.entries(); - for (let [source, obj] of items) - this._removeSource(source, obj); - } - - _updateVisibility() { - this._notificationBox.visible = - this._notificationBox.get_children().some(a => a.visible); - - this.visible = this._notificationBox.visible; - } - - _makeNotificationCountText(count, isChat) { - if (isChat) - return ngettext("%d new message", "%d new messages", count).format(count); - else - return ngettext("%d new notification", "%d new notifications", count).format(count); - } - - _makeNotificationSource(source, box) { - let sourceActor = new MessageTray.SourceActor(source, SUMMARY_ICON_SIZE); - box.add_child(sourceActor); - - let textBox = new St.BoxLayout({ vertical: true }); - box.add_child(textBox); - - let title = new St.Label({ text: source.title, - style_class: 'screen-shield-notification-label' }); - textBox.add(title); - - let count = source.unseenCount; - let countLabel = new St.Label({ text: this._makeNotificationCountText(count, source.isChat), - style_class: 'screen-shield-notification-count-text' }); - textBox.add(countLabel); - - box.visible = count != 0; - return [title, countLabel]; - } - - _makeNotificationDetailedSource(source, box) { - let sourceActor = new MessageTray.SourceActor(source, SUMMARY_ICON_SIZE); - let sourceBin = new St.Bin({ child: sourceActor }); - box.add(sourceBin); - - let textBox = new St.BoxLayout({ vertical: true }); - box.add_child(textBox); - - let title = new St.Label({ text: source.title, - style_class: 'screen-shield-notification-label' }); - textBox.add(title); - - let visible = false; - for (let i = 0; i < source.notifications.length; i++) { - let n = source.notifications[i]; - - if (n.acknowledged) - continue; - - let body = ''; - if (n.bannerBodyText) { - body = n.bannerBodyMarkup - ? n.bannerBodyText - : GLib.markup_escape_text(n.bannerBodyText, -1); - } - - let label = new St.Label({ style_class: 'screen-shield-notification-count-text' }); - label.clutter_text.set_markup(`${n.title} ${body}`); - textBox.add(label); - - visible = true; - } - - box.visible = visible; - return [title, null]; - } - - _shouldShowDetails(source) { - return source.policy.detailsInLockScreen || - source.narrowestPrivacyScope == MessageTray.PrivacyScope.SYSTEM; - } - - _showSource(source, obj, box) { - if (obj.detailed) - [obj.titleLabel, obj.countLabel] = this._makeNotificationDetailedSource(source, box); - else - [obj.titleLabel, obj.countLabel] = this._makeNotificationSource(source, box); - - box.visible = obj.visible && (source.unseenCount > 0); - } - - _sourceAdded(tray, source, initial) { - let obj = { - visible: source.policy.showInLockScreen, - detailed: this._shouldShowDetails(source), - sourceDestroyId: 0, - sourceCountChangedId: 0, - sourceTitleChangedId: 0, - sourceUpdatedId: 0, - sourceBox: null, - titleLabel: null, - countLabel: null, - }; - - obj.sourceBox = new St.BoxLayout({ style_class: 'screen-shield-notification-source', - x_expand: true }); - this._showSource(source, obj, obj.sourceBox); - this._notificationBox.add_child(obj.sourceBox); - - obj.sourceCountChangedId = source.connect('notify::count', () => { - this._countChanged(source, obj); - }); - obj.sourceTitleChangedId = source.connect('notify::title', () => { - this._titleChanged(source, obj); - }); - obj.policyChangedId = source.policy.connect('notify', (policy, pspec) => { - if (pspec.name == 'show-in-lock-screen') - this._visibleChanged(source, obj); - else - this._detailedChanged(source, obj); - }); - obj.sourceDestroyId = source.connect('destroy', () => { - this._onSourceDestroy(source, obj); - }); - - this._sources.set(source, obj); - - if (!initial) { - // block scrollbars while animating, if they're not needed now - let boxHeight = this._notificationBox.height; - if (this._scrollView.height >= boxHeight) - this._scrollView.vscrollbar_policy = St.PolicyType.NEVER; - - let widget = obj.sourceBox; - let [, natHeight] = widget.get_preferred_height(-1); - widget.height = 0; - widget.ease({ - height: natHeight, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - duration: 250, - onComplete: () => { - this._scrollView.vscrollbar_policy = St.PolicyType.AUTOMATIC; - widget.set_height(-1); - }, - }); - - this._updateVisibility(); - if (obj.sourceBox.visible) - this.emit('wake-up-screen'); - } - } - - _titleChanged(source, obj) { - obj.titleLabel.text = source.title; - } - - _countChanged(source, obj) { - // A change in the number of notifications may change whether we show - // details. - let newDetailed = this._shouldShowDetails(source); - let oldDetailed = obj.detailed; - - obj.detailed = newDetailed; - - if (obj.detailed || oldDetailed != newDetailed) { - // A new notification was pushed, or a previous notification was destroyed. - // Give up, and build the list again. - - obj.sourceBox.destroy_all_children(); - obj.titleLabel = obj.countLabel = null; - this._showSource(source, obj, obj.sourceBox); - } else { - let count = source.unseenCount; - obj.countLabel.text = this._makeNotificationCountText(count, source.isChat); - } - - obj.sourceBox.visible = obj.visible && (source.unseenCount > 0); - - this._updateVisibility(); - if (obj.sourceBox.visible) - this.emit('wake-up-screen'); - } - - _visibleChanged(source, obj) { - if (obj.visible == source.policy.showInLockScreen) - return; - - obj.visible = source.policy.showInLockScreen; - obj.sourceBox.visible = obj.visible && source.unseenCount > 0; - - this._updateVisibility(); - if (obj.sourceBox.visible) - this.emit('wake-up-screen'); - } - - _detailedChanged(source, obj) { - let newDetailed = this._shouldShowDetails(source); - if (obj.detailed == newDetailed) - return; - - obj.detailed = newDetailed; - - obj.sourceBox.destroy_all_children(); - obj.titleLabel = obj.countLabel = null; - this._showSource(source, obj, obj.sourceBox); - } - - _onSourceDestroy(source, obj) { - this._removeSource(source, obj); - this._updateVisibility(); - } - - _removeSource(source, obj) { - obj.sourceBox.destroy(); - obj.sourceBox = obj.titleLabel = obj.countLabel = null; - - source.disconnect(obj.sourceDestroyId); - source.disconnect(obj.sourceCountChangedId); - source.disconnect(obj.sourceTitleChangedId); - source.policy.disconnect(obj.policyChangedId); - - this._sources.delete(source); - } -}); - function clamp(value, min, max) { return Math.max(min, Math.min(max, value)); } @@ -926,10 +666,6 @@ var ScreenShield = class { this._lockScreenContents.add_actor(this._lockScreenContentsBox); - this._notificationsBox = new NotificationsBox(); - this._wakeUpScreenId = this._notificationsBox.connect('wake-up-screen', this._wakeUpScreen.bind(this)); - this._lockScreenContentsBox.add_child(this._notificationsBox); - this._hasLockScreen = true; } @@ -939,12 +675,6 @@ var ScreenShield = class { } _clearLockScreen() { - if (this._notificationsBox) { - this._notificationsBox.disconnect(this._wakeUpScreenId); - this._notificationsBox.destroy(); - this._notificationsBox = null; - } - this._lockScreenContentsBox.destroy(); this._hasLockScreen = false; diff --git a/js/ui/unlockDialog.js b/js/ui/unlockDialog.js index f1cdc8b53..31f0ff26a 100644 --- a/js/ui/unlockDialog.js +++ b/js/ui/unlockDialog.js @@ -6,12 +6,283 @@ const { AccountsService, Atk, Clutter, Gdm, Gio, const Layout = imports.ui.layout; const Main = imports.ui.main; +const MessageTray = imports.ui.messageTray; const AuthPrompt = imports.gdm.authPrompt; // The timeout before going back automatically to the lock screen (in seconds) const IDLE_TIMEOUT = 2 * 60; +const SUMMARY_ICON_SIZE = 48; + +var NotificationsBox = GObject.registerClass({ + Signals: { 'wake-up-screen': {} }, +}, class NotificationsBox extends St.BoxLayout { + _init() { + super._init({ + vertical: true, + name: 'unlockDialogNotifications', + style_class: 'unlock-dialog-notifications-container', + }); + + this._scrollView = new St.ScrollView({ hscrollbar_policy: St.PolicyType.NEVER }); + this._notificationBox = new St.BoxLayout({ + vertical: true, + style_class: 'unlock-dialog-notifications-container', + }); + this._scrollView.add_actor(this._notificationBox); + + this.add_child(this._scrollView); + + this._sources = new Map(); + Main.messageTray.getSources().forEach(source => { + this._sourceAdded(Main.messageTray, source, true); + }); + this._updateVisibility(); + + this._sourceAddedId = Main.messageTray.connect('source-added', this._sourceAdded.bind(this)); + + this.connect('destroy', this._onDestroy.bind(this)); + } + + _onDestroy() { + if (this._sourceAddedId) { + Main.messageTray.disconnect(this._sourceAddedId); + this._sourceAddedId = 0; + } + + let items = this._sources.entries(); + for (let [source, obj] of items) + this._removeSource(source, obj); + } + + _updateVisibility() { + this._notificationBox.visible = + this._notificationBox.get_children().some(a => a.visible); + + this.visible = this._notificationBox.visible; + } + + _makeNotificationCountText(count, isChat) { + if (isChat) + return ngettext('%d new message', '%d new messages', count).format(count); + else + return ngettext('%d new notification', '%d new notifications', count).format(count); + } + + _makeNotificationSource(source, box) { + let sourceActor = new MessageTray.SourceActor(source, SUMMARY_ICON_SIZE); + box.add_child(sourceActor); + + let textBox = new St.BoxLayout({ vertical: true }); + box.add_child(textBox); + + let title = new St.Label({ + text: source.title, + style_class: 'unlock-dialog-notification-label', + }); + textBox.add(title); + + let count = source.unseenCount; + let countLabel = new St.Label({ + text: this._makeNotificationCountText(count, source.isChat), + style_class: 'unlock-dialog-notification-count-text', + }); + textBox.add(countLabel); + + box.visible = count !== 0; + return [title, countLabel]; + } + + _makeNotificationDetailedSource(source, box) { + let sourceActor = new MessageTray.SourceActor(source, SUMMARY_ICON_SIZE); + let sourceBin = new St.Bin({ child: sourceActor }); + box.add(sourceBin); + + let textBox = new St.BoxLayout({ vertical: true }); + box.add_child(textBox); + + let title = new St.Label({ + text: source.title, + style_class: 'unlock-dialog-notification-label', + }); + textBox.add(title); + + let visible = false; + for (let i = 0; i < source.notifications.length; i++) { + let n = source.notifications[i]; + + if (n.acknowledged) + continue; + + let body = ''; + if (n.bannerBodyText) { + body = n.bannerBodyMarkup + ? n.bannerBodyText + : GLib.markup_escape_text(n.bannerBodyText, -1); + } + + let label = new St.Label({ style_class: 'unlock-dialog-notification-count-text' }); + label.clutter_text.set_markup(`${n.title} ${body}`); + textBox.add(label); + + visible = true; + } + + box.visible = visible; + return [title, null]; + } + + _shouldShowDetails(source) { + return source.policy.detailsInLockScreen || + source.narrowestPrivacyScope === MessageTray.PrivacyScope.SYSTEM; + } + + _showSource(source, obj, box) { + if (obj.detailed) + [obj.titleLabel, obj.countLabel] = this._makeNotificationDetailedSource(source, box); + else + [obj.titleLabel, obj.countLabel] = this._makeNotificationSource(source, box); + + box.visible = obj.visible && (source.unseenCount > 0); + } + + _sourceAdded(tray, source, initial) { + let obj = { + visible: source.policy.showInLockScreen, + detailed: this._shouldShowDetails(source), + sourceDestroyId: 0, + sourceCountChangedId: 0, + sourceTitleChangedId: 0, + sourceUpdatedId: 0, + sourceBox: null, + titleLabel: null, + countLabel: null, + }; + + obj.sourceBox = new St.BoxLayout({ + style_class: 'unlock-dialog-notification-source', + x_expand: true, + }); + this._showSource(source, obj, obj.sourceBox); + this._notificationBox.add_child(obj.sourceBox); + + obj.sourceCountChangedId = source.connect('notify::count', () => { + this._countChanged(source, obj); + }); + obj.sourceTitleChangedId = source.connect('notify::title', () => { + this._titleChanged(source, obj); + }); + obj.policyChangedId = source.policy.connect('notify', (policy, pspec) => { + if (pspec.name === 'show-in-lock-screen') + this._visibleChanged(source, obj); + else + this._detailedChanged(source, obj); + }); + obj.sourceDestroyId = source.connect('destroy', () => { + this._onSourceDestroy(source, obj); + }); + + this._sources.set(source, obj); + + if (!initial) { + // block scrollbars while animating, if they're not needed now + let boxHeight = this._notificationBox.height; + if (this._scrollView.height >= boxHeight) + this._scrollView.vscrollbar_policy = St.PolicyType.NEVER; + + let widget = obj.sourceBox; + let [, natHeight] = widget.get_preferred_height(-1); + widget.height = 0; + widget.ease({ + height: natHeight, + mode: Clutter.AnimationMode.EASE_OUT_QUAD, + duration: 250, + onComplete: () => { + this._scrollView.vscrollbar_policy = St.PolicyType.AUTOMATIC; + widget.set_height(-1); + }, + }); + + this._updateVisibility(); + if (obj.sourceBox.visible) + this.emit('wake-up-screen'); + } + } + + _titleChanged(source, obj) { + obj.titleLabel.text = source.title; + } + + _countChanged(source, obj) { + // A change in the number of notifications may change whether we show + // details. + let newDetailed = this._shouldShowDetails(source); + let oldDetailed = obj.detailed; + + obj.detailed = newDetailed; + + if (obj.detailed || oldDetailed !== newDetailed) { + // A new notification was pushed, or a previous notification was destroyed. + // Give up, and build the list again. + + obj.sourceBox.destroy_all_children(); + obj.titleLabel = obj.countLabel = null; + this._showSource(source, obj, obj.sourceBox); + } else { + let count = source.unseenCount; + obj.countLabel.text = this._makeNotificationCountText(count, source.isChat); + } + + obj.sourceBox.visible = obj.visible && (source.unseenCount > 0); + + this._updateVisibility(); + if (obj.sourceBox.visible) + this.emit('wake-up-screen'); + } + + _visibleChanged(source, obj) { + if (obj.visible === source.policy.showInLockScreen) + return; + + obj.visible = source.policy.showInLockScreen; + obj.sourceBox.visible = obj.visible && source.unseenCount > 0; + + this._updateVisibility(); + if (obj.sourceBox.visible) + this.emit('wake-up-screen'); + } + + _detailedChanged(source, obj) { + let newDetailed = this._shouldShowDetails(source); + if (obj.detailed === newDetailed) + return; + + obj.detailed = newDetailed; + + obj.sourceBox.destroy_all_children(); + obj.titleLabel = obj.countLabel = null; + this._showSource(source, obj, obj.sourceBox); + } + + _onSourceDestroy(source, obj) { + this._removeSource(source, obj); + this._updateVisibility(); + } + + _removeSource(source, obj) { + obj.sourceBox.destroy(); + obj.sourceBox = obj.titleLabel = obj.countLabel = null; + + source.disconnect(obj.sourceDestroyId); + source.disconnect(obj.sourceCountChangedId); + source.disconnect(obj.sourceTitleChangedId); + source.policy.disconnect(obj.policyChangedId); + + this._sources.delete(source); + } +}); + var Clock = GObject.registerClass( class UnlockDialogClock extends St.BoxLayout { _init() { @@ -112,6 +383,11 @@ var UnlockDialog = GObject.registerClass({ Main.ctrlAltTabManager.addGroup(this, _("Unlock Window"), 'dialog-password-symbolic'); + // Notifications + this._notificationsBox = new NotificationsBox(); + this._notificationsBox.connect('wake-up-screen', () => this.emit('wake-up-screen')); + this._promptBox.add_child(this._notificationsBox); + this._idleMonitor = Meta.IdleMonitor.get_core(); this._idleWatchId = this._idleMonitor.add_idle_watch(IDLE_TIMEOUT * 1000, this._escape.bind(this));