diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 7f472186..402501d9 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,5 +1,8 @@ + + + + android:name="io.flutter.embedding.android.SplashScreenDrawable" + android:resource="@drawable/launch_background" /> + diff --git a/android/app/src/main/java/co/appbrewery/clima/MainActivity.java b/android/app/src/main/java/co/appbrewery/clima/MainActivity.java index 88dd0abc..5aab8045 100644 --- a/android/app/src/main/java/co/appbrewery/clima/MainActivity.java +++ b/android/app/src/main/java/co/appbrewery/clima/MainActivity.java @@ -1,13 +1,5 @@ package co.appbrewery.clima; - -import android.os.Bundle; -import io.flutter.app.FlutterActivity; -import io.flutter.plugins.GeneratedPluginRegistrant; - +import io.flutter.embedding.android.FlutterActivity; public class MainActivity extends FlutterActivity { - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - GeneratedPluginRegistrant.registerWith(this); - } + } diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml index 00fa4417..06c28adc 100644 --- a/android/app/src/main/res/values/styles.xml +++ b/android/app/src/main/res/values/styles.xml @@ -1,8 +1,6 @@ + @drawable/launch_background + diff --git a/images/city_background.jpg b/images/city_background.jpg deleted file mode 100644 index 66d6a636..00000000 Binary files a/images/city_background.jpg and /dev/null differ diff --git a/images/city_background.png b/images/city_background.png new file mode 100644 index 00000000..14a34386 Binary files /dev/null and b/images/city_background.png differ diff --git a/images/clouds.jpg b/images/clouds.jpg new file mode 100644 index 00000000..2de41282 Binary files /dev/null and b/images/clouds.jpg differ diff --git a/images/location_background.jpg b/images/location_background.jpg deleted file mode 100644 index c6100cd4..00000000 Binary files a/images/location_background.jpg and /dev/null differ diff --git a/images/rain.jpg b/images/rain.jpg new file mode 100644 index 00000000..8e5cca4d Binary files /dev/null and b/images/rain.jpg differ diff --git a/images/sky.jpg b/images/sky.jpg new file mode 100644 index 00000000..a69dcca1 Binary files /dev/null and b/images/sky.jpg differ diff --git a/images/snowfall.jpg b/images/snowfall.jpg new file mode 100644 index 00000000..3005bac7 Binary files /dev/null and b/images/snowfall.jpg differ diff --git a/images/sunny.jpg b/images/sunny.jpg new file mode 100644 index 00000000..73dfef94 Binary files /dev/null and b/images/sunny.jpg differ diff --git a/images/tree.jpg b/images/tree.jpg new file mode 100644 index 00000000..c8f5c36d Binary files /dev/null and b/images/tree.jpg differ diff --git a/ios/Flutter/flutter_export_environment.sh b/ios/Flutter/flutter_export_environment.sh new file mode 100644 index 00000000..6abbd8ae --- /dev/null +++ b/ios/Flutter/flutter_export_environment.sh @@ -0,0 +1,14 @@ +#!/bin/sh +# This is a generated file; do not edit or check into version control. +export "FLUTTER_ROOT=C:\src\flutter" +export "FLUTTER_APPLICATION_PATH=C:\Users\LENOVO\StudioProjects\Clima-Flutter-1" +export "COCOAPODS_PARALLEL_CODE_SIGN=true" +export "FLUTTER_TARGET=lib\main.dart" +export "FLUTTER_BUILD_DIR=build" +export "SYMROOT=${SOURCE_ROOT}/../build\ios" +export "FLUTTER_BUILD_NAME=1.0.1" +export "FLUTTER_BUILD_NUMBER=1" +export "DART_OBFUSCATION=false" +export "TRACK_WIDGET_CREATION=false" +export "TREE_SHAKE_ICONS=false" +export "PACKAGE_CONFIG=.packages" diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index a8da75cb..79e12027 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -2,6 +2,8 @@ + NSLocationWhenInUseUsageDescription + This app needs access to location when open. CFBundleDevelopmentRegion en CFBundleExecutable diff --git a/lib/main.dart b/lib/main.dart index 37d19202..02f7e9f0 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -7,6 +7,7 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( + debugShowCheckedModeBanner: false, theme: ThemeData.dark(), home: LoadingScreen(), ); diff --git a/lib/screens/city_screen.dart b/lib/screens/city_screen.dart deleted file mode 100644 index 25c4e40c..00000000 --- a/lib/screens/city_screen.dart +++ /dev/null @@ -1,51 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:clima/utilities/constants.dart'; - -class CityScreen extends StatefulWidget { - @override - _CityScreenState createState() => _CityScreenState(); -} - -class _CityScreenState extends State { - @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: [ - Align( - alignment: Alignment.topLeft, - child: FlatButton( - onPressed: () {}, - child: Icon( - Icons.arrow_back_ios, - size: 50.0, - ), - ), - ), - Container( - padding: EdgeInsets.all(20.0), - child: null, - ), - FlatButton( - onPressed: () {}, - child: Text( - 'Get Weather', - style: kButtonTextStyle, - ), - ), - ], - ), - ), - ), - ); - } -} diff --git a/lib/screens/loading_screen.dart b/lib/screens/loading_screen.dart index 0b96a2a5..0c7be4c8 100644 --- a/lib/screens/loading_screen.dart +++ b/lib/screens/loading_screen.dart @@ -1,4 +1,7 @@ import 'package:flutter/material.dart'; +import '/screens/location_screen.dart'; +import 'package:flutter_spinkit/flutter_spinkit.dart'; +import '/services/weather.dart'; class LoadingScreen extends StatefulWidget { @override @@ -6,16 +9,31 @@ class LoadingScreen extends StatefulWidget { } class _LoadingScreenState extends State { + @override + void initState() { + super.initState(); + getLocationData(); + } + + void getLocationData() async { + WeatherModel weatherModel = WeatherModel(); + var weatherData = await weatherModel.getLocationWeather(); + + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => LocationScreen( + locationWeather: weatherData, + ), + ), + ); + } + @override Widget build(BuildContext context) { return Scaffold( body: Center( - child: RaisedButton( - onPressed: () { - //Get the current location - }, - child: Text('Get Location'), - ), + child: SpinKitFadingFour(color: Colors.white, size: 100.0), ), ); } diff --git a/lib/screens/location_screen.dart b/lib/screens/location_screen.dart index fd18be49..8c2592c0 100644 --- a/lib/screens/location_screen.dart +++ b/lib/screens/location_screen.dart @@ -1,76 +1,201 @@ +import 'dart:io'; import 'package:flutter/material.dart'; import 'package:clima/utilities/constants.dart'; +import '/services/weather.dart'; class LocationScreen extends StatefulWidget { + LocationScreen({this.locationWeather}); + + final locationWeather; + @override _LocationScreenState createState() => _LocationScreenState(); } class _LocationScreenState extends State { + WeatherModel weather = WeatherModel(); + + int temperature; + String weatherIcon; + String cityName; + String weatherMessage; + var condition; + AssetImage _imageToShow; + + @override + void initState() { + super.initState(); + updateUI(widget.locationWeather); + _imageToShow = AssetImage('images/tree.jpg'); + } + + void updateUI(dynamic weatherData) { + setState(() { + if (weatherData == null) { + temperature = 0; + weatherIcon = "Error"; + weatherMessage = "Unable to get weather data"; + cityName = '$cityName'; + return; + } + var temp = weatherData['main']['temp']; + temperature = temp.toInt(); + condition = weatherData['weather'][0]['id']; + weatherIcon = weather.getWeatherIcon(condition); + weatherMessage = weather.getMessage(temperature); + cityName = weatherData['name']; + + updateimage(); + }); + } + + Future _onBackPressed() { + return showDialog( + context: context, + builder: (context) => AlertDialog( + title: Text("Do you really want to exit the App"), + actions: [ + ElevatedButton( + child: Text("No"), + onPressed: () => Navigator.pop(context, false), + ), + ElevatedButton( + child: Text("Yes"), + onPressed: () => exit(0), + ), + ], + )); + } + + void updateimage() { + setState(() { + if (condition < 300) { + _imageToShow = AssetImage('images/city_background.png'); + } else if (condition < 400) { + _imageToShow = AssetImage('images/rain.jpg'); + } else if (condition < 700) { + _imageToShow = AssetImage('images/snowfall.jpg'); + } else if (condition == 800) { + _imageToShow = AssetImage('images/sunny.jpg'); + } else if (condition <= 804) { + _imageToShow = AssetImage('images/tree.jpg'); + } else { + _imageToShow = AssetImage('images/sky.jpg'); + } + }); + } + @override Widget build(BuildContext context) { return Scaffold( - body: Container( - decoration: BoxDecoration( - image: DecorationImage( - image: AssetImage('images/location_background.jpg'), - fit: BoxFit.cover, - colorFilter: ColorFilter.mode( - Colors.white.withOpacity(0.8), BlendMode.dstATop), + body: WillPopScope( + onWillPop: _onBackPressed, + child: Container( + decoration: BoxDecoration( + image: DecorationImage( + image: _imageToShow, + fit: BoxFit.cover, + colorFilter: ColorFilter.mode( + Colors.black.withOpacity(.6), BlendMode.dstATop), + ), ), - ), - constraints: BoxConstraints.expand(), - child: SafeArea( - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Row( + constraints: BoxConstraints.expand(), + child: SafeArea( + child: SingleChildScrollView( + child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - FlatButton( - onPressed: () {}, - child: Icon( - Icons.near_me, - size: 50.0, - ), + Column( + children: [ + SizedBox( + height: 10.0, + ), + Container( + padding: EdgeInsets.all(10.0), + child: TextField( + style: TextStyle( + color: Colors.black, + ), + decoration: kTextFieldInputDecoration, + onChanged: (value) { + cityName = value; + }, + ), + ), + SizedBox( + height: 10.0, + ), + ElevatedButton( + style: ElevatedButton.styleFrom( + primary: Colors.white.withOpacity(.1), + ), + onPressed: () async { + if (cityName != null) { + var weatherData = + await weather.getCityWeather(cityName); + updateUI(weatherData); + setState(() { + updateimage(); + }); + } + }, + child: Text( + 'Get Weather', + style: kButtonTextStyle, + ), + ), + ], + ), + SizedBox( + height: 90.0, ), - FlatButton( - onPressed: () {}, - child: Icon( - Icons.location_city, - size: 50.0, - ), + Column( + children: [ + Padding( + padding: EdgeInsets.only(left: 15.0), + child: Row( + children: [ + Text( + '$temperature°', + style: kTempTextStyle, + ), + Text( + weatherIcon, + style: kConditionTextStyle, + ), + ], + ), + ), + SizedBox( + height: 45.0, + ), + Padding( + padding: EdgeInsets.only( + right: 15.0, + ), + child: Text( + '$weatherMessage in $cityName', + textAlign: TextAlign.right, + style: kMessageTextStyle, + ), + ), + ], ), ], ), - Padding( - padding: EdgeInsets.only(left: 15.0), - child: Row( - children: [ - Text( - '32°', - style: kTempTextStyle, - ), - Text( - '☀️', - style: kConditionTextStyle, - ), - ], - ), - ), - Padding( - padding: EdgeInsets.only(right: 15.0), - child: Text( - "It's 🍦 time in San Francisco!", - textAlign: TextAlign.right, - style: kMessageTextStyle, - ), - ), - ], + ), ), ), ), + floatingActionButton: FloatingActionButton( + onPressed: () async { + var weatherData = await weather.getLocationWeather(); + updateUI(weatherData); + }, + child: const Icon(Icons.navigation, color: Colors.white), + backgroundColor: Colors.black, + ), ); } } diff --git a/lib/services/location.dart b/lib/services/location.dart index e69de29b..30b23ed6 100644 --- a/lib/services/location.dart +++ b/lib/services/location.dart @@ -0,0 +1,17 @@ +import 'package:geolocator/geolocator.dart'; + +class Location { + double latitude; + double longitude; + + Future getCurrentLocation() async { + try { + Position position = await Geolocator.getCurrentPosition( + desiredAccuracy: LocationAccuracy.high); + latitude = position.latitude; + longitude = position.longitude; + } catch (e) { + print(e); + } + } +} diff --git a/lib/services/networking.dart b/lib/services/networking.dart index e69de29b..170b8aae 100644 --- a/lib/services/networking.dart +++ b/lib/services/networking.dart @@ -0,0 +1,19 @@ +import 'package:http/http.dart' as http; +import 'dart:convert'; + +class NetworkHelper { + NetworkHelper(this.url); + + final String url; + + Future getData() async { + http.Response response = await http.get(Uri.parse(url)); + + if (response.statusCode == 200) { + String data = response.body; + return jsonDecode(data); + } else { + print(response.statusCode); + } + } +} diff --git a/lib/services/weather.dart b/lib/services/weather.dart index 9556b013..7a8e41bb 100644 --- a/lib/services/weather.dart +++ b/lib/services/weather.dart @@ -1,4 +1,32 @@ +import '/services/location.dart'; +import '/services/networking.dart'; + +const apiKey = '0310cbf06f31b35fdf8859655339853c'; +const openWeatherMapURL = 'https://api.openweathermap.org/data/2.5/weather'; + class WeatherModel { + +//latitude and longitude + Future getCityWeather(String cityName) async { + NetworkHelper networkHelper = NetworkHelper( + "$openWeatherMapURL?q=$cityName&appid=$apiKey&units=metric"); + + var weatherData = await networkHelper.getData(); + return weatherData; + } + + //search by cityName + Future getLocationWeather() async { + Location location = Location(); + await location.getCurrentLocation(); + + NetworkHelper networkHelper = NetworkHelper( + '$openWeatherMapURL?lat=${location.latitude}&lon=${location.longitude}&appid=$apiKey&units=metric'); // &units=metric used for celcuius + + var weatherData = await networkHelper.getData(); + return weatherData; + } + String getWeatherIcon(int condition) { if (condition < 300) { return '🌩'; diff --git a/lib/utilities/constants.dart b/lib/utilities/constants.dart index 6da86bca..a7361cc2 100644 --- a/lib/utilities/constants.dart +++ b/lib/utilities/constants.dart @@ -3,18 +3,37 @@ import 'package:flutter/material.dart'; const kTempTextStyle = TextStyle( fontFamily: 'Spartan MB', fontSize: 100.0, + color: Color(0xFFf4f5f2), ); const kMessageTextStyle = TextStyle( fontFamily: 'Spartan MB', - fontSize: 60.0, + fontSize: 50.0, + color: Color(0xFFf4f5f2), ); const kButtonTextStyle = TextStyle( fontSize: 30.0, fontFamily: 'Spartan MB', + color: Color(0xFFe6ebe1), ); const kConditionTextStyle = TextStyle( fontSize: 100.0, ); + +const kTextFieldInputDecoration = InputDecoration( + filled: true, + fillColor: Color(0xFFfafafa), + icon: Icon(Icons.location_city, color: Colors.white), + hintText: "Enter City Name", + hintStyle: TextStyle( + color: Colors.grey, + ), + border: OutlineInputBorder( + borderRadius: BorderRadius.all( + Radius.circular(10.0), + ), + borderSide: BorderSide.none, + ), +); diff --git a/pubspec.lock b/pubspec.lock index a48c6ef1..f3def147 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,62 +1,48 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: - archive: - dependency: transitive - description: - name: archive - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.11" - args: - dependency: transitive - description: - name: args - url: "https://pub.dartlang.org" - source: hosted - version: "1.5.2" async: dependency: transitive description: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.4.0" + version: "2.6.1" boolean_selector: dependency: transitive description: name: boolean_selector url: "https://pub.dartlang.org" source: hosted - version: "1.0.5" - charcode: + version: "2.1.0" + characters: dependency: transitive description: - name: charcode + name: characters url: "https://pub.dartlang.org" source: hosted - version: "1.1.2" - collection: + version: "1.1.0" + charcode: dependency: transitive description: - name: collection + name: charcode url: "https://pub.dartlang.org" source: hosted - version: "1.14.11" - convert: + version: "1.2.0" + clock: dependency: transitive description: - name: convert + name: clock url: "https://pub.dartlang.org" source: hosted - version: "2.1.1" - crypto: + version: "1.1.0" + collection: dependency: transitive description: - name: crypto + name: collection url: "https://pub.dartlang.org" source: hosted - version: "2.1.3" + version: "1.15.0" cupertino_icons: dependency: "direct main" description: @@ -64,65 +50,126 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.1.2" + fake_async: + dependency: transitive + description: + name: fake_async + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" flutter: dependency: "direct main" description: flutter source: sdk version: "0.0.0" + flutter_spinkit: + dependency: "direct main" + description: + name: flutter_spinkit + url: "https://pub.dartlang.org" + source: hosted + version: "5.1.0" flutter_test: dependency: "direct dev" description: flutter source: sdk version: "0.0.0" - image: + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + geolocator: + dependency: "direct main" + description: + name: geolocator + url: "https://pub.dartlang.org" + source: hosted + version: "7.6.0" + geolocator_android: dependency: transitive description: - name: image + name: geolocator_android url: "https://pub.dartlang.org" source: hosted - version: "2.1.4" + version: "1.0.0" + geolocator_apple: + dependency: transitive + description: + name: geolocator_apple + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + geolocator_platform_interface: + dependency: transitive + description: + name: geolocator_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.3.4" + geolocator_web: + dependency: transitive + description: + name: geolocator_web + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.6" + http: + dependency: "direct main" + description: + name: http + url: "https://pub.dartlang.org" + source: hosted + version: "0.13.3" + http_parser: + dependency: transitive + description: + name: http_parser + url: "https://pub.dartlang.org" + source: hosted + version: "4.0.0" + js: + dependency: transitive + description: + name: js + url: "https://pub.dartlang.org" + source: hosted + version: "0.6.3" matcher: dependency: transitive description: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.6" + version: "0.12.10" meta: dependency: transitive description: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.1.8" + version: "1.3.0" path: dependency: transitive description: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.6.4" + version: "1.8.0" pedantic: dependency: transitive description: name: pedantic url: "https://pub.dartlang.org" source: hosted - version: "1.8.0+1" - petitparser: + version: "1.11.1" + plugin_platform_interface: dependency: transitive description: - name: petitparser + name: plugin_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.4.0" - quiver: - dependency: transitive - description: - name: quiver - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.5" + version: "2.0.1" sky_engine: dependency: transitive description: flutter @@ -134,62 +181,56 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.5.5" + version: "1.8.1" stack_trace: dependency: transitive description: name: stack_trace url: "https://pub.dartlang.org" source: hosted - version: "1.9.3" + version: "1.10.0" stream_channel: dependency: transitive description: name: stream_channel url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.1.0" string_scanner: dependency: transitive description: name: string_scanner url: "https://pub.dartlang.org" source: hosted - version: "1.0.5" + version: "1.1.0" term_glyph: dependency: transitive description: name: term_glyph url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.2.0" test_api: dependency: transitive description: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.2.11" + version: "0.3.0" typed_data: dependency: transitive description: name: typed_data url: "https://pub.dartlang.org" source: hosted - version: "1.1.6" + version: "1.3.0" vector_math: dependency: transitive description: name: vector_math url: "https://pub.dartlang.org" source: hosted - version: "2.0.8" - xml: - dependency: transitive - description: - name: xml - url: "https://pub.dartlang.org" - source: hosted - version: "3.5.0" + version: "2.1.0" sdks: - dart: ">=2.4.0 <3.0.0" + dart: ">=2.12.0 <3.0.0" + flutter: ">=2.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index 0aa510bc..73ae3d97 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: clima description: A new Flutter application. -version: 1.0.0+1 +version: 1.0.1+1 environment: sdk: ">=2.1.0 <3.0.0" @@ -11,6 +11,9 @@ dependencies: sdk: flutter cupertino_icons: ^0.1.2 + geolocator: ^7.6.0 + http: ^0.13.3 + flutter_spinkit: ^5.1.0 dev_dependencies: flutter_test: