1
// -*- Mode: js; indent-tabs-mode: nil; c-basic-offset: 4; tab-width: 4 -*-
3
// Copyright (c) 2012 Giovanni Campagna <scampa.giovanni@gmail.com>
5
// Gnome Weather is free software; you can redistribute it and/or modify
6
// it under the terms of the GNU General Public License as published by the
7
// Free Software Foundation; either version 2 of the License, or (at your
8
// option) any later version.
10
// Gnome Weather is distributed in the hope that it will be useful, but
11
// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15
// You should have received a copy of the GNU General Public License along
16
// with Gnome Weather; if not, write to the Free Software Foundation,
17
// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19
const Gtk = imports.gi.Gtk;
20
const GLib = imports.gi.GLib;
21
const Gnome = imports.gi.GnomeDesktop;
22
const Lang = imports.lang;
24
const Forecast = imports.app.forecast;
25
const WForecast = imports.app.weeklyForecast;
26
const Params = imports.misc.params;
27
const Util = imports.misc.util;
29
const SPINNER_SIZE = 128;
31
const WeatherWidget = new Lang.Class({
32
Name: 'WeatherWidget',
35
_init: function(params) {
36
params = Params.fill(params, { shadow_type: Gtk.ShadowType.NONE,
37
name: 'weather-page' });
40
this._currentStyle = null;
43
let builder = new Gtk.Builder();
44
builder.add_from_resource('/org/gnome/Weather/Application/city.ui');
46
let outerBox = builder.get_object('outer-box');
47
this._contentFrame = builder.get_object('content-frame');
48
this._outerGrid = builder.get_object('outer-grid');
49
this._forecastGrid = builder.get_object('forecast-grid');
50
this._wForecastFrame = builder.get_object('weekly-forecast-frame');
51
let forecastScrollingWindow = builder.get_object('forecast-scrolled-window');
52
this._icon = builder.get_object('conditions-image');
53
this._temperature = builder.get_object('temperature-label');
54
this._conditions = builder.get_object('conditions-label');
55
this.timeLabel = builder.get_object('time-label');
56
this.timeGrid = builder.get_object('time-grid');
57
this._dayStack = builder.get_object('day-stack');
58
this._leftButton = builder.get_object('left-button');
59
this._rightButton = builder.get_object('right-button');
61
this._forecasts = new Forecast.ForecastBox({ hexpand: false });
62
this._forecastGrid.attach(this._forecasts, 0, 0, 1, 1);
64
this._weeklyForecasts = new WForecast.WeeklyForecastFrame();
65
this._outerGrid.attach(this._weeklyForecasts, 1, 0, 1, 2);
67
this._hscrollbar = forecastScrollingWindow.get_hscrollbar();
68
this._hscrollbar.set_opacity(0.0);
70
this._hadjustment = forecastScrollingWindow.get_hadjustment();
72
this._hadjustment.connect('changed', Lang.bind(this, function() {
73
if ((this._hadjustment.get_upper() - this._hadjustment.get_lower()) == this._hadjustment.page_size) {
74
this._leftButton.set_sensitive(false);
75
this._rightButton.set_sensitive(false);
76
} else if (this._hadjustment.value == this._hadjustment.get_lower()){
77
this._leftButton.set_sensitive(false);
78
this._rightButton.set_sensitive(true);
79
} else if (this._hadjustment.value >= (this._hadjustment.get_upper() - this._hadjustment.page_size)){
80
this._leftButton.set_sensitive(true);
81
this._rightButton.set_sensitive(false);
83
this._leftButton.set_sensitive(true);
84
this._rightButton.set_sensitive(true);
88
this._dayStack.connect('notify::visible-child', Lang.bind(this, function() {
91
let forecasts = this._info.get_forecast_list();
92
this._forecasts.update(forecasts, this._dayStack.get_visible_child_name());
93
this._hadjustment.value = this._hadjustment.get_lower();
94
this._forecasts.show();
98
this._leftButton.connect('clicked', Lang.bind(this, function() {
99
this._target = this._hadjustment.value - this._hadjustment.page_size;
100
if (this._target <= this._hadjustment.get_lower()) {
101
this._leftButton.set_sensitive(false);
102
this._rightButton.set_sensitive(true);
104
this._rightButton.set_sensitive(true);
106
this._start = new Date().getTime();
107
this._end = this._start + 328;
108
this._tickId = this._forecastGrid.add_tick_callback(Lang.bind(this, this._animate));
111
this._rightButton.connect('clicked', Lang.bind(this, function() {
112
this._target = this._hadjustment.value + this._hadjustment.page_size;
113
if (this._target >= this._hadjustment.get_upper() - this._hadjustment.page_size) {
114
this._rightButton.set_sensitive(false);
115
this._leftButton.set_sensitive(true);
117
this._leftButton.set_sensitive(true);
119
this._start = new Date().getTime();
120
this._end = this._start + 328;
121
this._tickId = this._forecastGrid.add_tick_callback(Lang.bind(this, this._animate));
127
_animate: function() {
128
let value = this._hadjustment.value;
130
let now = new Date().getTime();
131
if (now < this._end) {
132
t = (now - this._start) / 700;
133
t = this._easeOutCubic (t);
134
this._hadjustment.value = value + t * (this._target - value);
137
this._hadjustment.value = value + t * (this._target - value);
138
this._forecastGrid.remove_tick_callback(this._tickId);
143
_easeOutCubic: function(value) {
144
let temp = value - 1;
145
return temp * temp * temp + 1;
149
this._forecasts.clear();
152
_get_style_class: function(info) {
153
let icon = info.get_icon_name();
154
let name = icon.replace(/(-\d{3})/, "");
158
update: function(info) {
161
this._conditions.label = Util.getWeatherConditions(info);
162
this._temperature.label = info.get_temp_summary();
164
this._icon.icon_name = info.get_symbolic_icon_name();
165
let context = this._contentFrame.get_style_context();
166
if (this._currentStyle)
167
context.remove_class(this._currentStyle);
168
this._currentStyle = this._get_style_class(info);
169
context.add_class(this._currentStyle);
171
let forecasts = info.get_forecast_list();
172
this._forecasts.update(forecasts, this._dayStack.get_visible_child_name());
173
this._forecasts.show();
175
if (forecasts.length == 0) {
176
this._weeklyForecasts.hide();
178
this._weeklyForecasts.show();
179
this._weeklyForecasts.update(forecasts);
184
const WeatherView = new Lang.Class({
188
_init: function(params) {
190
this.get_accessible().accessible_name = _("City view");
192
let loadingPage = new Gtk.Grid({ orientation: Gtk.Orientation.VERTICAL,
193
halign: Gtk.Align.CENTER,
194
valign: Gtk.Align.CENTER });
196
this._spinner = new Gtk.Spinner({ height_request: SPINNER_SIZE,
197
width_request: SPINNER_SIZE });
198
loadingPage.add(this._spinner);
199
loadingPage.add(new Gtk.Label({ label: _("Loading…"),
200
name: "loading-label" }));
201
this.add_named(loadingPage, 'loading');
203
this.infoPage = new WeatherWidget();
204
this.add_named(this.infoPage, 'info');
209
this.connect('destroy', Lang.bind(this, this._onDestroy));
211
this._wallClock = new Gnome.WallClock();
212
this._clockHandlerId = null;
220
if (this._updateId) {
221
this._info.disconnect(this._updateId);
224
this.infoPage.clear();
230
this._updateId = this._info.connect('updated',
231
Lang.bind(this, this._onUpdate));
233
this._onUpdate(info);
237
_onDestroy: function() {
238
if (this._updateId) {
239
this._info.disconnect(this._updateId);
245
this.visible_child_name = 'loading';
246
this._spinner.start();
247
this.infoPage.clear();
249
getApp().model.updateInfo(this._info);
252
_onUpdate: function(info) {
253
this.infoPage.clear();
254
this.infoPage.update(info);
256
this._spinner.stop();
257
this.visible_child_name = 'info';
260
connectClock: function() {
261
this._clockHandlerId = this._wallClock.connect('notify::clock', Lang.bind(this, this._updateTime));
264
_updateTime: function() {
265
this.infoPage.timeLabel.label = this._getTime();
268
_getTime: function() {
269
if (this._info != null) {
270
let location = this._info.location;
271
let tz = GLib.TimeZone.new(location.get_timezone().get_tzid());
272
let dt = GLib.DateTime.new_now(tz);
273
return dt.format(_("%H:%M"));
278
disconnectClock: function() {
279
if (this._clockHandlerId) {
280
this._wallClock.disconnect(this._clockHandlerId);
281
this._clockHandlerId = null;