[gnome-shell/T27795: 104/138] discoveryFeed: Add Discovery Feed Button



commit 154044583803ab55442937f0d1c345bd255ae137
Author: Mario Sanchez Prada <mario endlessm com>
Date:   Wed Feb 14 16:01:25 2018 +0000

    discoveryFeed: Add Discovery Feed Button
    
    Also, make sure the feed is disabled on < 1024 screen widths,
    and that it responds to resolution changes.
    
    Finally, enable the discovery feed for English and Indonesian only,
    as we don't have enough content for it in other languages.
    
    Last, this includes the latest design changes implemented for
    EOS 3.3 squashed in. Please check the eos3.3 branch for details.
    
    2019-09-24: squash da3fa53ea "discoveryFeed: Tell the Discovery
                    Feed when its window is fully hidden"
    
    https://phabricator.endlessm.com/T17773
    https://phabricator.endlessm.com/T17840
    https://phabricator.endlessm.com/T18017
    https://phabricator.endlessm.com/T18546
    https://phabricator.endlessm.com/T18850
    https://phabricator.endlessm.com/T19354
    https://phabricator.endlessm.com/T20602

 .../dbus-interfaces/com.endlessm.DiscoveryFeed.xml |   1 +
 data/gnome-shell-theme.gresource.xml               |   4 +
 data/org.gnome.shell.gschema.xml.in                |   9 ++
 data/theme/discovery-feed-bar-hover.png            | Bin 0 -> 774 bytes
 data/theme/discovery-feed-bar-normal.png           | Bin 0 -> 758 bytes
 data/theme/discovery-feed-tile-hover.png           | Bin 0 -> 1684 bytes
 data/theme/discovery-feed-tile-normal.png          | Bin 0 -> 1642 bytes
 data/theme/gnome-shell-sass/_endless.scss          |  22 ++++
 js/js-resources.gresource.xml                      |   1 +
 js/ui/components/discoveryFeed.js                  |   4 +
 js/ui/discoveryFeedButton.js                       | 117 +++++++++++++++++++++
 js/ui/viewSelector.js                              |  48 +++++++--
 js/ui/windowManager.js                             |   5 +
 13 files changed, 204 insertions(+), 7 deletions(-)
---
diff --git a/data/dbus-interfaces/com.endlessm.DiscoveryFeed.xml 
b/data/dbus-interfaces/com.endlessm.DiscoveryFeed.xml
index 2df0c9756c..6b6d4c5ac4 100644
--- a/data/dbus-interfaces/com.endlessm.DiscoveryFeed.xml
+++ b/data/dbus-interfaces/com.endlessm.DiscoveryFeed.xml
@@ -1,5 +1,6 @@
 <node>
   <interface name="com.endlessm.DiscoveryFeed">
+    <method name="notifyHideAnimationCompleted" />
     <method name="show">
       <arg type="u" direction="in" name="timestamp"/>
     </method>
diff --git a/data/gnome-shell-theme.gresource.xml b/data/gnome-shell-theme.gresource.xml
index 91ce41da77..2eff7a8f92 100644
--- a/data/gnome-shell-theme.gresource.xml
+++ b/data/gnome-shell-theme.gresource.xml
@@ -38,6 +38,10 @@
     <file>corner-ripple-br.png</file>
     <file>corner-ripple-tl.png</file>
     <file>corner-ripple-tr.png</file>
+    <file>discovery-feed-bar-normal.png</file>
+    <file>discovery-feed-bar-hover.png</file>
+    <file>discovery-feed-tile-normal.png</file>
+    <file>discovery-feed-tile-hover.png</file>
     <file>endless-button-symbolic.svg</file>
     <file>endless-help-symbolic.svg</file>
     <file>hot-corner-symbolic.svg</file>
diff --git a/data/org.gnome.shell.gschema.xml.in b/data/org.gnome.shell.gschema.xml.in
index 6a98124781..aab188b446 100644
--- a/data/org.gnome.shell.gschema.xml.in
+++ b/data/org.gnome.shell.gschema.xml.in
@@ -207,6 +207,15 @@
         This key specifies the exact order of the icons shown in the applications launcher view.
       </description>
     </key>
+    <key name="discovery-feed-languages" type="as">
+      <default>['en', 'id']</default>
+      <summary>
+        Languages for which the discovery feed feature is enabled.
+      </summary>
+      <description>
+        If the system language matches any of these languages, the discovery feed will be enabled. You will 
need to restart the shell for changes to this setting to take effect.
+      </description>
+    </key>
     <child name="keybindings" schema="org.gnome.shell.keybindings"/>
   </schema>
 
diff --git a/data/theme/discovery-feed-bar-hover.png b/data/theme/discovery-feed-bar-hover.png
new file mode 100644
index 0000000000..22e0358701
Binary files /dev/null and b/data/theme/discovery-feed-bar-hover.png differ
diff --git a/data/theme/discovery-feed-bar-normal.png b/data/theme/discovery-feed-bar-normal.png
new file mode 100644
index 0000000000..0b0a35d443
Binary files /dev/null and b/data/theme/discovery-feed-bar-normal.png differ
diff --git a/data/theme/discovery-feed-tile-hover.png b/data/theme/discovery-feed-tile-hover.png
new file mode 100644
index 0000000000..20fb3aa152
Binary files /dev/null and b/data/theme/discovery-feed-tile-hover.png differ
diff --git a/data/theme/discovery-feed-tile-normal.png b/data/theme/discovery-feed-tile-normal.png
new file mode 100644
index 0000000000..d30afe3cff
Binary files /dev/null and b/data/theme/discovery-feed-tile-normal.png differ
diff --git a/data/theme/gnome-shell-sass/_endless.scss b/data/theme/gnome-shell-sass/_endless.scss
index 9e416e85a7..4c7c5d5756 100644
--- a/data/theme/gnome-shell-sass/_endless.scss
+++ b/data/theme/gnome-shell-sass/_endless.scss
@@ -449,3 +449,25 @@ popup-separator-menu-item {
         padding-right: 0px;
     }
 }
+
+// Discovery Feed
+
+.discovery-feed-bar-icon {
+    background-image: url("resource:///org/gnome/shell/theme/discovery-feed-bar-normal.png");
+    height: 18px;
+    width: 1004px;
+
+    &:highlighted {
+        background-image: url("resource:///org/gnome/shell/theme/discovery-feed-bar-hover.png");
+    }
+}
+
+.discovery-feed-tile-icon {
+    background-image: url("resource:///org/gnome/shell/theme/discovery-feed-tile-normal.png");
+    height: 27px;
+    width: 62px;
+
+    &:highlighted {
+        background-image: url("resource:///org/gnome/shell/theme/discovery-feed-tile-hover.png");
+    }
+}
diff --git a/js/js-resources.gresource.xml b/js/js-resources.gresource.xml
index f669a2ffb4..3c404e1c38 100644
--- a/js/js-resources.gresource.xml
+++ b/js/js-resources.gresource.xml
@@ -145,6 +145,7 @@
     <file>ui/components/appStore.js</file>
     <file>ui/components/discoveryFeed.js</file>
     <file>ui/components/trayArea.js</file>
+    <file>ui/discoveryFeedButton.js</file>
     <file>ui/endlessButton.js</file>
     <file>ui/forceAppExitDialog.js</file>
     <file>ui/hotCorner.js</file>
diff --git a/js/ui/components/discoveryFeed.js b/js/ui/components/discoveryFeed.js
index b37e864af4..c114c16c38 100644
--- a/js/ui/components/discoveryFeed.js
+++ b/js/ui/components/discoveryFeed.js
@@ -28,6 +28,10 @@ class DiscoveryFeed extends SideComponent.SideComponent {
         Main.discoveryFeed = null;
     }
 
+    notifyHideAnimationCompleted() {
+        this.proxy.notifyHideAnimationCompletedRemote();
+    }
+
     callShow(timestamp) {
         this.proxy.showRemote(timestamp);
     }
diff --git a/js/ui/discoveryFeedButton.js b/js/ui/discoveryFeedButton.js
new file mode 100644
index 0000000000..6fd6235fc7
--- /dev/null
+++ b/js/ui/discoveryFeedButton.js
@@ -0,0 +1,117 @@
+// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
+
+const { Clutter, Gio, GLib, GObject, St } = imports.gi;
+
+const Main = imports.ui.main;
+
+function maybeCreateInactiveButton() {
+    if (_checkIfDiscoveryFeedEnabled()) {
+        let discoveryFeed = new DiscoveryFeedButton();
+        discoveryFeed.reactive = false;
+        return discoveryFeed;
+    }
+
+    return null;
+}
+
+const DISCOVERY_FEED_PRIMARY_MONITOR_WIDTH_THRESHOLD = 1024;
+
+function _primaryMonitorWidthPassesThreshold() {
+    return Main.layoutManager.primaryMonitor.width >= DISCOVERY_FEED_PRIMARY_MONITOR_WIDTH_THRESHOLD;
+}
+
+function _checkIfDiscoveryFeedEnabled() {
+    let supportedLanguages = global.settings.get_value('discovery-feed-languages').deep_unpack();
+    let systemLanguages = GLib.get_language_names();
+
+    let isEnabled = supportedLanguages.some(lang => systemLanguages.indexOf(lang) !== -1);
+
+    return isEnabled;
+}
+
+function maybeCreateButton() {
+    if (_checkIfDiscoveryFeedEnabled())
+        return new DiscoveryFeedButton();
+
+    return null;
+}
+
+/** DiscoveryFeedButton:
+ *
+ * This class handles the button to launch the discovery feed application
+ */
+var DiscoveryFeedButton = GObject.registerClass(
+class DiscoveryFeedButton extends St.BoxLayout {
+    _init() {
+        super._init({
+            vertical: true,
+            visible: _primaryMonitorWidthPassesThreshold(),
+        });
+
+        this._bar = new St.Button({
+            name: 'discovery-feed-bar',
+            child: new St.Icon({ style_class: 'discovery-feed-bar-icon' }),
+            style_class: 'discovery-feed-bar',
+        });
+        this.add_child(this._bar);
+
+        this._tile = new St.Button({
+            name: 'discovery-feed-tile',
+            child: new St.Icon({ style_class: 'discovery-feed-tile-icon' }),
+            style_class: 'discovery-feed-tile',
+        });
+        this.add(this._tile, {
+            x_fill: false,
+            x_align: St.Align.MIDDLE,
+            expand: true,
+        });
+
+        this._bar.connect('clicked', () => {
+            Main.discoveryFeed.show(global.get_current_time());
+        });
+        this._tile.connect('clicked', () => {
+            Main.discoveryFeed.show(global.get_current_time());
+        });
+
+        this._bar.connect('notify::hover', this._onHoverChanged.bind(this));
+        this._tile.connect('notify::hover', this._onHoverChanged.bind(this));
+
+        Main.layoutManager.connect('monitors-changed', () => {
+            this.visible = _primaryMonitorWidthPassesThreshold();
+        });
+    }
+
+    _onHoverChanged(actor) {
+        if (actor.get_hover()) {
+            this._bar.child.add_style_pseudo_class('highlighted');
+            this._tile.child.add_style_pseudo_class('highlighted');
+        } else {
+            this._bar.child.remove_style_pseudo_class('highlighted');
+            this._tile.child.remove_style_pseudo_class('highlighted');
+        }
+     }
+
+    changeVisbilityState(value) {
+        // Helper function to ensure that visibility is set correctly,
+        // consumers of this button should use this function as opposed
+        // to mutating 'visible' directly, since it prevents the
+        // button from appearing in cases where it should not.
+        this.visible = value && _primaryMonitorWidthPassesThreshold();
+    }
+});
+
+function determineAllocationWithinBox(discoveryFeedButton, box, availWidth) {
+    // If we would not show the feed button because the monitor
+    // is too small, just return box directly
+    if (!_primaryMonitorWidthPassesThreshold())
+      return box;
+
+    let discoveryFeedButtonHeight = discoveryFeedButton.get_preferred_height(availWidth)[1];
+    let discoveryFeedButtonBox = box.copy();
+    let x1 = (availWidth - discoveryFeedButton.get_width()) * 0.5;
+    discoveryFeedButtonBox.y1 = 0;
+    discoveryFeedButtonBox.y2 = discoveryFeedButtonBox.y1 + discoveryFeedButtonHeight;
+    discoveryFeedButtonBox.x1 = x1;
+    discoveryFeedButtonBox.x2 = x1 + discoveryFeedButton.get_width();
+    return discoveryFeedButtonBox;
+}
diff --git a/js/ui/viewSelector.js b/js/ui/viewSelector.js
index 95db981199..ab46649d69 100644
--- a/js/ui/viewSelector.js
+++ b/js/ui/viewSelector.js
@@ -6,6 +6,7 @@ const { EosMetrics, Clutter, Gio,
 const Signals = imports.signals;
 
 const AppDisplay = imports.ui.appDisplay;
+const DiscoveryFeedButton = imports.ui.discoveryFeedButton;
 const LayoutManager = imports.ui.layout;
 const Main = imports.ui.main;
 const Monitor = imports.ui.monitor;
@@ -161,10 +162,11 @@ var ViewsDisplayLayout = GObject.registerClass({
             0, 1, 0)
     },
 }, class ViewsDisplayLayout extends Clutter.BinLayout {
-    _init(entry, gridContainerActor, searchResultsActor) {
+    _init(entry, discoveryFeedButton, gridContainerActor, searchResultsActor) {
         super._init();
 
         this._entry = entry;
+        this._discoveryFeedButton = discoveryFeedButton;
         this._gridContainerActor = gridContainerActor;
         this._searchResultsActor = searchResultsActor;
 
@@ -219,6 +221,12 @@ var ViewsDisplayLayout = GObject.registerClass({
         entryBox.y1 = this._heightAboveEntry + entryTopMargin;
         entryBox.y2 = entryBox.y1 + entryHeight;
 
+        let discoveryFeedButtonBox = allocation.copy();
+        if (this._discoveryFeedButton)
+            discoveryFeedButtonBox = 
DiscoveryFeedButton.determineAllocationWithinBox(this._discoveryFeedButton,
+                                                                                      allocation,
+                                                                                      availWidth);
+
         let gridContainerBox = allocation.copy();
         // The grid container box should have the dimensions of this container but start
         // after the search entry and according to the calculated xplacement policies
@@ -235,18 +243,24 @@ var ViewsDisplayLayout = GObject.registerClass({
             searchResultsBox.y2 = searchResultsBox.y1 + searchResultsHeight;
         }
 
-        return [entryBox, gridContainerBox, searchResultsBox];
+        return [entryBox, discoveryFeedButtonBox, gridContainerBox, searchResultsBox];
     }
 
     vfunc_allocate(actor, box, flags) {
-        let [entryBox, gridContainerBox, searchResultsBox] = this._computeChildrenAllocation(box);
+        let [entryBox, discoveryFeedButtonBox, gridContainerBox, searchResultsBox] =
+            this._computeChildrenAllocation(box);
 
         // We want to emit the signal BEFORE any allocation has happened since the
         // icon grid will need to precompute certain values before being able to
         // report a sensible preferred height for the specified width.
-        this.emit(     'grid-available-size-changed', box.x2 - box.x1, box.y2 - box.y1);
+
+        this.emit('grid-available-size-changed',
+                  gridContainerBox.x2 - gridContainerBox.x1,
+                  gridContainerBox.y2 - gridContainerBox.y1);
 
         this._entry.allocate(entryBox, flags);
+        if (this._discoveryFeedButton)
+            this._discoveryFeedButton.allocate(discoveryFeedButtonBox, flags);
         this._gridContainerActor.allocate(gridContainerBox, flags);
         if (this._searchResultsActor)
             this._searchResultsActor.allocate(searchResultsBox, flags);
@@ -262,6 +276,11 @@ var ViewsDisplayLayout = GObject.registerClass({
         this._gridContainerActor.opacity = (1 - v) * 255;
         this._searchResultsActor.opacity = v * 255;
 
+        if (this._discoveryFeedButton) {
+            this._discoveryFeedButton.changeVisbilityState(v != 1);
+            this._discoveryFeedButton.opacity = (1 - v) * 255;
+        }
+
         let entryTranslation = - this._heightAboveEntry * v;
         this._entry.translation_y = entryTranslation;
 
@@ -278,8 +297,9 @@ var ViewsDisplayLayout = GObject.registerClass({
 
 var ViewsDisplayContainer = GObject.registerClass(
 class ViewsDisplayContainer extends St.Widget {
-    _init(entry, gridContainer, searchResults) {
+    _init(entry, discoveryFeedButton, gridContainer, searchResults) {
         this._entry = entry;
+        this._discoveryFeedButton = discoveryFeedButton;
         this._gridContainer = gridContainer;
         this._searchResults = searchResults;
 
@@ -287,6 +307,7 @@ class ViewsDisplayContainer extends St.Widget {
 
         let layoutManager = new ViewsDisplayLayout(
             entry,
+            discoveryFeedButton,
             gridContainer.actor,
             searchResults.actor);
         super._init({
@@ -298,6 +319,8 @@ class ViewsDisplayContainer extends St.Widget {
         layoutManager.connect('grid-available-size-changed', this._onGridAvailableSizeChanged.bind(this));
 
         this.add_child(this._entry);
+        if (this._discoveryFeedButton)
+            this.add_child(this._discoveryFeedButton);
         this.add_child(this._gridContainer.actor);
         this.add_child(this._searchResults.actor);
     }
@@ -378,7 +401,10 @@ var ViewsDisplay = class {
         Main.overview.addAction(clickAction, false);
         this._searchResults.actor.bind_property('mapped', clickAction, 'enabled', 
GObject.BindingFlags.SYNC_CREATE);
 
-        this.actor = new ViewsDisplayContainer(this.entry, this._appDisplay, this._searchResults);
+        this.actor = new ViewsDisplayContainer(this.entry,
+                                               DiscoveryFeedButton.maybeCreateButton(),
+                                               this._appDisplay,
+                                               this._searchResults);
     }
 
     _recordDesktopSearchMetric(query, searchProvider) {
@@ -499,7 +525,13 @@ class ViewsClone extends St.Widget {
         });
         appGridContainer.reactive = false;
 
-        let layoutManager = new ViewsDisplayLayout(entry, appGridContainer, null);
+        let discoveryFeedButton = DiscoveryFeedButton.maybeCreateInactiveButton();
+        let layoutManager = new ViewsDisplayLayout(
+            entry,
+            discoveryFeedButton,
+            appGridContainer,
+            null
+        );
         super._init({
             layout_manager: layoutManager,
             x_expand: true,
@@ -514,6 +546,8 @@ class ViewsClone extends St.Widget {
         let cloneAdjustment = appGridContainer.scrollView.vscroll.adjustment;
         originalAdjustment.bind_property('value', cloneAdjustment, 'value', 
GObject.BindingFlags.SYNC_CREATE);
 
+        if (discoveryFeedButton)
+            this.add_child(discoveryFeedButton);
         this.add_child(entry);
         this.add_child(appGridContainer);
 
diff --git a/js/ui/windowManager.js b/js/ui/windowManager.js
index 11564552b1..f74284fed8 100644
--- a/js/ui/windowManager.js
+++ b/js/ui/windowManager.js
@@ -2250,6 +2250,11 @@ var WindowManager = class {
                     this._showOtherWindows(actor, false);
             }
 
+            /* If this is the Discovery Feed, notify it that it has
+             * finished closing now */
+            if (SideComponent.isDiscoveryFeedWindow(actor.meta_window))
+                Main.discoveryFeed.notifyHideAnimationCompleted();
+
             shellwm.completed_destroy(actor);
         }
     }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]