Weather demo

This commit is contained in:
Max Lynch
2015-07-01 17:59:31 -05:00
parent 165b07275e
commit 7f2ae39f88
6 changed files with 484 additions and 0 deletions

View File

@ -0,0 +1,35 @@
import {Http} from 'ionic/net/http';
let FLICKR_API_KEY = '504fd7414f6275eb5b657ddbfba80a2c';
let baseUrl = 'https://api.flickr.com/services/rest/';
export class Flickr {
constructor() {
/*
var flickrSearch = $resource(baseUrl, {
method: 'flickr.groups.pools.getPhotos',
group_id: '1463451@N25',
safe_search: 1,
jsoncallback: 'JSON_CALLBACK',
api_key: FLICKR_API_KEY,
format: 'json'
}, {
get: {
method: 'JSONP'
}
});
*/
}
static search(tags, lat, lng) {
return new Promise((resolve, reject) => {
Http.get(baseUrl + '?method=flickr.groups.pools.getPhotos&group_id=1463451@N25&safe_search=1&api_key=' + FLICKR_API_KEY + '&format=json&tags=' + tags + '&lat=' + lat + '&lng=' + lng).then((val) => {
resolve(val);
}, (err) => {
reject(httpResponse);
})
})
}
}

View File

@ -0,0 +1,56 @@
export class Geo {
static reverseGeocode(lat, lng) {
return new Promise((resolve, reject) => {
let geocoder = new google.maps.Geocoder();
geocoder.geocode({
'latLng': new google.maps.LatLng(lat, lng)
}, (results, status) => {
if (status == google.maps.GeocoderStatus.OK) {
console.log('Reverse', results);
if(results.length > 1) {
var r = results[1];
var a, types;
var parts = [];
var foundLocality = false;
var foundState = false;
for(var i = 0; i < r.address_components.length; i++) {
a = r.address_components[i];
types = a.types;
for(var j = 0; j < types.length; j++) {
if(!foundLocality && types[j] == 'locality') {
foundLocality = true;
parts.push(a.long_name);
} else if(!foundState && types[j] == 'administrative_area_level_1') {
foundState = true;
parts.push(a.short_name);
}
}
}
console.log('Reverse', parts);
resolve(parts.join(', '));
}
} else {
console.log('reverse fail', results, status);
reject(results);
}
});
});
}
static getLocation() {
return new Promise((resolve, reject) => {
navigator.geolocation.getCurrentPosition((position) => {
resolve(position);
}, (error) => {
reject(error);
})
});
}
}

View File

@ -0,0 +1,123 @@
import {Component, Directive} from 'angular2/src/core/annotations_impl/annotations';
import {FormBuilder, Control, ControlGroup, Validators, formDirectives} from 'angular2/forms';
import {IonicView, Animation, Modal, NavController, NavParams, IonicComponent} from 'ionic/ionic';
import {Geo} from './geo';
import {Weather} from './weather';
import {Flickr} from './flickr';
console.log('Imported', Geo, Weather, Flickr);
@Component({
selector: 'ion-app',
appInjector: [Modal]
})
@IonicView({
templateUrl: 'main.html'
})
class WeatherApp {
constructor(Modal: Modal) {
this.Modal = Modal;
this.currentLocationString = 'Madison, WI';
this.current = {
local_tz_short: 'CDT'
};
this.activeBgImageIndex = 0;
/*
$ionicPlatform.ready(function() {
// Hide the status bar
if(window.StatusBar) {
StatusBar.hide();
}
});
*/
}
onInit() {
this.refreshData();
}
showSettings() {
this.Modal.show(SettingsModal).then((settingsModal) => {
this.settingsModal = settingsModal;
});
}
getBackgroundImage(lat, lng, locString) {
Flickr.search(locString, lat, lng).then((resp) => {
let photos = resp.photos;
if(photos.photo.length) {
this.bgImages = photos.photo;
this.cycleBgImages();
}
}, (error) => {
console.error('Unable to get Flickr images', error);
});
}
getCurrent(lat, lng, locString) {
Weather.getAtLocation(lat, lng).then((resp) => {
this.current = resp.data;
console.log('GOT CURRENT', this.current);
}, (error) => {
alert('Unable to get current conditions');
console.error(error);
});
}
cycleBgImages() {
setTimeout(() => {
if(this.bgImages) {
this.activeBgImage = this.bgImages[this.activeBgImageIndex++ % this.bgImages.length];
}
});
}
refreshData() {
Geo.getLocation().then((position) => {
let lat = position.coords.latitude;
let lng = position.coords.longitude;
Geo.reverseGeocode(lat, lng).then((locString) => {
this.currentLocationString = locString;
this.getBackgroundImage(lat, lng, locString);
});
this.getCurrent(lat, lng);
}, (error) => {
alert('Unable to get current location: ' + error);
});
}
}
/*
.controller('SettingsCtrl', function($scope, Settings) {
$scope.settings = Settings.getSettings();
// Watch deeply for settings changes, and save them
// if necessary
$scope.$watch('settings', function(v) {
Settings.save();
}, true);
$scope.closeSettings = function() {
$scope.modal.hide();
};
});
*/
@IonicComponent(Modal)
@IonicView({
template: '<ion-view id="settings-modal"><ion-content padding><button primary (click)="close()">Close</button></ion-content></ion-view>'
})
export class SettingsModal extends Modal {}
export function main(ionicBootstrap) {
ionicBootstrap(WeatherApp);
}

View File

@ -0,0 +1,18 @@
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false"></script>
<link rel="stylesheet" href="style.css">
<ion-view>
<ion-toolbar id="header" class="no-border">
<ion-title>
<span class="city"><i id="city-nav-icon" class="icon ion-navigate"></i> {{currentLocationString}}</span><br>
<current-time localtz="current.local_tz_short"></current-time>
</ion-title>
<button (^click)="showSettings()" class="toolbar-secondary-item"><i class="icon ion-ios-gear"></i></button>
</ion-toolbar>
<ion-content>
<div id="main-content">
<current-weather></current-weather>
<forecast></forecast>
</div>
</ion-content>
</ion-view>

View File

@ -0,0 +1,240 @@
body {
text-shadow: 1px 1px 0px rgba(0,0,0,0.5);
background-color: black;
}
#wrapper {
background-color: black;
}
#scroller {
}
.bg-image {
position: fixed;
width: 120%;
height: 120%;
background-size: cover;
}
.bg-fade > .ng-enter {
opacity: 0;
-webkit-transition: opacity 2s ease-in-out;
}
.bg-fade > .ng-enter-active {
opacity: 1;
}
.bg-fade > .ng-leave {
opacity: 1;
-webkit-transition: opacity 2s ease-in-out;
}
.bg-fade > .ng-leave-active {
opacity: 0;
}
.wunderground-logo {
width: 100px;
height: 14px;
background: url('../img/wunderground.png') no-repeat transparent;
}
@media only screen and (-webkit-min-device-pixel-ratio: 2) {
.wunderground-logo {
background: url('../img/wunderground@2x.png') no-repeat transparent;
background-size: 100px 14px;
}
}
h1,h2,h3,h4,h5 {
color: #fff;
font-weight: 300;
}
#main-content {
color: #fff;
padding: 10px;
}
.ion-ios7-sunny-outline {
color: yellow;
}
.ionic-refresher-content {
color: rgb(255,255,255) !important;
text-shadow: none;
}
/**
* Header
*/
#header {
background-color: transparent !important;
height: 44px;
}
#header > * {
margin-top: 0;
}
#header .title {
font-size: 12px;
line-height: 20px;
margin-top: 4px;
}
#header .title .city {
font-size: 16px;
}
#city-nav-icon {
font-size: 11px;
margin-right: 2px;
}
.scroll-refresher {
overflow: visible;
}
.ionic-refresher-content {
background-color: rgba(0,0,0,0.4);
height: 400px;
bottom: 0;
}
.ionic-refresher-content i {
margin-top: 360px;
}
/**
* Current weather
*/
#current-weather {
height: 180px;
box-sizing: content-box;
}
#current-weather > * {
color: #fff;
}
#current-weather .current-temp {
font-size: 100px;
font-weight: 100;
margin: 0;
padding: 0;
line-height: 80px;
}
#current-icon {
font-size: 42px;
vertical-align: middle;
margin-right: 5px;
}
#temp-hi, #temp-lo { display: inline-block; }
#temp-lo {
margin-left: 10px;
}
/**
* Forecast and details
*/
.weather-box {
background-color: rgba(0,0,0,0.2);
padding: 9px;
margin: 10px 0px;
color: rgba(255,255,255,0.9);
}
.weather-box .title {
color: rgba(255,255,255,0.9);
font-weight: normal;
margin: 0;
padding-bottom: 5px;
border-bottom: 1px solid #fff;
}
.weather-box .row {
border-bottom: 1px dotted rgba(255,255,255,0.3);
margin: 0;
padding: 0;
}
.weather-box .col {
text-align: center;
}
.weather-box .col:first-child {
text-align: left;
}
.weather-box .col:last-child {
text-align: right;
}
.weather-box span {
vertical-align: middle;
}
.weather-box .icon {
font-size: 42px;
line-height: 24px;
vertical-align: middle;
}
.temp-high {
display: inline-block;
width: 30px;
text-align: right;
}
.temp-low {
display: inline-block;
width: 30px;
text-align: right;
color: #4a87ee;
}
.no-header {
top: 0 !important;
}
#forecast-scroll {
margin: 10px 0px;
}
#hourly-forecast {
width: 2250px;
height: 70px;
}
.hourly-hour {
display: inline-block;
margin-right: 10px;
text-align: center;
}
#forecast .credit {
float: right;
margin-top: 4px;
margin-right: 4px;
}
#forecast .credit a {
color: #fff;
}
/**
* Settings modal
*/
#settings-modal {
background-color: rgba(0,0,0,0.8);
}
#settings-modal .item {
background-color: rgba(0,0,0,0.9);
border: none;
color: #fff;
}
#settings-modal .input-label {
color: #fff;
}
ion-view {
background-color: black !important;
}
ion-content {
background-color: black !important;
}
#header {
background: transparent;
color: #fff;
}

View File

@ -0,0 +1,12 @@
import {Http} from 'ionic/net/http';
let WUNDERGROUND_API_KEY = '1cc2d3de40fa5af0';
let FORECASTIO_KEY = '4cd3c5673825a361eb5ce108103ee84a';
export class Weather {
static getAtLocation(lat, lng) {
let url = 'https://api.forecast.io/forecast/' + FORECASTIO_KEY + '/';
return Http.get(url + lat + ',' + lng);
}
}