├── .gitignore ├── .metadata ├── LICENSE.txt ├── README.md ├── analysis_options.yaml ├── android ├── .gitignore ├── app │ ├── build.gradle │ └── src │ │ ├── debug │ │ └── AndroidManifest.xml │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── kotlin │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── flutter_architecture │ │ │ │ └── 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 ├── 01d.png ├── 01n.png ├── 02d.png ├── 02n.png ├── 03d.png ├── 03n.png ├── 04d.png ├── 04n.png ├── 09d.png ├── 09n.png ├── 1.5x │ ├── 01d.png │ ├── 01n.png │ ├── 02d.png │ ├── 02n.png │ ├── 03d.png │ ├── 03n.png │ ├── 04d.png │ ├── 04n.png │ ├── 09d.png │ ├── 09n.png │ ├── 10d.png │ ├── 10n.png │ ├── 11d.png │ ├── 11n.png │ ├── 13d.png │ ├── 13n.png │ ├── 50d.png │ └── 50n.png ├── 10d.png ├── 10n.png ├── 11d.png ├── 11n.png ├── 13d.png ├── 13n.png ├── 2.0x │ ├── 01d.png │ ├── 01n.png │ ├── 02d.png │ ├── 02n.png │ ├── 03d.png │ ├── 03n.png │ ├── 04d.png │ ├── 04n.png │ ├── 09d.png │ ├── 09n.png │ ├── 10d.png │ ├── 10n.png │ ├── 11d.png │ ├── 11n.png │ ├── 13d.png │ ├── 13n.png │ ├── 50d.png │ └── 50n.png ├── 3.0x │ ├── 01d.png │ ├── 01n.png │ ├── 02d.png │ ├── 02n.png │ ├── 03d.png │ ├── 03n.png │ ├── 04d.png │ ├── 04n.png │ ├── 09d.png │ ├── 09n.png │ ├── 10d.png │ ├── 10n.png │ ├── 11d.png │ ├── 11n.png │ ├── 13d.png │ ├── 13n.png │ ├── 50d.png │ └── 50n.png ├── 50d.png ├── 50n.png ├── humidity_icon.svg ├── lottie_animation.json ├── pressure_icon.svg ├── sunset_icon.svg ├── visibility_icon.svg └── wind_icon.svg ├── fonts ├── Poppins-Bold.ttf ├── Poppins-BoldItalic.ttf ├── Poppins-ExtraBold.ttf ├── Poppins-ExtraBoldItalic.ttf ├── Poppins-Medium.ttf ├── Poppins-MediumItalic.ttf ├── Poppins-Regular.ttf ├── Poppins-SemiBold.ttf └── Poppins-SemiBoldItalic.ttf ├── 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 ├── core │ ├── basecomponents │ │ ├── base_responsive_widget.dart │ │ ├── base_view_model.dart │ │ └── base_view_model_view.dart │ ├── commundomain │ │ ├── entitties │ │ │ └── based_api_result │ │ │ │ ├── api_result_model.dart │ │ │ │ ├── api_result_model.freezed.dart │ │ │ │ ├── api_result_state.dart │ │ │ │ ├── api_result_state.freezed.dart │ │ │ │ └── error_result_model.dart │ │ └── usecases │ │ │ └── base_params_usecase.dart │ ├── di │ │ └── app_component │ │ │ ├── app_component.config.dart │ │ │ ├── app_component.dart │ │ │ └── app_module.dart │ └── utils │ │ ├── auto_router_setup │ │ ├── auto_router.dart │ │ └── auto_router.gr.dart │ │ ├── constants │ │ └── app_constants.dart │ │ ├── helpers │ │ ├── app_configurations_helper │ │ │ └── app_configurations_helper.dart │ │ ├── app_flavor_helper │ │ │ ├── app_flavors_helper.dart │ │ │ └── environment_config.dart │ │ ├── app_theme_helper │ │ │ ├── app_theme_helper.dart │ │ │ └── custom_theme_data.dart │ │ ├── connectivity_helper │ │ │ └── connectivity_checker_helper.dart │ │ ├── custom_exceptions │ │ │ └── custom_connection_exception.dart │ │ ├── extension_functions │ │ │ ├── date_extension_functions.dart │ │ │ ├── extension_functions.dart │ │ │ ├── http_response_extensions.dart │ │ │ └── size_extension.dart │ │ ├── http_strategy_helper │ │ │ ├── concrete_strategies │ │ │ │ ├── delete_request_strategy.dart │ │ │ │ ├── get_request_strategy.dart │ │ │ │ ├── post_request_strategy.dart │ │ │ │ └── put_request_strategy.dart │ │ │ ├── http_request_context.dart │ │ │ └── http_request_strategy.dart │ │ └── responsive_ui_helper │ │ │ └── responsive_config.dart │ │ ├── mapper │ │ └── data_mapper.dart │ │ └── values │ │ ├── colors.dart │ │ └── styles.dart ├── features │ └── weather_info │ │ ├── data │ │ ├── datasources │ │ │ ├── local_datasource │ │ │ │ ├── local_database.dart │ │ │ │ ├── weather_local_datasource.dart │ │ │ │ └── weather_local_datasource_impl.dart │ │ │ └── remote_datasource │ │ │ │ ├── weather_remote_datasource.dart │ │ │ │ └── weather_remote_datasource_impl.dart │ │ ├── models │ │ │ └── weather_info_remote_response_model │ │ │ │ ├── clouds_response │ │ │ │ ├── clouds_response_model.dart │ │ │ │ └── clouds_response_model.g.dart │ │ │ │ ├── coordinate_response │ │ │ │ ├── coordinate_response_model.dart │ │ │ │ └── coordinate_response_model.g.dart │ │ │ │ ├── main_weather_info_response │ │ │ │ ├── main_weather_info_response_model.dart │ │ │ │ └── main_weather_info_response_model.g.dart │ │ │ │ ├── sunset_sunrise_response │ │ │ │ ├── sunset_sunrise_response_model.dart │ │ │ │ └── sunset_sunrise_response_model.g.dart │ │ │ │ ├── weather_description_response │ │ │ │ ├── weather_description_response_model.dart │ │ │ │ └── weather_description_response_model.g.dart │ │ │ │ ├── weather_info_response_model.dart │ │ │ │ ├── weather_info_response_model.g.dart │ │ │ │ └── wind_info_response │ │ │ │ ├── wind_info_response_model.dart │ │ │ │ └── wind_info_response_model.g.dart │ │ └── repositories │ │ │ └── weather_repository_impl.dart │ │ ├── domain │ │ ├── entities │ │ │ ├── weather_local_info_response_entity │ │ │ │ ├── clouds_local_entity.dart │ │ │ │ ├── coordinate_local_entity.dart │ │ │ │ ├── main_weather_info_local_entity.dart │ │ │ │ ├── sunset_sunrise_local_entity.dart │ │ │ │ ├── weather_description_local_entity.dart │ │ │ │ ├── weather_local_info_entity.dart │ │ │ │ ├── weather_theme_local_entity.dart │ │ │ │ └── wind_info_local_entity.dart │ │ │ └── weather_remote_info_response_entity │ │ │ │ ├── clouds_entity.dart │ │ │ │ ├── coordinate_entity.dart │ │ │ │ ├── main_weather_info_entity.dart │ │ │ │ ├── sunset_sunrise_entity.dart │ │ │ │ ├── weather_description_entity.dart │ │ │ │ ├── weather_info_entity.dart │ │ │ │ ├── weather_theme_entity.dart │ │ │ │ └── wind_info_entity.dart │ │ ├── repositories │ │ │ └── weather_repository.dart │ │ └── usecases │ │ │ ├── get_all_local_weathers.dart │ │ │ ├── get_weather_data_by_city.dart │ │ │ └── get_weather_data_by_coordinates.dart │ │ ├── presentation │ │ ├── add_new_city │ │ │ ├── add_new_city_viewmodel.dart │ │ │ ├── view │ │ │ │ └── add_new_city_view.dart │ │ │ └── widgets │ │ │ │ ├── add_new_city_box_details │ │ │ │ └── add_new_city_box_details_widget.dart │ │ │ │ ├── add_new_city_header │ │ │ │ └── add_new_city_header_widget.dart │ │ │ │ └── searsh_city │ │ │ │ └── search_city_widget.dart │ │ └── weather_details │ │ │ ├── view │ │ │ └── weather_details.dart │ │ │ ├── weather_details_viewmodel.dart │ │ │ └── widgets │ │ │ ├── bottom_navigation_bar │ │ │ ├── bottom_navigation_bar_widget.dart │ │ │ └── bottom_navigation_custom_background.dart │ │ │ ├── weather_details_box │ │ │ ├── box_info_item_widget.dart │ │ │ ├── weather_details_box_list.dart │ │ │ └── weather_details_box_widget.dart │ │ │ ├── weather_details_data │ │ │ ├── weather_details_data_widget.dart │ │ │ └── weather_single_info_widget.dart │ │ │ └── weather_details_header │ │ │ └── weather_details_header.dart │ │ └── utils │ │ ├── enums │ │ └── weather_type_enum.dart │ │ └── requests_models │ │ └── weather_by_coordinates_request_model.dart ├── main.dart ├── objectbox-model.json └── objectbox.g.dart ├── pubspec.lock ├── pubspec.yaml ├── test ├── core │ └── utils │ │ └── helpers │ │ ├── api_call_helper_test.dart │ │ └── api_call_helper_test.mocks.dart └── features │ └── weather_info │ ├── data │ ├── datasources │ │ ├── weather_local_datasource_test │ │ │ ├── weather_datasources_test.dart │ │ │ └── weather_datasources_test.mocks.dart │ │ └── weather_remote_datasource_test │ │ │ ├── remote_datasource_test.dart │ │ │ ├── weather_datasources_mock.dart │ │ │ └── weather_datasources_mock.mocks.dart │ ├── models │ │ └── weather_info_response_model_test.dart │ └── repositories │ │ └── weather_repository_impl_test.dart │ └── domain │ ├── repositories │ ├── weather_repository_test.dart │ └── weather_repository_test.mocks.dart │ └── usecases │ ├── get_weather_data_by_city_test.dart │ └── get_weather_data_by_coordinates_test.dart └── test_assets └── weather_info_json_data.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | migrate_working_dir/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # The .vscode folder contains launch configuration and tasks you configure in 20 | # VS Code which you may wish to be included in version control, so this line 21 | # is commented out by default. 22 | #.vscode/ 23 | 24 | # Flutter/Dart/Pub related 25 | **/doc/api/ 26 | **/ios/Flutter/.last_build_id 27 | .dart_tool/ 28 | .flutter-plugins 29 | .flutter-plugins-dependencies 30 | .packages 31 | .pub-cache/ 32 | .pub/ 33 | /build/ 34 | 35 | # Symbolication related 36 | app.*.symbols 37 | 38 | # Obfuscation related 39 | app.*.map.json 40 | 41 | # Android Studio will place build artifacts here 42 | /android/app/debug 43 | /android/app/profile 44 | /android/app/release 45 | 46 | *.lock 47 | -------------------------------------------------------------------------------- /.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. 5 | 6 | version: 7 | revision: 4f9d92fbbdf072a70a70d2179a9f87392b94104c 8 | channel: stable 9 | 10 | project_type: app 11 | 12 | # Tracks metadata for the flutter migrate command 13 | migration: 14 | platforms: 15 | - platform: root 16 | create_revision: 4f9d92fbbdf072a70a70d2179a9f87392b94104c 17 | base_revision: 4f9d92fbbdf072a70a70d2179a9f87392b94104c 18 | - platform: android 19 | create_revision: 4f9d92fbbdf072a70a70d2179a9f87392b94104c 20 | base_revision: 4f9d92fbbdf072a70a70d2179a9f87392b94104c 21 | - platform: ios 22 | create_revision: 4f9d92fbbdf072a70a70d2179a9f87392b94104c 23 | base_revision: 4f9d92fbbdf072a70a70d2179a9f87392b94104c 24 | 25 | # User provided section 26 | 27 | # List of Local paths (relative to this file) that should be 28 | # ignored by the migrate tool. 29 | # 30 | # Files that are not part of the templates will be ignored by default. 31 | unmanaged_files: 32 | - 'lib/main.dart' 33 | - 'ios/Runner.xcodeproj/project.pbxproj' 34 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Marwa Mejri 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # flutter_architecture 2 | 3 | A new Flutter project. 4 | 5 | ## Getting Started 6 | 7 | This project is a starting point for a Flutter application. 8 | 9 | A few resources to get you started if this is your first Flutter project: 10 | 11 | - [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) 12 | - [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) 13 | 14 | For help getting started with Flutter development, view the 15 | [online documentation](https://docs.flutter.dev/), which offers tutorials, 16 | samples, guidance on mobile development, and a full API reference. 17 | -------------------------------------------------------------------------------- /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 | **/*.keystore 13 | **/*.jks 14 | -------------------------------------------------------------------------------- /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 flutter.compileSdkVersion 30 | ndkVersion flutter.ndkVersion 31 | 32 | compileOptions { 33 | sourceCompatibility JavaVersion.VERSION_1_8 34 | targetCompatibility JavaVersion.VERSION_1_8 35 | } 36 | 37 | kotlinOptions { 38 | jvmTarget = '1.8' 39 | } 40 | 41 | sourceSets { 42 | main.java.srcDirs += 'src/main/kotlin' 43 | } 44 | 45 | defaultConfig { 46 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 47 | applicationId "com.example.flutter_architecture" 48 | // You can update the following values to match your application needs. 49 | // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration. 50 | minSdkVersion flutter.minSdkVersion 51 | targetSdkVersion flutter.targetSdkVersion 52 | versionCode flutterVersionCode.toInteger() 53 | versionName flutterVersionName 54 | } 55 | 56 | buildTypes { 57 | release { 58 | // TODO: Add your own signing config for the release build. 59 | // Signing with the debug keys for now, so `flutter run --release` works. 60 | signingConfig signingConfigs.debug 61 | } 62 | } 63 | def appName = "My App" 64 | flavorDimensions "default" 65 | productFlavors { 66 | dev { 67 | applicationId "com.example.flutter_architecture" 68 | dimension "default" 69 | resValue "string", "app_name", "\"$appName (DEV)\"" 70 | } 71 | qa { 72 | applicationId "com.example.flutter_architecture" 73 | dimension "default" 74 | resValue "string", "app_name", "\"$appName (QA)\"" 75 | } 76 | sit { 77 | applicationId "com.example.flutter_architecture" 78 | dimension "default" 79 | resValue "string", "app_name", "\"$appName (SIT)\"" 80 | } 81 | uat { 82 | applicationId "com.example.flutter_architecture" 83 | dimension "default" 84 | resValue "string", "app_name", "\"$appName (UAT)\"" 85 | } 86 | prod { 87 | applicationId "com.example.flutter_architecture.prod" 88 | dimension "default" 89 | resValue "string", "app_name", "\"$appName\"" 90 | } 91 | } 92 | } 93 | 94 | flutter { 95 | source '../..' 96 | } 97 | 98 | dependencies { 99 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 100 | } 101 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 7 | 15 | 19 | 23 | 24 | 25 | 26 | 27 | 28 | 30 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/example/flutter_architecture/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.flutter_architecture 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 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/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 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.6.10' 3 | repositories { 4 | google() 5 | mavenCentral() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:7.1.2' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | mavenCentral() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | } 25 | subprojects { 26 | project.evaluationDependsOn(':app') 27 | } 28 | 29 | tasks.register("clean", Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip 6 | -------------------------------------------------------------------------------- /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/01d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/01d.png -------------------------------------------------------------------------------- /assets/01n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/01n.png -------------------------------------------------------------------------------- /assets/02d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/02d.png -------------------------------------------------------------------------------- /assets/02n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/02n.png -------------------------------------------------------------------------------- /assets/03d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/03d.png -------------------------------------------------------------------------------- /assets/03n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/03n.png -------------------------------------------------------------------------------- /assets/04d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/04d.png -------------------------------------------------------------------------------- /assets/04n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/04n.png -------------------------------------------------------------------------------- /assets/09d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/09d.png -------------------------------------------------------------------------------- /assets/09n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/09n.png -------------------------------------------------------------------------------- /assets/1.5x/01d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/1.5x/01d.png -------------------------------------------------------------------------------- /assets/1.5x/01n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/1.5x/01n.png -------------------------------------------------------------------------------- /assets/1.5x/02d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/1.5x/02d.png -------------------------------------------------------------------------------- /assets/1.5x/02n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/1.5x/02n.png -------------------------------------------------------------------------------- /assets/1.5x/03d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/1.5x/03d.png -------------------------------------------------------------------------------- /assets/1.5x/03n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/1.5x/03n.png -------------------------------------------------------------------------------- /assets/1.5x/04d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/1.5x/04d.png -------------------------------------------------------------------------------- /assets/1.5x/04n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/1.5x/04n.png -------------------------------------------------------------------------------- /assets/1.5x/09d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/1.5x/09d.png -------------------------------------------------------------------------------- /assets/1.5x/09n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/1.5x/09n.png -------------------------------------------------------------------------------- /assets/1.5x/10d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/1.5x/10d.png -------------------------------------------------------------------------------- /assets/1.5x/10n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/1.5x/10n.png -------------------------------------------------------------------------------- /assets/1.5x/11d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/1.5x/11d.png -------------------------------------------------------------------------------- /assets/1.5x/11n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/1.5x/11n.png -------------------------------------------------------------------------------- /assets/1.5x/13d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/1.5x/13d.png -------------------------------------------------------------------------------- /assets/1.5x/13n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/1.5x/13n.png -------------------------------------------------------------------------------- /assets/1.5x/50d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/1.5x/50d.png -------------------------------------------------------------------------------- /assets/1.5x/50n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/1.5x/50n.png -------------------------------------------------------------------------------- /assets/10d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/10d.png -------------------------------------------------------------------------------- /assets/10n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/10n.png -------------------------------------------------------------------------------- /assets/11d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/11d.png -------------------------------------------------------------------------------- /assets/11n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/11n.png -------------------------------------------------------------------------------- /assets/13d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/13d.png -------------------------------------------------------------------------------- /assets/13n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/13n.png -------------------------------------------------------------------------------- /assets/2.0x/01d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/2.0x/01d.png -------------------------------------------------------------------------------- /assets/2.0x/01n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/2.0x/01n.png -------------------------------------------------------------------------------- /assets/2.0x/02d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/2.0x/02d.png -------------------------------------------------------------------------------- /assets/2.0x/02n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/2.0x/02n.png -------------------------------------------------------------------------------- /assets/2.0x/03d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/2.0x/03d.png -------------------------------------------------------------------------------- /assets/2.0x/03n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/2.0x/03n.png -------------------------------------------------------------------------------- /assets/2.0x/04d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/2.0x/04d.png -------------------------------------------------------------------------------- /assets/2.0x/04n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/2.0x/04n.png -------------------------------------------------------------------------------- /assets/2.0x/09d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/2.0x/09d.png -------------------------------------------------------------------------------- /assets/2.0x/09n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/2.0x/09n.png -------------------------------------------------------------------------------- /assets/2.0x/10d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/2.0x/10d.png -------------------------------------------------------------------------------- /assets/2.0x/10n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/2.0x/10n.png -------------------------------------------------------------------------------- /assets/2.0x/11d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/2.0x/11d.png -------------------------------------------------------------------------------- /assets/2.0x/11n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/2.0x/11n.png -------------------------------------------------------------------------------- /assets/2.0x/13d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/2.0x/13d.png -------------------------------------------------------------------------------- /assets/2.0x/13n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/2.0x/13n.png -------------------------------------------------------------------------------- /assets/2.0x/50d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/2.0x/50d.png -------------------------------------------------------------------------------- /assets/2.0x/50n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/2.0x/50n.png -------------------------------------------------------------------------------- /assets/3.0x/01d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/3.0x/01d.png -------------------------------------------------------------------------------- /assets/3.0x/01n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/3.0x/01n.png -------------------------------------------------------------------------------- /assets/3.0x/02d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/3.0x/02d.png -------------------------------------------------------------------------------- /assets/3.0x/02n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/3.0x/02n.png -------------------------------------------------------------------------------- /assets/3.0x/03d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/3.0x/03d.png -------------------------------------------------------------------------------- /assets/3.0x/03n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/3.0x/03n.png -------------------------------------------------------------------------------- /assets/3.0x/04d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/3.0x/04d.png -------------------------------------------------------------------------------- /assets/3.0x/04n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/3.0x/04n.png -------------------------------------------------------------------------------- /assets/3.0x/09d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/3.0x/09d.png -------------------------------------------------------------------------------- /assets/3.0x/09n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/3.0x/09n.png -------------------------------------------------------------------------------- /assets/3.0x/10d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/3.0x/10d.png -------------------------------------------------------------------------------- /assets/3.0x/10n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/3.0x/10n.png -------------------------------------------------------------------------------- /assets/3.0x/11d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/3.0x/11d.png -------------------------------------------------------------------------------- /assets/3.0x/11n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/3.0x/11n.png -------------------------------------------------------------------------------- /assets/3.0x/13d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/3.0x/13d.png -------------------------------------------------------------------------------- /assets/3.0x/13n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/3.0x/13n.png -------------------------------------------------------------------------------- /assets/3.0x/50d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/3.0x/50d.png -------------------------------------------------------------------------------- /assets/3.0x/50n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/3.0x/50n.png -------------------------------------------------------------------------------- /assets/50d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/50d.png -------------------------------------------------------------------------------- /assets/50n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/assets/50n.png -------------------------------------------------------------------------------- /assets/humidity_icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/pressure_icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/sunset_icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/visibility_icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/wind_icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /fonts/Poppins-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/fonts/Poppins-Bold.ttf -------------------------------------------------------------------------------- /fonts/Poppins-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/fonts/Poppins-BoldItalic.ttf -------------------------------------------------------------------------------- /fonts/Poppins-ExtraBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/fonts/Poppins-ExtraBold.ttf -------------------------------------------------------------------------------- /fonts/Poppins-ExtraBoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/fonts/Poppins-ExtraBoldItalic.ttf -------------------------------------------------------------------------------- /fonts/Poppins-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/fonts/Poppins-Medium.ttf -------------------------------------------------------------------------------- /fonts/Poppins-MediumItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/fonts/Poppins-MediumItalic.ttf -------------------------------------------------------------------------------- /fonts/Poppins-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/fonts/Poppins-Regular.ttf -------------------------------------------------------------------------------- /fonts/Poppins-SemiBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/fonts/Poppins-SemiBold.ttf -------------------------------------------------------------------------------- /fonts/Poppins-SemiBoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/fonts/Poppins-SemiBoldItalic.ttf -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | **/dgph 2 | *.mode1v3 3 | *.mode2v3 4 | *.moved-aside 5 | *.pbxuser 6 | *.perspectivev3 7 | **/*sync/ 8 | .sconsign.dblite 9 | .tags* 10 | **/.vagrant/ 11 | **/DerivedData/ 12 | Icon? 13 | **/Pods/ 14 | **/.symlinks/ 15 | profile 16 | xcuserdata 17 | **/.generated/ 18 | Flutter/App.framework 19 | Flutter/Flutter.framework 20 | Flutter/Flutter.podspec 21 | Flutter/Generated.xcconfig 22 | Flutter/ephemeral/ 23 | Flutter/app.flx 24 | Flutter/app.zip 25 | Flutter/flutter_assets/ 26 | Flutter/flutter_export_environment.sh 27 | ServiceDefinitions.json 28 | Runner/GeneratedPluginRegistrant.* 29 | 30 | # Exceptions to above rules. 31 | !default.mode1v3 32 | !default.mode2v3 33 | !default.pbxuser 34 | !default.perspectivev3 35 | -------------------------------------------------------------------------------- /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 | 11.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.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 | 37 | 38 | 39 | 40 | 41 | 42 | 52 | 54 | 60 | 61 | 62 | 63 | 69 | 71 | 77 | 78 | 79 | 80 | 82 | 83 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /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/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/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/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/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/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/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/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/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/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/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/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/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/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/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/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/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/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/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/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/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/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/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/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/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/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/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/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/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/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/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/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marwaMejri/flutter_architecture/c36c18f372376a5b7607f0c27bdd45a40d8da0c5/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 | CFBundleDisplayName 8 | Flutter Architecture 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | flutter_architecture 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(FLUTTER_BUILD_NUMBER) 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIMainStoryboardFile 30 | Main 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | UIViewControllerBasedStatusBarAppearance 45 | 46 | CADisableMinimumFrameDurationOnPhone 47 | 48 | UIApplicationSupportsIndirectInputEvents 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /lib/core/basecomponents/base_responsive_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_architecture/core/di/app_component/app_component.dart'; 3 | import 'package:flutter_architecture/core/utils/helpers/app_configurations_helper/app_configurations_helper.dart'; 4 | import 'package:flutter_architecture/core/utils/helpers/responsive_ui_helper/responsive_config.dart'; 5 | 6 | class BaseResponsiveWidget extends StatelessWidget { 7 | const BaseResponsiveWidget({ 8 | Key? key, 9 | required this.buildWidget, 10 | this.initializeConfig = false, 11 | }) : super(key: key); 12 | 13 | final Widget Function( 14 | BuildContext context, 15 | ResponsiveUiConfig responsiveUiConfig, 16 | AppConfigurations appConfigurations) buildWidget; 17 | final bool initializeConfig; 18 | 19 | @override 20 | Widget build(BuildContext context) { 21 | final ResponsiveUiConfig responsiveUiConfig = locator(); 22 | final AppConfigurations appConfigurations = locator(); 23 | if (initializeConfig) { 24 | responsiveUiConfig.initialize(context); 25 | } 26 | return buildWidget(context, responsiveUiConfig, appConfigurations); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/core/basecomponents/base_view_model.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter/cupertino.dart'; 4 | import 'package:flutter_architecture/core/commundomain/entitties/based_api_result/api_result_model.dart'; 5 | import 'package:flutter_architecture/core/commundomain/entitties/based_api_result/api_result_state.dart'; 6 | import 'package:flutter_architecture/core/commundomain/entitties/based_api_result/error_result_model.dart'; 7 | import 'package:flutter_architecture/core/commundomain/usecases/base_params_usecase.dart'; 8 | 9 | class BaseViewModel extends ChangeNotifier { 10 | final StreamController _toggleLoading = 11 | StreamController.broadcast(); 12 | 13 | StreamController get toggleLoading => _toggleLoading; 14 | 15 | Future?> executeParamsUseCase({ 16 | required BaseParamsUseCase useCase, 17 | Params? query, 18 | bool launchLoader = true, 19 | }) async { 20 | showLoadingIndicator(launchLoader); 21 | final ApiResultModel _apiResult = await useCase(query); 22 | return _apiResult.when( 23 | success: (Type data) { 24 | showLoadingIndicator(false); 25 | return ApiResultState.data(data: data); 26 | }, 27 | failure: (ErrorResultModel errorResultEntity) { 28 | showLoadingIndicator(false); 29 | return ApiResultState.error( 30 | errorResultModel: ErrorResultModel( 31 | message: errorResultEntity.message, 32 | statusCode: errorResultEntity.statusCode, 33 | ), 34 | ); 35 | }, 36 | ); 37 | } 38 | 39 | void showLoadingIndicator(bool show) { 40 | _toggleLoading.add(show); 41 | } 42 | 43 | void onDispose() {} 44 | 45 | @override 46 | void dispose() { 47 | _toggleLoading.close(); 48 | onDispose(); 49 | super.dispose(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /lib/core/basecomponents/base_view_model_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:connectivity_plus/connectivity_plus.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_architecture/core/basecomponents/base_responsive_widget.dart'; 4 | import 'package:flutter_architecture/core/basecomponents/base_view_model.dart'; 5 | import 'package:flutter_architecture/core/utils/constants/app_constants.dart'; 6 | import 'package:flutter_architecture/core/utils/helpers/app_configurations_helper/app_configurations_helper.dart'; 7 | import 'package:flutter_architecture/core/utils/helpers/connectivity_helper/connectivity_checker_helper.dart'; 8 | import 'package:flutter_architecture/core/utils/helpers/extension_functions/size_extension.dart'; 9 | import 'package:flutter_architecture/core/utils/helpers/responsive_ui_helper/responsive_config.dart'; 10 | import 'package:provider/provider.dart'; 11 | 12 | class BaseViewModelView extends StatefulWidget { 13 | const BaseViewModelView({ 14 | Key? key, 15 | this.onInitState, 16 | required this.buildWidget, 17 | }) : super(key: key); 18 | final void Function(T provider)? onInitState; 19 | final Widget Function(T provider) buildWidget; 20 | 21 | @override 22 | State> createState() => _BaseViewModelViewState(); 23 | } 24 | 25 | class _BaseViewModelViewState extends State> { 26 | bool _showLoader = false; 27 | 28 | @override 29 | void initState() { 30 | super.initState(); 31 | final T _provider = Provider.of(context, listen: false); 32 | checkInternetAvailability(); 33 | toggleLoadingWidget(_provider); 34 | if (widget.onInitState != null) { 35 | widget.onInitState!(_provider); 36 | } 37 | } 38 | 39 | void checkInternetAvailability() { 40 | ConnectivityCheckerHelper.listenToConnectivityChanged().listen( 41 | (ConnectivityResult connectivityResult) { 42 | if (connectivityResult == ConnectivityResult.none) { 43 | if (!mounted) { 44 | return; 45 | } 46 | ScaffoldMessenger.of(context).showSnackBar( 47 | const SnackBar( 48 | content: Text(commonConnectionFailedMessage), 49 | ), 50 | ); 51 | } 52 | }, 53 | ); 54 | } 55 | 56 | void toggleLoadingWidget(T provider) { 57 | (provider as BaseViewModel).toggleLoading.stream.listen((bool show) { 58 | if (!mounted) { 59 | return; 60 | } 61 | setState(() { 62 | _showLoader = show; 63 | }); 64 | }); 65 | } 66 | 67 | @override 68 | Widget build(BuildContext context) { 69 | return Consumer( 70 | builder: (BuildContext context, T provider, Widget? child) { 71 | return Stack( 72 | alignment: Alignment.center, 73 | children: [ 74 | widget.buildWidget(provider), 75 | if (_showLoader) 76 | BaseResponsiveWidget( 77 | buildWidget: (BuildContext context, 78 | ResponsiveUiConfig responsiveUiConfig, 79 | AppConfigurations appConfigurations) { 80 | return AnimatedOpacity( 81 | opacity: 1, 82 | duration: const Duration(milliseconds: 200), 83 | child: Container( 84 | width: responsiveUiConfig.screenWidth, 85 | height: responsiveUiConfig.screenHeight, 86 | color: Colors.transparent, 87 | child: Center( 88 | child: Container( 89 | decoration: BoxDecoration( 90 | shape: BoxShape.circle, 91 | color: appConfigurations.appTheme.primaryColor, 92 | ), 93 | padding: EdgeInsets.all( 94 | 15.w, 95 | ), 96 | width: 70.w, 97 | height: 70.w, 98 | child: CircularProgressIndicator( 99 | color: 100 | appConfigurations.appTheme.backgroundLightColor, 101 | ), 102 | ), 103 | ), 104 | ), 105 | ); 106 | }, 107 | ), 108 | ], 109 | ); 110 | }, 111 | ); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /lib/core/commundomain/entitties/based_api_result/api_result_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_architecture/core/commundomain/entitties/based_api_result/error_result_model.dart'; 2 | import 'package:freezed_annotation/freezed_annotation.dart'; 3 | 4 | part 'api_result_model.freezed.dart'; 5 | 6 | @freezed 7 | class ApiResultModel with _$ApiResultModel { 8 | const factory ApiResultModel.success({required T data}) = Success; 9 | 10 | const factory ApiResultModel.failure( 11 | {required ErrorResultModel errorResultEntity}) = Failure; 12 | } 13 | -------------------------------------------------------------------------------- /lib/core/commundomain/entitties/based_api_result/api_result_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_architecture/core/commundomain/entitties/based_api_result/error_result_model.dart'; 2 | import 'package:freezed_annotation/freezed_annotation.dart'; 3 | 4 | part 'api_result_state.freezed.dart'; 5 | 6 | @freezed 7 | class ApiResultState with _$ApiResultState { 8 | const factory ApiResultState.data({required T data}) = Data; 9 | 10 | const factory ApiResultState.error( 11 | {required ErrorResultModel errorResultModel}) = Error; 12 | } 13 | -------------------------------------------------------------------------------- /lib/core/commundomain/entitties/based_api_result/error_result_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | class ErrorResultModel extends Equatable { 4 | const ErrorResultModel({ 5 | this.statusCode, 6 | this.message, 7 | }); 8 | 9 | final int? statusCode; 10 | final String? message; 11 | 12 | @override 13 | List get props => [ 14 | statusCode, 15 | message, 16 | ]; 17 | } 18 | -------------------------------------------------------------------------------- /lib/core/commundomain/usecases/base_params_usecase.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:flutter_architecture/core/commundomain/entitties/based_api_result/api_result_model.dart'; 3 | 4 | abstract class BaseParamsUseCase { 5 | Future> call(Request? params); 6 | } 7 | 8 | class NoParams extends Equatable { 9 | @override 10 | List get props => []; 11 | } 12 | -------------------------------------------------------------------------------- /lib/core/di/app_component/app_component.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_architecture/core/di/app_component/app_component.config.dart'; 2 | import 'package:get_it/get_it.dart'; 3 | import 'package:injectable/injectable.dart'; 4 | 5 | final GetIt locator = GetIt.I; 6 | 7 | @InjectableInit( 8 | preferRelativeImports: false, 9 | ) 10 | Future initAppComponentLocator() async => locator.init(); -------------------------------------------------------------------------------- /lib/core/di/app_component/app_module.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_architecture/features/weather_info/data/datasources/local_datasource/local_database.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | 4 | 5 | @module 6 | abstract class AppModule { 7 | @preResolve 8 | Future get prefs => AppLocalDatabase.create(); 9 | } 10 | -------------------------------------------------------------------------------- /lib/core/utils/auto_router_setup/auto_router.dart: -------------------------------------------------------------------------------- 1 | import 'package:auto_route/auto_route.dart'; 2 | import 'package:flutter_architecture/core/utils/auto_router_setup/auto_router.gr.dart'; 3 | 4 | @AutoRouterConfig() 5 | class AppRouter extends $AppRouter { 6 | @override 7 | List get routes => [ 8 | AutoRoute( 9 | page: WeatherDetailsView.page, 10 | initial: true, 11 | ), 12 | AutoRoute( 13 | page: AddNewCityView.page, 14 | ), 15 | ]; 16 | } 17 | -------------------------------------------------------------------------------- /lib/core/utils/auto_router_setup/auto_router.gr.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | // ************************************************************************** 4 | // AutoRouterGenerator 5 | // ************************************************************************** 6 | 7 | // ignore_for_file: type=lint 8 | // coverage:ignore-file 9 | 10 | // ignore_for_file: no_leading_underscores_for_library_prefixes 11 | import 'package:auto_route/auto_route.dart' as _i3; 12 | import 'package:flutter/material.dart' as _i4; 13 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_remote_info_response_entity/weather_info_entity.dart' 14 | as _i5; 15 | import 'package:flutter_architecture/features/weather_info/presentation/add_new_city/view/add_new_city_view.dart' 16 | as _i1; 17 | import 'package:flutter_architecture/features/weather_info/presentation/weather_details/view/weather_details.dart' 18 | as _i2; 19 | 20 | abstract class $AppRouter extends _i3.RootStackRouter { 21 | $AppRouter({super.navigatorKey}); 22 | 23 | @override 24 | final Map pagesMap = { 25 | AddNewCityView.name: (routeData) { 26 | return _i3.AutoRoutePage( 27 | routeData: routeData, 28 | child: const _i1.AddNewCityView(), 29 | ); 30 | }, 31 | WeatherDetailsView.name: (routeData) { 32 | final args = routeData.argsAs( 33 | orElse: () => const WeatherDetailsViewArgs()); 34 | return _i3.AutoRoutePage( 35 | routeData: routeData, 36 | child: _i2.WeatherDetailsView( 37 | key: args.key, 38 | weatherInfoEntity: args.weatherInfoEntity, 39 | ), 40 | ); 41 | }, 42 | }; 43 | } 44 | 45 | /// generated route for 46 | /// [_i1.AddNewCityView] 47 | class AddNewCityView extends _i3.PageRouteInfo { 48 | const AddNewCityView({List<_i3.PageRouteInfo>? children}) 49 | : super( 50 | AddNewCityView.name, 51 | initialChildren: children, 52 | ); 53 | 54 | static const String name = 'AddNewCityView'; 55 | 56 | static const _i3.PageInfo page = _i3.PageInfo(name); 57 | } 58 | 59 | /// generated route for 60 | /// [_i2.WeatherDetailsView] 61 | class WeatherDetailsView extends _i3.PageRouteInfo { 62 | WeatherDetailsView({ 63 | _i4.Key? key, 64 | _i5.WeatherInfoEntity? weatherInfoEntity, 65 | List<_i3.PageRouteInfo>? children, 66 | }) : super( 67 | WeatherDetailsView.name, 68 | args: WeatherDetailsViewArgs( 69 | key: key, 70 | weatherInfoEntity: weatherInfoEntity, 71 | ), 72 | initialChildren: children, 73 | ); 74 | 75 | static const String name = 'WeatherDetailsView'; 76 | 77 | static const _i3.PageInfo page = 78 | _i3.PageInfo(name); 79 | } 80 | 81 | class WeatherDetailsViewArgs { 82 | const WeatherDetailsViewArgs({ 83 | this.key, 84 | this.weatherInfoEntity, 85 | }); 86 | 87 | final _i4.Key? key; 88 | 89 | final _i5.WeatherInfoEntity? weatherInfoEntity; 90 | 91 | @override 92 | String toString() { 93 | return 'WeatherDetailsViewArgs{key: $key, weatherInfoEntity: $weatherInfoEntity}'; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /lib/core/utils/constants/app_constants.dart: -------------------------------------------------------------------------------- 1 | /// timeout request constants 2 | const String commonErrorUnexpectedMessage = 3 | 'Something went wrong please try again'; 4 | const int timeoutRequestStatusCode = 1000; 5 | 6 | /// app flavors strings 7 | const String devEnvironmentString = 'DEV'; 8 | const String qaEnvironmentString = 'QA'; 9 | const String sitEnvironmentString = 'SIT'; 10 | const String uatEnvironmentString = 'UAT'; 11 | const String prodEnvironmentString = 'PROD'; 12 | 13 | /// IOException request constants 14 | const String commonConnectionFailedMessage = 15 | 'Please check your Internet Connection'; 16 | const int ioExceptionStatusCode = 900; 17 | 18 | /// http client header constants 19 | 20 | const String acceptLanguageKey = 'Accept-Language'; 21 | const String authorisationKey = 'Authorization'; 22 | const String bearerKey = 'Bearer '; 23 | const String contentTypeKey = 'Content-Type'; 24 | const String contentTypeValue = 'application/json'; 25 | const String contentMultipartTypeValue = 'multipart/form-data'; 26 | 27 | ///This is the time limit for every api call 28 | const Duration timeOutDuration = Duration(seconds: 20); 29 | 30 | ///The app base Url should be provided in this value 31 | const String devBaseUrl = 'https://api.openweathermap.org/data/2.5'; 32 | const String prodBaseUrl = 'https://api.openweathermap.org/data/2.5/prod'; 33 | const String qaBaseUrl = 'https://api.openweathermap.org/data/2.5/qa'; 34 | const String uatBaseUrl = 'https://api.openweathermap.org/data/2.5/uat'; 35 | 36 | /// getWeather details uri's and header keys 37 | const String getWeatherDetails = '/weather'; 38 | const String appIdKey = 'appid'; 39 | const String appIdValue = '0ae6735afdc6f99d7af23db5d1bd1fbe'; 40 | const String cityNameKey = 'q'; 41 | const String latitudeKey = 'lat'; 42 | const String longitudeKey = 'lon'; 43 | 44 | /// local database keys 45 | const String weatherInfoTable = 'WeatherInfo'; 46 | -------------------------------------------------------------------------------- /lib/core/utils/helpers/app_configurations_helper/app_configurations_helper.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_architecture/core/di/app_component/app_component.dart'; 2 | import 'package:flutter_architecture/core/utils/helpers/app_flavor_helper/app_flavors_helper.dart'; 3 | import 'package:flutter_architecture/core/utils/helpers/app_theme_helper/custom_theme_data.dart'; 4 | import 'package:flutter_architecture/core/utils/values/colors.dart'; 5 | import 'package:injectable/injectable.dart'; 6 | 7 | @singleton 8 | class AppConfigurations { 9 | String? baseUrl = locator().baseUrl; 10 | CustomThemeData appTheme = CustomThemeData( 11 | buttonEnabledColor: blue3E97C8, 12 | buttonDisabledColor: blueD8E7F2, 13 | primaryColor: blue203C6F, 14 | validColor: green27B15F, 15 | secondaryColor: blueF3F6F8, 16 | thirdColor: blueD8E7F2, 17 | backgroundLightColor: white, 18 | backgroundGreyColor: greyE5E5EA, 19 | errorColor: redCF3A3A, 20 | loaderColor: blue203C6F, 21 | subTitleTextColor: black404040, 22 | titleTextColor: black101010, 23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /lib/core/utils/helpers/app_flavor_helper/app_flavors_helper.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_architecture/core/utils/constants/app_constants.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | 4 | /// this enum will present the list of supported environments 5 | enum ProductFlavor { 6 | DEV, 7 | QA, 8 | SIT, 9 | UAT, 10 | PROD, 11 | } 12 | 13 | extension ProductFlavorExtension on ProductFlavor? { 14 | String setBaseUrl() { 15 | switch (this) { 16 | case ProductFlavor.DEV: 17 | return devBaseUrl; 18 | case ProductFlavor.QA: 19 | return qaBaseUrl; 20 | case ProductFlavor.SIT: 21 | return qaBaseUrl; 22 | case ProductFlavor.UAT: 23 | return uatBaseUrl; 24 | case ProductFlavor.PROD: 25 | return prodBaseUrl; 26 | default: 27 | return devBaseUrl; 28 | } 29 | } 30 | } 31 | 32 | extension StringExtension on String { 33 | ProductFlavor? toProductFlavor() { 34 | switch (this) { 35 | case devEnvironmentString: 36 | return ProductFlavor.DEV; 37 | case qaEnvironmentString: 38 | return ProductFlavor.QA; 39 | case sitEnvironmentString: 40 | return ProductFlavor.SIT; 41 | case uatEnvironmentString: 42 | return ProductFlavor.UAT; 43 | case prodEnvironmentString: 44 | return ProductFlavor.PROD; 45 | default: 46 | return null; 47 | } 48 | } 49 | } 50 | 51 | @singleton 52 | class AppFlavorsHelper { 53 | ProductFlavor? _productFlavor; 54 | String? _baseUrl; 55 | 56 | void configure({required ProductFlavor? productFlavor}) { 57 | _productFlavor = productFlavor; 58 | _baseUrl = productFlavor?.setBaseUrl(); 59 | } 60 | 61 | ProductFlavor? get productFlavor => _productFlavor; 62 | 63 | String? get baseUrl => _baseUrl; 64 | } 65 | -------------------------------------------------------------------------------- /lib/core/utils/helpers/app_flavor_helper/environment_config.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_architecture/core/utils/constants/app_constants.dart'; 2 | 3 | class EnvironmentConfig { 4 | static const String BUILD_VARIANT = String.fromEnvironment('BUILD_VARIANT', 5 | defaultValue: devEnvironmentString); 6 | } 7 | -------------------------------------------------------------------------------- /lib/core/utils/helpers/app_theme_helper/app_theme_helper.dart: -------------------------------------------------------------------------------- 1 | 2 | class AppThemeHelper { 3 | 4 | } 5 | -------------------------------------------------------------------------------- /lib/core/utils/helpers/app_theme_helper/custom_theme_data.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class CustomThemeData { 4 | CustomThemeData({ 5 | required this.buttonEnabledColor, 6 | required this.buttonDisabledColor, 7 | required this.primaryColor, 8 | required this.secondaryColor, 9 | required this.thirdColor, 10 | required this.loaderColor, 11 | required this.errorColor, 12 | required this.validColor, 13 | required this.titleTextColor, 14 | required this.subTitleTextColor, 15 | required this.backgroundLightColor, 16 | required this.backgroundGreyColor, 17 | }); 18 | 19 | Color buttonEnabledColor; 20 | Color buttonDisabledColor; 21 | Color primaryColor; 22 | Color secondaryColor; 23 | Color thirdColor; 24 | Color loaderColor; 25 | Color errorColor; 26 | Color validColor; 27 | Color titleTextColor; 28 | Color subTitleTextColor; 29 | Color backgroundLightColor; 30 | Color backgroundGreyColor; 31 | } 32 | -------------------------------------------------------------------------------- /lib/core/utils/helpers/connectivity_helper/connectivity_checker_helper.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:connectivity_plus/connectivity_plus.dart'; 3 | import 'package:injectable/injectable.dart'; 4 | 5 | @injectable 6 | class ConnectivityCheckerHelper { 7 | Future checkConnectivity() async { 8 | final ConnectivityResult connectivityResult = 9 | await Connectivity().checkConnectivity(); 10 | return _handleResult(connectivityResult); 11 | } 12 | 13 | static Stream listenToConnectivityChanged() { 14 | return Connectivity().onConnectivityChanged; 15 | } 16 | 17 | bool _handleResult(ConnectivityResult connectivityResult) { 18 | final bool connected; 19 | if (connectivityResult == ConnectivityResult.mobile || 20 | connectivityResult == ConnectivityResult.wifi) { 21 | connected = true; 22 | } else { 23 | connected = false; 24 | } 25 | 26 | return connected; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/core/utils/helpers/custom_exceptions/custom_connection_exception.dart: -------------------------------------------------------------------------------- 1 | class CustomConnectionException implements Exception { 2 | CustomConnectionException({this.exceptionCode, this.exceptionMessage}); 3 | 4 | final int? exceptionCode; 5 | final String? exceptionMessage; 6 | } 7 | -------------------------------------------------------------------------------- /lib/core/utils/helpers/extension_functions/date_extension_functions.dart: -------------------------------------------------------------------------------- 1 | import 'package:intl/intl.dart'; 2 | 3 | extension ExtensionsOnNullableInt on int? { 4 | String? fromTimestampToDate() { 5 | if (this != null) { 6 | final DateTime _date = DateTime.fromMillisecondsSinceEpoch(this! * 1000); 7 | return DateFormat('dd-MM-yyyy').format(_date); 8 | } 9 | return null; 10 | } 11 | 12 | String? fromTimestampToTime() { 13 | if (this != null) { 14 | final DateTime _date = DateTime.fromMillisecondsSinceEpoch(this! * 1000); 15 | return DateFormat.Hms().format(_date); 16 | } 17 | return null; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/core/utils/helpers/extension_functions/extension_functions.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:http/http.dart'; 4 | import 'package:intl/intl.dart'; 5 | 6 | extension ExtensionsOnString on String { 7 | Uri parseUri({Map? params}) { 8 | return Uri.parse( 9 | this, 10 | ).replace( 11 | queryParameters: params?.map( 12 | (String key, dynamic value) => MapEntry( 13 | key, 14 | value.toString(), 15 | ), 16 | ), 17 | ); 18 | } 19 | 20 | bool isEqual(String? value) { 21 | return toLowerCase() == value?.toLowerCase(); 22 | } 23 | } 24 | 25 | extension ExtensionsOnDouble on double? { 26 | String? toWindSpeed() { 27 | if (this != null) { 28 | return '${toString()}km/h'; 29 | } 30 | return null; 31 | } 32 | 33 | String? toCelsius() { 34 | if (this != null) { 35 | final NumberFormat numberFormat = NumberFormat('###.##', 'en_US'); 36 | final double value = this! - 273.15; 37 | return '${numberFormat.format(value)}°'; 38 | } 39 | return null; 40 | } 41 | } 42 | 43 | extension ExtensionsOnInt on int? { 44 | String? toKM() { 45 | if (this != null) { 46 | return '${(this! / 1000).round()}Km'; 47 | } 48 | return null; 49 | } 50 | } 51 | 52 | extension ExtensionsOnHttpResponse on Response { 53 | dynamic decodeJson() { 54 | return jsonDecode(body); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /lib/core/utils/helpers/extension_functions/http_response_extensions.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_architecture/core/commundomain/entitties/based_api_result/api_result_model.dart'; 2 | import 'package:flutter_architecture/core/commundomain/entitties/based_api_result/error_result_model.dart'; 3 | import 'package:http/http.dart' as http; 4 | 5 | extension ExtensionOnHttpResponse on http.Response { 6 | ApiResultModel performHttpRequest() { 7 | if (statusCode >= 200 && statusCode < 300) { 8 | return ApiResultModel.success(data: this); 9 | } else { 10 | return ApiResultModel.failure( 11 | errorResultEntity: ErrorResultModel( 12 | message: reasonPhrase, 13 | statusCode: statusCode, 14 | ), 15 | ); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lib/core/utils/helpers/extension_functions/size_extension.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_architecture/core/di/app_component/app_component.dart'; 2 | import 'package:flutter_architecture/core/utils/helpers/responsive_ui_helper/responsive_config.dart'; 3 | 4 | extension ExtensionsOnNum on num { 5 | static final ResponsiveUiConfig _responsiveUiConfig = locator(); 6 | 7 | double get w => _responsiveUiConfig.setWidth(this); 8 | 9 | double get h => _responsiveUiConfig.setHeight(this); 10 | } 11 | -------------------------------------------------------------------------------- /lib/core/utils/helpers/http_strategy_helper/concrete_strategies/delete_request_strategy.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:flutter_architecture/core/commundomain/entitties/based_api_result/api_result_model.dart'; 4 | import 'package:flutter_architecture/core/utils/constants/app_constants.dart'; 5 | import 'package:flutter_architecture/core/utils/helpers/extension_functions/http_response_extensions.dart'; 6 | import 'package:flutter_architecture/core/utils/helpers/http_strategy_helper/http_request_strategy.dart'; 7 | import 'package:http/http.dart' as http; 8 | 9 | class DeleteRequestStrategy implements HttpRequestStrategy { 10 | @override 11 | Future> executeRequest({ 12 | required String uri, 13 | Map headers = const {}, 14 | Map requestData = const {}, 15 | }) async { 16 | final String encodedJson = json.encode(requestData); 17 | final http.Response response = await http 18 | .delete( 19 | Uri.parse(uri), 20 | headers: headers, 21 | body: encodedJson, 22 | ) 23 | .timeout(timeOutDuration); 24 | return response.performHttpRequest(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/core/utils/helpers/http_strategy_helper/concrete_strategies/get_request_strategy.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter_architecture/core/commundomain/entitties/based_api_result/api_result_model.dart'; 4 | import 'package:flutter_architecture/core/utils/constants/app_constants.dart'; 5 | import 'package:flutter_architecture/core/utils/helpers/extension_functions/extension_functions.dart'; 6 | import 'package:flutter_architecture/core/utils/helpers/extension_functions/http_response_extensions.dart'; 7 | import 'package:flutter_architecture/core/utils/helpers/http_strategy_helper/http_request_strategy.dart'; 8 | import 'package:http/http.dart' as http; 9 | 10 | class GetRequestStrategy implements HttpRequestStrategy { 11 | @override 12 | Future> executeRequest({ 13 | required String uri, 14 | Map headers = const {}, 15 | Map requestData = const {}, 16 | }) async { 17 | final http.Response response = await http 18 | .get(uri.parseUri(params: requestData), headers: headers) 19 | .timeout(timeOutDuration); 20 | return response.performHttpRequest(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/core/utils/helpers/http_strategy_helper/concrete_strategies/post_request_strategy.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:flutter_architecture/core/commundomain/entitties/based_api_result/api_result_model.dart'; 4 | import 'package:flutter_architecture/core/utils/constants/app_constants.dart'; 5 | import 'package:flutter_architecture/core/utils/helpers/extension_functions/http_response_extensions.dart'; 6 | import 'package:flutter_architecture/core/utils/helpers/http_strategy_helper/http_request_strategy.dart'; 7 | import 'package:http/http.dart' as http; 8 | 9 | class PostRequestStrategy implements HttpRequestStrategy { 10 | @override 11 | Future> executeRequest({ 12 | required String uri, 13 | Map headers = const {}, 14 | Map requestData = const {}, 15 | }) async { 16 | final String encodedJson = json.encode(requestData); 17 | final http.Response response = await http 18 | .post( 19 | Uri.parse(uri), 20 | headers: headers, 21 | body: encodedJson, 22 | encoding: utf8, 23 | ) 24 | .timeout(timeOutDuration); 25 | return response.performHttpRequest(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lib/core/utils/helpers/http_strategy_helper/concrete_strategies/put_request_strategy.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:flutter_architecture/core/commundomain/entitties/based_api_result/api_result_model.dart'; 4 | import 'package:flutter_architecture/core/utils/constants/app_constants.dart'; 5 | import 'package:flutter_architecture/core/utils/helpers/extension_functions/http_response_extensions.dart'; 6 | import 'package:flutter_architecture/core/utils/helpers/http_strategy_helper/http_request_strategy.dart'; 7 | import 'package:http/http.dart' as http; 8 | 9 | class PutRequestStrategy implements HttpRequestStrategy { 10 | @override 11 | Future> executeRequest({ 12 | required String uri, 13 | Map headers = const {}, 14 | Map requestData = const {}, 15 | }) async { 16 | final String encodedJson = json.encode(requestData); 17 | final http.Response response = await http 18 | .put( 19 | Uri.parse(uri), 20 | headers: headers, 21 | body: encodedJson, 22 | ) 23 | .timeout(timeOutDuration); 24 | return response.performHttpRequest(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/core/utils/helpers/http_strategy_helper/http_request_context.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:io'; 3 | 4 | import 'package:flutter_architecture/core/commundomain/entitties/based_api_result/api_result_model.dart'; 5 | import 'package:flutter_architecture/core/commundomain/entitties/based_api_result/error_result_model.dart'; 6 | import 'package:flutter_architecture/core/di/app_component/app_component.dart'; 7 | import 'package:flutter_architecture/core/utils/constants/app_constants.dart'; 8 | import 'package:flutter_architecture/core/utils/helpers/app_configurations_helper/app_configurations_helper.dart'; 9 | import 'package:flutter_architecture/core/utils/helpers/connectivity_helper/connectivity_checker_helper.dart'; 10 | import 'package:flutter_architecture/core/utils/helpers/custom_exceptions/custom_connection_exception.dart'; 11 | import 'package:flutter_architecture/core/utils/helpers/http_strategy_helper/http_request_strategy.dart'; 12 | import 'package:http/http.dart' as http; 13 | import 'package:injectable/injectable.dart'; 14 | 15 | @injectable 16 | class HttpRequestContext { 17 | HttpRequestContext(this.connectivityCheckerHelper); 18 | 19 | final ConnectivityCheckerHelper connectivityCheckerHelper; 20 | final String? baseUrl = locator().baseUrl; 21 | 22 | Map _sharedDefaultHeader = {}; 23 | 24 | Future initSharedDefaultHeader( 25 | [String contentValue = contentTypeValue]) async { 26 | _sharedDefaultHeader = {}; 27 | _sharedDefaultHeader.addAll({ 28 | contentTypeKey: contentValue, 29 | }); 30 | } 31 | 32 | Future _getConnectionState() async { 33 | final bool _result = await connectivityCheckerHelper.checkConnectivity(); 34 | return _result; 35 | } 36 | 37 | Future> makeRequest({ 38 | required String uri, 39 | required HttpRequestStrategy httpRequestStrategy, 40 | Map headers = const {}, 41 | Map requestData = const {}, 42 | }) async { 43 | await initSharedDefaultHeader(); 44 | _sharedDefaultHeader.addAll(headers); 45 | if (await _getConnectionState()) { 46 | try { 47 | final String _url = '$baseUrl$uri'; 48 | return httpRequestStrategy.executeRequest( 49 | uri: _url, 50 | headers: _sharedDefaultHeader, 51 | requestData: requestData, 52 | ); 53 | } on TimeoutException catch (_) { 54 | return const ApiResultModel.failure( 55 | errorResultEntity: ErrorResultModel( 56 | message: commonErrorUnexpectedMessage, 57 | statusCode: timeoutRequestStatusCode, 58 | ), 59 | ); 60 | } on IOException catch (_) { 61 | throw CustomConnectionException( 62 | exceptionMessage: commonConnectionFailedMessage, 63 | exceptionCode: ioExceptionStatusCode, 64 | ); 65 | } 66 | } else { 67 | throw CustomConnectionException( 68 | exceptionMessage: commonConnectionFailedMessage, 69 | exceptionCode: ioExceptionStatusCode, 70 | ); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /lib/core/utils/helpers/http_strategy_helper/http_request_strategy.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_architecture/core/commundomain/entitties/based_api_result/api_result_model.dart'; 2 | import 'package:http/http.dart' as http; 3 | 4 | abstract class HttpRequestStrategy { 5 | Future> executeRequest({ 6 | required String uri, 7 | Map headers = const {}, 8 | Map requestData = const {}, 9 | }); 10 | } 11 | -------------------------------------------------------------------------------- /lib/core/utils/helpers/responsive_ui_helper/responsive_config.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:injectable/injectable.dart'; 3 | 4 | @singleton 5 | class ResponsiveUiConfig { 6 | late MediaQueryData _mediaQueryData; 7 | late double _screenWidth; 8 | late double _screenHeight; 9 | 10 | double get screenWidth => _screenWidth; 11 | 12 | double get screenHeight => _screenHeight; 13 | 14 | ///this method initialize all of our attributes 15 | void initialize(BuildContext context) { 16 | _mediaQueryData = MediaQuery.of(context); 17 | _screenWidth = _mediaQueryData.size.width; 18 | _screenHeight = _mediaQueryData.size.height; 19 | } 20 | 21 | double setWidth(num value) => _screenWidth * (value / 375); 22 | 23 | double setHeight(num value) => _screenHeight * (value / 812); 24 | } 25 | -------------------------------------------------------------------------------- /lib/core/utils/mapper/data_mapper.dart: -------------------------------------------------------------------------------- 1 | abstract class DataMapper { 2 | Type mapToEntity(); 3 | } 4 | -------------------------------------------------------------------------------- /lib/core/utils/values/colors.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | ///app colors 4 | Color blue3E97C8 = const Color(0xFF3E97C8); 5 | Color white = const Color(0xFFFFFFFF); 6 | Color black101010 = const Color(0xFF101010); 7 | Color black404040 = const Color(0xFF404040); 8 | Color greyDDDDDD = const Color(0xFFDDDDDD); 9 | Color blue203C6F = const Color(0xFF203C6F); 10 | Color blueD8E7F2 = const Color(0xFFD8E7F2); 11 | Color green27B15F = const Color(0xFF27B15F); 12 | Color blueF3F6F8 = const Color(0xFFF3F6F8); 13 | Color redCF3A3A = const Color(0xFFCF3A3A); 14 | Color greyE5E5EA = const Color(0xFFE5E5EA); 15 | 16 | 17 | -------------------------------------------------------------------------------- /lib/core/utils/values/styles.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_architecture/core/utils/values/colors.dart'; 3 | 4 | TextStyle poppinsBold = TextStyle( 5 | color: white, 6 | fontFamily: 'PoppinsBold', 7 | ); 8 | TextStyle poppinsBoldItalic = TextStyle( 9 | color: white, 10 | fontFamily: 'PoppinsBoldItalic', 11 | ); 12 | TextStyle poppinsExtraBold = TextStyle( 13 | color: white, 14 | fontFamily: 'PoppinsExtraBold', 15 | ); 16 | TextStyle poppinsExtraBoldItalic = TextStyle( 17 | color: white, 18 | fontFamily: 'PoppinsExtraBoldItalic', 19 | ); 20 | TextStyle poppinsMedium = TextStyle( 21 | color: white, 22 | fontFamily: 'PoppinsMedium', 23 | ); 24 | TextStyle poppinsMediumItalic = TextStyle( 25 | color: white, 26 | fontFamily: 'PoppinsMediumItalic', 27 | ); 28 | TextStyle poppinsRegular = TextStyle( 29 | color: white, 30 | fontFamily: 'PoppinsRegular', 31 | ); 32 | TextStyle poppinsSemiBold = TextStyle( 33 | color: white, 34 | fontFamily: 'PoppinsSemiBold', 35 | ); 36 | TextStyle poppinsSemiBoldItalic = TextStyle( 37 | color: white, 38 | fontFamily: 'PoppinsSemiBoldItalic', 39 | ); 40 | -------------------------------------------------------------------------------- /lib/features/weather_info/data/datasources/local_datasource/local_database.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:flutter_architecture/objectbox.g.dart'; 4 | import 'package:path/path.dart' as p; 5 | import 'package:path_provider/path_provider.dart'; 6 | 7 | 8 | class AppLocalDatabase { 9 | static Store? _store; 10 | 11 | /// Create an instance of ObjectBox to use throughout the app. 12 | static Future create() async { 13 | final Directory docsDir = await getApplicationDocumentsDirectory(); 14 | _store = await openStore( 15 | directory: p.join(docsDir.path, 'objectbox'), 16 | ); 17 | return AppLocalDatabase(); 18 | } 19 | 20 | int? insert(T object) { 21 | final Box? box = _store?.box(); 22 | return box?.put(object); 23 | } 24 | 25 | Future?> getAll() async { 26 | final Box? box = _store?.box(); 27 | return box?.getAll(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/features/weather_info/data/datasources/local_datasource/weather_local_datasource.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_architecture/features/weather_info/data/models/weather_info_remote_response_model/weather_info_response_model.dart'; 2 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_remote_info_response_entity/weather_info_entity.dart'; 3 | 4 | abstract class WeatherLocalDataSource { 5 | Future getLastWeatherInfo(); 6 | 7 | Future?> getAllLocalWeathers(); 8 | 9 | void cacheWeatherInfo(WeatherInfoResponseModel? weatherInfoResponseModel); 10 | } 11 | -------------------------------------------------------------------------------- /lib/features/weather_info/data/datasources/remote_datasource/weather_remote_datasource.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_architecture/core/commundomain/entitties/based_api_result/api_result_model.dart'; 2 | import 'package:flutter_architecture/features/weather_info/data/models/weather_info_remote_response_model/weather_info_response_model.dart'; 3 | import 'package:flutter_architecture/features/weather_info/utils/requests_models/weather_by_coordinates_request_model.dart'; 4 | 5 | 6 | abstract class WeatherRemoteDataSource { 7 | Future> getWeatherDataByCoordinates( 8 | {WeatherByCoordinatesRequestModel? weatherByCoordinatesRequestModel}); 9 | 10 | Future> getWeatherDataByCity( 11 | {String? cityName}); 12 | } 13 | -------------------------------------------------------------------------------- /lib/features/weather_info/data/datasources/remote_datasource/weather_remote_datasource_impl.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_architecture/core/commundomain/entitties/based_api_result/api_result_model.dart'; 2 | import 'package:flutter_architecture/core/commundomain/entitties/based_api_result/error_result_model.dart'; 3 | import 'package:flutter_architecture/core/utils/constants/app_constants.dart'; 4 | import 'package:flutter_architecture/core/utils/helpers/custom_exceptions/custom_connection_exception.dart'; 5 | import 'package:flutter_architecture/core/utils/helpers/extension_functions/extension_functions.dart'; 6 | import 'package:flutter_architecture/core/utils/helpers/http_strategy_helper/concrete_strategies/get_request_strategy.dart'; 7 | import 'package:flutter_architecture/core/utils/helpers/http_strategy_helper/http_request_context.dart'; 8 | import 'package:flutter_architecture/features/weather_info/data/datasources/remote_datasource/weather_remote_datasource.dart'; 9 | import 'package:flutter_architecture/features/weather_info/data/models/weather_info_remote_response_model/weather_info_response_model.dart'; 10 | import 'package:flutter_architecture/features/weather_info/utils/requests_models/weather_by_coordinates_request_model.dart'; 11 | import 'package:http/http.dart'; 12 | import 'package:injectable/injectable.dart'; 13 | 14 | @Injectable(as: WeatherRemoteDataSource) 15 | class WeatherRemoteDataSourceImpl implements WeatherRemoteDataSource { 16 | WeatherRemoteDataSourceImpl(this._apiCallHelper); 17 | 18 | final HttpRequestContext _apiCallHelper; 19 | 20 | @override 21 | Future> getWeatherDataByCity( 22 | {String? cityName}) async { 23 | try { 24 | final ApiResultModel _result = await _apiCallHelper.makeRequest( 25 | httpRequestStrategy: GetRequestStrategy(), 26 | uri: getWeatherDetails, 27 | requestData: { 28 | cityNameKey: cityName, 29 | appIdKey: appIdValue 30 | }); 31 | return _result.when( 32 | success: (Response response) { 33 | return ApiResultModel.success( 34 | data: WeatherInfoResponseModel.fromJson( 35 | response.decodeJson(), 36 | ), 37 | ); 38 | }, 39 | failure: (ErrorResultModel errorModel) { 40 | return ApiResultModel.failure( 41 | errorResultEntity: errorModel); 42 | }, 43 | ); 44 | } on CustomConnectionException catch (exception) { 45 | throw CustomConnectionException( 46 | exceptionMessage: exception.exceptionMessage, 47 | exceptionCode: exception.exceptionCode, 48 | ); 49 | } 50 | } 51 | 52 | @override 53 | Future> getWeatherDataByCoordinates( 54 | {WeatherByCoordinatesRequestModel? 55 | weatherByCoordinatesRequestModel}) async { 56 | try { 57 | final ApiResultModel _result = await _apiCallHelper.makeRequest( 58 | httpRequestStrategy: GetRequestStrategy(), 59 | uri: getWeatherDetails, 60 | requestData: { 61 | latitudeKey: weatherByCoordinatesRequestModel?.lat, 62 | longitudeKey: weatherByCoordinatesRequestModel?.lon, 63 | appIdKey: appIdValue, 64 | }); 65 | return _result.when( 66 | success: (Response response) { 67 | return ApiResultModel.success( 68 | data: WeatherInfoResponseModel.fromJson( 69 | response.decodeJson(), 70 | ), 71 | ); 72 | }, 73 | failure: (ErrorResultModel errorModel) { 74 | return ApiResultModel.failure( 75 | errorResultEntity: errorModel); 76 | }, 77 | ); 78 | } on CustomConnectionException catch (exception) { 79 | throw CustomConnectionException( 80 | exceptionMessage: exception.exceptionMessage, 81 | exceptionCode: exception.exceptionCode, 82 | ); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /lib/features/weather_info/data/models/weather_info_remote_response_model/clouds_response/clouds_response_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_architecture/core/utils/mapper/data_mapper.dart'; 2 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_remote_info_response_entity/clouds_entity.dart'; 3 | import 'package:json_annotation/json_annotation.dart'; 4 | 5 | part 'clouds_response_model.g.dart'; 6 | 7 | @JsonSerializable() 8 | class CloudsResponseModel extends DataMapper { 9 | CloudsResponseModel({ 10 | this.all, 11 | }); 12 | 13 | factory CloudsResponseModel.fromJson(Map json) => 14 | _$CloudsResponseModelFromJson(json); 15 | 16 | final int? all; 17 | 18 | @override 19 | CloudsEntity mapToEntity() { 20 | return CloudsEntity( 21 | all: all ?? 0, 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/features/weather_info/data/models/weather_info_remote_response_model/clouds_response/clouds_response_model.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'clouds_response_model.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | CloudsResponseModel _$CloudsResponseModelFromJson(Map json) => 10 | CloudsResponseModel( 11 | all: json['all'] as int?, 12 | ); 13 | 14 | Map _$CloudsResponseModelToJson( 15 | CloudsResponseModel instance) => 16 | { 17 | 'all': instance.all, 18 | }; 19 | -------------------------------------------------------------------------------- /lib/features/weather_info/data/models/weather_info_remote_response_model/coordinate_response/coordinate_response_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_architecture/core/utils/mapper/data_mapper.dart'; 2 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_remote_info_response_entity/coordinate_entity.dart'; 3 | import 'package:json_annotation/json_annotation.dart'; 4 | 5 | part 'coordinate_response_model.g.dart'; 6 | 7 | @JsonSerializable() 8 | class CoordinateResponseModel extends DataMapper { 9 | CoordinateResponseModel({ 10 | this.lon, 11 | this.lat, 12 | }); 13 | 14 | factory CoordinateResponseModel.fromJson(Map json) => 15 | _$CoordinateResponseModelFromJson(json); 16 | 17 | final double? lon; 18 | final double? lat; 19 | 20 | @override 21 | CoordinateEntity mapToEntity() { 22 | return CoordinateEntity( 23 | lat: lat ?? 0.0, 24 | lon: lon ?? 0.0, 25 | ); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lib/features/weather_info/data/models/weather_info_remote_response_model/coordinate_response/coordinate_response_model.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'coordinate_response_model.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | CoordinateResponseModel _$CoordinateResponseModelFromJson( 10 | Map json) => 11 | CoordinateResponseModel( 12 | lon: (json['lon'] as num?)?.toDouble(), 13 | lat: (json['lat'] as num?)?.toDouble(), 14 | ); 15 | 16 | Map _$CoordinateResponseModelToJson( 17 | CoordinateResponseModel instance) => 18 | { 19 | 'lon': instance.lon, 20 | 'lat': instance.lat, 21 | }; 22 | -------------------------------------------------------------------------------- /lib/features/weather_info/data/models/weather_info_remote_response_model/main_weather_info_response/main_weather_info_response_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_architecture/core/utils/helpers/extension_functions/extension_functions.dart'; 2 | import 'package:flutter_architecture/core/utils/mapper/data_mapper.dart'; 3 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_remote_info_response_entity/main_weather_info_entity.dart'; 4 | import 'package:json_annotation/json_annotation.dart'; 5 | 6 | part 'main_weather_info_response_model.g.dart'; 7 | 8 | @JsonSerializable() 9 | class MainWeatherInfoResponseModel extends DataMapper { 10 | MainWeatherInfoResponseModel({ 11 | this.temp, 12 | this.feelsLike, 13 | this.tempMin, 14 | this.tempMax, 15 | this.pressure, 16 | this.humidity, 17 | }); 18 | 19 | factory MainWeatherInfoResponseModel.fromJson(Map json) => 20 | _$MainWeatherInfoResponseModelFromJson(json); 21 | 22 | final double? temp; 23 | @JsonKey(name: 'feels_like') 24 | final double? feelsLike; 25 | @JsonKey(name: 'temp_min') 26 | final double? tempMin; 27 | @JsonKey(name: 'temp_max') 28 | final double? tempMax; 29 | final int? pressure; 30 | final int? humidity; 31 | 32 | @override 33 | MainWeatherInfoEntity mapToEntity() { 34 | return MainWeatherInfoEntity( 35 | temp: temp?.toCelsius() ?? '', 36 | feelsLike: feelsLike ?? 0.0, 37 | humidity: humidity ?? 0, 38 | pressure: pressure ?? 0, 39 | tempMax: tempMax ?? 0.0, 40 | tempMin: tempMin ?? 0.0, 41 | ); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /lib/features/weather_info/data/models/weather_info_remote_response_model/main_weather_info_response/main_weather_info_response_model.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'main_weather_info_response_model.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | MainWeatherInfoResponseModel _$MainWeatherInfoResponseModelFromJson( 10 | Map json) => 11 | MainWeatherInfoResponseModel( 12 | temp: (json['temp'] as num?)?.toDouble(), 13 | feelsLike: (json['feels_like'] as num?)?.toDouble(), 14 | tempMin: (json['temp_min'] as num?)?.toDouble(), 15 | tempMax: (json['temp_max'] as num?)?.toDouble(), 16 | pressure: json['pressure'] as int?, 17 | humidity: json['humidity'] as int?, 18 | ); 19 | 20 | Map _$MainWeatherInfoResponseModelToJson( 21 | MainWeatherInfoResponseModel instance) => 22 | { 23 | 'temp': instance.temp, 24 | 'feels_like': instance.feelsLike, 25 | 'temp_min': instance.tempMin, 26 | 'temp_max': instance.tempMax, 27 | 'pressure': instance.pressure, 28 | 'humidity': instance.humidity, 29 | }; 30 | -------------------------------------------------------------------------------- /lib/features/weather_info/data/models/weather_info_remote_response_model/sunset_sunrise_response/sunset_sunrise_response_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_architecture/core/utils/helpers/extension_functions/date_extension_functions.dart'; 2 | import 'package:flutter_architecture/core/utils/mapper/data_mapper.dart'; 3 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_remote_info_response_entity/sunset_sunrise_entity.dart'; 4 | import 'package:json_annotation/json_annotation.dart'; 5 | 6 | part 'sunset_sunrise_response_model.g.dart'; 7 | 8 | @JsonSerializable() 9 | class SunsetSunriseResponseModel extends DataMapper { 10 | SunsetSunriseResponseModel({ 11 | this.type, 12 | this.id, 13 | this.country, 14 | this.sunrise, 15 | this.sunset, 16 | }); 17 | 18 | factory SunsetSunriseResponseModel.fromJson(Map json) => 19 | _$SunsetSunriseResponseModelFromJson(json); 20 | final int? type; 21 | final int? id; 22 | final String? country; 23 | final int? sunrise; 24 | final int? sunset; 25 | 26 | 27 | @override 28 | SunsetSunriseEntity mapToEntity() { 29 | return SunsetSunriseEntity( 30 | sunrise: sunrise?.fromTimestampToTime(), 31 | type: type ?? 0, 32 | id: id ?? 0, 33 | country: country ?? '', 34 | sunset: sunset?.fromTimestampToTime(), 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /lib/features/weather_info/data/models/weather_info_remote_response_model/sunset_sunrise_response/sunset_sunrise_response_model.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'sunset_sunrise_response_model.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | SunsetSunriseResponseModel _$SunsetSunriseResponseModelFromJson( 10 | Map json) => 11 | SunsetSunriseResponseModel( 12 | type: json['type'] as int?, 13 | id: json['id'] as int?, 14 | country: json['country'] as String?, 15 | sunrise: json['sunrise'] as int?, 16 | sunset: json['sunset'] as int?, 17 | ); 18 | 19 | Map _$SunsetSunriseResponseModelToJson( 20 | SunsetSunriseResponseModel instance) => 21 | { 22 | 'type': instance.type, 23 | 'id': instance.id, 24 | 'country': instance.country, 25 | 'sunrise': instance.sunrise, 26 | 'sunset': instance.sunset, 27 | }; 28 | -------------------------------------------------------------------------------- /lib/features/weather_info/data/models/weather_info_remote_response_model/weather_description_response/weather_description_response_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_architecture/core/utils/mapper/data_mapper.dart'; 2 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_remote_info_response_entity/weather_description_entity.dart'; 3 | import 'package:json_annotation/json_annotation.dart'; 4 | 5 | part 'weather_description_response_model.g.dart'; 6 | 7 | @JsonSerializable() 8 | class WeatherDescriptionResponseModel 9 | extends DataMapper { 10 | WeatherDescriptionResponseModel({ 11 | this.id, 12 | this.main, 13 | this.description, 14 | this.icon, 15 | }); 16 | 17 | factory WeatherDescriptionResponseModel.fromJson(Map json) => 18 | _$WeatherDescriptionResponseModelFromJson(json); 19 | 20 | final int? id; 21 | final String? main; 22 | final String? description; 23 | final String? icon; 24 | 25 | 26 | @override 27 | WeatherDescriptionEntity mapToEntity() { 28 | return WeatherDescriptionEntity( 29 | id: id ?? 0, 30 | description: description ?? '', 31 | icon: icon ?? '', 32 | main: main ?? '', 33 | ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /lib/features/weather_info/data/models/weather_info_remote_response_model/weather_description_response/weather_description_response_model.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'weather_description_response_model.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | WeatherDescriptionResponseModel _$WeatherDescriptionResponseModelFromJson( 10 | Map json) => 11 | WeatherDescriptionResponseModel( 12 | id: json['id'] as int?, 13 | main: json['main'] as String?, 14 | description: json['description'] as String?, 15 | icon: json['icon'] as String?, 16 | ); 17 | 18 | Map _$WeatherDescriptionResponseModelToJson( 19 | WeatherDescriptionResponseModel instance) => 20 | { 21 | 'id': instance.id, 22 | 'main': instance.main, 23 | 'description': instance.description, 24 | 'icon': instance.icon, 25 | }; 26 | -------------------------------------------------------------------------------- /lib/features/weather_info/data/models/weather_info_remote_response_model/weather_info_response_model.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'weather_info_response_model.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | WeatherInfoResponseModel _$WeatherInfoResponseModelFromJson( 10 | Map json) => 11 | WeatherInfoResponseModel( 12 | coordinateData: json['coord'] == null 13 | ? null 14 | : CoordinateResponseModel.fromJson( 15 | json['coord'] as Map), 16 | weatherDescription: (json['weather'] as List?) 17 | ?.map((e) => WeatherDescriptionResponseModel.fromJson( 18 | e as Map)) 19 | .toList(), 20 | mainWeatherData: json['main'] == null 21 | ? null 22 | : MainWeatherInfoResponseModel.fromJson( 23 | json['main'] as Map), 24 | weatherVisibility: json['visibility'] as int?, 25 | windData: json['wind'] == null 26 | ? null 27 | : WindInfoResponseModel.fromJson( 28 | json['wind'] as Map), 29 | cloudsData: json['clouds'] == null 30 | ? null 31 | : CloudsResponseModel.fromJson( 32 | json['clouds'] as Map), 33 | date: json['dt'] as int?, 34 | sunsetAndSunriseData: json['sys'] == null 35 | ? null 36 | : SunsetSunriseResponseModel.fromJson( 37 | json['sys'] as Map), 38 | timezone: json['timezone'] as int?, 39 | id: json['id'] as int?, 40 | cityName: json['name'] as String?, 41 | ); 42 | 43 | Map _$WeatherInfoResponseModelToJson( 44 | WeatherInfoResponseModel instance) => 45 | { 46 | 'coord': instance.coordinateData, 47 | 'weather': instance.weatherDescription, 48 | 'main': instance.mainWeatherData, 49 | 'visibility': instance.weatherVisibility, 50 | 'wind': instance.windData, 51 | 'clouds': instance.cloudsData, 52 | 'dt': instance.date, 53 | 'sys': instance.sunsetAndSunriseData, 54 | 'timezone': instance.timezone, 55 | 'id': instance.id, 56 | 'name': instance.cityName, 57 | }; 58 | -------------------------------------------------------------------------------- /lib/features/weather_info/data/models/weather_info_remote_response_model/wind_info_response/wind_info_response_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_architecture/core/utils/helpers/extension_functions/extension_functions.dart'; 2 | import 'package:flutter_architecture/core/utils/mapper/data_mapper.dart'; 3 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_remote_info_response_entity/wind_info_entity.dart'; 4 | import 'package:json_annotation/json_annotation.dart'; 5 | 6 | part 'wind_info_response_model.g.dart'; 7 | 8 | @JsonSerializable() 9 | class WindInfoResponseModel extends DataMapper { 10 | WindInfoResponseModel({ 11 | this.speed, 12 | this.deg, 13 | }); 14 | 15 | factory WindInfoResponseModel.fromJson(Map json) => 16 | _$WindInfoResponseModelFromJson(json); 17 | final double? speed; 18 | final int? deg; 19 | 20 | 21 | @override 22 | WindInfoEntity mapToEntity() { 23 | return WindInfoEntity( 24 | deg: deg ?? 0, 25 | speed: speed?.toWindSpeed() ?? '', 26 | ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/features/weather_info/data/models/weather_info_remote_response_model/wind_info_response/wind_info_response_model.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'wind_info_response_model.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | WindInfoResponseModel _$WindInfoResponseModelFromJson( 10 | Map json) => 11 | WindInfoResponseModel( 12 | speed: (json['speed'] as num?)?.toDouble(), 13 | deg: json['deg'] as int?, 14 | ); 15 | 16 | Map _$WindInfoResponseModelToJson( 17 | WindInfoResponseModel instance) => 18 | { 19 | 'speed': instance.speed, 20 | 'deg': instance.deg, 21 | }; 22 | -------------------------------------------------------------------------------- /lib/features/weather_info/domain/entities/weather_local_info_response_entity/clouds_local_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_architecture/core/utils/mapper/data_mapper.dart'; 2 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_remote_info_response_entity/clouds_entity.dart'; 3 | import 'package:objectbox/objectbox.dart'; 4 | 5 | @Entity() 6 | class CloudsLocalEntity extends DataMapper { 7 | CloudsLocalEntity({ 8 | this.all, 9 | this.id, 10 | }); 11 | 12 | int? all; 13 | int? id; 14 | 15 | @override 16 | CloudsEntity mapToEntity() { 17 | return CloudsEntity( 18 | all: all, 19 | ); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/features/weather_info/domain/entities/weather_local_info_response_entity/coordinate_local_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_architecture/core/utils/mapper/data_mapper.dart'; 2 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_remote_info_response_entity/coordinate_entity.dart'; 3 | import 'package:objectbox/objectbox.dart'; 4 | 5 | 6 | @Entity() 7 | class CoordinateLocalEntity extends DataMapper { 8 | CoordinateLocalEntity({ 9 | this.lon, 10 | this.lat, 11 | this.id, 12 | }); 13 | 14 | int? id; 15 | double? lon; 16 | double? lat; 17 | 18 | @override 19 | CoordinateEntity mapToEntity() { 20 | return CoordinateEntity( 21 | lat: lat, 22 | lon: lon, 23 | ); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/features/weather_info/domain/entities/weather_local_info_response_entity/main_weather_info_local_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_architecture/core/utils/mapper/data_mapper.dart'; 2 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_remote_info_response_entity/main_weather_info_entity.dart'; 3 | import 'package:objectbox/objectbox.dart'; 4 | 5 | 6 | @Entity() 7 | class MainWeatherInfoLocalEntity extends DataMapper { 8 | MainWeatherInfoLocalEntity({ 9 | this.temp, 10 | this.feelsLike, 11 | this.tempMin, 12 | this.tempMax, 13 | this.pressure, 14 | this.humidity, 15 | this.id, 16 | }); 17 | 18 | int? id; 19 | String? temp; 20 | double? feelsLike; 21 | double? tempMin; 22 | double? tempMax; 23 | int? pressure; 24 | int? humidity; 25 | 26 | @override 27 | MainWeatherInfoEntity mapToEntity() { 28 | return MainWeatherInfoEntity( 29 | tempMin: tempMin, 30 | tempMax: tempMax, 31 | pressure: pressure, 32 | humidity: humidity, 33 | feelsLike: feelsLike, 34 | temp: temp, 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /lib/features/weather_info/domain/entities/weather_local_info_response_entity/sunset_sunrise_local_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_architecture/core/utils/mapper/data_mapper.dart'; 2 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_remote_info_response_entity/sunset_sunrise_entity.dart'; 3 | import 'package:objectbox/objectbox.dart'; 4 | 5 | 6 | @Entity() 7 | class SunsetSunriseLocalEntity extends DataMapper { 8 | SunsetSunriseLocalEntity({ 9 | this.type, 10 | this.id, 11 | this.country, 12 | this.sunrise, 13 | this.sunset, 14 | }); 15 | 16 | int? type; 17 | int? id; 18 | String? country; 19 | String? sunrise; 20 | String? sunset; 21 | 22 | @override 23 | SunsetSunriseEntity mapToEntity() { 24 | return SunsetSunriseEntity( 25 | sunset: sunset, 26 | country: country, 27 | type: type, 28 | sunrise: sunrise, 29 | id: id, 30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lib/features/weather_info/domain/entities/weather_local_info_response_entity/weather_description_local_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_architecture/core/utils/mapper/data_mapper.dart'; 2 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_remote_info_response_entity/weather_description_entity.dart'; 3 | import 'package:objectbox/objectbox.dart'; 4 | 5 | 6 | @Entity() 7 | class WeatherDescriptionLocalEntity 8 | extends DataMapper { 9 | WeatherDescriptionLocalEntity({ 10 | this.id, 11 | this.main, 12 | this.description, 13 | this.icon, 14 | }); 15 | 16 | int? id; 17 | String? main; 18 | String? description; 19 | String? icon; 20 | 21 | @override 22 | WeatherDescriptionEntity mapToEntity() { 23 | return WeatherDescriptionEntity( 24 | id: id, 25 | main: main, 26 | icon: icon, 27 | description: description, 28 | ); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/features/weather_info/domain/entities/weather_local_info_response_entity/weather_local_info_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_architecture/core/utils/mapper/data_mapper.dart'; 2 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_local_info_response_entity/clouds_local_entity.dart'; 3 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_local_info_response_entity/main_weather_info_local_entity.dart'; 4 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_local_info_response_entity/sunset_sunrise_local_entity.dart'; 5 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_local_info_response_entity/weather_description_local_entity.dart'; 6 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_local_info_response_entity/weather_theme_local_entity.dart'; 7 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_local_info_response_entity/wind_info_local_entity.dart'; 8 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_remote_info_response_entity/weather_info_entity.dart'; 9 | import 'package:objectbox/objectbox.dart'; 10 | 11 | @Entity() 12 | class WeatherInfoLocalEntity extends DataMapper { 13 | WeatherInfoLocalEntity({ 14 | this.visibility, 15 | this.dt, 16 | this.timezone, 17 | this.id, 18 | this.name, 19 | }); 20 | 21 | final ToMany weather = 22 | ToMany(); 23 | final ToOne main = 24 | ToOne(); 25 | String? visibility; 26 | final ToOne wind = ToOne(); 27 | final ToOne clouds = ToOne(); 28 | String? dt; 29 | final ToOne sys = ToOne(); 30 | int? timezone; 31 | int? id; 32 | @Unique(onConflict: ConflictStrategy.replace) 33 | String? name; 34 | final ToOne weatherTheme = 35 | ToOne(); 36 | 37 | @override 38 | WeatherInfoEntity mapToEntity() { 39 | return WeatherInfoEntity( 40 | timezone: timezone, 41 | id: id, 42 | weatherTheme: weatherTheme.target?.mapToEntity(), 43 | name: name, 44 | weather: weather 45 | .map((WeatherDescriptionLocalEntity element) => element.mapToEntity()) 46 | .toList(), 47 | clouds: clouds.target?.mapToEntity(), 48 | dt: dt, 49 | main: main.target?.mapToEntity(), 50 | visibility: visibility, 51 | sys: sys.target?.mapToEntity(), 52 | wind: wind.target?.mapToEntity(), 53 | ); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /lib/features/weather_info/domain/entities/weather_local_info_response_entity/weather_theme_local_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_architecture/core/utils/mapper/data_mapper.dart'; 3 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_remote_info_response_entity/weather_theme_entity.dart'; 4 | import 'package:objectbox/objectbox.dart'; 5 | 6 | 7 | 8 | @Entity() 9 | class WeatherThemeLocalEntity extends DataMapper { 10 | 11 | WeatherThemeLocalEntity({ 12 | this.firstColorHex, 13 | this.secondColorHex, 14 | this.id, 15 | }); 16 | int? firstColorHex; 17 | int? secondColorHex; 18 | int? id; 19 | 20 | @override 21 | WeatherThemeEntity mapToEntity() { 22 | return WeatherThemeEntity( 23 | secondColor: Color(secondColorHex ?? 0), 24 | firstColor: Color(firstColorHex ?? 0), 25 | ); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lib/features/weather_info/domain/entities/weather_local_info_response_entity/wind_info_local_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_architecture/core/utils/mapper/data_mapper.dart'; 2 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_remote_info_response_entity/wind_info_entity.dart'; 3 | import 'package:objectbox/objectbox.dart'; 4 | 5 | @Entity() 6 | class WindInfoLocalEntity extends DataMapper { 7 | WindInfoLocalEntity({ 8 | this.speed, 9 | this.deg, 10 | this.id, 11 | }); 12 | 13 | int? id; 14 | String? speed; 15 | int? deg; 16 | 17 | @override 18 | WindInfoEntity mapToEntity() { 19 | return WindInfoEntity( 20 | deg: deg, 21 | speed: speed, 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/features/weather_info/domain/entities/weather_remote_info_response_entity/clouds_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | class CloudsEntity extends Equatable { 4 | const CloudsEntity({ 5 | this.all, 6 | }); 7 | 8 | final int? all; 9 | 10 | @override 11 | List get props => [ 12 | all, 13 | ]; 14 | } 15 | -------------------------------------------------------------------------------- /lib/features/weather_info/domain/entities/weather_remote_info_response_entity/coordinate_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | 4 | class CoordinateEntity extends Equatable { 5 | const CoordinateEntity({ 6 | this.lon, 7 | this.lat, 8 | }); 9 | 10 | final double? lon; 11 | final double? lat; 12 | 13 | @override 14 | List get props => [ 15 | lon, 16 | lat, 17 | ]; 18 | } 19 | -------------------------------------------------------------------------------- /lib/features/weather_info/domain/entities/weather_remote_info_response_entity/main_weather_info_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | class MainWeatherInfoEntity extends Equatable { 4 | const MainWeatherInfoEntity({ 5 | this.temp, 6 | this.feelsLike, 7 | this.tempMin, 8 | this.tempMax, 9 | this.pressure, 10 | this.humidity, 11 | }); 12 | 13 | final String? temp; 14 | final double? feelsLike; 15 | final double? tempMin; 16 | final double? tempMax; 17 | final int? pressure; 18 | final int? humidity; 19 | 20 | @override 21 | List get props => 22 | [temp, feelsLike, tempMin, tempMax, pressure, humidity]; 23 | } 24 | -------------------------------------------------------------------------------- /lib/features/weather_info/domain/entities/weather_remote_info_response_entity/sunset_sunrise_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | class SunsetSunriseEntity extends Equatable { 4 | const SunsetSunriseEntity({ 5 | this.type, 6 | this.id, 7 | this.country, 8 | this.sunrise, 9 | this.sunset, 10 | }); 11 | 12 | final int? type; 13 | final int? id; 14 | final String? country; 15 | final String? sunrise; 16 | final String? sunset; 17 | 18 | @override 19 | List get props => [ 20 | type, 21 | id, 22 | country, 23 | sunrise, 24 | sunset, 25 | ]; 26 | } 27 | -------------------------------------------------------------------------------- /lib/features/weather_info/domain/entities/weather_remote_info_response_entity/weather_description_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | class WeatherDescriptionEntity extends Equatable { 4 | const WeatherDescriptionEntity({ 5 | this.id, 6 | this.main, 7 | this.description, 8 | this.icon, 9 | }); 10 | 11 | final int? id; 12 | final String? main; 13 | final String? description; 14 | final String? icon; 15 | 16 | @override 17 | List get props => [ 18 | id, 19 | main, 20 | description, 21 | icon, 22 | ]; 23 | } 24 | -------------------------------------------------------------------------------- /lib/features/weather_info/domain/entities/weather_remote_info_response_entity/weather_info_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_remote_info_response_entity/clouds_entity.dart'; 3 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_remote_info_response_entity/main_weather_info_entity.dart'; 4 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_remote_info_response_entity/sunset_sunrise_entity.dart'; 5 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_remote_info_response_entity/weather_description_entity.dart'; 6 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_remote_info_response_entity/weather_theme_entity.dart'; 7 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_remote_info_response_entity/wind_info_entity.dart'; 8 | 9 | class WeatherInfoEntity extends Equatable { 10 | const WeatherInfoEntity({ 11 | this.weather, 12 | this.main, 13 | this.visibility, 14 | this.wind, 15 | this.clouds, 16 | this.dt, 17 | this.sys, 18 | this.timezone, 19 | this.id, 20 | this.name, 21 | this.weatherTheme, 22 | }); 23 | final List? weather; 24 | final MainWeatherInfoEntity? main; 25 | final String? visibility; 26 | final WindInfoEntity? wind; 27 | final CloudsEntity? clouds; 28 | final String? dt; 29 | final SunsetSunriseEntity? sys; 30 | final int? timezone; 31 | final int? id; 32 | final String? name; 33 | final WeatherThemeEntity? weatherTheme; 34 | 35 | @override 36 | List get props => [ 37 | weather, 38 | main, 39 | visibility, 40 | wind, 41 | clouds, 42 | dt, 43 | sys, 44 | timezone, 45 | id, 46 | name, 47 | weatherTheme, 48 | ]; 49 | } 50 | -------------------------------------------------------------------------------- /lib/features/weather_info/domain/entities/weather_remote_info_response_entity/weather_theme_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class WeatherThemeEntity { 4 | 5 | WeatherThemeEntity({ 6 | this.firstColor, 7 | this.secondColor, 8 | }); 9 | Color? firstColor; 10 | Color? secondColor; 11 | } 12 | -------------------------------------------------------------------------------- /lib/features/weather_info/domain/entities/weather_remote_info_response_entity/wind_info_entity.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | class WindInfoEntity extends Equatable { 4 | const WindInfoEntity({ 5 | this.speed, 6 | this.deg, 7 | }); 8 | 9 | final String? speed; 10 | final int? deg; 11 | 12 | @override 13 | List get props => [ 14 | speed, 15 | deg, 16 | ]; 17 | } 18 | -------------------------------------------------------------------------------- /lib/features/weather_info/domain/repositories/weather_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_architecture/core/commundomain/entitties/based_api_result/api_result_model.dart'; 2 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_remote_info_response_entity/weather_info_entity.dart'; 3 | import 'package:flutter_architecture/features/weather_info/utils/requests_models/weather_by_coordinates_request_model.dart'; 4 | 5 | abstract class WeatherRepository { 6 | Future> getWeatherDataByCoordinates( 7 | {WeatherByCoordinatesRequestModel? weatherByCoordinatesRequestModel}); 8 | 9 | Future> getWeatherDataByCity( 10 | {String? cityName}); 11 | 12 | Future?>> getAllLocalWeathers(); 13 | } 14 | -------------------------------------------------------------------------------- /lib/features/weather_info/domain/usecases/get_all_local_weathers.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_architecture/core/commundomain/entitties/based_api_result/api_result_model.dart'; 2 | import 'package:flutter_architecture/core/commundomain/usecases/base_params_usecase.dart'; 3 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_remote_info_response_entity/weather_info_entity.dart'; 4 | import 'package:flutter_architecture/features/weather_info/domain/repositories/weather_repository.dart'; 5 | import 'package:injectable/injectable.dart'; 6 | 7 | @injectable 8 | class GetAllLocalWeathers 9 | implements BaseParamsUseCase?, NoParams> { 10 | GetAllLocalWeathers(this.weatherRepository); 11 | 12 | final WeatherRepository weatherRepository; 13 | 14 | @override 15 | Future?>> call(NoParams? params) { 16 | return weatherRepository.getAllLocalWeathers(); 17 | 18 | } 19 | 20 | 21 | } 22 | -------------------------------------------------------------------------------- /lib/features/weather_info/domain/usecases/get_weather_data_by_city.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_architecture/core/commundomain/entitties/based_api_result/api_result_model.dart'; 2 | import 'package:flutter_architecture/core/commundomain/usecases/base_params_usecase.dart'; 3 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_remote_info_response_entity/weather_info_entity.dart'; 4 | import 'package:flutter_architecture/features/weather_info/domain/repositories/weather_repository.dart'; 5 | import 'package:injectable/injectable.dart'; 6 | 7 | @injectable 8 | class GetWeatherDataByCity 9 | implements BaseParamsUseCase { 10 | GetWeatherDataByCity(this.weatherRepository); 11 | 12 | final WeatherRepository weatherRepository; 13 | 14 | @override 15 | Future> call(String? cityName) { 16 | return weatherRepository.getWeatherDataByCity(cityName: cityName); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lib/features/weather_info/domain/usecases/get_weather_data_by_coordinates.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_architecture/core/commundomain/entitties/based_api_result/api_result_model.dart'; 2 | import 'package:flutter_architecture/core/commundomain/usecases/base_params_usecase.dart'; 3 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_remote_info_response_entity/weather_info_entity.dart'; 4 | import 'package:flutter_architecture/features/weather_info/domain/repositories/weather_repository.dart'; 5 | import 'package:flutter_architecture/features/weather_info/utils/requests_models/weather_by_coordinates_request_model.dart'; 6 | import 'package:injectable/injectable.dart'; 7 | 8 | @injectable 9 | class GetWeatherDataByCoordinates 10 | implements 11 | BaseParamsUseCase { 13 | GetWeatherDataByCoordinates(this.weatherRepository); 14 | 15 | final WeatherRepository weatherRepository; 16 | 17 | @override 18 | Future> call( 19 | WeatherByCoordinatesRequestModel? weatherByCoordinatesRequestModel) { 20 | return weatherRepository.getWeatherDataByCoordinates( 21 | weatherByCoordinatesRequestModel: weatherByCoordinatesRequestModel); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/features/weather_info/presentation/add_new_city/add_new_city_viewmodel.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter_architecture/core/basecomponents/base_view_model.dart'; 4 | import 'package:flutter_architecture/core/commundomain/entitties/based_api_result/api_result_state.dart'; 5 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_remote_info_response_entity/weather_info_entity.dart'; 6 | import 'package:flutter_architecture/features/weather_info/domain/usecases/get_all_local_weathers.dart'; 7 | import 'package:flutter_architecture/features/weather_info/domain/usecases/get_weather_data_by_city.dart'; 8 | import 'package:injectable/injectable.dart'; 9 | 10 | @injectable 11 | class AddNewCityViewModel extends BaseViewModel { 12 | AddNewCityViewModel( 13 | this.getWeatherDataByCity, 14 | this.getAllLocalWeathers, 15 | ); 16 | 17 | final GetWeatherDataByCity getWeatherDataByCity; 18 | final GetAllLocalWeathers getAllLocalWeathers; 19 | 20 | final StreamController?> _weatherResult = 21 | StreamController?>.broadcast(); 22 | 23 | StreamController?> get weatherResult => 24 | _weatherResult; 25 | final StreamController?>?> 26 | _weatherLocalResult = 27 | StreamController?>?>.broadcast(); 28 | 29 | StreamController?>?> 30 | get weatherLocalResult => _weatherLocalResult; 31 | 32 | Future getWeatherByCity({String? cityName}) async { 33 | final ApiResultState? _result = 34 | await executeParamsUseCase( 35 | useCase: getWeatherDataByCity, 36 | query: cityName, 37 | ); 38 | _weatherResult.add(_result); 39 | } 40 | 41 | Future getAllLocalWeathersData() async { 42 | final ApiResultState?>? _result = 43 | await executeParamsUseCase( 44 | useCase: getAllLocalWeathers, 45 | ); 46 | _weatherLocalResult.add(_result); 47 | } 48 | 49 | @override 50 | void onDispose() { 51 | super.onDispose(); 52 | _weatherLocalResult.close(); 53 | _weatherResult.close(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /lib/features/weather_info/presentation/add_new_city/widgets/add_new_city_box_details/add_new_city_box_details_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_architecture/core/basecomponents/base_responsive_widget.dart'; 3 | import 'package:flutter_architecture/core/utils/helpers/app_configurations_helper/app_configurations_helper.dart'; 4 | import 'package:flutter_architecture/core/utils/helpers/extension_functions/size_extension.dart'; 5 | import 'package:flutter_architecture/core/utils/helpers/responsive_ui_helper/responsive_config.dart'; 6 | import 'package:flutter_architecture/core/utils/values/styles.dart'; 7 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_remote_info_response_entity/weather_info_entity.dart'; 8 | 9 | class AddNewCityBoxDetailsWidget extends StatelessWidget { 10 | const AddNewCityBoxDetailsWidget({ 11 | Key? key, 12 | this.weatherInfoEntity, 13 | this.onClickBox, 14 | }) : super(key: key); 15 | final WeatherInfoEntity? weatherInfoEntity; 16 | final Function(WeatherInfoEntity? weatherInfoEntity)? onClickBox; 17 | 18 | @override 19 | Widget build(BuildContext context) { 20 | return BaseResponsiveWidget( 21 | buildWidget: (BuildContext context, ResponsiveUiConfig responsiveUiConfig, 22 | AppConfigurations appConfigurations) { 23 | return GestureDetector( 24 | onTap: () { 25 | if (onClickBox != null) { 26 | onClickBox!(weatherInfoEntity); 27 | } 28 | }, 29 | child: Container( 30 | width: responsiveUiConfig.screenWidth, 31 | padding: EdgeInsets.symmetric( 32 | horizontal: 20.w, 33 | vertical: 20.h, 34 | ), 35 | margin: EdgeInsets.all(20.w), 36 | decoration: BoxDecoration( 37 | gradient: LinearGradient( 38 | begin: Alignment.topCenter, 39 | end: Alignment.bottomCenter, 40 | colors: [ 41 | weatherInfoEntity?.weatherTheme?.secondColor ?? 42 | appConfigurations.appTheme.thirdColor, 43 | weatherInfoEntity?.weatherTheme?.firstColor ?? 44 | appConfigurations.appTheme.secondaryColor, 45 | ], 46 | ), 47 | borderRadius: BorderRadius.all( 48 | Radius.circular( 49 | 20.w, 50 | ), 51 | ), 52 | ), 53 | child: Row( 54 | mainAxisSize: MainAxisSize.max, 55 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 56 | crossAxisAlignment: CrossAxisAlignment.start, 57 | children: [ 58 | Flexible( 59 | flex: 2, 60 | child: Text( 61 | weatherInfoEntity?.name ?? '', 62 | style: poppinsBold.copyWith( 63 | color: appConfigurations.appTheme.primaryColor, 64 | fontSize: 20.w, 65 | ), 66 | ), 67 | ), 68 | Flexible( 69 | flex: 2, 70 | child: Column( 71 | mainAxisAlignment: MainAxisAlignment.center, 72 | crossAxisAlignment: CrossAxisAlignment.center, 73 | children: [ 74 | Text( 75 | weatherInfoEntity?.main?.temp ?? '', 76 | style: poppinsRegular.copyWith( 77 | fontSize: 16.w, 78 | color: appConfigurations.appTheme.primaryColor, 79 | ), 80 | ), 81 | Text( 82 | weatherInfoEntity?.weather?[0]?.description ?? '', 83 | textAlign: TextAlign.center, 84 | style: poppinsRegular.copyWith( 85 | fontSize: 16.w, 86 | color: appConfigurations.appTheme.primaryColor, 87 | ), 88 | ), 89 | ], 90 | ), 91 | ) 92 | ], 93 | ), 94 | ), 95 | ); 96 | }, 97 | ); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /lib/features/weather_info/presentation/add_new_city/widgets/add_new_city_header/add_new_city_header_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_architecture/core/basecomponents/base_responsive_widget.dart'; 3 | import 'package:flutter_architecture/core/utils/helpers/app_configurations_helper/app_configurations_helper.dart'; 4 | import 'package:flutter_architecture/core/utils/helpers/extension_functions/size_extension.dart'; 5 | import 'package:flutter_architecture/core/utils/helpers/responsive_ui_helper/responsive_config.dart'; 6 | import 'package:flutter_architecture/core/utils/values/colors.dart'; 7 | import 'package:flutter_architecture/core/utils/values/styles.dart'; 8 | 9 | class AddNewCityHeaderWidget extends StatelessWidget { 10 | const AddNewCityHeaderWidget({Key? key}) : super(key: key); 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | return BaseResponsiveWidget( 15 | buildWidget: (BuildContext context, ResponsiveUiConfig responsiveUiConfig, 16 | AppConfigurations appConfigurations) => 17 | Row( 18 | crossAxisAlignment: CrossAxisAlignment.center, 19 | mainAxisAlignment: MainAxisAlignment.start, 20 | mainAxisSize: MainAxisSize.min, 21 | children: [ 22 | IconButton( 23 | onPressed: () { 24 | Navigator.of(context).pop(); 25 | }, 26 | icon: Icon( 27 | Icons.arrow_back, 28 | color: appConfigurations.appTheme.primaryColor, 29 | ), 30 | ), 31 | Text( 32 | 'Manage cities', 33 | style: poppinsMedium.copyWith( 34 | color: appConfigurations.appTheme.primaryColor, 35 | fontSize: 20.w, 36 | ), 37 | ), 38 | ], 39 | ), 40 | ); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /lib/features/weather_info/presentation/add_new_city/widgets/searsh_city/search_city_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_architecture/core/basecomponents/base_responsive_widget.dart'; 3 | import 'package:flutter_architecture/core/utils/helpers/app_configurations_helper/app_configurations_helper.dart'; 4 | import 'package:flutter_architecture/core/utils/helpers/extension_functions/size_extension.dart'; 5 | import 'package:flutter_architecture/core/utils/helpers/responsive_ui_helper/responsive_config.dart'; 6 | import 'package:flutter_architecture/core/utils/values/styles.dart'; 7 | 8 | class SearchCityWidget extends StatelessWidget { 9 | const SearchCityWidget({ 10 | Key? key, 11 | this.controller, 12 | required this.onTapFunction, 13 | }) : super(key: key); 14 | final TextEditingController? controller; 15 | final Function() onTapFunction; 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | return BaseResponsiveWidget( 20 | buildWidget: (BuildContext context, ResponsiveUiConfig responsiveUiConfig, 21 | AppConfigurations appConfigurations) { 22 | return Material( 23 | color: Colors.transparent, 24 | child: Center( 25 | child: Container( 26 | margin: EdgeInsets.symmetric( 27 | horizontal: 20.w, 28 | ), 29 | padding: EdgeInsets.symmetric( 30 | horizontal: 30.w, 31 | vertical: 20.h, 32 | ), 33 | decoration: BoxDecoration( 34 | color: appConfigurations.appTheme.thirdColor, 35 | borderRadius: BorderRadius.all( 36 | Radius.circular( 37 | 20.w, 38 | ), 39 | ), 40 | ), 41 | child: Column( 42 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 43 | crossAxisAlignment: CrossAxisAlignment.center, 44 | mainAxisSize: MainAxisSize.min, 45 | children: [ 46 | Text( 47 | 'Add City', 48 | style: poppinsBold.copyWith( 49 | color: appConfigurations.appTheme.primaryColor, 50 | fontSize: 20.w, 51 | ), 52 | ), 53 | SizedBox( 54 | height: 20.h, 55 | ), 56 | TextFormField( 57 | controller: controller, 58 | decoration: InputDecoration( 59 | contentPadding: EdgeInsets.all( 60 | 8.w, 61 | ), 62 | border: OutlineInputBorder( 63 | borderRadius: BorderRadius.circular(10.w), 64 | ), 65 | hintText: 'Enter a place name', 66 | prefixIcon: Icon( 67 | Icons.search, 68 | color: appConfigurations.appTheme.backgroundGreyColor, 69 | size: 25.w, 70 | ), 71 | ), 72 | ), 73 | SizedBox( 74 | height: 20.h, 75 | ), 76 | GestureDetector( 77 | onTap: () { 78 | Navigator.pop(context); 79 | onTapFunction(); 80 | }, 81 | child: Container( 82 | padding: EdgeInsets.all( 83 | 10.w, 84 | ), 85 | decoration: BoxDecoration( 86 | shape: BoxShape.circle, 87 | color: appConfigurations.appTheme.primaryColor, 88 | ), 89 | child: Icon( 90 | Icons.check, 91 | color: appConfigurations.appTheme.secondaryColor, 92 | size: 50.w, 93 | ), 94 | ), 95 | ), 96 | ], 97 | ), 98 | ), 99 | ), 100 | ); 101 | }, 102 | ); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /lib/features/weather_info/presentation/weather_details/weather_details_viewmodel.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter_architecture/core/basecomponents/base_view_model.dart'; 4 | import 'package:flutter_architecture/core/commundomain/entitties/based_api_result/api_result_state.dart'; 5 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_remote_info_response_entity/weather_info_entity.dart'; 6 | import 'package:flutter_architecture/features/weather_info/domain/usecases/get_weather_data_by_coordinates.dart'; 7 | import 'package:flutter_architecture/features/weather_info/utils/requests_models/weather_by_coordinates_request_model.dart'; 8 | import 'package:injectable/injectable.dart'; 9 | 10 | @injectable 11 | class WeatherDetailsViewModel extends BaseViewModel { 12 | WeatherDetailsViewModel(this.getWeatherDataByCoordinates); 13 | 14 | final GetWeatherDataByCoordinates getWeatherDataByCoordinates; 15 | 16 | final StreamController?> _weatherResult = 17 | StreamController?>.broadcast(); 18 | 19 | StreamController?> get weatherResult => 20 | _weatherResult; 21 | 22 | Future getWeatherByCoordinates( 23 | {WeatherByCoordinatesRequestModel? 24 | weatherByCoordinatesRequestModel}) async { 25 | final ApiResultState? _result = 26 | await executeParamsUseCase( 27 | useCase: getWeatherDataByCoordinates, 28 | query: weatherByCoordinatesRequestModel, 29 | ); 30 | _weatherResult.add(_result); 31 | } 32 | 33 | @override 34 | void onDispose() { 35 | super.onDispose(); 36 | _weatherResult.close(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/features/weather_info/presentation/weather_details/widgets/bottom_navigation_bar/bottom_navigation_bar_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_architecture/core/basecomponents/base_responsive_widget.dart'; 3 | import 'package:flutter_architecture/core/utils/helpers/app_configurations_helper/app_configurations_helper.dart'; 4 | import 'package:flutter_architecture/core/utils/helpers/extension_functions/size_extension.dart'; 5 | import 'package:flutter_architecture/core/utils/helpers/responsive_ui_helper/responsive_config.dart'; 6 | import 'package:flutter_architecture/features/weather_info/presentation/weather_details/widgets/bottom_navigation_bar/bottom_navigation_custom_background.dart'; 7 | 8 | class BottomNavigationBarWidget extends StatelessWidget { 9 | const BottomNavigationBarWidget({Key? key, this.navigateToAddScreen}) 10 | : super(key: key); 11 | final Function()? navigateToAddScreen; 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return BaseResponsiveWidget( 16 | buildWidget: (BuildContext context, ResponsiveUiConfig responsiveUiConfig, 17 | AppConfigurations appConfigurations) { 18 | return Stack( 19 | clipBehavior: Clip.none, 20 | alignment: Alignment.center, 21 | children: [ 22 | SizedBox( 23 | height: 80.w, 24 | width: responsiveUiConfig.screenWidth, 25 | child: CustomPaint( 26 | painter: BottomNavigationCustomBackground(), //3 27 | ), 28 | ), 29 | Positioned( 30 | bottom: 26.h, 31 | child: GestureDetector( 32 | onTap: () { 33 | if (navigateToAddScreen != null) { 34 | navigateToAddScreen!(); 35 | } 36 | }, 37 | child: Container( 38 | width: 60.w, 39 | height: 60.h, 40 | decoration: BoxDecoration( 41 | shape: BoxShape.circle, 42 | color: appConfigurations.appTheme.primaryColor, 43 | ), 44 | child: Center( 45 | child: Icon( 46 | Icons.library_books_sharp, 47 | color: appConfigurations.appTheme.backgroundGreyColor, 48 | ), 49 | ), 50 | ), 51 | ), 52 | ), 53 | ], 54 | ); 55 | }, 56 | ); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /lib/features/weather_info/presentation/weather_details/widgets/bottom_navigation_bar/bottom_navigation_custom_background.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class BottomNavigationCustomBackground extends CustomPainter { 4 | @override 5 | void paint(Canvas canvas, Size size) { 6 | final Path path = Path(); 7 | final Paint paint = Paint(); 8 | paint.style = PaintingStyle.fill; 9 | paint.color = Colors.white; 10 | path.moveTo(0, size.height); 11 | path.lineTo(0, size.height * 0.65); 12 | path.quadraticBezierTo( 13 | size.width * 0.35, 0, size.width * 0.4, size.height * 0.15); 14 | path.cubicTo(size.width * 0.38, size.height * 0.95, size.width * 0.6, 15 | size.height * 0.95, size.width * 0.6, size.height * 0.2); 16 | path.quadraticBezierTo( 17 | size.width * 0.63, 0, size.width, size.height * 0.65); 18 | 19 | path.lineTo(size.width, size.height); 20 | path.lineTo(0, size.height); 21 | path.close(); 22 | canvas.drawShadow(path, Colors.grey, 50.0, false); 23 | canvas.drawPath(path, paint); 24 | } 25 | 26 | @override 27 | bool shouldRepaint(covariant CustomPainter oldDelegate) { 28 | return true; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/features/weather_info/presentation/weather_details/widgets/weather_details_box/box_info_item_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_architecture/core/basecomponents/base_responsive_widget.dart'; 3 | import 'package:flutter_architecture/core/utils/helpers/app_configurations_helper/app_configurations_helper.dart'; 4 | import 'package:flutter_architecture/core/utils/helpers/extension_functions/size_extension.dart'; 5 | import 'package:flutter_architecture/core/utils/helpers/responsive_ui_helper/responsive_config.dart'; 6 | import 'package:flutter_architecture/core/utils/values/colors.dart'; 7 | import 'package:flutter_architecture/core/utils/values/styles.dart'; 8 | 9 | class BoxInfoItemWidget extends StatelessWidget { 10 | const BoxInfoItemWidget({ 11 | Key? key, 12 | this.boxInfoKey, 13 | this.boxInfoValue, 14 | }) : super(key: key); 15 | final String? boxInfoKey; 16 | final String? boxInfoValue; 17 | 18 | @override 19 | Widget build(BuildContext context) { 20 | return BaseResponsiveWidget( 21 | buildWidget: (BuildContext context, ResponsiveUiConfig responsiveUiConfig, 22 | AppConfigurations appConfigurations) => 23 | RichText( 24 | textAlign: TextAlign.center, 25 | text: TextSpan( 26 | text: '$boxInfoKey: ', 27 | style: poppinsRegular.copyWith( 28 | color: appConfigurations.appTheme.backgroundLightColor, 29 | fontSize: 15.w, 30 | ), 31 | children: [ 32 | TextSpan( 33 | text: boxInfoValue ?? '', 34 | style: poppinsBold.copyWith( 35 | color: appConfigurations.appTheme.backgroundLightColor, 36 | fontSize: 13.w, 37 | ), 38 | ), 39 | ], 40 | ), 41 | ), 42 | ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /lib/features/weather_info/presentation/weather_details/widgets/weather_details_box/weather_details_box_list.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_architecture/core/utils/helpers/extension_functions/size_extension.dart'; 3 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_remote_info_response_entity/sunset_sunrise_entity.dart'; 4 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_remote_info_response_entity/wind_info_entity.dart'; 5 | import 'package:flutter_architecture/features/weather_info/presentation/weather_details/widgets/weather_details_box/box_info_item_widget.dart'; 6 | import 'package:flutter_architecture/features/weather_info/presentation/weather_details/widgets/weather_details_box/weather_details_box_widget.dart'; 7 | 8 | class WeatherDetailsBoxList extends StatelessWidget { 9 | const WeatherDetailsBoxList({ 10 | Key? key, 11 | this.sunsetSunriseEntity, 12 | this.windInfoEntity, 13 | }) : super(key: key); 14 | final SunsetSunriseEntity? sunsetSunriseEntity; 15 | final WindInfoEntity? windInfoEntity; 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | return Padding( 20 | padding: EdgeInsets.symmetric( 21 | horizontal: 20.w, 22 | ), 23 | child: Row( 24 | crossAxisAlignment: CrossAxisAlignment.center, 25 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 26 | children: [ 27 | WeatherDetailsBoxWidget( 28 | boxWidget: Column( 29 | mainAxisAlignment: MainAxisAlignment.start, 30 | crossAxisAlignment: CrossAxisAlignment.start, 31 | children: [ 32 | BoxInfoItemWidget( 33 | boxInfoKey: 'Sunset', 34 | boxInfoValue: sunsetSunriseEntity?.sunset, 35 | ), 36 | BoxInfoItemWidget( 37 | boxInfoKey: 'Sunrise', 38 | boxInfoValue: sunsetSunriseEntity?.sunrise, 39 | ), 40 | ], 41 | ), 42 | boxIcon: 'assets/sunset_icon.svg', 43 | boxTitle: 'Sunset & Sunrise', 44 | ), 45 | WeatherDetailsBoxWidget( 46 | boxWidgetPadding: EdgeInsets.symmetric( 47 | horizontal: 20.w, 48 | vertical: 15.h, 49 | ), 50 | boxWidget: Column( 51 | mainAxisAlignment: MainAxisAlignment.start, 52 | crossAxisAlignment: CrossAxisAlignment.start, 53 | children: [ 54 | BoxInfoItemWidget( 55 | boxInfoKey: 'Speed', 56 | boxInfoValue: windInfoEntity?.speed, 57 | ), 58 | BoxInfoItemWidget( 59 | boxInfoKey: 'Degree', 60 | boxInfoValue: windInfoEntity?.deg.toString(), 61 | ), 62 | ], 63 | ), 64 | boxIcon: 'assets/wind_icon.svg', 65 | boxTitle: 'Wind info', 66 | ), 67 | ], 68 | ), 69 | ); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /lib/features/weather_info/presentation/weather_details/widgets/weather_details_box/weather_details_box_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_architecture/core/basecomponents/base_responsive_widget.dart'; 3 | import 'package:flutter_architecture/core/utils/helpers/app_configurations_helper/app_configurations_helper.dart'; 4 | import 'package:flutter_architecture/core/utils/helpers/extension_functions/size_extension.dart'; 5 | import 'package:flutter_architecture/core/utils/helpers/responsive_ui_helper/responsive_config.dart'; 6 | import 'package:flutter_architecture/core/utils/values/colors.dart'; 7 | import 'package:flutter_architecture/core/utils/values/styles.dart'; 8 | import 'package:flutter_svg/flutter_svg.dart'; 9 | 10 | class WeatherDetailsBoxWidget extends StatelessWidget { 11 | const WeatherDetailsBoxWidget({ 12 | Key? key, 13 | this.boxTitle, 14 | this.boxIcon, 15 | required this.boxWidget, 16 | this.boxWidgetPadding, 17 | }) : super(key: key); 18 | final String? boxTitle; 19 | final String? boxIcon; 20 | final Widget boxWidget; 21 | final EdgeInsets? boxWidgetPadding; 22 | 23 | @override 24 | Widget build(BuildContext context) { 25 | return BaseResponsiveWidget( 26 | buildWidget: (BuildContext context, ResponsiveUiConfig responsiveUiConfig, AppConfigurations appConfigurations) => 27 | Container( 28 | padding: boxWidgetPadding ?? EdgeInsets.all(15.w), 29 | decoration: BoxDecoration( 30 | color: appConfigurations.appTheme.primaryColor.withOpacity(0.2), 31 | borderRadius: BorderRadius.all( 32 | Radius.circular(20.w), 33 | ), 34 | ), 35 | child: Column( 36 | mainAxisAlignment: MainAxisAlignment.center, 37 | crossAxisAlignment: CrossAxisAlignment.center, 38 | children: [ 39 | Text( 40 | boxTitle ?? '', 41 | style: poppinsRegular.copyWith( 42 | color: Colors.white70, 43 | fontSize: 16.w, 44 | ), 45 | ), 46 | SizedBox( 47 | height: 15.h, 48 | ), 49 | if (boxIcon != null) 50 | SvgPicture.asset( 51 | boxIcon!, 52 | width: 60.w, 53 | color: appConfigurations.appTheme.primaryColor, 54 | ), 55 | SizedBox( 56 | height: 15.h, 57 | ), 58 | boxWidget, 59 | ], 60 | ), 61 | ), 62 | ); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /lib/features/weather_info/presentation/weather_details/widgets/weather_details_data/weather_details_data_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_architecture/core/di/app_component/app_component.dart'; 3 | import 'package:flutter_architecture/core/utils/helpers/app_configurations_helper/app_configurations_helper.dart'; 4 | import 'package:flutter_architecture/core/utils/helpers/extension_functions/size_extension.dart'; 5 | import 'package:flutter_architecture/core/utils/values/styles.dart'; 6 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_remote_info_response_entity/main_weather_info_entity.dart'; 7 | import 'package:flutter_architecture/features/weather_info/presentation/weather_details/widgets/weather_details_data/weather_single_info_widget.dart'; 8 | 9 | class WeatherDetailsDataWidget extends StatelessWidget { 10 | const WeatherDetailsDataWidget({ 11 | Key? key, 12 | this.weatherDescription, 13 | this.weatherVisibility, 14 | this.mainWeatherInfoEntity, 15 | }) : super(key: key); 16 | final String? weatherDescription; 17 | final String? weatherVisibility; 18 | final MainWeatherInfoEntity? mainWeatherInfoEntity; 19 | 20 | @override 21 | Widget build(BuildContext context) { 22 | final AppConfigurations appConfigurations = locator(); 23 | return Column( 24 | crossAxisAlignment: CrossAxisAlignment.center, 25 | mainAxisAlignment: MainAxisAlignment.center, 26 | children: [ 27 | Text( 28 | weatherDescription ?? '', 29 | style: poppinsBoldItalic.copyWith( 30 | color: appConfigurations.appTheme.primaryColor, 31 | fontSize: 16.w, 32 | ), 33 | ), 34 | Text( 35 | mainWeatherInfoEntity?.temp ?? '', 36 | style: poppinsBoldItalic.copyWith( 37 | color: appConfigurations.appTheme.primaryColor, 38 | fontSize: 50.w, 39 | ), 40 | ), 41 | Padding( 42 | padding: EdgeInsets.symmetric( 43 | horizontal: 25.w, 44 | vertical: 25.h, 45 | ), 46 | child: Row( 47 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 48 | crossAxisAlignment: CrossAxisAlignment.center, 49 | children: [ 50 | WeatherSingleInfo( 51 | infoTitle: 'Pressure', 52 | assetSize: 25.w, 53 | assetString: 'assets/pressure_icon.svg', 54 | infoDescription: '${mainWeatherInfoEntity?.pressure}', 55 | ), 56 | WeatherSingleInfo( 57 | infoTitle: 'Visibility', 58 | assetSize: 20.w, 59 | assetString: 'assets/visibility_icon.svg', 60 | infoDescription: weatherVisibility, 61 | ), 62 | WeatherSingleInfo( 63 | infoTitle: 'Humidity', 64 | assetString: 'assets/humidity_icon.svg', 65 | infoDescription: '${mainWeatherInfoEntity?.humidity}%', 66 | ), 67 | ], 68 | ), 69 | ), 70 | ], 71 | ); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /lib/features/weather_info/presentation/weather_details/widgets/weather_details_data/weather_single_info_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_architecture/core/di/app_component/app_component.dart'; 3 | import 'package:flutter_architecture/core/utils/helpers/app_configurations_helper/app_configurations_helper.dart'; 4 | import 'package:flutter_architecture/core/utils/helpers/extension_functions/size_extension.dart'; 5 | import 'package:flutter_architecture/core/utils/values/styles.dart'; 6 | import 'package:flutter_svg/flutter_svg.dart'; 7 | 8 | class WeatherSingleInfo extends StatelessWidget { 9 | const WeatherSingleInfo({ 10 | super.key, 11 | this.infoTitle, 12 | this.infoDescription, 13 | this.assetString, 14 | this.assetSize, 15 | }); 16 | 17 | final String? infoTitle; 18 | final String? infoDescription; 19 | final String? assetString; 20 | final double? assetSize; 21 | 22 | @override 23 | Widget build(BuildContext context) { 24 | final AppConfigurations appConfigurations = locator(); 25 | return Column( 26 | mainAxisSize: MainAxisSize.min, 27 | crossAxisAlignment: CrossAxisAlignment.center, 28 | mainAxisAlignment: MainAxisAlignment.center, 29 | children: [ 30 | Text( 31 | infoTitle ?? '', 32 | style: poppinsRegular.copyWith( 33 | fontSize: 16.w, 34 | color: Colors.white70, 35 | ), 36 | ), 37 | Row( 38 | mainAxisAlignment: MainAxisAlignment.center, 39 | crossAxisAlignment: CrossAxisAlignment.center, 40 | mainAxisSize: MainAxisSize.min, 41 | children: [ 42 | if (assetString != null) 43 | SvgPicture.asset( 44 | assetString!, 45 | color: appConfigurations.appTheme.primaryColor, 46 | width: assetSize ?? 20.w, 47 | ), 48 | Text( 49 | infoDescription ?? '', 50 | style: poppinsRegular.copyWith( 51 | fontSize: 14.w, 52 | color: appConfigurations.appTheme.backgroundLightColor, 53 | ), 54 | ), 55 | ], 56 | ), 57 | ], 58 | ); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /lib/features/weather_info/presentation/weather_details/widgets/weather_details_header/weather_details_header.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_architecture/core/di/app_component/app_component.dart'; 3 | import 'package:flutter_architecture/core/utils/helpers/app_configurations_helper/app_configurations_helper.dart'; 4 | import 'package:flutter_architecture/core/utils/helpers/extension_functions/size_extension.dart'; 5 | import 'package:flutter_architecture/core/utils/values/colors.dart'; 6 | import 'package:flutter_architecture/core/utils/values/styles.dart'; 7 | 8 | class WeatherDetailsHeader extends StatelessWidget { 9 | const WeatherDetailsHeader({ 10 | Key? key, 11 | this.locationName, 12 | this.date, 13 | }) : super(key: key); 14 | final String? locationName; 15 | final String? date; 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | final AppConfigurations appConfigurations = locator(); 20 | return Padding( 21 | padding: EdgeInsets.only( 22 | top: 50.w, 23 | ), 24 | child: Column( 25 | mainAxisAlignment: MainAxisAlignment.center, 26 | crossAxisAlignment: CrossAxisAlignment.center, 27 | children: [ 28 | Text( 29 | locationName ?? '', 30 | style: poppinsBold.copyWith( 31 | color: appConfigurations.appTheme.primaryColor, 32 | fontSize: 22.w, 33 | ), 34 | ), 35 | Text( 36 | date ?? '', 37 | style: poppinsRegular.copyWith( 38 | color: appConfigurations.appTheme.primaryColor, 39 | fontSize: 20.w, 40 | ), 41 | ), 42 | ], 43 | ), 44 | ); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /lib/features/weather_info/utils/enums/weather_type_enum.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_architecture/core/utils/values/colors.dart'; 3 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_remote_info_response_entity/weather_theme_entity.dart'; 4 | 5 | enum WeatherTypeEnum { 6 | Thunderstorm, 7 | Drizzle, 8 | Rain, 9 | Snow, 10 | Clear, 11 | Clouds, 12 | other, 13 | } 14 | 15 | extension WeatherTypeEnumExtension on String? { 16 | WeatherTypeEnum? toWeatherType() { 17 | WeatherTypeEnum? value; 18 | switch (this) { 19 | case 'Thunderstorm': 20 | value = WeatherTypeEnum.Thunderstorm; 21 | break; 22 | case 'Drizzle': 23 | value = WeatherTypeEnum.Drizzle; 24 | break; 25 | case 'Snow': 26 | value = WeatherTypeEnum.Snow; 27 | break; 28 | case 'Rain': 29 | value = WeatherTypeEnum.Rain; 30 | break; 31 | case 'Clear': 32 | value = WeatherTypeEnum.Clear; 33 | break; 34 | case 'Clouds': 35 | value = WeatherTypeEnum.Clouds; 36 | break; 37 | default: 38 | value = WeatherTypeEnum.other; 39 | break; 40 | } 41 | return value; 42 | } 43 | } 44 | 45 | extension WeatherTypeEnumThemeExtension on WeatherTypeEnum? { 46 | WeatherThemeEntity? toWeatherTheme() { 47 | WeatherThemeEntity? value; 48 | switch (this) { 49 | case WeatherTypeEnum.Thunderstorm: 50 | case WeatherTypeEnum.Clouds: 51 | case WeatherTypeEnum.Rain: 52 | value = WeatherThemeEntity( 53 | firstColor: blue3E97C8, 54 | secondColor: blue3E97C8.withOpacity(0.8), 55 | ); 56 | break; 57 | case WeatherTypeEnum.Drizzle: 58 | case WeatherTypeEnum.Snow: 59 | value = WeatherThemeEntity( 60 | firstColor: blue3E97C8, 61 | secondColor: blueD8E7F2, 62 | ); 63 | break; 64 | case WeatherTypeEnum.Clear: 65 | value = WeatherThemeEntity( 66 | firstColor: Colors.orange, 67 | secondColor: Colors.yellow, 68 | ); 69 | break; 70 | case WeatherTypeEnum.other: 71 | value = WeatherThemeEntity( 72 | firstColor: greyDDDDDD, 73 | secondColor: black404040, 74 | ); 75 | break; 76 | default: 77 | value = WeatherThemeEntity( 78 | firstColor: blue3E97C8, 79 | secondColor: blueD8E7F2, 80 | ); 81 | break; 82 | } 83 | return value; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /lib/features/weather_info/utils/requests_models/weather_by_coordinates_request_model.dart: -------------------------------------------------------------------------------- 1 | class WeatherByCoordinatesRequestModel { 2 | WeatherByCoordinatesRequestModel({ 3 | this.lat, 4 | this.lon, 5 | }); 6 | 7 | final double? lat; 8 | final double? lon; 9 | } 10 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_architecture/core/di/app_component/app_component.dart'; 3 | import 'package:flutter_architecture/core/utils/auto_router_setup/auto_router.dart'; 4 | import 'package:flutter_architecture/core/utils/helpers/app_flavor_helper/app_flavors_helper.dart'; 5 | import 'package:flutter_architecture/core/utils/helpers/app_flavor_helper/environment_config.dart'; 6 | import 'package:flutter_architecture/features/weather_info/presentation/add_new_city/add_new_city_viewmodel.dart'; 7 | import 'package:flutter_architecture/features/weather_info/presentation/weather_details/weather_details_viewmodel.dart'; 8 | import 'package:provider/provider.dart'; 9 | 10 | Future main() async { 11 | WidgetsFlutterBinding.ensureInitialized(); 12 | await initAppComponentLocator(); 13 | final AppFlavorsHelper configService = locator(); 14 | final ProductFlavor? _productFlavor = 15 | EnvironmentConfig.BUILD_VARIANT.toProductFlavor(); 16 | configService.configure(productFlavor: _productFlavor); 17 | runApp(const MyApp()); 18 | } 19 | 20 | class MyApp extends StatefulWidget { 21 | const MyApp({super.key}); 22 | 23 | @override 24 | State createState() => _MyAppState(); 25 | } 26 | 27 | class _MyAppState extends State { 28 | final AppRouter _appRouter = AppRouter(); 29 | final GlobalKey navigatorKey = GlobalKey(); 30 | 31 | @override 32 | Widget build(BuildContext context) { 33 | return MultiProvider( 34 | providers: [ 35 | ChangeNotifierProvider( 36 | create: (BuildContext context) => locator(), 37 | ), 38 | ChangeNotifierProvider( 39 | create: (BuildContext context) => locator(), 40 | ), 41 | ], 42 | child: MaterialApp.router( 43 | routerConfig: _appRouter.config(), 44 | debugShowCheckedModeBanner: false, 45 | ), 46 | ); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /test/core/utils/helpers/api_call_helper_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_architecture/core/utils/helpers/http_strategy_helper/http_request_context.dart'; 2 | import 'package:mockito/annotations.dart'; 3 | import 'package:mockito/mockito.dart'; 4 | 5 | class ApiCallHelperTest extends Mock 6 | implements HttpRequestContext {} 7 | 8 | @GenerateMocks([ApiCallHelperTest]) 9 | class Mocks {} -------------------------------------------------------------------------------- /test/core/utils/helpers/api_call_helper_test.mocks.dart: -------------------------------------------------------------------------------- 1 | // Mocks generated by Mockito 5.4.2 from annotations 2 | // in flutter_architecture/test/core/utils/helpers/api_call_helper_test.dart. 3 | // Do not manually edit this file. 4 | 5 | // ignore_for_file: no_leading_underscores_for_library_prefixes 6 | import 'dart:async' as _i5; 7 | 8 | import 'package:flutter_architecture/core/commundomain/entitties/based_api_result/api_result_model.dart' 9 | as _i3; 10 | import 'package:flutter_architecture/core/utils/helpers/connectivity_helper/connectivity_checker_helper.dart' 11 | as _i2; 12 | import 'package:flutter_architecture/core/utils/helpers/http_strategy_helper/http_request_strategy.dart' 13 | as _i7; 14 | import 'package:http/http.dart' as _i6; 15 | import 'package:mockito/mockito.dart' as _i1; 16 | 17 | import 'api_call_helper_test.dart' as _i4; 18 | 19 | // ignore_for_file: type=lint 20 | // ignore_for_file: avoid_redundant_argument_values 21 | // ignore_for_file: avoid_setters_without_getters 22 | // ignore_for_file: comment_references 23 | // ignore_for_file: implementation_imports 24 | // ignore_for_file: invalid_use_of_visible_for_testing_member 25 | // ignore_for_file: prefer_const_constructors 26 | // ignore_for_file: unnecessary_parenthesis 27 | // ignore_for_file: camel_case_types 28 | // ignore_for_file: subtype_of_sealed_class 29 | 30 | class _FakeConnectivityCheckerHelper_0 extends _i1.SmartFake 31 | implements _i2.ConnectivityCheckerHelper { 32 | _FakeConnectivityCheckerHelper_0( 33 | Object parent, 34 | Invocation parentInvocation, 35 | ) : super( 36 | parent, 37 | parentInvocation, 38 | ); 39 | } 40 | 41 | class _FakeApiResultModel_1 extends _i1.SmartFake 42 | implements _i3.ApiResultModel { 43 | _FakeApiResultModel_1( 44 | Object parent, 45 | Invocation parentInvocation, 46 | ) : super( 47 | parent, 48 | parentInvocation, 49 | ); 50 | } 51 | 52 | /// A class which mocks [ApiCallHelperTest]. 53 | /// 54 | /// See the documentation for Mockito's code generation for more information. 55 | class MockApiCallHelperTest extends _i1.Mock implements _i4.ApiCallHelperTest { 56 | MockApiCallHelperTest() { 57 | _i1.throwOnMissingStub(this); 58 | } 59 | 60 | @override 61 | _i2.ConnectivityCheckerHelper get connectivityCheckerHelper => 62 | (super.noSuchMethod( 63 | Invocation.getter(#connectivityCheckerHelper), 64 | returnValue: _FakeConnectivityCheckerHelper_0( 65 | this, 66 | Invocation.getter(#connectivityCheckerHelper), 67 | ), 68 | ) as _i2.ConnectivityCheckerHelper); 69 | 70 | @override 71 | _i5.Future initSharedDefaultHeader( 72 | [String? contentValue = r'application/json']) => 73 | (super.noSuchMethod( 74 | Invocation.method( 75 | #initSharedDefaultHeader, 76 | [contentValue], 77 | ), 78 | returnValue: _i5.Future.value(), 79 | returnValueForMissingStub: _i5.Future.value(), 80 | ) as _i5.Future); 81 | 82 | @override 83 | _i5.Future<_i3.ApiResultModel<_i6.Response>> makeRequest({ 84 | required String? uri, 85 | required _i7.HttpRequestStrategy? httpRequestStrategy, 86 | Map? headers = const {}, 87 | Map? requestData = const {}, 88 | }) => 89 | (super.noSuchMethod( 90 | Invocation.method( 91 | #makeRequest, 92 | [], 93 | { 94 | #uri: uri, 95 | #httpRequestStrategy: httpRequestStrategy, 96 | #headers: headers, 97 | #requestData: requestData, 98 | }, 99 | ), 100 | returnValue: _i5.Future<_i3.ApiResultModel<_i6.Response>>.value( 101 | _FakeApiResultModel_1<_i6.Response>( 102 | this, 103 | Invocation.method( 104 | #makeRequest, 105 | [], 106 | { 107 | #uri: uri, 108 | #httpRequestStrategy: httpRequestStrategy, 109 | #headers: headers, 110 | #requestData: requestData, 111 | }, 112 | ), 113 | )), 114 | ) as _i5.Future<_i3.ApiResultModel<_i6.Response>>); 115 | } 116 | -------------------------------------------------------------------------------- /test/features/weather_info/data/datasources/weather_local_datasource_test/weather_datasources_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_architecture/features/weather_info/data/datasources/local_datasource/weather_local_datasource.dart'; 2 | import 'package:mockito/annotations.dart'; 3 | import 'package:mockito/mockito.dart'; 4 | 5 | class MockWeatherLocalDataSource extends Mock 6 | implements WeatherLocalDataSource {} 7 | 8 | @GenerateMocks([MockWeatherLocalDataSource]) 9 | class Mocks {} 10 | -------------------------------------------------------------------------------- /test/features/weather_info/data/datasources/weather_local_datasource_test/weather_datasources_test.mocks.dart: -------------------------------------------------------------------------------- 1 | // Mocks generated by Mockito 5.4.2 from annotations 2 | // in flutter_architecture/test/features/weather_info/data/datasources/weather_local_datasource_test/weather_datasources_test.dart. 3 | // Do not manually edit this file. 4 | 5 | // ignore_for_file: no_leading_underscores_for_library_prefixes 6 | import 'dart:async' as _i3; 7 | 8 | import 'package:flutter_architecture/features/weather_info/data/models/weather_info_remote_response_model/weather_info_response_model.dart' 9 | as _i5; 10 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_remote_info_response_entity/weather_info_entity.dart' 11 | as _i4; 12 | import 'package:mockito/mockito.dart' as _i1; 13 | 14 | import 'weather_datasources_test.dart' as _i2; 15 | 16 | // ignore_for_file: type=lint 17 | // ignore_for_file: avoid_redundant_argument_values 18 | // ignore_for_file: avoid_setters_without_getters 19 | // ignore_for_file: comment_references 20 | // ignore_for_file: implementation_imports 21 | // ignore_for_file: invalid_use_of_visible_for_testing_member 22 | // ignore_for_file: prefer_const_constructors 23 | // ignore_for_file: unnecessary_parenthesis 24 | // ignore_for_file: camel_case_types 25 | // ignore_for_file: subtype_of_sealed_class 26 | 27 | /// A class which mocks [MockWeatherLocalDataSource]. 28 | /// 29 | /// See the documentation for Mockito's code generation for more information. 30 | class MockMockWeatherLocalDataSource extends _i1.Mock 31 | implements _i2.MockWeatherLocalDataSource { 32 | MockMockWeatherLocalDataSource() { 33 | _i1.throwOnMissingStub(this); 34 | } 35 | 36 | @override 37 | _i3.Future<_i4.WeatherInfoEntity?> getLastWeatherInfo() => 38 | (super.noSuchMethod( 39 | Invocation.method( 40 | #getLastWeatherInfo, 41 | [], 42 | ), 43 | returnValue: _i3.Future<_i4.WeatherInfoEntity?>.value(), 44 | ) as _i3.Future<_i4.WeatherInfoEntity?>); 45 | 46 | @override 47 | _i3.Future?> getAllLocalWeathers() => 48 | (super.noSuchMethod( 49 | Invocation.method( 50 | #getAllLocalWeathers, 51 | [], 52 | ), 53 | returnValue: _i3.Future?>.value(), 54 | ) as _i3.Future?>); 55 | 56 | @override 57 | void cacheWeatherInfo( 58 | _i5.WeatherInfoResponseModel? weatherInfoResponseModel) => 59 | super.noSuchMethod( 60 | Invocation.method( 61 | #cacheWeatherInfo, 62 | [weatherInfoResponseModel], 63 | ), 64 | returnValueForMissingStub: null, 65 | ); 66 | } 67 | -------------------------------------------------------------------------------- /test/features/weather_info/data/datasources/weather_remote_datasource_test/remote_datasource_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:flutter_architecture/core/commundomain/entitties/based_api_result/api_result_model.dart'; 4 | import 'package:flutter_architecture/core/utils/constants/app_constants.dart'; 5 | import 'package:flutter_architecture/core/utils/helpers/http_strategy_helper/concrete_strategies/get_request_strategy.dart'; 6 | import 'package:flutter_architecture/features/weather_info/data/datasources/remote_datasource/weather_remote_datasource_impl.dart'; 7 | import 'package:flutter_test/flutter_test.dart'; 8 | import 'package:http/http.dart' as http; 9 | import 'package:mockito/mockito.dart'; 10 | 11 | import '../../../../../core/utils/helpers/api_call_helper_test.mocks.dart'; 12 | 13 | void main() { 14 | late WeatherRemoteDataSourceImpl _sut; 15 | late MockApiCallHelperTest _apiCallHelper; 16 | setUp(() { 17 | _apiCallHelper = MockApiCallHelperTest(); 18 | _sut = WeatherRemoteDataSourceImpl(_apiCallHelper); 19 | }); 20 | group('test getWeatherDataByCity()', () { 21 | const String _cityName = 'Sousse'; 22 | final Map _params = { 23 | cityNameKey: _cityName, 24 | appIdKey: appIdValue 25 | }; 26 | void _arrangeResponse() { 27 | when(_apiCallHelper.makeRequest( 28 | uri: getWeatherDetails, 29 | requestData: _params, 30 | httpRequestStrategy: GetRequestStrategy(), 31 | )).thenAnswer((_) async { 32 | final http.Response _response = http.Response( 33 | File('test_assets/weather_info_json_data.json').readAsStringSync(), 34 | 200, 35 | ); 36 | return ApiResultModel.success(data: _response); 37 | }); 38 | } 39 | 40 | test( 41 | 'should perform GET request on a URL with extra headers and a body', 42 | () async { 43 | //arrange 44 | _arrangeResponse(); 45 | //act 46 | _sut.getWeatherDataByCity(cityName: _cityName); 47 | //assert 48 | verify(_apiCallHelper.makeRequest( 49 | uri: getWeatherDetails, 50 | requestData: _params, 51 | httpRequestStrategy: GetRequestStrategy(), 52 | )); 53 | }, 54 | ); 55 | }); 56 | } 57 | -------------------------------------------------------------------------------- /test/features/weather_info/data/datasources/weather_remote_datasource_test/weather_datasources_mock.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_architecture/features/weather_info/data/datasources/remote_datasource/weather_remote_datasource.dart'; 2 | import 'package:mockito/annotations.dart'; 3 | import 'package:mockito/mockito.dart'; 4 | 5 | class RemoteDataSource extends Mock 6 | implements WeatherRemoteDataSource {} 7 | 8 | @GenerateMocks([RemoteDataSource]) 9 | class Mocks {} -------------------------------------------------------------------------------- /test/features/weather_info/data/datasources/weather_remote_datasource_test/weather_datasources_mock.mocks.dart: -------------------------------------------------------------------------------- 1 | // Mocks generated by Mockito 5.4.2 from annotations 2 | // in flutter_architecture/test/features/weather_info/data/datasources/weather_remote_datasource_test/weather_datasources_mock.dart. 3 | // Do not manually edit this file. 4 | 5 | // ignore_for_file: no_leading_underscores_for_library_prefixes 6 | import 'dart:async' as _i4; 7 | 8 | import 'package:flutter_architecture/core/commundomain/entitties/based_api_result/api_result_model.dart' 9 | as _i2; 10 | import 'package:flutter_architecture/features/weather_info/data/models/weather_info_remote_response_model/weather_info_response_model.dart' 11 | as _i5; 12 | import 'package:flutter_architecture/features/weather_info/utils/requests_models/weather_by_coordinates_request_model.dart' 13 | as _i6; 14 | import 'package:mockito/mockito.dart' as _i1; 15 | 16 | import 'weather_datasources_mock.dart' as _i3; 17 | 18 | // ignore_for_file: type=lint 19 | // ignore_for_file: avoid_redundant_argument_values 20 | // ignore_for_file: avoid_setters_without_getters 21 | // ignore_for_file: comment_references 22 | // ignore_for_file: implementation_imports 23 | // ignore_for_file: invalid_use_of_visible_for_testing_member 24 | // ignore_for_file: prefer_const_constructors 25 | // ignore_for_file: unnecessary_parenthesis 26 | // ignore_for_file: camel_case_types 27 | // ignore_for_file: subtype_of_sealed_class 28 | 29 | class _FakeApiResultModel_0 extends _i1.SmartFake 30 | implements _i2.ApiResultModel { 31 | _FakeApiResultModel_0( 32 | Object parent, 33 | Invocation parentInvocation, 34 | ) : super( 35 | parent, 36 | parentInvocation, 37 | ); 38 | } 39 | 40 | /// A class which mocks [RemoteDataSource]. 41 | /// 42 | /// See the documentation for Mockito's code generation for more information. 43 | class MockRemoteDataSource extends _i1.Mock implements _i3.RemoteDataSource { 44 | MockRemoteDataSource() { 45 | _i1.throwOnMissingStub(this); 46 | } 47 | 48 | @override 49 | _i4.Future<_i2.ApiResultModel<_i5.WeatherInfoResponseModel?>> 50 | getWeatherDataByCoordinates( 51 | {_i6.WeatherByCoordinatesRequestModel? 52 | weatherByCoordinatesRequestModel}) => 53 | (super.noSuchMethod( 54 | Invocation.method( 55 | #getWeatherDataByCoordinates, 56 | [], 57 | { 58 | #weatherByCoordinatesRequestModel: 59 | weatherByCoordinatesRequestModel 60 | }, 61 | ), 62 | returnValue: _i4.Future< 63 | _i2.ApiResultModel<_i5.WeatherInfoResponseModel?>>.value( 64 | _FakeApiResultModel_0<_i5.WeatherInfoResponseModel?>( 65 | this, 66 | Invocation.method( 67 | #getWeatherDataByCoordinates, 68 | [], 69 | { 70 | #weatherByCoordinatesRequestModel: 71 | weatherByCoordinatesRequestModel 72 | }, 73 | ), 74 | )), 75 | ) as _i4.Future<_i2.ApiResultModel<_i5.WeatherInfoResponseModel?>>); 76 | 77 | @override 78 | _i4.Future< 79 | _i2.ApiResultModel<_i5.WeatherInfoResponseModel?>> getWeatherDataByCity( 80 | {String? cityName}) => 81 | (super.noSuchMethod( 82 | Invocation.method( 83 | #getWeatherDataByCity, 84 | [], 85 | {#cityName: cityName}, 86 | ), 87 | returnValue: 88 | _i4.Future<_i2.ApiResultModel<_i5.WeatherInfoResponseModel?>>.value( 89 | _FakeApiResultModel_0<_i5.WeatherInfoResponseModel?>( 90 | this, 91 | Invocation.method( 92 | #getWeatherDataByCity, 93 | [], 94 | {#cityName: cityName}, 95 | ), 96 | )), 97 | ) as _i4.Future<_i2.ApiResultModel<_i5.WeatherInfoResponseModel?>>); 98 | } 99 | -------------------------------------------------------------------------------- /test/features/weather_info/data/models/weather_info_response_model_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:io'; 3 | import 'package:flutter_architecture/features/weather_info/data/models/weather_info_remote_response_model/clouds_response/clouds_response_model.dart'; 4 | import 'package:flutter_architecture/features/weather_info/data/models/weather_info_remote_response_model/coordinate_response/coordinate_response_model.dart'; 5 | import 'package:flutter_architecture/features/weather_info/data/models/weather_info_remote_response_model/main_weather_info_response/main_weather_info_response_model.dart'; 6 | import 'package:flutter_architecture/features/weather_info/data/models/weather_info_remote_response_model/sunset_sunrise_response/sunset_sunrise_response_model.dart'; 7 | import 'package:flutter_architecture/features/weather_info/data/models/weather_info_remote_response_model/weather_description_response/weather_description_response_model.dart'; 8 | import 'package:flutter_architecture/features/weather_info/data/models/weather_info_remote_response_model/weather_info_response_model.dart'; 9 | import 'package:flutter_architecture/features/weather_info/data/models/weather_info_remote_response_model/wind_info_response/wind_info_response_model.dart'; 10 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_remote_info_response_entity/weather_info_entity.dart'; 11 | import 'package:flutter_test/flutter_test.dart'; 12 | 13 | void main() { 14 | final WeatherInfoResponseModel _weatherInfoResponseModel = 15 | WeatherInfoResponseModel( 16 | date: 1663066385, 17 | sunsetAndSunriseData: SunsetSunriseResponseModel( 18 | country: 'TN', 19 | id: 1193, 20 | type: 1, 21 | sunrise: 1663045105, 22 | sunset: 1663090127, 23 | ), 24 | timezone: 3600, 25 | id: 2464915, 26 | cityName: 'Sousse', 27 | mainWeatherData: MainWeatherInfoResponseModel( 28 | temp: 304.03, 29 | feelsLike: 307.27, 30 | tempMin: 303.02, 31 | tempMax: 304.03, 32 | pressure: 1014, 33 | humidity: 58, 34 | ), 35 | windData: WindInfoResponseModel(speed: 5.66, deg: 100), 36 | weatherVisibility: 10000, 37 | cloudsData: CloudsResponseModel( 38 | all: 20, 39 | ), 40 | weatherDescription: [ 41 | WeatherDescriptionResponseModel( 42 | id: 801, 43 | main: 'Clouds', 44 | description: 'few clouds', 45 | icon: '02d', 46 | ), 47 | ], 48 | coordinateData: CoordinateResponseModel(lon: 10.637, lat: 35.8254), 49 | ); 50 | test( 51 | 'should be a subclass of WeatherInfoEntity()', 52 | () async { 53 | //assert 54 | expect(_weatherInfoResponseModel.mapToEntity(), 55 | isA()); 56 | }, 57 | ); 58 | group('test fromJson() function', () { 59 | test( 60 | 'should return valid model', 61 | () async { 62 | //arrange 63 | final Map _jsonMap = json.decode( 64 | File('test_assets/weather_info_json_data.json').readAsStringSync()); 65 | //act 66 | final WeatherInfoResponseModel result = 67 | WeatherInfoResponseModel.fromJson(_jsonMap); 68 | //assert 69 | expect(result.mapToEntity(), 70 | _weatherInfoResponseModel.mapToEntity()); 71 | }, 72 | ); 73 | }); 74 | } 75 | -------------------------------------------------------------------------------- /test/features/weather_info/data/repositories/weather_repository_impl_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_architecture/core/commundomain/entitties/based_api_result/api_result_model.dart'; 2 | import 'package:flutter_architecture/features/weather_info/data/models/weather_info_remote_response_model/clouds_response/clouds_response_model.dart'; 3 | import 'package:flutter_architecture/features/weather_info/data/models/weather_info_remote_response_model/coordinate_response/coordinate_response_model.dart'; 4 | import 'package:flutter_architecture/features/weather_info/data/models/weather_info_remote_response_model/main_weather_info_response/main_weather_info_response_model.dart'; 5 | import 'package:flutter_architecture/features/weather_info/data/models/weather_info_remote_response_model/sunset_sunrise_response/sunset_sunrise_response_model.dart'; 6 | import 'package:flutter_architecture/features/weather_info/data/models/weather_info_remote_response_model/weather_description_response/weather_description_response_model.dart'; 7 | import 'package:flutter_architecture/features/weather_info/data/models/weather_info_remote_response_model/weather_info_response_model.dart'; 8 | import 'package:flutter_architecture/features/weather_info/data/models/weather_info_remote_response_model/wind_info_response/wind_info_response_model.dart'; 9 | import 'package:flutter_architecture/features/weather_info/data/repositories/weather_repository_impl.dart'; 10 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_remote_info_response_entity/weather_info_entity.dart'; 11 | import 'package:flutter_test/flutter_test.dart'; 12 | import 'package:mockito/mockito.dart'; 13 | 14 | import '../datasources/weather_local_datasource_test/weather_datasources_test.dart'; 15 | import '../datasources/weather_remote_datasource_test/weather_datasources_mock.mocks.dart'; 16 | 17 | void main() { 18 | late WeatherRepositoryImpl _sut; 19 | late MockRemoteDataSource _remoteDatasource; 20 | late MockWeatherLocalDataSource _localDatasource; 21 | setUp( 22 | () { 23 | _remoteDatasource = MockRemoteDataSource(); 24 | _localDatasource = MockWeatherLocalDataSource(); 25 | _sut = WeatherRepositoryImpl( 26 | remoteDataSource: _remoteDatasource, 27 | localDataSource: _localDatasource, 28 | ); 29 | }, 30 | ); 31 | group('test getWeatherDataByCoordinates() when device offline', () { 32 | const String _cityName = 'Sousse'; 33 | final WeatherInfoResponseModel _weatherInfoResponseModel = 34 | WeatherInfoResponseModel( 35 | date: 1663066385, 36 | sunsetAndSunriseData: SunsetSunriseResponseModel( 37 | country: 'TN', 38 | id: 1193, 39 | type: 1, 40 | sunrise: 1663045105, 41 | sunset: 1663090127, 42 | ), 43 | timezone: 3600, 44 | id: 2464915, 45 | cityName: 'Sousse', 46 | mainWeatherData: MainWeatherInfoResponseModel( 47 | temp: 304.03, 48 | feelsLike: 307.27, 49 | tempMin: 303.02, 50 | tempMax: 304.03, 51 | pressure: 1014, 52 | humidity: 58, 53 | ), 54 | windData: WindInfoResponseModel(speed: 5.66, deg: 100), 55 | weatherVisibility: 10000, 56 | cloudsData: CloudsResponseModel( 57 | all: 20, 58 | ), 59 | weatherDescription: [ 60 | WeatherDescriptionResponseModel( 61 | id: 801, 62 | main: 'Clouds', 63 | description: 'few clouds', 64 | icon: '02d', 65 | ), 66 | ], 67 | coordinateData: CoordinateResponseModel(lon: 10.637, lat: 35.8254), 68 | ); 69 | void _arrangeResponse() { 70 | when(_remoteDatasource.getWeatherDataByCity(cityName: _cityName)) 71 | .thenAnswer((_) async { 72 | return ApiResultModel.success( 73 | data: _weatherInfoResponseModel); 74 | }); 75 | } 76 | 77 | test( 78 | 'should return correct data', 79 | () async { 80 | //arrange 81 | _arrangeResponse(); 82 | //act 83 | final ApiResultModel result = 84 | await _sut.getWeatherDataByCity(cityName: _cityName); 85 | //assert 86 | expect( 87 | result, 88 | ApiResultModel.success( 89 | data: _weatherInfoResponseModel.mapToEntity()), 90 | ); 91 | }, 92 | ); 93 | }); 94 | } 95 | -------------------------------------------------------------------------------- /test/features/weather_info/domain/repositories/weather_repository_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_architecture/features/weather_info/domain/repositories/weather_repository.dart'; 2 | import 'package:mockito/annotations.dart'; 3 | import 'package:mockito/mockito.dart'; 4 | 5 | class MockWeatherRepository extends Mock implements WeatherRepository {} 6 | @GenerateMocks([MockWeatherRepository]) 7 | class Mocks{} -------------------------------------------------------------------------------- /test/features/weather_info/domain/usecases/get_weather_data_by_city_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_architecture/core/commundomain/entitties/based_api_result/api_result_model.dart'; 2 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_remote_info_response_entity/clouds_entity.dart'; 3 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_remote_info_response_entity/weather_description_entity.dart'; 4 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_remote_info_response_entity/weather_info_entity.dart'; 5 | import 'package:flutter_architecture/features/weather_info/domain/usecases/get_weather_data_by_city.dart'; 6 | import 'package:flutter_test/flutter_test.dart'; 7 | import 'package:mockito/mockito.dart'; 8 | 9 | import '../repositories/weather_repository_test.mocks.dart'; 10 | 11 | void main() { 12 | late MockMockWeatherRepository _mockWeatherRepository; 13 | late GetWeatherDataByCity _sut; 14 | setUp(() { 15 | _mockWeatherRepository = MockMockWeatherRepository(); 16 | _sut = GetWeatherDataByCity(_mockWeatherRepository); 17 | }); 18 | group('test getWeatherDataByCity() use case', () { 19 | const String _cityName = 'sousse'; 20 | 21 | const WeatherInfoEntity _mockedResult = WeatherInfoEntity( 22 | clouds: CloudsEntity(all: 0), 23 | name: _cityName, 24 | weather: [ 25 | WeatherDescriptionEntity( 26 | id: 800, 27 | main: 'Clear', 28 | description: 'clear sky', 29 | icon: '01d', 30 | ), 31 | ], 32 | ); 33 | void _arrangeResponse() { 34 | when(_mockWeatherRepository.getWeatherDataByCity(cityName: _cityName)) 35 | .thenAnswer((_) async { 36 | return const ApiResultModel.success(data: _mockedResult); 37 | }); 38 | } 39 | 40 | test( 41 | 'should get weather data from the repository with the given city name', 42 | () async { 43 | //arrange 44 | _arrangeResponse(); 45 | //act 46 | final ApiResultModel result = await _sut(_cityName); 47 | //assert 48 | expect( 49 | result, 50 | const ApiResultModel.success(data: _mockedResult), 51 | ); 52 | }, 53 | ); 54 | }); 55 | } 56 | -------------------------------------------------------------------------------- /test/features/weather_info/domain/usecases/get_weather_data_by_coordinates_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_architecture/core/commundomain/entitties/based_api_result/api_result_model.dart'; 2 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_remote_info_response_entity/clouds_entity.dart'; 3 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_remote_info_response_entity/weather_description_entity.dart'; 4 | import 'package:flutter_architecture/features/weather_info/domain/entities/weather_remote_info_response_entity/weather_info_entity.dart'; 5 | import 'package:flutter_architecture/features/weather_info/domain/usecases/get_weather_data_by_coordinates.dart'; 6 | import 'package:flutter_architecture/features/weather_info/utils/requests_models/weather_by_coordinates_request_model.dart'; 7 | import 'package:flutter_test/flutter_test.dart'; 8 | import 'package:mockito/mockito.dart'; 9 | 10 | import '../repositories/weather_repository_test.mocks.dart'; 11 | 12 | void main() { 13 | late MockMockWeatherRepository _mockWeatherRepository; 14 | late GetWeatherDataByCoordinates _sut; 15 | setUp(() { 16 | _mockWeatherRepository = MockMockWeatherRepository(); 17 | _sut = GetWeatherDataByCoordinates(_mockWeatherRepository); 18 | }); 19 | group('test getWeatherDataByCoordinates() use case', () { 20 | const WeatherInfoEntity _mockedResult = WeatherInfoEntity( 21 | clouds: CloudsEntity(all: 0), 22 | weather: [ 23 | WeatherDescriptionEntity( 24 | id: 800, 25 | main: 'Clear', 26 | description: 'clear sky', 27 | icon: '01d', 28 | ), 29 | ], 30 | ); 31 | const double lat = 10.0; 32 | const double lon = 50.0; 33 | void _arrangeResponse() { 34 | when(_mockWeatherRepository.getWeatherDataByCoordinates( 35 | weatherByCoordinatesRequestModel: 36 | WeatherByCoordinatesRequestModel(lon: lon, lat: lat), 37 | )).thenAnswer((_) async { 38 | return const ApiResultModel.success(data: _mockedResult); 39 | }); 40 | } 41 | 42 | test( 43 | 'should get weather data from the repository with the given coordinates', 44 | () async { 45 | //arrange 46 | _arrangeResponse(); 47 | //act 48 | final ApiResultModel result = 49 | await _sut(WeatherByCoordinatesRequestModel(lon: lon, lat: lat)); 50 | //assert 51 | expect( 52 | result, 53 | const ApiResultModel.success(data: _mockedResult), 54 | ); 55 | verify(_mockWeatherRepository.getWeatherDataByCoordinates( 56 | weatherByCoordinatesRequestModel: 57 | WeatherByCoordinatesRequestModel(lon: lon, lat: lat), 58 | )); 59 | verifyNoMoreInteractions(_mockWeatherRepository); 60 | }, 61 | ); 62 | }); 63 | } 64 | -------------------------------------------------------------------------------- /test_assets/weather_info_json_data.json: -------------------------------------------------------------------------------- 1 | { 2 | "coord": { 3 | "lon": 10.637, 4 | "lat": 35.8254 5 | }, 6 | "weather": [ 7 | { 8 | "id": 801, 9 | "main": "Clouds", 10 | "description": "few clouds", 11 | "icon": "02d" 12 | } 13 | ], 14 | "base": "stations", 15 | "main": { 16 | "temp": 304.03, 17 | "feels_like": 307.27, 18 | "temp_min": 303.02, 19 | "temp_max": 304.03, 20 | "pressure": 1014, 21 | "humidity": 58 22 | }, 23 | "visibility": 10000, 24 | "wind": { 25 | "speed": 5.66, 26 | "deg": 100 27 | }, 28 | "clouds": { 29 | "all": 20 30 | }, 31 | "dt": 1663066385, 32 | "sys": { 33 | "type": 1, 34 | "id": 1193, 35 | "country": "TN", 36 | "sunrise": 1663045105, 37 | "sunset": 1663090127 38 | }, 39 | "timezone": 3600, 40 | "id": 2464915, 41 | "name": "Sousse", 42 | "cod": 200 43 | } --------------------------------------------------------------------------------