[gnome-weather] Continue implementing the new designs



commit 37b8766669fa6df08b6ffd22626d2caebc271e92
Author: Giovanni Campagna <gcampagna src gnome org>
Date:   Sat Feb 23 03:32:34 2013 +0100

    Continue implementing the new designs
    
    Add a sidebar that shows detailed forecasts for today (or for tomorrow,
    if today is too late)

 data/application.css |    7 +--
 src/forecast.js      |  161 +++++++++++++++++++++++++++++++++++++++++++++++++-
 src/main.js          |    3 +
 src/view.js          |   36 ++++++++++-
 4 files changed, 195 insertions(+), 12 deletions(-)
---
diff --git a/data/application.css b/data/application.css
index 96eb94b..bf3cc03 100644
--- a/data/application.css
+++ b/data/application.css
@@ -1,6 +1,6 @@
 #weather-page {
     padding: 12px;
-    /*background: white;*/
+    padding-right: 0;
 }
 
 #loading-label {
@@ -18,9 +18,6 @@
     font-size: small;
 }
 
-#conditions-image:dir(ltr) {
+#conditions-image {
     padding-right: 12px;
 }
-#conditions-image:dir(rtl) {
-    padding-left: 12px;
-}
\ No newline at end of file
diff --git a/src/forecast.js b/src/forecast.js
index 50cfba7..d0df482 100644
--- a/src/forecast.js
+++ b/src/forecast.js
@@ -21,7 +21,8 @@ const Util = imports.util;
 
 // In microseconds
 const ONE_DAY = 24*3600*1000*1000;
-const SIX_HOURS = 6*3600*1000*1000;
+const TWELVE_HOURS = 12*3600*1000*1000;
+const ONE_HOUR = 3600*1000*1000;
 
 const ForecastBox = new Lang.Class({
     Name: 'ForecastBox',
@@ -50,10 +51,10 @@ const ForecastBox = new Lang.Class({
             let info = infos[i];
 
             // only show forecasts if they're separated by
-            // at least 6 hours
+            // at least 12 hours
             let [ok, date] = info.get_value_update();
             let datetime = GLib.DateTime.new_from_unix_local(date);
-            if (current && datetime.difference(current) < SIX_HOURS)
+            if (current && datetime.difference(current) < TWELVE_HOURS)
                 continue;
 
             let text = '<b>' + this._getDate(datetime, subday) + '</b>';
@@ -126,3 +127,157 @@ const ForecastBox = new Lang.Class({
     }
 });
 
+const TodaySidebar = new Lang.Class({
+    Name: 'TodaySidebar',
+    Extends: Gtk.ScrolledWindow,
+
+    _init: function(params) {
+        params = Params.fill(params, { hscrollbar_policy: Gtk.PolicyType.NEVER });
+        this.parent(params);
+
+        this._grid = new Gtk.Grid({ column_spacing: 6,
+                                    row_spacing: 12,
+                                    margin_left: 12,
+                                    margin_right: 12 });
+        this.add(this._grid);
+
+        this._headline = new Gtk.Label({ use_markup: true,
+                                         xalign: 0.0 });
+        this._grid.attach(this._headline, 0, 0, 3, 1);
+
+        this._subline = new Gtk.Label({ margin_bottom: 4,
+                                        xalign: 0.0 });
+        this._grid.attach(this._subline, 0, 1, 3, 1);
+
+        this._hasMore = false;
+        this._moreButton = new Gtk.Button({ label: _("More..."),
+                                            margin_top: 4,
+                                            halign: Gtk.Align.END,
+                                            visible: true });
+        this._moreButton.connect('clicked', Lang.bind(this, this._showMore));
+
+        this._infoWidgets = [];
+        this._trimmedIndex = -1;
+    },
+
+    clear: function() {
+        this._infoWidgets.forEach(function(w) { w.destroy(); });
+        this._infoWidgets = [];
+
+        if (this._hasMore) {
+            this._grid.remove(this._moreButton);
+            this._hasMore = false;
+        }
+    },
+
+    // Ensure that infos are sufficiently spaced, and
+    // remove infos for the wrong day
+    _preprocess: function(now, infos) {
+        let ret = [];
+        let current = now;
+
+        for (let i = 0; i < infos.length; i++) {
+            let info = infos[i];
+
+            let [ok, date] = info.get_value_update();
+            let datetime = GLib.DateTime.new_from_unix_local(date);
+            if (datetime.difference(current) < ONE_HOUR)
+                continue;
+
+            if (!Util.arrayEqual(now.get_ymd(),
+                                 datetime.get_ymd()))
+                break;
+
+            ret.push(info);
+            current = datetime;
+        }
+
+        return ret;
+    },
+
+    update: function(infos) {
+        let [ok, v_first] = infos[0].get_value_update();
+
+        let now = GLib.DateTime.new_now_local();
+        let first = GLib.DateTime.new_from_unix_local(v_first);
+
+        let sameDay = Util.arrayEqual(now.get_ymd(),
+                                      first.get_ymd());
+
+        // Show today if we have it (sameDay), and if it's
+        // worth it, ie. it's not after 9pm (as the weather at
+        // point is unlikely to change)
+        if (sameDay && now.get_hour() < 21) {
+            this._headline.label = '<b>' + _("Forecast for Today") + '</b>';
+        } else {
+            this._headline.label = '<b>' + _("Forecast for Tomorrow") + '</b>';
+            now = now.add_days(1);
+        }
+
+        this._subline.label = now.format(_("%B %d"));
+
+        infos = this._preprocess(now, infos);
+        let i;
+
+        // Show at most 6 hours now, we'll show more with the ... button
+        for (i = 0; i < Math.min(infos.length, 6); i++) {
+            let info = infos[i];
+            this._addOneInfo(info, i + 2);
+        }
+
+        this._trimmedIndex = i;
+        if (this._trimmedIndex < infos.length) {
+            this._grid.attach(this._moreButton, 2, i+2, 1, 1);
+            this._hasMore = true;
+        }
+
+        this._infos = infos;
+    },
+
+    _addOneInfo: function(info, row) {
+        let [ok, date] = info.get_value_update();
+        let datetime = GLib.DateTime.new_from_unix_local(date);
+
+        let label = new Gtk.Label({ label: datetime.format(_("%k:%M")),
+                                    visible: true,
+                                    xalign: 1.0 });
+        label.get_style_context().add_class('dim-label');
+        this._grid.attach(label, 0, row, 1, 1);
+        this._infoWidgets.push(label);
+
+        let image = new Gtk.Image({ icon_name: info.get_symbolic_icon_name(),
+                                    icon_size: Gtk.IconSize.MENU,
+                                    use_fallback: true,
+                                    visible: true });
+        this._grid.attach(image, 1, row, 1, 1);
+        this._infoWidgets.push(image);
+
+        let conditions = new Gtk.Label({ label: this._getConditions(info),
+                                         visible: true,
+                                         xalign: 0.0 });
+        this._grid.attach(conditions, 2, row, 1, 1);
+        this._infoWidgets.push(conditions);
+    },
+
+    _getConditions: function(info) {
+        let conditions = info.get_conditions();
+        if (conditions == '-') // Not significant
+            conditions = info.get_sky();
+        return conditions;
+    },
+
+    _showMore: function() {
+        if (!this._hasMore) {
+            log('_showMore called when _hasMore is false, this should not happen');
+            return;
+        }
+
+        this._grid.remove(this._moreButton);
+        this._hasMore = false;
+
+        for (let i = this._trimmedIndex; i < this._infos.length; i++) {
+            let info = this._infos[i];
+            this._addOneInfo(info, i + 2);
+        }
+    },
+});
diff --git a/src/main.js b/src/main.js
index 1d73509..224cb05 100644
--- a/src/main.js
+++ b/src/main.js
@@ -46,6 +46,9 @@ const Application = new Lang.Class({
 
         Util.loadStyleSheet();
 
+        let settings = Gtk.Settings.get_for_screen(Gdk.Screen.get_default());
+        settings.gtk_application_prefer_dark_theme = true;
+
         this.world = GWeather.Location.new_world(false);
     },
 
diff --git a/src/view.js b/src/view.js
index 6c16efb..086e568 100644
--- a/src/view.js
+++ b/src/view.js
@@ -30,7 +30,7 @@ const WeatherWidget = new Lang.Class({
                                        name: 'weather-page' });
         this.parent(params);
 
-        let outerGrid = new Gtk.Grid({ orientation: Gtk.Orientation.VERTICAL });
+        let outerGrid = new Gtk.Grid();
 
         let alignment = new Gtk.Grid({ hexpand: true, vexpand: true,
                                        halign: Gtk.Align.CENTER,
@@ -55,21 +55,43 @@ const WeatherWidget = new Lang.Class({
 
         this._attribution = new Gtk.Label({ xalign: 0.0, wrap: true,
                                             name: 'attribution-label',
-                                            max_width_chars: 30,
                                             use_markup: true });
         innerGrid.attach(this._attribution, 1, 2, 1, 1);
 
         alignment.add(innerGrid);
-        outerGrid.add(alignment);
+        outerGrid.attach(alignment, 0, 0, 1, 1);
 
         this._forecasts = new Forecast.ForecastBox({ hexpand: true });
-        outerGrid.add(this._forecasts);
+        outerGrid.attach(this._forecasts, 0, 1, 1, 1);
+
+        this._revealButton = new Gd.HeaderSimpleButton({ symbolic_icon_name: 'go-previous-symbolic',
+                                                         halign: Gtk.Align.CENTER,
+                                                         valign: Gtk.Align.CENTER });
+        outerGrid.attach(this._revealButton, 1, 0, 1, 2);
+
+        this._today = new Forecast.TodaySidebar({ vexpand: true,
+                                                  name: 'today-sidebar' });
+        this._revealer = new Gd.Revealer({ child: this._today,
+                                           reveal_child: false,
+                                           orientation: Gtk.Orientation.VERTICAL });
+        outerGrid.attach(this._revealer, 2, 0, 1, 2);
+
+        this._revealButton.connect('clicked', Lang.bind(this, function() {
+            if (this._revealer.reveal_child) {
+                this._revealer.reveal_child = false;
+                this._revealButton.symbolic_icon_name = 'go-previous-symbolic';
+            } else {
+                this._revealer.reveal_child = true;
+                this._revealButton.symbolic_icon_name = 'go-next-symbolic';
+            }
+        }));
 
         this.add(outerGrid);
     },
 
     clear: function() {
         this._forecasts.clear();
+        this._today.clear();
     },
 
     update: function(info) {
@@ -93,8 +115,14 @@ const WeatherWidget = new Lang.Class({
         if (forecasts.length > 0) {
             this._forecasts.update(forecasts);
             this._forecasts.show();
+
+            this._today.update(forecasts);
+            this._revealButton.show();
+            this._revealer.show();
         } else {
             this._forecasts.hide();
+            this._revealButton.hide();
+            this._revealer.hide();
         }
     }
 });


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