diff --git a/ionic/components/app/test/weather/flickr.js b/ionic/components/app/test/weather/flickr.js
new file mode 100644
index 0000000000..6cb32d9964
--- /dev/null
+++ b/ionic/components/app/test/weather/flickr.js
@@ -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);
+ })
+ })
+ }
+}
diff --git a/ionic/components/app/test/weather/geo.js b/ionic/components/app/test/weather/geo.js
new file mode 100644
index 0000000000..c56b15e3e8
--- /dev/null
+++ b/ionic/components/app/test/weather/geo.js
@@ -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);
+ })
+ });
+ }
+}
diff --git a/ionic/components/app/test/weather/index.js b/ionic/components/app/test/weather/index.js
new file mode 100644
index 0000000000..01d0cdda66
--- /dev/null
+++ b/ionic/components/app/test/weather/index.js
@@ -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: ''
+})
+export class SettingsModal extends Modal {}
+
+export function main(ionicBootstrap) {
+ ionicBootstrap(WeatherApp);
+}
diff --git a/ionic/components/app/test/weather/main.html b/ionic/components/app/test/weather/main.html
new file mode 100644
index 0000000000..615b07d5b2
--- /dev/null
+++ b/ionic/components/app/test/weather/main.html
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ionic/components/app/test/weather/style.css b/ionic/components/app/test/weather/style.css
new file mode 100644
index 0000000000..40bf576d32
--- /dev/null
+++ b/ionic/components/app/test/weather/style.css
@@ -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;
+}
diff --git a/ionic/components/app/test/weather/weather.js b/ionic/components/app/test/weather/weather.js
new file mode 100644
index 0000000000..0cefbe41c7
--- /dev/null
+++ b/ionic/components/app/test/weather/weather.js
@@ -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);
+ }
+}