Snippets

Kevin Armstrong Weather Display

You are viewing an old version of this snippet. View the current version.
Revised by Kevin Armstrong 7dd9337
import 'dart:convert';
import 'package:intl/intl.dart';
import 'package:flutter/material.dart';
import 'package:fluids/plugins/weather/models/models.dart';
import 'package:fluids/utils/md_icons.dart';

class CityForecast extends StatelessWidget {
  final GlobalKey<AnimatedListState> _listKey = GlobalKey<AnimatedListState>();
  final String city;
  final String state;
  final Forecast forecast;

  CityForecast({this.city, this.state, this.forecast});

  @override
  Widget build(BuildContext context) {
    final int contentHgt = 240;
    double imageHeight = MediaQuery.of(context).size.height - contentHgt;
    return Stack(
      children: <Widget>[
        new Positioned(
          child: Image.network(
            weatherImage,
            fit: BoxFit.cover,
          ),
          height: imageHeight,
          top: 0.0,
          left: 0.0,
          right: 0.0,
        ),
        new Scaffold(
          appBar: new AppBar(
            backgroundColor: Colors.transparent,
            elevation: 0.0,
          ),
          backgroundColor: Colors.transparent,
          body: new Column(
            mainAxisAlignment: MainAxisAlignment.end,
            children: <Widget>[
              _makeWeatherRow(context),
              Container(
                height: contentHgt.toDouble(),
                color: Colors.white,
                child: new SafeArea(
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.start,
                    children: <Widget>[
                      _makeWeatherExtra(context),
                      Expanded(
                        child: AnimatedList(
                          key: _listKey,
                          initialItemCount: forecast.daily.length,
                          scrollDirection: Axis.horizontal,
                          itemBuilder: (BuildContext context, int index, animation){
                            return _makeDay(context, animation, forecast.daily[index]);
                          },
                        ),
                      )
                    ],
                  ),
                ),
              )
            ],
          ),
        ),
      ],
    );
  }

  _makeDay(BuildContext context, animation, Weather w){
    return FadeTransition(
      opacity: animation,
      child: SizeTransition(
        sizeFactor: animation,
        child: new Container(
          width: 120.0,
          decoration: BoxDecoration(
            border: Border(right: BorderSide(width: 1.0, color: Colors.black26)),
          ),
          margin: EdgeInsets.symmetric(vertical: 10.0),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text(DateFormat('EEE').format(w.dateTime).toUpperCase()),
              Expanded(
                child: Icon(w.mcIcon, size: 40.0,),
              ),
              Text('${w.temperatureMax.round()} / ${w.temperatureMin.round()}', style: Theme.of(context).textTheme.title,),
            ],
          ),
        ),
      ),
    );
  }

  _makeWeatherRow(context) {
    Weather current = forecast != null && forecast.currently != null ? forecast.currently : null;
    return current == null ? Container() : Container(
      color: Colors.black45,
      padding: EdgeInsets.all(20.0),
      child: new Column(
        children: <Widget>[
          new Row(
            crossAxisAlignment: CrossAxisAlignment.center,
            children: <Widget>[
              Row(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: <Widget>[
                  Text(current.temperature.toStringAsFixed(0), style: Theme.of(context).textTheme.display2.copyWith(color: Colors.white),),
                  Icon(MDIcons.temperature_fahrenheit, color: Colors.white, size: 30.0,),
                ],
              ),
              new Expanded(
                child: Container(
                  alignment: Alignment.center,
                  padding: const EdgeInsets.only(right: 30.0),
                  child: Icon(current.mcIcon, color: Colors.white, size: 60.0,),
                ),
              ),
              Column(
                crossAxisAlignment: CrossAxisAlignment.end,
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  Text('$city, $state'.toUpperCase(), style: Theme.of(context).textTheme.title.copyWith(color: Colors.white),),
                  Text(DateFormat('EEEEE, MMMM d').format(DateTime.now()).toUpperCase(), style: Theme.of(context).textTheme.body1.copyWith(color: Colors.white),),
                ],
              )
            ],
          ),
          _makeWeatherSummary(context),
        ],
      ),
    );
  }

  _makeWeatherExtra(BuildContext context) {
    Weather current = forecast != null && forecast.currently != null ? forecast.currently : null;
    return current == null ? Container() : Container(
      child: Column(
        children: <Widget>[
          Container(
            padding: const EdgeInsets.all(15.0),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: <Widget>[
                _makeExtraInfoStat(context, MDIcons.flag_variant_outline, '${current.windSpeed.round()} MPH'),
                _makeExtraInfoStat(context, MDIcons.compass_outline, '${current.windDirection}'),
                _makeExtraInfoStat(context, MDIcons.umbrella_outline, '${current.precipitationProbability.round()}%'),
              ],
            ),
          ),
          Divider(),
        ],
      ),
    );
  }

  _makeExtraInfoStat(BuildContext context, IconData icon, String info){
    return Row(
      children: <Widget>[
        Icon(icon),
        Text(info.toUpperCase(), style: Theme.of(context).textTheme.title,),
      ],
    );
  }

  _makeWeatherSummary(BuildContext context) {
    String summary = Utf8Codec().decode(forecast.dailySummary.codeUnits);
    return Container(
      child: Column(
        children: <Widget>[
          Container(
            padding: const EdgeInsets.only(top: 10.0),
            child: Text(
              summary,
              style: Theme.of(context).textTheme.body1.copyWith(color: Colors.white),
            ),
          ),
        ],
      ),
    );
  }
}
import './weather.dart';

class Forecast {
  final num latitude;
  final num longitude;
  final String timezone;
  final Weather currently;
  final List<Weather> minutely;
  final List<Weather> hourly;
  final List<Weather> daily;
  final String dailySummary;
  final String dailyIcon;
  final String hourlySummary;
  final String hourlyIcon;
  final String minutelySummary;
  final String minutelyIcon;

  Forecast({
    this.latitude: 0.0,
    this.longitude: 0.0,
    this.timezone: '',
    this.currently,
    this.minutely: const [],
    this.hourly: const [],
    this.daily: const [],
    this.dailyIcon: '',
    this.dailySummary: '',
    this.hourlyIcon: '',
    this.hourlySummary: '',
    this.minutelyIcon: '',
    this.minutelySummary: '',
  });

  static Forecast fromMap(Map<String, dynamic> map){
    bool hasMinutely = map['minutely'] != null;
    bool hasHourly = map['hourly'] != null;
    bool hasDaily = map['daily'] != null;
    var minutely = [];
    String minutelyIcon = '';
    String minutelySummary = '';
    var hourly = [];
    String hourlyIcon = '';
    String hourlySummary = '';
    var daily = [];
    String dailyIcon = '';
    String dailySummary = '';
    Weather currently;

    if(hasMinutely){
      List items = map['minutely']['data'] ?? [];
      minutely = items.map((item) => Weather.fromMap(item)).toList();
      minutelyIcon = map['minutely']['icon'] ?? '';
      minutelySummary = map['minutely']['summary'] ?? '';
    }
    if(hasHourly){
      List items = map['hourly']['data'] ?? [];
      hourly = items.map((item) => Weather.fromMap(item)).toList();
      hourlyIcon = map['hourly']['icon'] ?? '';
      hourlySummary = map['hourly']['summary'] ?? '';
    }
    if(hasDaily){
      List items = map['daily']['data'] ?? [];
      daily = items.map((item) => Weather.fromMap(item)).toList();
      dailyIcon = map['daily']['icon'] ?? '';
      dailySummary = map['daily']['summary'] ?? '';
    }
    if(map['currently'] != null){
      currently = Weather.fromMap(map['currently']);
    }
    return new Forecast(
      latitude: map['latitude'] ?? 0.0,
      longitude: map['longitude'] ?? 0.0,
      timezone: map['timezone'] ?? '',
      currently: currently,
      minutely: minutely,
      hourly: hourly,
      daily: daily,
      minutelyIcon: minutelyIcon,
      hourlyIcon: hourlyIcon,
      dailyIcon: dailyIcon,
      minutelySummary: minutelySummary,
      hourlySummary: hourlySummary,
      dailySummary: dailySummary,
    );
  }

  Forecast copyWith({
    num latitude,
    num longitude,
    String timezone,
    Weather currently,
    List minutely,
    List hourly,
    List daily,
    String dailyIcon,
    String dailySummary,
    String hourlyIcon,
    String hourlySummary,
    String minutelyIcon,
    String minutelySummary,
  }){
    return new Forecast(
      latitude: latitude ?? this.latitude,
      longitude: longitude ?? this.longitude,
      timezone: timezone ?? this.timezone,
      currently: currently ?? this.currently,
      minutely: minutely ?? this.minutely,
      hourly: hourly ?? this.hourly,
      daily: daily ?? this.daily,
      minutelyIcon: minutelyIcon ?? this.minutelyIcon,
      hourlyIcon: hourlyIcon ?? this.hourlyIcon,
      dailyIcon: dailyIcon ?? this.dailyIcon,
      minutelySummary: minutelySummary ?? this.minutelySummary,
      hourlySummary: hourlySummary ?? this.hourlySummary,
      dailySummary: dailySummary ?? this.dailySummary,
    );
  }

  double get currentDayMax {
    if(daily.isNotEmpty){
      Weather today = daily[0];
      return today.temperatureHigh;
    }
    return 0.0;
  }
  double get currentDayMin {
    if(daily.isNotEmpty){
      Weather today = daily[0];
      return today.temperatureLow;
    }
    return 0.0;
  }
}
import 'package:flutter/widgets.dart';
import 'package:fluids/helpers/mdicons.dart';

class Weather {
  String summary = "";
  String icon = "";
  String precipitationType = "";
  num time = 0;
  num sunriseTime = 0;
  num sunsetTime = 0;
  num temperatureHighTime = 0;
  num temperatureLowTime = 0;
  num apparentTemperatureHighTime = 0;
  num apparentTemperatureLowTime = 0;
  num nearestStormDistance = 0;
  num nearestStormBearing = 0;
  num precipitationIntensity = 0;
  num precipitationProbability = 0;
  num windBearing = 0;
  num uvIndex = 0;
  num temperature = 0.0;
  num temperatureHigh = 0.0;
  num temperatureLow = 0.0;
  num apparentTemperature = 0.0;
  num apparentTemperatureHigh = 0.0;
  num apparentTemperatureLow = 0.0;
  num dewPoint = 0.0;
  num humidity = 0.0;
  num windSpeed = 0.0;
  num windGust = 0.0;
  num visibility = 0.0;
  num cloudCover = 0.0;
  num pressure = 0.0;
  num ozone = 0.0;
  num moonPhase = 0.0;

  Weather({this.summary, this.icon, this.precipitationType, this.time,
    this.sunriseTime, this.sunsetTime, this.temperatureHighTime,
    this.temperatureLowTime, this.apparentTemperatureHighTime,
    this.apparentTemperatureLowTime, this.nearestStormDistance,
    this.nearestStormBearing, this.precipitationIntensity,
    this.precipitationProbability, this.windBearing, this.uvIndex,
    this.temperature, this.temperatureHigh, this.temperatureLow, this.apparentTemperature,
    this.apparentTemperatureHigh, this.apparentTemperatureLow,
    this.dewPoint, this.humidity, this.windSpeed, this.windGust, this.visibility,
    this.cloudCover, this.pressure, this.ozone, this.moonPhase});

  static Weather fromMap(Map<String, dynamic> map){
    return new Weather(
      summary: map['summary'] ?? '',
      icon: map['icon'] == null ? '' : map['icon'],
      precipitationType: map['precipType'] == null ? '' : map['precipType'],
      time: map['time'] == null ? 0 : map['time'],
      sunriseTime: map['sunriseTime'] == null ? 0 : map['sunriseTime'],
      sunsetTime: map['sunsetTime'] == null ? 0 : map['sunsetTime'],
      temperatureHighTime: map['temperatureHighTime'] == null ? 0 : map['temperatureHighTime'],
      temperatureLowTime: map['temperatureLowTime'] == null ? 0 : map['temperatureLowTime'],
      apparentTemperatureHighTime: map['apparentTemperatureHighTime'] == null ? 0 : map['apparentTemperatureHighTime'],
      apparentTemperatureLowTime: map['apparentTemperatureLowTime'] == null ? 0 : map['apparentTemperatureLowTime'],
      nearestStormDistance: map['nearestStormDistance'] == null ? 0 : map['nearestStormDistance'],
      nearestStormBearing: map['nearestStormBearing'] == null ? 0 : map['nearestStormBearing'],
      precipitationIntensity: map['precipIntensity'] == null ? 0 : map['precipIntensity'],
      precipitationProbability: map['precipProbability'] == null ? 0 : map['precipProbability'],
      windBearing: map['windBearing'] == null ? 0 : map['windBearing'],
      uvIndex: map['uvIndex'] == null ? 0 : map['uvIndex'],
      temperature: map['temperature'] == null ? 0.0 : map['temperature'],
      apparentTemperature: map['apparentTemperature'] == null ? 0.0 : map['apparentTemperature'],
      temperatureHigh: map['temperatureHigh'] == null ? 0.0 : map['temperatureHigh'],
      temperatureLow: map['temperatureLow'] == null ? 0.0 : map['temperatureLow'],
      apparentTemperatureHigh: map['apparentTemperatureHigh'] == null ? 0.0 : map['apparentTemperatureHigh'],
      apparentTemperatureLow: map['apparentTemperatureLow'] == null ? 0.0 : map['apparentTemperatureLow'],
      dewPoint: map['dewPoint'] == null ? 0.0 : map['dewPoint'],
      humidity: map['humidity'] == null ? 0.0 : map['humidity'],
      windSpeed: map['windSpeed'] == null ? 0.0 : map['windSpeed'],
      windGust: map['windGust'] == null ? 0.0 : map['windGust'],
      visibility: map['visibility'] == null ? 0.0 : map['visibility'],
      cloudCover: map['cloudCover'] == null ? 0.0 : map['cloudCover'],
      pressure: map['pressure'] == null ? 0.0 : map['pressure'],
      ozone: map['ozone'] == null ? 0.0 : map['ozone'],
      moonPhase: map['moonPhase'] == null ? 0.0 : map['moonPhase'],
    );
  }

  num get temperatureFahrenheit => temperature.round();

  num get temperatureCelcius => ((temperature - 32) * (5/9)).round();

  num get feelsLikeFahrenheit => apparentTemperature.round();

  num get feelsLikeCelcius => ((apparentTemperature - 32) * (5/9)).round();

  IconData get mcIcon {
    switch(icon){
      case "clear-day":
        return MDIcons.weather_sunny;
      case "clear-night":
        return MDIcons.weather_night;
      case "rain":
        return MDIcons.weather_pouring;
      case "snow":
        return MDIcons.weather_snowy;
      case "sleet":
        return MDIcons.weather_snowy_rainy;
      case "wind":
        return MDIcons.weather_windy;
      case "fog":
        return MDIcons.weather_fog;
      case "cloudy":
        return MDIcons.weather_cloudy;
      case "partly-cloudy-day":
        return MDIcons.weather_partlycloudy;
      case "partly-cloudy-night":
        return MDIcons.weather_cloudy;
      default:
        return MDIcons.thermometer;
    }
  }
  String get windDirection {
    num val = ((windBearing / 22.5) + 0.5).floor();
    List<String> directions = ["N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW"];
    return directions[(val % 16)];
  }
  DateTime get dateTime => DateTime.fromMillisecondsSinceEpoch(time*1000);
  DateTime get sunriseDateTime => DateTime.fromMillisecondsSinceEpoch(sunriseTime*1000);
  DateTime get sunsetDateTime => DateTime.fromMillisecondsSinceEpoch(sunsetTime*1000);
  DateTime get temperatureHighDateTime => DateTime.fromMillisecondsSinceEpoch(temperatureHighTime*1000);
  DateTime get temperatureLowDateTime => DateTime.fromMillisecondsSinceEpoch(temperatureLowTime*1000);
  String get precipitationPercent => '${(precipitationProbability * 100).round()}%';
  String get humidityPercent => '${(humidity * 100).round()}%';
}
HTTPS SSH

You can clone a snippet to your computer for local editing. Learn more.