diff --git a/pkg/arvo/app/weather.hoon b/pkg/arvo/app/weather.hoon index 684956b151..31e0b00d27 100644 --- a/pkg/arvo/app/weather.hoon +++ b/pkg/arvo/app/weather.hoon @@ -83,7 +83,7 @@ ?. ?=(%s -.jon) [~ state] =/ str=@t +.jon - =/ req=request:http (request-darksky str) + =/ req=request:http (request-wttr str) =/ out *outbound-config:iris =/ lismov=(list card) [%pass /[(scot %da now.bol)] %arvo %i %request req out]~ @@ -102,11 +102,11 @@ ^- (list card) [%give %fact ~[/all] %json !>((frond:enjs:format %location jon))]~ :: -++ request-darksky +++ request-wttr |= location=@t ^- request:http - =/ base 'https://api.darksky.net/forecast/634639c10670c7376dc66b6692fe57ca/' - =/ url=@t (cat 3 (cat 3 base location) '?units=auto') + =/ base 'https://wttr.in/' + =/ url=@t (cat 3 (cat 3 base location) '?format=j1') =/ hed [['Accept' 'application/json']]~ [%'GET' url hed *(unit octs)] :: @@ -133,8 +133,9 @@ =/ jon=json %+ frond:enjs:format %weather %- pairs:enjs:format - :~ [%currently (~(got by p.u.ujon) 'currently')] - [%daily (~(got by p.u.ujon) 'daily')] + :~ [%current-condition (~(got by p.u.ujon) 'current_condition')] + [%weather (~(got by p.u.ujon) 'weather')] + [%nearest-area (~(got by p.u.ujon) 'nearest_area')] == :- [%give %fact ~[/all] %json !>(jon)]~ %= state @@ -146,7 +147,7 @@ |= [wir=wire err=(unit tang)] ^- (quip card _state) ?~ err - =/ req/request:http (request-darksky location) + =/ req/request:http (request-wttr location) =/ out *outbound-config:iris :_ state(timer `(add now.bol ~h3)) :~ [%pass /[(scot %da now.bol)] %arvo %i %request req out] diff --git a/pkg/interface/src/logic/api/launch.ts b/pkg/interface/src/logic/api/launch.ts index bbe49db730..ce0a09a1c0 100644 --- a/pkg/interface/src/logic/api/launch.ts +++ b/pkg/interface/src/logic/api/launch.ts @@ -18,8 +18,8 @@ export default class LaunchApi extends BaseApi { return this.launchAction({ 'change-is-shown': { name, isShown }}); } - weather(latlng: any) { - return this.action('weather', 'json', latlng); + weather(location: string) { + return this.action('weather', 'json', location); } private launchAction(data) { diff --git a/pkg/interface/src/views/apps/launch/components/tiles/weather.js b/pkg/interface/src/views/apps/launch/components/tiles/weather.js index b973e37292..9dd62c8090 100644 --- a/pkg/interface/src/views/apps/launch/components/tiles/weather.js +++ b/pkg/interface/src/views/apps/launch/components/tiles/weather.js @@ -1,14 +1,43 @@ import React from 'react'; import moment from 'moment'; import { Box, Icon, Text, BaseAnchor, BaseInput } from '@tlon/indigo-react'; +import ErrorBoundary from '~/views/components/ErrorBoundary'; import Tile from './tile'; +export const weatherStyleMap = { + Sunny: 'rgba(67, 169, 255, 0.4)', + PartlyCloudy: 'rgba(178, 211, 255, 0.33)', + Cloudy: 'rgba(136, 153, 176, 0.43)', + VeryCloudy: 'rgba(78, 90, 106, 0.43)', + Fog: 'rgba(100, 119, 128, 0.12)', + LightShowers: 'rgba(121, 148, 185, 0.33)', + LightSleetShowers: 'rgba(114, 130, 153, 0.33)', + LightSleet: 'rgba(155, 164, 177, 0.33)', + ThunderyShowers: 'rgba(53, 77, 103, 0.33)', + LightSnow: 'rgba(179, 182, 200, 0.33)', + HeavySnow: 'rgba(179, 182, 200, 0.33)', + LightRain: 'rgba(58, 79, 107, 0.33)', + HeavyShowers: 'rgba(36, 54, 77, 0.33)', + HeavyRain: 'rgba(5, 9, 13, 0.39)', + LightSnowShowers: 'rgba(174, 184, 198, 0.33)', + HeavySnowShowers: 'rgba(55, 74, 107, 0.33)', + ThunderyHeavyRain: 'rgba(45, 56, 66, 0.61)', + ThunderySnowShowers: 'rgba(40, 54, 79, 0.46)', + default: 'transparent' +}; + +const imperialCountries = [ + 'United States of America', + 'Myanmar', + 'Liberia', +]; + export default class WeatherTile extends React.Component { constructor(props) { super(props); this.state = { - latlong: '', + location: '', manualEntry: false, error: false }; @@ -17,89 +46,45 @@ export default class WeatherTile extends React.Component { // geolocation and manual input functions locationSubmit() { navigator.geolocation.getCurrentPosition((res) => { - const latlng = `${res.coords.latitude},${res.coords.longitude}`; + const location = `${res.coords.latitude},${res.coords.longitude}`; this.setState({ - latlng + location }, (err) => { console.log(err); }, { maximumAge: Infinity, timeout: 10000 }); - this.props.api.launch.weather(latlng); + this.props.api.launch.weather(location); this.setState({ manualEntry: !this.state.manualEntry }); }); } - manualLocationSubmit() { + manualLocationSubmit(event) { event.preventDefault(); - const gpsInput = document.getElementById('gps'); - const latlngNoSpace = gpsInput.value.replace(/\s+/g, ''); - const latlngParse = /-?[0-9]+(?:\.[0-9]*)?,-?[0-9]+(?:\.[0-9]*)?/g; - if (latlngParse.test(latlngNoSpace)) { - const latlng = latlngNoSpace; - this.setState({ latlng }, (err) => { + const location = document.getElementById('location').value; + this.setState({ location }, (err) => { console.log(err); }, { maximumAge: Infinity, timeout: 10000 }); - this.props.api.launch.weather(latlng); + this.props.api.launch.weather(location); this.setState({ manualEntry: !this.state.manualEntry }); - } else { - this.setState({ error: true }); - return false; - } } - // set appearance based on weather - setColors(data) { - let weatherStyle = { - bg: '', - text: '' - }; - switch (data.currently.icon) { - case 'clear-day': - weatherStyle = { bg: '#E9F5FF', text: '#333' }; - break; - case 'clear-night': - weatherStyle = { bg: '#14263C', text: '#fff' }; - break; - case 'rain': - weatherStyle = { bg: '#2E1611', text: '#fff' }; - break; - case 'snow': - weatherStyle = { bg: '#F9F9FB', text: '#333' }; - break; - case 'sleet': - weatherStyle = { bg: '#EFF1F3', text: '#333' }; - break; - case 'wind': - weatherStyle = { bg: '#F7FEF6', text: '#333' }; - break; - case 'fog': - weatherStyle = { bg: '#504D44', text: '#fff' }; - break; - case 'cloudy': - weatherStyle = { bg: '#EEF1F5', text: '#333' }; - break; - case 'partly-cloudy-day': - weatherStyle = { bg: '#F3F6FA', text: '#333' }; - break; - case 'partly-cloudy-night': - weatherStyle = { bg: '#283442', text: '#fff' }; - break; - default: - weatherStyle = { bg: 'white', text: 'black' }; - } - return weatherStyle; + // set appearance based on weather + colorFromCondition(data) { + let weatherDesc = data['current-condition'][0].weatherDesc[0].value; + return weatherStyleMap[weatherDesc] || weatherStyleMap.default; } + // all tile views - renderWrapper(child, - weatherStyle = { bg: 'white', text: 'black' } - ) { + renderWrapper(child, backgroundColor = 'white') { return ( - - {child} - + + + {child} + + ); } - renderManualEntry() { + renderManualEntry(data) { let secureCheck; let error; if (this.state.error === true) { @@ -114,6 +99,10 @@ export default class WeatherTile extends React.Component { ); } + let locationName; + if ('nearest-area' in data) { + locationName = data['nearest-area'][0].areaName[0].value; + } return this.renderWrapper( {secureCheck} - Please enter your{' '} - - latitude and longitude - - . + Please enter your location. + {locationName ? ` Current location is near ${locationName}.` : ''} {error} { if (e.key === 'Enter') { - e.preventDefault(); - this.manualLocationSubmit(e.target.value); + this.manualLocationSubmit(e); } }} /> @@ -171,7 +152,7 @@ export default class WeatherTile extends React.Component { fontSize='0' border='0' type="submit" - onClick={() => this.manualLocationSubmit()} + onClick={this.manualLocationSubmit.bind(this)} value="->" /> @@ -182,7 +163,6 @@ export default class WeatherTile extends React.Component { renderNoData() { return this.renderWrapper( 24) { @@ -220,6 +202,10 @@ export default class WeatherTile extends React.Component { ? `Sun sets in ${sunsetDiff}h` : `Sun rises in ${sunriseDiff}h`; + const temp = data['nearest-area'] && imperialCountries.includes(data['nearest-area'][0].country[0].value) + ? `${Math.round(c.temp_F)}℉` + : `${Math.round(c.temp_C)}℃`; + return this.renderWrapper( - - + + Weather this.setState({ manualEntry: !this.state.manualEntry }) @@ -248,24 +234,22 @@ export default class WeatherTile extends React.Component { display="flex" flexDirection="column" > - {c.summary} - {Math.round(c.temperature)}° - {nextSolarEvent} + {c.weatherDesc[0].value.replace(/([a-z])([A-Z])/g, '$1 $2')} + {temp} + {nextSolarEvent} - - , weatherStyle); + , bg); } render() { const data = this.props.weather ? this.props.weather : {}; if (this.state.manualEntry === true) { - return this.renderManualEntry(); + return this.renderManualEntry(data); } - if ('currently' in data && 'daily' in data) { - const weatherStyle = this.setColors(data); - return this.renderWithData(data, weatherStyle); + if ('current-condition' in data && 'weather' in data) { + return this.renderWithData(data); } if (this.props.location) {