├── .gitignore ├── .metadata ├── README.md ├── android ├── .gitignore ├── app │ ├── build.gradle │ └── src │ │ ├── debug │ │ └── AndroidManifest.xml │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── kotlin │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── weather_app_flutter │ │ │ │ └── MainActivity.kt │ │ └── res │ │ │ ├── drawable-v21 │ │ │ └── launch_background.xml │ │ │ ├── drawable │ │ │ └── launch_background.xml │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── values-night │ │ │ └── styles.xml │ │ │ └── values │ │ │ └── styles.xml │ │ └── profile │ │ └── AndroidManifest.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties └── settings.gradle ├── assets └── city_list.json ├── data ├── screenshot.jpg ├── screenshot_config_json.png └── test.json ├── images ├── placeholder.png ├── sunrise.png └── sunset.png ├── ios ├── .gitignore ├── Flutter │ ├── AppFrameworkInfo.plist │ ├── Debug.xcconfig │ └── Release.xcconfig ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── WorkspaceSettings.xcsettings │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── WorkspaceSettings.xcsettings └── Runner │ ├── AppDelegate.swift │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Icon-App-1024x1024@1x.png │ │ ├── Icon-App-20x20@1x.png │ │ ├── Icon-App-20x20@2x.png │ │ ├── Icon-App-20x20@3x.png │ │ ├── Icon-App-29x29@1x.png │ │ ├── Icon-App-29x29@2x.png │ │ ├── Icon-App-29x29@3x.png │ │ ├── Icon-App-40x40@1x.png │ │ ├── Icon-App-40x40@2x.png │ │ ├── Icon-App-40x40@3x.png │ │ ├── Icon-App-60x60@2x.png │ │ ├── Icon-App-60x60@3x.png │ │ ├── Icon-App-76x76@1x.png │ │ ├── Icon-App-76x76@2x.png │ │ └── Icon-App-83.5x83.5@2x.png │ └── LaunchImage.imageset │ │ ├── Contents.json │ │ ├── LaunchImage.png │ │ ├── LaunchImage@2x.png │ │ ├── LaunchImage@3x.png │ │ └── README.md │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── Info.plist │ └── Runner-Bridging-Header.h ├── lib ├── config │ ├── build_config.dart │ └── env_config.dart ├── core │ ├── app_colors.dart │ ├── app_utils.dart │ └── text_style.dart ├── main.dart ├── network │ ├── WeatherApi.dart │ ├── WeatherApiImpl.dart │ ├── api_interceptor.dart │ └── dio_client.dart └── ui │ └── home │ ├── model │ ├── City.dart │ ├── weather_data.dart │ └── weather_response.dart │ ├── view │ └── HomePage.dart │ └── widget │ ├── Item_sun_time.dart │ ├── input_section.dart │ ├── item_weather_property.dart │ ├── sun_time.dart │ ├── temperature_section.dart │ ├── weather_data_output.dart │ └── weather_property.dart ├── pubspec.lock ├── pubspec.yaml ├── test └── widget_test.dart └── web ├── favicon.png ├── icons ├── Icon-192.png └── Icon-512.png ├── index.html └── manifest.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | **/ios/Flutter/.last_build_id 26 | .dart_tool/ 27 | .flutter-plugins 28 | .flutter-plugins-dependencies 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Web related 35 | lib/generated_plugin_registrant.dart 36 | 37 | # Symbolication related 38 | app.*.symbols 39 | 40 | # Obfuscation related 41 | app.*.map.json 42 | 43 | # Android related 44 | **/android/**/gradle-wrapper.jar 45 | **/android/.gradle 46 | **/android/captures/ 47 | **/android/gradlew 48 | **/android/gradlew.bat 49 | **/android/local.properties 50 | **/android/**/GeneratedPluginRegistrant.java 51 | 52 | # iOS/XCode related 53 | **/ios/**/*.mode1v3 54 | **/ios/**/*.mode2v3 55 | **/ios/**/*.moved-aside 56 | **/ios/**/*.pbxuser 57 | **/ios/**/*.perspectivev3 58 | **/ios/**/*sync/ 59 | **/ios/**/.sconsign.dblite 60 | **/ios/**/.tags* 61 | **/ios/**/.vagrant/ 62 | **/ios/**/DerivedData/ 63 | **/ios/**/Icon? 64 | **/ios/**/Pods/ 65 | **/ios/**/.symlinks/ 66 | **/ios/**/profile 67 | **/ios/**/xcuserdata 68 | **/ios/.generated/ 69 | **/ios/Flutter/App.framework 70 | **/ios/Flutter/Flutter.framework 71 | **/ios/Flutter/Generated.xcconfig 72 | **/ios/Flutter/app.flx 73 | **/ios/Flutter/app.zip 74 | **/ios/Flutter/flutter_assets/ 75 | **/ios/ServiceDefinitions.json 76 | **/ios/Runner/GeneratedPluginRegistrant.* 77 | 78 | ### Android ### 79 | # Built application files 80 | *.apk 81 | *.aar 82 | *.ap_ 83 | *.aab 84 | 85 | # Files for the ART/Dalvik VM 86 | *.dex 87 | 88 | # Generated files 89 | bin/ 90 | gen/ 91 | out/ 92 | # Uncomment the following line in case you need and you don't have the release build type files in your app 93 | # release/ 94 | 95 | # Gradle files 96 | .gradle/ 97 | build/ 98 | 99 | # Local configuration file (sdk path, etc) 100 | local.properties 101 | 102 | # Custom file and directory 103 | /assets/config.json -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 1d9032c7e1d867f071f2277eb1673e8f9b0274e3 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Basic Flutter (Android + iOS) App (Dart + Dio) - Weather App 2 | 3 | This is a very beginning friendly project of Flutter. A simple weather forecast App using Open Weather Map API. 4 | I have used `StatefulWidget` for state management. For network calls I used the popular Flutter package `Dio`. 5 | 6 | 7 | 8 | ### Prerequisite 9 | Basic understanding of Dart programming language. Have to familiar with REST API and network calls with HTTP protocol. 10 | 11 | ### Project Description 12 | We will develop a weather forecast Android Application with Flutter. The UI will be as like as above screenshot. There is a `DropdownButton` with some `City` name. After selection a city, user need to hit the `View Weather` button. Then App will send request to Open Weather web API and show the weather information in the UI. 13 | 14 | ### Open Weather API 15 | We will use [Open Weather Map API](https://openweathermap.org/api) for collecting weather information. To get the real weather information of a city, you need to sign up and get your own `APP ID`. Otherwise you can test the API with their sample `BASE URL` and sample `APP ID` without creating account. 16 | 17 | ### Project Setup 18 | Clone the project and open it using Android Studio. Then create a file `config.json` inside `assets` folder. Add `baseUrl` and `appId` JSON field inside the parent JSON object. 19 | 20 | 21 | 22 | #### Use Sample API without creating account 23 | Add below lines at your `config.json` file. Then run the project. You'll get dummy or static API response from Open Weather API. 24 | ``` 25 | { 26 | "baseUrl": "https://samples.openweathermap.org/data/2.5", 27 | "appId": "b6907d289e10d714a6e88b30761fae22" 28 | } 29 | ``` 30 | #### Use Real APP ID after sign up and activation of your APP ID 31 | After Sign up at the website collect your own `APP ID` from their [API Keys page](https://home.openweathermap.org/api_keys). Then add your `APP ID` in `config.json` file like below. 32 | ``` 33 | { 34 | "baseUrl": "http://api.openweathermap.org/data/2.5", 35 | "appId": "" 36 | } 37 | ``` 38 | The BASE URL and APP ID will be fetched from `main.dart` file and will be stored it in our local configuration file. 39 | 40 | **Note:** The free version of Open Weather API allows maximum 60 API calls per minute. 41 | ### Run the project 42 | Run `flutter pub get` to sync the packages. Then run the app to your real device or emulator. 43 | ### Disclaimer 44 | This is my first project in Flutter. So there are lots of things to improve. It is not guaranteed about the best practices and Flutter convention in this project. Please don't use this project as a reference or as a boilerplate of your other project. For the sake of simplicity, I avoided to use Bloc, GetX etc. Next time I'll create different repositories for them. 45 | Feel free to create issues for improvement.Thanks. 46 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply plugin: 'kotlin-android' 26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 27 | 28 | android { 29 | compileSdkVersion 30 30 | 31 | sourceSets { 32 | main.java.srcDirs += 'src/main/kotlin' 33 | } 34 | 35 | defaultConfig { 36 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 37 | applicationId "com.example.weather_app_flutter" 38 | minSdkVersion 16 39 | targetSdkVersion 30 40 | versionCode flutterVersionCode.toInteger() 41 | versionName flutterVersionName 42 | } 43 | 44 | buildTypes { 45 | release { 46 | // TODO: Add your own signing config for the release build. 47 | // Signing with the debug keys for now, so `flutter run --release` works. 48 | signingConfig signingConfigs.debug 49 | } 50 | } 51 | } 52 | 53 | flutter { 54 | source '../..' 55 | } 56 | 57 | dependencies { 58 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 59 | } 60 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 9 | 16 | 20 | 23 | 28 | 31 | 32 | 33 | 34 | 35 | 36 | 38 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/example/weather_app_flutter/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.weather_app_flutter 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity : FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 11 | 12 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 11 | 12 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hasancse91/weather_app_flutter/2ae0303f2ec7941c341ea2c4bfd3c6055eec588b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hasancse91/weather_app_flutter/2ae0303f2ec7941c341ea2c4bfd3c6055eec588b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hasancse91/weather_app_flutter/2ae0303f2ec7941c341ea2c4bfd3c6055eec588b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hasancse91/weather_app_flutter/2ae0303f2ec7941c341ea2c4bfd3c6055eec588b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hasancse91/weather_app_flutter/2ae0303f2ec7941c341ea2c4bfd3c6055eec588b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.3.50' 3 | repositories { 4 | google() 5 | jcenter() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:4.1.0' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | jcenter() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | project.evaluationDependsOn(':app') 25 | } 26 | 27 | task clean(type: Delete) { 28 | delete rootProject.buildDir 29 | } 30 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip 7 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") 4 | def properties = new Properties() 5 | 6 | assert localPropertiesFile.exists() 7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } 8 | 9 | def flutterSdkPath = properties.getProperty("flutter.sdk") 10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" 12 | -------------------------------------------------------------------------------- /assets/city_list.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": 1185241, 4 | "name": "Dhaka", 5 | "country": "BD" 6 | }, 7 | { 8 | "id": 1336135, 9 | "name": "Khulna", 10 | "country": "BD" 11 | }, 12 | { 13 | "id": 1337200, 14 | "name": "Chittagong", 15 | "country": "BD" 16 | }, 17 | { 18 | "id": 1336134, 19 | "name": "Coxs Bazar", 20 | "country": "BD" 21 | }, 22 | { 23 | "id": 1185128, 24 | "name": "Rajshahi", 25 | "country": "BD" 26 | }, 27 | { 28 | "id": 1336137, 29 | "name": "Barisal", 30 | "country": "BD" 31 | }, 32 | { 33 | "id": 1185099, 34 | "name": "Sylhet", 35 | "country": "BD" 36 | }, 37 | { 38 | "id": 1185188, 39 | "name": "Rangpur", 40 | "country": "BD" 41 | }, 42 | { 43 | "id": 5056033, 44 | "name": "London", 45 | "country": "US" 46 | }, 47 | { 48 | "id": 1275004, 49 | "name": "Kolkata", 50 | "country": "IN" 51 | }, 52 | { 53 | "id": 108410, 54 | "name": "Riyadh", 55 | "country": "SA" 56 | }, 57 | { 58 | "id": 292968, 59 | "name": "Abu Dhabi", 60 | "country": "AE" 61 | }, 62 | { 63 | "id": 5128638, 64 | "name": "New York", 65 | "country": "US" 66 | }, 67 | { 68 | "id": 1850147, 69 | "name": "Tokyo", 70 | "country": "JP" 71 | }, 72 | { 73 | "id": 1176615, 74 | "name": "Islamabad", 75 | "country": "PK" 76 | }, 77 | { 78 | "id": 1261481, 79 | "name": "New Delhi", 80 | "country": "IN" 81 | } 82 | ] -------------------------------------------------------------------------------- /data/screenshot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hasancse91/weather_app_flutter/2ae0303f2ec7941c341ea2c4bfd3c6055eec588b/data/screenshot.jpg -------------------------------------------------------------------------------- /data/screenshot_config_json.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hasancse91/weather_app_flutter/2ae0303f2ec7941c341ea2c4bfd3c6055eec588b/data/screenshot_config_json.png -------------------------------------------------------------------------------- /data/test.json: -------------------------------------------------------------------------------- 1 | {"status":"Success","statusCode":200,"data":{"userList":[{"id":"7f141043-104b-4b61-a9b6-95941aed2292","name":"John Doe","profilePictureUrl":"https:\/\/picsum.photos\/id\/12\/300\/300","dateOfBirth":"2021-08-17T08:39:04.1665352+00:00","relation":"Father","isAeonUser":true},{"id":"7f141043-104b-4b61-a9b6-95941aed2292","name":"John Doe","profilePictureUrl":"https:\/\/picsum.photos\/id\/12\/300\/300","dateOfBirth":"2021-08-17T08:39:04.1665352+00:00","relation":"Father","isAeonUser":false},{"id":"7f141043-104b-4b61-a9b6-95941aed2292","name":"John Doe","profilePictureUrl":"https:\/\/picsum.photos\/id\/12\/300\/300","dateOfBirth":"2021-08-17T08:39:04.1665352+00:00","relation":"Father","isAeonUser":true}],"pageNumber":1,"pageSize":10,"total":20},"message":"Successful","errors":null} 2 | -------------------------------------------------------------------------------- /images/placeholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hasancse91/weather_app_flutter/2ae0303f2ec7941c341ea2c4bfd3c6055eec588b/images/placeholder.png -------------------------------------------------------------------------------- /images/sunrise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hasancse91/weather_app_flutter/2ae0303f2ec7941c341ea2c4bfd3c6055eec588b/images/sunrise.png -------------------------------------------------------------------------------- /images/sunset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hasancse91/weather_app_flutter/2ae0303f2ec7941c341ea2c4bfd3c6055eec588b/images/sunset.png -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/ephemeral/ 22 | Flutter/app.flx 23 | Flutter/app.zip 24 | Flutter/flutter_assets/ 25 | Flutter/flutter_export_environment.sh 26 | ServiceDefinitions.json 27 | Runner/GeneratedPluginRegistrant.* 28 | 29 | # Exceptions to above rules. 30 | !default.mode1v3 31 | !default.mode2v3 32 | !default.pbxuser 33 | !default.perspectivev3 34 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 11 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 12 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 13 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 14 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 15 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 16 | /* End PBXBuildFile section */ 17 | 18 | /* Begin PBXCopyFilesBuildPhase section */ 19 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = { 20 | isa = PBXCopyFilesBuildPhase; 21 | buildActionMask = 2147483647; 22 | dstPath = ""; 23 | dstSubfolderSpec = 10; 24 | files = ( 25 | ); 26 | name = "Embed Frameworks"; 27 | runOnlyForDeploymentPostprocessing = 0; 28 | }; 29 | /* End PBXCopyFilesBuildPhase section */ 30 | 31 | /* Begin PBXFileReference section */ 32 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 33 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 34 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 35 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 36 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 37 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 38 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 39 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 40 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 41 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 42 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 43 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 44 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 45 | /* End PBXFileReference section */ 46 | 47 | /* Begin PBXFrameworksBuildPhase section */ 48 | 97C146EB1CF9000F007C117D /* Frameworks */ = { 49 | isa = PBXFrameworksBuildPhase; 50 | buildActionMask = 2147483647; 51 | files = ( 52 | ); 53 | runOnlyForDeploymentPostprocessing = 0; 54 | }; 55 | /* End PBXFrameworksBuildPhase section */ 56 | 57 | /* Begin PBXGroup section */ 58 | 9740EEB11CF90186004384FC /* Flutter */ = { 59 | isa = PBXGroup; 60 | children = ( 61 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 62 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 63 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 64 | 9740EEB31CF90195004384FC /* Generated.xcconfig */, 65 | ); 66 | name = Flutter; 67 | sourceTree = ""; 68 | }; 69 | 97C146E51CF9000F007C117D = { 70 | isa = PBXGroup; 71 | children = ( 72 | 9740EEB11CF90186004384FC /* Flutter */, 73 | 97C146F01CF9000F007C117D /* Runner */, 74 | 97C146EF1CF9000F007C117D /* Products */, 75 | ); 76 | sourceTree = ""; 77 | }; 78 | 97C146EF1CF9000F007C117D /* Products */ = { 79 | isa = PBXGroup; 80 | children = ( 81 | 97C146EE1CF9000F007C117D /* Runner.app */, 82 | ); 83 | name = Products; 84 | sourceTree = ""; 85 | }; 86 | 97C146F01CF9000F007C117D /* Runner */ = { 87 | isa = PBXGroup; 88 | children = ( 89 | 97C146FA1CF9000F007C117D /* Main.storyboard */, 90 | 97C146FD1CF9000F007C117D /* Assets.xcassets */, 91 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 92 | 97C147021CF9000F007C117D /* Info.plist */, 93 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 94 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 95 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, 96 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, 97 | ); 98 | path = Runner; 99 | sourceTree = ""; 100 | }; 101 | /* End PBXGroup section */ 102 | 103 | /* Begin PBXNativeTarget section */ 104 | 97C146ED1CF9000F007C117D /* Runner */ = { 105 | isa = PBXNativeTarget; 106 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; 107 | buildPhases = ( 108 | 9740EEB61CF901F6004384FC /* Run Script */, 109 | 97C146EA1CF9000F007C117D /* Sources */, 110 | 97C146EB1CF9000F007C117D /* Frameworks */, 111 | 97C146EC1CF9000F007C117D /* Resources */, 112 | 9705A1C41CF9048500538489 /* Embed Frameworks */, 113 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 114 | ); 115 | buildRules = ( 116 | ); 117 | dependencies = ( 118 | ); 119 | name = Runner; 120 | productName = Runner; 121 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */; 122 | productType = "com.apple.product-type.application"; 123 | }; 124 | /* End PBXNativeTarget section */ 125 | 126 | /* Begin PBXProject section */ 127 | 97C146E61CF9000F007C117D /* Project object */ = { 128 | isa = PBXProject; 129 | attributes = { 130 | LastUpgradeCheck = 1020; 131 | ORGANIZATIONNAME = ""; 132 | TargetAttributes = { 133 | 97C146ED1CF9000F007C117D = { 134 | CreatedOnToolsVersion = 7.3.1; 135 | LastSwiftMigration = 1100; 136 | }; 137 | }; 138 | }; 139 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; 140 | compatibilityVersion = "Xcode 9.3"; 141 | developmentRegion = en; 142 | hasScannedForEncodings = 0; 143 | knownRegions = ( 144 | en, 145 | Base, 146 | ); 147 | mainGroup = 97C146E51CF9000F007C117D; 148 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */; 149 | projectDirPath = ""; 150 | projectRoot = ""; 151 | targets = ( 152 | 97C146ED1CF9000F007C117D /* Runner */, 153 | ); 154 | }; 155 | /* End PBXProject section */ 156 | 157 | /* Begin PBXResourcesBuildPhase section */ 158 | 97C146EC1CF9000F007C117D /* Resources */ = { 159 | isa = PBXResourcesBuildPhase; 160 | buildActionMask = 2147483647; 161 | files = ( 162 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 163 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 164 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 165 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 166 | ); 167 | runOnlyForDeploymentPostprocessing = 0; 168 | }; 169 | /* End PBXResourcesBuildPhase section */ 170 | 171 | /* Begin PBXShellScriptBuildPhase section */ 172 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 173 | isa = PBXShellScriptBuildPhase; 174 | buildActionMask = 2147483647; 175 | files = ( 176 | ); 177 | inputPaths = ( 178 | ); 179 | name = "Thin Binary"; 180 | outputPaths = ( 181 | ); 182 | runOnlyForDeploymentPostprocessing = 0; 183 | shellPath = /bin/sh; 184 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; 185 | }; 186 | 9740EEB61CF901F6004384FC /* Run Script */ = { 187 | isa = PBXShellScriptBuildPhase; 188 | buildActionMask = 2147483647; 189 | files = ( 190 | ); 191 | inputPaths = ( 192 | ); 193 | name = "Run Script"; 194 | outputPaths = ( 195 | ); 196 | runOnlyForDeploymentPostprocessing = 0; 197 | shellPath = /bin/sh; 198 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; 199 | }; 200 | /* End PBXShellScriptBuildPhase section */ 201 | 202 | /* Begin PBXSourcesBuildPhase section */ 203 | 97C146EA1CF9000F007C117D /* Sources */ = { 204 | isa = PBXSourcesBuildPhase; 205 | buildActionMask = 2147483647; 206 | files = ( 207 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 208 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 209 | ); 210 | runOnlyForDeploymentPostprocessing = 0; 211 | }; 212 | /* End PBXSourcesBuildPhase section */ 213 | 214 | /* Begin PBXVariantGroup section */ 215 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 216 | isa = PBXVariantGroup; 217 | children = ( 218 | 97C146FB1CF9000F007C117D /* Base */, 219 | ); 220 | name = Main.storyboard; 221 | sourceTree = ""; 222 | }; 223 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 224 | isa = PBXVariantGroup; 225 | children = ( 226 | 97C147001CF9000F007C117D /* Base */, 227 | ); 228 | name = LaunchScreen.storyboard; 229 | sourceTree = ""; 230 | }; 231 | /* End PBXVariantGroup section */ 232 | 233 | /* Begin XCBuildConfiguration section */ 234 | 249021D3217E4FDB00AE95B9 /* Profile */ = { 235 | isa = XCBuildConfiguration; 236 | buildSettings = { 237 | ALWAYS_SEARCH_USER_PATHS = NO; 238 | CLANG_ANALYZER_NONNULL = YES; 239 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 240 | CLANG_CXX_LIBRARY = "libc++"; 241 | CLANG_ENABLE_MODULES = YES; 242 | CLANG_ENABLE_OBJC_ARC = YES; 243 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 244 | CLANG_WARN_BOOL_CONVERSION = YES; 245 | CLANG_WARN_COMMA = YES; 246 | CLANG_WARN_CONSTANT_CONVERSION = YES; 247 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 248 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 249 | CLANG_WARN_EMPTY_BODY = YES; 250 | CLANG_WARN_ENUM_CONVERSION = YES; 251 | CLANG_WARN_INFINITE_RECURSION = YES; 252 | CLANG_WARN_INT_CONVERSION = YES; 253 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 254 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 255 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 256 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 257 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 258 | CLANG_WARN_STRICT_PROTOTYPES = YES; 259 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 260 | CLANG_WARN_UNREACHABLE_CODE = YES; 261 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 262 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 263 | COPY_PHASE_STRIP = NO; 264 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 265 | ENABLE_NS_ASSERTIONS = NO; 266 | ENABLE_STRICT_OBJC_MSGSEND = YES; 267 | GCC_C_LANGUAGE_STANDARD = gnu99; 268 | GCC_NO_COMMON_BLOCKS = YES; 269 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 270 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 271 | GCC_WARN_UNDECLARED_SELECTOR = YES; 272 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 273 | GCC_WARN_UNUSED_FUNCTION = YES; 274 | GCC_WARN_UNUSED_VARIABLE = YES; 275 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 276 | MTL_ENABLE_DEBUG_INFO = NO; 277 | SDKROOT = iphoneos; 278 | SUPPORTED_PLATFORMS = iphoneos; 279 | TARGETED_DEVICE_FAMILY = "1,2"; 280 | VALIDATE_PRODUCT = YES; 281 | }; 282 | name = Profile; 283 | }; 284 | 249021D4217E4FDB00AE95B9 /* Profile */ = { 285 | isa = XCBuildConfiguration; 286 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 287 | buildSettings = { 288 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 289 | CLANG_ENABLE_MODULES = YES; 290 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 291 | ENABLE_BITCODE = NO; 292 | INFOPLIST_FILE = Runner/Info.plist; 293 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 294 | PRODUCT_BUNDLE_IDENTIFIER = com.example.weatherAppFlutter; 295 | PRODUCT_NAME = "$(TARGET_NAME)"; 296 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 297 | SWIFT_VERSION = 5.0; 298 | VERSIONING_SYSTEM = "apple-generic"; 299 | }; 300 | name = Profile; 301 | }; 302 | 97C147031CF9000F007C117D /* Debug */ = { 303 | isa = XCBuildConfiguration; 304 | buildSettings = { 305 | ALWAYS_SEARCH_USER_PATHS = NO; 306 | CLANG_ANALYZER_NONNULL = YES; 307 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 308 | CLANG_CXX_LIBRARY = "libc++"; 309 | CLANG_ENABLE_MODULES = YES; 310 | CLANG_ENABLE_OBJC_ARC = YES; 311 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 312 | CLANG_WARN_BOOL_CONVERSION = YES; 313 | CLANG_WARN_COMMA = YES; 314 | CLANG_WARN_CONSTANT_CONVERSION = YES; 315 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 316 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 317 | CLANG_WARN_EMPTY_BODY = YES; 318 | CLANG_WARN_ENUM_CONVERSION = YES; 319 | CLANG_WARN_INFINITE_RECURSION = YES; 320 | CLANG_WARN_INT_CONVERSION = YES; 321 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 322 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 323 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 324 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 325 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 326 | CLANG_WARN_STRICT_PROTOTYPES = YES; 327 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 328 | CLANG_WARN_UNREACHABLE_CODE = YES; 329 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 330 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 331 | COPY_PHASE_STRIP = NO; 332 | DEBUG_INFORMATION_FORMAT = dwarf; 333 | ENABLE_STRICT_OBJC_MSGSEND = YES; 334 | ENABLE_TESTABILITY = YES; 335 | GCC_C_LANGUAGE_STANDARD = gnu99; 336 | GCC_DYNAMIC_NO_PIC = NO; 337 | GCC_NO_COMMON_BLOCKS = YES; 338 | GCC_OPTIMIZATION_LEVEL = 0; 339 | GCC_PREPROCESSOR_DEFINITIONS = ( 340 | "DEBUG=1", 341 | "$(inherited)", 342 | ); 343 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 344 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 345 | GCC_WARN_UNDECLARED_SELECTOR = YES; 346 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 347 | GCC_WARN_UNUSED_FUNCTION = YES; 348 | GCC_WARN_UNUSED_VARIABLE = YES; 349 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 350 | MTL_ENABLE_DEBUG_INFO = YES; 351 | ONLY_ACTIVE_ARCH = YES; 352 | SDKROOT = iphoneos; 353 | TARGETED_DEVICE_FAMILY = "1,2"; 354 | }; 355 | name = Debug; 356 | }; 357 | 97C147041CF9000F007C117D /* Release */ = { 358 | isa = XCBuildConfiguration; 359 | buildSettings = { 360 | ALWAYS_SEARCH_USER_PATHS = NO; 361 | CLANG_ANALYZER_NONNULL = YES; 362 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 363 | CLANG_CXX_LIBRARY = "libc++"; 364 | CLANG_ENABLE_MODULES = YES; 365 | CLANG_ENABLE_OBJC_ARC = YES; 366 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 367 | CLANG_WARN_BOOL_CONVERSION = YES; 368 | CLANG_WARN_COMMA = YES; 369 | CLANG_WARN_CONSTANT_CONVERSION = YES; 370 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 371 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 372 | CLANG_WARN_EMPTY_BODY = YES; 373 | CLANG_WARN_ENUM_CONVERSION = YES; 374 | CLANG_WARN_INFINITE_RECURSION = YES; 375 | CLANG_WARN_INT_CONVERSION = YES; 376 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 377 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 378 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 379 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 380 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 381 | CLANG_WARN_STRICT_PROTOTYPES = YES; 382 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 383 | CLANG_WARN_UNREACHABLE_CODE = YES; 384 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 385 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 386 | COPY_PHASE_STRIP = NO; 387 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 388 | ENABLE_NS_ASSERTIONS = NO; 389 | ENABLE_STRICT_OBJC_MSGSEND = YES; 390 | GCC_C_LANGUAGE_STANDARD = gnu99; 391 | GCC_NO_COMMON_BLOCKS = YES; 392 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 393 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 394 | GCC_WARN_UNDECLARED_SELECTOR = YES; 395 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 396 | GCC_WARN_UNUSED_FUNCTION = YES; 397 | GCC_WARN_UNUSED_VARIABLE = YES; 398 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 399 | MTL_ENABLE_DEBUG_INFO = NO; 400 | SDKROOT = iphoneos; 401 | SUPPORTED_PLATFORMS = iphoneos; 402 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 403 | TARGETED_DEVICE_FAMILY = "1,2"; 404 | VALIDATE_PRODUCT = YES; 405 | }; 406 | name = Release; 407 | }; 408 | 97C147061CF9000F007C117D /* Debug */ = { 409 | isa = XCBuildConfiguration; 410 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 411 | buildSettings = { 412 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 413 | CLANG_ENABLE_MODULES = YES; 414 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 415 | ENABLE_BITCODE = NO; 416 | INFOPLIST_FILE = Runner/Info.plist; 417 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 418 | PRODUCT_BUNDLE_IDENTIFIER = com.example.weatherAppFlutter; 419 | PRODUCT_NAME = "$(TARGET_NAME)"; 420 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 421 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 422 | SWIFT_VERSION = 5.0; 423 | VERSIONING_SYSTEM = "apple-generic"; 424 | }; 425 | name = Debug; 426 | }; 427 | 97C147071CF9000F007C117D /* Release */ = { 428 | isa = XCBuildConfiguration; 429 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 430 | buildSettings = { 431 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 432 | CLANG_ENABLE_MODULES = YES; 433 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 434 | ENABLE_BITCODE = NO; 435 | INFOPLIST_FILE = Runner/Info.plist; 436 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 437 | PRODUCT_BUNDLE_IDENTIFIER = com.example.weatherAppFlutter; 438 | PRODUCT_NAME = "$(TARGET_NAME)"; 439 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 440 | SWIFT_VERSION = 5.0; 441 | VERSIONING_SYSTEM = "apple-generic"; 442 | }; 443 | name = Release; 444 | }; 445 | /* End XCBuildConfiguration section */ 446 | 447 | /* Begin XCConfigurationList section */ 448 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 449 | isa = XCConfigurationList; 450 | buildConfigurations = ( 451 | 97C147031CF9000F007C117D /* Debug */, 452 | 97C147041CF9000F007C117D /* Release */, 453 | 249021D3217E4FDB00AE95B9 /* Profile */, 454 | ); 455 | defaultConfigurationIsVisible = 0; 456 | defaultConfigurationName = Release; 457 | }; 458 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 459 | isa = XCConfigurationList; 460 | buildConfigurations = ( 461 | 97C147061CF9000F007C117D /* Debug */, 462 | 97C147071CF9000F007C117D /* Release */, 463 | 249021D4217E4FDB00AE95B9 /* Profile */, 464 | ); 465 | defaultConfigurationIsVisible = 0; 466 | defaultConfigurationName = Release; 467 | }; 468 | /* End XCConfigurationList section */ 469 | }; 470 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 471 | } 472 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images": [ 3 | { 4 | "size": "20x20", 5 | "idiom": "iphone", 6 | "filename": "Icon-App-20x20@2x.png", 7 | "scale": "2x" 8 | }, 9 | { 10 | "size": "20x20", 11 | "idiom": "iphone", 12 | "filename": "Icon-App-20x20@3x.png", 13 | "scale": "3x" 14 | }, 15 | { 16 | "size": "29x29", 17 | "idiom": "iphone", 18 | "filename": "Icon-App-29x29@1x.png", 19 | "scale": "1x" 20 | }, 21 | { 22 | "size": "29x29", 23 | "idiom": "iphone", 24 | "filename": "Icon-App-29x29@2x.png", 25 | "scale": "2x" 26 | }, 27 | { 28 | "size": "29x29", 29 | "idiom": "iphone", 30 | "filename": "Icon-App-29x29@3x.png", 31 | "scale": "3x" 32 | }, 33 | { 34 | "size": "40x40", 35 | "idiom": "iphone", 36 | "filename": "Icon-App-40x40@2x.png", 37 | "scale": "2x" 38 | }, 39 | { 40 | "size": "40x40", 41 | "idiom": "iphone", 42 | "filename": "Icon-App-40x40@3x.png", 43 | "scale": "3x" 44 | }, 45 | { 46 | "size": "60x60", 47 | "idiom": "iphone", 48 | "filename": "Icon-App-60x60@2x.png", 49 | "scale": "2x" 50 | }, 51 | { 52 | "size": "60x60", 53 | "idiom": "iphone", 54 | "filename": "Icon-App-60x60@3x.png", 55 | "scale": "3x" 56 | }, 57 | { 58 | "size": "20x20", 59 | "idiom": "ipad", 60 | "filename": "Icon-App-20x20@1x.png", 61 | "scale": "1x" 62 | }, 63 | { 64 | "size": "20x20", 65 | "idiom": "ipad", 66 | "filename": "Icon-App-20x20@2x.png", 67 | "scale": "2x" 68 | }, 69 | { 70 | "size": "29x29", 71 | "idiom": "ipad", 72 | "filename": "Icon-App-29x29@1x.png", 73 | "scale": "1x" 74 | }, 75 | { 76 | "size": "29x29", 77 | "idiom": "ipad", 78 | "filename": "Icon-App-29x29@2x.png", 79 | "scale": "2x" 80 | }, 81 | { 82 | "size": "40x40", 83 | "idiom": "ipad", 84 | "filename": "Icon-App-40x40@1x.png", 85 | "scale": "1x" 86 | }, 87 | { 88 | "size": "40x40", 89 | "idiom": "ipad", 90 | "filename": "Icon-App-40x40@2x.png", 91 | "scale": "2x" 92 | }, 93 | { 94 | "size": "76x76", 95 | "idiom": "ipad", 96 | "filename": "Icon-App-76x76@1x.png", 97 | "scale": "1x" 98 | }, 99 | { 100 | "size": "76x76", 101 | "idiom": "ipad", 102 | "filename": "Icon-App-76x76@2x.png", 103 | "scale": "2x" 104 | }, 105 | { 106 | "size": "83.5x83.5", 107 | "idiom": "ipad", 108 | "filename": "Icon-App-83.5x83.5@2x.png", 109 | "scale": "2x" 110 | }, 111 | { 112 | "size": "1024x1024", 113 | "idiom": "ios-marketing", 114 | "filename": "Icon-App-1024x1024@1x.png", 115 | "scale": "1x" 116 | } 117 | ], 118 | "info": { 119 | "version": 1, 120 | "author": "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hasancse91/weather_app_flutter/2ae0303f2ec7941c341ea2c4bfd3c6055eec588b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hasancse91/weather_app_flutter/2ae0303f2ec7941c341ea2c4bfd3c6055eec588b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hasancse91/weather_app_flutter/2ae0303f2ec7941c341ea2c4bfd3c6055eec588b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hasancse91/weather_app_flutter/2ae0303f2ec7941c341ea2c4bfd3c6055eec588b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hasancse91/weather_app_flutter/2ae0303f2ec7941c341ea2c4bfd3c6055eec588b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hasancse91/weather_app_flutter/2ae0303f2ec7941c341ea2c4bfd3c6055eec588b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hasancse91/weather_app_flutter/2ae0303f2ec7941c341ea2c4bfd3c6055eec588b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hasancse91/weather_app_flutter/2ae0303f2ec7941c341ea2c4bfd3c6055eec588b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hasancse91/weather_app_flutter/2ae0303f2ec7941c341ea2c4bfd3c6055eec588b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hasancse91/weather_app_flutter/2ae0303f2ec7941c341ea2c4bfd3c6055eec588b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hasancse91/weather_app_flutter/2ae0303f2ec7941c341ea2c4bfd3c6055eec588b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hasancse91/weather_app_flutter/2ae0303f2ec7941c341ea2c4bfd3c6055eec588b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hasancse91/weather_app_flutter/2ae0303f2ec7941c341ea2c4bfd3c6055eec588b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hasancse91/weather_app_flutter/2ae0303f2ec7941c341ea2c4bfd3c6055eec588b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hasancse91/weather_app_flutter/2ae0303f2ec7941c341ea2c4bfd3c6055eec588b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images": [ 3 | { 4 | "idiom": "universal", 5 | "filename": "LaunchImage.png", 6 | "scale": "1x" 7 | }, 8 | { 9 | "idiom": "universal", 10 | "filename": "LaunchImage@2x.png", 11 | "scale": "2x" 12 | }, 13 | { 14 | "idiom": "universal", 15 | "filename": "LaunchImage@3x.png", 16 | "scale": "3x" 17 | } 18 | ], 19 | "info": { 20 | "version": 1, 21 | "author": "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hasancse91/weather_app_flutter/2ae0303f2ec7941c341ea2c4bfd3c6055eec588b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hasancse91/weather_app_flutter/2ae0303f2ec7941c341ea2c4bfd3c6055eec588b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hasancse91/weather_app_flutter/2ae0303f2ec7941c341ea2c4bfd3c6055eec588b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | Weather Forecast 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /lib/config/build_config.dart: -------------------------------------------------------------------------------- 1 | import 'package:weather_app_flutter/config/env_config.dart'; 2 | 3 | class BuildConfig { 4 | late final EnvConfig config; 5 | bool _lock = false; 6 | 7 | static final BuildConfig instance = BuildConfig._internal(); 8 | 9 | BuildConfig._internal(); 10 | 11 | factory BuildConfig.instantiate({ 12 | required EnvConfig envConfig, 13 | }) { 14 | if (instance._lock) return instance; 15 | 16 | instance.config = envConfig; 17 | instance._lock = true; 18 | 19 | return instance; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/config/env_config.dart: -------------------------------------------------------------------------------- 1 | import 'package:logger/logger.dart'; 2 | 3 | class EnvConfig { 4 | final String baseUrl; 5 | final String appId; 6 | late final Logger logger; 7 | 8 | EnvConfig({ 9 | required this.baseUrl, 10 | required this.appId, 11 | }) { 12 | logger = Logger( 13 | printer: PrettyPrinter( 14 | colors: true, 15 | printEmojis: true, 16 | printTime: false, 17 | ), 18 | ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/core/app_colors.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | import 'package:flutter/material.dart'; 3 | 4 | abstract class AppColors { 5 | static const Color colorPrimary = Colors.teal; 6 | static const Color colorAccent = Color(0xFFFF5722); 7 | 8 | static const Color textLabelColor = Color(0xFF616161); 9 | static const Color textValueColor = Colors.black; 10 | } -------------------------------------------------------------------------------- /lib/core/app_utils.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:intl/intl.dart'; 4 | 5 | String unixTimestampToDateTimeString(int? timestamp) { 6 | if (timestamp == null) return '--/--'; 7 | var date = DateTime.fromMillisecondsSinceEpoch(timestamp * 1000); 8 | var formattedDate = DateFormat('dd MMM, yyyy - hh:mm a').format(date); 9 | return formattedDate; 10 | } 11 | 12 | String unixTimestampToTimeString(int? timestamp) { 13 | if (timestamp == null) return '--/--'; 14 | var date = DateTime.fromMillisecondsSinceEpoch(timestamp * 1000); 15 | var formattedDate = DateFormat('hh:mm a').format(date); 16 | return formattedDate; 17 | } 18 | 19 | int kelvinToCelsius(double? temperature) { 20 | if (temperature == null) return 0; 21 | 22 | return (temperature - 273.15).toInt(); 23 | } 24 | 25 | enum SnackBarType { MESSAGE, ERROR } 26 | 27 | showSnackBar(BuildContext context, String message, 28 | {SnackBarType type = SnackBarType.MESSAGE}) { 29 | Color backgroundColor = 30 | type == SnackBarType.MESSAGE ? Colors.black87 : Colors.red; 31 | 32 | final snackBar = SnackBar( 33 | backgroundColor: backgroundColor, 34 | content: Text(message), 35 | action: SnackBarAction( 36 | label: 'OK', 37 | onPressed: () { 38 | // Some code to undo the change. 39 | }, 40 | ), 41 | ); 42 | 43 | // Find the ScaffoldMessenger in the widget tree 44 | // and use it to show a SnackBar. 45 | ScaffoldMessenger.of(context).showSnackBar(snackBar); 46 | } 47 | -------------------------------------------------------------------------------- /lib/core/text_style.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:weather_app_flutter/core/app_colors.dart'; 3 | 4 | const extraLargeTitleTextStyle = TextStyle( 5 | fontSize: 80, 6 | fontWeight: FontWeight.w400, 7 | color: Colors.teal, 8 | ); 9 | 10 | const titleTextStyle = TextStyle(color: Colors.teal, fontSize: 20); 11 | 12 | const labelTextStyle = TextStyle( 13 | fontSize: 16, 14 | fontWeight: FontWeight.normal, 15 | color: AppColors.textLabelColor, 16 | ); 17 | 18 | const valueTextStyle = TextStyle( 19 | fontSize: 16, 20 | fontWeight: FontWeight.normal, 21 | color: AppColors.textValueColor, 22 | ); 23 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter/services.dart'; 5 | import 'package:logger/logger.dart'; 6 | import 'package:weather_app_flutter/config/build_config.dart'; 7 | import 'package:weather_app_flutter/config/env_config.dart'; 8 | 9 | import 'ui/home/view/HomePage.dart'; 10 | 11 | Future main() async { 12 | var logger = Logger(); 13 | WidgetsFlutterBinding.ensureInitialized(); 14 | try { 15 | EnvConfig config = await getConfig(); 16 | BuildConfig.instantiate(envConfig: config); 17 | runApp(MyApp()); 18 | } catch (e) { 19 | logger.e(e); 20 | } 21 | } 22 | 23 | class MyApp extends StatelessWidget { 24 | final String appTitle = 'Weather Forecast - Flutter'; 25 | 26 | @override 27 | Widget build(BuildContext context) { 28 | return MaterialApp( 29 | title: appTitle, 30 | theme: ThemeData(primarySwatch: Colors.teal), 31 | home: HomePage(title: appTitle), 32 | debugShowCheckedModeBanner: false, 33 | ); 34 | } 35 | } 36 | 37 | Future getConfig() async { 38 | var logger = Logger(); 39 | try { 40 | String configString = await rootBundle.loadString('assets/config.json'); 41 | final configJson = await json.decode(configString) as Map; 42 | 43 | String baseUrl = configJson['baseUrl']; 44 | String appId = configJson['appId']; 45 | 46 | if(baseUrl.isEmpty || appId.isEmpty) 47 | logger.e('Base URL and AppID should not empty. ' 48 | 'Please follow the guideline for configuring this project.\n' 49 | 'Guideline: https://github.com/hasancse91/weather_app_flutter'); 50 | 51 | return EnvConfig( 52 | baseUrl: baseUrl, 53 | appId: appId, 54 | ); 55 | } catch (e) { 56 | throw Exception('$e\nLocal configuration NOT found. ' 57 | 'Please follow the guideline for configuring this project.\n' 58 | 'Guideline: https://github.com/hasancse91/weather_app_flutter'); 59 | } 60 | } -------------------------------------------------------------------------------- /lib/network/WeatherApi.dart: -------------------------------------------------------------------------------- 1 | import 'package:weather_app_flutter/ui/home/model/weather_data.dart'; 2 | 3 | abstract class WeatherApi { 4 | Future? getWeatherInfo(int? cityId); 5 | } 6 | -------------------------------------------------------------------------------- /lib/network/WeatherApiImpl.dart: -------------------------------------------------------------------------------- 1 | import 'package:weather_app_flutter/config/build_config.dart'; 2 | import 'package:weather_app_flutter/network/WeatherApi.dart'; 3 | import 'package:weather_app_flutter/network/dio_client.dart'; 4 | import 'package:weather_app_flutter/ui/home/model/weather_data.dart'; 5 | import 'package:weather_app_flutter/ui/home/model/weather_response.dart'; 6 | 7 | class WeatherApiImpl extends WeatherApi { 8 | var logger = BuildConfig.instance.config.logger; 9 | 10 | @override 11 | Future? getWeatherInfo(int? cityId) { 12 | return _getWeather(cityId); 13 | } 14 | 15 | Future _getWeather(int? cityId) async { 16 | try { 17 | var dioClient = DioClient().client; 18 | var response = await dioClient.get( 19 | '/weather', 20 | queryParameters: {'id': cityId}, 21 | ); 22 | 23 | logger.i("Response body JSON:\n$response"); 24 | 25 | WeatherResponse weatherResponse = WeatherResponse.fromJson(response.data); 26 | WeatherData weatherData = weatherResponse.toWeatherData(); 27 | return weatherData; 28 | } catch (e) { 29 | throw e; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lib/network/api_interceptor.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | import 'package:pretty_dio_logger/pretty_dio_logger.dart'; 3 | import 'package:weather_app_flutter/config/build_config.dart'; 4 | 5 | List getInterceptors() { 6 | return [ 7 | _getPrettyLoggerInterceptor(), 8 | _getAppIdQueryParameterInterceptor(), 9 | ]; 10 | } 11 | 12 | PrettyDioLogger _getPrettyLoggerInterceptor() { 13 | return PrettyDioLogger(requestHeader: true, responseHeader: true); 14 | } 15 | 16 | Interceptor _getAppIdQueryParameterInterceptor() { 17 | var interceptor = InterceptorsWrapper(onRequest: (options, handler) { 18 | options.queryParameters.addAll( 19 | {'appid': BuildConfig.instance.config.appId}, 20 | ); 21 | 22 | return handler.next(options); 23 | }); 24 | 25 | return interceptor; 26 | } 27 | -------------------------------------------------------------------------------- /lib/network/dio_client.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | import 'package:weather_app_flutter/config/build_config.dart'; 3 | import 'package:weather_app_flutter/network/api_interceptor.dart'; 4 | 5 | class DioClient { 6 | static final DioClient _dioClient = DioClient._internal(); 7 | late Dio _dio; 8 | 9 | factory DioClient() { 10 | return _dioClient; 11 | } 12 | 13 | Dio get client => _dio; 14 | 15 | DioClient._internal() { 16 | var options = BaseOptions( 17 | baseUrl: BuildConfig.instance.config.baseUrl, 18 | connectTimeout: 5000, 19 | receiveTimeout: 3000, 20 | ); 21 | 22 | _dio = Dio(options); 23 | _dio.interceptors.addAll(getInterceptors()); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/ui/home/model/City.dart: -------------------------------------------------------------------------------- 1 | class City { 2 | int id; 3 | String name; 4 | String countryCode; 5 | 6 | City(this.id, this.name, this.countryCode); 7 | 8 | City.fromJson(Map json) 9 | : id = json['id'], 10 | name = json['name'], 11 | countryCode = json['country']; 12 | 13 | Map toJson() => { 14 | 'id': id, 15 | 'name': name, 16 | 'country': countryCode, 17 | }; 18 | } 19 | -------------------------------------------------------------------------------- /lib/ui/home/model/weather_data.dart: -------------------------------------------------------------------------------- 1 | class WeatherData { 2 | String dateTime; 3 | String temperature; 4 | String cityAndCountry; 5 | String weatherConditionIconUrl; 6 | String weatherConditionIconDescription; 7 | String humidity; 8 | String pressure; 9 | String visibility; 10 | String sunrise; 11 | String sunset; 12 | 13 | WeatherData({ 14 | required this.dateTime, 15 | required this.temperature, 16 | required this.cityAndCountry, 17 | required this.weatherConditionIconUrl, 18 | required this.weatherConditionIconDescription, 19 | required this.humidity, 20 | required this.pressure, 21 | required this.visibility, 22 | required this.sunrise, 23 | required this.sunset, 24 | }); 25 | } 26 | -------------------------------------------------------------------------------- /lib/ui/home/model/weather_response.dart: -------------------------------------------------------------------------------- 1 | import 'package:weather_app_flutter/core/app_utils.dart'; 2 | import 'package:weather_app_flutter/ui/home/model/weather_data.dart'; 3 | 4 | /// This code is generated by JsonToDart plugin. 5 | /// Plugin homepage: https://plugins.jetbrains.com/plugin/12562-jsontodart-json-to-dart-/ 6 | class WeatherResponse { 7 | Coord? coord; 8 | List? weather; 9 | String? base; 10 | Main? main; 11 | int? visibility; 12 | Wind? wind; 13 | Clouds? clouds; 14 | int? dt; 15 | Sys? sys; 16 | int? timezone; 17 | int? id; 18 | String? name; 19 | int? cod; 20 | 21 | WeatherResponse( 22 | {this.coord, 23 | this.weather, 24 | this.base, 25 | this.main, 26 | this.visibility, 27 | this.wind, 28 | this.clouds, 29 | this.dt, 30 | this.sys, 31 | this.timezone, 32 | this.id, 33 | this.name, 34 | this.cod}); 35 | 36 | WeatherResponse.fromJson(dynamic json) { 37 | coord = json["coord"] != null ? Coord.fromJson(json["coord"]) : null; 38 | if (json["weather"] != null) { 39 | weather = []; 40 | json["weather"].forEach((v) { 41 | weather?.add(Weather.fromJson(v)); 42 | }); 43 | } 44 | base = json["base"]; 45 | main = json["main"] != null ? Main.fromJson(json["main"]) : null; 46 | visibility = json["visibility"]; 47 | wind = json["wind"] != null ? Wind.fromJson(json["wind"]) : null; 48 | clouds = json["clouds"] != null ? Clouds.fromJson(json["clouds"]) : null; 49 | dt = json["dt"]; 50 | sys = json["sys"] != null ? Sys.fromJson(json["sys"]) : null; 51 | timezone = json["timezone"]; 52 | id = json["id"]; 53 | name = json["name"]; 54 | cod = json["cod"]; 55 | } 56 | 57 | Map toJson() { 58 | var map = {}; 59 | if (coord != null) { 60 | map["coord"] = coord?.toJson(); 61 | } 62 | if (weather != null) { 63 | map["weather"] = weather?.map((v) => v.toJson()).toList(); 64 | } 65 | map["base"] = base; 66 | if (main != null) { 67 | map["main"] = main?.toJson(); 68 | } 69 | map["visibility"] = visibility; 70 | if (wind != null) { 71 | map["wind"] = wind?.toJson(); 72 | } 73 | if (clouds != null) { 74 | map["clouds"] = clouds?.toJson(); 75 | } 76 | map["dt"] = dt; 77 | if (sys != null) { 78 | map["sys"] = sys?.toJson(); 79 | } 80 | map["timezone"] = timezone; 81 | map["id"] = id; 82 | map["name"] = name; 83 | map["cod"] = cod; 84 | return map; 85 | } 86 | 87 | WeatherData toWeatherData() { 88 | return WeatherData( 89 | dateTime: unixTimestampToDateTimeString(dt), 90 | temperature: kelvinToCelsius(main!.temp).toString(), 91 | cityAndCountry: "$name, ${sys!.country}", 92 | weatherConditionIconUrl: 93 | "http://openweathermap.org/img/w/${weather![0].icon}.png", 94 | weatherConditionIconDescription: weather![0].description ?? '', 95 | humidity: "${main!.humidity}%", 96 | pressure: "${main!.pressure} mBar", 97 | visibility: "${visibility! / 1000.0} KM", 98 | sunrise: unixTimestampToTimeString(sys!.sunrise), 99 | sunset: unixTimestampToTimeString(sys!.sunset)); 100 | } 101 | } 102 | 103 | class Sys { 104 | int? type; 105 | int? id; 106 | String? country; 107 | int? sunrise; 108 | int? sunset; 109 | 110 | Sys({this.type, this.id, this.country, this.sunrise, this.sunset}); 111 | 112 | Sys.fromJson(dynamic json) { 113 | type = json["type"]; 114 | id = json["id"]; 115 | country = json["country"]; 116 | sunrise = json["sunrise"]; 117 | sunset = json["sunset"]; 118 | } 119 | 120 | Map toJson() { 121 | var map = {}; 122 | map["type"] = type; 123 | map["id"] = id; 124 | map["country"] = country; 125 | map["sunrise"] = sunrise; 126 | map["sunset"] = sunset; 127 | return map; 128 | } 129 | } 130 | 131 | class Clouds { 132 | int? all; 133 | 134 | Clouds({this.all}); 135 | 136 | Clouds.fromJson(dynamic json) { 137 | all = json["all"]; 138 | } 139 | 140 | Map toJson() { 141 | var map = {}; 142 | map["all"] = all; 143 | return map; 144 | } 145 | } 146 | 147 | class Wind { 148 | num? speed; 149 | int? deg; 150 | double? gust; 151 | 152 | Wind({this.speed, this.deg, this.gust}); 153 | 154 | Wind.fromJson(dynamic json) { 155 | speed = json["speed"]; 156 | deg = json["deg"]; 157 | gust = json["gust"]; 158 | } 159 | 160 | Map toJson() { 161 | var map = {}; 162 | map["speed"] = speed; 163 | map["deg"] = deg; 164 | map["gust"] = gust; 165 | return map; 166 | } 167 | } 168 | 169 | class Main { 170 | double? temp; 171 | double? feelsLike; 172 | double? tempMin; 173 | double? tempMax; 174 | int? pressure; 175 | int? humidity; 176 | int? seaLevel; 177 | int? grndLevel; 178 | 179 | Main( 180 | {this.temp, 181 | this.feelsLike, 182 | this.tempMin, 183 | this.tempMax, 184 | this.pressure, 185 | this.humidity, 186 | this.seaLevel, 187 | this.grndLevel}); 188 | 189 | Main.fromJson(dynamic json) { 190 | temp = json["temp"]; 191 | feelsLike = json["feels_like"]; 192 | tempMin = json["temp_min"]; 193 | tempMax = json["temp_max"]; 194 | pressure = json["pressure"]; 195 | humidity = json["humidity"]; 196 | seaLevel = json["sea_level"]; 197 | grndLevel = json["grnd_level"]; 198 | } 199 | 200 | Map toJson() { 201 | var map = {}; 202 | map["temp"] = temp; 203 | map["feels_like"] = feelsLike; 204 | map["temp_min"] = tempMin; 205 | map["temp_max"] = tempMax; 206 | map["pressure"] = pressure; 207 | map["humidity"] = humidity; 208 | map["sea_level"] = seaLevel; 209 | map["grnd_level"] = grndLevel; 210 | return map; 211 | } 212 | } 213 | 214 | class Weather { 215 | int? id; 216 | String? main; 217 | String? description; 218 | String? icon; 219 | 220 | Weather({this.id, this.main, this.description, this.icon}); 221 | 222 | Weather.fromJson(dynamic json) { 223 | id = json["id"]; 224 | main = json["main"]; 225 | description = json["description"]; 226 | icon = json["icon"]; 227 | } 228 | 229 | Map toJson() { 230 | var map = {}; 231 | map["id"] = id; 232 | map["main"] = main; 233 | map["description"] = description; 234 | map["icon"] = icon; 235 | return map; 236 | } 237 | } 238 | 239 | class Coord { 240 | double? lon; 241 | double? lat; 242 | 243 | Coord({this.lon, this.lat}); 244 | 245 | Coord.fromJson(dynamic json) { 246 | lon = json["lon"]; 247 | lat = json["lat"]; 248 | } 249 | 250 | Map toJson() { 251 | var map = {}; 252 | map["lon"] = lon; 253 | map["lat"] = lat; 254 | return map; 255 | } 256 | } 257 | -------------------------------------------------------------------------------- /lib/ui/home/view/HomePage.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter/services.dart'; 5 | import 'package:flutter/widgets.dart'; 6 | import 'package:weather_app_flutter/config/build_config.dart'; 7 | import 'package:weather_app_flutter/core/app_utils.dart'; 8 | import 'package:weather_app_flutter/network/WeatherApi.dart'; 9 | import 'package:weather_app_flutter/network/WeatherApiImpl.dart'; 10 | import 'package:weather_app_flutter/ui/home/model/City.dart'; 11 | import 'package:weather_app_flutter/ui/home/model/weather_data.dart'; 12 | import 'package:weather_app_flutter/ui/home/widget/weather_data_output.dart'; 13 | 14 | class HomePage extends StatefulWidget { 15 | final String title; 16 | 17 | HomePage({Key? key, required this.title}) : super(key: key); 18 | 19 | @override 20 | _HomePageState createState() => _HomePageState(); 21 | } 22 | 23 | class _HomePageState extends State { 24 | final logger = BuildConfig.instance.config.logger; 25 | List cityList = []; 26 | City? selectedCity; 27 | bool isWeatherDataLoaded = false; 28 | WeatherData? weather; 29 | late WeatherApi weatherApi; 30 | 31 | @override 32 | void initState() { 33 | super.initState(); 34 | readCityList(); 35 | weatherApi = WeatherApiImpl(); 36 | } 37 | 38 | @override 39 | Widget build(BuildContext context) { 40 | return Scaffold( 41 | appBar: AppBar( 42 | title: Text(widget.title), 43 | ), 44 | body: Container( 45 | margin: EdgeInsets.all(20.0), 46 | child: Column( 47 | crossAxisAlignment: CrossAxisAlignment.start, 48 | children: [ 49 | _getInputSection(), 50 | if (isWeatherDataLoaded) WeatherDataOutput(weather: weather!), 51 | ], 52 | ), 53 | ), 54 | ); 55 | } 56 | 57 | _getInputSection() { 58 | return Container( 59 | margin: EdgeInsets.only(bottom: 16.0), 60 | child: Row( 61 | mainAxisAlignment: MainAxisAlignment.spaceEvenly, 62 | children: [ 63 | _getCityDropdown(), 64 | ElevatedButton(onPressed: showWeather, child: Text('VIEW WEATHER')), 65 | ], 66 | )); 67 | } 68 | 69 | DropdownButton _getCityDropdown() { 70 | return DropdownButton( 71 | value: selectedCity, 72 | onChanged: (City? newCity) { 73 | setState(() { 74 | if (newCity != null) selectedCity = newCity; 75 | isWeatherDataLoaded = false; 76 | }); 77 | }, 78 | items: cityList.map((City city) { 79 | return DropdownMenuItem(value: city, child: Text(city.name)); 80 | }).toList(), 81 | ); 82 | } 83 | 84 | void readCityList() async { 85 | String response = await rootBundle.loadString('assets/city_list.json'); 86 | final data = await json.decode(response) as List; 87 | setState(() { 88 | cityList = data.map((city) => City.fromJson(city)).toList(); 89 | selectedCity = cityList[0]; 90 | }); 91 | } 92 | 93 | showWeather() async { 94 | try { 95 | var weatherTemp = await weatherApi.getWeatherInfo(selectedCity?.id); 96 | setState(() { 97 | weather = weatherTemp; 98 | isWeatherDataLoaded = true; 99 | }); 100 | } catch (e) { 101 | showSnackBar(context, e.toString(), type: SnackBarType.ERROR); 102 | logger.e(e); 103 | } 104 | } 105 | } -------------------------------------------------------------------------------- /lib/ui/home/widget/Item_sun_time.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:weather_app_flutter/core/text_style.dart'; 3 | 4 | class ItemSunTime extends StatelessWidget { 5 | final String label; 6 | final String value; 7 | final String imagePath; 8 | 9 | const ItemSunTime({ 10 | Key? key, 11 | required this.label, 12 | required this.value, 13 | required this.imagePath, 14 | }) : super(key: key); 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | return Column( 19 | children: [ 20 | Text(label, style: labelTextStyle), 21 | Container( 22 | child: Image.asset( 23 | imagePath, 24 | width: 100, 25 | height: 100, 26 | ), 27 | margin: EdgeInsets.only(top: 12.0, bottom: 12.0), 28 | ), 29 | Text(value, style: valueTextStyle), 30 | ], 31 | ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lib/ui/home/widget/input_section.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:weather_app_flutter/ui/home/model/City.dart'; 3 | 4 | class InputSection extends StatefulWidget { 5 | final List cityList; 6 | final Function(int) onTap; 7 | 8 | const InputSection({Key? key, required this.cityList, required this.onTap}) 9 | : super(key: key); 10 | 11 | @override 12 | _InputSectionState createState() => 13 | _InputSectionState(cityList: cityList, onTap: onTap); 14 | } 15 | 16 | class _InputSectionState extends State { 17 | final List cityList; 18 | final Function(int) onTap; 19 | City? selectedCity; 20 | 21 | _InputSectionState({required this.cityList, required this.onTap}); 22 | 23 | @override 24 | Widget build(BuildContext context) { 25 | if (cityList.isNotEmpty) selectedCity = cityList[0]; 26 | 27 | return Container( 28 | margin: EdgeInsets.only(bottom: 16.0), 29 | child: Row( 30 | mainAxisAlignment: MainAxisAlignment.spaceEvenly, 31 | children: [ 32 | _getCityDropdown(), 33 | ElevatedButton( 34 | onPressed: onTap(selectedCity!.id), 35 | child: Text('VIEW WEATHER'), 36 | ), 37 | ], 38 | )); 39 | } 40 | 41 | DropdownButton _getCityDropdown() { 42 | return DropdownButton( 43 | value: selectedCity, 44 | onChanged: (City? newCity) { 45 | setState(() { 46 | if (newCity != null) selectedCity = newCity; 47 | }); 48 | }, 49 | items: cityList.map((City city) { 50 | return DropdownMenuItem( 51 | value: city, 52 | child: Text(city.name), 53 | ); 54 | }).toList(), 55 | ); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /lib/ui/home/widget/item_weather_property.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:weather_app_flutter/core/text_style.dart'; 3 | 4 | class ItemWeatherProperty extends StatelessWidget { 5 | final String label; 6 | final String value; 7 | 8 | const ItemWeatherProperty({ 9 | Key? key, 10 | required this.label, 11 | required this.value, 12 | }) : super(key: key); 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | return Padding( 17 | padding: const EdgeInsets.only(top: 4, bottom: 4), 18 | child: Row(children: [ 19 | Text(label, style: labelTextStyle), 20 | SizedBox(width: 24), 21 | Text(value, style: valueTextStyle), 22 | ]), 23 | ); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/ui/home/widget/sun_time.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:weather_app_flutter/ui/home/widget/Item_sun_time.dart'; 3 | 4 | class SunTime extends StatelessWidget { 5 | final String sunrise; 6 | final String sunset; 7 | 8 | const SunTime({ 9 | Key? key, 10 | required this.sunrise, 11 | required this.sunset, 12 | }) : super(key: key); 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | return Row( 17 | mainAxisAlignment: MainAxisAlignment.spaceEvenly, 18 | children: [ 19 | ItemSunTime( 20 | label: "Sunrise", 21 | value: sunrise, 22 | imagePath: 'images/sunrise.png', 23 | ), 24 | ItemSunTime( 25 | label: "Sunset", 26 | value: sunset, 27 | imagePath: 'images/sunset.png', 28 | ), 29 | ], 30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lib/ui/home/widget/temperature_section.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:weather_app_flutter/core/text_style.dart'; 3 | 4 | class TemperatureSection extends StatelessWidget { 5 | final String dateTime; 6 | final String temperature; 7 | final String iconUrl; 8 | final String description; 9 | final String cityAndCountry; 10 | 11 | const TemperatureSection({ 12 | Key? key, 13 | required this.dateTime, 14 | required this.temperature, 15 | required this.iconUrl, 16 | required this.description, 17 | required this.cityAndCountry, 18 | }) : super(key: key); 19 | 20 | @override 21 | Widget build(BuildContext context) { 22 | return Column( 23 | crossAxisAlignment: CrossAxisAlignment.start, 24 | children: [ 25 | Text(dateTime, style: valueTextStyle), 26 | _getTemperatureRow(), 27 | Text(cityAndCountry, style: titleTextStyle) 28 | ], 29 | ); 30 | } 31 | 32 | _getTemperatureRow() { 33 | return Row( 34 | children: [ 35 | Text(temperature, style: extraLargeTitleTextStyle), 36 | Text('°C', style: TextStyle(fontSize: 35, color: Colors.teal)), 37 | Spacer(), 38 | Column( 39 | mainAxisAlignment: MainAxisAlignment.center, 40 | crossAxisAlignment: CrossAxisAlignment.center, 41 | children: [ 42 | // Image.network(iconUrl, width: 60, height: 60), 43 | FadeInImage( 44 | width: 60, 45 | height: 60, 46 | image: NetworkImage(iconUrl), 47 | placeholder: AssetImage("images/placeholder.png"), 48 | imageErrorBuilder: (context, error, stackTrace) { 49 | return Icon(Icons.error); 50 | }, 51 | fit: BoxFit.fitWidth, 52 | ), 53 | Text(description), 54 | ], 55 | ) 56 | ], 57 | ); 58 | } 59 | } -------------------------------------------------------------------------------- /lib/ui/home/widget/weather_data_output.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:weather_app_flutter/ui/home/model/weather_data.dart'; 3 | import 'package:weather_app_flutter/ui/home/widget/sun_time.dart'; 4 | import 'package:weather_app_flutter/ui/home/widget/temperature_section.dart'; 5 | import 'package:weather_app_flutter/ui/home/widget/weather_property.dart'; 6 | 7 | class WeatherDataOutput extends StatelessWidget { 8 | final WeatherData weather; 9 | 10 | const WeatherDataOutput({Key? key, required this.weather}) : super(key: key); 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | return Expanded( 15 | child: Column( 16 | children: [ 17 | TemperatureSection( 18 | dateTime: weather.dateTime, 19 | temperature: weather.temperature, 20 | iconUrl: weather.weatherConditionIconUrl, 21 | description: weather.weatherConditionIconDescription, 22 | cityAndCountry: weather.cityAndCountry, 23 | ), 24 | SizedBox(height: 16), 25 | WeatherProperty( 26 | humidity: weather.humidity, 27 | pressure: weather.pressure, 28 | visibility: weather.visibility, 29 | ), 30 | Spacer(), 31 | SunTime(sunrise: weather.sunrise, sunset: weather.sunset), 32 | SizedBox(height: 10) 33 | ], 34 | ), 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /lib/ui/home/widget/weather_property.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:weather_app_flutter/ui/home/widget/item_weather_property.dart'; 3 | 4 | class WeatherProperty extends StatelessWidget { 5 | final String humidity; 6 | final String pressure; 7 | final String visibility; 8 | 9 | const WeatherProperty({ 10 | Key? key, 11 | required this.humidity, 12 | required this.pressure, 13 | required this.visibility, 14 | }) : super(key: key); 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | return Column( 19 | children: [ 20 | ItemWeatherProperty(label: "Humidity", value: humidity), 21 | ItemWeatherProperty(label: "Pressure", value: pressure), 22 | ItemWeatherProperty(label: "Visibility", value: visibility) 23 | ], 24 | ); 25 | } 26 | } -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | characters: 5 | dependency: transitive 6 | description: 7 | name: characters 8 | url: "https://pub.dartlang.org" 9 | source: hosted 10 | version: "1.1.0" 11 | charcode: 12 | dependency: transitive 13 | description: 14 | name: charcode 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "1.2.0" 18 | clock: 19 | dependency: transitive 20 | description: 21 | name: clock 22 | url: "https://pub.dartlang.org" 23 | source: hosted 24 | version: "1.1.0" 25 | collection: 26 | dependency: transitive 27 | description: 28 | name: collection 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "1.15.0" 32 | cupertino_icons: 33 | dependency: "direct main" 34 | description: 35 | name: cupertino_icons 36 | url: "https://pub.dartlang.org" 37 | source: hosted 38 | version: "1.0.3" 39 | dio: 40 | dependency: "direct main" 41 | description: 42 | name: dio 43 | url: "https://pub.dartlang.org" 44 | source: hosted 45 | version: "4.0.0" 46 | flutter: 47 | dependency: "direct main" 48 | description: flutter 49 | source: sdk 50 | version: "0.0.0" 51 | http_parser: 52 | dependency: transitive 53 | description: 54 | name: http_parser 55 | url: "https://pub.dartlang.org" 56 | source: hosted 57 | version: "4.0.0" 58 | intl: 59 | dependency: "direct main" 60 | description: 61 | name: intl 62 | url: "https://pub.dartlang.org" 63 | source: hosted 64 | version: "0.17.0" 65 | logger: 66 | dependency: "direct dev" 67 | description: 68 | name: logger 69 | url: "https://pub.dartlang.org" 70 | source: hosted 71 | version: "1.0.0" 72 | meta: 73 | dependency: transitive 74 | description: 75 | name: meta 76 | url: "https://pub.dartlang.org" 77 | source: hosted 78 | version: "1.3.0" 79 | path: 80 | dependency: transitive 81 | description: 82 | name: path 83 | url: "https://pub.dartlang.org" 84 | source: hosted 85 | version: "1.8.0" 86 | pretty_dio_logger: 87 | dependency: "direct dev" 88 | description: 89 | name: pretty_dio_logger 90 | url: "https://pub.dartlang.org" 91 | source: hosted 92 | version: "1.2.0-beta-1" 93 | sky_engine: 94 | dependency: transitive 95 | description: flutter 96 | source: sdk 97 | version: "0.0.99" 98 | source_span: 99 | dependency: transitive 100 | description: 101 | name: source_span 102 | url: "https://pub.dartlang.org" 103 | source: hosted 104 | version: "1.8.1" 105 | string_scanner: 106 | dependency: transitive 107 | description: 108 | name: string_scanner 109 | url: "https://pub.dartlang.org" 110 | source: hosted 111 | version: "1.1.0" 112 | term_glyph: 113 | dependency: transitive 114 | description: 115 | name: term_glyph 116 | url: "https://pub.dartlang.org" 117 | source: hosted 118 | version: "1.2.0" 119 | typed_data: 120 | dependency: transitive 121 | description: 122 | name: typed_data 123 | url: "https://pub.dartlang.org" 124 | source: hosted 125 | version: "1.3.0" 126 | vector_math: 127 | dependency: transitive 128 | description: 129 | name: vector_math 130 | url: "https://pub.dartlang.org" 131 | source: hosted 132 | version: "2.1.0" 133 | sdks: 134 | dart: ">=2.12.0 <3.0.0" 135 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: weather_app_flutter 2 | description: A weather forecast flutter App 3 | version: 1.0.0+1 4 | 5 | environment: 6 | sdk: '>=2.12.0 <3.0.0' 7 | 8 | dependencies: 9 | flutter: 10 | sdk: flutter 11 | dio: ^4.0.0 12 | cupertino_icons: ^1.0.2 13 | intl: ^0.17.0 14 | 15 | dev_dependencies: 16 | pretty_dio_logger: ^1.1.1 17 | logger: ^1.0.0 18 | 19 | flutter: 20 | uses-material-design: true 21 | assets: 22 | - images/ 23 | - assets/ 24 | -------------------------------------------------------------------------------- /test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | import 'package:weather_app_flutter/main.dart'; 12 | 13 | void main() { 14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(MyApp()); 17 | 18 | // Verify that our counter starts at 0. 19 | expect(find.text('0'), findsOneWidget); 20 | expect(find.text('1'), findsNothing); 21 | 22 | // Tap the '+' icon and trigger a frame. 23 | await tester.tap(find.byIcon(Icons.add)); 24 | await tester.pump(); 25 | 26 | // Verify that our counter has incremented. 27 | expect(find.text('0'), findsNothing); 28 | expect(find.text('1'), findsOneWidget); 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hasancse91/weather_app_flutter/2ae0303f2ec7941c341ea2c4bfd3c6055eec588b/web/favicon.png -------------------------------------------------------------------------------- /web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hasancse91/weather_app_flutter/2ae0303f2ec7941c341ea2c4bfd3c6055eec588b/web/icons/Icon-192.png -------------------------------------------------------------------------------- /web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hasancse91/weather_app_flutter/2ae0303f2ec7941c341ea2c4bfd3c6055eec588b/web/icons/Icon-512.png -------------------------------------------------------------------------------- /web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | weather_app_flutter 27 | 28 | 29 | 30 | 33 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "weather_app_flutter", 3 | "short_name": "weather_app_flutter", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "A new Flutter project.", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | } 22 | ] 23 | } 24 | --------------------------------------------------------------------------------