Clima Flutter Weather App


An app that detects current location latitude and longitude, then fetch weather temperature for current city, also you can search for any city.


pubsec.yml

nameclima
descriptionA new Flutter application.

version1.0.0+1

environment:
  sdk">=2.1.0 <3.0.0"

dependencies:
  flutter:
    sdkflutter

  cupertino_icons^0.1.2
  geolocator^5.1.5
  http^0.12.0+2
  flutter_spinkit^4.1.0

dev_dependencies:
  flutter_test:
    sdkflutter

flutter:
  uses-material-designtrue

  assets:
  - images/

  fonts:
  - familySpartan MB
    fonts:
    - assetfonts/SpartanMB-Black.otf
      weight900

lib/main.dart

import 'package:flutter/material.dart';
import 'package:clima/screens/loading_screen.dart';


void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData.dark(),
      home: LoadingScreen(),
    );
  }
}

lib/screens/loading_screen.dart

import 'package:flutter/material.dart';
import 'package:clima/screens/location_screen.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:clima/services/weather.dart';



class LoadingScreen extends StatefulWidget {
  @override
  _LoadingScreenState createState() => _LoadingScreenState();
}

class _LoadingScreenState extends State<LoadingScreen> {


 @override
 void initState(){
   super.initState();

   getWeather();
 }


 void getWeather() async{
      var weatherData = await WeatherModel().getWeatherLocation();
      Navigator.push(context, MaterialPageRoute(builder: (context) => LocationScreen(weatherData: weatherData)));
    }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      resizeToAvoidBottomInset: false,
      body: Builder(
        builder: (context) => Center(
          child: SpinKitWave(
            color: Colors.white,
            size: 40,
          ),
        ),
      ),
    );
  }
}


lib/screens/location_screen.dart

import 'package:clima/screens/city_screen.dart';
import 'package:flutter/material.dart';
import 'package:clima/utilities/constants.dart';
import 'package:clima/services/weather.dart';

class LocationScreen extends StatefulWidget {
  LocationScreen({this.weatherData});

  final weatherData;

  @override
  _LocationScreenState createState() => _LocationScreenState();
}

class _LocationScreenState extends State<LocationScreen> {
  int temperature;
  int condition;
  String cityName;

  String cityIcon;
  String weatherMessage;

  @override
  void initState(){
    super.initState();
    updateUI(widget.weatherData);
  }

  updateUI(dynamic weatherData){
    setState(() {
      temperature = 0;
      condition  = 0;
      cityName = 'Phone';
      cityIcon = 'Error';
    if(weatherData == null){
      weatherMessage = 'Something wrong, May be internet problem';
      return;
    }

    double localTemp = weatherData['main']['temp'];
    temperature = localTemp.toInt();
    condition  = weatherData['weather'][0]['id'];
    cityName = weatherData['name'];

    WeatherModel weatherModel = WeatherModel();
    cityIcon = weatherModel.getWeatherIcon(condition);
    weatherMessage = weatherModel.getMessage(temperature);

    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        resizeToAvoidBottomInset: false,
        body: Builder(
        builder: (context) => Container(
          decoration: BoxDecoration(
            image: DecorationImage(
              image: AssetImage('images/location_background.jpg'),
              fit: BoxFit.cover,
              colorFilter: ColorFilter.mode(
                  Colors.white.withOpacity(0.8), BlendMode.dstATop),
            ),
          ),
          constraints: BoxConstraints.expand(),
          child: SafeArea(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: <Widget>[
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: <Widget>[
                    FlatButton(
                      onPressed: () async {
                        var weatherData = await WeatherModel().getWeatherLocation();
                        updateUI(weatherData);
                        Scaffold.of(context).showSnackBar(SnackBar(content: Text('Weather Data has been updated.',), duration: Duration(milliseconds: 1000),),);
                      },
                      child: Icon(
                        Icons.near_me,
                        size: 40.0,
                      ),
                    ),
                    FlatButton(
                      onPressed: () async{
                        String cityName = await Navigator.push(context, MaterialPageRoute(builder: (context) => CityScreen()));
                        if(cityName != null){
                          var weatherData = await WeatherModel().getCityWeather(cityName);
                          updateUI(weatherData);
                        }
                      },
                      child: Icon(
                        Icons.location_city,
                        size: 40.0,
                      ),
                    ),
                  ],
                ),
                Padding(
                  padding: EdgeInsets.only(left: 15.0),
                  child: Row(
                    children: <Widget>[
                      Text(
                        '$temperature°',
                        style: kTempTextStyle,
                      ),
                      Text(
                        cityIcon,
                        style: kConditionTextStyle,
                      ),
                    ],
                  ),
                ),
                Padding(
                  padding: EdgeInsets.only(right: 15.0),
                  child: Text(
                    '$weatherMessage in $cityName',
                    textAlign: TextAlign.right,
                    style: kMessageTextStyle,
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

lib/screens/city_screen.dart

import 'package:flutter/material.dart';
import 'package:clima/utilities/constants.dart';

class CityScreen extends StatefulWidget {
  @override
  _CityScreenState createState() => _CityScreenState();
}

class _CityScreenState extends State<CityScreen> {
  String cityName;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        decoration: BoxDecoration(
          image: DecorationImage(
            image: AssetImage('images/city_background.jpg'),
            fit: BoxFit.cover,
          ),
        ),
        constraints: BoxConstraints.expand(),
        child: SafeArea(
          child: Column(
            children: <Widget>[
              Align(
                alignment: Alignment.topLeft,
                child: FlatButton(
                  onPressed: () {
                    Navigator.pop(context);
                  },
                  child: Icon(
                    Icons.arrow_back_ios,
                    size: 50.0,
                  ),
                ),
              ),
              Container(
                padding: EdgeInsets.all(20.0),
                child: TextField(
                  style: TextStyle(
                    color: Colors.black
                  ),
                  decoration: kTextFieldInputDecoration,
                  onChanged: (value){
                    cityName = value;
                  },
                ),
              ),
              FlatButton(
                onPressed: () {
                  Navigator.pop(context, cityName);
                },
                child: Text(
                  'Get Weather',
                  style: kButtonTextStyle,
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

lib/services/location.dart

import 'package:geolocator/geolocator.dart';

class Location{
  double lattitude;
  double longitude;

  Future getCurrentLocation() async {
    try{
      Position position = await Geolocator().getCurrentPosition(desiredAccuracy: LocationAccuracy.lowest);
      this.lattitude = position.latitude;
      this.longitude = position.longitude;
    }catch(e){
      print(e);
    }
  }

}

lib/services/networking.dart

import 'dart:convert';
import 'package:http/http.dart' as Http;

class NetworkHelper{
  NetworkHelper(this.url);
  final String url;

  Future getData() async{
    Http.Response response;
    try{
      response = await Http.get(url);
    }catch(e){
      return null;
    }

      if(response.statusCode == 200) {
        return jsonDecode(response.body);
      }else{
        print('Response was not 200');
      }
    }

}

lib/services/weather.dart

import 'package:clima/services/location.dart';
import 'package:clima/services/networking.dart';


class WeatherModel {

  String apiKey = 'c8ce20542b396ef0d2b4a37f9bf8c052';
  String openWeatherMapURL = 'https://api.openweathermap.org/data/2.5/weather';


  Future getWeatherLocation() async{
    Location location = Location();
    await location.getCurrentLocation();
    NetworkHelper networkHelper = NetworkHelper('$openWeatherMapURL?lat=${location.lattitude}&lon=${location.longitude}&units=metric&appid=$apiKey');

    return networkHelper.getData();
  }

  Future getCityWeather(String cityName) async{
    Location location = Location();
    await location.getCurrentLocation();
    NetworkHelper networkHelper = NetworkHelper('$openWeatherMapURL?q=${Uri.encodeComponent(cityName)}&units=metric&appid=$apiKey');
    return networkHelper.getData();
  }

  String getWeatherIcon(int condition) {
    if (condition < 300) {
      return '๐ŸŒฉ';
    } else if (condition < 400) {
      return '๐ŸŒง';
    } else if (condition < 600) {
      return '☔️';
    } else if (condition < 700) {
      return '☃️';
    } else if (condition < 800) {
      return '๐ŸŒซ';
    } else if (condition == 800) {
      return '☀️';
    } else if (condition <= 804) {
      return '☁️';
    } else {
      return '๐Ÿคท‍';
    }
  }

  String getMessage(int temp) {
    if (temp > 25) {
      return 'It\'s ๐Ÿฆ time';
    } else if (temp > 20) {
      return 'Time for shorts and ๐Ÿ‘•';
    } else if (temp < 10) {
      return 'You\'ll need ๐Ÿงฃ and ๐Ÿงค';
    } else {
      return 'Bring a ๐Ÿงฅ just in case';
    }
  }
}

lib/utilities/constant.dart

import 'package:flutter/material.dart';

const kTempTextStyle = TextStyle(
  fontFamily: 'Spartan MB',
  fontSize: 80.0,
);

const kMessageTextStyle = TextStyle(
  fontFamily: 'Spartan MB',
  fontSize: 40.0,
);

const kButtonTextStyle = TextStyle(
  fontSize: 30.0,
  fontFamily: 'Spartan MB',
);

const kConditionTextStyle = TextStyle(
  fontSize: 80.0,
);

const kTextFieldInputDecoration = InputDecoration(
  filled: true,
  fillColor: Colors.white,
  icon: Icon(Icons.location_city, color: Colors.yellow,),
  hintText: 'Enter City Name',
  hintStyle: TextStyle(
    color: Colors.grey,
  ),
  border: OutlineInputBorder(
    borderRadius: BorderRadius.all(Radius.circular(10.0)),
    borderSide: BorderSide.none,
  ),
);


Find me on:
https://twitter.com/naimurhasanrwd

Comments