[gnome-weather/wip/new-ui: 1/2] world-view, libgd removal and city-view changes
- From: Giovanni Campagna <gcampagna src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-weather/wip/new-ui: 1/2] world-view, libgd removal and city-view changes
- Date: Wed, 30 Jul 2014 14:02:39 +0000 (UTC)
commit fc9b938a67f29d4693739a0c10d7dcb678e69a00
Author: Saurabh <srp201201051 gmail com>
Date: Mon Jul 28 15:17:34 2014 +0530
world-view, libgd removal and city-view changes
https://bugzilla.gnome.org/show_bug.cgi?id=733236
Makefile.am | 4 +-
autogen.sh | 2 -
configure.ac | 9 -
data/application.css | 4 +
data/city.ui | 181 +++++--
data/new-location-dialog.ui | 63 ---
...rg.gnome.Weather.Application.data.gresource.xml | 2 +-
data/org.gnome.Weather.Application.gschema.xml | 8 +
data/places-popover.ui | 284 +++++++++++
data/window.ui | 159 +------
libgd | 1 -
src/app/city.js | 127 ++++--
src/app/currentLocationController.js | 68 ++--
src/app/forecast.js | 338 ++-----------
src/app/main.js | 47 +-
src/app/weeklyForecast.js | 141 +++++
src/app/window.js | 208 +-------
src/misc/util.js | 32 +-
...org.gnome.Weather.Application.src.gresource.xml | 1 +
src/shared/world.js | 538 ++++++++++----------
20 files changed, 1089 insertions(+), 1128 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index 0be1a60..2738258 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,7 +1,7 @@
-ACLOCAL_AMFLAGS = -I m4 -I libgd ${ACLOCAL_FLAGS}
+ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
DISTCHECK_CONFIGURE_FLAGS = --disable-dogtail
-SUBDIRS = po data libgd src tests
+SUBDIRS = po data src tests
MAINTAINERCLEANFILES = \
$(srcdir)/INSTALL \
diff --git a/autogen.sh b/autogen.sh
index a7a6ed9..fdf163f 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -4,7 +4,6 @@
srcdir=`dirname $0`
test -z "$srcdir" && srcdir=.
-ACLOCAL_FLAGS="-I libgd ${ACLOCAL_FLAGS}"
PKG_NAME="gnome-weather"
test -f $srcdir/configure.ac || {
@@ -21,6 +20,5 @@ which gnome-autogen.sh || {
(cd "$srcdir" ;
test -d m4 || mkdir m4/ ;
-git submodule update --init --recursive ;
)
. gnome-autogen.sh
diff --git a/configure.ac b/configure.ac
index e57bb87..c8638c4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -23,8 +23,6 @@ AC_PROG_CC
AM_PROG_CC_C_O
LT_INIT([disable-static])
-LIBGD_INIT([main-view gir])
-
PKG_PROG_PKG_CONFIG([0.22])
APPSTREAM_XML
@@ -63,12 +61,6 @@ if test x$enable_coverage = xyes; then
if test x$LCOV = x || test x$GENHTML = x; then
AC_MSG_ERROR([lcov and genhtml are required for --enable-coverage])
fi
-
- # only enable these if we ever want code coverage for libgd
- # (which we don't)
- #CFLAGS="$CFLAGS -g -O0 --coverage"
- #CXXFLAGS="$CXXFLAGS -g -O0 --coverage"
- #LIBS="$LIBS -lgcov"
fi
AM_CONDITIONAL([ENABLE_COVERAGE], [test x$enable_coverage = xyes])
@@ -81,7 +73,6 @@ AC_CONFIG_FILES([
Makefile
data/Makefile
data/icons/Makefile
- libgd/Makefile
src/Makefile
tests/Makefile
po/Makefile.in
diff --git a/data/application.css b/data/application.css
index 0886843..62938dd 100644
--- a/data/application.css
+++ b/data/application.css
@@ -81,6 +81,10 @@
padding: 12px;
}
+#weekly-forecast-frame {
+ background-color: rgba(0, 0, 0, 0.5);
+}
+
.content-view.cell {
font-weight: bold;
}
diff --git a/data/city.ui b/data/city.ui
index 6a48271..cbef771 100644
--- a/data/city.ui
+++ b/data/city.ui
@@ -24,6 +24,9 @@
<property name="valign">center</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
+ <property name="margin_left">50</property>
+ <property name="margin_right">20</property>
+ <property name="row_spacing">11</property>
<child>
<object class="GtkGrid" id="inner-grid">
<property name="name">conditions-grid</property>
@@ -85,8 +88,130 @@
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
- <property name="width">1</property>
- <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkGrid" id="stack-grid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkStackSwitcher" id="day-stack-switcher">
+ <property name="visible">True</property>
+ <property name="stack">day-stack</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkStack" id="day-stack">
+ <property name="visible">False</property>
+ <property name="no_show_all">True</property>
+ <child>
+ <object class="GtkButton" id="today-Button">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="name">today-button</property>
+ <property name="title">Today</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="tomorrow-button">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="name">tomorrow-button</property>
+ <property name="title">Tomorrow</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkGrid" id="parent-grid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkScrolledWindow" id="forecast-scrolled-window">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="vscrollbar_policy">never</property>
+ <property name="min_content_width">360</property>
+ <child>
+ <object class="GtkViewport" id="forecast-viewport">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hscroll_policy">natural</property>
+ <property name="vscroll_policy">natural</property>
+ <child>
+ <object class="GtkGrid" id="forecast-grid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">center</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="left-button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="valign">center</property>
+ <child>
+ <object class="GtkImage" id="left-image">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="stock">gtk-go-back</property>
+ <property name="icon_size">1</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="right-button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="valign">center</property>
+ <child>
+ <object class="GtkImage" id="right-image">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="stock">gtk-go-forward</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
</packing>
</child>
</object>
@@ -101,6 +226,8 @@
<object class="GtkGrid" id="time-grid">
<property name="visible">True</property>
<property name="can_focus">False</property>
+ <property name="halign">end</property>
+ <property name="margin_right">20</property>
<child>
<object class="GtkImage" id="clock-image">
<property name="visible">True</property>
@@ -143,55 +270,5 @@
</child>
</object>
</child>
- <child type="overlay">
- <object class="GtkGrid" id="revealer-grid">
- <property name="visible">True</property>
- <property name="halign">end</property>
- <child>
- <object class="GtkButton" id="reveal-button">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="halign">center</property>
- <property name="valign">center</property>
- <property name="margin_right">20</property>
- <style>
- <class name="image-button"/>
- <class name="osd"/>
- </style>
- <child internal-child="accessible">
- <object class="AtkObject" id="reveal-button-a11y">
- <property name="accessible-name" translatable="yes">Detailed forecast</property>
- <property name="accessible-role">7</property><!-- check_box -->
- </object>
- </child>
- <child>
- <object class="GtkImage" id="reveal-button-image">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="icon-size">1</property>
- </object>
- </child>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">0</property>
- <property name="width">1</property>
- <property name="height">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkRevealer" id="revealer">
- <property name="reveal-child">false</property>
- <property name="transition-type">slide-left</property>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">0</property>
- <property name="width">1</property>
- <property name="height">1</property>
- </packing>
- </child>
- </object>
- </child>
</object>
</interface>
diff --git a/data/org.gnome.Weather.Application.data.gresource.xml
b/data/org.gnome.Weather.Application.data.gresource.xml
index d0ae379..22d1ea4 100644
--- a/data/org.gnome.Weather.Application.data.gresource.xml
+++ b/data/org.gnome.Weather.Application.data.gresource.xml
@@ -3,8 +3,8 @@
<gresource prefix="/org/gnome/Weather/Application">
<file preprocess="xml-stripblanks">app-menu.ui</file>
<file preprocess="xml-stripblanks">window.ui</file>
- <file preprocess="xml-stripblanks">new-location-dialog.ui</file>
<file preprocess="xml-stripblanks">city.ui</file>
+ <file preprocess="xml-stripblanks">places-popover.ui</file>
<file>application.css</file>
<file>weather-clear.jpg</file>
<file>weather-clear-night.jpg</file>
diff --git a/data/org.gnome.Weather.Application.gschema.xml b/data/org.gnome.Weather.Application.gschema.xml
index 76677e4..aaf9d79 100644
--- a/data/org.gnome.Weather.Application.gschema.xml
+++ b/data/org.gnome.Weather.Application.gschema.xml
@@ -8,5 +8,13 @@
GVariant returned by gweather_location_serialize().
</description>
</key>
+ <key name="automatic-location" type="b">
+ <default>true</default>
+ <summary>Automatic location</summary>
+ <description>
+ The automatic location is the value of automatic-location switch which decides whether
+ to fetch current location or not.
+ </description>
+ </key>
</schema>
</schemalist>
diff --git a/data/places-popover.ui b/data/places-popover.ui
new file mode 100644
index 0000000..1a084f2
--- /dev/null
+++ b/data/places-popover.ui
@@ -0,0 +1,284 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.16.1 -->
+<interface>
+ <requires lib="gtk+" version="3.0"/>
+ <object class="GtkGrid" id="popover-grid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="row_spacing">10</property>
+ <property name="margin">12</property>
+ <property name="vexpand">False</property>
+ <child>
+ <object class="GWeatherLocationEntry" id="location-entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkStack" id="auto-location-stack">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="vexpand">False</property>
+ <property name="homogeneous">False</property>
+ <child>
+ <object class="GtkGrid" id="auto-location-grid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">horizontal</property>
+ <property name="column_homogeneous">True</property>
+ <property name="margin_top">6</property>
+ <property name="margin_bottom">6</property>
+ <property name="vexpand">False</property>
+ <child>
+ <object class="GtkLabel" id="auto-location-label">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label">Automatic location</property>
+ <property name="halign">start</property>
+ <property name="vexpand">False</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSwitch" id="auto-location-switch">
+ <property name="visible">True</property>
+ <property name="halign">end</property>
+ <property name="vexpand">False</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="name">auto-location-switch-grid</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="locating-label">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label">Locating....</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="vexpand">False</property>
+ </object>
+ <packing>
+ <property name="name">locating-label</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkStack" id="popover-stack">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="vexpand">False</property>
+ <property name="homogeneous">False</property>
+ <child>
+ <object class="GtkGrid" id="search-grid">
+ <property name="visible">True</property>
+ <property name="name">search-city-grid</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="margin_top">25</property>
+ <property name="margin_bottom">25</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="row_homogeneous">True</property>
+ <property name="vexpand">False</property>
+ <child>
+ <object class="GtkImage" id="search-image">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">edit-find-symbolic</property>
+ <property name="icon_size">6</property>
+ <property name="use_fallback">True</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="vexpand">False</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="search-label">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label">Search for a city</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="vexpand">False</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="name">search-grid</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkGrid" id="locations-grid">
+ <property name="visible">True</property>
+ <property name="name">locations-grid</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="row_spacing">10</property>
+ <property name="vexpand">False</property>
+ <child>
+ <object class="GtkLabel" id="recently-viewed-label">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label">Viewed recently</property>
+ <property name="halign">start</property>
+ <property name="vexpand">False</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkListBox" id="locations-list-box">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">False</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="name">locations-grid</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">2</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ </object>
+ <object class="GtkGrid" id="initial-grid">
+ <property name="visible">True</property>
+ <property name="name">initial-grid</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="margin_top">25</property>
+ <property name="margin_bottom">25</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="row_homogeneous">True</property>
+ <property name="vexpand">False</property>
+ <child>
+ <object class="GtkImage" id="mark-location-image">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">mark-location-symbolic</property>
+ <property name="icon_size">6</property>
+ <property name="use_fallback">True</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="vexpand">False</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="search-location-label">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label">Search for a location</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="vexpand">False</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="search-nereby-location-label">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label">To see weather information, enter the name of a city.</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="vexpand">False</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GWeatherLocationEntry" id="initial-grid-location-entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">3</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/data/window.ui b/data/window.ui
index 5b1352a..e48d9b3 100644
--- a/data/window.ui
+++ b/data/window.ui
@@ -1,68 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 3.10 -->
- <menu id="selection-menu">
- <section>
- <item>
- <attribute name="action">win.select-all</attribute>
- <attribute name="label" translatable="yes">Select All</attribute>
- <attribute name="accel"><Primary>a</attribute>
- </item>
- <item>
- <attribute name="action">win.select-none</attribute>
- <attribute name="label" translatable="yes">Select None</attribute>
- </item>
- </section>
- </menu>
- <object class="GtkMenuButton" id="selection-menu-button">
- <property name="menu-model">selection-menu</property>
- <property name="visible">True</property>
- <property name="can-focus">True</property>
- <child>
- <object class="GtkBox" id="selection-menu-button-box">
- <property name="visible">True</property>
- <property name="can-focus">False</property>
- <property name="orientation">horizontal</property>
- <property name="spacing">6</property>
- <child>
- <object class="GtkLabel" id="selection-menu-button-label">
- <property name="visible">True</property>
- <property name="can-focus">False</property>
- <property name="label" translatable="yes">Click on locations to select them</property>
- </object>
- <packing>
- <property name="pack-type">start</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkArrow" id="selection-menu-button-arrow">
- <property name="visible">True</property>
- <property name="can-focus">False</property>
- <property name="arrow-type">down</property>
- <property name="shadow-type">none</property>
- </object>
- <packing>
- <property name="pack-type">start</property>
- <property name="position">1</property>
- </packing>
- </child>
- </object>
- </child>
- <style>
- <class name="selection-menu"/>
- </style>
- </object>
<object class="GtkHeaderBar" id="header-bar">
<property name="visible">True</property>
<property name="vexpand">False</property>
<property name="show-close-button">True</property>
<child>
- <object class="GtkButton" id="new-button">
+ <object class="GtkMenuButton" id="places-button">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="label" translatable="yes">New</property>
- <property name="action-name">win.new-location</property>
+ <property name="label" translatable="yes">Places</property>
+ <property name="use-popover">True</property>
<property name="valign">center</property>
<style>
<class name="text-button"/>
@@ -73,78 +21,6 @@
</packing>
</child>
<child>
- <object class="GtkButton" id="world-button">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="action-name">win.go-world</property>
- <property name="valign">center</property>
- <style>
- <class name="image-button"/>
- </style>
- <child internal-child="accessible">
- <object class="AtkObject" id="world-button-a11y">
- <property name="accessible-name" translatable="yes">Back</property>
- </object>
- </child>
- <child>
- <object class="GtkImage" id="world-button-image">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="icon-size">1</property>
- <property name="icon-name">go-previous-symbolic</property>
- </object>
- </child>
- </object>
- <packing>
- <property name="pack_type">start</property>
- </packing>
- </child>
- <child>
- <object class="GtkButton" id="select-button">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="action-name">win.selection-mode</property>
- <property name="action-target">true</property>
- <property name="valign">center</property>
- <style>
- <class name="image-button"/>
- </style>
- <child internal-child="accessible">
- <object class="AtkObject" id="select-button-a11y">
- <property name="accessible-name" translatable="yes">Select</property>
- </object>
- </child>
- <child>
- <object class="GtkImage" id="select-button-image">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="icon-name">object-select-symbolic</property>
- <property name="icon-size">1</property>
- </object>
- </child>
- </object>
- <packing>
- <property name="pack_type">end</property>
- </packing>
- </child>
- <child>
- <object class="GtkButton" id="done-button">
- <property name="visible">True</property>
- <property name="no_show_all">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Cancel</property>
- <property name="valign">center</property>
- <property name="action-name">win.selection-mode</property>
- <property name="action-target">false</property>
- <style>
- <class name="text-button"/>
- </style>
- </object>
- <packing>
- <property name="pack_type">end</property>
- </packing>
- </child>
- <child>
<object class="GtkButton" id="refresh-button">
<property name="visible">True</property>
<property name="can_focus">True</property>
@@ -193,34 +69,5 @@
<property name="height">1</property>
</packing>
</child>
- <child>
- <object class="GtkActionBar" id="selection-bar">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="no-show-all">True</property>
- <child>
- <object class="GtkButton" id="delete-button">
- <property name="visible">True</property>
- <property name="sensitive">False</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Delete</property>
- <property name="action-name">win.delete-selected</property>
- <property name="valign">center</property>
- <style>
- <class name="text-button"/>
- </style>
- </object>
- <packing>
- <property name="pack_type">end</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="left-attach">0</property>
- <property name="top-attach">1</property>
- <property name="width">1</property>
- <property name="height">1</property>
- </packing>
- </child>
</object>
</interface>
diff --git a/src/app/city.js b/src/app/city.js
index b29e02e..928837f 100644
--- a/src/app/city.js
+++ b/src/app/city.js
@@ -16,14 +16,13 @@
// with Gnome Weather; if not, write to the Free Software Foundation,
// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-const Atk = imports.gi.Atk;
-const GObject = imports.gi.GObject;
const Gtk = imports.gi.Gtk;
const GLib = imports.gi.GLib;
const Gnome = imports.gi.GnomeDesktop;
const Lang = imports.lang;
const Forecast = imports.app.forecast;
+const WForecast = imports.app.weeklyForecast;
const Params = imports.misc.params;
const Util = imports.misc.util;
@@ -39,49 +38,114 @@ const WeatherWidget = new Lang.Class({
this.parent(params);
this._currentStyle = null;
+ this._info = null;
let builder = new Gtk.Builder();
builder.add_from_resource('/org/gnome/Weather/Application/city.ui');
let outerBox = builder.get_object('outer-box');
this._contentFrame = builder.get_object('content-frame');
- let outerGrid = builder.get_object('outer-grid');
+ this._outerGrid = builder.get_object('outer-grid');
+ this._forecastGrid = builder.get_object('forecast-grid');
+ this._wForecastFrame = builder.get_object('weekly-forecast-frame');
+ let forecastScrollingWindow = builder.get_object('forecast-scrolled-window');
this._icon = builder.get_object('conditions-image');
this._temperature = builder.get_object('temperature-label');
this._conditions = builder.get_object('conditions-label');
- this._revealButton = builder.get_object('reveal-button');
- this._revealer = builder.get_object('revealer');
- this._time = builder.get_object('time-label');
+ this.timeLabel = builder.get_object('time-label');
+ this._dayStack = builder.get_object('day-stack');
+ this._leftButton = builder.get_object('left-button');
+ this._rightButton = builder.get_object('right-button');
+
+ this._forecasts = new Forecast.ForecastBox({ hexpand: false });
+ this._forecastGrid.attach(this._forecasts, 0, 0, 1, 1);
+
+ this._weeklyForecasts = new WForecast.WeeklyForecastFrame();
+ this._outerGrid.attach(this._weeklyForecasts, 1, 0, 1, 2);
+
+ this._hscrollbar = forecastScrollingWindow.get_hscrollbar();
+ this._hscrollbar.set_opacity(0.0);
+
+ this._hadjustment = forecastScrollingWindow.get_hadjustment();
+
+ this._hadjustment.connect('changed', Lang.bind(this, function() {
+ if ((this._hadjustment.get_upper() - this._hadjustment.get_lower()) ==
this._hadjustment.page_size) {
+ this._leftButton.set_sensitive(false);
+ this._rightButton.set_sensitive(false);
+ } else if (this._hadjustment.value == this._hadjustment.get_lower()){
+ this._leftButton.set_sensitive(false);
+ this._rightButton.set_sensitive(true);
+ } else if (this._hadjustment.value >= (this._hadjustment.get_upper() -
this._hadjustment.page_size)){
+ this._leftButton.set_sensitive(true);
+ this._rightButton.set_sensitive(false);
+ } else {
+ this._leftButton.set_sensitive(true);
+ this._rightButton.set_sensitive(true);
+ }
+ }));
- this._forecasts = new Forecast.ForecastBox({ hexpand: true });
- outerGrid.attach(this._forecasts, 0, 2, 1, 1);
+ this._dayStack.connect('notify::visible-child', Lang.bind(this, function() {
+ this.clear();
+ if (this._info) {
+ let forecasts = this._info.get_forecast_list();
+ this._forecasts.update(forecasts, this._dayStack.get_visible_child_name());
+ this._hadjustment.value = this._hadjustment.get_lower();
+ this._forecasts.show();
+ }
+ }));
- this._today = new Forecast.TodaySidebar({ vexpand: true,
- name: 'today-sidebar' });
- this._revealer.child = this._today;
+ this._leftButton.connect('clicked', Lang.bind(this, function() {
+ this._target = this._hadjustment.value - this._hadjustment.page_size;
+ if (this._target <= this._hadjustment.get_lower()) {
+ this._leftButton.set_sensitive(false);
+ this._rightButton.set_sensitive(true);
+ } else
+ this._rightButton.set_sensitive(true);
+
+ this._start = new Date().getTime();
+ this._end = this._start + 700;
+ this._tickId = this._forecastGrid.add_tick_callback(Lang.bind(this, this._animate));
+ }));
- this._revealButton.connect('clicked', Lang.bind(this, function() {
- this._revealer.reveal_child = !this._revealer.reveal_child;
- this._syncRevealButton();
+ this._rightButton.connect('clicked', Lang.bind(this, function() {
+ this._target = this._hadjustment.value + this._hadjustment.page_size;
+ if (this._target >= this._hadjustment.get_upper() - this._hadjustment.page_size) {
+ this._rightButton.set_sensitive(false);
+ this._leftButton.set_sensitive(true);
+ } else
+ this._leftButton.set_sensitive(true);
+
+ this._start = new Date().getTime();
+ this._end = this._start + 700;
+ this._tickId = this._forecastGrid.add_tick_callback(Lang.bind(this, this._animate));
}));
- this._syncRevealButton();
this.add(outerBox);
},
- _syncRevealButton: function() {
- if (this._revealer.reveal_child) {
- this._revealButton.get_child().icon_name = 'go-next-symbolic';
- this._revealButton.get_accessible().ref_state_set().add_state(Atk.StateType.CHECKED);
+ _animate: function() {
+ let value = this._hadjustment.value;
+ let t = 1.0;
+ let now = new Date().getTime();
+ if (now < this._end) {
+ t = (now - this._start) / 700;
+ t = this._easeOutCubic (t);
+ this._hadjustment.value = value + t * (this._target - value);
+ return true;
} else {
- this._revealButton.get_child().icon_name = 'go-previous-symbolic';
- this._revealButton.get_accessible().ref_state_set().remove_state(Atk.StateType.CHECKED);
+ this._hadjustment.value = value + t * (this._target - value);
+ this._forecastGrid.remove_tick_callback(this._tickId);
+ return false;
}
},
+ _easeOutCubic: function(value) {
+ let temp = value - 1;
+ return temp * temp * temp + 1;
+ },
+
clear: function() {
this._forecasts.clear();
- this._today.clear();
},
_get_style_class: function(info) {
@@ -91,6 +155,8 @@ const WeatherWidget = new Lang.Class({
},
update: function(info) {
+ this._info = info;
+
this._conditions.label = Util.getWeatherConditions(info);
this._temperature.label = info.get_temp_summary();
@@ -102,17 +168,14 @@ const WeatherWidget = new Lang.Class({
context.add_class(this._currentStyle);
let forecasts = info.get_forecast_list();
- if (forecasts.length > 0) {
- this._forecasts.update(forecasts);
- this._forecasts.show();
+ this._forecasts.update(forecasts, this._dayStack.get_visible_child_name());
+ this._forecasts.show();
- this._today.update(info);
- this._revealButton.show();
- this._revealer.show();
+ if (forecasts.length == 0) {
+ this._weeklyForecasts.hide();
} else {
- this._forecasts.hide();
- this._revealButton.hide();
- this._revealer.hide();
+ this._weeklyForecasts.show();
+ this._weeklyForecasts.update(forecasts);
}
}
});
@@ -196,7 +259,7 @@ const WeatherView = new Lang.Class({
},
_updateTime: function() {
- this._infoPage._time.label = this._getTime();
+ this._infoPage.timeLabel.label = this._getTime();
},
_getTime: function() {
diff --git a/src/app/currentLocationController.js b/src/app/currentLocationController.js
index c4df077..9682a73 100644
--- a/src/app/currentLocationController.js
+++ b/src/app/currentLocationController.js
@@ -17,12 +17,13 @@
// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
const GLib = imports.gi.GLib;
-const GObject = imports.gi.GObject;
const Gio = imports.gi.Gio;
const Lang = imports.lang;
const GWeather = imports.gi.GWeather;
const Geocode = imports.gi.GeocodeGlib;
+const Util = imports.misc.util;
+
const ManagerInterface = '<node> \
<interface name="org.freedesktop.GeoClue2.Manager"> \
<method name="GetClient"> \
@@ -70,9 +71,18 @@ const CurrentLocationController = new Lang.Class({
_init: function(world) {
this._world = world;
+ this._processStarted = false;
+ this._settings = Util.getSettings('org.gnome.Weather.Application');
+ this.autoLocation = this._settings.get_value('automatic-location').deep_unpack();
+ if(this.autoLocation)
+ this._startGeolocationService();
+ },
+
+ _startGeolocationService: function() {
+ this._processStarted = true;
this._managerProxy = new ManagerProxy(Gio.DBus.system,
- "org.freedesktop.GeoClue2",
- "/org/freedesktop/GeoClue2/Manager");
+ "org.freedesktop.GeoClue2",
+ "/org/freedesktop/GeoClue2/Manager");
this._managerProxy.GetClientRemote(this._onGetClientReady.bind(this));
},
@@ -80,6 +90,7 @@ const CurrentLocationController = new Lang.Class({
_onGetClientReady: function(result, e) {
if (e) {
log ("Failed to connect to GeoClue2 service: " + e.message);
+ this._world.currentLocationChanged(null);
return;
}
@@ -100,11 +111,14 @@ const CurrentLocationController = new Lang.Class({
this._clientProxy.connectSignal("LocationUpdated",
this._getCurrentLocation.bind(this));
- this._clientProxy.StartRemote(function(result, e) {
- if (e) {
- log ("Failed to connect to GeoClue2 service: " + e.message);
- }
- });
+ this._clientProxy.StartRemote(Lang.bind(this, this._callback, this._world));
+ },
+
+ _callback: function(result, e, world) {
+ if (e) {
+ log ("Failed to connect to GeoClue2 service: " + e.message);
+ world.currentLocationChanged(null);
+ }
},
_getCurrentLocation: function(proxy, sender, [oldPath, newPath]) {
@@ -117,35 +131,25 @@ const CurrentLocationController = new Lang.Class({
description: geoclueLocation.Description });
this.currentLocation = GWeather.Location.get_world().find_nearest_city (location.latitude,
location.longitude);
- this._addCurrentLocation();
+ this._world.currentLocationChanged(this.currentLocation);
},
- _addCurrentLocation: function() {
- let allLocations = this._world.getAllSavedLocations();
- let isSimilar = Lang.bind(this, function(location) {
- return this._isLocationSimilar(location);
- });
- if (allLocations.some(isSimilar))
- return;
-
- this._world.addLocation(this.currentLocation, false);
+ setAutoLocation: function(active) {
+ this._settings.set_value('automatic-location', new GLib.Variant('b', active));
+ this._autoLocationChanged(active);
},
- _isLocationSimilar: function(location) {
- if (this.currentLocation != null) {
- let station_code = location.get_code ();
- let currentLocationCode = this.currentLocation.get_code();
-
- if (station_code && currentLocationCode && (station_code == currentLocationCode)) {
- let name = location.get_name ();
- let currentLocationName = this.currentLocation.get_name();
-
- if (name && currentLocationName && (name == currentLocationName)) {
- return true;
- }
+ _autoLocationChanged: function(active) {
+ if (active) {
+ if (!this._processStarted) {
+ this._startGeolocationService();
+ } else {
+ this._locationUpdatedId =
+ this._clientProxy.connectSignal("LocationUpdated",
+ this._getCurrentLocation.bind(this));
}
+ } else {
+ this._clientProxy.disconnectSignal(this._locationUpdatedId);
}
-
- return false;
}
});
diff --git a/src/app/forecast.js b/src/app/forecast.js
index baec9a3..03fec52 100644
--- a/src/app/forecast.js
+++ b/src/app/forecast.js
@@ -19,7 +19,6 @@
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Gtk = imports.gi.Gtk;
-const GWeather = imports.gi.GWeather;
const Lang = imports.lang;
const Params = imports.misc.params;
@@ -27,8 +26,6 @@ const Strings = imports.shared.strings;
const Util = imports.misc.util;
// In microseconds
-const ONE_DAY = 24*3600*1000*1000;
-const TWELVE_HOURS = 12*3600*1000*1000;
const ONE_HOUR = 3600*1000*1000;
const ForecastBox = new Lang.Class({
@@ -40,177 +37,14 @@ const ForecastBox = new Lang.Class({
this.parent(params);
this.get_accessible().accessible_name = _("Forecast");
+ this._settings = new Gio.Settings({ schema: 'org.gnome.desktop.interface' });
+
this._grid = new Gtk.Grid({ orientation: Gtk.Orientation.HORIZONTAL,
column_spacing: 24,
row_spacing: 6,
margin: 12,
column_homogeneous: true });
this.add(this._grid);
-
- let context = this.get_style_context();
- context.add_class('background');
- context.add_class('osd');
- },
-
- update: function(infos) {
- let dates = infos.map(function(i) {
- let [ok, date] = i.get_value_update();
- return GLib.DateTime.new_from_unix_local(date);
- });
-
- let subday = this._hasSubdayResolution(dates);
- this._today = GLib.DateTime.new_now_local();
- this._tomorrow = this._today.add_days(1);
-
- let current, currentPart;
- let n = 0;
- // limit to 5 infos max
- for (let i = 0; i < dates.length && n < 5; i++) {
- let info = infos[i];
-
- // only show forecasts if they're separated by
- // at least 12 hours
- let [ok, date] = info.get_value_update();
- let datetime = GLib.DateTime.new_from_unix_local(date);
- let part = Strings.getDatetimePart(datetime);
-
- // Filter out "uninteresting" times (ie, during the night)
- if (part == -1)
- continue;
-
- // Filter two datetime that would give the same "Day Part" string
- if (current && part == currentPart &&
- Util.arrayEqual(current.get_ymd(), datetime.get_ymd()))
- continue;
-
- let text = '<b>' + this._getDate(datetime, subday) + '</b>';
- let label = new Gtk.Label({ label: text,
- use_markup: true,
- visible: true });
- this._grid.attach(label, n, 0, 1, 1);
-
- let image = new Gtk.Image({ icon_name: info.get_symbolic_icon_name(),
- icon_size: Gtk.IconSize.DIALOG,
- use_fallback: true,
- visible: true });
- this._grid.attach(image, n, 1, 1, 1);
-
- let temperature = new Gtk.Label({ label: this._getTemperature(info),
- visible: true });
- this._grid.attach(temperature, n, 2, 1, 1);
-
- current = datetime;
- currentPart = part;
- n++;
- }
- },
-
- clear: function() {
- this._grid.foreach(function(w) { w.destroy(); });
- },
-
- _hasSubdayResolution: function(dates) {
- if (dates.length == 1)
- return false;
-
- if (dates[1].difference(dates[0]) < ONE_DAY)
- return true;
- else
- return false;
- },
-
- _getDate: function(datetime, subday) {
- if (Util.arrayEqual(this._today.get_ymd(),
- datetime.get_ymd())) {
- if (subday)
- return Strings.formatToday(datetime);
- else
- return _("Today");
- } else if (Util.arrayEqual(this._tomorrow.get_ymd(),
- datetime.get_ymd())) {
- if (subday)
- return Strings.formatTomorrow(datetime);
- else
- return _("Tomorrow");
- } else {
- if (subday)
- return Strings.formatDayPart(datetime);
- else
- return datetime.format('%A');
- }
- },
-
- _getTemperature: function(info) {
- let [ok1, ] = info.get_value_temp_min(GWeather.TemperatureUnit.DEFAULT);
- let [ok2, ] = info.get_value_temp_max(GWeather.TemperatureUnit.DEFAULT);
-
- if (ok1 && ok2) {
- // TRANSLATORS: this is the temperature string, minimum and maximum.
- // The two values are already formatted, so it would be something like
- // "7 °C / 19 °C"
- return _("%s / %s").format(info.get_temp_min(), info.get_temp_max());
- } else {
- return info.get_temp_summary();
- }
- }
-});
-
-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);
-
- let context = this.get_style_context();
- context.add_class('view');
- context.add_class('content-view');
-
- this._settings = new Gio.Settings({ schema: 'org.gnome.desktop.interface' });
-
- let box = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL,
- vexpand: true });
- this.add(box);
-
- this._grid = new Gtk.Grid({ column_spacing: 12,
- row_spacing: 6,
- margin: 12 });
- box.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._attribution = new Gtk.Label({ xalign: 0.5,
- wrap: true,
- max_width_chars: 32,
- margin_bottom: 10,
- name: 'attribution-label',
- use_markup: true });
- box.pack_end(this._attribution, false, false, 0);
-
- this._moreButton = new Gtk.Button({ label: _("More…"),
- margin_top: 4,
- halign: Gtk.Align.END,
- visible: true });
- this._moreButton.connect('clicked', Lang.bind(this, this._changeView));
- this._tomorrow = false;
-
- this._infoWidgets = [];
- this._trimmedIndex = -1;
- },
-
- clear: function() {
- this._infoWidgets.forEach(function(w) { w.destroy(); });
- this._infoWidgets = [];
-
- if (this._moreButton.get_parent())
- this._grid.remove(this._moreButton);
},
// Ensure that infos are sufficiently spaced, and
@@ -256,57 +90,31 @@ const TodaySidebar = new Lang.Class({
return ret;
},
- update: function(info) {
- let infos = info.get_forecast_list();
-
- 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);
-
- this._trimmedToday = this._preprocess(now, infos);
- this._trimmedTomorrow = this._preprocess(now.add_days(1), infos);
-
- let hasToday = this._trimmedToday.length > 0;
- let hasTomorrow = this._trimmedTomorrow.length > 0;
-
- this._tomorrow = !hasToday;
- this._updateHeadline();
-
- let i;
- let infos = hasToday ? this._trimmedToday : this._trimmedTomorrow;
+ update: function(infos, day) {
+ if (infos.length > 0) {
+ let now = GLib.DateTime.new_now_local();
+ if (day == "tomorrow-button")
+ now = now.add_days(1);
+ let dayInfo = this._preprocess(now, infos);
- // 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._grid.attach(this._moreButton, 2, i+2, 1, 1);
-
- this._trimmedIndex = i;
- this._hasMore = false;
- if (this._trimmedIndex < infos.length) {
- this._hasMore = true;
- this._moreButton.label = _("More…");
- this._moreButton.show();
- } else if (hasToday && hasTomorrow) {
- this._moreButton.show();
- this._moreButton.label = _("Tomorrow");
- } else {
- this._moreButton.hide();
- }
+ if (dayInfo.length == 0) {
+ now = now.add_hours(-2);
+ dayInfo = this._preprocess(now, infos);
+ }
- let attr = info.get_attribution();
- if (attr) {
- this._attribution.label = attr;
- this._attribution.show();
+ for (let i = 0; i < dayInfo.length; i++) {
+ let info = dayInfo[i];
+ this._addOneInfo(info, i);
+ }
} else {
- this._attribution.hide();
+ let label = new Gtk.Label({ label: _("Forecast not available"),
+ use_markup: true,
+ visible: true });
+ this._grid.attach(label, 0, 0, 1, 1);
}
},
- _addOneInfo: function(info, row) {
+ _addOneInfo: function(info, col) {
let [ok, date] = info.get_value_update();
let datetime = GLib.DateTime.new_from_unix_local(date);
@@ -321,104 +129,22 @@ const TodaySidebar = new Lang.Class({
timeFormat = _("%R");
let label = new Gtk.Label({ label: datetime.format(timeFormat),
- 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);
+ use_markup: true,
+ visible: true });
+ this._grid.attach(label, col, 0, 1, 1);
let image = new Gtk.Image({ icon_name: info.get_symbolic_icon_name(),
- icon_size: Gtk.IconSize.MENU,
+ icon_size: Gtk.IconSize.DIALOG,
use_fallback: true,
visible: true });
- this._grid.attach(image, 1, row, 1, 1);
- this._infoWidgets.push(image);
-
- let conditions = new Gtk.Label({ label: Util.getWeatherConditions(info),
- visible: true,
- xalign: 0.0 });
- this._grid.attach(conditions, 2, row, 1, 1);
- this._infoWidgets.push(conditions);
- },
+ this._grid.attach(image, col, 1, 1, 1);
- _updateHeadline: function() {
- // Show today if we have it
-
- let date = GLib.DateTime.new_now_local();
- if (this._tomorrow)
- date = date.add_days(1);
-
- if (this._tomorrow)
- this._headline.label = '<b>' + _("Forecast for Tomorrow") + '</b>';
- else
- this._headline.label = '<b>' + _("Forecast for Today") + '</b>';
-
- // Translators: this is the date format for the sidebar date
- // It's a long date (explicit day name), relative to this week
- this._subline.label = date.format(_("%B %d"));
+ let temperature = new Gtk.Label({ label: Util.getTemperature(info),
+ visible: true });
+ this._grid.attach(temperature, col, 2, 1, 1);
},
- _changeView: function() {
- if (this._hasMore) {
- this._hasMore = false;
- this._grid.remove(this._moreButton);
-
- let hasToday = this._trimmedToday.length > 0;
- let hasTomorrow = this._trimmedTomorrow.length > 0;
-
- let infos = hasToday ? this._trimmedToday : this._trimmedTomorrow;
-
- let i;
- for (i = this._trimmedIndex; i < infos.length; i++) {
- let info = infos[i];
- this._addOneInfo(info, i + 2);
- }
- this._trimmedIndex = i;
-
- this._grid.attach(this._moreButton, 2, i+2, 1, 1);
-
- if (hasToday && hasTomorrow) {
- this._moreButton.show();
- this._moreButton.label = _("Tomorrow");
- } else {
- this._moreButton.hide();
- }
- } else {
- this.clear();
-
- let hasToday = this._trimmedToday.length > 0;
- let hasTomorrow = this._trimmedTomorrow.length > 0;
- let infos;
-
- if (this._tomorrow && hasToday) {
- infos = this._trimmedToday;
- this._tomorrow = false;
- } else if (!this._tomorrow && hasTomorrow) {
- infos = this._trimmedTomorrow;
- this._tomorrow = true;
- }
- this._updateHeadline();
-
- let i;
- for (i = 0; i < infos.length; i++) {
- let info = infos[i];
- this._addOneInfo(info, i + 2);
- }
- this._trimmedIndex = i;
-
- this._grid.attach(this._moreButton, 2, i+2, 1, 1);
-
- if (hasToday && hasTomorrow) {
- this._moreButton.show();
-
- if (this._tomorrow)
- this._moreButton.label = _("Today");
- else
- this._moreButton.label = _("Tomorrow");
- } else {
- this._moreButton.hide();
- }
-
- }
- },
+ clear: function() {
+ this._grid.foreach(function(w) { w.destroy(); });
+ }
});
diff --git a/src/app/main.js b/src/app/main.js
index 43ffc7a..89b6029 100644
--- a/src/app/main.js
+++ b/src/app/main.js
@@ -16,19 +16,15 @@
// with Gnome Weather; if not, write to the Free Software Foundation,
// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-pkg.initSubmodule('libgd');
pkg.initGettext();
pkg.initFormat();
-pkg.require({ 'Gd': '1.0',
- 'Gdk': '3.0',
- 'GdkPixbuf': '2.0',
+pkg.require({ 'Gdk': '3.0',
'Gio': '2.0',
'GLib': '2.0',
'GObject': '2.0',
'Gtk': '3.0',
'GWeather': '3.0' });
-const Gd = imports.gi.Gd;
const Gdk = imports.gi.Gdk;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
@@ -91,7 +87,6 @@ const Application = new Lang.Class({
vfunc_startup: function() {
this.parent();
- Gd.ensure_types();
Util.loadStyleSheet('/org/gnome/Weather/Application/application.css');
@@ -100,7 +95,7 @@ const Application = new Lang.Class({
this.world = GWeather.Location.get_world();
this.model = new World.WorldModel(this.world, true);
- this._currentLocationController = new
CurrentLocationController.CurrentLocationController(this.model);
+ this.currentLocationController = new CurrentLocationController.CurrentLocationController(this.model);
this.model.connect('notify::loading', Lang.bind(this, function() {
if (this.model.loading)
@@ -131,24 +126,32 @@ const Application = new Lang.Class({
_createWindow: function() {
let win = new Window.MainWindow({ application: this });
-
- if (this.model.loading) {
- let timeoutId, notifyId;
- let model = this.model;
-
- timeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 1000, function() {
- log('Timeout during model load, perhaps the network is not available?');
- model.disconnect(notifyId);
+ let notifyId;
+
+ if (!this.currentLocationController.autoLocation) {
+ if (this.model.loading) {
+ let timeoutId;
+ let model = this.model;
+
+ timeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 1000, function() {
+ log('Timeout during model load, perhaps the network is not available?');
+ model.disconnect(notifyId);
+ win.show();
+ return false;
+ });
+ notifyId = this.model.connect('notify::loading', function(model) {
+ model.disconnect(notifyId);
+ GLib.source_remove(timeoutId);
+ win.show();
+ });
+ } else {
win.show();
- return false;
- });
- notifyId = this.model.connect('notify::loading', function(model) {
+ }
+ } else {
+ notifyId = this.model.connect('notify::loading', Lang.bind(this, function(model) {
model.disconnect(notifyId);
- GLib.source_remove(timeoutId);
win.show();
- });
- } else {
- win.show();
+ }));
}
return win;
diff --git a/src/app/weeklyForecast.js b/src/app/weeklyForecast.js
new file mode 100644
index 0000000..a05ddca
--- /dev/null
+++ b/src/app/weeklyForecast.js
@@ -0,0 +1,141 @@
+// -*- Mode: js; indent-tabs-mode: nil; c-basic-offset: 4; tab-width: 4 -*-
+//
+// Copyright (c) 2014 Saurabh Patel <srp201201051 gmail com>
+//
+// Gnome Weather 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.
+//
+// Gnome Weather 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 Gnome Weather; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+const Gio = imports.gi.Gio;
+const GLib = imports.gi.GLib;
+const Gtk = imports.gi.Gtk;
+const Lang = imports.lang;
+
+const Params = imports.misc.params;
+const Strings = imports.shared.strings;
+const Util = imports.misc.util;
+
+const WeeklyForecastFrame = new Lang.Class({
+ Name: 'WeeklyForecastFrame',
+ Extends: Gtk.Frame,
+
+ _init: function(params) {
+ params = Params.fill(params, { shadow_type: Gtk.ShadowType.NONE,
+ name: _("weekly-forecast-frame") });
+ this.parent(params);
+ this.get_accessible().accessible_name = _("WeeklyForecast");
+
+ this._settings = new Gio.Settings({ schema: 'org.gnome.desktop.interface' });
+
+ this._grid = new Gtk.Grid({ orientation: Gtk.Orientation.VERTICAL,
+ margin_top: 10,
+ margin_bottom: 30,
+ margin_left: 50,
+ margin_right: 50,
+ valign: Gtk.Align.CENTER,
+ halign: Gtk.Align.START,
+ row_spacing: 25,
+ row_homogeneous: true });
+
+ this.add(this._grid);
+ },
+
+ // get infos for the correct day
+ _preprocess: function(infos, day) {
+ let ret = [];
+ let i;
+
+ // First ignore all infos that are on a different
+ // older than day.
+ // infos are ordered by time, and it's assumed at some point
+ // there is an info for the day (otherwise, nothing
+ // is shown)
+ for (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 (Util.arrayEqual(day.get_ymd(), datetime.get_ymd())) {
+ break;
+ }
+ }
+
+ let infoCount = 0;
+ while (i < infos.length && infoCount < 5) {
+ let count = 0;
+ let temp = [];
+ for ( ; 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 (!Util.arrayEqual(day.get_ymd(),
+ datetime.get_ymd()))
+ break;
+
+ temp[count++] = info;
+ }
+ if (count > 0)
+ ret.push(temp[Math.floor(count/2)]);
+ day = day.add_days(1);
+ infoCount++;
+ }
+ return ret;
+ },
+
+ update: function(infos) {
+ let day = GLib.DateTime.new_now_local();
+ day = day.add_days(2);
+
+ let weeklyInfo = this._preprocess(infos, day);
+ this.clear();
+
+ for (let i = 0; i < weeklyInfo.length; i++) {
+ let info = weeklyInfo[i];
+ let [ok, date] = info.get_value_update();
+ let datetime = GLib.DateTime.new_from_unix_local(date);
+
+ // Translators: this is the time format for full weekday name according to the current locale
+ let timeFormat = _("%A");
+
+ let grid = new Gtk.Grid({ orientation: Gtk.Orientation.HORIZONTAL,
+ row_spacing: 5,
+ column_spacing: 10 });
+
+ let label = new Gtk.Label({ label: datetime.format(timeFormat),
+ use_markup: true,
+ halign: Gtk.Align.START,
+ visible: true });
+ grid.attach(label, 0, 0, 2, 1);
+
+ let image = new Gtk.Image({ icon_name: info.get_symbolic_icon_name(),
+ icon_size: Gtk.IconSize.DIALOG,
+ use_fallback: true,
+ halign: Gtk.Align.START,
+ visible: true });
+ grid.attach(image, 0, 1, 1, 1);
+
+ let temperature = new Gtk.Label({ label: Util.getTemperature(info),
+ halign: Gtk.Align.END,
+ visible: true });
+ grid.attach(temperature, 1, 1, 1, 1);
+ grid.show();
+ this._grid.attach(grid, 0, i, 1, 1);
+ }
+ },
+
+ clear: function() {
+ this._grid.foreach(function(w) { w.destroy(); });
+ }
+});
diff --git a/src/app/window.js b/src/app/window.js
index 3838321..24b8ac8 100644
--- a/src/app/window.js
+++ b/src/app/window.js
@@ -16,8 +16,6 @@
// with Gnome Weather; if not, write to the Free Software Foundation,
// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-const GLib = imports.gi.GLib;
-const GObject = imports.gi.GObject;
const Gtk = imports.gi.Gtk;
const GWeather = imports.gi.GWeather;
const Lang = imports.lang;
@@ -27,60 +25,11 @@ const Params = imports.misc.params;
const World = imports.shared.world;
const Util = imports.misc.util;
-const Gettext = imports.gettext;
-const Tweener = imports.tweener.tweener;
-
const Page = {
WORLD: 0,
CITY: 1
};
-const NewLocationController = new Lang.Class({
- Name: 'NewLocationController',
-
- _init: function(parentWindow, worldModel) {
- this._worldModel = worldModel;
-
- let builder = Util.loadUI('/org/gnome/Weather/Application/new-location-dialog.ui',
- { 'parent-window': parentWindow });
-
- let dialog = builder.get_object('location-dialog');
- let entry = builder.get_object('location-entry');
-
- dialog.add_button(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL);
- dialog.add_button(Gtk.STOCK_ADD, Gtk.ResponseType.OK);
- dialog.set_default_response(Gtk.ResponseType.OK);
-
- dialog.connect('response', Lang.bind(this, this._onResponse));
- entry.connect('notify::location', Lang.bind(this, this._locationChanged));
-
- this._dialog = dialog;
- this._entry = entry;
- },
-
- run: function() {
- this._dialog.show();
- this._locationChanged(this._entry);
- },
-
- _onResponse: function(dialog, response) {
- dialog.destroy();
-
- if (response != Gtk.ResponseType.OK)
- return;
-
- let location = this._entry.location;
- if (!location)
- return;
-
- this._worldModel.addLocation(location, true);
- },
-
- _locationChanged: function(entry) {
- this._dialog.set_response_sensitive(Gtk.ResponseType.OK, entry.location != null);
- }
-});
-
const MainWindow = new Lang.Class({
Name: 'MainWindow',
Extends: Gtk.ApplicationWindow,
@@ -96,24 +45,10 @@ const MainWindow = new Lang.Class({
this._pageWidgets = [[],[]];
Util.initActions(this,
- [{ name: 'new-location',
- activate: this._newLocation },
- { name: 'about',
+ [{ name: 'about',
activate: this._showAbout },
{ name: 'close',
activate: this._close },
- { name: 'selection-mode',
- activate: this._setSelectionMode,
- parameter_type: new GLib.VariantType('b'),
- state: new GLib.Variant('b', false) },
- { name: 'go-world',
- activate: this._goWorld },
- { name: 'select-all',
- activate: this._selectAll },
- { name: 'select-none',
- activate: this._selectNone },
- { name: 'delete-selected',
- activate: this._deleteSelected },
{ name: 'refresh',
activate: this.update }]);
@@ -127,93 +62,46 @@ const MainWindow = new Lang.Class({
this._header.title = title;
this._header.subtitle = subtitle;
- let newButton = builder.get_object('new-button');
- this._pageWidgets[Page.WORLD].push(newButton);
+ this._worldView = new World.WorldContentView(this.application, { visible: true });
+ this._worldView.hide();
- let goWorldButton = builder.get_object('world-button');
- this._pageWidgets[Page.CITY].push(goWorldButton);
+ this._model = this._worldView.model;
+ this._model.connect('show-info', Lang.bind(this, function(model, info) {
+ this.showInfo(info);
+ }));
+ this._model.connect('no-cityview', Lang.bind(this, function() {
+ for (let i = 0; i < this._pageWidgets[Page.WORLD].length; i++)
+ this._pageWidgets[Page.WORLD][i].show_all();
+ }));
- let select = builder.get_object('select-button');
- this._pageWidgets[Page.WORLD].push(select);
+ this._initialGrid = this._worldView.initialGrid;
+ this._pageWidgets[Page.WORLD].push(this._initialGrid);
- let refresh = builder.get_object('refresh-button');
- this._pageWidgets[Page.CITY].push(refresh);
+ let placesButton = builder.get_object('places-button');
+ this._pageWidgets[Page.CITY].push(placesButton);
- let selectDone = builder.get_object('done-button');
- this._pageWidgets[Page.WORLD].push(selectDone);
+ placesButton.set_popover(this._worldView);
- let selectionBar = builder.get_object('selection-bar');
- let selectionMenu = builder.get_object("selection-menu");
+ let refresh = builder.get_object('refresh-button');
+ this._pageWidgets[Page.CITY].push(refresh);
- this._selectionMenuButton = builder.get_object('selection-menu-button');
- this._selectionMenuButtonLabel = builder.get_object('selection-menu-button-label');
this._stack = builder.get_object('main-stack');
- this._deleteButton = builder.get_object('delete-button');
-
this._cityView = new City.WeatherView({ hexpand: true,
vexpand: true });
this._stack.add(this._cityView);
- this._worldView = new World.WorldContentView(this.application.model, { visible: true });
- let iconView = this._worldView.iconView;
- this._stack.add(this._worldView);
+ this._stack.add(this._initialGrid);
- iconView.connect('item-activated', Lang.bind(this, this._itemActivated));
-
- iconView.connect('notify::selection-mode', Lang.bind(this, function() {
- if (iconView.selection_mode) {
- this._header.get_style_context().add_class('selection-mode');
- this._header.set_custom_title(this._selectionMenuButton);
- } else {
- this._header.get_style_context().remove_class('selection-mode');
- this._header.set_custom_title(null);
- }
-
- let selectionState = new GLib.Variant('b', iconView.selection_mode);
- this.lookup_action('selection-mode').set_state(selectionState);
- }));
-
- iconView.bind_property('selection-mode', newButton, 'visible',
- GObject.BindingFlags.INVERT_BOOLEAN);
- iconView.bind_property('selection-mode', this._header, 'show-close-button',
- GObject.BindingFlags.INVERT_BOOLEAN);
- iconView.bind_property('selection-mode', select, 'visible',
- GObject.BindingFlags.INVERT_BOOLEAN);
- iconView.bind_property('selection-mode', selectDone, 'visible',
- GObject.BindingFlags.SYNC_CREATE);
- iconView.bind_property('selection-mode', selectionBar, 'visible',
- GObject.BindingFlags.SYNC_CREATE);
- this._worldView.bind_property('empty', this.lookup_action('selection-mode'), 'enabled',
- GObject.BindingFlags.SYNC_CREATE |
- GObject.BindingFlags.INVERT_BOOLEAN);
-
- this._stack.set_visible_child(this._worldView);
-
- iconView.connect('view-selection-changed', Lang.bind(this, function() {
- let items = iconView.get_selection();
- let label;
- let sensitive;
-
- if (items.length > 0) {
- label = Gettext.ngettext("%d selected",
- "%d selected",
- items.length).format(items.length);
- sensitive = true;
- } else {
- label = _("Click on locations to select them");
- sensitive = false;
- }
-
- this._selectionMenuButtonLabel.label = label;
- this._deleteButton.sensitive = sensitive;
- }));
+ this._stack.set_visible_child(this._initialGrid);
this.add(grid);
grid.show_all();
for (let i = 0; i < this._pageWidgets[Page.CITY].length; i++)
this._pageWidgets[Page.CITY][i].hide();
+
+ this._model.fillCityView(this.application.currentLocationController.autoLocation);
},
update: function() {
@@ -222,7 +110,7 @@ const MainWindow = new Lang.Class({
_getTitle: function() {
if (this._currentPage == Page.WORLD)
- return [_("World Weather"), null];
+ return [_("Select Location"), null];
let location = this._cityView.info.location;
let city = location;
@@ -241,9 +129,6 @@ const MainWindow = new Lang.Class({
},
_goToPage: function(page) {
- if (page == this._currentPage)
- return;
-
for (let i = 0; i < this._pageWidgets[this._currentPage].length; i++)
this._pageWidgets[this._currentPage][i].hide();
@@ -260,13 +145,6 @@ const MainWindow = new Lang.Class({
this._header.subtitle = subtitle;
},
- _itemActivated: function(view, id, path) {
- let [ok, iter] = view.model.get_iter(path);
- let info = view.model.get_value(iter, World.Columns.INFO);
-
- this.showInfo(info);
- },
-
showInfo: function(info) {
this._cityView.info = info;
this._cityView.connectClock();
@@ -274,33 +152,6 @@ const MainWindow = new Lang.Class({
this._goToPage(Page.CITY);
},
- _goWorld: function() {
- this._stack.set_visible_child(this._worldView);
- this._goToPage(Page.WORLD);
- this._cityView.disconnectClock();
- },
-
- _newLocation: function() {
- let controller = new NewLocationController(this.get_toplevel(),
- this._worldView.model);
-
- controller.run();
- },
-
- _setSelectionMode: function(action, param) {
- this._worldView.iconView.selection_mode = param.get_boolean();
- this._deleteButton.sensitive = false;
- },
-
- _selectAll: function() {
- this._worldView.iconView.selection_mode = true;
- this._worldView.iconView.select_all();
- },
-
- _selectNone: function() {
- this._worldView.iconView.unselect_all();
- },
-
_showAbout: function() {
let artists = [ 'Jakub Steiner <jimmac gmail com>',
'Pink Sherbet Photography (D. Sharon Pruitt)',
@@ -333,19 +184,6 @@ const MainWindow = new Lang.Class({
});
},
- _deleteSelected: function() {
- let items = this._worldView.iconView.get_selection();
- let model = this._worldView.iconView.model;
-
- for (let i = items.length - 1; i >= 0; i--) {
- let [res, iter] = model.get_iter(items[i]);
- if (res)
- model.removeLocation(iter);
- }
-
- this._worldView.iconView.selection_mode = false;
- },
-
_close: function() {
this.destroy();
}
diff --git a/src/misc/util.js b/src/misc/util.js
index fc08e3f..80250dd 100644
--- a/src/misc/util.js
+++ b/src/misc/util.js
@@ -29,6 +29,7 @@ const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Gtk = imports.gi.Gtk;
const System = imports.system;
+const GWeather = imports.gi.GWeather;
const Params = imports.misc.params;
@@ -147,7 +148,32 @@ function normalizeCasefoldAndUnaccent(str) {
return str.replace(/[\u0300-\u036f]|[\u1dc0-\u1dff]|[\u20d0-\u20ff]|[\ufe20-\ufe2f]/, '');
}
-function assertEqual(one, two) {
- if (one != two)
- throw Error('Assertion failed: ' + one + ' != ' + two);
+function getTemperature(info) {
+ let [ok1, ] = info.get_value_temp_min(GWeather.TemperatureUnit.DEFAULT);
+ let [ok2, ] = info.get_value_temp_max(GWeather.TemperatureUnit.DEFAULT);
+
+ if (ok1 && ok2) {
+ // TRANSLATORS: this is the temperature string, minimum and maximum.
+ // The two values are already formatted, so it would be something like
+ // "7 °C / 19 °C"
+ return _("%s / %s").format(info.get_temp_min(), info.get_temp_max());
+ } else {
+ return info.get_temp_summary();
+ }
+}
+
+function getEnabledProviders() {
+ let provider_override = GLib.getenv('GWEATHER_DEBUG_BACKEND');
+ if (provider_override) {
+ return (GWeather.Provider.METAR | GWeather.Provider[provider_override]);
+ } else {
+ return (GWeather.Provider.METAR | GWeather.Provider.YR_NO | GWeather.Provider.OWM);
+ }
}
+
+function getLabelFromRow(row) {
+ let children = row.get_children();
+ let grid = children[0];
+ let gridChildren = children[0].get_children();
+ return gridChildren[1].get_label();
+}
\ No newline at end of file
diff --git a/src/org.gnome.Weather.Application.src.gresource.xml
b/src/org.gnome.Weather.Application.src.gresource.xml
index 3e59a63..33a1ebe 100644
--- a/src/org.gnome.Weather.Application.src.gresource.xml
+++ b/src/org.gnome.Weather.Application.src.gresource.xml
@@ -4,6 +4,7 @@
<file>app/city.js</file>
<file>app/currentLocationController.js</file>
<file>app/forecast.js</file>
+ <file>app/weeklyForecast.js</file>
<file>app/main.js</file>
<file>app/window.js</file>
<file>misc/params.js</file>
diff --git a/src/shared/world.js b/src/shared/world.js
index 4c6861e..d7fbc9b 100644
--- a/src/shared/world.js
+++ b/src/shared/world.js
@@ -16,85 +16,123 @@
// with Gnome Weather; if not, write to the Free Software Foundation,
// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-const Gd = imports.gi.Gd;
-const GdkPixbuf = imports.gi.GdkPixbuf;
const GLib = imports.gi.GLib;
const GObject = imports.gi.GObject;
const Gtk = imports.gi.Gtk;
const GWeather = imports.gi.GWeather;
const Lang = imports.lang;
+const Signals = imports.signals;
const Params = imports.misc.params;
const Util = imports.misc.util;
-const Columns = {
- ID: Gd.MainColumns.ID,
- URI: Gd.MainColumns.URI,
- PRIMARY_TEXT: Gd.MainColumns.PRIMARY_TEXT,
- SECONDARY_TEXT: Gd.MainColumns.SECONDARY_TEXT,
- ICON: Gd.MainColumns.ICON,
- MTIME: Gd.MainColumns.MTIME,
- SELECTED: Gd.MainColumns.SELECTED,
- PULSE: Gd.MainColumns.PULSE,
- LOCATION: Gd.MainColumns.LAST,
- INFO: Gd.MainColumns.LAST+1,
- AUTOMATIC: Gd.MainColumns.LAST+2
-};
-const ColumnTypes = {
- ID: String,
- URI: String,
- PRIMARY_TEXT: String,
- SECONDARY_TEXT: String,
- ICON: GdkPixbuf.Pixbuf,
- MTIME: GObject.Int,
- SELECTED: Boolean,
- PULSE: GObject.UInt,
- LOCATION: GWeather.Location,
- INFO: GWeather.Info,
- AUTOMATIC: Boolean
-};
-Util.assertEqual(Object.keys(Columns).length, Object.keys(ColumnTypes).length);
-Util.assertEqual(Gd.MainColumns.LAST+3, Object.keys(ColumnTypes).length);
-
-const ICON_SIZE = 128;
-
const WorldModel = new Lang.Class({
Name: 'WorldModel',
- Extends: Gtk.ListStore,
Signals: {
- 'updated': { param_types: [ GWeather.Info ] }
+ 'updated': { param_types: [ GWeather.Info ] },
+ 'no-cityview': { param_types: [] },
+ 'show-info': { param_types: [ GWeather.Info ] },
+ 'current-location-changed': { param_types: [ GWeather.Location ] },
+ 'validate-listbox': { param_types: [ GWeather.Location ] }
},
Properties: {
'loading': GObject.ParamSpec.boolean('loading', '', '', GObject.ParamFlags.READABLE, false)
},
_init: function(world, enableGtk) {
- this.parent();
- this.set_column_types([ColumnTypes[c] for (c in ColumnTypes)]);
this._world = world;
this._settings = Util.getSettings('org.gnome.Weather.Application');
- let provider_override = GLib.getenv('GWEATHER_DEBUG_BACKEND');
- if (provider_override) {
- this._providers = GWeather.Provider.METAR | GWeather.Provider[provider_override];
- } else {
- this._providers = GWeather.Provider.METAR | GWeather.Provider.YR_NO |
- GWeather.Provider.OWM;
- }
+ this._providers = Util.getEnabledProviders();
this._loadingCount = 0;
+ this._infoList = [];
+
+ this._enableGtk = enableGtk;
+
+ this._currentLocationInfo = null;
+
+ this.currentlyLoadedInfo = null;
+
+ this.addedCurrentLocation = false;
+ },
+
+ currentLocationChanged: function(location) {
+ if (location) {
+ this._newCurrentLocationInfo = new GWeather.Info({ location: location,
+ enabled_providers: this._providers });
+ if (this._currentLocationInfo) {
+ if (!this._currentLocationInfo.location.equal(location)) {
+ this._newCurrentLocationInfo.connect('updated', Lang.bind(this, function(info) {
+ this._updateLoadingCount(-1);
+ this.emit('updated', this._newCurrentLocationInfo);
+ }));
+ this.updateInfo(this._newCurrentLocationInfo);
+ this._currentLocationInfo = this._newCurrentLocationInfo;
+ }
+ } else {
+ this._newCurrentLocationInfo.connect('updated', Lang.bind(this, function(info) {
+ this._updateLoadingCount(-1);
+ this.emit('updated', this._newCurrentLocationInfo);
+ }));
+ this.updateInfo(this._newCurrentLocationInfo);
+ this._currentLocationInfo = this._newCurrentLocationInfo;
+ }
+ }
+ this.emit('notify::loading');
+ this.emit('current-location-changed', location);
+ },
+
+ rowActivated: function(listbox, row) {
+ let cityName = Util.getLabelFromRow(row);
+ this.emit('show-info', this._infoList[cityName]);
+ this.currentlyLoadedInfo = this._infoList[cityName];
+ this.emit('validate-listbox', this.currentlyLoadedInfo.location);
+ },
+
+ showRecent: function(listbox) {
+ let row = listbox.get_row_at_index(0);
+ if (row) {
+ this.rowActivated(null, row);
+ return;
+ } else
+ this.emit('no-cityview');
+ },
+
+ _showCurrentLocation: function() {
+ if (this._currentLocationInfo) {
+ this.emit('show-info', this._currentLocationInfo);
+ this.currentlyLoadedInfo = this._currentLocationInfo;
+ }
+ },
+
+ fillListbox: function (listbox) {
let locations = this._settings.get_value('locations').deep_unpack();
- for (let i = 0; i < locations.length; i++) {
- let variant = locations[i];
- let location = this._world.deserialize(variant);
- this._addLocationInternal(location, false);
+ if (locations.length != 0) {
+ for (let i = 0; i < locations.length && i < 5; i++) {
+ let variant = locations[i];
+ let location = this._world.deserialize(variant);
+ this._addLocationInternal(location, listbox, false);
+ }
}
+ },
- this._settings.connect('changed::locations', Lang.bind(this, this._onChanged));
+ fillCityView: function(autoLocation) {
+ let locations = this._settings.get_value('locations').deep_unpack();
- this._enableGtk = enableGtk;
+ if (!autoLocation) {
+ if (locations.length > 0) {
+ let variant = locations[locations.length-1];
+ let location = this._world.deserialize(variant);
+ this.emit('show-info', this._infoList[location.get_city_name()]);
+ this.currentlyLoadedInfo = this._infoList[location.get_city_name()];
+ this.emit('validate-listbox', this.currentlyLoadedInfo.location);
+ } else {
+ this.emit('no-cityview');
+ }
+ }
},
_updateLoadingCount: function(delta) {
@@ -103,7 +141,7 @@ const WorldModel = new Lang.Class({
let isLoading = this._loadingCount > 0;
if (wasLoading != isLoading)
- this.notify('loading');
+ this.emit('notify::loading');
},
updateInfo: function(info) {
@@ -115,265 +153,241 @@ const WorldModel = new Lang.Class({
return this._loadingCount > 0;
},
- _addLocationInternal: function(location, automatic) {
+ _addLocationInternal: function(location, listbox, isCurrentLocation) {
+ let grid = new Gtk.Grid({ orientation: Gtk.Orientation.HORIZONTAL,
+ column_spacing: 15,
+ margin_top: 6,
+ margin_bottom: 6,
+ column_homogeneous: true });
+
+ let name = location.get_city_name();
+ let locationLabel = new Gtk.Label({ label: name,
+ use_markup: true,
+ halign: Gtk.Align.START,
+ visible: true });
+ grid.attach(locationLabel, 0, 0, 1, 1);
+
+ let conditionGrid = new Gtk.Grid({ orientation: Gtk.Orientation.HORIZONTAL,
+ column_spacing: 1,
+ column_homogeneous: true });
+
+ let tempLabel = new Gtk.Label({ use_markup: true,
+ halign: Gtk.Align.END,
+ visible: true });
+ conditionGrid.attach(tempLabel, 0, 0, 1, 1);
+
+ if (isCurrentLocation) {
+ let image = new Gtk.Image({ icon_size: Gtk.IconSize.LARGE_TOOLBAR,
+ icon_name: 'mark-location-symbolic',
+ use_fallback: true,
+ halign: Gtk.Align.END,
+ visible: true });
+ conditionGrid.attach(image, 1, 0, 1, 1);
+ }
+
+ let image = new Gtk.Image({ icon_size: Gtk.IconSize.LARGE_TOOLBAR,
+ use_fallback: true,
+ halign: Gtk.Align.END,
+ visible: true });
+ if (isCurrentLocation)
+ conditionGrid.attach(image, 2, 0, 1, 1);
+ else
+ conditionGrid.attach(image, 1, 0, 2, 1);
+
+ conditionGrid.show();
+ grid.attach(conditionGrid, 1, 0, 1, 1);
+
+ grid.show();
+ if(isCurrentLocation) {
+ if (this.addedCurrentLocation) {
+ let children = listbox.get_children();
+ children[0].destroy();
+ }
+ listbox.insert(grid, 0);
+ } else {
+ if (this.addedCurrentLocation)
+ listbox.insert(grid, 1);
+ else
+ listbox.insert(grid, 0);
+ }
+
let info = new GWeather.Info({ location: location,
enabled_providers: this._providers });
- let iter;
+
+ this._infoList[locationLabel.get_label()] = info;
+
info.connect('updated', Lang.bind(this, function(info) {
- let secondary_text = Util.getWeatherConditions(info);
- if (this._enableGtk) {
- let icon = Util.loadIcon(info.get_symbolic_icon_name(), ICON_SIZE);
- this.set(iter,
- [Columns.ICON, Columns.SECONDARY_TEXT],
- [icon, secondary_text]);
- } else {
- this.set_value(iter, Columns.SECONDARY_TEXT, secondary_text);
- }
+ tempLabel.label = info.get_temp_summary();
+ image.icon_name = info.get_symbolic_icon_name();
this._updateLoadingCount(-1);
this.emit('updated', info);
}));
this.updateInfo(info);
-
- let primary_text = location.get_city_name();
-
- iter = this.insert_with_valuesv(-1,
- [Columns.PRIMARY_TEXT,
- Columns.LOCATION,
- Columns.INFO,
- Columns.AUTOMATIC],
- [primary_text,
- location,
- info,
- automatic]);
-
- if (this._enableGtk) {
- let icon = Util.loadIcon('view-refresh-symbolic', ICON_SIZE);
- this.set_value(iter, Columns.ICON, icon);
- }
},
- _onChanged: function() {
- let newLocations = this._settings.get_value('locations').deep_unpack();
- let toErase = [];
+ addNewLocation: function(newLocation, listbox, isCurrentLocation) {
+ if (newLocation) {
+ let locations = this._settings.get_value('locations').deep_unpack();
+
+ if (!isCurrentLocation) {
+ for (let i = 0; i < locations.length; i++) {
+ let location = this._world.deserialize(locations[i]);
+ if (location.equal(newLocation)) {
+ this.emit('show-info', this._infoList[location.get_city_name()]);
+ this.currentlyLoadedInfo = this._infoList[location.get_city_name()];
+ this.emit('validate-listbox', this.currentlyLoadedInfo.location);
+ return;
+ }
+ }
- let [ok, iter] = this.get_iter_first();
- while (ok) {
- let auto = this.get_value(iter, Columns.AUTOMATIC);
- if (auto) {
- ok = this.iter_next(iter);
- continue;
- }
- let location = this.get_value(iter, Columns.LOCATION);
+ locations.push(newLocation.serialize());
- let found = false;
- for (let j = 0; j < newLocations.length; j++) {
- let variant = newLocations[j];
- if (variant == null)
- continue;
+ if (locations.length > 5) {
+ let children = listbox.get_children();
+ children[children.length-1].destroy();
+ }
- let newLocation = this._world.deserialize(variant);
+ this._settings.set_value('locations', new GLib.Variant('av', locations));
+ }
- if (location.equal(newLocation)) {
- newLocations[j] = null;
- found = true;
- break;
+ this._addLocationInternal(newLocation, listbox, isCurrentLocation);
+ if (!isCurrentLocation) {
+ this.emit('show-info', this._infoList[newLocation.get_city_name()]);
+ this.currentlyLoadedInfo = this._infoList[newLocation.get_city_name()];
+ this.emit('validate-listbox', this.currentlyLoadedInfo.location);
+ }
+ else {
+ if(!this.addedCurrentLocation) {
+ this.emit('show-info', this._currentLocationInfo);
+ this.currentlyLoadedInfo = this._currentLocationInfo;
+ this.emit('validate-listbox', this.currentlyLoadedInfo.location);
}
+ this.addedCurrentLocation = true;
}
-
- if (!found)
- toErase.push(iter.copy());
-
- ok = this.iter_next(iter);
}
+ }
+});
- for (let i = 0; i < toErase.length; i++)
- this.remove(toErase[i]);
+const WorldContentView = new Lang.Class({
+ Name: 'WorldContentView',
+ Extends: Gtk.Popover,
- for (let i = 0; i < newLocations.length; i++) {
- let variant = newLocations[i];
- if (variant == null)
- continue;
+ _init: function(application, params) {
+ params = Params.fill(params, { hexpand: false, vexpand: false });
+ this.parent(params);
- let newLocation = this._world.deserialize(variant);
- this._addLocationInternal(newLocation, false);
- }
- },
+ this.get_accessible().accessible_name = _("World view");
- _addSavedLocation: function(location) {
- let newLocations = this._settings.get_value('locations').deep_unpack();
- newLocations.push(location.serialize());
- this._settings.set_value('locations', new GLib.Variant('av', newLocations));
- },
+ let builder = new Gtk.Builder();
+ builder.add_from_resource('/org/gnome/Weather/Application/places-popover.ui');
- getAllSavedLocations: function() {
- let locations = this._settings.get_value('locations').deep_unpack();
- let returnValue = [];
+ let grid = builder.get_object('popover-grid');
+ this.add(grid);
- for (let i = 0; i < locations.length; i++) {
- let variant = locations[i];
- if (variant == null) {
- log('null stored in GSettings?');
- continue;
- }
+ this.initialGrid = builder.get_object('initial-grid');
- returnValue.push(this._world.deserialize(variant));
- }
+ let stackPopover = builder.get_object('popover-stack');
- return returnValue;
- },
+ this.model = application.model;
- getLocationInfo: function(location) {
- let [ok, iter] = this.get_iter_first();
- while (ok) {
- let storedLocation = this.get_value(iter, Columns.LOCATION);
- if (storedLocation.equal(location))
- return this.get_value(iter, Columns.INFO);
+ let listbox = builder.get_object('locations-list-box');
- ok = this.iter_next(iter);
- }
+ let initialGridLocEntry = builder.get_object('initial-grid-location-entry');
+ initialGridLocEntry.connect('notify::location', Lang.bind(this, function(entry) {
+ this._locationChanged(entry, listbox);
+ }));
- return null;
- },
+ let locationEntry = builder.get_object('location-entry');
+ locationEntry.connect('notify::location', Lang.bind(this, function(entry) {
+ this._locationChanged(entry, listbox)
+ }));
- addLocation: function(location, saved) {
- if (saved)
- this._addSavedLocation(location);
- else
- this._addLocationInternal(location, true);
- },
+ this.model.fillListbox(listbox);
- removeLocation: function(iter) {
- let auto = this.get_value(iter, Columns.AUTOMATIC);
- if (auto) {
- this.remove(iter);
- return;
- }
+ this.connect('notify::visible', Lang.bind(this, function() {
+ listbox.set_selection_mode(0);
+ locationEntry.grab_focus();
+ listbox.set_selection_mode(1);
+ }));
- let location = this.get_value(iter, Columns.LOCATION);
- let variant = location.serialize();
+ let autoLocStack = builder.get_object('auto-location-stack');
- let newLocations = this._settings.get_value('locations').deep_unpack();
+ let autoLocSwitch = builder.get_object('auto-location-switch');
- for (let i = 0; i < newLocations.length; i++) {
- if (newLocations[i].equal(variant)) {
- newLocations.splice(i, 1);
- break;
- }
- }
+ let currentLocationController = application.currentLocationController;
- this._settings.set_value('locations', new GLib.Variant('av', newLocations));
- },
-});
+ let handlerId = autoLocSwitch.connect('notify::active', Lang.bind(this, function() {
+ currentLocationController.setAutoLocation(autoLocSwitch.get_active());
-const WorldIconView = new Lang.Class({
- Name: 'WorldView',
- Extends: Gd.MainView,
+ if (autoLocSwitch.get_active() && !this.model.addedCurrentLocation)
+ autoLocStack.set_visible_child_name('locating-label');
- _init: function(params) {
- params = Params.fill(params, { view_type: Gd.MainViewType.ICON });
- this.parent(params);
- this.get_accessible().accessible_name = _("Cities");
+ this.hide();
+ }));
- this.connect('selection-mode-request', Lang.bind(this, function() {
- this.selection_mode = true;
+ if(currentLocationController.autoLocation)
+ autoLocStack.set_visible_child_name('locating-label');
+ else {
+ autoLocStack.set_visible_child_name('auto-location-switch-grid');
+ GObject.signal_handler_block(autoLocSwitch, handlerId);
+ autoLocSwitch.set_active(false);
+ GObject.signal_handler_unblock(autoLocSwitch, handlerId);
+ }
+
+ listbox.connect('row-activated', Lang.bind(this, function(listbox, row) {
+ this.hide();
+ this.model.rowActivated(listbox, row);
}));
- }
-});
-const WorldContentView = new Lang.Class({
- Name: 'WorldContentView',
- Extends: Gtk.Bin,
- Properties: { 'empty': GObject.ParamSpec.boolean('empty', '', '', GObject.ParamFlags.READABLE, false) },
+ this.model.connect('current-location-changed', Lang.bind(this, function(model, location) {
+ autoLocStack.set_visible_child_name('auto-location-switch-grid');
+ if (location) {
+ this.model.addNewLocation(location, listbox, true);
- _init: function(model, params) {
- params = Params.fill(params, { hexpand: true, vexpand: true,
- halign: Gtk.Align.FILL, valign: Gtk.Align.FILL });
- this.parent(params);
- this.get_accessible().accessible_name = _("World view");
+ GObject.signal_handler_block(autoLocSwitch, handlerId);
+ autoLocSwitch.set_active(true);
+ GObject.signal_handler_unblock(autoLocSwitch, handlerId);
+ } else {
+ if (!this.model.addedCurrentLocation)
+ this.model.showRecent(listbox);
- this.iconView = new WorldIconView({ model: model, visible: true });
-
- this._placeHolder = new Gtk.Grid({ halign: Gtk.Align.CENTER,
- valign: Gtk.Align.CENTER,
- name: 'weather-page-placeholder',
- column_spacing: 6 });
- this._placeHolder.get_style_context().add_class('dim-label');
-
- let iconGrid = new Gtk.Grid({ row_spacing: 4, column_spacing: 4,
- valign: Gtk.Align.CENTER });
- iconGrid.attach(new Gtk.Image({ icon_name: 'weather-overcast-symbolic',
- icon_size: Gtk.IconSize.LARGE_TOOLBAR }),
- 0, 0, 1, 1);
- iconGrid.attach(new Gtk.Image({ icon_name: 'weather-few-clouds-symbolic',
- icon_size: Gtk.IconSize.LARGE_TOOLBAR }),
- 1, 0, 1, 1);
- iconGrid.attach(new Gtk.Image({ icon_name: 'weather-clear-symbolic',
- icon_size: Gtk.IconSize.LARGE_TOOLBAR }),
- 0, 1, 1, 1);
- iconGrid.attach(new Gtk.Image({ icon_name: 'weather-showers-symbolic',
- icon_size: Gtk.IconSize.LARGE_TOOLBAR }),
- 1, 1, 1, 1);
-
- this._placeHolder.attach(iconGrid, 0, 0, 1, 2);
-
- this._placeHolder.attach(new Gtk.Label({ name: 'weather-page-placeholder-title',
- label: _("Add locations"),
- xalign: 0.0 }),
- 1, 0, 1, 1);
- this._placeHolder.attach(new Gtk.Label({ label: _("Use the <b>New</b> button on the toolbar to add
more world locations"),
- use_markup: true,
- max_width_chars: 30,
- wrap: true,
- xalign: 0.0,
- halign: Gtk.Align.START,
- valign: Gtk.Align.START }),
- 1, 1, 1, 1);
- this._placeHolder.show_all();
-
- this.model = model;
- this._rowInsertedId = model.connect('row-inserted', Lang.bind(this, this._updateEmpty));
- this._rowDeletedId = model.connect('row-deleted', Lang.bind(this, this._updateEmpty));
-
- let [ok, ] = model.get_iter_first();
- if (ok)
- this.add(this.iconView);
- else
- this.add(this._placeHolder);
- this._empty = !ok;
+ GObject.signal_handler_block(autoLocSwitch, handlerId);
+ autoLocSwitch.set_active(false);
+ GObject.signal_handler_unblock(autoLocSwitch, handlerId);
- this.connect('destroy', Lang.bind(this, this._onDestroy));
- },
+ autoLocSwitch.set_sensitive(false);
+ }
+ }));
+
+ this.model.connect('validate-listbox', Lang.bind(this, function() {
+ listbox.invalidate_filter();
+ let children = listbox.get_children();
+ if (children.length == 1) {
+ stackPopover.set_visible_child_name("search-grid");
+ return;
+ }
+ stackPopover.set_visible_child_name("locations-grid");
+ }));
- get empty() {
- return this._empty;
+ listbox.set_filter_func(Lang.bind(this, this._filterListbox, this.model));
},
- _onDestroy: function() {
- if (this._rowInsertedId) {
- this.model.disconnect(this._rowInsertedId);
- this._rowInsertedId = 0;
- }
- if (this._rowDeletedId) {
- this.model.disconnect(this._rowDeletedId);
- this._rowDeletedId = 0;
+ _filterListbox: function(row, model) {
+ if(model.currentlyLoadedInfo) {
+ let cityName = Util.getLabelFromRow(row);
+ let loadedCity = model.currentlyLoadedInfo.location.get_city_name();
+ return (cityName != loadedCity);
}
+ return true;
},
- _updateEmpty: function() {
- let [ok, iter] = this.model.get_iter_first();
-
- if (!ok != this._empty) {
- if (ok) {
- this.remove(this._placeHolder);
- this.add(this.iconView);
- } else {
- this.remove(this.iconView);
- this.add(this._placeHolder);
- }
-
- this._empty = !ok;
- this.notify('empty');
+ _locationChanged: function(entry, listbox) {
+ if (entry.location) {
+ this.model.addNewLocation(entry.location, listbox, false);
+ this.hide();
+ entry.location = null;
}
}
});
+Signals.addSignalMethods(WorldModel.prototype);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]